From: Andrew Davis <afd@ti.com>
To: "A. Sverdlin" <alexander.sverdlin@siemens.com>,
<linux-leds@vger.kernel.org>
Cc: Lee Jones <lee@kernel.org>, Daniel Thompson <danielt@kernel.org>,
"Jingoo Han" <jingoohan1@gmail.com>,
Pavel Machek <pavel@kernel.org>, Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>, Helge Deller <deller@gmx.de>,
<dri-devel@lists.freedesktop.org>, <devicetree@vger.kernel.org>,
<linux-kernel@vger.kernel.org>, <linux-fbdev@vger.kernel.org>
Subject: Re: [PATCH 3/3] backlight: lp8864: Convert from LED to backlight class driver
Date: Mon, 15 Jun 2026 14:51:33 -0500 [thread overview]
Message-ID: <0b39450b-559b-43d4-a1e9-bb6684691cb5@ti.com> (raw)
In-Reply-To: <20260615120353.3409035-4-alexander.sverdlin@siemens.com>
On 6/15/26 7:03 AM, A. Sverdlin wrote:
> From: Alexander Sverdlin <alexander.sverdlin@siemens.com>
>
> Move the TI LP8864/LP8866 driver from drivers/leds/ to
> drivers/video/backlight/
Why move it? You can register a backlight device from any directory.
> and convert it to register a backlight class
> device as its primary interface.
>
What do you mean by "primary"? You should be able to register with
both frameworks and have the driver interop between as needed.
> The motivation is a use case on a hot-pluggable segment of an I2C bus.
> The generic led-backlight driver (drivers/video/backlight/led_bl.c) is a
> platform driver and as such inherently non-hotpluggable.
That isn't strictly true, there is platform_device_{del,unregister}(), so
whatever your mechanism for removing the I2C device would be, the same
could be done to the led_bl device before then removing the I2C device.
We don't want to have to move every LED driver that could possibly
be used as a backlight to the backlight framework, the led_bl.c
handles adapting LED->backlight as needed. So what you really need
here is to de-couple led_bl.c from DT so it can better handle dynamic
add/remove. Then this LED driver simply could register a "led-backlight"
platform driver to handle the backlight interface, and remove the
backlight device when it itself (the LED device) is removed.
Andrew
It cannot react
> to dynamic appearance/disappearance of the underlying I2C device. By
> making the LP8864 driver directly register a backlight class device, it
> becomes a native I2C driver that properly supports hot-plug/unplug
> events on the I2C bus.
>
> Key changes:
> - Register a backlight class device using
> devm_backlight_device_register() as the primary interface
> - Implement backlight_ops (update_status, get_brightness)
> - The hardware 16-bit brightness register (0x0000-0xFFFF) is directly
> exposed as the backlight brightness range
> - Support DT properties "default-brightness" and "max-brightness"
> from the backlight common binding
> - Include BL_CORE_SUSPENDRESUME for proper power management integration
> - Preserve backward-compatible LED class device registration: if the
> "led" child node is present in the DT, an LED class device is also
> registered (same as the original driver behavior)
> - Preserve the CONFIG_LEDS_LP8864 Kconfig symbol name so that existing
> kernel configurations are not affected
> - Update MAINTAINERS to reflect the new file location
>
> This will be noticeable for applications which already used the LP8864
> as a backend for the generic led-backlight platform driver, as a
> backlight device will now appear directly in addition to the LED class
> device. However, no in-tree device-trees reference this driver, so
> there is no mainline impact.
>
> Signed-off-by: Alexander Sverdlin <alexander.sverdlin@siemens.com>
> ---
> MAINTAINERS | 2 +-
> drivers/leds/Kconfig | 12 --
> drivers/leds/Makefile | 1 -
> drivers/video/backlight/Kconfig | 15 +++
> drivers/video/backlight/Makefile | 1 +
> .../backlight/lp8864_bl.c} | 111 ++++++++++++++----
> 6 files changed, 106 insertions(+), 36 deletions(-)
> rename drivers/{leds/leds-lp8864.c => video/backlight/lp8864_bl.c} (70%)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index dbd4552236e64..250e8b1ed4bb5 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -26481,7 +26481,7 @@ M: Alexander Sverdlin <alexander.sverdlin@siemens.com>
> L: linux-leds@vger.kernel.org
> S: Maintained
> F: Documentation/devicetree/bindings/leds/backlight/ti,lp8864.yaml
> -F: drivers/leds/leds-lp8864.c
> +F: drivers/video/backlight/lp8864_bl.c
>
> TEXAS INSTRUMENTS' SYSTEM CONTROL INTERFACE (TISCI) PROTOCOL DRIVER
> M: Nishanth Menon <nm@ti.com>
> diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
> index f4a0a3c8c8705..990cb9ef18c1e 100644
> --- a/drivers/leds/Kconfig
> +++ b/drivers/leds/Kconfig
> @@ -529,18 +529,6 @@ config LEDS_LP8860
> on the LP8860 4 channel LED driver using the I2C communication
> bus.
>
> -config LEDS_LP8864
> - tristate "LED support for the TI LP8864/LP8866 4/6 channel LED drivers"
> - depends on LEDS_CLASS && I2C && OF
> - select REGMAP_I2C
> - help
> - If you say yes here you get support for the TI LP8864-Q1,
> - LP8864S-Q1, LP8866-Q1, LP8866S-Q1 4/6 channel LED backlight
> - drivers with I2C interface.
> -
> - To compile this driver as a module, choose M here: the
> - module will be called leds-lp8864.
> -
> config LEDS_CLEVO_MAIL
> tristate "Mail LED on Clevo notebook"
> depends on LEDS_CLASS && BROKEN
> diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
> index 8fdb45d5b4393..5e624a48aa2a5 100644
> --- a/drivers/leds/Makefile
> +++ b/drivers/leds/Makefile
> @@ -59,7 +59,6 @@ obj-$(CONFIG_LEDS_LP55XX_COMMON) += leds-lp55xx-common.o
> obj-$(CONFIG_LEDS_LP8501) += leds-lp8501.o
> obj-$(CONFIG_LEDS_LP8788) += leds-lp8788.o
> obj-$(CONFIG_LEDS_LP8860) += leds-lp8860.o
> -obj-$(CONFIG_LEDS_LP8864) += leds-lp8864.o
> obj-$(CONFIG_LEDS_LT3593) += leds-lt3593.o
> obj-$(CONFIG_LEDS_MAX5970) += leds-max5970.o
> obj-$(CONFIG_LEDS_MAX77650) += leds-max77650.o
> diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
> index a7a3fbaf7c29e..82ecd7e46236d 100644
> --- a/drivers/video/backlight/Kconfig
> +++ b/drivers/video/backlight/Kconfig
> @@ -514,6 +514,21 @@ config BACKLIGHT_LED
> If you have a LCD backlight adjustable by LED class driver, say Y
> to enable this driver.
>
> +config LEDS_LP8864
> + tristate "Backlight driver for TI LP8864/LP8866 4/6 channel LED drivers"
> + depends on I2C && OF
> + select REGMAP_I2C
> + select NEW_LEDS
> + select LEDS_CLASS
> + help
> + If you say yes here you get support for the TI LP8864-Q1,
> + LP8864S-Q1, LP8866-Q1, LP8866S-Q1 4/6 channel LED backlight
> + drivers with I2C interface. The driver registers a backlight
> + class device and optionally an LED class device.
> +
> + To compile this driver as a module, choose M here: the
> + module will be called lp8864_bl.
> +
> endif # BACKLIGHT_CLASS_DEVICE
>
> endmenu
> diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
> index 794820a98ed49..6a7287d01d81b 100644
> --- a/drivers/video/backlight/Makefile
> +++ b/drivers/video/backlight/Makefile
> @@ -62,3 +62,4 @@ obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o
> obj-$(CONFIG_BACKLIGHT_ARCXCNN) += arcxcnn_bl.o
> obj-$(CONFIG_BACKLIGHT_RAVE_SP) += rave-sp-backlight.o
> obj-$(CONFIG_BACKLIGHT_LED) += led_bl.o
> +obj-$(CONFIG_LEDS_LP8864) += lp8864_bl.o
> diff --git a/drivers/leds/leds-lp8864.c b/drivers/video/backlight/lp8864_bl.c
> similarity index 70%
> rename from drivers/leds/leds-lp8864.c
> rename to drivers/video/backlight/lp8864_bl.c
> index d05211b970c94..67b28f7daedd2 100644
> --- a/drivers/leds/leds-lp8864.c
> +++ b/drivers/video/backlight/lp8864_bl.c
> @@ -1,12 +1,13 @@
> // SPDX-License-Identifier: GPL-2.0-only
> /*
> - * TI LP8864/LP8866 4/6 Channel LED Driver
> + * TI LP8864/LP8866 4/6 Channel LED Backlight Driver
> *
> - * Copyright (C) 2024 Siemens AG
> + * Copyright (C) 2024-2026 Siemens AG
> *
> * Based on LP8860 driver by Dan Murphy <dmurphy@ti.com>
> */
>
> +#include <linux/backlight.h>
> #include <linux/gpio/consumer.h>
> #include <linux/i2c.h>
> #include <linux/init.h>
> @@ -27,6 +28,8 @@
> #define LP8864_LED_STATUS 0x12
> #define LP8864_LED_STATUS_WR_MASK GENMASK(14, 9) /* Writeable bits in the LED_STATUS reg */
>
> +#define LP8864_MAX_BRIGHTNESS 0xffff
> +
> /* Textual meaning for status bits, starting from bit 1 */
> static const char *const lp8864_supply_status_msg[] = {
> "Vin under-voltage fault",
> @@ -71,13 +74,15 @@ static const char *const lp8864_led_status_msg[] = {
> /**
> * struct lp8864
> * @client: Pointer to the I2C client
> - * @led_dev: led class device pointer
> + * @led_dev: optional led class device pointer
> + * @bl: backlight device pointer
> * @regmap: Devices register map
> * @led_status_mask: Helps to report LED fault only once
> */
> struct lp8864 {
> struct i2c_client *client;
> - struct led_classdev led_dev;
> + struct led_classdev *led_dev;
> + struct backlight_device *bl;
> struct regmap *regmap;
> u16 led_status_mask;
> };
> @@ -157,28 +162,59 @@ static int lp8864_fault_check(struct lp8864 *priv)
> return ret;
> }
>
> -static int lp8864_brightness_set(struct led_classdev *led_cdev,
> - enum led_brightness brt_val)
> +static int lp8864_brightness_set(struct lp8864 *priv, unsigned int brightness)
> {
> - struct lp8864 *priv = container_of(led_cdev, struct lp8864, led_dev);
> - /* Scale 0..LED_FULL into 16-bit HW brightness */
> - unsigned int val = brt_val * 0xffff / LED_FULL;
> int ret;
>
> ret = lp8864_fault_check(priv);
> if (ret)
> return ret;
>
> - ret = regmap_write(priv->regmap, LP8864_BRT_CONTROL, val);
> + ret = regmap_write(priv->regmap, LP8864_BRT_CONTROL, brightness);
> if (ret)
> dev_err(&priv->client->dev, "Failed to write brightness value\n");
>
> return ret;
> }
>
> -static enum led_brightness lp8864_brightness_get(struct led_classdev *led_cdev)
> +static int lp8864_backlight_update_status(struct backlight_device *bl)
> +{
> + return lp8864_brightness_set(bl_get_data(bl), backlight_get_brightness(bl));
> +}
> +
> +static int lp8864_backlight_get_brightness(struct backlight_device *bl)
> {
> - struct lp8864 *priv = container_of(led_cdev, struct lp8864, led_dev);
> + struct lp8864 *priv = bl_get_data(bl);
> + unsigned int val;
> + int ret;
> +
> + ret = regmap_read(priv->regmap, LP8864_BRT_CONTROL, &val);
> + if (ret) {
> + dev_err(&priv->client->dev, "Failed to read brightness value\n");
> + return ret;
> + }
> +
> + return val;
> +}
> +
> +static const struct backlight_ops lp8864_backlight_ops = {
> + .options = BL_CORE_SUSPENDRESUME,
> + .update_status = lp8864_backlight_update_status,
> + .get_brightness = lp8864_backlight_get_brightness,
> +};
> +
> +static int lp8864_led_brightness_set(struct led_classdev *led_cdev,
> + enum led_brightness brt_val)
> +{
> + struct lp8864 *priv = dev_get_drvdata(led_cdev->dev->parent);
> +
> + /* Scale 0..LED_FULL into 16-bit HW brightness */
> + return lp8864_brightness_set(priv, brt_val * 0xffff / LED_FULL);
> +}
> +
> +static enum led_brightness lp8864_led_brightness_get(struct led_classdev *led_cdev)
> +{
> + struct lp8864 *priv = dev_get_drvdata(led_cdev->dev->parent);
> unsigned int val;
> int ret;
>
> @@ -212,18 +248,15 @@ static int lp8864_probe(struct i2c_client *client)
> struct device_node *np = dev_of_node(&client->dev);
> struct device_node *child_node;
> struct led_init_data init_data = {};
> + struct backlight_device *bl;
> + struct backlight_properties props;
> struct gpio_desc *enable_gpio;
> + u32 val;
>
> priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
> if (!priv)
> return -ENOMEM;
>
> - child_node = of_get_next_available_child(np, NULL);
> - if (!child_node) {
> - dev_err(&client->dev, "No LED function defined\n");
> - return -EINVAL;
> - }
> -
> ret = devm_regulator_get_enable_optional(&client->dev, "vled");
> if (ret && ret != -ENODEV)
> return dev_err_probe(&client->dev, ret, "Failed to enable vled regulator\n");
> @@ -238,8 +271,7 @@ static int lp8864_probe(struct i2c_client *client)
> return ret;
>
> priv->client = client;
> - priv->led_dev.brightness_set_blocking = lp8864_brightness_set;
> - priv->led_dev.brightness_get = lp8864_brightness_get;
> + i2c_set_clientdata(client, priv);
>
> priv->regmap = devm_regmap_init_i2c(client, &lp8864_regmap_config);
> if (IS_ERR(priv->regmap))
> @@ -258,11 +290,46 @@ static int lp8864_probe(struct i2c_client *client)
> if (ret)
> return ret;
>
> + /* Register backlight class device */
> + memset(&props, 0, sizeof(props));
> + props.type = BACKLIGHT_RAW;
> + props.max_brightness = LP8864_MAX_BRIGHTNESS;
> + props.brightness = LP8864_MAX_BRIGHTNESS;
> + props.scale = BACKLIGHT_SCALE_LINEAR;
> +
> + if (!device_property_read_u32(&client->dev, "max-brightness", &val))
> + props.max_brightness = val;
> +
> + if (!device_property_read_u32(&client->dev, "default-brightness", &val))
> + props.brightness = val;
> +
> + bl = devm_backlight_device_register(&client->dev, "lp8864-backlight",
> + &client->dev, priv,
> + &lp8864_backlight_ops, &props);
> + if (IS_ERR(bl))
> + return dev_err_probe(&client->dev, PTR_ERR(bl),
> + "Failed to register backlight device\n");
> +
> + priv->bl = bl;
> + backlight_update_status(bl);
> +
> + /* Register LED class device if "led" child node is present */
> + child_node = of_get_available_child_by_name(np, "led");
> + if (!child_node)
> + return 0;
> +
> + priv->led_dev = devm_kzalloc(&client->dev, sizeof(*priv->led_dev), GFP_KERNEL);
> + if (!priv->led_dev)
> + return -ENOMEM;
> +
> + priv->led_dev->brightness_set_blocking = lp8864_led_brightness_set;
> + priv->led_dev->brightness_get = lp8864_led_brightness_get;
> +
> init_data.fwnode = of_fwnode_handle(child_node);
> init_data.devicename = "lp8864";
> init_data.default_label = ":display_cluster";
>
> - ret = devm_led_classdev_register_ext(&client->dev, &priv->led_dev, &init_data);
> + ret = devm_led_classdev_register_ext(&client->dev, priv->led_dev, &init_data);
> if (ret)
> dev_err(&client->dev, "Failed to register LED device (%pe)\n", ERR_PTR(ret));
>
> @@ -291,6 +358,6 @@ static struct i2c_driver lp8864_driver = {
> };
> module_i2c_driver(lp8864_driver);
>
> -MODULE_DESCRIPTION("Texas Instruments LP8864/LP8866 LED driver");
> +MODULE_DESCRIPTION("Texas Instruments LP8864/LP8866 LED Backlight driver");
> MODULE_AUTHOR("Alexander Sverdlin <alexander.sverdlin@siemens.com>");
> MODULE_LICENSE("GPL");
next prev parent reply other threads:[~2026-06-15 19:51 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-15 12:03 [PATCH 0/3] Convert LP8864 LED driver to backlight class A. Sverdlin
2026-06-15 12:03 ` [PATCH 1/3] dt-bindings: backlight: ti,lp8864: Add backlight class properties A. Sverdlin
2026-06-15 12:03 ` [PATCH 2/3] leds: lp8864: Rename struct lp8864_led and local variables A. Sverdlin
2026-06-15 12:03 ` [PATCH 3/3] backlight: lp8864: Convert from LED to backlight class driver A. Sverdlin
2026-06-15 19:51 ` Andrew Davis [this message]
2026-06-16 7:17 ` Sverdlin, Alexander
2026-06-23 11:41 ` Daniel Thompson
2026-06-23 11:59 ` Sverdlin, Alexander
2026-06-23 13:17 ` Daniel Thompson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=0b39450b-559b-43d4-a1e9-bb6684691cb5@ti.com \
--to=afd@ti.com \
--cc=alexander.sverdlin@siemens.com \
--cc=conor+dt@kernel.org \
--cc=danielt@kernel.org \
--cc=deller@gmx.de \
--cc=devicetree@vger.kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=jingoohan1@gmail.com \
--cc=krzk+dt@kernel.org \
--cc=lee@kernel.org \
--cc=linux-fbdev@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-leds@vger.kernel.org \
--cc=pavel@kernel.org \
--cc=robh@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox