summaryrefslogtreecommitdiff
path: root/drivers/leds
AgeCommit message (Collapse)Author
21 hoursMerge branch 'headers' of git://git.infradead.org/users/willy/pagecache.gitMark Brown
# Conflicts: # drivers/gpu/drm/amd/amdkfd/kfd_migrate.c # net/ceph/osd_client.c
22 hoursMerge branch 'for-leds-next' of ↵Mark Brown
https://git.kernel.org/pub/scm/linux/kernel/git/lee/leds.git
2026-09-24leds: trigger: Add led_trigger_notify_hw_control_changed() interfaceRong Zhang
Some hardware can autonomously activate/deactivate hardware control. After that, the LED hardware notifies the LED driver. Currently, there is no mechanism for LED drivers to notify the LED core about such events and initiate a trigger transition to reflect the hardware state. Add a new interface called led_trigger_notify_hw_control_changed(), so that LED drivers can call it to notify the LED core about the transition. The interface only allows two transitions: 1. "none" => private trigger 2. private trigger => "none" If the current trigger is neither the private trigger nor "none", no transition will be made. This protects the currently selected software trigger. Note that LED_OFF won't be emitted during the #2 transition, as some hardware may have selected a new brightness level during its hardware state transition (e.g., laptop keyboards with a shortcut cycling through different backlight brightnesses and auto mode). The interface is designed as a void function as any failure should be non-fatal and the result of transition should not have any impact on the LED drivers' event handling procedures. To use the interface, the config LEDS_TRIGGERS_HW_CHANGED must be enabled, and the LED driver must set the LED_TRIG_HW_CHANGED flag for the classdev. By default, the config is enabled when LEDS_BRIGHTNESS_HW_CHANGED is enabled. Acked-by: Ike Panhc <ikepanhc@gmail.com> Signed-off-by: Rong Zhang <i@rong.moe> Link: https://patch.msgid.link/20260921-leds-trigger-hw-changed-v7-10-fe3cdb6dec51@rong.moe Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-24leds: trigger: Enforce strict checks in led_trigger_is_hw_controlled()Rong Zhang
With all existing triggers adopting the new interface, strict checks could be enforced to make the semantics of hardware control triggers clearer. In detail, a hardware control trigger should: - Implement hw_offloaded() callback to indicate hardware control - Associate with the LED classdev's hw_control_trigger string The fallback path is kept, but a warning message is emitted when it reaches there. Acked-by: Ike Panhc <ikepanhc@gmail.com> Signed-off-by: Rong Zhang <i@rong.moe> Link: https://patch.msgid.link/20260921-leds-trigger-hw-changed-v7-9-fe3cdb6dec51@rong.moe Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-24leds: trigger: netdev: Implement hw_offloaded() callbackRong Zhang
"netdev" can run in hardware control according to hardware capabilities and trigger options. Implement hw_offloaded() callback to provide its hardware control state to the LED core, and document the relation between the custom "offloaded" attribute and the generic "trigger_may_offload_to_hw" attribute. The callback mimics how the existing "offloaded" attribute does, i.e., locklessly reads hw_control, as it's just a hint and don't need to be accurate. Acked-by: Ike Panhc <ikepanhc@gmail.com> Signed-off-by: Rong Zhang <i@rong.moe> Link: https://patch.msgid.link/20260921-leds-trigger-hw-changed-v7-8-fe3cdb6dec51@rong.moe Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-24leds: turris-omnia: Implement hw_offloaded() trigger callback and declare ↵Rong Zhang
hw_control_trigger "omnia-mcu" is a private hardware control trigger which always stays in hardware control mode. Implement hw_offloaded() callback with its return value to be always true to reflect this. Meanwhile, declare it as a hardware control trigger as it's forgotten before. Acked-by: Ike Panhc <ikepanhc@gmail.com> Signed-off-by: Rong Zhang <i@rong.moe> Link: https://patch.msgid.link/20260921-leds-trigger-hw-changed-v7-7-fe3cdb6dec51@rong.moe Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-24leds: cros_ec: Implement hw_offloaded() trigger callbackRong Zhang
"chromeos-auto" is a private hardware control trigger which always stays in hardware control. Implement hw_offloaded() callback with its return value to be always true to reflect this. Reviewed-by: Thomas Weißschuh <linux@weissschuh.net> Acked-by: Ike Panhc <ikepanhc@gmail.com> Signed-off-by: Rong Zhang <i@rong.moe> Link: https://patch.msgid.link/20260921-leds-trigger-hw-changed-v7-6-fe3cdb6dec51@rong.moe Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-24leds: trigger: Add hw_offloaded() callback and provide ↵Rong Zhang
trigger_may_offload_to_hw attribute There are multiple triggers implementing hardware control. However, the LED trigger core doesn't really know the hardware control (offloaded) state since the coordination is done directly between the trigger and the LED driver. It can only assume private triggers as offloaded and generic ones as not offloaded. Add an hw_offloaded() callback so that triggers can report their offloaded states to the LED trigger core. When unimplemented, it defaults to true for private triggers and false for generic ones to keep the current behavior unchanged. With that, provide a new attribute "trigger_may_offload_to_hw", so that userspace can determine: - if the LED device supports hardware control (supported => visible) - which trigger is the hardware control trigger selected by the LED device and offloaded to hardware ("[foo_trigger]") Note: the documentation describes the attribute as "returning a list" despite the LED core currently only supports one hardware control trigger per LED device. This is intentional to make the attribute extensible in the future without breaking userspace. IOW, userspace should parse the new attribute in the same way as /sys/class/leds/<led>/trigger. Acked-by: Ike Panhc <ikepanhc@gmail.com> Signed-off-by: Rong Zhang <i@rong.moe> Link: https://patch.msgid.link/20260921-leds-trigger-hw-changed-v7-5-fe3cdb6dec51@rong.moe Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-24leds: trigger: Move led_trigger_group to the right placeRong Zhang
Currently led_trigger_group and its members are placed at led-class.c, but they falls into the triggers namespace and does triggers stuff. Placing them at led-class.c also requires the read and write callback to be exported and results in an extra #ifdef block. Move it into led-triggers.c, so that it becomes the only symbol to be exported for sysfs attributes. Signed-off-by: Rong Zhang <i@rong.moe> Link: https://patch.msgid.link/20260921-leds-trigger-hw-changed-v7-4-fe3cdb6dec51@rong.moe Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-24leds: class: Remove hardware control trigger when writing brightnessRong Zhang
Since commit b819dc7d8fb2 ("leds: core: Report ENODATA for brightness of hardware controlled LED"), the brightness attribute becomes write-only when the LED is controlled fully by the hardware. A write-only attribute is very confusing. Moreover, most LED drivers set hardware brightness innocently with the side effect of disabling hardware control, but the hardware control trigger remains active, resulting in the software and hardware being out of sync. Fix it by removing the hardware control trigger when writing the brightness attribute. This should also match the semantics of hardware control: When the LED is in hw control, no software blink is possible and doing so will effectively disable hw control. Fixes: b819dc7d8fb2 ("leds: core: Report ENODATA for brightness of hardware controlled LED") Acked-by: Ike Panhc <ikepanhc@gmail.com> Signed-off-by: Rong Zhang <i@rong.moe> Link: https://patch.msgid.link/20260921-leds-trigger-hw-changed-v7-3-fe3cdb6dec51@rong.moe Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-24leds: trigger: Move led_trigger_is_hw_controlled() to the right placeRong Zhang
Currently led_trigger_is_hw_controlled() is placed at led-class.c, which is not an right place as it falls into the triggers namespace and does triggers stuff. Move it into led-triggers.c, and split it into locked and unlocked variant for convenience. Fixes: b819dc7d8fb2 ("leds: core: Report ENODATA for brightness of hardware controlled LED") Acked-by: Ike Panhc <ikepanhc@gmail.com> Signed-off-by: Rong Zhang <i@rong.moe> Link: https://patch.msgid.link/20260921-leds-trigger-hw-changed-v7-2-fe3cdb6dec51@rong.moe Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-24leds: class: Always protect brightness_show() with led_accessRong Zhang
The led_classdev_register_ext() protects transient states when registering with the led_access mutex and relies on all sensitive sysfs attribute callbacks holding the mutex to prevent exposing transient states. The Fixes: commit broke this as it accessed trigger_lock without holding led_access. Fix it by protecting brightness_show() with led_access in all code paths. Fixes: b819dc7d8fb2 ("leds: core: Report ENODATA for brightness of hardware controlled LED") Signed-off-by: Rong Zhang <i@rong.moe> Link: https://patch.msgid.link/20260921-leds-trigger-hw-changed-v7-1-fe3cdb6dec51@rong.moe Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-23leds: rgb: qcom-lpg: Use fwnode APIs for LED parsingRosen Penev
Convert LED and channel parsing in lpg_add_led() and lpg_parse_channel() from DT-specific helpers to the fwnode API. The probe loop now uses device_for_each_child_node_scoped(), dropping explicit node lifetime handling. Behaviour is unchanged for device tree: fwnode_get_child_node_count() and both child iteration helpers skip unavailable children on OF, and the fwnode handle is passed straight to LED registration. cdev->default_trigger is only assigned when fwnode_property_read_string() succeeds, so an absent linux,default-trigger property no longer yields an uninitialized pointer. Assisted-by: LLM Signed-off-by: Rosen Penev <rosenp@gmail.com> Link: https://patch.msgid.link/20260919001331.720072-1-rosenp@gmail.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-23leds: Use assign_bit() where applicablePeng Fan
Convert open-coded if/else with set_bit/clear_bit and their non-atomic __set_bit/__clear_bit variants to the assign_bit/__assign_bit API. Done with Coccinelle semantic patch and manual fixups. Signed-off-by: Peng Fan <peng.fan@nxp.com> Link: https://patch.msgid.link/20260918141728.3022983-1-peng.fan@oss.nxp.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-23leds: aat1290: Allocate mm_current_scale with ARRAY_SIZE()Kees Cook
In preparation for making the devm_kmalloc family of allocators type aware, we need to make sure that the returned type from the allocation matches the type of the variable being assigned. (Before, the allocator would always return "void *", which can be implicitly cast to any pointer type.) This allocates one int per entry of max_mm_current_percent, but the size was taken from the whole array, which would make the allocation type a pointer to the array rather than the "int *" being assigned. Allocate ARRAY_SIZE-many entries instead. The resulting allocation size is the same: AAT1290_MM_CURRENT_SCALE_SIZE and ARRAY_SIZE(max_mm_current_percent) are both 15. Build tested ARCH=x86_64 allmodconfig with GCC 16.2.0: drivers/leds/flash/leds-aat1290.o Assisted-by: LLM coccinelle Signed-off-by: Kees Cook <kees+treewide@kernel.org> Link: https://patch.msgid.link/20260917211357.i.412-kees@kernel.org Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-23leds: ltc3208: Add driver for LTC3208 Multidisplay LED DriverJan Carlo Roleda
Kernel driver implementation for LTC3208 Multidisplay LED Driver. The LTC3208 is a Multi-display LED driver, designed to control up to 7 distinct LED channels (MAIN, SUB, AUX, CAMHI, CAMLO, RED, GREEN, BLUE), each configurable with its own current level that is equally set to its respective output current source pins for external LEDs. It is programmed via the I2C serial interface. MAIN and SUB support 8-bit current level resolution, while AUX, CAMHI/LO, RED, GREEN, and BLUE support 4-bit levels. The AUX LED channel can be configured to mirror the CAM, SUB, and MAIN channel current levels, or as its own independent AUX channel. The CAM LED channel is configured as 2 separate CAMHI and CAMLO register sub-channels, which current is selected via the CAMHL pin, or set to CAMHI register only via setting the S_CAMHILO bit high in register G (0x7). Signed-off-by: Jan Carlo Roleda <jancarlo.roleda@analog.com> Link: https://patch.msgid.link/20260923003325.61722-3-jancarlo.roleda@analog.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-22leds: flash: Simplify flash_fault_show()Dmitry Antipov
Do not emit extra trailing space and use sysfs_emit_at() over sprintf()/strcat()/strlen() in flash_fault_show(). Suggested-by: Lee Jones <lee@kernel.org> Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru> Link: https://patch.msgid.link/20260916161607.90106-2-dmantipov@yandex.ru Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-22leds: flash: Prevent using uninitialized variable in flash_fault_show()Dmitry Antipov
In flash_fault_show(), address of uninitialized 'fault' variable is passed to device-specific .fault_get callbacks. This is not a problem if such a callback directly assigns the value like rt4505_fault_get(), but results in an undefined behavior if callback just performs bitwise ORs like as3645a_get_fault(). So just initialize 'fault' with zero. Reported-by: sashiko-bot@kernel.org Closes: https://sashiko.dev/#/patchset/20260904054437.461706-1-dmantipov@yandex.ru?part=1 Fixes: 7aea8389a77ab ("leds: Add LED Flash class extension to the LED subsystem") Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru> Link: https://patch.msgid.link/20260916161607.90106-1-dmantipov@yandex.ru Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-22leds: st1202: Give the channel current ceiling a single helperManuel Fombuena
The channel current register is 8 bits wide, while max_brightness comes from the device tree and can be larger. The brightness, pattern and blink paths each apply that limit on their own, open-coding the same min_t() against U8_MAX, and the blink path previously drifted from the others by ignoring max_brightness altogether. Move the limit into st1202_iled_max() and use it in all three places. Each path programs the same value as before: the LED core already limits brightness to max_brightness, so capping it against st1202_iled_max() in st1202_led_set() gives the same result as capping it against U8_MAX. Signed-off-by: Manuel Fombuena <fombuena@outlook.com> Assisted-by: LLM Link: https://patch.msgid.link/GV1PR08MB8497935DA426302FB808A81EC5BA2@GV1PR08MB8497.eurprd08.prod.outlook.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-22leds: st1202: Cap the channel current in st1202_led_set()Manuel Fombuena
st1202_led_set() writes the requested brightness straight into the 8-bit channel current register. The LED core limits brightness to max_brightness, which comes from the device tree max-brightness property and has no upper bound, so on a board declaring more than 255 a brightness of 256 reaches the register as 0 and turns the LED off, and larger values wrap around. Cap the value at U8_MAX, the width of the register, so anything above it drives the channel at full current. The pattern and blink paths already cap the current they program the same way. Fixes: 259230378c65 ("leds: Add LED1202 I2C driver") Signed-off-by: Manuel Fombuena <fombuena@outlook.com> Assisted-by: LLM Link: https://patch.msgid.link/GV1PR08MB8497C60D1D2921DD0384926FC5BA2@GV1PR08MB8497.eurprd08.prod.outlook.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-22leds: st1202: Honour max_brightness when blinkingManuel Fombuena
st1202_blink_set() drives the channel current register to U8_MAX, the full scale of the part, regardless of the ceiling the board declared. led_classdev_register_ext() takes max_brightness from the device tree max-brightness property. The driver does not implement led-max-microamp, so that is the only way a board can ask for less than 20 mA. The brightness and pattern paths both respect it. Blinking is the one that does not, so a board that declares a lower ceiling holds it until something enables the timer trigger. Program the same value the other paths use, capped at the width of the current register so an out of range property cannot wrap it to zero. Fixes: 35cbd34a6a05 ("leds: st1202: Add hardware-accelerated blink support") Signed-off-by: Manuel Fombuena <fombuena@outlook.com> Assisted-by: LLM Link: https://patch.msgid.link/GV1PR08MB84979A5D536C71D319A06808C5BA2@GV1PR08MB8497.eurprd08.prod.outlook.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-22leds: st1202: Clear unused pattern slots in blink_set()Manuel Fombuena
st1202_blink_set() programs slots 0 and 1 of its own channel and leaves slots 2 to 7 at ST1202_PATTERN_PWM_FULL, the value both st1202_led_set() and st1202_led_pattern_clear() leave behind. Nothing keeps those slots out of the output except the duration registers being zero, and those are shared by all twelve channels. Another channel programming a hardware pattern longer than two steps writes those durations again and re-arms the sequencer, so the blinking channel drives full scale for the extra steps. With two LEDs on one device, blinking one and giving the other a four step pattern, the blinking channel lights during the two steps it never programmed. Zero the channel's own unused slots, the same invariant st1202_led_pattern_set() applies to the slots beyond its pattern length. blink_set() already zeroes durations 2 to 7 when it runs; the slots are exposed only when another channel sets those shared durations again. A channel whose blink is shorter than the active timeline still loses its own timing, because the sequencer has one set of duration registers. This only stops it emitting output it never asked for. Fixes: 35cbd34a6a05 ("leds: st1202: Add hardware-accelerated blink support") Signed-off-by: Manuel Fombuena <fombuena@outlook.com> Assisted-by: LLM Link: https://patch.msgid.link/GV1PR08MB849770CF6D41F3DFF56B1AC3C5BA2@GV1PR08MB8497.eurprd08.prod.outlook.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-22leds: st1202: Do not set brightness from atomic contextManuel Fombuena
st1202_brightness_set() takes the chip mutex and performs I2C transfers, both of which can sleep, but it is installed as the brightness_set callback. led_set_brightness_nopm() calls that op directly on the assumption that it never sleeps, including from softirq context, so the driver can sleep in atomic context. The driver also installs brightness_set_blocking, but the core only falls back to it when brightness_set is absent, so st1202_led_set() was never reached. It merely turned the channel on or off and ignored the requested brightness, so dropping brightness_set on its own would have lost brightness control entirely. Move the register programming into st1202_led_set() so the blocking callback honours the brightness value, and drop brightness_set. The core now defers the update to a work queue, where sleeping is allowed. Errors from the register writes are propagated rather than discarded. st1202_led_set() was the last user of the locking st1202_channel_set() wrapper, which is removed. Programming every PWM slot to full scale is kept: it is what makes the brightness visible while the global sequencer is running, without having to stop the sequencer and disturb the other channels. Fixes: 259230378c65 ("leds: Add LED1202 I2C driver") Signed-off-by: Manuel Fombuena <fombuena@outlook.com> Assisted-by: LLM Link: https://patch.msgid.link/GV1PR08MB8497CF8FB57A272EB671F0C6C5BA2@GV1PR08MB8497.eurprd08.prod.outlook.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-22leds: st1202: Take a reference on the LED firmware nodeManuel Fombuena
st1202_dt_init() stores each LED's firmware node while walking the device tree with for_each_available_child_of_node_scoped(), which drops its reference to the node at the end of every iteration. The LED class stores the pointer with device_set_node() and does not take a reference of its own, so nothing keeps the node alive for as long as the LED device uses it. That has been the case since the driver was added, when the LED class devices were registered inside that same loop. Commit c72e455b89f2 ("leds: leds-st1202: Fix NULL pointer access on race condition") moved the registration into a separate loop in st1202_probe(), which also leaves the stored pointer unreferenced between the two loops. With CONFIG_OF_DYNAMIC the node can be freed while it is still in use, leaving led->fwnode and the LED device's firmware node dangling. Take a reference when the node is stored and release it through a devm action. The action is registered before the LED class devices are, so it runs after they have been unregistered. Fixes: 259230378c65 ("leds: Add LED1202 I2C driver") Signed-off-by: Manuel Fombuena <fombuena@outlook.com> Assisted-by: LLM Link: https://patch.msgid.link/GV1PR08MB849710C564F23C21BDA3EA41C5BA2@GV1PR08MB8497.eurprd08.prod.outlook.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-22leds: st1202: Program the channel current for hardware patternsManuel Fombuena
A channel's output is ILED x Pattern_PWM / 4095, so a pattern is only visible while the analog current register holds a non-zero value. st1202_led_pattern_set() programs the PWM slots and starts the sequencer but never writes ILED, so a channel whose current is zero stays dark while pattern_set() reports success. Zero is reached by ordinary use. Writing 0 to brightness sets it, and so does switching away from the pattern trigger, because pattern_trig_deactivate() ends with led_set_brightness(LED_OFF). A sequence as simple as echo none > trigger echo pattern > trigger echo "255 500 0 500" > hw_pattern therefore programs a pattern that never lights up. Program the current in pattern_set() and release it in pattern_clear(), so the pattern path owns ILED for as long as a pattern is loaded. Releasing it matters because the trigger calls pattern_clear() before it parses a new pattern: without that, a rejected or empty hw_pattern write would leave the channel at full current with every PWM slot at full scale, latching the LED on. Clearing before the slots are raised also avoids a brief full-brightness flash on every reprogram. A current of zero is not enough to release the channel, though: the datasheet notes that it does not switch the channel off but leaves a small uncontrolled current, which shows as a faint glow. pattern_clear() therefore also disables the channel, and pattern_set() enables it again. Both are done before the sequencer is stopped, so an I2C error partway through a clear cannot leave the channel lit. Probe clears every channel, so the LEDs now reach user space switched off. Until now they came up lit at the chip's power-on current, because pattern_clear() fills every slot at full scale. Probe no longer enables the channels itself either: st1202_setup() has already disabled them all, and each path that lights a channel enables it when needed. The current is programmed to the same max_brightness the PWM values are scaled against, so a pattern step of N produces the same output as writing N to brightness, and a board declaring a lower ceiling through the max-brightness property keeps it on both paths. Note that this makes a hardware pattern take the channel to its maximum current, so brightness reads back as max_brightness once a pattern is loaded and as zero once it is cleared. The pattern's own values, not the last brightness written, decide what the channel shows while a pattern is running. Fixes: 259230378c65 ("leds: Add LED1202 I2C driver") Signed-off-by: Manuel Fombuena <fombuena@outlook.com> Assisted-by: LLM Link: https://patch.msgid.link/GV1PR08MB84978D7C1CC0367D1818093DC5BA2@GV1PR08MB8497.eurprd08.prod.outlook.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-22leds: st1202: Scale pattern brightness to the 12-bit PWM rangeManuel Fombuena
The LED1202 PWM registers are 12 bits wide, but st1202_led_pattern_set() writes the 8-bit brightness value carried by struct led_pattern into them unscaled. A pattern step asking for full brightness therefore drives the channel at 255 out of 4095, about 6% duty cycle, so a pattern is dimmer than the same brightness set directly. Scale the value to the full PWM range before programming it. Scale against max_brightness rather than the register maximum. The LED core takes max_brightness from the DT max-brightness property, so a board can declare a ceiling below full scale, and the pattern trigger already rejects steps above it. Scaling against a hardcoded 255 would leave such a board unable to reach its own declared maximum from the pattern path while the brightness path reaches it. Scaling divides by max_brightness. The LED core replaces a zero max-brightness from the device tree with LED_FULL, so the divisor should never be zero, but the helper returns zero rather than rely on that. max_brightness is capped at U8_MAX, the driver's own maximum, so a device tree declaring more than the part supports is treated as full scale. struct led_pattern brightness is signed, so clamp both ends and floor a negative value to LED_OFF rather than let it wrap. Document that a step is relative to max_brightness, since the range given in the documentation no longer holds when the device tree sets max-brightness. Fixes: 259230378c65 ("leds: Add LED1202 I2C driver") Signed-off-by: Manuel Fombuena <fombuena@outlook.com> Assisted-by: LLM Link: https://patch.msgid.link/GV1PR08MB8497B938D3592582E17CB757C5BA2@GV1PR08MB8497.eurprd08.prod.outlook.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-22leds: st1202: Clear unused pattern slots in pattern_set()Manuel Fombuena
The pattern duration registers are chip-wide while the PWM registers are per-channel, so a channel can end up driven by a sequencer timeline it never programmed. st1202_led_pattern_set() programs only the first len slots. The pattern trigger calls pattern_clear() before pattern_set() only once a channel is already in PATTERN_TYPE_HW mode, and activating the trigger resets that mode, so the first hardware pattern written after every activation skips it. If another channel has already programmed a longer pattern, durations [len, 8) are still set, and this channel's PWM for those slots holds whatever was last written there. That used to be LED_OFF, so a channel stayed dark for the slots it had not programmed itself. Since commit d2ca0e2b6d64 ("leds: st1202: Set all pattern PWM slots to full after clearing pattern") pattern_clear() leaves ST1202_PATTERN_PWM_FULL there, and so does the brightness path since commit 7cbe470366bd ("leds: st1202: Fix brightness having no effect while pattern mode is active"). The channel now plays its own steps and then sits at full brightness for the rest of the sequence. Zero this channel's PWM for the unused slots so it stays dark for the remainder of the timeline, as st1202_blink_set() already does for the channels it is not driving. The duration registers are deliberately left alone. All twelve channels share them, so clearing them would truncate a longer pattern still running elsewhere on the same device. A channel whose pattern is shorter than the active timeline therefore keeps the longer period; that follows from having a single hardware sequencer and is not something this can correct. Fixes: d2ca0e2b6d64 ("leds: st1202: Set all pattern PWM slots to full after clearing pattern") Signed-off-by: Manuel Fombuena <fombuena@outlook.com> Assisted-by: LLM Link: https://patch.msgid.link/GV1PR08MB8497E9939E3C0D68401659D0C5BA2@GV1PR08MB8497.eurprd08.prod.outlook.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-22leds: st1202: Use u8 consistently for 8-bit valuesManuel Fombuena
The driver spells 8-bit unsigned values both as uint8_t and as u8, a mix present since the driver was added. The register helpers and the prescaler conversion use uint8_t, while the rest of the driver uses u8, which is also the preferred type in kernel code. Convert the remaining uint8_t uses to u8. No functional change. Signed-off-by: Manuel Fombuena <fombuena@outlook.com> Assisted-by: LLM Link: https://patch.msgid.link/GV1PR08MB8497783FB573CD48491F9648C5BA2@GV1PR08MB8497.eurprd08.prod.outlook.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-22leds: st1202: Name pattern index variables consistentlyManuel Fombuena
The driver already names pattern indices "pattern" in the signatures of st1202_pwm_pattern_write() and st1202_duration_pattern_write(), and st1202_blink_set() follows the same convention. The remaining loops abbreviate it to "patt", which matches nothing else in the file. Rename those loop variables to "pattern". In st1202_led_pattern_set() that name is taken by the array of pattern steps, so rename the parameter to "patterns", which also reflects better that it is an array. Two st1202_pwm_pattern_write() calls exceed 100 columns with the longer name and are wrapped accordingly. No functional change. Signed-off-by: Manuel Fombuena <fombuena@outlook.com> Assisted-by: LLM Link: https://patch.msgid.link/GV1PR08MB8497AD614B8686BBDA654674C5BA2@GV1PR08MB8497.eurprd08.prod.outlook.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-22leds: st1202: Spell out the phase-shift configuration bitManuel Fombuena
ST1202_CONFIG_REG_SHFT is abbreviated to the point of being unreadable and, unlike the neighbouring PATS and PATSR bits, carries no comment explaining what it controls. Rename it to ST1202_CONFIG_REG_PHASE_SHIFT and document it in the same style as the other configuration bits, retaining the datasheet name in the comment so it remains searchable. The longer name no longer fits the existing layout in st1202_led_pattern_set(), where the continuation line was already 106 columns wide. Re-wrap that register write to match the layout st1202_blink_set() uses for the same operation and drop the redundant parentheses around the bit mask. No functional change. Signed-off-by: Manuel Fombuena <fombuena@outlook.com> Assisted-by: LLM Link: https://patch.msgid.link/GV1PR08MB849716E21E082D3B93B5B683C5BA2@GV1PR08MB8497.eurprd08.prod.outlook.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-22leds: st1202: Correct the name of the prescaler conversion helperManuel Fombuena
st1202_prescalar_to_miliseconds() converts a duration in milliseconds into the prescaler value written to the pattern duration registers, so its name states the conversion the wrong way round. It also misspells both "prescaler" and "milliseconds". Rename it to st1202_milliseconds_to_prescaler(). No functional change. Signed-off-by: Manuel Fombuena <fombuena@outlook.com> Assisted-by: LLM Link: https://patch.msgid.link/GV1PR08MB8497AA602374777F1BA08E07C5BA2@GV1PR08MB8497.eurprd08.prod.outlook.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-22leds: lm3692x: Fix regulator/gpio leak and wrong enabled state on last write ↵Cong Nguyen
failure Every write in lm3692x_leds_enable() checks its return and jumps to out: on failure -- except the last one, which falls through and sets led->enabled = true regardless of whether it actually succeeded. Leaks the regulator on a failing probe, and short-circuits later brightness_set() calls without retrying. Route it through out: like every other write here, and only set enabled = true once it succeeds. Fixes: 260718b3a35d ("leds: lm3692x: Disable chip on brightness 0") Assisted-by: Claude:claude-opus-4 Signed-off-by: Cong Nguyen <congnt264@gmail.com> Link: https://patch.msgid.link/20260915034515.4147981-1-congnt264@gmail.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-22leds: pca9532: Check i2c_smbus_read_byte_data() return valueHaibo Chen
Coverity report INTEGER_OVERFLOW (tainted_data_return -> cast_underflow -> overflow) in pca9532_getled(). pca9532_getled() stored the return value of i2c_smbus_read_byte_data() into a char and used it directly to compute the LED state without checking for an error. i2c_smbus_read_byte_data() returns a negative error code on failure. On an I2C read error the negative value was assigned to an unsigned type, triggering an integer underflow/overflow, and a meaningless LED state was returned to the caller. Read the value into an int, check for the error, and fall back to PCA9532_OFF while emitting a warning when the read fails. Fixes: 28c5fe99016d ("leds: pca9532: Extend pca9532 device tree support") Assisted-by: VeroCoder:vero-1 [cli] Signed-off-by: Haibo Chen <haibo.chen@nxp.com> Reviewed-by: Frank Li <Frank.Li@nxp.com> Link: https://patch.msgid.link/20260727-led-fix-v1-1-d635c5037109@nxp.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-22leds: ktd2692: Pass context to regulator cleanupMyeonghun Pak
regulator_disable_action() retrieves the driver context from device driver data. However, ktd2692_parse_dt() registers the action before ktd2692_probe() stores the context with platform_set_drvdata(). If devm_add_action_or_reset() cannot allocate the action, it invokes the callback immediately. A later probe failure also invokes it during managed-resource unwinding. Both paths dereference a NULL context. Pass the already allocated context directly to the action and retain the device pointer in it for error reporting. The context is allocated before the action is registered, so reverse-order devres unwinding keeps it alive through the callback. This issue was identified during our ongoing static-analysis research while reviewing kernel code. Fixes: ee78b9360e14 ("leds: ktd2692: Fix an error handling path") Cc: stable@vger.kernel.org Co-developed-by: Ijae Kim <ae878000@gmail.com> Signed-off-by: Ijae Kim <ae878000@gmail.com> Signed-off-by: Myeonghun Pak <mhun512@gmail.com> Link: https://patch.msgid.link/20260910194525.99654-1-mhun512@gmail.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-22leds: lp8860: Fix device_node leak in lp8860_probe()Miles Krause
lp8860_probe() looks up the driver's single LED child node with of_get_next_available_child() and hands it to the LED core as init_data.fwnode, but never drops the reference that lookup returned: child_node = of_get_next_available_child(np, NULL); if (!child_node) return -EINVAL; ... init_data.fwnode = of_fwnode_handle(child_node); of_get_next_available_child() returns the node with its refcount incremented, and the LED core does not take a reference of its own: led_classdev_register_ext() only reads properties out of init_data.fwnode and then stores the bare pointer with device_set_node(). The reference therefore stays owned by the driver for as long as it holds the node. Nothing in lp8860_probe() ever releases it, so it is leaked on every error return taken after the lookup - the enable GPIO, the vled regulator, devm_mutex_init(), the regmap allocation, the optional EEPROM programming and the LED class registration - and on a fully successful probe alike. A device that binds and unbinds repeatedly leaks one device_node reference per bind. Sibling drivers already get this right: leds-lm3692x.c, from the same TI LED family, calls fwnode_handle_put(init_data.fwnode) once after devm_led_classdev_register_ext() to cover both outcomes, while leds-ktd2692.c and leds-aat1290.c take the node with __free(device_node). Use __free(device_node) here too. Unlike a single of_node_put() at the end of probe it also covers the intermediate error returns, and it keeps the node alive for the whole function, which the LED core still needs when it reads the child's properties during registration. Fixes: 99ca0ea57309 ("leds: lp8860: Use generic support for composing LED names") Signed-off-by: Miles Krause <mileskrause5200@gmail.com> Link: https://patch.msgid.link/20260910-leds-lp8860-of-node-leak-v1-1-d333cff4345b@gmail.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-17leds: is31fl32xx: Use fwnode/device property APIsRosen Penev
Convert the DT-specific helpers in is31fl32xx_parse_dt() and is31fl32xx_parse_child_dt() to their fwnode/device equivalents. Behaviour is unchanged for device tree: device_property_read_bool(), device_for_each_child_node_scoped() and device_get_child_node_count() operate on the same nodes and keep the skip of unavailable children. Use the %pfwP format specifier in error messages, as child is now a struct fwnode_handle and %pOF would misread it as a device_node. Assisted-by: opencode:deepseek-v4-flash-free Signed-off-by: Rosen Penev <rosenp@gmail.com> Link: https://patch.msgid.link/20260907201940.40524-1-rosenp@gmail.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-17leds: syscon: Use device property APIRosen Penev
Replace the DT-specific of_property_read_u32() calls and the dev_of_node()/of_fwnode_handle() roundtrip with their device/fwnode equivalents. Behaviour is unchanged for device tree: device_property_read_u32() and dev_fwnode() operate on the same node, and the fallback from "reg" to "offset" is preserved. Use dev_fwnode() for init_data.fwnode; unlike a child node from a scoped iterator, the platform device's own node is held by the driver core for the device lifetime. Assisted-by: opencode:deepseek-v4-flash-free Signed-off-by: Rosen Penev <rosenp@gmail.com> Link: https://patch.msgid.link/20260907202436.42304-1-rosenp@gmail.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-16leds: ss4200: Fix typo "retrive" in commentHemanth Selam
Correct "retrive" to "retrieve", reported by scripts/checkpatch.pl using the misspelling list in scripts/spelling.txt. Only touches a comment, no code changes. Since v1 the subject carries the driver name and a capitalised description, to match the LED subsystem convention. Assisted-by: Cursor:claude-opus-5 Signed-off-by: Hemanth Selam <hemanth.selam@gmail.com> Link: https://patch.msgid.link/20260907045436.18039-1-hemanth.selam@gmail.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-10mfd: lm3533: Convert to use OF bindingsSvyatoslav Ryhel
Since there are no users of this driver via platform data, remove the platform data support and switch to using Device Tree bindings. Previously, all cell devices were linked to the parent device. This could cause problems further down the line because the LM3533 has multiple cells of the same type. Using a single phandle to the parent could cause confusion when attempting to reference or call the correct child node. Since this commit adds a dedicated node for every cell, remove linking of the cell to the parent node. Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com> Reviewed-by: Daniel Thompson (RISCstar) <danielt@kernel.org> #for backlight Acked-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com> #for-iio Link: https://patch.msgid.link/20260731113632.158440-9-clamor95@gmail.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-10mfd: lm3533: Pass only regmap and light sensor presence to child devicesSvyatoslav Ryhel
Instead of passing the entire lm3533 core data structure, only pass the regmap and the light sensor presence flag to child devices. Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com> Acked-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com> #for-iio Link: https://patch.msgid.link/20260731113632.158440-5-clamor95@gmail.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-10mfd: lm3533: Remove driver specific regmap wrappersSvyatoslav Ryhel
Remove driver-specific regmap wrappers in favor of using regmap helpers directly. Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com> Acked-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com> Link: https://patch.msgid.link/20260731113632.158440-3-clamor95@gmail.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-03leds: max77705: Use fwnode_for_each_child_node_scoped() in max77705_add_led()Manush Prajwal
Rework the subled loop in max77705_add_led() around fwnode_for_each_child_node_scoped() instead of adding a manual fwnode_handle_put(child) before the early return on a max77705_parse_subled() failure, so the reference on the current child fwnode is released automatically on every exit path from the loop. child is never used outside the loop, so the now-unused outer child declaration is dropped along with it. Suggested-by: Krzysztof Kozlowski <krzk@kernel.org> Fixes: 3b6eaa3db567 ("leds: Use fwnode_for_each_child_node() instead") Signed-off-by: Manush Prajwal <manushprajwal555@gmail.com> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com> Link: https://patch.msgid.link/6a914e1e.7d702ed2.1273e8.2a52@mx.google.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-09-03leds: st1202: Add hardware-accelerated blink supportManuel Fombuena
Implement blink_set() to enable hardware-accelerated blinking via the timer trigger. The LED1202 pattern engine is used to produce a two-step sequence: full brightness for delay_on, off for delay_off, repeating indefinitely. Requested delays are clamped to the hardware range [22ms, 5610ms] then rounded up to the nearest 22ms step. Clamping before rounding prevents integer overflow in roundup() for extreme input values; since ST1202_MILLIS_PATTERN_DUR_MAX is an exact multiple of ST1202_MILLIS_PATTERN_DUR_MIN, rounding a clamped value cannot exceed the maximum. A zero delay is replaced with the default of 500ms independently for each of delay_on and delay_off. The LED1202 pattern sequencer is global and its timing registers are shared across all channels, so only one blink configuration can be active at a time. Other active channels have their PWM slots zeroed for both pattern steps so they remain dark rather than outputting unintended values when the sequencer runs. The target channel's ILED register is set to full brightness and the channel is enabled, since the timer trigger deactivates the current trigger before calling blink_set which would otherwise leave the channel disabled. Signed-off-by: Manuel Fombuena <fombuena@outlook.com> Link: https://patch.msgid.link/GV1PR08MB84973F79E871176EB387C377C5DA2@GV1PR08MB8497.eurprd08.prod.outlook.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-08-27Merge tag 'leds-next-7.3' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/lee/leds Pull LED updates from Lee Jones: "New Support & Features: - Core: Extend netdev trigger speeds up to 100G - PWM Multicolor: Introduce default-intensity property - Analog Devices LTC3220: Add support for 18 channel LED driver - NXP PCA963x: Add multicolor LED class support Improvements & Fixes: - GPIO: Clear error pointers for skipped LEDs - Broadcom BCM63138: Use %pe to print pinctrl error instead of %ld - ISSI IS31FL319x: Modernize device registration by using fwnode APIs - NXP PCA9532: Fix inverted GPIO output polarity - NXP PCA9532: Fix phantom device registration on missing hardware - STMicroelectronics ST1202: Correct and extend hw_pattern documentation - STMicroelectronics ST1202: Fix channel disable logic on zero brightness and ensure brightness changes are applied in active mode - STMicroelectronics ST1202: Fix hardware pattern sequence programming, validate inputs, and correct pattern duration calculations - STMicroelectronics ST1202: Validate LED reg property against channel count - TI LP5860: Fix a potential double-unlock during device initialization and fix error handling path by using devm_mutex_init() Cleanups & Refactoring: - GPIO: Make legacy gpiolib interface optional Device Tree Binding Updates: - Core: Add default-intensity property - Core: Document "gpio" trigger - Analog Devices LTC3220: Add DT binding for LTC3220 18 channel LED driver - Broadcom BCM6358: Convert to DT schema - LaCie NS2: Convert to DT schema - NXP PCA963x: Add multicolor LED support - NXP PCA963x: Fix reg maximum for pca9635 - TI TPS65217: Convert backlight bindings to DT schema" * tag 'leds-next-7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/leds: (29 commits) leds: is31fl319x: Modernize registration dt-bindings: leds: lacie,ns2-leds: Convert to DT schema leds: pca963x: Add multicolor LED class support dt-bindings: leds: nxp,pca963x: Add multicolor LED support dt-bindings: leds: nxp,pca963x: Fix reg maximum for pca9635 leds: gpio: Clear error pointers for skipped LEDs dt-bindings: leds: backlight: Convert TPS65217 to DT schema leds: pca9532: Fix phantom device registration on missing hardware leds: gpio: Make legacy gpiolib interface optional leds: bcm63138: Use %pe to print pinctrl error instead of %ld dt-bindings: leds: Add default-intensity property leds: ltc3220: Add Support for LTC3220 18 channel LED Driver dt-bindings: leds: Add LTC3220 18 channel LED Driver dt-bindings: leds: bcm6358: Convert to DT schema dt-bindings: leds: Document "gpio" trigger leds: st1202: Correct and extend hw_pattern documentation leds: st1202: Validate LED reg property against channel count leds: st1202: Disable channel when brightness is set to zero leds: st1202: Fix brightness having no effect while pattern mode is active leds: st1202: Fix spurious pattern sequence start in setup ...
2026-08-25headers: Remove swap.h from suspend.hMatthew Wilcox (Oracle)
Nothing in suspend.h needs swap.h. However, many files indirectly depend on some of swap.h's dependencies, so this is a large cross-subsystem patch. Stats: 42 are missing includes of interrupt.h (the question of why swap.h brings in interrupt.h remains unanswered). 10 missing includes of seq_file.h 5 missing includes of swap.h (obviously all files could have just added swap.h, but I preferred to bring in a more minimal inclusion set) 3 missing includes of highmem.h 2 missing includes of device.h 2 missing includes of string_choices.h 1 missing include of cacheflush.h 1 missing include of dma-direction.h 1 missing include of kthread.h 1 missing include of pagemap.h 1 missing include of string_helpers.h 1 missing include of writeback.h I tried to follow whatever conventions appeared to be in use for the various subsystems I touched; for example I added string_choices.h to drm_print.h instead of individually to each driver which used the functions declared there. Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
2026-08-12leds: is31fl319x: Modernize registrationAndreas Kemnade
Use _ext version to have properties parsed to avoid needing to parse them in the driver itself. More modern properties are recognized and the LEDs can be referenced via phandle. Due to the maximum current mechanics, LEDs are not registered right in the first iteration over the nodes. Signed-off-by: Andreas Kemnade <andreas@kemnade.info> Link: https://patch.msgid.link/20260806-led-modern-v4-1-eed715baab2e@kemnade.info Signed-off-by: Lee Jones <lee@kernel.org>
2026-08-06leds: pca963x: Add multicolor LED class supportLoic Poulain
Allow grouping of individual PCA963x PWM channels into a single multicolor LED device by adding support for the LED multicolor class. A child node with sub-children is treated as a multicolor group, others are treated as single leds, keeping full backwards compatibility. Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com> Link: https://patch.msgid.link/20260727-monza-leds-v8-3-6e7e93d44dba@oss.qualcomm.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-08-06leds: gpio: Clear error pointers for skipped LEDsSteve Dunnagan
gpio_led_get_gpiod() returns an error pointer when a platform-data LED's GPIO is unavailable. gpio_led_probe() skips registration in that case, but leaves the error pointer in led_dat->gpiod. The skipped entry remains included in priv->num_leds. During shutdown, gpio_led_shutdown() walks those entries and passes the error pointer to gpio_led_set(), producing: gpiod_set_value: invalid GPIO (errorpointer: -ENOENT) Clear led_dat->gpiod before skipping the LED so skipped entries do not retain error-valued descriptors. Fixes: 45d4c6de4e49 ("leds: gpio: Try to lookup gpiod from device") Suggested-by: Lee Jones <lee@kernel.org> Assisted-by: ChatGPT:GPT-5.5-Thinking Signed-off-by: Steve Dunnagan <sdunnaga@redhat.com> Reviewed-by: Linus Walleij <linusw@kernel.org> Link: https://patch.msgid.link/20260724180412.43150-1-sdunnaga@redhat.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-07-23leds: pca9532: Fix phantom device registration on missing hardwareCosmo Chou
The initial PWM and PSC register writes in pca9532_configure() do not check the return values of i2c_smbus_write_byte_data(). If the I2C device is physically absent from the bus, the write fails with -ENXIO. However, the driver ignores this error and allows probe() to complete successfully. This results in the registration of phantom LED class devices and gpiochips backed by non-existent hardware. Subsequent GPIO reads from these phantom chips return bogus values (due to -ENXIO being truncated to an unsigned char in pca9532_gpio_get_value()), silently corrupting hardware state tracking in userspace. Propagate the I2C write failures back to probe() so the driver core can gracefully abort binding and release devres-managed resources. Fixes: e14fa82439d3 ("leds: Add pca9532 led driver") Signed-off-by: Cosmo Chou <chou.cosmo@gmail.com> Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com> Link: https://patch.msgid.link/20260715080747.1638097-1-chou.cosmo@gmail.com Signed-off-by: Lee Jones <lee@kernel.org>
2026-07-23leds: gpio: Make legacy gpiolib interface optionalArnd Bergmann
There are still a handful of ancient mips/armv5/sh boards that use the gpio_led:gpio member to pass an old-style gpio number, but all modern users have been converted to gpio descriptors. While the CONFIG_GPIOLIB_LEGACY option that guards devm_gpio_request_one() and related helpers is currently turned on in all kernel builds, the plan is to only enable it on the few platforms that actually pass gpio numbers in any platform_data. Split out the legacy portion of the platform_data handling into a custom helper function that is guarded with in #ifdef block, to allow the the leds-gpio driver to compile cleanly when CONFIG_GPIOLIB_LEGACY gets turned off. Once the last user is converted, this function can be removed. Link: https://lore.kernel.org/all/e9252384-a55c-4a91-9c61-06e05a0b2ce4@app.fastmail.com/ Signed-off-by: Arnd Bergmann <arnd@arndb.de> Reviewed-by: Linus Walleij <linusw@kernel.org> Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> # for input Link: https://patch.msgid.link/20260710211854.1371746-4-arnd@kernel.org Signed-off-by: Lee Jones <lee@kernel.org>