* [PATCH v6 0/3] Samsung Expressatt: Camera Flash
@ 2026-05-28 2:34 Rudraksha Gupta via B4 Relay
2026-05-28 2:34 ` [PATCH v6 1/3] dt-bindings: leds: rt8515: Support single-GPIO flash ICs with vin supply Rudraksha Gupta via B4 Relay
` (3 more replies)
0 siblings, 4 replies; 8+ messages in thread
From: Rudraksha Gupta via B4 Relay @ 2026-05-28 2:34 UTC (permalink / raw)
To: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bjorn Andersson, Konrad Dybcio,
Liam Girdwood, Mark Brown
Cc: linux-leds, devicetree, linux-kernel, linux-arm-msm, phone-devel,
Rudraksha Gupta, Conor Dooley, David Heidelberg, Konrad Dybcio
This small series adds camera flash to an existing similar mainline
driver and adds it to the Samsung Expressatt's DTS
// Tests
// # Navigate to LED
sudo su
cd /sys/class/leds/white:flash
// # Should stay at dim brightness
echo 1 > brightness
echo 1 > brightness
echo 1 > brightness
echo 1 > brightness
echo 0 > brightness # LED_OFF
// # Max Brightness
echo 50 > brightness
echo 0 > brightness # LED_OFF
echo 99 > brightness
echo 0 > brightness # LED_OFF
echo 1000 > brightness
echo 0 > brightness # LED_OFF
echo 100 > brightness
echo 0 > brightness # LED_OFF
// # Should increase in brightness
for i in $(seq 1 16); do echo $i > brightness; sleep 1; done
echo 0 > brightness # LED_OFF
// # Test flash strobe (rt8515_led_flash_strobe_set)
cat max_flash_timeout # check max
echo 200000 > flash_timeout # 200ms
echo 1 > flash_strobe # strobe ON → brightness_commit + timer
cat flash_strobe # should read 1, then 0 after timeout
sleep 1
cat flash_strobe # should be 0 (timer fired)
// # Test manual strobe cancel
echo 1 > flash_strobe ; echo 0 > flash_strobe # immediate off
// # Check regulator error handling
dmesg | tail -20 # look for any "failed to turn off LED" msgs
// # Multiple strobes shouldn't cause errors
echo 200000 > flash_timeout
echo 1 > flash_strobe
echo 1 > flash_strobe
sleep 1
cat flash_strobe
dmesg | tail -20
// # Multiple strobes shouldn't cause errors (extreme test)
for i in $(seq 1 500); do echo 1 > flash_strobe; echo 0 > flash_strobe; done
dmesg | tail -20
// # Test minimal timeout (turns on briefly)
echo 1 > flash_timeout
echo 1 > flash_strobe
sleep 0.1
cat flash_strobe
dmesg | tail -20
// # Flash strobe overrides brightness and flashes at full brightness
echo 200000 > flash_timeout
echo 1 > brightness
echo 1 > flash_strobe
sleep 1
cat flash_strobe
cat brightness
dmesg | tail -20
Downstream reference:
Link: https://github.com/LineageOS/android_kernel_samsung_d2/blob/stable/cm-12.0-YNG4N/drivers/leds/Makefile#L51
Link: https://github.com/LineageOS/android_kernel_samsung_d2/blob/stable/cm-12.0-YNG4N/arch/arm/mach-msm/board-apexq-camera.c#L591
Signed-off-by: Rudraksha Gupta <guptarud@gmail.com>
---
Changes in v6:
- Address Lee Jones's comments:
- formatting
- use cancel_delayed_work_sync()
- Link to v5: https://lore.kernel.org/r/20260503-expressatt_camera_flash-v5-0-95524506a799@gmail.com
Changes in v5:
- Address Lee Jones's comments:
- formatting
- use devm_regulator_get_optional()
- use a workqueue instead of a timer
- previously we were validating ent-gpios xor vin-supply at probe,
but was removed. update the commit msg to reflect this
- Link to v4: https://lore.kernel.org/r/20260331-expressatt_camera_flash-v4-0-f1e99f474513@gmail.com
Changes in v4:
- Driver:
- revert function renames
- add comment to use flash instead if torch pin not available
- Link to v3: https://lore.kernel.org/r/20260326-expressatt_camera_flash-v3-0-e75e5d58990f@gmail.com
Changes in v3:
- DTS:
- Renamed and reordered nodes
- Driver:
- Use regulator_is_enabled() instead of reg_enabled
- remove ent xor vin check
- remove rt->reg == -ENODEV check
- rename functions to reflect what they do and added ret's
- Fixed: LED was increasing in brightness when setting the same
brightness multiple times
- Link to v2: https://lore.kernel.org/r/20260318-expressatt_camera_flash-v2-0-5c2b9a623dcb@gmail.com
Changes in v2:
- dt-bindings: Explain the hardware and not the driver
- **/*: Use vin-supply instead of unlock-gpio
- expressatt DTS: Reorder pinctrl-*
- expressatt DTS: Define rfs-ohms to a default (couldn't find
information about this)
- Link to v1: https://lore.kernel.org/r/20260306-expressatt_camera_flash-v1-0-b1996f7cdfdd@gmail.com
---
Rudraksha Gupta (3):
dt-bindings: leds: rt8515: Support single-GPIO flash ICs with vin supply
leds: flash: rt8515: Support single-GPIO flash ICs with vin supply
ARM: dts: qcom: msm8960: expressatt: Add camera flash
.../devicetree/bindings/leds/richtek,rt8515.yaml | 34 ++++-
.../dts/qcom/qcom-msm8960-samsung-expressatt.dts | 43 ++++++
drivers/leds/flash/leds-rt8515.c | 148 ++++++++++++++++-----
3 files changed, 188 insertions(+), 37 deletions(-)
---
base-commit: 3131ff5a117498bb4b9db3a238bb311cbf8383ce
change-id: 20260306-expressatt_camera_flash-13c15a7427aa
prerequisite-message-id: <20260527-expressatt-touchkey-v2-1-049dca41fc3a@gmail.com>
prerequisite-patch-id: 2b24e9ba47500ef05d38e37b40d8ca2dceb4716a
Best regards,
--
Rudraksha Gupta <guptarud@gmail.com>
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v6 1/3] dt-bindings: leds: rt8515: Support single-GPIO flash ICs with vin supply 2026-05-28 2:34 [PATCH v6 0/3] Samsung Expressatt: Camera Flash Rudraksha Gupta via B4 Relay @ 2026-05-28 2:34 ` Rudraksha Gupta via B4 Relay 2026-05-28 2:34 ` [PATCH v6 2/3] leds: flash: " Rudraksha Gupta via B4 Relay ` (2 subsequent siblings) 3 siblings, 0 replies; 8+ messages in thread From: Rudraksha Gupta via B4 Relay @ 2026-05-28 2:34 UTC (permalink / raw) To: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij, Bjorn Andersson, Konrad Dybcio, Liam Girdwood, Mark Brown Cc: linux-leds, devicetree, linux-kernel, linux-arm-msm, phone-devel, Rudraksha Gupta, Conor Dooley From: Rudraksha Gupta <guptarud@gmail.com> Some flash ICs use the same one-wire pulse-count protocol as the RT8515 but have only a single enable line for both flash and torch modes, plus an optional input voltage supply (e.g. a GPIO-controlled fixed regulator) that gates power to the chip. Make ent-gpios optional and add a vin-supply property to support these variants. Add a oneOf constraint requiring exactly one of ent-gpios or vin-supply. Add a binding example showing the single-GPIO configuration with an input supply. Assisted-by: Claude:claude-opus-4.6 Acked-by: Conor Dooley <conor.dooley@microchip.com> Reviewed-by: Linus Walleij <linusw@kernel.org> Signed-off-by: Rudraksha Gupta <guptarud@gmail.com> --- .../devicetree/bindings/leds/richtek,rt8515.yaml | 34 +++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/leds/richtek,rt8515.yaml b/Documentation/devicetree/bindings/leds/richtek,rt8515.yaml index 0356371a6b01..ab3c5139132c 100644 --- a/Documentation/devicetree/bindings/leds/richtek,rt8515.yaml +++ b/Documentation/devicetree/bindings/leds/richtek,rt8515.yaml @@ -15,6 +15,10 @@ description: | current for each mode is defined in hardware using two resistors RFS and RTS. + Some flash ICs use the same one-wire pulse-count protocol but have + only a single enable line for both flash and torch modes. For these + single-channel variants, only enf-gpios is needed. + properties: compatible: const: richtek,rt8515 @@ -26,6 +30,11 @@ properties: ent-gpios: maxItems: 1 description: A connection to the 'ENT' (enable torch) pin. + Not present on single-channel flash ICs that use only one enable + line for both flash and torch modes. + + vin-supply: + description: Optional input supply for the flash IC. richtek,rfs-ohms: minimum: 7680 @@ -81,10 +90,15 @@ properties: required: - compatible - - ent-gpios - enf-gpios - led +oneOf: + - required: + - ent-gpios + - required: + - vin-supply + additionalProperties: false examples: @@ -108,4 +122,22 @@ examples: }; }; + - | + /* Single-channel flash IC with input supply */ + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/leds/common.h> + + led-controller { + compatible = "richtek,rt8515"; + enf-gpios = <&tlmm 3 GPIO_ACTIVE_HIGH>; + vin-supply = <&flash_reg>; + richtek,rfs-ohms = <16000>; + + led { + function = LED_FUNCTION_FLASH; + color = <LED_COLOR_ID_WHITE>; + flash-max-timeout-us = <250000>; + }; + }; + ... -- 2.54.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v6 2/3] leds: flash: rt8515: Support single-GPIO flash ICs with vin supply 2026-05-28 2:34 [PATCH v6 0/3] Samsung Expressatt: Camera Flash Rudraksha Gupta via B4 Relay 2026-05-28 2:34 ` [PATCH v6 1/3] dt-bindings: leds: rt8515: Support single-GPIO flash ICs with vin supply Rudraksha Gupta via B4 Relay @ 2026-05-28 2:34 ` Rudraksha Gupta via B4 Relay 2026-08-13 10:27 ` Lee Jones 2026-05-28 2:34 ` [PATCH v6 3/3] ARM: dts: qcom: msm8960: expressatt: Add camera flash Rudraksha Gupta via B4 Relay 2026-08-11 9:31 ` [PATCH v6 0/3] Samsung Expressatt: Camera Flash Rudraksha Gupta 3 siblings, 1 reply; 8+ messages in thread From: Rudraksha Gupta via B4 Relay @ 2026-05-28 2:34 UTC (permalink / raw) To: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij, Bjorn Andersson, Konrad Dybcio, Liam Girdwood, Mark Brown Cc: linux-leds, devicetree, linux-kernel, linux-arm-msm, phone-devel, Rudraksha Gupta From: Rudraksha Gupta <guptarud@gmail.com> Extend the RT8515 driver to support flash ICs that use only a single GPIO for both flash and torch modes (no separate ENT pin), with an optional vin regulator that gates power to the flash IC. When vin-supply is provided, the driver enables the regulator before activating the LED and disables it when turning off. Make ent-gpios optional. When ent-gpios is absent, the driver uses enf-gpios for both flash and torch brightness control. Assisted-by: Claude:claude-opus-4.6 Reviewed-by: Linus Walleij <linusw@kernel.org> Signed-off-by: Rudraksha Gupta <guptarud@gmail.com> --- drivers/leds/flash/leds-rt8515.c | 148 +++++++++++++++++++++++++++++---------- 1 file changed, 112 insertions(+), 36 deletions(-) diff --git a/drivers/leds/flash/leds-rt8515.c b/drivers/leds/flash/leds-rt8515.c index f6b439674c03..0fb84d98211d 100644 --- a/drivers/leds/flash/leds-rt8515.c +++ b/drivers/leds/flash/leds-rt8515.c @@ -31,6 +31,7 @@ #include <linux/platform_device.h> #include <linux/property.h> #include <linux/regulator/consumer.h> +#include <linux/workqueue.h> #include <media/v4l2-flash-led-class.h> @@ -44,6 +45,9 @@ #define RT8515_TIMEOUT_US 250000U #define RT8515_MAX_TIMEOUT_US 300000U +#define RT8515_OFF 0 +#define RT8515_ON 1 + struct rt8515 { struct led_classdev_flash fled; struct device *dev; @@ -52,7 +56,7 @@ struct rt8515 { struct regulator *reg; struct gpio_desc *enable_torch; struct gpio_desc *enable_flash; - struct timer_list powerdown_timer; + struct delayed_work powerdown_work; u32 max_timeout; /* Flash max timeout */ int flash_max_intensity; int torch_max_intensity; @@ -63,27 +67,57 @@ static struct rt8515 *to_rt8515(struct led_classdev_flash *fled) return container_of(fled, struct rt8515, fled); } -static void rt8515_gpio_led_off(struct rt8515 *rt) +static int rt8515_gpio_led_off(struct rt8515 *rt) { - gpiod_set_value(rt->enable_flash, 0); - gpiod_set_value(rt->enable_torch, 0); + int ret = 0; + + gpiod_set_value(rt->enable_flash, RT8515_OFF); + gpiod_set_value(rt->enable_torch, RT8515_OFF); + + if (!rt->reg) + return ret; + + ret = regulator_is_enabled(rt->reg); + if (ret > 0) + ret = regulator_disable(rt->reg); + + return ret; } -static void rt8515_gpio_brightness_commit(struct gpio_desc *gpiod, - int brightness) +static int rt8515_gpio_brightness_commit(struct rt8515 *rt, struct gpio_desc *gpiod, int brightness) { int i; + int ret; + + /* + * Reset the IC to start brightness from zero, + * then re-enable and pulse to the desired level. + */ + ret = rt8515_gpio_led_off(rt); + if (ret) + return ret; + + /* IC needs time to reset its brightness counter */ + usleep_range(100, 200); + + if (rt->reg) { + ret = regulator_enable(rt->reg); + if (ret) + return ret; + } /* * Toggling a GPIO line with a small delay increases the * brightness one step at a time. */ for (i = 0; i < brightness; i++) { - gpiod_set_value(gpiod, 0); + gpiod_set_value(gpiod, RT8515_OFF); udelay(1); - gpiod_set_value(gpiod, 1); + gpiod_set_value(gpiod, RT8515_ON); udelay(1); } + + return 0; } /* This is setting the torch light level */ @@ -92,23 +126,38 @@ static int rt8515_led_brightness_set(struct led_classdev *led, { struct led_classdev_flash *fled = lcdev_to_flcdev(led); struct rt8515 *rt = to_rt8515(fled); + int ret = 0; mutex_lock(&rt->lock); if (brightness == LED_OFF) { /* Off */ - rt8515_gpio_led_off(rt); + ret = rt8515_gpio_led_off(rt); + if (ret) + goto out; } else if (brightness < RT8515_TORCH_MAX) { - /* Step it up to movie mode brightness using the flash pin */ - rt8515_gpio_brightness_commit(rt->enable_torch, brightness); + /* + * Step it up to movie mode brightness. + * If there is no separate torch pin, use the flash pin + * for torch as well. + */ + ret = rt8515_gpio_brightness_commit(rt, + rt->enable_torch ?: rt->enable_flash, brightness); + if (ret) + goto out; } else { - /* Max torch brightness requested */ - gpiod_set_value(rt->enable_torch, 1); + /* + * Max torch brightness requested. + * If there is no separate torch pin, use the flash pin + * for torch as well. + */ + gpiod_set_value(rt->enable_torch ?: rt->enable_flash, RT8515_ON); } +out: mutex_unlock(&rt->lock); - return 0; + return ret; } static int rt8515_led_flash_strobe_set(struct led_classdev_flash *fled, @@ -117,27 +166,36 @@ static int rt8515_led_flash_strobe_set(struct led_classdev_flash *fled, struct rt8515 *rt = to_rt8515(fled); struct led_flash_setting *timeout = &fled->timeout; int brightness = rt->flash_max_intensity; + int ret = 0; - mutex_lock(&rt->lock); - - if (state) { - /* Enable LED flash mode and set brightness */ - rt8515_gpio_brightness_commit(rt->enable_flash, brightness); - /* Set timeout */ - mod_timer(&rt->powerdown_timer, - jiffies + usecs_to_jiffies(timeout->val)); - } else { - timer_delete_sync(&rt->powerdown_timer); + if (!state) { + cancel_delayed_work_sync(&rt->powerdown_work); + mutex_lock(&rt->lock); /* Turn the LED off */ - rt8515_gpio_led_off(rt); + ret = rt8515_gpio_led_off(rt); + if (!ret) + fled->led_cdev.brightness = LED_OFF; + mutex_unlock(&rt->lock); + return ret; } + mutex_lock(&rt->lock); + + /* Enable LED flash mode and set brightness */ + ret = rt8515_gpio_brightness_commit(rt, rt->enable_flash, brightness); + if (ret) + goto out; + + /* Set timeout */ + schedule_delayed_work(&rt->powerdown_work, usecs_to_jiffies(timeout->val)); + fled->led_cdev.brightness = LED_OFF; /* After this the torch LED will be disabled */ +out: mutex_unlock(&rt->lock); - return 0; + return ret; } static int rt8515_led_flash_strobe_get(struct led_classdev_flash *fled, @@ -145,7 +203,7 @@ static int rt8515_led_flash_strobe_get(struct led_classdev_flash *fled, { struct rt8515 *rt = to_rt8515(fled); - *state = timer_pending(&rt->powerdown_timer); + *state = delayed_work_pending(&rt->powerdown_work); return 0; } @@ -163,12 +221,18 @@ static const struct led_flash_ops rt8515_flash_ops = { .timeout_set = rt8515_led_flash_timeout_set, }; -static void rt8515_powerdown_timer(struct timer_list *t) +static void rt8515_powerdown_work(struct work_struct *work) { - struct rt8515 *rt = timer_container_of(rt, t, powerdown_timer); + struct rt8515 *rt = container_of(work, struct rt8515, powerdown_work.work); + int ret; /* Turn the LED off */ - rt8515_gpio_led_off(rt); + mutex_lock(&rt->lock); + ret = rt8515_gpio_led_off(rt); + mutex_unlock(&rt->lock); + + if (ret) + dev_err(rt->dev, "failed to turn off LED (%d)\n", ret); } static void rt8515_init_flash_timeout(struct rt8515 *rt) @@ -298,11 +362,18 @@ static int rt8515_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(rt->enable_flash), "cannot get ENF (enable flash) GPIO\n"); - /* ENT - Enable Torch line */ - rt->enable_torch = devm_gpiod_get(dev, "ent", GPIOD_OUT_LOW); + /* ENT - Enable Torch line (optional for single-GPIO flash ICs) */ + rt->enable_torch = devm_gpiod_get_optional(dev, "ent", GPIOD_OUT_LOW); if (IS_ERR(rt->enable_torch)) return dev_err_probe(dev, PTR_ERR(rt->enable_torch), - "cannot get ENT (enable torch) GPIO\n"); + "Failed to obtain the Enable Torch GPIO\n"); + + rt->reg = devm_regulator_get_optional(dev, "vin"); + if (IS_ERR(rt->reg)) { + if (PTR_ERR(rt->reg) == -EPROBE_DEFER) + return -EPROBE_DEFER; + rt->reg = NULL; + } child = device_get_next_child_node(dev, NULL); if (!child) { @@ -328,12 +399,17 @@ static int rt8515_probe(struct platform_device *pdev) dev_warn(dev, "flash-max-timeout-us property missing\n"); } - timer_setup(&rt->powerdown_timer, rt8515_powerdown_timer, 0); + INIT_DELAYED_WORK(&rt->powerdown_work, rt8515_powerdown_work); rt8515_init_flash_timeout(rt); fled->ops = &rt8515_flash_ops; - led->max_brightness = rt->torch_max_intensity; + /* + * If there is no separate torch pin, use flash max intensity + * as max brightness instead. + */ + led->max_brightness = rt->enable_torch ? + rt->torch_max_intensity : rt->flash_max_intensity; led->brightness_set_blocking = rt8515_led_brightness_set; led->flags |= LED_CORE_SUSPENDRESUME | LED_DEV_CAP_FLASH; @@ -372,7 +448,7 @@ static void rt8515_remove(struct platform_device *pdev) struct rt8515 *rt = platform_get_drvdata(pdev); rt8515_v4l2_flash_release(rt); - timer_delete_sync(&rt->powerdown_timer); + cancel_delayed_work_sync(&rt->powerdown_work); mutex_destroy(&rt->lock); } -- 2.54.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v6 2/3] leds: flash: rt8515: Support single-GPIO flash ICs with vin supply 2026-05-28 2:34 ` [PATCH v6 2/3] leds: flash: " Rudraksha Gupta via B4 Relay @ 2026-08-13 10:27 ` Lee Jones 0 siblings, 0 replies; 8+ messages in thread From: Lee Jones @ 2026-08-13 10:27 UTC (permalink / raw) To: guptarud Cc: Pavel Machek, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij, Bjorn Andersson, Konrad Dybcio, Liam Girdwood, Mark Brown, linux-leds, devicetree, linux-kernel, linux-arm-msm, phone-devel /* Sashiko Automation: Reviewed (0 Findings) */ On Wed, 27 May 2026, Rudraksha Gupta via B4 Relay wrote: > From: Rudraksha Gupta <guptarud@gmail.com> > > Extend the RT8515 driver to support flash ICs that use only a single > GPIO for both flash and torch modes (no separate ENT pin), with an > optional vin regulator that gates power to the flash IC. > > When vin-supply is provided, the driver enables the regulator before > activating the LED and disables it when turning off. > > Make ent-gpios optional. When ent-gpios is absent, the driver uses > enf-gpios for both flash and torch brightness control. > > Assisted-by: Claude:claude-opus-4.6 > Reviewed-by: Linus Walleij <linusw@kernel.org> > Signed-off-by: Rudraksha Gupta <guptarud@gmail.com> > --- > drivers/leds/flash/leds-rt8515.c | 148 +++++++++++++++++++++++++++++---------- > 1 file changed, 112 insertions(+), 36 deletions(-) > > diff --git a/drivers/leds/flash/leds-rt8515.c b/drivers/leds/flash/leds-rt8515.c > index f6b439674c03..0fb84d98211d 100644 > --- 'a/drivers/leds/flash/leds-rt8515.c' > +++ 'b/drivers/leds/flash/leds-rt8515.c' > @@ -31,6 +31,7 @@ > #include <linux/platform_device.h> > #include <linux/property.h> > #include <linux/regulator/consumer.h> > +#include <linux/workqueue.h> > > #include <media/v4l2-flash-led-class.h> > > @@ -44,6 +45,9 @@ > #define RT8515_TIMEOUT_US 250000U > #define RT8515_MAX_TIMEOUT_US 300000U > > +#define RT8515_OFF 0 > +#define RT8515_ON 1 > + > struct rt8515 { > struct led_classdev_flash fled; > struct device *dev; > @@ -52,7 +56,7 @@ struct rt8515 { > struct regulator *reg; > struct gpio_desc *enable_torch; > struct gpio_desc *enable_flash; > - struct timer_list powerdown_timer; > + struct delayed_work powerdown_work; > u32 max_timeout; /* Flash max timeout */ > int flash_max_intensity; > int torch_max_intensity; > @@ -63,27 +67,57 @@ static struct rt8515 *to_rt8515(struct led_classdev_flash *fled) > return container_of(fled, struct rt8515, fled); > } > > -static void rt8515_gpio_led_off(struct rt8515 *rt) > +static int rt8515_gpio_led_off(struct rt8515 *rt) > { > - gpiod_set_value(rt->enable_flash, 0); > - gpiod_set_value(rt->enable_torch, 0); > + int ret = 0; > + > + gpiod_set_value(rt->enable_flash, RT8515_OFF); > + gpiod_set_value(rt->enable_torch, RT8515_OFF); > + > + if (!rt->reg) > + return ret; This is odd. I'd argue that this actually hurts readability. Just return 0 here and drop the initialisation when on creation. > + > + ret = regulator_is_enabled(rt->reg); > + if (ret > 0) > + ret = regulator_disable(rt->reg); > + > + return ret; What about: return regulator_is_enabled(rt->reg) ? regulator_disable(rt->reg) : 0; Or, if you're not a fan of ternary operators: if (regulator_is_enabled(rt->reg)) return regulator_disable(rt->reg); return 0; Both of those allow you to drop 'ret' altogether. > } > > -static void rt8515_gpio_brightness_commit(struct gpio_desc *gpiod, > - int brightness) > +static int rt8515_gpio_brightness_commit(struct rt8515 *rt, struct gpio_desc *gpiod, int brightness) > { > int i; Place this inside the for loop: for (int i = 0; ... > + int ret; > + > + /* > + * Reset the IC to start brightness from zero, > + * then re-enable and pulse to the desired level. > + */ > + ret = rt8515_gpio_led_off(rt); > + if (ret) > + return ret; > + > + /* IC needs time to reset its brightness counter */ > + usleep_range(100, 200); > + > + if (rt->reg) { > + ret = regulator_enable(rt->reg); > + if (ret) > + return ret; > + } > > /* > * Toggling a GPIO line with a small delay increases the > * brightness one step at a time. > */ > for (i = 0; i < brightness; i++) { > - gpiod_set_value(gpiod, 0); > + gpiod_set_value(gpiod, RT8515_OFF); > udelay(1); > - gpiod_set_value(gpiod, 1); > + gpiod_set_value(gpiod, RT8515_ON); > udelay(1); > } > + > + return 0; > } > > /* This is setting the torch light level */ > @@ -92,23 +126,38 @@ static int rt8515_led_brightness_set(struct led_classdev *led, > { > struct led_classdev_flash *fled = lcdev_to_flcdev(led); > struct rt8515 *rt = to_rt8515(fled); > + int ret = 0; > mutex_lock(&rt->lock); > > if (brightness == LED_OFF) { > /* Off */ Suggest we remove this comment whilst we're in here. > - rt8515_gpio_led_off(rt); > + ret = rt8515_gpio_led_off(rt); > + if (ret) > + goto out; > } else if (brightness < RT8515_TORCH_MAX) { > - /* Step it up to movie mode brightness using the flash pin */ > - rt8515_gpio_brightness_commit(rt->enable_torch, brightness); > + /* > + * Step it up to movie mode brightness. > + * If there is no separate torch pin, use the flash pin > + * for torch as well. > + */ > + ret = rt8515_gpio_brightness_commit(rt, > + rt->enable_torch ?: rt->enable_flash, brightness); > + if (ret) > + goto out; > } else { > - /* Max torch brightness requested */ > - gpiod_set_value(rt->enable_torch, 1); > + /* > + * Max torch brightness requested. > + * If there is no separate torch pin, use the flash pin > + * for torch as well. > + */ > + gpiod_set_value(rt->enable_torch ?: rt->enable_flash, RT8515_ON); > } > > +out: > mutex_unlock(&rt->lock); > > - return 0; > + return ret; > } > > static int rt8515_led_flash_strobe_set(struct led_classdev_flash *fled, > @@ -117,27 +166,36 @@ static int rt8515_led_flash_strobe_set(struct led_classdev_flash *fled, > struct rt8515 *rt = to_rt8515(fled); > struct led_flash_setting *timeout = &fled->timeout; > int brightness = rt->flash_max_intensity; > + int ret = 0; > > - mutex_lock(&rt->lock); > - > - if (state) { > - /* Enable LED flash mode and set brightness */ > - rt8515_gpio_brightness_commit(rt->enable_flash, brightness); > - /* Set timeout */ > - mod_timer(&rt->powerdown_timer, > - jiffies + usecs_to_jiffies(timeout->val)); > - } else { > - timer_delete_sync(&rt->powerdown_timer); > + if (!state) { > + cancel_delayed_work_sync(&rt->powerdown_work); > + mutex_lock(&rt->lock); > /* Turn the LED off */ And here. > - rt8515_gpio_led_off(rt); > + ret = rt8515_gpio_led_off(rt); > + if (!ret) > + fled->led_cdev.brightness = LED_OFF; > + mutex_unlock(&rt->lock); > + return ret; > } > > + mutex_lock(&rt->lock); > + > + /* Enable LED flash mode and set brightness */ > + ret = rt8515_gpio_brightness_commit(rt, rt->enable_flash, brightness); > + if (ret) > + goto out; > + > + /* Set timeout */ > + schedule_delayed_work(&rt->powerdown_work, usecs_to_jiffies(timeout->val)); > + > fled->led_cdev.brightness = LED_OFF; > /* After this the torch LED will be disabled */ > > +out: > mutex_unlock(&rt->lock); > > - return 0; > + return ret; > } > > static int rt8515_led_flash_strobe_get(struct led_classdev_flash *fled, > @@ -145,7 +203,7 @@ static int rt8515_led_flash_strobe_get(struct led_classdev_flash *fled, > { > struct rt8515 *rt = to_rt8515(fled); > > - *state = timer_pending(&rt->powerdown_timer); > + *state = delayed_work_pending(&rt->powerdown_work); > > return 0; > } > @@ -163,12 +221,18 @@ static const struct led_flash_ops rt8515_flash_ops = { > .timeout_set = rt8515_led_flash_timeout_set, > }; > > -static void rt8515_powerdown_timer(struct timer_list *t) > +static void rt8515_powerdown_work(struct work_struct *work) > { > - struct rt8515 *rt = timer_container_of(rt, t, powerdown_timer); > + struct rt8515 *rt = container_of(work, struct rt8515, powerdown_work.work); > + int ret; > > /* Turn the LED off */ Seriously? =;-) > - rt8515_gpio_led_off(rt); > + mutex_lock(&rt->lock); > + ret = rt8515_gpio_led_off(rt); > + mutex_unlock(&rt->lock); > + > + if (ret) > + dev_err(rt->dev, "failed to turn off LED (%d)\n", ret); > } > > static void rt8515_init_flash_timeout(struct rt8515 *rt) > @@ -298,11 +362,18 @@ static int rt8515_probe(struct platform_device *pdev) > return dev_err_probe(dev, PTR_ERR(rt->enable_flash), > "cannot get ENF (enable flash) GPIO\n"); > > - /* ENT - Enable Torch line */ > - rt->enable_torch = devm_gpiod_get(dev, "ent", GPIOD_OUT_LOW); > + /* ENT - Enable Torch line (optional for single-GPIO flash ICs) */ > + rt->enable_torch = devm_gpiod_get_optional(dev, "ent", GPIOD_OUT_LOW); > if (IS_ERR(rt->enable_torch)) > return dev_err_probe(dev, PTR_ERR(rt->enable_torch), > - "cannot get ENT (enable torch) GPIO\n"); > + "Failed to obtain the Enable Torch GPIO\n"); > + > + rt->reg = devm_regulator_get_optional(dev, "vin"); > + if (IS_ERR(rt->reg)) { > + if (PTR_ERR(rt->reg) == -EPROBE_DEFER) > + return -EPROBE_DEFER; > + rt->reg = NULL; -EPROBE_DEFER is the only error message we're handling? What about if an -ENOMEM occurs? We're now masking that. > + } > > child = device_get_next_child_node(dev, NULL); > if (!child) { > @@ -328,12 +399,17 @@ static int rt8515_probe(struct platform_device *pdev) > dev_warn(dev, > "flash-max-timeout-us property missing\n"); > } > - timer_setup(&rt->powerdown_timer, rt8515_powerdown_timer, 0); > + INIT_DELAYED_WORK(&rt->powerdown_work, rt8515_powerdown_work); > rt8515_init_flash_timeout(rt); > > fled->ops = &rt8515_flash_ops; > > - led->max_brightness = rt->torch_max_intensity; > + /* > + * If there is no separate torch pin, use flash max intensity > + * as max brightness instead. > + */ > + led->max_brightness = rt->enable_torch ? > + rt->torch_max_intensity : rt->flash_max_intensity; > led->brightness_set_blocking = rt8515_led_brightness_set; > led->flags |= LED_CORE_SUSPENDRESUME | LED_DEV_CAP_FLASH; > > @@ -372,7 +448,7 @@ static void rt8515_remove(struct platform_device *pdev) > struct rt8515 *rt = platform_get_drvdata(pdev); > > rt8515_v4l2_flash_release(rt); > - timer_delete_sync(&rt->powerdown_timer); > + cancel_delayed_work_sync(&rt->powerdown_work); > mutex_destroy(&rt->lock); > } > > > -- > 2.54.0 > > -- Lee Jones ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v6 3/3] ARM: dts: qcom: msm8960: expressatt: Add camera flash 2026-05-28 2:34 [PATCH v6 0/3] Samsung Expressatt: Camera Flash Rudraksha Gupta via B4 Relay 2026-05-28 2:34 ` [PATCH v6 1/3] dt-bindings: leds: rt8515: Support single-GPIO flash ICs with vin supply Rudraksha Gupta via B4 Relay 2026-05-28 2:34 ` [PATCH v6 2/3] leds: flash: " Rudraksha Gupta via B4 Relay @ 2026-05-28 2:34 ` Rudraksha Gupta via B4 Relay 2026-08-11 9:31 ` [PATCH v6 0/3] Samsung Expressatt: Camera Flash Rudraksha Gupta 3 siblings, 0 replies; 8+ messages in thread From: Rudraksha Gupta via B4 Relay @ 2026-05-28 2:34 UTC (permalink / raw) To: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij, Bjorn Andersson, Konrad Dybcio, Liam Girdwood, Mark Brown Cc: linux-leds, devicetree, linux-kernel, linux-arm-msm, phone-devel, Rudraksha Gupta, David Heidelberg, Konrad Dybcio From: Rudraksha Gupta <guptarud@gmail.com> Add camera flash support for the Samsung Galaxy Express (expressatt). The flash IC uses a one-wire pulse-count protocol on GPIO 3, powered by a GPIO-controlled fixed regulator on PMIC MPP 4. The regulator is modeled as a regulator-fixed node and supplied to the flash IC via vin-supply. Downstream references: Link: https://github.com/LineageOS/android_kernel_samsung_d2/blob/stable/cm-12.0-YNG4N/drivers/leds/Makefile#L51 Link: https://github.com/LineageOS/android_kernel_samsung_d2/blob/stable/cm-12.0-YNG4N/arch/arm/mach-msm/board-apexq-camera.c#L591 Assisted-by: Claude:claude-opus-4.6 Reviewed-by: David Heidelberg <david@ixit.cz> Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com> Signed-off-by: Rudraksha Gupta <guptarud@gmail.com> --- .../dts/qcom/qcom-msm8960-samsung-expressatt.dts | 43 ++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts b/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts index 5a3d88e31cf5..8fcd5e8574fa 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include <dt-bindings/input/input.h> +#include <dt-bindings/leds/common.h> #include <dt-bindings/reset/qcom,gcc-msm8960.h> #include "qcom-msm8960.dtsi" @@ -61,6 +62,32 @@ touchkey_enable: touchkey-enable { regulator-boot-on; }; + vreg_flash: regulator-flash { + compatible = "regulator-fixed"; + regulator-name = "VREG_FLASH_3P3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&pm8921_mpps 4 GPIO_ACTIVE_HIGH>; + enable-active-high; + pinctrl-0 = <&flash_led_unlock>; + pinctrl-names = "default"; + }; + + led-controller { + compatible = "richtek,rt8515"; + enf-gpios = <&tlmm 3 GPIO_ACTIVE_HIGH>; + vin-supply = <&vreg_flash>; + richtek,rfs-ohms = <16000>; + pinctrl-0 = <&cam_flash_en>; + pinctrl-names = "default"; + + led { + function = LED_FUNCTION_FLASH; + color = <LED_COLOR_ID_WHITE>; + flash-max-timeout-us = <250000>; + }; + }; + i2c-gpio-touchkey { compatible = "i2c-gpio"; #address-cells = <1>; @@ -171,6 +198,13 @@ touchscreen@4a { }; &tlmm { + cam_flash_en: cam-flash-en-state { + pins = "gpio3"; + function = "gpio"; + drive-strength = <16>; + bias-pull-down; + }; + spi1_default: spi1-default-state { mosi-pins { pins = "gpio6"; @@ -571,3 +605,12 @@ magnetometer@2e { /* TODO: Figure out Mount Matrix */ }; }; + +&pm8921_mpps { + flash_led_unlock: flash-led-unlock-state { + pins = "mpp4"; + function = "digital"; + output-low; + power-source = <PM8921_GPIO_S4>; + }; +}; -- 2.54.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v6 0/3] Samsung Expressatt: Camera Flash 2026-05-28 2:34 [PATCH v6 0/3] Samsung Expressatt: Camera Flash Rudraksha Gupta via B4 Relay ` (2 preceding siblings ...) 2026-05-28 2:34 ` [PATCH v6 3/3] ARM: dts: qcom: msm8960: expressatt: Add camera flash Rudraksha Gupta via B4 Relay @ 2026-08-11 9:31 ` Rudraksha Gupta 2026-08-12 7:49 ` Linus Walleij 3 siblings, 1 reply; 8+ messages in thread From: Rudraksha Gupta @ 2026-08-11 9:31 UTC (permalink / raw) To: devnull+guptarud.gmail.com Cc: andersson, broonie, conor+dt, conor.dooley, david, devicetree, guptarud, konrad.dybcio, konradybcio, krzk+dt, lee, lgirdwood, linusw, linux-arm-msm, linux-kernel, linux-leds, pavel, phone-devel, robh Hello, https://lore.kernel.org/all/20260527-expressatt_camera_flash-v6-0-de0f150024e4@gmail.com/#t This series seems to have fallen in between the cracks. Should I resend this patch series? Thanks, Rudraksha ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v6 0/3] Samsung Expressatt: Camera Flash 2026-08-11 9:31 ` [PATCH v6 0/3] Samsung Expressatt: Camera Flash Rudraksha Gupta @ 2026-08-12 7:49 ` Linus Walleij 2026-08-12 13:27 ` Lee Jones 0 siblings, 1 reply; 8+ messages in thread From: Linus Walleij @ 2026-08-12 7:49 UTC (permalink / raw) To: Rudraksha Gupta, Lee Jones Cc: devnull+guptarud.gmail.com, andersson, broonie, conor+dt, conor.dooley, david, devicetree, konrad.dybcio, konradybcio, krzk+dt, lgirdwood, linux-arm-msm, linux-kernel, linux-leds, pavel, phone-devel, robh On Tue, Aug 11, 2026 at 11:31 AM Rudraksha Gupta <guptarud@gmail.com> wrote: > https://lore.kernel.org/all/20260527-expressatt_camera_flash-v6-0-de0f150024e4@gmail.com/#t > > This series seems to have fallen in between the cracks. Should I resend > this patch series? Let's just gently poke Lee about it and see what he says. Yours, Linus Walleij ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v6 0/3] Samsung Expressatt: Camera Flash 2026-08-12 7:49 ` Linus Walleij @ 2026-08-12 13:27 ` Lee Jones 0 siblings, 0 replies; 8+ messages in thread From: Lee Jones @ 2026-08-12 13:27 UTC (permalink / raw) To: Linus Walleij Cc: Rudraksha Gupta, devnull+guptarud.gmail.com, andersson, broonie, conor+dt, conor.dooley, david, devicetree, konrad.dybcio, konradybcio, krzk+dt, lgirdwood, linux-arm-msm, linux-kernel, linux-leds, pavel, phone-devel, robh On Wed, 12 Aug 2026, Linus Walleij wrote: > On Tue, Aug 11, 2026 at 11:31 AM Rudraksha Gupta <guptarud@gmail.com> wrote: > > > https://lore.kernel.org/all/20260527-expressatt_camera_flash-v6-0-de0f150024e4@gmail.com/#t > > > > This series seems to have fallen in between the cracks. Should I resend > > this patch series? > > Let's just gently poke Lee about it and see what he says. Sorry, it had slipped through. Please submit a [RESEND]. -- Lee Jones ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-08-13 10:27 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-05-28 2:34 [PATCH v6 0/3] Samsung Expressatt: Camera Flash Rudraksha Gupta via B4 Relay 2026-05-28 2:34 ` [PATCH v6 1/3] dt-bindings: leds: rt8515: Support single-GPIO flash ICs with vin supply Rudraksha Gupta via B4 Relay 2026-05-28 2:34 ` [PATCH v6 2/3] leds: flash: " Rudraksha Gupta via B4 Relay 2026-08-13 10:27 ` Lee Jones 2026-05-28 2:34 ` [PATCH v6 3/3] ARM: dts: qcom: msm8960: expressatt: Add camera flash Rudraksha Gupta via B4 Relay 2026-08-11 9:31 ` [PATCH v6 0/3] Samsung Expressatt: Camera Flash Rudraksha Gupta 2026-08-12 7:49 ` Linus Walleij 2026-08-12 13:27 ` Lee Jones
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox