Loading Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt +9 −2 Original line number Diff line number Diff line Loading @@ -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 Loading drivers/leds/leds-qpnp-flash-v2.c +88 −22 Original line number Diff line number Diff line Loading @@ -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) Loading @@ -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) Loading Loading @@ -174,6 +179,12 @@ enum { LED3, }; enum strobe_type { SW_STROBE = 0, HW_STROBE, LPG_STROBE, }; /* * Configurations for each individual LED */ Loading @@ -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; }; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; } Loading Loading @@ -981,7 +1015,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) { Loading Loading @@ -1035,13 +1069,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 || Loading @@ -1049,13 +1076,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; Loading @@ -1073,7 +1100,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) { Loading Loading @@ -1365,7 +1392,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; Loading Loading @@ -1484,14 +1511,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) { Loading @@ -1507,7 +1572,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); Loading Loading @@ -1887,9 +1952,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; Loading Loading
Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt +9 −2 Original line number Diff line number Diff line Loading @@ -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 Loading
drivers/leds/leds-qpnp-flash-v2.c +88 −22 Original line number Diff line number Diff line Loading @@ -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) Loading @@ -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) Loading Loading @@ -174,6 +179,12 @@ enum { LED3, }; enum strobe_type { SW_STROBE = 0, HW_STROBE, LPG_STROBE, }; /* * Configurations for each individual LED */ Loading @@ -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; }; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; } Loading Loading @@ -981,7 +1015,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) { Loading Loading @@ -1035,13 +1069,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 || Loading @@ -1049,13 +1076,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; Loading @@ -1073,7 +1100,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) { Loading Loading @@ -1365,7 +1392,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; Loading Loading @@ -1484,14 +1511,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) { Loading @@ -1507,7 +1572,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); Loading Loading @@ -1887,9 +1952,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; Loading