From 810464bfb01b63806442c312545975ac5ca1d5d3 Mon Sep 17 00:00:00 2001 From: Shyam Kumar Thella Date: Fri, 15 May 2020 12:13:28 +0530 Subject: [PATCH 1/2] leds: qti-flash: Disable flash LED when brightness is set to 0 Disable the flash LED channel when a brightness of 0 is set. As flash/torch devices can be enabled and disabled using switch as well as from sysfs, reset the state of flash/torch devices when they are disabled instead of doing it in switch disable. Change-Id: If8ffb22d8c72a94325a1e9237778b810a152a293 Signed-off-by: Shyam Kumar Thella --- drivers/leds/leds-qti-flash.c | 47 +++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/drivers/leds/leds-qti-flash.c b/drivers/leds/leds-qti-flash.c index 319b09ab71c5..b77faa29312b 100644 --- a/drivers/leds/leds-qti-flash.c +++ b/drivers/leds/leds-qti-flash.c @@ -162,7 +162,8 @@ struct flash_switch_data { * @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 - * @ref_count : Reference count used to enable/disable flash LED + * @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 { @@ -184,7 +185,8 @@ struct qti_flash_led { u8 revision; u8 subtype; u8 max_channels; - u8 ref_count; + u8 chan_en_map; + bool module_en; bool trigger_lmh; }; @@ -289,25 +291,24 @@ static int qti_flash_led_module_control(struct qti_flash_led *led, u8 val; if (enable) { - if (!led->ref_count) { + if (!led->module_en && led->chan_en_map) { val = FLASH_MODULE_ENABLE; rc = qti_flash_led_write(led, FLASH_ENABLE_CONTROL, &val, 1); if (rc < 0) return rc; + + led->module_en = true; } - - led->ref_count++; } else { - if (led->ref_count) - led->ref_count--; - - if (!led->ref_count) { + if (led->module_en && !led->chan_en_map) { val = FLASH_MODULE_DISABLE; rc = qti_flash_led_write(led, FLASH_ENABLE_CONTROL, &val, 1); if (rc < 0) return rc; + + led->module_en = false; } } @@ -318,12 +319,16 @@ static int qti_flash_led_strobe(struct qti_flash_led *led, struct flash_switch_data *snode, u8 mask, u8 value) { - int rc; + int rc, i; bool enable = mask & value; spin_lock(&led->lock); if (enable) { + for (i = 0; i < led->max_channels; i++) + if ((mask & BIT(i)) && (value & BIT(i))) + led->chan_en_map |= BIT(i); + rc = qti_flash_led_module_control(led, enable); if (rc < 0) goto error; @@ -341,6 +346,11 @@ static int qti_flash_led_strobe(struct qti_flash_led *led, if (rc < 0) goto error; } else { + for (i = 0; i < led->max_channels; i++) + if ((led->chan_en_map & BIT(i)) && + (mask & BIT(i)) && !(value & BIT(i))) + led->chan_en_map &= ~(BIT(i)); + rc = qti_flash_led_masked_write(led, FLASH_EN_LED_CTRL, mask, value); if (rc < 0) @@ -411,6 +421,9 @@ 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; + spin_lock(&led->lock); if ((fnode->strobe_sel == HW_STROBE) && gpio_is_valid(led->hw_strobe_gpio[fnode->id])) @@ -427,6 +440,7 @@ static int qti_flash_led_disable(struct flash_node_data *fnode) if (rc < 0) goto out; + fnode->configured = false; fnode->current_ma = 0; out: @@ -454,11 +468,19 @@ 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 (brightness <= 0) { + if (!brightness) { rc = qti_flash_led_disable(fnode); - if (rc < 0) + if (rc < 0) { pr_err("Failed to set brightness %d to LED\n", brightness); + return; + } + + 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; } @@ -596,7 +618,6 @@ static int qti_flash_switch_disable(struct flash_switch_data *snode) } led_dis |= (1 << led->fnode[i].id); - led->fnode[i].configured = false; } snode->on_time_ms = 0; From 3afbba8e295cc4ec72254a3969b35b4825fbb041 Mon Sep 17 00:00:00 2001 From: Shyam Kumar Thella Date: Mon, 25 May 2020 09:03:31 +0530 Subject: [PATCH 2/2] leds: qti-flash: Disable flash LED channel after De-strobe Currently when a flash/torch device is disabled, ITARGET of the channel is programmed to 0 by qti_flash_led_disable() before the channel is de-strobed. This is causing a ramp down of the flash LED channel during disable. Fix this by programming target current to 0 only after channel is de-strobed. Change-Id: Ie566f4e75b8af8c27b7b9a828823a9bfddc48bb6 Signed-off-by: Shyam Kumar Thella --- drivers/leds/leds-qti-flash.c | 55 +++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/drivers/leds/leds-qti-flash.c b/drivers/leds/leds-qti-flash.c index b77faa29312b..790a2dc81f2b 100644 --- a/drivers/leds/leds-qti-flash.c +++ b/drivers/leds/leds-qti-flash.c @@ -469,17 +469,16 @@ static void qti_flash_led_brightness_set(struct led_classdev *led_cdev, led = fnode->led; if (!brightness) { - rc = qti_flash_led_disable(fnode); + rc = qti_flash_led_strobe(fnode->led, NULL, + FLASH_LED_ENABLE(fnode->id), 0); if (rc < 0) { - pr_err("Failed to set brightness %d to LED\n", - brightness); + pr_err("Failed to destrobe LED, rc=%d\n", rc); return; } - rc = qti_flash_led_strobe(fnode->led, NULL, - FLASH_LED_ENABLE(fnode->id), 0); + rc = qti_flash_led_disable(fnode); if (rc < 0) - pr_err("Failed to destrobe LED, rc=%d\n", rc); + pr_err("Failed to disable LED\n"); return; } @@ -600,6 +599,21 @@ static int qti_flash_switch_disable(struct flash_switch_data *snode) int rc = 0, i; u8 led_dis = 0; + for (i = 0; i < led->num_fnodes; i++) { + if (!(snode->led_mask & BIT(led->fnode[i].id)) || + !led->fnode[i].configured) + continue; + + led_dis |= BIT(led->fnode[i].id); + } + + rc = qti_flash_led_strobe(led, NULL, led_dis, ~led_dis); + if (rc < 0) { + pr_err("Failed to destrobe LEDs under with switch, rc=%d\n", + rc); + return rc; + } + for (i = 0; i < led->num_fnodes; i++) { /* * Do not turn OFF flash/torch device if @@ -607,7 +621,7 @@ static int qti_flash_switch_disable(struct flash_switch_data *snode) * ii. brightness is not configured for device under this switch */ if (!(snode->led_mask & BIT(led->fnode[i].id)) || - !led->fnode[i].configured) + !led->fnode[i].configured) continue; rc = qti_flash_led_disable(&led->fnode[i]); @@ -616,14 +630,12 @@ static int qti_flash_switch_disable(struct flash_switch_data *snode) &led->fnode[i].id); break; } - - led_dis |= (1 << led->fnode[i].id); } snode->on_time_ms = 0; snode->off_time_ms = 0; - return qti_flash_led_strobe(led, NULL, led_dis, ~led_dis); + return rc; } static void qti_flash_led_switch_brightness_set( @@ -1108,20 +1120,25 @@ static int qti_flash_strobe_set(struct led_classdev_flash *fdev, if (fnode->enabled == state) return 0; - if (!state) { - rc = qti_flash_led_disable(fnode); - if (rc < 0) { - pr_err("Failed to disable LED %u\n", fnode->id); - return rc; - } - } + if (state && !fnode->configured) + return -EINVAL; mask = FLASH_LED_ENABLE(fnode->id); value = state ? FLASH_LED_ENABLE(fnode->id) : 0; rc = qti_flash_led_strobe(fnode->led, NULL, mask, value); - if (!rc) - fnode->enabled = state; + if (rc < 0) { + pr_err("Failed to %s LED, rc=%d\n", + state ? "strobe" : "desrobe", rc); + return rc; + } + fnode->enabled = state; + + if (!state) { + rc = qti_flash_led_disable(fnode); + if (rc < 0) + pr_err("Failed to disable LED %u\n", fnode->id); + } return rc; }