From 8dfab2b485a1aee06aec94d8320c88d7dbb3c480 Mon Sep 17 00:00:00 2001 From: Guru Das Srinagesh Date: Wed, 22 Jul 2020 10:42:34 -0700 Subject: [PATCH 01/15] leds: qti-flash: Allow dynamic symmetry current redistribution Currently, when symmetry is enabled, current redistribution occurs only when a switch is turned on after being disabled initially. Enable current redistribution to occur on the fly as long as a switch is enabled. This applies to both torch and flash devices. Illustrative example: user0 user3 Torch0 Torch3 Comment 500 0 250 250 (average of user set values) 150 0 75 75 (150 + 0 / 2) 150 100 125 125 (150 + 100 / 2). Change-Id: I5f832e4fa669a9662d45592c5c3a512df07f7255 Signed-off-by: Guru Das Srinagesh --- drivers/leds/leds-qti-flash.c | 48 ++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/drivers/leds/leds-qti-flash.c b/drivers/leds/leds-qti-flash.c index 646a2aac058f..e0483fca515a 100644 --- a/drivers/leds/leds-qti-flash.c +++ b/drivers/leds/leds-qti-flash.c @@ -117,6 +117,7 @@ struct flash_node_data { struct led_classdev_flash fdev; u32 ires_ua; u32 default_ires_ua; + u32 user_current_ma; u32 current_ma; u32 max_current; u8 duration; @@ -438,6 +439,7 @@ static int qti_flash_led_disable(struct flash_node_data *fnode) fnode->configured = false; fnode->current_ma = 0; + fnode->user_current_ma = 0; out: spin_unlock(&led->lock); @@ -450,10 +452,9 @@ static enum led_brightness qti_flash_led_brightness_get( return led_cdev->brightness; } -static void qti_flash_led_brightness_set(struct led_classdev *led_cdev, +static int __qti_flash_led_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) { - struct qti_flash_led *led = NULL; struct flash_node_data *fnode = NULL; struct led_classdev_flash *fdev = NULL; int rc; @@ -462,21 +463,20 @@ static void qti_flash_led_brightness_set(struct led_classdev *led_cdev, fdev = container_of(led_cdev, struct led_classdev_flash, led_cdev); fnode = container_of(fdev, struct flash_node_data, fdev); - led = fnode->led; if (!brightness) { rc = qti_flash_led_strobe(fnode->led, NULL, FLASH_LED_ENABLE(fnode->id), 0); if (rc < 0) { pr_err("Failed to destrobe LED, rc=%d\n", rc); - return; + return rc; } rc = qti_flash_led_disable(fnode); if (rc < 0) pr_err("Failed to disable LED\n"); - return; + return rc; } min_current_ma = DIV_ROUND_CLOSEST(fnode->ires_ua, 1000); @@ -501,10 +501,11 @@ static void qti_flash_led_brightness_set(struct led_classdev *led_cdev, rc = qti_flash_led_enable(fnode); if (rc < 0) pr_err("Failed to set brightness %d to LED\n", brightness); + + return rc; } -static int qti_flash_led_symmetry_config( - struct flash_switch_data *snode) +static int qti_flash_led_symmetry_config(struct flash_switch_data *snode) { struct qti_flash_led *led = snode->led; int i, total_curr_ma = 0, symmetric_leds = 0, per_led_curr_ma; @@ -525,7 +526,7 @@ static int qti_flash_led_symmetry_config( for (i = 0; i < led->num_fnodes; i++) { if ((snode->led_mask & BIT(led->fnode[i].id)) && (led->fnode[i].type == type)) { - total_curr_ma += led->fnode[i].current_ma; + total_curr_ma += led->fnode[i].user_current_ma; symmetric_leds++; } } @@ -549,7 +550,7 @@ static int qti_flash_led_symmetry_config( for (i = 0; i < led->num_fnodes; i++) { if (snode->led_mask & BIT(led->fnode[i].id) && led->fnode[i].type == type) { - qti_flash_led_brightness_set( + __qti_flash_led_brightness_set( &led->fnode[i].fdev.led_cdev, per_led_curr_ma); } } @@ -557,6 +558,35 @@ static int qti_flash_led_symmetry_config( return 0; } +static void qti_flash_led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct led_classdev_flash *fdev; + struct flash_node_data *fnode; + struct qti_flash_led *led; + int i, rc; + + fdev = container_of(led_cdev, struct led_classdev_flash, led_cdev); + fnode = container_of(fdev, struct flash_node_data, fdev); + led = fnode->led; + + rc = __qti_flash_led_brightness_set(led_cdev, brightness); + if (!rc) + fnode->user_current_ma = brightness; + else + return; + + for (i = 0; i < led->num_snodes; i++) { + pr_debug("snode[%d] symm %d, enabled %d\n", i, + led->snode[i].symmetry_en, + led->snode[i].enabled); + if (led->snode[i].symmetry_en && led->snode[i].enabled) { + qti_flash_led_symmetry_config(&led->snode[i]); + break; + } + } +} + static int qti_flash_switch_enable(struct flash_switch_data *snode) { struct qti_flash_led *led = snode->led; From 61cd84a09c09179691b66556f94e2c2a3a01f55d Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Mon, 27 Jul 2020 18:00:40 -0700 Subject: [PATCH 02/15] leds: qti-flash: Fix indentations and change macros to enum Fix the indentation of macro definitions, kernel-doc comments and structure member definitions. While at it, change macro definitions OTST1_IDX, OTST2_IDX and FLASH_THERMAL_LEVELS (renaming it to OTST_MAX) to enums as it seems to be appropriate and makes it more readable. Change-Id: I2c4b68e274a58c71f935cfbf07b9ba59fba90544 Signed-off-by: Subbaraman Narayanamurthy --- drivers/leds/leds-qti-flash.c | 161 ++++++++++++++++++---------------- 1 file changed, 83 insertions(+), 78 deletions(-) diff --git a/drivers/leds/leds-qti-flash.c b/drivers/leds/leds-qti-flash.c index e0483fca515a..65fb0d23690a 100644 --- a/drivers/leds/leds-qti-flash.c +++ b/drivers/leds/leds-qti-flash.c @@ -22,52 +22,52 @@ #include "leds.h" -#define FLASH_LED_REVISION1 0x00 +#define FLASH_LED_REVISION1 0x00 #define FLASH_LED_PERIPH_SUBTYPE 0x05 -#define FLASH_LED_STATUS1 0x06 +#define FLASH_LED_STATUS1 0x06 -#define FLASH_LED_STATUS2 0x07 -#define FLASH_LED_OTST1_STATUS BIT(5) -#define FLASH_LED_OTST2_STATUS BIT(4) -#define FLASH_LED_VPH_PWR_LOW BIT(0) +#define FLASH_LED_STATUS2 0x07 +#define FLASH_LED_OTST1_STATUS BIT(5) +#define FLASH_LED_OTST2_STATUS BIT(4) +#define FLASH_LED_VPH_PWR_LOW BIT(0) -#define FLASH_INT_RT_STS 0x10 -#define FLASH_LED_FAULT_RT_STS BIT(0) -#define FLASH_LED_ALL_RAMP_DN_DONE_RT_STS BIT(3) -#define FLASH_LED_ALL_RAMP_UP_DONE_RT_STS BIT(4) +#define FLASH_INT_RT_STS 0x10 +#define FLASH_LED_FAULT_RT_STS BIT(0) +#define FLASH_LED_ALL_RAMP_DN_DONE_RT_STS BIT(3) +#define FLASH_LED_ALL_RAMP_UP_DONE_RT_STS BIT(4) #define FLASH_LED_SAFETY_TIMER(id) (0x3E + id) #define FLASH_LED_SAFETY_TIMER_EN_MASK BIT(7) #define FLASH_LED_SAFETY_TIMER_EN BIT(7) #define SAFETY_TIMER_MAX_TIMEOUT_MS 1280 #define SAFETY_TIMER_MIN_TIMEOUT_MS 10 -#define SAFETY_TIMER_STEP_SIZE 10 -#define SAFETY_TIMER_DEFAULT_TIMEOUT_MS 200 +#define SAFETY_TIMER_STEP_SIZE 10 +#define SAFETY_TIMER_DEFAULT_TIMEOUT_MS 200 -#define FLASH_LED_ITARGET(id) (0x42 + id) -#define FLASH_LED_ITARGET_MASK GENMASK(6, 0) +#define FLASH_LED_ITARGET(id) (0x42 + id) +#define FLASH_LED_ITARGET_MASK GENMASK(6, 0) -#define FLASH_ENABLE_CONTROL 0x46 -#define FLASH_MODULE_ENABLE BIT(7) -#define FLASH_MODULE_DISABLE 0x0 +#define FLASH_ENABLE_CONTROL 0x46 +#define FLASH_MODULE_ENABLE BIT(7) +#define FLASH_MODULE_DISABLE 0x0 -#define FLASH_LED_IRESOLUTION 0x49 +#define FLASH_LED_IRESOLUTION 0x49 #define FLASH_LED_IRESOLUTION_MASK(id) BIT(id) -#define FLASH_LED_STROBE_CTRL(id) (0x4A + id) +#define FLASH_LED_STROBE_CTRL(id) (0x4A + id) #define FLASH_LED_STROBE_CFG_MASK GENMASK(6, 4) #define FLASH_LED_STROBE_CFG_SHIFT 4 #define FLASH_LED_HW_SW_STROBE_SEL BIT(2) #define FLASH_LED_STROBE_SEL_SHIFT 2 -#define FLASH_EN_LED_CTRL 0x4E +#define FLASH_EN_LED_CTRL 0x4E #define FLASH_LED_ENABLE(id) BIT(id) -#define FLASH_LED_DISABLE 0 +#define FLASH_LED_DISABLE 0 #define FLASH_LED_MITIGATION_SEL 0x63 -#define FLASH_LED_PREEMPTIVE_LMH_MASK GENMASK(1, 0) +#define FLASH_LED_PREEMPTIVE_LMH_MASK GENMASK(1, 0) #define FLASH_LED_LMH_MITIGATION_SW 0x2 #define FLASH_LED_THERMAL_OTST2_CFG1 0x78 @@ -77,21 +77,18 @@ #define FLASH_LED_V2_OTST1_THRSH_MIN 0x10 #define FLASH_LED_OTST2_THRSH_MIN 0x30 -#define MAX_IRES_LEVELS 2 -#define IRES_12P5_MAX_CURR_MA 1500 -#define IRES_5P0_MAX_CURR_MA 640 -#define TORCH_MAX_CURR_MA 500 -#define IRES_12P5_UA 12500 -#define IRES_5P0_UA 5000 -#define IRES_DEFAULT_UA IRES_12P5_UA -#define MAX_FLASH_CURRENT_MA 2000 +#define MAX_IRES_LEVELS 2 +#define IRES_12P5_MAX_CURR_MA 1500 +#define IRES_5P0_MAX_CURR_MA 640 +#define TORCH_MAX_CURR_MA 500 +#define IRES_12P5_UA 12500 +#define IRES_5P0_UA 5000 +#define IRES_DEFAULT_UA IRES_12P5_UA +#define MAX_FLASH_CURRENT_MA 2000 #define IBATT_OCP_THRESH_DEFAULT_UA 4500000 -#define FLASH_THERMAL_LEVELS 2 -#define OTST1_IDX 0 -#define OTST2_IDX 1 -#define OTST1_CURR_LIM_MA 200 -#define OTST2_CURR_LIM_MA 500 -#define VLED_MAX_DEFAULT_UV 3500000 +#define OTST1_CURR_LIM_MA 200 +#define OTST2_CURR_LIM_MA 500 +#define VLED_MAX_DEFAULT_UV 3500000 enum flash_led_type { FLASH_LED_TYPE_UNKNOWN, @@ -112,9 +109,15 @@ enum strobe_type { HW_STROBE, }; +enum thermal_levels { + OTST1_IDX, + OTST2_IDX, + OTST_MAX, +}; + struct flash_node_data { struct qti_flash_led *led; - struct led_classdev_flash fdev; + struct led_classdev_flash fdev; u32 ires_ua; u32 default_ires_ua; u32 user_current_ma; @@ -134,8 +137,8 @@ struct flash_node_data { struct flash_switch_data { struct qti_flash_led *led; struct led_classdev cdev; - struct hrtimer on_timer; - struct hrtimer off_timer; + struct hrtimer on_timer; + struct hrtimer off_timer; u64 on_time_ms; u64 off_time_ms; u32 led_mask; @@ -145,50 +148,52 @@ struct flash_switch_data { /** * struct qti_flash_led: Main Flash LED data structure - * @pdev : Pointer for platform device - * @regmap : Pointer for regmap structure - * @fnode : Pointer for array of child LED devices - * @snode : Pointer for array of child switch devices - * @batt_psy : Pointer for battery power supply - * @lock : Spinlock to be used for critical section - * @num_fnodes : Number of flash/torch nodes defined in device tree - * @num_snodes : Number of switch nodes defined in device tree - * @hw_strobe_gpio : Pointer for array of GPIOs for HW strobing - * @all_ramp_up_done_irq : IRQ number for all ramp up interrupt - * @all_ramp_down_done_irq : IRQ number for all ramp down interrupt - * @led_fault_irq : IRQ number for LED fault interrupt - * @max_current : Maximum current available for flash - * @thermal_derate_current : Thermal derating current limits - * @base : Base address of the flash LED module - * @revision : Revision of the flash LED module - * @subtype : Peripheral subtype of the flash LED module - * @max_channels : Maximum number of channels supported by flash module - * @chan_en_map : Bit map of individual channel enable - * @module_en : Flag used to enable/disable flash LED module - * @trigger_lmh : Flag to enable lmh mitigation + * @pdev: Pointer for platform device + * @regmap: Pointer for regmap structure + * @fnode: Pointer for array of child LED devices + * @snode: Pointer for array of child switch devices + * @batt_psy: Pointer for battery power supply + * @lock: Spinlock to be used for critical section + * @num_fnodes: Number of flash/torch nodes defined in device + * tree + * @num_snodes: Number of switch nodes defined in device tree + * @hw_strobe_gpio: Pointer for array of GPIOs for HW strobing + * @all_ramp_up_done_irq: IRQ number for all ramp up interrupt + * @all_ramp_down_done_irq: IRQ number for all ramp down interrupt + * @led_fault_irq: IRQ number for LED fault interrupt + * @max_current: Maximum current available for flash + * @thermal_derate_current: Thermal derating current limits + * @base: Base address of the flash LED module + * @revision: Revision of the flash LED module + * @subtype: Peripheral subtype of the flash LED module + * @max_channels: Maximum number of channels supported by flash + * module + * @chan_en_map: Bit map of individual channel enable + * @module_en: Flag used to enable/disable flash LED module + * @trigger_lmh: Flag to enable lmh mitigation */ struct qti_flash_led { struct platform_device *pdev; - struct regmap *regmap; + struct regmap *regmap; struct flash_node_data *fnode; - struct flash_switch_data *snode; + struct flash_switch_data *snode; struct power_supply *batt_psy; - spinlock_t lock; - u32 num_fnodes; - u32 num_snodes; - int *hw_strobe_gpio; - int all_ramp_up_done_irq; - int all_ramp_down_done_irq; - int led_fault_irq; - int max_current; - int thermal_derate_current[FLASH_THERMAL_LEVELS]; - u16 base; - u8 revision; - u8 subtype; - u8 max_channels; - u8 chan_en_map; - bool module_en; - bool trigger_lmh; + spinlock_t lock; + u32 num_fnodes; + u32 num_snodes; + int *hw_strobe_gpio; + int all_ramp_up_done_irq; + int all_ramp_down_done_irq; + int led_fault_irq; + int max_current; + int thermal_derate_current[OTST_MAX]; + u16 base; + u8 revision; + u8 subtype; + u8 max_channels; + u8 chan_en_map; + bool module_en; + bool trigger_lmh; }; struct flash_current_headroom { From ca4b79a5bb0d3c6061c58521e03fc1436153aadd Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Tue, 28 Jul 2020 20:32:51 -0700 Subject: [PATCH 03/15] leds: qti-flash: Fix LMH mitigation configuration Currently, LMH mitigation is not enabled but just the option is selected to SW. Fix it by enabling LMH mitigation properly when the user queries for maximum flash current or LED is strobed. If the module is enabled, LMH mitigation would get enabled in HW. Change-Id: Ie5d7deaa6bf3ce6ed320d62972660136a0e8095d Signed-off-by: Subbaraman Narayanamurthy --- drivers/leds/leds-qti-flash.c | 47 ++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/drivers/leds/leds-qti-flash.c b/drivers/leds/leds-qti-flash.c index 65fb0d23690a..0b19995355de 100644 --- a/drivers/leds/leds-qti-flash.c +++ b/drivers/leds/leds-qti-flash.c @@ -66,9 +66,8 @@ #define FLASH_LED_ENABLE(id) BIT(id) #define FLASH_LED_DISABLE 0 -#define FLASH_LED_MITIGATION_SEL 0x63 -#define FLASH_LED_PREEMPTIVE_LMH_MASK GENMASK(1, 0) -#define FLASH_LED_LMH_MITIGATION_SW 0x2 +#define FLASH_LED_MITIGATION_SW 0x65 +#define FLASH_LED_LMH_MITIGATION_SW_EN BIT(0) #define FLASH_LED_THERMAL_OTST2_CFG1 0x78 #define FLASH_LED_THERMAL_OTST1_CFG1 0x7A @@ -317,6 +316,23 @@ static int qti_flash_led_module_control(struct qti_flash_led *led, return rc; } +static int qti_flash_lmh_mitigation_config(struct qti_flash_led *led, + bool enable) +{ + u8 val = enable ? FLASH_LED_LMH_MITIGATION_SW_EN : 0; + int rc; + + rc = qti_flash_led_write(led, FLASH_LED_MITIGATION_SW, &val, 1); + if (rc < 0) + pr_err("Failed to %s LMH mitigation, rc=%d\n", + enable ? "enable" : "disable", rc); + else + pr_debug("%s LMH mitigation\n", + enable ? "enabled" : "disabled"); + + return rc; +} + static int qti_flash_led_strobe(struct qti_flash_led *led, struct flash_switch_data *snode, u8 mask, u8 value) @@ -343,6 +359,15 @@ static int qti_flash_led_strobe(struct qti_flash_led *led, HRTIMER_MODE_REL); } + if (led->trigger_lmh) { + rc = qti_flash_lmh_mitigation_config(led, true); + if (rc < 0) + return rc; + + /* Wait for LMH mitigation to take effect */ + udelay(500); + } + rc = qti_flash_led_masked_write(led, FLASH_EN_LED_CTRL, mask, value); if (rc < 0) @@ -358,6 +383,14 @@ static int qti_flash_led_strobe(struct qti_flash_led *led, if (rc < 0) goto error; + if (led->trigger_lmh) { + rc = qti_flash_lmh_mitigation_config(led, false); + if (rc < 0) + return rc; + + led->trigger_lmh = false; + } + rc = qti_flash_led_module_control(led, enable); if (rc < 0) goto error; @@ -870,13 +903,9 @@ static int qti_flash_led_calc_max_avail_current( vflash_vdip = VDIP_THRESH_DEFAULT_UV; if (!led->trigger_lmh) { - rc = qti_flash_led_masked_write(led, FLASH_LED_MITIGATION_SEL, - FLASH_LED_PREEMPTIVE_LMH_MASK, - FLASH_LED_LMH_MITIGATION_SW); - if (rc < 0) { - pr_err("Failed to enable LMH mitigation, rc=%d\n", rc); + rc = qti_flash_lmh_mitigation_config(led, true); + if (rc < 0) return rc; - } /* Wait for lmh mitigation to take effect */ udelay(100); From 473df1747b7e9327ea1490c51088ca6c0e558561 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Fri, 7 Aug 2020 16:31:03 -0700 Subject: [PATCH 04/15] leds: qti-flash: Fix error logging in qti_flash_led_symmetry_config() If symmetry is enabled and user sets the brightness on switch device directly without setting brightness on flash or torch devices, then an error log is printed. Fix it. Change-Id: I10cc9e3143173fb4ea9dad0ed078fde3594b6e54 Signed-off-by: Subbaraman Narayanamurthy --- drivers/leds/leds-qti-flash.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/leds/leds-qti-flash.c b/drivers/leds/leds-qti-flash.c index 0b19995355de..ad4e56618667 100644 --- a/drivers/leds/leds-qti-flash.c +++ b/drivers/leds/leds-qti-flash.c @@ -569,14 +569,14 @@ static int qti_flash_led_symmetry_config(struct flash_switch_data *snode) } } - if (symmetric_leds > 0 && total_curr_ma > 0) { - per_led_curr_ma = total_curr_ma / symmetric_leds; - } else { - pr_err("Incorrect configuration, symmetric_leds: %d total_curr_ma: %d\n", + if (!symmetric_leds || !total_curr_ma) { + pr_debug("Incorrect configuration, symmetric_leds: %d total_curr_ma: %d\n", symmetric_leds, total_curr_ma); - return -EINVAL; + return 0; } + per_led_curr_ma = total_curr_ma / symmetric_leds; + if (per_led_curr_ma == 0) { pr_warn("per_led_curr_ma cannot be 0\n"); return 0; From 1a6aa7063c21571312e3b0d4861b3bba52fd5ebc Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Mon, 10 Aug 2020 19:40:57 -0700 Subject: [PATCH 05/15] leds: qti-flash: Handle error return path properly Currently if qti_flash_lmh_mitigation_config() returns an error in qti_flash_led_strobe(), spin_unlock() is not called in the error return path. Fix it. Fixes: 42bdecad7ccd7 ("leds: qti-flash: Fix LMH mitigation configuration") Change-Id: I1bede93873a151cc9bab7f2000d8f058e1890fda Signed-off-by: Subbaraman Narayanamurthy --- drivers/leds/leds-qti-flash.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/leds/leds-qti-flash.c b/drivers/leds/leds-qti-flash.c index ad4e56618667..d95e840c633a 100644 --- a/drivers/leds/leds-qti-flash.c +++ b/drivers/leds/leds-qti-flash.c @@ -362,7 +362,7 @@ static int qti_flash_led_strobe(struct qti_flash_led *led, if (led->trigger_lmh) { rc = qti_flash_lmh_mitigation_config(led, true); if (rc < 0) - return rc; + goto error; /* Wait for LMH mitigation to take effect */ udelay(500); @@ -386,7 +386,7 @@ static int qti_flash_led_strobe(struct qti_flash_led *led, if (led->trigger_lmh) { rc = qti_flash_lmh_mitigation_config(led, false); if (rc < 0) - return rc; + goto error; led->trigger_lmh = false; } From e1d79e321d3048c5af623b4e7148097efa0612d7 Mon Sep 17 00:00:00 2001 From: Guru Das Srinagesh Date: Mon, 24 Aug 2020 14:22:00 -0700 Subject: [PATCH 06/15] leds: qti-flash: Show on_time and off_time in microseconds Adjust the units of on_time and off_time to microseconds to align with max_flash_timeout, which uses those units. Change-Id: I65f29175606d5571720215f196d2e08e6d6a18f0 Signed-off-by: Guru Das Srinagesh --- drivers/leds/leds-qti-flash.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/leds/leds-qti-flash.c b/drivers/leds/leds-qti-flash.c index d95e840c633a..db5bac5cf279 100644 --- a/drivers/leds/leds-qti-flash.c +++ b/drivers/leds/leds-qti-flash.c @@ -1102,7 +1102,7 @@ static ssize_t qti_flash_on_time_show(struct device *dev, snode = container_of(led_cdev, struct flash_switch_data, cdev); - return scnprintf(buf, PAGE_SIZE, "%lu\n", snode->on_time_ms); + return scnprintf(buf, PAGE_SIZE, "%lu\n", snode->on_time_ms * 1000); } static ssize_t qti_flash_off_time_store(struct device *dev, @@ -1133,7 +1133,7 @@ static ssize_t qti_flash_off_time_show(struct device *dev, snode = container_of(led_cdev, struct flash_switch_data, cdev); - return scnprintf(buf, PAGE_SIZE, "%lu\n", snode->off_time_ms); + return scnprintf(buf, PAGE_SIZE, "%lu\n", snode->off_time_ms * 1000); } static struct device_attribute qti_flash_led_attrs[] = { From 4404a1a342578d5b6d8f09698370ee47abb07720 Mon Sep 17 00:00:00 2001 From: Guru Das Srinagesh Date: Mon, 10 Aug 2020 13:56:46 -0700 Subject: [PATCH 07/15] leds: qti-flash: Fix early return in qti_flash_led_disable() When attempting to disable a flash node that is not configured, return gracefully as it is not an error condition. Change-Id: I3cf82eddc4ac078384a5278bd2832f7adceba853 Signed-off-by: Guru Das Srinagesh --- drivers/leds/leds-qti-flash.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/leds/leds-qti-flash.c b/drivers/leds/leds-qti-flash.c index db5bac5cf279..794bfe4d36cf 100644 --- a/drivers/leds/leds-qti-flash.c +++ b/drivers/leds/leds-qti-flash.c @@ -456,8 +456,10 @@ static int qti_flash_led_disable(struct flash_node_data *fnode) struct qti_flash_led *led = fnode->led; int rc; - if (!fnode->configured) - return -EINVAL; + if (!fnode->configured) { + pr_debug("%s is not configured\n", fnode->fdev.led_cdev.name); + return 0; + } spin_lock(&led->lock); if ((fnode->strobe_sel == HW_STROBE) && From fb86d87aa86b8d2a99c8984b8bf2d0bd9353c06b Mon Sep 17 00:00:00 2001 From: Guru Das Srinagesh Date: Mon, 14 Sep 2020 15:39:07 -0700 Subject: [PATCH 08/15] leds: qti-flash: Handle all-enabled led mask separately In certain devices, LED channels are paired and connected to two separate LEDs. Due to symmetrical configuration, a switch that controls all four channels sets the same brightness value to both LEDs, which is not the intended behaviour; hence, handle this case separately. E.g. If flash0 (group 1) is set to 144 and flash1 (group 2) is set to 1056, current will be distributed evenly to all 4 channels like so: 300 mA would be set on all channels (as 144 + 1056 = 1200; 1200 / 4 = 300). Change this to: 144 / 2 = 72 on channels 0 and 3 (group 1) 1056 / 2 = 528 on channels 1 and 2 (group 2). Change-Id: Ie135811d59104cfa5551d17ebbb729a57c101099 Signed-off-by: Guru Das Srinagesh --- drivers/leds/leds-qti-flash.c | 82 +++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 23 deletions(-) diff --git a/drivers/leds/leds-qti-flash.c b/drivers/leds/leds-qti-flash.c index 794bfe4d36cf..55b5be404150 100644 --- a/drivers/leds/leds-qti-flash.c +++ b/drivers/leds/leds-qti-flash.c @@ -89,6 +89,8 @@ #define OTST2_CURR_LIM_MA 500 #define VLED_MAX_DEFAULT_UV 3500000 +#define LED_MASK_ALL(led) GENMASK(led->max_channels - 1, 0) + enum flash_led_type { FLASH_LED_TYPE_UNKNOWN, FLASH_LED_TYPE_FLASH, @@ -170,6 +172,7 @@ struct flash_switch_data { * @chan_en_map: Bit map of individual channel enable * @module_en: Flag used to enable/disable flash LED module * @trigger_lmh: Flag to enable lmh mitigation + * @non_all_mask_switch_present: Used in handling symmetry for all_mask switch */ struct qti_flash_led { struct platform_device *pdev; @@ -193,6 +196,7 @@ struct qti_flash_led { u8 chan_en_map; bool module_en; bool trigger_lmh; + bool non_all_mask_switch_present; }; struct flash_current_headroom { @@ -545,26 +549,14 @@ static int __qti_flash_led_brightness_set(struct led_classdev *led_cdev, return rc; } -static int qti_flash_led_symmetry_config(struct flash_switch_data *snode) +static int qti_flash_config_group_symmetry(struct qti_flash_led *led, + enum flash_led_type type, + u32 led_mask) { - struct qti_flash_led *led = snode->led; - int i, total_curr_ma = 0, symmetric_leds = 0, per_led_curr_ma; - enum flash_led_type type = FLASH_LED_TYPE_UNKNOWN; - - /* Determine which LED type has triggered switch ON */ - for (i = 0; i < led->num_fnodes; i++) { - if ((snode->led_mask & BIT(led->fnode[i].id)) && - (led->fnode[i].configured)) - type = led->fnode[i].type; - } - - if (type == FLASH_LED_TYPE_UNKNOWN) { - /* No channels are configured */ - return 0; - } + int i, rc = 0, total_curr_ma = 0, symmetric_leds = 0, per_led_curr_ma; for (i = 0; i < led->num_fnodes; i++) { - if ((snode->led_mask & BIT(led->fnode[i].id)) && + if ((led_mask & BIT(led->fnode[i].id)) && (led->fnode[i].type == type)) { total_curr_ma += led->fnode[i].user_current_ma; symmetric_leds++; @@ -584,18 +576,60 @@ static int qti_flash_led_symmetry_config(struct flash_switch_data *snode) return 0; } - pr_debug("symmetric_leds: %d total: %d per_led_curr_ma: %d\n", - symmetric_leds, total_curr_ma, per_led_curr_ma); + pr_debug("mask: %#x symmetric_leds: %d total: %d per_led_curr_ma: %d\n", + led_mask, symmetric_leds, total_curr_ma, per_led_curr_ma); for (i = 0; i < led->num_fnodes; i++) { - if (snode->led_mask & BIT(led->fnode[i].id) && + if (led_mask & BIT(led->fnode[i].id) && led->fnode[i].type == type) { - __qti_flash_led_brightness_set( + rc = __qti_flash_led_brightness_set( &led->fnode[i].fdev.led_cdev, per_led_curr_ma); + if (rc < 0) + return rc; } } - return 0; + return rc; +} + +static int qti_flash_led_symmetry_config(struct flash_switch_data *snode) +{ + struct qti_flash_led *led = snode->led; + enum flash_led_type type = FLASH_LED_TYPE_UNKNOWN; + int i, rc; + + /* Determine which LED type has triggered switch ON */ + for (i = 0; i < led->num_fnodes; i++) { + if ((snode->led_mask & BIT(led->fnode[i].id)) && + (led->fnode[i].configured)) + type = led->fnode[i].type; + } + + if (type == FLASH_LED_TYPE_UNKNOWN) { + /* No channels are configured */ + return 0; + } + + if (snode->led_mask == LED_MASK_ALL(led) && + led->non_all_mask_switch_present) { + /* + * Gather masks from the other switches and configure symmetry + * accordingly. + */ + for (i = 0; i < led->num_snodes; i++) { + if (led->snode[i].led_mask != LED_MASK_ALL(led)) { + rc = qti_flash_config_group_symmetry(led, type, + led->snode[i].led_mask); + if (rc < 0) + return rc; + } + } + } else { + rc = qti_flash_config_group_symmetry(led, type, + snode->led_mask); + } + + return rc; } static void qti_flash_led_brightness_set(struct led_classdev *led_cdev, @@ -1403,10 +1437,12 @@ static int register_switch_device(struct qti_flash_led *led, pr_err("Failed to read led mask rc=%d\n", rc); return rc; } - if ((snode->led_mask > ((1 << led->max_channels) - 1))) { + if (snode->led_mask > LED_MASK_ALL(led)) { pr_err("Error, Invalid value for led-mask mask=0x%x\n", snode->led_mask); return -EINVAL; + } else if (snode->led_mask < LED_MASK_ALL(led)) { + led->non_all_mask_switch_present = true; } snode->symmetry_en = of_property_read_bool(node, "qcom,symmetry-en"); From e713399a51e970e610e5673eded07d756b82eab0 Mon Sep 17 00:00:00 2001 From: Guru Das Srinagesh Date: Thu, 17 Sep 2020 20:15:29 -0700 Subject: [PATCH 09/15] leds: qti-flash: Enable zero brightness symmetry distribution Currently, when a single channel's brightness is set, and then cleared to zero subsequently, the LED stays on instead of getting turned off because symmetrical brightness distribution logic does not allow the paired channel's brightness to be set to zero. Fix this. It was also observed that the brightness of a channel that is getting turned off doesn't show up as zero, so fix that as well. In addition, strengthen error-checking of the "qcom,led-mask" device tree property. Change-Id: I245ec2177b2ebe0f567eb96397dd13a05a587d60 Signed-off-by: Guru Das Srinagesh --- drivers/leds/leds-qti-flash.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/leds/leds-qti-flash.c b/drivers/leds/leds-qti-flash.c index 55b5be404150..78418eafbce5 100644 --- a/drivers/leds/leds-qti-flash.c +++ b/drivers/leds/leds-qti-flash.c @@ -520,6 +520,8 @@ static int __qti_flash_led_brightness_set(struct led_classdev *led_cdev, if (rc < 0) pr_err("Failed to disable LED\n"); + led_cdev->brightness = 0; + return rc; } @@ -563,19 +565,13 @@ static int qti_flash_config_group_symmetry(struct qti_flash_led *led, } } - if (!symmetric_leds || !total_curr_ma) { - pr_debug("Incorrect configuration, symmetric_leds: %d total_curr_ma: %d\n", - symmetric_leds, total_curr_ma); - return 0; + if (!symmetric_leds) { + pr_err("led-mask %#x has zero symmetric leds\n", led_mask); + return -EINVAL; } per_led_curr_ma = total_curr_ma / symmetric_leds; - if (per_led_curr_ma == 0) { - pr_warn("per_led_curr_ma cannot be 0\n"); - return 0; - } - pr_debug("mask: %#x symmetric_leds: %d total: %d per_led_curr_ma: %d\n", led_mask, symmetric_leds, total_curr_ma, per_led_curr_ma); @@ -1437,9 +1433,8 @@ static int register_switch_device(struct qti_flash_led *led, pr_err("Failed to read led mask rc=%d\n", rc); return rc; } - if (snode->led_mask > LED_MASK_ALL(led)) { - pr_err("Error, Invalid value for led-mask mask=0x%x\n", - snode->led_mask); + if (!snode->led_mask || snode->led_mask > LED_MASK_ALL(led)) { + pr_err("led-mask %#x invalid\n", snode->led_mask); return -EINVAL; } else if (snode->led_mask < LED_MASK_ALL(led)) { led->non_all_mask_switch_present = true; From 0ac549f68c1707e9de99911e2a29aa0158229ac4 Mon Sep 17 00:00:00 2001 From: Guru Das Srinagesh Date: Wed, 23 Sep 2020 08:47:15 -0700 Subject: [PATCH 10/15] leds: qti-flash: Initialize rc in qti_flash_led_symmetry_config() Initialize rc just for sanity so that it is not used uninitialized in the return path. Fixes: 568fc7ac9b69 ("leds: qti-flash: Handle all-enabled led mask separately") Change-Id: I77caac87781b7a2ad2de0ecb13c5b3cd9ca3707b Signed-off-by: Guru Das Srinagesh --- drivers/leds/leds-qti-flash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/leds/leds-qti-flash.c b/drivers/leds/leds-qti-flash.c index 78418eafbce5..3e5eeade377a 100644 --- a/drivers/leds/leds-qti-flash.c +++ b/drivers/leds/leds-qti-flash.c @@ -592,7 +592,7 @@ static int qti_flash_led_symmetry_config(struct flash_switch_data *snode) { struct qti_flash_led *led = snode->led; enum flash_led_type type = FLASH_LED_TYPE_UNKNOWN; - int i, rc; + int i, rc = 0; /* Determine which LED type has triggered switch ON */ for (i = 0; i < led->num_fnodes; i++) { From 24ca52d06d445006481357cedc7cae4727cf440c Mon Sep 17 00:00:00 2001 From: Anjelique Melendez Date: Mon, 18 Oct 2021 10:00:57 -0700 Subject: [PATCH 11/15] leds: qti-flash: Skip configuring a LED channel if it's configured already Currently, brightness for a torch/flash device can be set on a channel that's already configured for a flash/torch device that shared the same LED channel. Though the target current configured at the end for that channel is correct, there is a transitional behavior where the channel can be disabled and enabled again. Fix this by not allowing the brightness to be set if it's attempted for the same channel id but another type (flash or torch) is configured before. Change-Id: I3ae5990121af1302e14dc2bd14f9baa178dd0cd2 Signed-off-by: Anjelique Melendez --- drivers/leds/leds-qti-flash.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/leds/leds-qti-flash.c b/drivers/leds/leds-qti-flash.c index 3e5eeade377a..ec1672bd3bf3 100644 --- a/drivers/leds/leds-qti-flash.c +++ b/drivers/leds/leds-qti-flash.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "qti-flash: %s: " fmt, __func__ @@ -239,6 +239,22 @@ static int current_to_code(u32 target_curr_ma, u32 ires_ua) return DIV_ROUND_CLOSEST(target_curr_ma * 1000, ires_ua) - 1; } +static bool is_channel_configured(struct flash_node_data *fnode) +{ + int i; + + for (i = 0; i < fnode->led->num_fnodes; i++) { + if (fnode->led->fnode[i].id == fnode->id && + fnode->led->fnode[i].type != fnode->type && + fnode->led->fnode[i].configured) { + pr_debug("Channel %d for %s is already configured by %s\n", fnode->id, + fnode->fdev.led_cdev.name, fnode->led->fnode[i].fdev.led_cdev.name); + return true; + } + } + return false; +} + static int qti_flash_led_read(struct qti_flash_led *led, u16 offset, u8 *data, u8 len) { @@ -640,6 +656,9 @@ static void qti_flash_led_brightness_set(struct led_classdev *led_cdev, fnode = container_of(fdev, struct flash_node_data, fdev); led = fnode->led; + if (is_channel_configured(fnode)) + return; + rc = __qti_flash_led_brightness_set(led_cdev, brightness); if (!rc) fnode->user_current_ma = brightness; From 5d3ac1aac33768139f72f18f2418f7aec22a6db2 Mon Sep 17 00:00:00 2001 From: Anjelique Melendez Date: Fri, 19 Nov 2021 16:11:57 -0800 Subject: [PATCH 12/15] leds: led-qti-flash: Make interrupts optional Currently interrupts are required in flash LED driver but are only used for debugging purposes. Allow interrupts to be optional. Change-Id: I40f86a2543e836124e6fb358731076f63f1774f3 Signed-off-by: Anjelique Melendez --- drivers/leds/leds-qti-flash.c | 51 ++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/drivers/leds/leds-qti-flash.c b/drivers/leds/leds-qti-flash.c index ec1672bd3bf3..b5196d501ade 100644 --- a/drivers/leds/leds-qti-flash.c +++ b/drivers/leds/leds-qti-flash.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. */ #define pr_fmt(fmt) "qti-flash: %s: " fmt, __func__ @@ -1397,32 +1398,38 @@ static int qti_flash_led_register_interrupts(struct qti_flash_led *led) { int rc; - rc = devm_request_threaded_irq(&led->pdev->dev, - led->all_ramp_up_done_irq, NULL, qti_flash_led_irq_handler, - IRQF_ONESHOT, "flash_all_ramp_up", led); - if (rc < 0) { - pr_err("Failed to request all_ramp_up_done(%d) IRQ(err:%d)\n", - led->all_ramp_up_done_irq, rc); - return rc; + if (led->all_ramp_up_done_irq >= 0) { + rc = devm_request_threaded_irq(&led->pdev->dev, + led->all_ramp_up_done_irq, NULL, qti_flash_led_irq_handler, + IRQF_ONESHOT, "flash_all_ramp_up", led); + if (rc < 0) { + pr_err("Failed to request all_ramp_up_done(%d) IRQ(err:%d)\n", + led->all_ramp_up_done_irq, rc); + return rc; + } } - rc = devm_request_threaded_irq(&led->pdev->dev, - led->all_ramp_down_done_irq, NULL, qti_flash_led_irq_handler, - IRQF_ONESHOT, "flash_all_ramp_down", led); - if (rc < 0) { - pr_err("Failed to request all_ramp_down_done(%d) IRQ(err:%d)\n", - led->all_ramp_down_done_irq, - rc); - return rc; + if (led->all_ramp_down_done_irq >= 0) { + rc = devm_request_threaded_irq(&led->pdev->dev, + led->all_ramp_down_done_irq, NULL, qti_flash_led_irq_handler, + IRQF_ONESHOT, "flash_all_ramp_down", led); + if (rc < 0) { + pr_err("Failed to request all_ramp_down_done(%d) IRQ(err:%d)\n", + led->all_ramp_down_done_irq, + rc); + return rc; + } } - rc = devm_request_threaded_irq(&led->pdev->dev, - led->led_fault_irq, NULL, qti_flash_led_irq_handler, - IRQF_ONESHOT, "flash_fault", led); - if (rc < 0) { - pr_err("Failed to request led_fault(%d) IRQ(err:%d)\n", - led->led_fault_irq, rc); - return rc; + if (led->led_fault_irq >= 0) { + rc = devm_request_threaded_irq(&led->pdev->dev, + led->led_fault_irq, NULL, qti_flash_led_irq_handler, + IRQF_ONESHOT, "flash_fault", led); + if (rc < 0) { + pr_err("Failed to request led_fault(%d) IRQ(err:%d)\n", + led->led_fault_irq, rc); + return rc; + } } return 0; From 749dacbb8b2282b20cc964fcd56a482ee0532c8d Mon Sep 17 00:00:00 2001 From: Anjelique Melendez Date: Mon, 22 Nov 2021 11:41:28 -0800 Subject: [PATCH 13/15] leds: leds-qti-flash: Add support for qcom,secure-vm Currently, to calculate max_avail_current, parameters from battery power supply are needed. These parameters are provided by battery_charger driver, which on some platforms need to be obtained from charger FW. Add a new property "qcom,secure-vm" which if specified for a secure VM would provide a fixed max_avail_current to support camera SW requirements. Change-Id: I7ac19765470406edf693a5ce92c499f2d7f81511 Signed-off-by: Anjelique Melendez --- drivers/leds/leds-qti-flash.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/leds/leds-qti-flash.c b/drivers/leds/leds-qti-flash.c index b5196d501ade..6dec71bd306f 100644 --- a/drivers/leds/leds-qti-flash.c +++ b/drivers/leds/leds-qti-flash.c @@ -174,6 +174,8 @@ struct flash_switch_data { * @module_en: Flag used to enable/disable flash LED module * @trigger_lmh: Flag to enable lmh mitigation * @non_all_mask_switch_present: Used in handling symmetry for all_mask switch + * @secure_vm: Flag indicating whether flash LED is used by + * secure VM */ struct qti_flash_led { struct platform_device *pdev; @@ -198,6 +200,7 @@ struct qti_flash_led { bool module_en; bool trigger_lmh; bool non_all_mask_switch_present; + bool secure_vm; }; struct flash_current_headroom { @@ -1043,6 +1046,11 @@ static int qti_flash_led_get_max_avail_current( { int thermal_current_limit = 0, rc; + if (led->secure_vm) { + led->max_current = MAX_FLASH_CURRENT_MA; + return 0; + } + led->trigger_lmh = false; rc = qti_flash_led_calc_max_avail_current(led, max_current_ma); if (rc < 0) { @@ -1702,6 +1710,8 @@ static int qti_flash_led_register_device(struct qti_flash_led *led, } + led->secure_vm = of_property_read_bool(node, "qcom,secure-vm"); + led->all_ramp_up_done_irq = of_irq_get_byname(node, "all-ramp-up-done-irq"); if (led->all_ramp_up_done_irq < 0) From 17ef00fb6d234c8b5993e2d01dc08da2945a5a07 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Wed, 24 Nov 2021 11:53:14 +0530 Subject: [PATCH 14/15] leds: qti-flash: Update LMH mitigation configuration for qti flash Based on the HW recommendation, LMH mitigation needs to be enabled only when LEDs are used in flash mode with a total current greater than or equal to 1A. Update support for the same. Change-Id: I926a021dc7e864dea402d88d8bb2cf1d6ed580f7 Signed-off-by: Jishnu Prakash [quic_subbaram@quicinc.com: Fix trivial merge conflict] Signed-off-by: Subbaraman Narayanamurthy --- drivers/leds/leds-qti-flash.c | 62 +++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/drivers/leds/leds-qti-flash.c b/drivers/leds/leds-qti-flash.c index 6dec71bd306f..bbb9633106d1 100644 --- a/drivers/leds/leds-qti-flash.c +++ b/drivers/leds/leds-qti-flash.c @@ -346,13 +346,18 @@ static int qti_flash_lmh_mitigation_config(struct qti_flash_led *led, u8 val = enable ? FLASH_LED_LMH_MITIGATION_SW_EN : 0; int rc; + if (enable == led->trigger_lmh) + return 0; + rc = qti_flash_led_write(led, FLASH_LED_MITIGATION_SW, &val, 1); - if (rc < 0) + if (rc < 0) { pr_err("Failed to %s LMH mitigation, rc=%d\n", enable ? "enable" : "disable", rc); - else + } else { pr_debug("%s LMH mitigation\n", enable ? "enabled" : "disabled"); + led->trigger_lmh = enable; + } return rc; } @@ -383,15 +388,6 @@ static int qti_flash_led_strobe(struct qti_flash_led *led, HRTIMER_MODE_REL); } - if (led->trigger_lmh) { - rc = qti_flash_lmh_mitigation_config(led, true); - if (rc < 0) - goto error; - - /* Wait for LMH mitigation to take effect */ - udelay(500); - } - rc = qti_flash_led_masked_write(led, FLASH_EN_LED_CTRL, mask, value); if (rc < 0) @@ -411,8 +407,6 @@ static int qti_flash_led_strobe(struct qti_flash_led *led, rc = qti_flash_lmh_mitigation_config(led, false); if (rc < 0) goto error; - - led->trigger_lmh = false; } rc = qti_flash_led_module_control(led, enable); @@ -680,10 +674,13 @@ static void qti_flash_led_brightness_set(struct led_classdev *led_cdev, } } +#define FLASH_LMH_TRIGGER_LIMIT_MA 1000 + static int qti_flash_switch_enable(struct flash_switch_data *snode) { struct qti_flash_led *led = snode->led; - int rc = 0, i; + int rc = 0, total_curr_ma = 0, i; + enum flash_led_type type = FLASH_LED_TYPE_UNKNOWN; u8 led_en = 0; /* If symmetry enabled switch, then turn ON all its LEDs */ @@ -706,9 +703,32 @@ static int qti_flash_switch_enable(struct flash_switch_data *snode) !led->fnode[i].configured) continue; + /* + * For flash, LMH mitigation needs to be enabled + * if total current used is greater than or + * equal to 1A. + */ + + type = led->fnode[i].type; + if (type == FLASH_LED_TYPE_FLASH) + total_curr_ma += led->fnode[i].user_current_ma; + led_en |= (1 << led->fnode[i].id); } + if (total_curr_ma >= FLASH_LMH_TRIGGER_LIMIT_MA) { + rc = qti_flash_lmh_mitigation_config(led, true); + if (rc < 0) + return rc; + + /* Wait for lmh mitigation to take effect */ + udelay(500); + } else if (led->trigger_lmh) { + rc = qti_flash_lmh_mitigation_config(led, false); + if (rc < 0) + return rc; + } + return qti_flash_led_strobe(led, snode, snode->led_mask, led_en); } @@ -957,19 +977,6 @@ static int qti_flash_led_calc_max_avail_current( voltage_hdrm_mv = qti_flash_led_get_voltage_headroom(led); vflash_vdip = VDIP_THRESH_DEFAULT_UV; - if (!led->trigger_lmh) { - rc = qti_flash_lmh_mitigation_config(led, true); - if (rc < 0) - return rc; - - /* Wait for lmh mitigation to take effect */ - udelay(100); - - led->trigger_lmh = true; - return qti_flash_led_calc_max_avail_current(led, - max_current_ma); - } - ibatt_safe_ua = DIV_ROUND_CLOSEST((ocv_uv - (vflash_vdip + VFLASH_DIP_MARGIN_UV)) * UCONV, rbatt_uohm); @@ -1051,7 +1058,6 @@ static int qti_flash_led_get_max_avail_current( return 0; } - led->trigger_lmh = false; rc = qti_flash_led_calc_max_avail_current(led, max_current_ma); if (rc < 0) { pr_err("Failed to calculate max avail current, rc=%d\n", rc); From d356880fb9d2b7581ae5bc4c3d18fb42bd4e8cef Mon Sep 17 00:00:00 2001 From: David Collins Date: Fri, 27 May 2022 15:23:15 -0700 Subject: [PATCH 15/15] leds: leds-qti-flash: update locking used for trigger iteration Commit 2a5a8fa8b231 ("leds: trigger: use RCU to protect the led_cdevs list") changed the locking mechanism for the led_cdevs list. Update the locking in the leds-qti-flash driver to match. Change-Id: I54b044052134b29f56cbf18ad2d37832d89eba55 Signed-off-by: David Collins --- drivers/leds/leds-qti-flash.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/leds/leds-qti-flash.c b/drivers/leds/leds-qti-flash.c index bbb9633106d1..95b941d5d199 100644 --- a/drivers/leds/leds-qti-flash.c +++ b/drivers/leds/leds-qti-flash.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #define pr_fmt(fmt) "qti-flash: %s: " fmt, __func__ @@ -819,15 +819,15 @@ static struct led_classdev *trigger_to_lcdev(struct led_trigger *trig) { struct led_classdev *led_cdev; - read_lock(&trig->leddev_list_lock); - list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) { + rcu_read_lock(); + list_for_each_entry_rcu(led_cdev, &trig->led_cdevs, trig_list) { if (!strcmp(led_cdev->default_trigger, trig->name)) { - read_unlock(&trig->leddev_list_lock); + rcu_read_unlock(); return led_cdev; } } + rcu_read_unlock(); - read_unlock(&trig->leddev_list_lock); return NULL; }