Merge "leds: qpnp-flash-v2: Add support for LPG strobe"

This commit is contained in:
Linux Build Service Account 2017-05-26 00:09:34 -07:00 committed by Gerrit - the friendly Code Review server
commit b4f36ef221
2 changed files with 97 additions and 24 deletions

View file

@ -169,8 +169,15 @@ Optional properties:
sleep configuration defined for each pin or pin group.
- qcom,hw-strobe-gpio : phandle to specify GPIO for hardware strobing. This is used when there is no
pinctrl support or PMIC GPIOs are used.
- qcom,hw-strobe-sel : Boolean property to enable hardware strobe. If not defined, software strobe
will be used.
- qcom,strobe-sel : Property to select strobe type. If not defined,
software strobe will be used. Allowed options are:
0 - SW strobe
1 - HW strobe
2 - LPG strobe
LPG strobe is supported only for LED3.
If LPG strobe is specified, then strobe control is
configured for active high and level triggered. Also
qcom,hw-strobe-option should be set to 1 or 2.
- qcom,hw-strobe-edge-trigger : Boolean property to select trigger type. If defined, hw-strobe is set to
be edge triggered. Otherwise, it is level triggered.
- qcom,hw-strobe-active-low : Boolean property to select strobe signal polarity. If defined, hw-strobe

View file

@ -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;