summaryrefslogtreecommitdiff
path: root/drivers/leds/leds-qpnp-flash-v2.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/leds/leds-qpnp-flash-v2.c')
-rw-r--r--drivers/leds/leds-qpnp-flash-v2.c110
1 files changed, 88 insertions, 22 deletions
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
index 1a6cad946a25..a89a92d253ac 100644
--- a/drivers/leds/leds-qpnp-flash-v2.c
+++ b/drivers/leds/leds-qpnp-flash-v2.c
@@ -63,11 +63,13 @@
#define FLASH_LED_REG_MITIGATION_SEL(base) (base + 0x6E)
#define FLASH_LED_REG_MITIGATION_SW(base) (base + 0x6F)
#define FLASH_LED_REG_LMH_LEVEL(base) (base + 0x70)
+#define FLASH_LED_REG_MULTI_STROBE_CTRL(base) (base + 0x71)
+#define FLASH_LED_REG_LPG_INPUT_CTRL(base) (base + 0x72)
#define FLASH_LED_REG_CURRENT_DERATE_EN(base) (base + 0x76)
#define FLASH_LED_HDRM_VOL_MASK GENMASK(7, 4)
#define FLASH_LED_CURRENT_MASK GENMASK(6, 0)
-#define FLASH_LED_ENABLE_MASK GENMASK(2, 0)
+#define FLASH_LED_STROBE_MASK GENMASK(1, 0)
#define FLASH_HW_STROBE_MASK GENMASK(2, 0)
#define FLASH_LED_ISC_WARMUP_DELAY_MASK GENMASK(1, 0)
#define FLASH_LED_CURRENT_DERATE_EN_MASK GENMASK(2, 0)
@@ -91,6 +93,9 @@
#define THERMAL_DERATE_SLOW_SHIFT 4
#define THERMAL_DERATE_SLOW_MASK GENMASK(6, 4)
#define THERMAL_DERATE_FAST_MASK GENMASK(2, 0)
+#define LED1N2_FLASH_ONCE_ONLY_BIT BIT(0)
+#define LED3_FLASH_ONCE_ONLY_BIT BIT(1)
+#define LPG_INPUT_SEL_BIT BIT(0)
#define VPH_DROOP_DEBOUNCE_US_TO_VAL(val_us) (val_us / 8)
#define VPH_DROOP_HYST_MV_TO_VAL(val_mv) (val_mv / 25)
@@ -174,6 +179,12 @@ enum {
LED3,
};
+enum strobe_type {
+ SW_STROBE = 0,
+ HW_STROBE,
+ LPG_STROBE,
+};
+
/*
* Configurations for each individual LED
*/
@@ -194,7 +205,8 @@ struct flash_node_data {
u8 ires;
u8 hdrm_val;
u8 current_reg_val;
- u8 trigger;
+ u8 strobe_ctrl;
+ u8 strobe_sel;
bool led_on;
};
@@ -232,6 +244,7 @@ struct flash_led_platform_data {
int thermal_thrsh1;
int thermal_thrsh2;
int thermal_thrsh3;
+ int hw_strobe_option;
u32 led1n2_iclamp_low_ma;
u32 led1n2_iclamp_mid_ma;
u32 led3_iclamp_low_ma;
@@ -246,7 +259,6 @@ struct flash_led_platform_data {
u8 chgr_mitigation_sel;
u8 lmh_level;
u8 iled_thrsh_val;
- u8 hw_strobe_option;
bool hdrm_auto_mode_en;
bool thermal_derate_en;
bool otst_ramp_bkup_en;
@@ -557,6 +569,28 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led)
return rc;
}
+ if (led->pdata->hw_strobe_option > 0) {
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_STROBE_CFG(led->base),
+ FLASH_LED_STROBE_MASK,
+ led->pdata->hw_strobe_option);
+ if (rc < 0)
+ return rc;
+ }
+
+ if (led->fnode[LED3].strobe_sel == LPG_STROBE) {
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_MULTI_STROBE_CTRL(led->base),
+ LED3_FLASH_ONCE_ONLY_BIT, 0);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_LPG_INPUT_CTRL(led->base),
+ LPG_INPUT_SEL_BIT, LPG_INPUT_SEL_BIT);
+ if (rc < 0)
+ return rc;
+ }
return 0;
}
@@ -980,7 +1014,7 @@ static int qpnp_flash_led_switch_disable(struct flash_switch_data *snode)
led->fnode[i].led_on = false;
- if (led->fnode[i].trigger & FLASH_LED_HW_SW_STROBE_SEL_BIT) {
+ if (led->fnode[i].strobe_sel == HW_STROBE) {
rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i],
led->pdata->hw_strobe_option, false);
if (rc < 0) {
@@ -1034,13 +1068,6 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
if (rc < 0)
return rc;
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_STROBE_CFG(led->base),
- FLASH_LED_ENABLE_MASK,
- led->pdata->hw_strobe_option);
- if (rc < 0)
- return rc;
-
val = 0;
for (i = 0; i < led->num_fnodes; i++) {
if (!led->fnode[i].led_on ||
@@ -1048,13 +1075,13 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
continue;
addr_offset = led->fnode[i].id;
- if (led->fnode[i].trigger & FLASH_LED_HW_SW_STROBE_SEL_BIT)
- mask = FLASH_HW_STROBE_MASK;
- else
+ if (led->fnode[i].strobe_sel == SW_STROBE)
mask = FLASH_LED_HW_SW_STROBE_SEL_BIT;
+ else
+ mask = FLASH_HW_STROBE_MASK;
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_STROBE_CTRL(led->base + addr_offset),
- mask, led->fnode[i].trigger);
+ mask, led->fnode[i].strobe_ctrl);
if (rc < 0)
return rc;
@@ -1072,7 +1099,7 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
val |= FLASH_LED_ENABLE << led->fnode[i].id;
- if (led->fnode[i].trigger & FLASH_LED_HW_SW_STROBE_SEL_BIT) {
+ if (led->fnode[i].strobe_sel == HW_STROBE) {
rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i],
led->pdata->hw_strobe_option, true);
if (rc < 0) {
@@ -1364,7 +1391,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
const char *temp_string;
int rc, min_ma;
u32 val;
- bool strobe_sel = 0, edge_trigger = 0, active_high = 0;
+ bool hw_strobe = 0, edge_trigger = 0, active_high = 0;
fnode->pdev = led->pdev;
fnode->cdev.brightness_set = qpnp_flash_led_brightness_set;
@@ -1483,14 +1510,52 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
return rc;
}
- strobe_sel = of_property_read_bool(node, "qcom,hw-strobe-sel");
- if (strobe_sel) {
+ fnode->strobe_sel = SW_STROBE;
+ rc = of_property_read_u32(node, "qcom,strobe-sel", &val);
+ if (rc < 0) {
+ if (rc != -EINVAL) {
+ pr_err("Unable to read qcom,strobe-sel property\n");
+ return rc;
+ }
+ } else {
+ if (val < SW_STROBE || val > LPG_STROBE) {
+ pr_err("Incorrect strobe selection specified %d\n",
+ val);
+ return -EINVAL;
+ }
+ fnode->strobe_sel = (u8)val;
+ }
+
+ /*
+ * LPG strobe is allowed only for LED3 and HW strobe option should be
+ * option 2 or 3.
+ */
+ if (fnode->strobe_sel == LPG_STROBE) {
+ if (led->pdata->hw_strobe_option ==
+ FLASH_LED_HW_STROBE_OPTION_1) {
+ pr_err("Incorrect strobe option for LPG strobe\n");
+ return -EINVAL;
+ }
+ if (fnode->id != LED3) {
+ pr_err("Incorrect LED chosen for LPG strobe\n");
+ return -EINVAL;
+ }
+ }
+
+ if (fnode->strobe_sel == HW_STROBE) {
edge_trigger = of_property_read_bool(node,
"qcom,hw-strobe-edge-trigger");
active_high = !of_property_read_bool(node,
"qcom,hw-strobe-active-low");
+ hw_strobe = 1;
+ } else if (fnode->strobe_sel == LPG_STROBE) {
+ /* LPG strobe requires level trigger and active high */
+ edge_trigger = 0;
+ active_high = 1;
+ hw_strobe = 1;
}
- fnode->trigger = (strobe_sel << 2) | (edge_trigger << 1) | active_high;
+ fnode->strobe_ctrl = (hw_strobe << 2) | (edge_trigger << 1) |
+ active_high;
rc = led_classdev_register(&led->pdev->dev, &fnode->cdev);
if (rc < 0) {
@@ -1506,7 +1571,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
fnode->strobe_pinctrl = NULL;
}
- if (fnode->trigger & FLASH_LED_HW_SW_STROBE_SEL_BIT) {
+ if (fnode->strobe_sel == HW_STROBE) {
if (of_find_property(node, "qcom,hw-strobe-gpio", NULL)) {
fnode->hw_strobe_gpio = of_get_named_gpio(node,
"qcom,hw-strobe-gpio", 0);
@@ -1886,9 +1951,10 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led,
led->pdata->vph_droop_hysteresis <<= FLASH_LED_VPH_DROOP_HYST_SHIFT;
+ led->pdata->hw_strobe_option = -EINVAL;
rc = of_property_read_u32(node, "qcom,hw-strobe-option", &val);
if (!rc) {
- led->pdata->hw_strobe_option = (u8)val;
+ led->pdata->hw_strobe_option = val;
} else if (rc != -EINVAL) {
pr_err("Unable to parse hw strobe option, rc=%d\n", rc);
return rc;