leds: flash: LM3643 dual LED flash driver
Subsystems (2)
v3 cover leds: flash: LM3643 dual LED flash driver
This series adds a flash LED driver for the Texas Instruments LM3643. I wrote it to support the Windows Hello NIR illuminator on my ThinkPad X9-15 Gen 1, which has a single LED connected to both current sources. The driver has also been tested by Ruslan Koreev on a ThinkPad X1 Carbon Gen 14.
On both ThinkPad models the chip is described by ACPI but has no _DSD. The original RFC asked how to supply the missing child nodes. This series includes DMI-matched software nodes for both laptop models.
1/4 DT binding
2/4 driver
3/4 DMI match table and values for the X1 Carbon
4/4 DMI entry for the X9-15 Gen 1
Changes in v3:
- dt-bindings: document the enable-gpios (HWEN), flash-gpios (STROBE) and vin-supply (IN) connections (Krzysztof Kozlowski)
- dt-bindings: drop redundant minimum: 0, use led-controller as the node name in the example and tidy formatting (Krzysztof Kozlowski)
- driver: enable the optional vin-supply and drive the optional HWEN GPIO high at probe
- driver: reject an out-of-range max-brightness rather than clamping after registration (previously LED core applied max-brightness exposing sysfs before the clamp)
- driver: allow a torch output to be switched off while the device is flashing (previously returned -EBUSY)
- driver: take the chip lock when claiming current outputs
- driver: fix indentation in lm3643_torch_get_brightness()
- 3/4, 4/4: use DMI_EXACT_MATCH for the DMI entries
- 3/4: log use of the DMI description with dev_dbg() instead of dev_info()
Changes in v2:
- Rebased onto leds/for-leds-next
- dt-bindings: make flash-max-microamp, led-max-microamp and flash-max-timeout-us required
- driver: return device to standby state when the last output is switched off (squashed fix provided by Ruslan Koreev)
- New 3/4: DMI mechanism and entry for the X1 Carbon developed by Ruslan. Plus a minor update to provide a reg property for consistency with the DT bindings.
- New 4/4: DMI entry for the X9-15 Gen 1 and update struct names to be model-specific.
v2: https://lore.kernel.org/all/[email protected]/
v1: https://lore.kernel.org/all/[email protected]/
Rillian Grant (3):
dt-bindings: leds: Document TI LM3643 dual LED flash driver
leds: flash: Add support for the TI LM3643 dual LED flash driver
leds: flash: lm3643: Describe the LED on the Lenovo ThinkPad X9-15 Gen
1
Ruslan Koreev (1):
leds: flash: lm3643: Describe the LED of ACPI boards without LED nodes
.../devicetree/bindings/leds/ti,lm3643.yaml | 143 +++ MAINTAINERS | 7 + drivers/leds/flash/Kconfig | 12 + drivers/leds/flash/Makefile | 1 + drivers/leds/flash/leds-lm3643.c | 929 ++++++++++++++++++ 5 files changed, 1092 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/ti,lm3643.yaml create mode 100644 drivers/leds/flash/leds-lm3643.c
base-commit: 05b4738b0078f7d6f154f68068a11c8a0635e9df
Signature · 1 line
2.56.0
PATCH v3 1/4 dt-bindings: leds: Document TI LM3643 dual LED flash driver
Document Texas Instruments LM3643 dual LED flash driver devicetree bindings.
--- .../devicetree/bindings/leds/ti,lm3643.yaml | 143 ++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/ti,lm3643.yaml
Documentation/devicetree/bindings/leds/ti,lm3643.yaml new file +143 -0
@@ -0,0 +1,143 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/ti,lm3643.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments LM3643 1500mA dual LED Flash Driver + +maintainers: + - Rillian Grant <[email protected]> + +description: | + The LM3643 is a dual LED flash driver utilizing a synchronous boost converter + to provide power to two current sources. + + The dual high-side current sources can be tied together to provide flash + currents up to 1.5A through a single LED. + + Datasheet: https://www.ti.com/lit/ds/symlink/lm3643.pdf + +properties: + compatible: + enum: + - ti,lm3643 + + reg: + maxItems: 1 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + enable-gpios: + description: GPIO connected to the HWEN pin. + maxItems: 1 + + flash-gpios: + description: GPIO connected to the STROBE pin. + maxItems: 1 + + vin-supply: + description: Supply connected to the IN line. + +patternProperties: + "^led@[0-1]$": + type: object + $ref: common.yaml# + unevaluatedProperties: false + + properties: + reg: + description: Index of the LED. + maximum: 1 + + led-sources: + minItems: 1 + maxItems: 2 + items: + maximum: 1 + + flash-max-microamp: + description: | + Maximum flash current through this LED. Each high-side current source + can provide up to 1.5A. The maximum current the boost can deliver is + 1.5A across both sources. + + Valid values for an LED connected to one source: + 10900 - 1500000, step by 11725 (rounded down) + Valid values for an LED connected to both sources: + 21800 - 1500000, step by 23450 (rounded down) + minimum: 10900 + maximum: 1500000 + + led-max-microamp: + description: | + Maximum torch current through this LED. In torch mode each high-side + current source can provide up to 179mA. + + Valid values for an LED connected to one source: + 977 - 179000, step by 1400 (rounded down) + Valid values for an LED connected to both sources: + 1954 - 358000, step by 2800 (rounded down) + minimum: 977 + maximum: 358000 + + flash-max-timeout-us: + description: + The chip supports timeouts from 10ms to 100ms in increments of 10ms + and from 100ms to 400ms in increments of 50ms. The provided value + will be rounded down to a supported value. + minimum: 10000 + maximum: 400000 + + required: + - reg + - led-sources + - flash-max-microamp + - led-max-microamp + - flash-max-timeout-us + +required: + - compatible + - reg + - "#address-cells" + - "#size-cells" + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/leds/common.h> + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + led-controller@63 { + compatible = "ti,lm3643"; + reg = <0x63>; + + #address-cells = <1>; + #size-cells = <0>; + + enable-gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; + flash-gpios = <&gpio 43 GPIO_ACTIVE_HIGH>; + vin-supply = <&vreg_flash>; + + led@0 { + reg = <0>; + led-sources = <0>, <1>; + + function = LED_FUNCTION_FLASH; + color = <LED_COLOR_ID_IR>; + + flash-max-microamp = <750000>; + led-max-microamp = <180000>; + flash-max-timeout-us = <150000>; + }; + }; + };
Signature · 1 line
2.56.0
[email protected]
AI reviewRe: [PATCH v3 1/4] dt-bindings: leds: Document TI LM3643 dual LED flash driver
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] leds: missing driver name in commit message prefix --
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] leds: missing driver name in commit message prefix
--
commit 3be78a7ca4f65d71d150658aa87edd42d6d057a1
Author: Rillian Grant <[email protected]>
dt-bindings: leds: Document TI LM3643 dual LED flash driver
This commit documents the devicetree bindings for the Texas Instruments LM3643 dual LED flash driver.
Quoted 1 line
dt-bindings: leds: Document TI LM3643 dual LED flash driver
[Severity: Low]
This isn't a bug, but does the commit message subject omit the driver name in the prefix? According to the LED subsystem rules, commit messages should include the appropriate driver prefix followed by a capitalized description, such as "dt-bindings: leds: ti,lm3643: Document...". Missing the driver portion of the prefix hinders Git history categorization and violates subsystem naming conventions.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
Re: [PATCH v3 1/4] dt-bindings: leds: Document TI LM3643 dual LED flash driver
In reply to Rillian GrantQuoted 8 lines · Rillian Grant
Document Texas Instruments LM3643 dual LED flash driver devicetree bindings.
Signed-off-by Rillian Grant <[email protected]>--- .../devicetree/bindings/leds/ti,lm3643.yaml | 143 ++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/ti,lm3643.yaml
Best regards,
Krzysztof
PATCH v3 2/4 leds: flash: Add support for the TI LM3643 dual LED flash driver
In reply to Rillian GrantThe LM3643 is an I2C dual LED flash driver. Its two high-side current sources share a synchronous boost converter and each supports torch and flash modes with programmable current and flash timeout alongside fault reporting.
It also supports connecting both sources together to supply one LED with current up to the boost converter's 1.5A maximum. In that case the current will be split between each source symmetrically and the sources will be enabled and disabled at the same time.
As strobing is toggled chip-wide the driver returns -EBUSY when a sibling LED is active.
Flash timeouts do not have a constant step. The driver advertises the most granular step and rounds down to the nearest supported value.
Register behavior was taken from the datasheet (SNVS967A).
--- MAINTAINERS | 7 + drivers/leds/flash/Kconfig | 12 + drivers/leds/flash/Makefile | 1 + drivers/leds/flash/leds-lm3643.c | 796 +++++++++++++++++++++++++++++++ 4 files changed, 816 insertions(+) create mode 100644 drivers/leds/flash/leds-lm3643.c
MAINTAINERS +7 -0
@@ -27036,6 +27036,13 @@ F: include/linux/dma/k3-udma-glue.h F: include/linux/dma/ti-cppi5.h X: drivers/dma/ti/cppi41.c +TEXAS INSTRUMENTS LM3643 LED FLASH DRIVER +M: Rillian Grant <[email protected]> +L: [email protected] +S: Maintained +F: Documentation/devicetree/bindings/leds/ti,lm3643.yaml +F: drivers/leds/flash/leds-lm3643.c + TEXAS INSTRUMENTS TPS25990 HARDWARE MONITOR DRIVER M: Jerome Brunet <[email protected]> L: [email protected]
drivers/leds/flash/Kconfig +12 -0
@@ -39,6 +39,18 @@ config LEDS_LM3601X This option enables support for the TI LM3601x family of flash, torch and indicator classes. +config LEDS_LM3643 + tristate "LED support for LM3643 dual LED flash driver" + depends on I2C + depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS + select REGMAP_I2C + help + This option enables support for the Texas Instruments LM3643 dual + LED flash driver. + + This driver can also be built as a module. If so, the module + will be called "leds-lm3643". + config LEDS_MAX77693 tristate "LED support for MAX77693 Flash" depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS
drivers/leds/flash/Makefile +1 -0
@@ -6,6 +6,7 @@ obj-$(CONFIG_LEDS_AAT1290) += leds-aat1290.o obj-$(CONFIG_LEDS_AS3645A) += leds-as3645a.o obj-$(CONFIG_LEDS_KTD2692) += leds-ktd2692.o obj-$(CONFIG_LEDS_LM3601X) += leds-lm3601x.o +obj-$(CONFIG_LEDS_LM3643) += leds-lm3643.o obj-$(CONFIG_LEDS_MAX77693) += leds-max77693.o obj-$(CONFIG_LEDS_QCOM_FLASH) += leds-qcom-flash.o obj-$(CONFIG_LEDS_RT4505) += leds-rt4505.o
drivers/leds/flash/leds-lm3643.c new file +796 -0
796 lines not on this page · raw message
Signature · 1 line
2.56.0
[email protected]
AI reviewRe: [PATCH v3 2/4] leds: flash: Add support for the TI LM3643 dual LED flash driver
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [Medium] leds: missing hardware startup delay after asserting enable GPIO - [Low] leds: non-standard…
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] leds: missing hardware startup delay after asserting enable GPIO
- [Low] leds: non-standard commit message prefix used
--
commit e9482e46025f29c98cd459b067571fee928be4b6
Author: Rillian Grant <[email protected]>
leds: flash: Add support for the TI LM3643 dual LED flash driver
This commit introduces support for the Texas Instruments LM3643 dual LED flash driver over I2C. The chip provides torch and flash modes with programmable current and timeouts via a shared synchronous boost converter.
Quoted 1 line
leds: flash: Add support for the TI LM3643 dual LED flash driver
[Severity: Low]
This isn't a bug, but does this commit subject violate the subsystem naming conventions?
According to the LED subsystem guidelines, embedding subsystem subdirectory names like flash into the prefix hinders Git history categorization. Embedding implementation details can also create rigid and non-reusable drivers.
Could the driver name lm3643 be used in the prefix instead, such as "leds: lm3643: "?
Quoted 3 lines
drivers/leds/flash/leds-lm3643.c new file +0
-0
[ ... ]
Quoted 2 lines
drivers/leds/flash/leds-lm3643.c new file +2
-0+static int lm3643_probe (struct i2c_client *client) +{
[ ... ]
Quoted 6 lines
drivers/leds/flash/leds-lm3643.c new file +6
-0+ hwen =devm_gpiod_get_optional (dev,"enable" ,GPIOD_OUT_HIGH ); +if (IS_ERR (hwen)) +return dev_err_probe (dev,PTR_ERR (hwen),"failed to get enable GPIO\n" ); + + chip =devm_kzalloc (dev,sizeof (*chip),GFP_KERNEL ); +if (!chip)
drivers/leds/flash/leds-lm3643.c line 727
Quoted 10 lines
drivers/leds/flash/leds-lm3643.c new file +10
-0+return -ENOMEM ; +i2c_set_clientdata (client, chip); + + chip->regmap =devm_regmap_init_i2c (client, &lm3643_regmap_config); +if (IS_ERR (chip->regmap)) +return dev_err_probe (dev, +PTR_ERR (chip->regmap), +"failed to allocate register map\n" ); + + ret =regmap_read (chip->regmap,LM3643_REG_DEV_ID , &dev_id);
[Severity: Medium]
Does this sequence require a hardware startup delay after asserting the enable GPIO?
The lm3643_probe() function drives the HWEN GPIO high and then shortly after initiates an I2C regmap_read() to fetch the device ID. Failing to provide a programmatic delay (e.g., via usleep_range) might cause the I2C transfer to fail on platforms where the CPU executes the bus transaction before the hardware state machine and internal oscillator are fully initialized.
Could a small delay be added here to ensure the chip is ready for I2C traffic before the register read is attempted?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
Re: [PATCH v3 2/4] leds: flash: Add support for the TI LM3643 dual LED flash driver
Quoted 11 lines
[Severity: Low]
This isn't a bug, but does this commit subject violate the subsystem naming conventions?According to the LED subsystem guidelines, embedding subsystem subdirectory names like flash into the prefix hinders Git history categorization. Embedding implementation details can also create rigid and non-reusable drivers.
Could the driver name lm3643 be used in the prefix instead, such as "leds: lm3643: "?
Happy to switch to "leds: flash: lm3643:" across the series if there is another revision, or for the maintainer to adjust when applying.
Quoted 4 lines
[Severity: Medium]
Does this sequence require a hardware startup delay after asserting the enable GPIO?
Quoted 8 lines
The
lm3643_probe()function drives the HWEN GPIO high and then shortly after initiates an I2Cregmap_read()to fetch the device ID. Failing to provide a programmatic delay (e.g., viausleep_range) might cause the I2C transfer to fail on platforms where the CPU executes the bus transaction before the hardware state machine and internal oscillator are fully initialized.Could a small delay be added here to ensure the chip is ready for I2C traffic before the register read is attempted?
The LM3643 datasheet specifies no delay between HWEN high and I2C ready, so I'd rather not add an arbitrary sleep.
Signature · 1 line
Rillian Grant
PATCH v3 3/4 leds: flash: lm3643: Describe the LED of ACPI boards without LED nodes
In reply to Rillian GrantFrom: Ruslan Koreev <[email protected]>
Lenovo ThinkPads enumerate the LM3643 through ACPI (HID TXNW3643) without a _DSD, so the device has no LED child nodes and the driver refuses to probe. On these laptops the chip drives the Windows Hello IR flood illuminator, with both current sources feeding a single LED, and Lenovo's Windows driver applies a fixed configuration to any LM3643 it finds.
Add a DMI table that provides that description as a software node when the firmware offers none: one IR flash LED on both outputs, with torch and flash limits well below the chip's maximums. Start with the ThinkPad X1 Carbon Gen 14.
The description is keyed by DMI instead of being applied to every TXNW3643 because the wiring is a board property: which output feeds which LED and how much current the LED tolerates cannot be read from the chip, and a wrong guess overdrives an LED. The firmware cannot be fixed from the driver side, and a per-board table is what x86-android-tablets does for devices whose ACPI tables describe nothing either. Boards with a _DSD are not affected, the fallback only runs when the device has no child nodes. The limits are conservative because the LED part is not documented; the illuminator is bright enough for face authentication at a fraction of them.
Tested on that laptop: torch through /sys/class/leds/ir:flash lights the ST VD55G1 IR camera's field of view, and the resulting frames are good enough for face authentication.
--- drivers/leds/flash/leds-lm3643.c | 93 ++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+)
drivers/leds/flash/leds-lm3643.c +93 -0
@@ -9,6 +9,7 @@#include <linux/bitfield.h> #include <linux/bits.h> #include <linux/cleanup.h> +#include <linux/dmi.h> #include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/led-class-flash.h>
@@ -691,6 +692,92 @@ static int lm3643_register_led(struct device *dev, struct lm3643 *chip,return lm3643_register_v4l2 (dev, led, fwnode); } +/* +* Lenovo ThinkPads enumerate the chip through ACPI (HID TXNW3643) without a +* _DSD, so the LED is not described by firmware. On the boards below it drives +* the Windows Hello IR flood illuminator, with both current sources feeding a +* single LED. Describe that with a software node, with torch and flash limits +* (100 mA and 300 mA per output) well below the chip's maximums. +*/ +static const u32 lm3643_ir_flood_sources[] = {0 ,1 }; + +static const struct property_entry lm3643_ir_flood_props[] = { +PROPERTY_ENTRY_U32 ("reg" ,0 ), +PROPERTY_ENTRY_U32_ARRAY ("led-sources" , lm3643_ir_flood_sources), +PROPERTY_ENTRY_STRING ("function" ,LED_FUNCTION_FLASH ), +PROPERTY_ENTRY_U32 ("color" ,LED_COLOR_ID_IR ), +PROPERTY_ENTRY_U32 ("led-max-microamp" ,200000 ), +PROPERTY_ENTRY_U32 ("flash-max-microamp" ,600000 ), +PROPERTY_ENTRY_U32 ("flash-max-timeout-us" ,100000 ), + { } +}; + +static const struct software_node lm3643_ir_flood_root = { + .name ="lm3643" , +}; + +static const struct software_node lm3643_ir_flood_led = { + .name ="led-0" , + .parent = &lm3643_ir_flood_root, + .properties = lm3643_ir_flood_props, +}; + +static const struct software_node *lm3643_ir_flood_nodes[] = { + &lm3643_ir_flood_root, + &lm3643_ir_flood_led, +NULL +}; + +static const struct dmi_system_id lm3643_dmi_leds[] = { + { +/* Lenovo ThinkPad X1 Carbon Gen 14 */ + .matches = { +DMI_EXACT_MATCH (DMI_SYS_VENDOR ,"LENOVO" ), +DMI_EXACT_MATCH (DMI_PRODUCT_VERSION ,"ThinkPad X1 Carbon Gen 14" ), + }, + .driver_data = (void *)lm3643_ir_flood_nodes, + }, + { } +}; + +static void lm3643_remove_dmi_leds (void *data) +{ +struct device *dev = data; +const struct dmi_system_id *id =dmi_first_match (lm3643_dmi_leds); + +set_secondary_fwnode (dev,NULL ); +if (id) +software_node_unregister_node_group (id->driver_data); +} + +static int lm3643_add_dmi_leds (struct device *dev) +{ +const struct dmi_system_id *id; +const struct software_node **nodes; +int ret; + +if (!has_acpi_companion (dev)) +return 0 ; + + id =dmi_first_match (lm3643_dmi_leds); +if (!id) +return 0 ; + + nodes = id->driver_data; +/* The nodes are static: a second chip on the same board cannot reuse them */ +if (software_node_fwnode (nodes[0 ])) +return dev_err_probe (dev, -EBUSY ,"LED description already in use\n" ); + + ret =software_node_register_node_group (nodes); +if (ret) +return dev_err_probe (dev, ret,"failed to register the LED description\n" ); + +set_secondary_fwnode (dev,software_node_fwnode (nodes[0 ])); +dev_dbg (dev,"no LED nodes in firmware, using the DMI description\n" ); + +return devm_add_action_or_reset (dev, lm3643_remove_dmi_leds, dev); +} +static int lm3643_probe (struct i2c_client *client) {struct device *dev = &client->dev;
@@ -701,6 +788,12 @@ static int lm3643_probe(struct i2c_client *client)int ret; count =device_get_child_node_count (dev); +if (!count) { + ret =lm3643_add_dmi_leds (dev); +if (ret) +return ret; + count =device_get_child_node_count (dev); + }if (!count || count >LM3643_NUM_CHANNELS )return dev_err_probe (dev, -EINVAL ,"%u LED nodes found, expected 1 to %d\n" , count,LM3643_NUM_CHANNELS );
Signature · 1 line
2.56.0
[email protected]
AI reviewRe: [PATCH v3 3/4] leds: flash: lm3643: Describe the LED of ACPI boards without LED nodes
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] leds: flash: lm3643: TOCTOU race in swnode registration causes UAF --
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] leds: flash: lm3643: TOCTOU race in swnode registration causes UAF --
commit a08dd419e737ce9719711220082ac93884d1bc47
Author: Ruslan Koreev <[email protected]>
leds: flash: lm3643: Describe the LED of ACPI boards without LED nodes
This commit adds a DMI table and software node descriptions for Lenovo ThinkPads that enumerate the LM3643 through ACPI without a _DSD. This fallback allows the Windows Hello IR flood illuminator to be probed and registered when the firmware provides no child nodes.
Quoted 4 lines
drivers/leds/flash/leds-lm3643.c +0
-0
[ ... ]
Quoted 9 lines
drivers/leds/flash/leds-lm3643.c +9
-0+static int lm3643_add_dmi_leds (struct device *dev) +{ +const struct dmi_system_id *id; +const struct software_node **nodes; +int ret; + +if (!has_acpi_companion (dev)) +return 0 ; +
drivers/leds/flash/leds-lm3643.c static int lm3643_register_led(struct device *dev, struct lm3643 *chip, · line 771
Quoted 10 lines
drivers/leds/flash/leds-lm3643.c +10
-0+ id =dmi_first_match (lm3643_dmi_leds); +if (!id) +return 0 ; + + nodes = id->driver_data; +/* The nodes are static: a second chip on the same board cannot reuse them */ +if (software_node_fwnode (nodes[0 ])) +return dev_err_probe (dev, -EBUSY ,"LED description already in use\n" ); + + ret =software_node_register_node_group (nodes);
[Severity: High]
Is there a potential race condition here when multiple devices probe concurrently?
If two threads execute lm3643_add_dmi_leds() simultaneously (for example, during concurrent sysfs bind or async probe of two LM3643 devices matching the same DMI table), they both might pass the lockless software_node_fwnode(nodes[0]) check before either registers the nodes.
Thread A could then successfully register the group via software_node_register_node_group(nodes).
Thread B would subsequently attempt to register the same static nodes array, fail, and drop into the error path within software_node_register_node_group():
drivers/base/swnode.c:software_node_register_node_group() {
...
ret = software_node_register(node_group[i]);
if (ret) {
software_node_unregister_node_group(node_group);
return ret;
}
...
}Because software_node_unregister_node_group() unconditionally unregisters the entire array, Thread B's failure teardown will free the nodes that Thread A successfully registered.
Could this lead to a use-after-free when Thread A subsequently calls device_get_child_node_count() and accesses the freed software nodes?
Quoted 8 lines
drivers/leds/flash/leds-lm3643.c +8
-0+if (ret) +return dev_err_probe (dev, ret,"failed to register the LED description\n" ); + +set_secondary_fwnode (dev,software_node_fwnode (nodes[0 ])); +dev_dbg (dev,"no LED nodes in firmware, using the DMI description\n" ); + +return devm_add_action_or_reset (dev, lm3643_remove_dmi_leds, dev); +}
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
Re: [PATCH v3 3/4] leds: flash: lm3643: Describe the LED of ACPI boards without LED nodes
Quoted 8 lines
[Severity: High]
Is there a potential race condition here when multiple devices probe concurrently?If two threads execute
lm3643_add_dmi_leds()simultaneously (for example, during concurrent sysfs bind or async probe of two LM3643 devices matching the same DMI table), they both might pass the locklesssoftware_node_fwnode(nodes[0])check before either registers the nodes.
This condition is currently unreachable. It would require two LM3643 instances on the same DMI entry.
I'd be happy to add a static mutex if preferred, or alongside any future DMI entry for a board with more than one LM3643.
Signature · 1 line
Rillian Grant
Lee Jones
maintainerRe: [PATCH v3 3/4] leds: flash: lm3643: Describe the LED of ACPI boards without LED nodes
Quoted 9 lines · Rillian Grant
Quoted 8 lines
[Severity: High]
Is there a potential race condition here when multiple devices probe concurrently?If two threads execute
lm3643_add_dmi_leds()simultaneously (for example, during concurrent sysfs bind or async probe of two LM3643 devices matching the same DMI table), they both might pass the locklesssoftware_node_fwnode(nodes[0])check before either registers the nodes.
Quoted 5 lines
This condition is currently unreachable. It would require two LM3643 instances on the same DMI entry.
I'd be happy to add a static mutex if preferred, or alongside any future DMI entry for a board with more than one LM3643.
Please.
Signature · 1 line
Lee Jones
Lee Jones
maintainerRe: [PATCH v3 3/4] leds: flash: lm3643: Describe the LED of ACPI boards without LED nodes
In reply to Rillian GrantAndy, et al., Please see below.
Quoted 88 lines · Rillian Grant
From: Ruslan Koreev <[email protected]>
Lenovo ThinkPads enumerate the LM3643 through ACPI (HID TXNW3643) without a
_DSD, so the device has no LED child nodes and the driver refuses to probe. On these laptops the chip drives the Windows Hello IR flood illuminator, with both current sources feeding a single LED, and Lenovo's Windows driver applies a fixed configuration to any LM3643 it finds.Add a DMI table that provides that description as a software node when the firmware offers none: one IR flash LED on both outputs, with torch and flash limits well below the chip's maximums. Start with the ThinkPad X1 Carbon Gen 14.
The description is keyed by DMI instead of being applied to every TXNW3643 because the wiring is a board property: which output feeds which LED and how much current the LED tolerates cannot be read from the chip, and a wrong guess overdrives an LED. The firmware cannot be fixed from the driver side, and a per-board table is what x86-android-tablets does for devices whose ACPI tables describe nothing either. Boards with a
_DSDare not affected, the fallback only runs when the device has no child nodes. The limits are conservative because the LED part is not documented; the illuminator is bright enough for face authentication at a fraction of them.Tested on that laptop: torch through /sys/class/leds/ir:flash lights the ST VD55G1 IR camera's field of view, and the resulting frames are good enough for face authentication.
Signed-off-by Ruslan Koreev <[email protected]>[rillian: add reg property to match the DT binding][rillian: change DMI activation log to dev_dbg()][rillian: use DMI_EXACT_MATCH]Signed-off-by Rillian Grant <[email protected]>--- drivers/leds/flash/leds-lm3643.c | 93 ++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+)drivers/leds/flash/leds-lm3643.c +35
-0@@ -9,6 +9,7 @@#include <linux/bitfield.h> #include <linux/bits.h> #include <linux/cleanup.h> +#include <linux/dmi.h> #include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/led-class-flash.h> @@ -691,6 +692,92 @@ static int lm3643_register_led(struct device *dev, struct lm3643 *chip,return lm3643_register_v4l2 (dev, led, fwnode); } +/* +* Lenovo ThinkPads enumerate the chip through ACPI (HID TXNW3643) without a +* _DSD, so the LED is not described by firmware. On the boards below it drives +* the Windows Hello IR flood illuminator, with both current sources feeding a +* single LED. Describe that with a software node, with torch and flash limits +* (100 mA and 300 mA per output) well below the chip's maximums. +*/ +static const u32 lm3643_ir_flood_sources[] = {0 ,1 }; + +static const struct property_entry lm3643_ir_flood_props[] = { +PROPERTY_ENTRY_U32 ("reg" ,0 ), +PROPERTY_ENTRY_U32_ARRAY ("led-sources" , lm3643_ir_flood_sources), +PROPERTY_ENTRY_STRING ("function" ,LED_FUNCTION_FLASH ), +PROPERTY_ENTRY_U32 ("color" ,LED_COLOR_ID_IR ), +PROPERTY_ENTRY_U32 ("led-max-microamp" ,200000 ), +PROPERTY_ENTRY_U32 ("flash-max-microamp" ,600000 ), +PROPERTY_ENTRY_U32 ("flash-max-timeout-us" ,100000 ), + { } +}; + +static const struct software_node lm3643_ir_flood_root = { + .name ="lm3643" , +}; + +static const struct software_node lm3643_ir_flood_led = { + .name ="led-0" , + .parent = &lm3643_ir_flood_root, + .properties = lm3643_ir_flood_props, +}; + +static const struct software_node *lm3643_ir_flood_nodes[] = { + &lm3643_ir_flood_root, + &lm3643_ir_flood_led, +NULL
drivers/leds/flash/leds-lm3643.c static int lm3643_register_led(struct device *dev, struct lm3643 *chip, · line 738
Quoted 10 lines
drivers/leds/flash/leds-lm3643.c +10
-0+}; + +static const struct dmi_system_id lm3643_dmi_leds[] = { + { +/* Lenovo ThinkPad X1 Carbon Gen 14 */ + .matches = { +DMI_EXACT_MATCH (DMI_SYS_VENDOR ,"LENOVO" ), +DMI_EXACT_MATCH (DMI_PRODUCT_VERSION ,"ThinkPad X1 Carbon Gen 14" ), + }, + .driver_data = (void *)lm3643_ir_flood_nodes,
Andy, et al.,
I don't usually allow data from other registration mechanisms to be passed through another (MFD data via OF for instance).
Is this okay?
Quoted 28 lines
drivers/leds/flash/leds-lm3643.c +28
-0+ }, + { } +}; + +static void lm3643_remove_dmi_leds (void *data) +{ +struct device *dev = data; +const struct dmi_system_id *id =dmi_first_match (lm3643_dmi_leds); + +set_secondary_fwnode (dev,NULL ); +if (id) +software_node_unregister_node_group (id->driver_data); +} + +static int lm3643_add_dmi_leds (struct device *dev) +{ +const struct dmi_system_id *id; +const struct software_node **nodes; +int ret; + +if (!has_acpi_companion (dev)) +return 0 ; + + id =dmi_first_match (lm3643_dmi_leds); +if (!id) +return 0 ; + + nodes = id->driver_data;
drivers/leds/flash/leds-lm3643.c static int lm3643_register_led(struct device *dev, struct lm3643 *chip, · line 776
Quoted 10 lines
drivers/leds/flash/leds-lm3643.c +10
-0+/* The nodes are static: a second chip on the same board cannot reuse them */ +if (software_node_fwnode (nodes[0 ])) +return dev_err_probe (dev, -EBUSY ,"LED description already in use\n" ); + + ret =software_node_register_node_group (nodes); +if (ret) +return dev_err_probe (dev, ret,"failed to register the LED description\n" ); + +set_secondary_fwnode (dev,software_node_fwnode (nodes[0 ])); +dev_dbg (dev,"no LED nodes in firmware, using the DMI description\n" );
Please remove temporary debug prints before submitting.
Quoted 24 lines
drivers/leds/flash/leds-lm3643.c +10
-0+ +return devm_add_action_or_reset (dev, lm3643_remove_dmi_leds, dev); +} +static int lm3643_probe (struct i2c_client *client) {struct device *dev = &client->dev;@@ -701,6 +788,12 @@ static int lm3643_probe(struct i2c_client *client)int ret; count =device_get_child_node_count (dev); +if (!count) { + ret =lm3643_add_dmi_leds (dev); +if (ret) +return ret; + count =device_get_child_node_count (dev); + }if (!count || count >LM3643_NUM_CHANNELS )return dev_err_probe (dev, -EINVAL ,"%u LED nodes found, expected 1 to %d\n" , count,LM3643_NUM_CHANNELS );Signature · 1 line
2.56.0
Signature · 1 line
Lee Jones
Re: [PATCH v3 3/4] leds: flash: lm3643: Describe the LED of ACPI boards without LED nodes
Hi Lee, others,
Quoted 51 lines · Lee Jones
Quoted 38 lines
drivers/leds/flash/leds-lm3643.c +34
-0@@ -691,6 +692,92 @@ static int lm3643_register_led(struct device *dev, struct lm3643 *chip,return lm3643_register_v4l2 (dev, led, fwnode); } +/* +* Lenovo ThinkPads enumerate the chip through ACPI (HID TXNW3643) without a +* _DSD, so the LED is not described by firmware. On the boards below it drives +* the Windows Hello IR flood illuminator, with both current sources feeding a +* single LED. Describe that with a software node, with torch and flash limits +* (100 mA and 300 mA per output) well below the chip's maximums. +*/ +static const u32 lm3643_ir_flood_sources[] = {0 ,1 }; + +static const struct property_entry lm3643_ir_flood_props[] = { +PROPERTY_ENTRY_U32 ("reg" ,0 ), +PROPERTY_ENTRY_U32_ARRAY ("led-sources" , lm3643_ir_flood_sources), +PROPERTY_ENTRY_STRING ("function" ,LED_FUNCTION_FLASH ), +PROPERTY_ENTRY_U32 ("color" ,LED_COLOR_ID_IR ), +PROPERTY_ENTRY_U32 ("led-max-microamp" ,200000 ), +PROPERTY_ENTRY_U32 ("flash-max-microamp" ,600000 ), +PROPERTY_ENTRY_U32 ("flash-max-timeout-us" ,100000 ), + { } +}; + +static const struct software_node lm3643_ir_flood_root = { + .name ="lm3643" , +}; + +static const struct software_node lm3643_ir_flood_led = { + .name ="led-0" , + .parent = &lm3643_ir_flood_root, + .properties = lm3643_ir_flood_props, +}; + +static const struct software_node *lm3643_ir_flood_nodes[] = { + &lm3643_ir_flood_root, + &lm3643_ir_flood_led, +NULL drivers/leds/flash/leds-lm3643.c static int lm3643_register_led(struct device *dev, struct lm3643 *chip, · line 738
Quoted 10 lines
drivers/leds/flash/leds-lm3643.c +10
-0+}; + +static const struct dmi_system_id lm3643_dmi_leds[] = { + { +/* Lenovo ThinkPad X1 Carbon Gen 14 */ + .matches = { +DMI_EXACT_MATCH (DMI_SYS_VENDOR ,"LENOVO" ), +DMI_EXACT_MATCH (DMI_PRODUCT_VERSION ,"ThinkPad X1 Carbon Gen 14" ), + }, + .driver_data = (void *)lm3643_ir_flood_nodes,Andy, et al.,
Quoted 4 lines
I don't usually allow data from other registration mechanisms to be passed through another (MFD data via OF for instance).
Is this okay?
In this case the ipu-bridge needs to provide the information to the lm3643 driver via software nodes, as it already does for a number of other devices. There's no point in putting the information to the LED driver.
Presumably the ACPI device node already exists so this should be straightforward. What's also missing from the sensor then is the flash-leds property, the lens-focus handling serves as an example.
Signature · 3 lines
Regards, Sakari Ailus
Re: [PATCH v3 3/4] leds: flash: lm3643: Describe the LED of ACPI boards without LED nodes
Quoted 1 line · Sakari Ailus
On Tue, Oct 20, 2026 at 11:45:06AM +0100, Lee Jones wrote:
...
Quoted 6 lines
Quoted 6 lines
Andy, et al.,
I don't usually allow data from other registration mechanisms to be passed through another (MFD data via OF for instance).
Is this okay?
Seconding Sakari's answer, this doesn't sound like the best approach.
Quoted 7 lines
In this case the ipu-bridge needs to provide the information to the lm3643 driver via software nodes, as it already does for a number of other devices. There's no point in putting the information to the LED driver.
Presumably the ACPI device node already exists so this should be straightforward. What's also missing from the sensor then is the flash-leds property, the lens-focus handling serves as an example.
+1 to all the above.
Signature · 2 lines
With Best Regards, Andy Shevchenko
PATCH v3 4/4 leds: flash: lm3643: Describe the LED on the Lenovo ThinkPad X9-15 Gen 1
In reply to Rillian GrantThe ThinkPad X9-15 Gen 1 enumerates the LM3643 through ACPI (HID TXNW3643) without a _DSD, like the X1 Carbon Gen 14. It drives the Windows Hello IR flood illuminator with both current sources feeding a single LED.
The flash limits were obtained from an ETW trace of the SPB class extension during a Windows Hello unlock. The Windows driver programs 304 mA per current source (code 0x19 with the LED2 override set) and a 400 ms flash timeout.
There is no vendor value for the torch limit, so use the same conservative limit as the X1 Carbon Gen 14.
Rename the X1 Carbon Gen 14 nodes after the machine now that the table has a second entry. Sources and root node remain shared.
--- drivers/leds/flash/leds-lm3643.c | 70 +++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 15 deletions(-)
drivers/leds/flash/leds-lm3643.c +55 -15
@@ -692,16 +692,21 @@ static int lm3643_register_led(struct device *dev, struct lm3643 *chip,return lm3643_register_v4l2 (dev, led, fwnode); } -/* -* Lenovo ThinkPads enumerate the chip through ACPI (HID TXNW3643) without a -* _DSD, so the LED is not described by firmware. On the boards below it drives -* the Windows Hello IR flood illuminator, with both current sources feeding a -* single LED. Describe that with a software node, with torch and flash limits -* (100 mA and 300 mA per output) well below the chip's maximums. -*/ static const u32 lm3643_ir_flood_sources[] = {0 ,1 }; -static const struct property_entry lm3643_ir_flood_props[] = { +static const struct software_node lm3643_ir_flood_root = { + .name ="lm3643" , +}; + +/* +* The Lenovo ThinkPad X1 Carbon Gen 14 enumerates the chip through ACPI +* (HID TXNW3643) without a _DSD, so the LED is not described by firmware. +* On the X1 Gen 14 it drives the Windows Hello IR flood illuminator, with +* both current sources feeding a single LED. Describe that with a software +* node, with torch and flash limits (100 mA and 300 mA per output) well below +* the chip's maximums. +*/ +static const struct property_entry lm3643_x1c14_props[] = {PROPERTY_ENTRY_U32 ("reg" ,0 ),PROPERTY_ENTRY_U32_ARRAY ("led-sources" , lm3643_ir_flood_sources),PROPERTY_ENTRY_STRING ("function" ,LED_FUNCTION_FLASH ),
@@ -712,19 +717,46 @@ static const struct property_entry lm3643_ir_flood_props[] = { { } }; -static const struct software_node lm3643_ir_flood_root = { - .name ="lm3643" , +static const struct software_node lm3643_x1c14_led = { + .name ="led-0" , + .parent = &lm3643_ir_flood_root, + .properties = lm3643_x1c14_props, +}; + +static const struct software_node *lm3643_x1c14_nodes[] = { + &lm3643_ir_flood_root, + &lm3643_x1c14_led, +NULL }; -static const struct software_node lm3643_ir_flood_led = { +/* +* The Lenovo ThinkPad X9-15 Gen 1 enumerates the chip through ACPI +* (HID TXNW3643) without a _DSD. On the X9-15 it drives the Windows Hello IR +* flood illuminator, with both current sources feeding a single LED. Flash +* maximums were obtained from an SPB class extension ETW trace of the +* vendor-supplied Windows driver. The torch limit is a conservative value well +* below the chip's maximum. +*/ +static const struct property_entry lm3643_x9_15_props[] = { +PROPERTY_ENTRY_U32 ("reg" ,0 ), +PROPERTY_ENTRY_U32_ARRAY ("led-sources" , lm3643_ir_flood_sources), +PROPERTY_ENTRY_STRING ("function" ,LED_FUNCTION_FLASH ), +PROPERTY_ENTRY_U32 ("color" ,LED_COLOR_ID_IR ), +PROPERTY_ENTRY_U32 ("led-max-microamp" ,200000 ), +PROPERTY_ENTRY_U32 ("flash-max-microamp" ,608050 ), +PROPERTY_ENTRY_U32 ("flash-max-timeout-us" ,400000 ), + { } +}; + +static const struct software_node lm3643_x9_15_led = { .name ="led-0" , .parent = &lm3643_ir_flood_root, - .properties = lm3643_ir_flood_props, + .properties = lm3643_x9_15_props, }; -static const struct software_node *lm3643_ir_flood_nodes[] = { +static const struct software_node *lm3643_x9_15_nodes[] = { &lm3643_ir_flood_root, - &lm3643_ir_flood_led, + &lm3643_x9_15_led,NULL };
@@ -735,7 +767,15 @@ static const struct dmi_system_id lm3643_dmi_leds[] = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X1 Carbon Gen 14"), }, - .driver_data = (void *)lm3643_ir_flood_nodes, + .driver_data = (void *)lm3643_x1c14_nodes, + }, + { + /* Lenovo ThinkPad X9-15 Gen 1 */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X9-15 Gen 1"), + }, + .driver_data = (void *)lm3643_x9_15_nodes, }, { } };
Signature · 1 line
2.56.0
[email protected]
AI reviewRe: [PATCH v3 4/4] leds: flash: lm3643: Describe the LED on the Lenovo ThinkPad X9-15 Gen 1
Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 10 lines
The ThinkPad X9-15 Gen 1 enumerates the LM3643 through ACPI (HID TXNW3643) without a
_DSD, like the X1 Carbon Gen 14. It drives the Windows Hello IR flood illuminator with both current sources feeding a single LED.The flash limits were obtained from an ETW trace of the SPB class extension during a Windows Hello unlock. The Windows driver programs 304 mA per current source (code
0x19with the LED2 override set) and a 400 ms flash timeout.
Quoted 7 lines
There is no vendor value for the torch limit, so use the same conservative limit as the X1 Carbon Gen 14.
Rename the X1 Carbon Gen 14 nodes after the machine now that the table has a second entry. Sources and root node remain shared.
Signed-off-by Rillian Grant <[email protected]>
Sashiko has reviewed this patch and found no issues. It looks great!
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=4
Lee Jones
maintainerRe: [PATCH v3 4/4] leds: flash: lm3643: Describe the LED on the Lenovo ThinkPad X9-15 Gen 1
In reply to Rillian Grant--- checkpatch.pl: clean (0 issues) ---
Quoted 82 lines · Rillian Grant
The ThinkPad X9-15 Gen 1 enumerates the LM3643 through ACPI (HID TXNW3643) without a
_DSD, like the X1 Carbon Gen 14. It drives the Windows Hello IR flood illuminator with both current sources feeding a single LED.The flash limits were obtained from an ETW trace of the SPB class extension during a Windows Hello unlock. The Windows driver programs 304 mA per current source (code
0x19with the LED2 override set) and a 400 ms flash timeout.There is no vendor value for the torch limit, so use the same conservative limit as the X1 Carbon Gen 14.
Rename the X1 Carbon Gen 14 nodes after the machine now that the table has a second entry. Sources and root node remain shared.
Signed-off-by Rillian Grant <[email protected]>--- drivers/leds/flash/leds-lm3643.c | 70 +++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 15 deletions(-)drivers/leds/flash/leds-lm3643.c +31
-11@@ -692,16 +692,21 @@ static int lm3643_register_led(struct device *dev, struct lm3643 *chip,return lm3643_register_v4l2 (dev, led, fwnode); } -/* -* Lenovo ThinkPads enumerate the chip through ACPI (HID TXNW3643) without a -* _DSD, so the LED is not described by firmware. On the boards below it drives -* the Windows Hello IR flood illuminator, with both current sources feeding a -* single LED. Describe that with a software node, with torch and flash limits -* (100 mA and 300 mA per output) well below the chip's maximums. -*/ static const u32 lm3643_ir_flood_sources[] = {0 ,1 }; -static const struct property_entry lm3643_ir_flood_props[] = { +static const struct software_node lm3643_ir_flood_root = { + .name ="lm3643" , +}; + +/* +* The Lenovo ThinkPad X1 Carbon Gen 14 enumerates the chip through ACPI +* (HID TXNW3643) without a _DSD, so the LED is not described by firmware. +* On the X1 Gen 14 it drives the Windows Hello IR flood illuminator, with +* both current sources feeding a single LED. Describe that with a software +* node, with torch and flash limits (100 mA and 300 mA per output) well below +* the chip's maximums. +*/ +static const struct property_entry lm3643_x1c14_props[] = {PROPERTY_ENTRY_U32 ("reg" ,0 ),PROPERTY_ENTRY_U32_ARRAY ("led-sources" , lm3643_ir_flood_sources),PROPERTY_ENTRY_STRING ("function" ,LED_FUNCTION_FLASH ),@@ -712,19 +717,46 @@ static const struct property_entry lm3643_ir_flood_props[] = { { } }; -static const struct software_node lm3643_ir_flood_root = { - .name ="lm3643" , +static const struct software_node lm3643_x1c14_led = { + .name ="led-0" , + .parent = &lm3643_ir_flood_root, + .properties = lm3643_x1c14_props, +}; + +static const struct software_node *lm3643_x1c14_nodes[] = { + &lm3643_ir_flood_root, + &lm3643_x1c14_led, +NULL }; -static const struct software_node lm3643_ir_flood_led = { +/* +* The Lenovo ThinkPad X9-15 Gen 1 enumerates the chip through ACPI +* (HID TXNW3643) without a _DSD. On the X9-15 it drives the Windows Hello IR +* flood illuminator, with both current sources feeding a single LED. Flash +* maximums were obtained from an SPB class extension ETW trace of the +* vendor-supplied Windows driver. The torch limit is a conservative value well +* below the chip's maximum. +*/
drivers/leds/flash/leds-lm3643.c static const struct property_entry lm3643_ir_flood_props[] = { · line 749
Quoted 10 lines
drivers/leds/flash/leds-lm3643.c +10
-0+static const struct property_entry lm3643_x9_15_props[] = { +PROPERTY_ENTRY_U32 ("reg" ,0 ), +PROPERTY_ENTRY_U32_ARRAY ("led-sources" , lm3643_ir_flood_sources), +PROPERTY_ENTRY_STRING ("function" ,LED_FUNCTION_FLASH ), +PROPERTY_ENTRY_U32 ("color" ,LED_COLOR_ID_IR ), +PROPERTY_ENTRY_U32 ("led-max-microamp" ,200000 ), +PROPERTY_ENTRY_U32 ("flash-max-microamp" ,608050 ), +PROPERTY_ENTRY_U32 ("flash-max-timeout-us" ,400000 ), + { } +};
Given that Patch 3 [0] uses conservative fallback values (600000 uA and 300000 us) versus these traced Windows driver values (608050 uA and 400000 us), why don't we just use the same set of properties for both machines and save ourselves some duplication?
[0]
static const struct property_entry lm3643_ir_flood_props[] = {
PROPERTY_ENTRY_U32("reg", 0),
PROPERTY_ENTRY_U32_ARRAY("led-sources", lm3643_ir_flood_sources),
PROPERTY_ENTRY_STRING("function", LED_FUNCTION_FLASH),
PROPERTY_ENTRY_U32("color", LED_COLOR_ID_IR),
PROPERTY_ENTRY_U32("led-max-microamp", 200000),
PROPERTY_ENTRY_U32("flash-max-microamp", 600000),
PROPERTY_ENTRY_U32("flash-max-timeout-us", 100000),
{ }
};Quoted 37 lines
drivers/leds/flash/leds-lm3643.c +14
-4+ +static const struct software_node lm3643_x9_15_led = { .name ="led-0" , .parent = &lm3643_ir_flood_root, - .properties = lm3643_ir_flood_props, + .properties = lm3643_x9_15_props, }; -static const struct software_node *lm3643_ir_flood_nodes[] = { +static const struct software_node *lm3643_x9_15_nodes[] = { &lm3643_ir_flood_root, - &lm3643_ir_flood_led, + &lm3643_x9_15_led,NULL };@@ -735,7 +767,15 @@ static const struct dmi_system_id lm3643_dmi_leds[] = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X1 Carbon Gen 14"), }, - .driver_data = (void *)lm3643_ir_flood_nodes, + .driver_data = (void *)lm3643_x1c14_nodes, + }, + { + /* Lenovo ThinkPad X9-15 Gen 1 */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X9-15 Gen 1"), + }, + .driver_data = (void *)lm3643_x9_15_nodes, }, { } };Signature · 1 line
2.56.0
Signature · 1 line
Lee Jones
Re: [PATCH v3 4/4] leds: flash: lm3643: Describe the LED on the Lenovo ThinkPad X9-15 Gen 1
Hi Lee,
We can share the board-description code in ipu-bridge and add flash-leds, as Sakari and Andy suggested, while keeping per-board current settings.
Lenovo's packages set IRFlashLedIntensity=30 for the X1 [1] and 40 for the X9 [2]. With both outputs using the same current setting, these convert to nominal totals of 467350 uA and 608050 uA respectively. The X9 result matches Rillian's trace; the X1 result is from static analysis, with live Windows behavior still unverified.
My earlier claim that Windows applies a fixed configuration to any LM3643 was too broad: the sensor configuration affects the current request.
Both default paths configure a 400 ms controller timeout. Actual mode, pulse duration and continuous-torch limits remain unverified, so these are candidate operating settings rather than established LED limits.
Rillian, could you share the relevant SPB trace, including mode, current and timeout writes, together with the installed driver version?
[1] https://download.lenovo.com/pccbbs/mobiles/n4oce17w.html
[2] https://download.lenovo.com/pccbbs/mobiles/n4cim20w.html
Ruslan
Re: [PATCH v3 4/4] leds: flash: lm3643: Describe the LED on the Lenovo ThinkPad X9-15 Gen 1
Hi Ruslan,
Quoted 2 lines · On Wednesday, 21 October 2026 15:40:34 GMT Ruslan Koreev wrote:
Rillian, could you share the relevant SPB trace, including mode, current and timeout writes, together with the installed driver version?
Driver versions: the X9-15 Gen 1 values are from the Windows install on my machine. The X1 Carbon Gen 14 values are from the current package on Lenovo's support site.
X9-15 Gen 1:
- lm3643.inf/.sys 70.26100.2.18321 (02/20/2025)
- IR sensor: HM1092, hm1092.inf 70.26100.2.18321
- FlashLEDsIntensity = 0x3C64 (lm3643.inf)
- IRFlashLedIntensity = 40 (hm1092.inf)
X1 Carbon Gen 14:
- lm3643.inf 71.26100.10.21060 (08/05/2026) however lm3643.sys contradicts with 71.26100.23.21060
- IR sensor: VD55G1, TBE0020A1.inf 71.26100.10.21060
- FlashLEDsIntensity = 0x3C64 (lm3643.inf)
- IRFlashLedIntensity = 30 (TBE0020A1.inf)
Both lm3643.inf files bind ACPI\TXNW3643 and ACPI\INT347D. Apart from the version, they differ only in where DeviceCharacteristics/Security are written. The registry on the X9 matches the INF defaults.
Before I submitted the DMI software node patch, I had seen that the Carbon had a different driver version and a different IRFlashLedIntensity. That is why I didn't reuse its values for the X9.
I traced Microsoft-Windows-SPB-ClassExtension (analytic) during a Windows Hello face unlock on the X9. Every write to the LM3643 is preceded by a read of the same register. Register decodes are from SNVS967A.
Start of the session (once, after the controller entered D0):
R 0x0A=00 R 0x0B=00 R 0x01=03 R 0x0C=02
R 0x07=09 -> W 0x07=09 boost config, POR default (2 MHz, 2.8 A ILIM,
short detect on)
W 0x01=03 standby, LED1+LED2 enable, TX pin enable off
(POR is 0x80)
W 0x08=00 no torch ramp, flash timeout 10 ms
Per pulse (repeats every ~133 ms):
W 0x01=03 standby
W 0x08=0F no torch ramp, flash timeout 400 ms
W 0x03=99 bit7 = LED2 flash current override (LED2 = LED1),
code 0x19 -> 25 x 11.725 + 10.9 = ~304 mA per
LED (~608 mA total)
W 0x01=0F flash mode (M1,M0=11), LED1+LED2 <- LED on
... ~65 ms ...
W 0x08=00 timeout set to 10 ms while the flash is running
W 0x01=03 standby <- LED off
R 0x0A=01 R 0x0B=00 Flags1 bit0 = flash time-out flag (0x00 after
the first pulse, 0x01 after every later pulse)This unlock had 6 pulses. The last one was turned off after ~3 ms, once the face was recognised. The driver never wrote the torch registers (0x05/0x06) or the LED2 flash register (0x04), and never used IR mode, STROBE or TX. The only values written to 0x01 were 0x03 and 0x0F.
The LM3643 transactions with timestamps are attached. The raw ETL/XML trace is available on request.
--
Rillian Grant
10:47:24.493347 LM3643 W 0x0A | R 0x00 10:47:24.493427 -- controller 0x3CF250DE2738 D-state 0x1 10:47:24.504454 LM3643 W 0x0B | R 0x00 10:47:24.504748 LM3643 W 0x01 | R 0x03 10:47:24.505018 LM3643 W 0x0C | R 0x02 10:47:24.505315 LM3643 W 0x07 | R 0x09 10:47:24.505564 LM3643 W 0x0709 10:47:24.505741 LM3643 W 0x01 | R 0x03 10:47:24.506021 LM3643 W 0x0103 10:47:24.506229 LM3643 W 0x01 | R 0x03 10:47:24.506479 LM3643 W 0x01 | R 0x03 10:47:24.506736 LM3643 W 0x0103 10:47:24.507080 LM3643 W 0x08 | R 0x00 10:47:24.507317 LM3643 W 0x0800 10:47:24.507537 LM3643 W 0x01 | R 0x03 10:47:24.507777 LM3643 W 0x0103 10:47:24.507935 LM3643 W 0x01 | R 0x03 10:47:24.508181 LM3643 W 0x0103 10:47:24.552953 HM1092(IR) W 0x010000 10:47:24.632548 HM1092(IR) W 0x010001 10:47:24.669203 -- controller 0x3CF250DDE738 D-state 0x1 10:47:24.675057 LM3643 W 0x01 | R 0x03 10:47:24.675520 LM3643 W 0x0103 10:47:24.675806 LM3643 W 0x08 | R 0x00 10:47:24.676278 LM3643 W 0x080F 10:47:24.676575 LM3643 W 0x03 | R 0x99 10:47:24.676857 LM3643 W 0x0399 10:47:24.677059 LM3643 W 0x01 | R 0x03 10:47:24.677316 LM3643 W 0x010F 10:47:24.681780 IMX471(RGB) W 0x010000 10:47:24.741365 LM3643 W 0x08 | R 0x0F 10:47:24.741647 LM3643 W 0x0800 10:47:24.741872 LM3643 W 0x01 | R 0x0F 10:47:24.742178 LM3643 W 0x0103 10:47:24.742372 LM3643 W 0x0A | R 0x00 10:47:24.742621 LM3643 W 0x0B | R 0x00 10:47:24.742969 IMX471(RGB) W 0x010001 10:47:24.807808 LM3643 W 0x01 | R 0x03 10:47:24.808069 LM3643 W 0x0103 10:47:24.808246 LM3643 W 0x08 | R 0x00 10:47:24.808503 LM3643 W 0x080F 10:47:24.808776 LM3643 W 0x03 | R 0x99 10:47:24.809023 LM3643 W 0x0399 10:47:24.809178 LM3643 W 0x01 | R 0x03 10:47:24.809456 LM3643 W 0x010F 10:47:24.874410 LM3643 W 0x08 | R 0x0F 10:47:24.874691 LM3643 W 0x0800 10:47:24.874913 LM3643 W 0x01 | R 0x0F 10:47:24.875165 LM3643 W 0x0103 10:47:24.875371 LM3643 W 0x0A | R 0x01 10:47:24.875619 LM3643 W 0x0B | R 0x00 10:47:24.940847 LM3643 W 0x01 | R 0x03 10:47:24.941139 LM3643 W 0x0103 10:47:24.941306 LM3643 W 0x08 | R 0x00 10:47:24.941552 LM3643 W 0x080F 10:47:24.941768 LM3643 W 0x03 | R 0x99 10:47:24.942104 LM3643 W 0x0399 10:47:24.942271 LM3643 W 0x01 | R 0x03 10:47:24.942513 LM3643 W 0x010F 10:47:25.007386 LM3643 W 0x08 | R 0x0F 10:47:25.007683 LM3643 W 0x0800 10:47:25.007896 LM3643 W 0x01 | R 0x0F 10:47:25.008160 LM3643 W 0x0103 10:47:25.008322 LM3643 W 0x0A | R 0x01 10:47:25.008577 LM3643 W 0x0B | R 0x00 10:47:25.073907 LM3643 W 0x01 | R 0x03 10:47:25.074207 LM3643 W 0x0103 10:47:25.074392 LM3643 W 0x08 | R 0x00 10:47:25.074649 LM3643 W 0x080F 10:47:25.074867 LM3643 W 0x03 | R 0x99 10:47:25.075123 LM3643 W 0x0399 10:47:25.075366 LM3643 W 0x01 | R 0x03 10:47:25.075621 LM3643 W 0x010F 10:47:25.140383 LM3643 W 0x08 | R 0x0F 10:47:25.140639 LM3643 W 0x0800 10:47:25.140858 LM3643 W 0x01 | R 0x0F 10:47:25.141103 LM3643 W 0x0103 10:47:25.141266 LM3643 W 0x0A | R 0x01 10:47:25.141507 LM3643 W 0x0B | R 0x00 10:47:25.206938 LM3643 W 0x01 | R 0x03 10:47:25.207270 LM3643 W 0x0103 10:47:25.207443 LM3643 W 0x08 | R 0x00 10:47:25.207689 LM3643 W 0x080F 10:47:25.207897 LM3643 W 0x03 | R 0x99 10:47:25.208150 LM3643 W 0x0399 10:47:25.208318 LM3643 W 0x01 | R 0x03 10:47:25.208581 LM3643 W 0x010F 10:47:25.273481 LM3643 W 0x08 | R 0x0F 10:47:25.273782 LM3643 W 0x0800 10:47:25.274032 LM3643 W 0x01 | R 0x0F 10:47:25.274303 LM3643 W 0x0103 10:47:25.274485 LM3643 W 0x0A | R 0x01 10:47:25.274721 LM3643 W 0x0B | R 0x00 10:47:25.339949 LM3643 W 0x01 | R 0x03 10:47:25.340239 LM3643 W 0x0103 10:47:25.340418 LM3643 W 0x08 | R 0x00 10:47:25.340684 LM3643 W 0x080F 10:47:25.340932 LM3643 W 0x03 | R 0x99 10:47:25.341210 LM3643 W 0x0399 10:47:25.341406 LM3643 W 0x01 | R 0x03 10:47:25.341660 LM3643 W 0x010F 10:47:25.344654 LM3643 W 0x08 | R 0x0F 10:47:25.344956 LM3643 W 0x0800 10:47:25.345171 LM3643 W 0x01 | R 0x0F 10:47:25.345419 LM3643 W 0x0103 10:47:25.345575 LM3643 W 0x0A | R 0x01 10:47:25.345808 LM3643 W 0x0B | R 0x00 10:47:25.473344 HM1092(IR) W 0x010000 10:47:25.474241 LM3643 W 0x08 | R 0x00 10:47:25.474501 LM3643 W 0x0800 10:47:25.474715 LM3643 W 0x01 | R 0x03 10:47:25.474956 LM3643 W 0x0103 10:47:25.475106 LM3643 W 0x01 | R 0x03 10:47:25.475403 LM3643 W 0x0103 10:47:25.486367 LM3643 W 0x0A | R 0x01 10:47:25.486763 LM3643 W 0x0B | R 0x00 10:47:25.623971 IMX471(RGB) W 0x010000 10:47:27.620034 -- controller 0x3CF250DE2738 D-state 0x4 10:47:28.631808 -- controller 0x3CF250DDE738 D-state 0x4