]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
leds: Add support for TI LP5860 LED driver chip
authorSteffen Trumtrar <s.trumtrar@pengutronix.de>
Tue, 5 May 2026 06:16:10 +0000 (08:16 +0200)
committerLee Jones <lee@kernel.org>
Wed, 17 Jun 2026 10:28:29 +0000 (11:28 +0100)
Add support for the Texas Instruments LP5860 LED driver chip
via SPI interfaces.

The LP5860 is an LED matrix driver for up to 196 LEDs, which supports
short and open detection of the individual channel select lines.

It can be connected to SPI or I2C bus. For now add support for SPI only.

Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
Link: https://patch.msgid.link/20260505-v6-14-topic-ti-lp5860-v10-1-ee29341a75e4@pengutronix.de
Signed-off-by: Lee Jones <lee@kernel.org>
drivers/leds/rgb/Kconfig
drivers/leds/rgb/Makefile
drivers/leds/rgb/leds-lp5860-core.c [new file with mode: 0644]
drivers/leds/rgb/leds-lp5860-spi.c [new file with mode: 0644]
drivers/leds/rgb/leds-lp5860.h [new file with mode: 0644]

index 28ef4c487367cfd53bbcead27dab1dd5633f896c..9a4ba6531cf87d18b4d8aa35801dc5eca78b0ae9 100644 (file)
@@ -39,6 +39,31 @@ config LEDS_LP5812
 
          If unsure, say N.
 
+config LEDS_LP5860_CORE
+       tristate "Core Driver for TI LP5860"
+       depends on LEDS_CLASS
+       depends on OF
+       select REGMAP
+       help
+         This option supports common operations for LP5860 devices.
+         The LP5860 is a LED matrix driver with 18 constant current
+         sinks and 11 scan switches for 198 LED dots. Each dot can be
+         controlled individually and supports 8/16-bit PWM dimming.
+         The chip supports individual LED open and short detection.
+
+         The device can be used with SPI or I2C bus.
+
+config LEDS_LP5860_SPI
+       tristate "LED Support for TI LP5860 SPI LED driver chip"
+       depends on SPI
+       select LEDS_LP5860_CORE
+       help
+         If you say yes here you get support for the Texas Instruments
+         LP5860 LED driver for SPI bus connections.
+
+         To compile this driver as a module, choose M here: the
+         module will be called leds-lp5860-spi.
+
 config LEDS_NCP5623
        tristate "LED support for NCP5623"
        depends on I2C
index be45991f63f50d82ba706e646ee562a53f0813ac..f3b365ea082d11080ed864da0aedd0ca577e3a41 100644 (file)
@@ -3,6 +3,8 @@
 obj-$(CONFIG_LEDS_GROUP_MULTICOLOR)    += leds-group-multicolor.o
 obj-$(CONFIG_LEDS_KTD202X)             += leds-ktd202x.o
 obj-$(CONFIG_LEDS_LP5812)              += leds-lp5812.o
+obj-$(CONFIG_LEDS_LP5860_CORE)         += leds-lp5860-core.o
+obj-$(CONFIG_LEDS_LP5860_SPI)          += leds-lp5860-spi.o
 obj-$(CONFIG_LEDS_NCP5623)             += leds-ncp5623.o
 obj-$(CONFIG_LEDS_PWM_MULTICOLOR)      += leds-pwm-multicolor.o
 obj-$(CONFIG_LEDS_QCOM_LPG)            += leds-qcom-lpg.o
diff --git a/drivers/leds/rgb/leds-lp5860-core.c b/drivers/leds/rgb/leds-lp5860-core.c
new file mode 100644 (file)
index 0000000..fd0e2f6
--- /dev/null
@@ -0,0 +1,234 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2025 Pengutronix
+ *
+ * Author: Steffen Trumtrar <kernel@pengutronix.de>
+ */
+
+#include <linux/led-class-multicolor.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_platform.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+
+#include "leds-lp5860.h"
+
+static struct lp5860_led *mcled_cdev_to_led(struct led_classdev_mc *mc_cdev)
+{
+       return container_of(mc_cdev, struct lp5860_led, mc_cdev);
+}
+
+static int lp5860_set_dot_onoff(struct lp5860_led *led, unsigned int dot, bool enable)
+{
+       unsigned int offset = dot / LP5860_MAX_DOT_ONOFF_GROUP_NUM;
+       unsigned int mask = BIT(dot % LP5860_MAX_DOT_ONOFF_GROUP_NUM);
+
+       if (dot > LP5860_MAX_LED)
+               return -EINVAL;
+
+       return regmap_update_bits(led->chip->regmap,
+                                 LP5860_REG_DOT_ONOFF_START + offset, mask,
+                                 enable ? LP5860_DOT_ALL_ON : LP5860_DOT_ALL_OFF);
+}
+
+static int lp5860_set_mc_brightness(struct led_classdev *cdev,
+                                   enum led_brightness brightness)
+{
+       struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev);
+       struct lp5860_led *led = mcled_cdev_to_led(mc_cdev);
+
+       led_mc_calc_color_components(mc_cdev, brightness);
+
+       guard(mutex)(&led->chip->lock);
+       for (int i = 0; i < led->mc_cdev.num_colors; i++) {
+               unsigned int channel = mc_cdev->subled_info[i].channel;
+               unsigned int led_brightness = mc_cdev->subled_info[i].brightness;
+               int ret;
+
+               ret = lp5860_set_dot_onoff(led, channel, !!led_brightness);
+               if (ret)
+                       return ret;
+
+               ret = regmap_write(led->chip->regmap,
+                                  LP5860_REG_PWM_BRI_START + channel, led_brightness);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int lp5860_chip_enable(struct lp5860 *lp, bool enable)
+{
+       guard(mutex)(&lp->lock);
+       return regmap_write(lp->regmap, LP5860_REG_CHIP_EN, enable);
+}
+
+static int lp5860_led_init(struct lp5860_led *led, struct fwnode_handle *fwnode,
+                          unsigned int channel)
+{
+       enum led_default_state default_state;
+       unsigned int brightness;
+       int ret;
+
+       guard(mutex)(&led->chip->lock);
+       ret = regmap_read(led->chip->regmap, LP5860_REG_PWM_BRI_START + channel, &brightness);
+       if (ret)
+               return ret;
+
+       default_state = led_init_default_state_get(fwnode);
+
+       switch (default_state) {
+       case LEDS_DEFSTATE_ON:
+               led->brightness = LP5860_MAX_BRIGHTNESS;
+               break;
+       case LEDS_DEFSTATE_KEEP:
+               led->brightness = min(brightness, LP5860_MAX_BRIGHTNESS);
+               break;
+       default:
+               led->brightness = 0;
+               break;
+       }
+
+       return 0;
+}
+
+static int lp5860_iterate_subleds(struct lp5860_led *led, struct led_init_data *init_data)
+{
+       struct fwnode_handle *led_node = NULL;
+       struct fwnode_handle *multi_led = init_data->fwnode;
+       int subled = 0;
+
+       fwnode_for_each_child_node(multi_led, led_node) {
+               u32 channel;
+               u32 color_index;
+               int ret;
+
+               ret = fwnode_property_read_u32(led_node, "color", &color_index);
+               if (ret) {
+                       dev_err_probe(led->chip->dev, ret,
+                                     "%pfwP: Cannot read 'color' property. Skipping.\n", led_node);
+                       fwnode_handle_put(led_node);
+                       return ret;
+               }
+
+               ret = fwnode_property_read_u32(led_node, "reg", &channel);
+               if (ret < 0 || channel > LP5860_MAX_LED) {
+                       dev_err_probe(led->chip->dev, ret,
+                                     "%pfwP: 'reg' property is missing. Skipping.\n", led_node);
+                       fwnode_handle_put(led_node);
+                       return ret;
+               }
+
+               led->mc_cdev.subled_info[subled].color_index = color_index;
+               led->mc_cdev.subled_info[subled].channel = channel;
+               ret = lp5860_led_init(led, init_data->fwnode, channel);
+               if (ret) {
+                       dev_err_probe(led->chip->dev, ret,
+                                     "%pfwP: Failed to init LED\n", led_node);
+                       fwnode_handle_put(led_node);
+                       return ret;
+               }
+
+               subled++;
+       }
+
+       return 0;
+}
+
+static int lp5860_init_dt(struct lp5860 *lp)
+{
+       struct led_init_data init_data = {};
+       struct led_classdev *led_cdev;
+       struct mc_subled *mc_led_info;
+       struct lp5860_led *led;
+       int led_index = 0;
+       int chan;
+       int ret;
+
+       device_for_each_child_node_scoped(lp->dev, multi_led) {
+               led = &lp->leds[led_index];
+
+               init_data.fwnode = multi_led;
+
+               /* Count the number of channels in this multi_led */
+               chan = fwnode_get_child_node_count(multi_led);
+               if (!chan || chan > LP5860_MAX_LED_CHANNELS)
+                       return -EINVAL;
+
+               led->mc_cdev.num_colors = chan;
+
+               mc_led_info = devm_kcalloc(lp->dev, chan, sizeof(*mc_led_info), GFP_KERNEL);
+               if (!mc_led_info)
+                       return -ENOMEM;
+
+               led->chip = lp;
+               led->mc_cdev.subled_info = mc_led_info;
+               led_cdev = &led->mc_cdev.led_cdev;
+               led_cdev->max_brightness = LP5860_MAX_BRIGHTNESS;
+               led_cdev->brightness_set_blocking = lp5860_set_mc_brightness;
+
+               ret = lp5860_iterate_subleds(led, &init_data);
+               if (ret)
+                       continue;
+
+               ret = lp5860_set_mc_brightness(&led->mc_cdev.led_cdev, led->brightness);
+               if (ret)
+                       return dev_err_probe(lp->dev, ret, "%pfwP: Failed to set Multi-Color brightness\n",
+                                            multi_led);
+
+               ret = devm_led_classdev_multicolor_register_ext(lp->dev, &led->mc_cdev, &init_data);
+               if (ret)
+                       return dev_err_probe(lp->dev, ret, "%pfwP: Failed to register Multi-Color LEDs\n",
+                                            multi_led);
+               led_index++;
+       }
+
+       return 0;
+}
+
+int lp5860_device_init(struct device *dev)
+{
+       struct lp5860 *lp = dev_get_drvdata(dev);
+       int ret;
+
+       ret = lp5860_chip_enable(lp, LP5860_CHIP_ENABLE);
+       if (ret)
+               return ret;
+
+       /*
+        * Set to 8-bit PWM data without VSYNC.
+        * Data is sent out for display instantly after received.
+        */
+       mutex_lock(&lp->lock);
+       ret = regmap_update_bits(lp->regmap, LP5860_REG_DEV_INITIAL, LP5860_MODE_MASK,
+                                LP5860_MODE_1 << LP5860_MODE_SHIFT);
+       if (ret)
+               goto err_disable;
+       mutex_unlock(&lp->lock);
+
+       ret = lp5860_init_dt(lp);
+       if (ret)
+               goto err_disable;
+
+       return 0;
+
+err_disable:
+       mutex_unlock(&lp->lock);
+       lp5860_chip_enable(lp, LP5860_CHIP_DISABLE);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(lp5860_device_init);
+
+void lp5860_device_remove(struct device *dev)
+{
+       struct lp5860 *lp = dev_get_drvdata(dev);
+
+       lp5860_chip_enable(lp, LP5860_CHIP_DISABLE);
+}
+EXPORT_SYMBOL_GPL(lp5860_device_remove);
+
+MODULE_AUTHOR("Steffen Trumtrar <kernel@pengutronix.de>");
+MODULE_DESCRIPTION("TI LP5860 RGB LED core driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/rgb/leds-lp5860-spi.c b/drivers/leds/rgb/leds-lp5860-spi.c
new file mode 100644 (file)
index 0000000..5e0c448
--- /dev/null
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2025 Pengutronix
+ *
+ * Author: Steffen Trumtrar <kernel@pengutronix.de>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include "leds-lp5860.h"
+
+#define LP5860_SPI_WRITE_FLAG BIT(13)
+
+/*
+ * The lp5860 uses a rather uncommon SPI data format: The R/W flag is on BIT(5) in the two address
+ * bytes; BIT(4) to BIT(0) are don't care. Therefore it has 10 bits for the address and 6 bits for
+ * padding the address. The address bytes are sent MSB first. Matching the cores registers to regmap
+ * results in write_flag_mask being BIT(13).
+ */
+static const struct regmap_config lp5860_regmap_config = {
+       .name = "lp5860",
+       .reg_bits = 10,
+       .pad_bits = 6,
+       .val_bits = 8,
+       .write_flag_mask = LP5860_SPI_WRITE_FLAG,
+       .reg_format_endian = REGMAP_ENDIAN_BIG,
+       .max_register = LP5860_MAX_REG,
+};
+
+static int lp5860_probe(struct spi_device *spi)
+{
+       struct device *dev = &spi->dev;
+       struct lp5860 *lp5860;
+       unsigned int multi_leds;
+
+       multi_leds = device_get_child_node_count(dev);
+       if (!multi_leds) {
+               dev_err(dev, "LEDs are not defined in Device Tree!");
+               return -ENODEV;
+       }
+
+       if (multi_leds > LP5860_MAX_LED) {
+               dev_err(dev, "Too many LEDs specified.\n");
+               return -EINVAL;
+       }
+
+       lp5860 = devm_kzalloc(dev, struct_size(lp5860, leds, multi_leds),
+                             GFP_KERNEL);
+       if (!lp5860)
+               return -ENOMEM;
+
+       lp5860->regmap = devm_regmap_init_spi(spi, &lp5860_regmap_config);
+       if (IS_ERR(lp5860->regmap))
+               return dev_err_probe(&spi->dev, PTR_ERR(lp5860->regmap),
+                                    "Failed to initialise Regmap.\n");
+
+       lp5860->dev = dev;
+       mutex_init(&lp5860->lock);
+
+       spi_set_drvdata(spi, lp5860);
+
+       return lp5860_device_init(dev);
+}
+
+static void lp5860_remove(struct spi_device *spi)
+{
+       struct lp5860 *lp5860 = spi_get_drvdata(spi);
+
+       mutex_destroy(&lp5860->lock);
+
+       lp5860_device_remove(&spi->dev);
+}
+
+static const struct of_device_id lp5860_of_match[] = {
+       { .compatible = "ti,lp5860" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, lp5860_of_match);
+
+static struct spi_driver lp5860_driver = {
+       .driver = {
+               .name = "lp5860-spi",
+               .of_match_table = lp5860_of_match,
+       },
+       .probe  = lp5860_probe,
+       .remove = lp5860_remove,
+};
+module_spi_driver(lp5860_driver);
+
+MODULE_AUTHOR("Steffen Trumtrar <kernel@pengutronix.de>");
+MODULE_DESCRIPTION("TI LP5860 RGB LED SPI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/rgb/leds-lp5860.h b/drivers/leds/rgb/leds-lp5860.h
new file mode 100644 (file)
index 0000000..940be0c
--- /dev/null
@@ -0,0 +1,268 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2025 Pengutronix
+ *
+ * Author: Steffen Trumtrar <kernel@pengutronix.de>
+ */
+
+#ifndef _DRIVERS_LEDS_RGB_LP5860_H
+#define _DRIVERS_LEDS_RGB_LP5860_H
+
+#include <linux/led-class-multicolor.h>
+#include <linux/regmap.h>
+
+#define LP5860_REG_CHIP_EN             0x00
+#define LP5860_REG_DEV_INITIAL         0x01
+#define LP5860_REG_DEV_CONFIG1         0x02
+#define LP5860_REG_DEV_CONFIG2         0x03
+#define LP5860_REG_DEV_CONFIG3         0x04
+#define LP5860_REG_GLOBAL_BRI          0x05
+#define LP5860_REG_GROUP0_BRI          0x06
+#define LP5860_REG_GROUP1_BRI          0x07
+#define LP5860_REG_GROUP2_BRI          0x08
+#define LP5860_REG_R_CURRENT_SET       0x09
+#define LP5860_REG_G_CURRENT_SET       0x0A
+#define LP5860_REG_B_CURRENT_SET       0x0B
+#define LP5860_REG_GRP_SEL_START       0x0C
+#define LP5860_REG_DOT_ONOFF_START     0x43
+#define LP5860_REG_DOT_ONOFF_MAX       0x63
+#define LP5860_REG_FAULT_STATE         0x64
+#define LP5860_REG_DOT_LOD_START       0x65
+#define LP5860_REG_DOT_LSD_START       0x86
+#define LP5860_REG_LOD_CLEAR           0xA7
+#define LP5860_REG_LSD_CLEAR           0xA8
+#define LP5860_REG_RESET               0xA9
+#define LP5860_REG_DC_START            0x0100
+#define LP5860_REG_PWM_BRI_START       0x0200
+#define LP5860_MAX_REG                 0x038B
+
+/* Register chip_enable value */
+#define LP5860_CHIP_SHIFT              0
+#define LP5860_CHIP_MASK               BIT(0)
+#define LP5860_CHIP_DISABLE            false
+#define LP5860_CHIP_ENABLE             true
+
+/* Register dev_initial value */
+#define LP5860_MAX_LINE_SHIFT          3
+#define LP5860_MAX_LINE_MASK           GENMASK(6, 3)
+#define LP5860_MAX_LINE_11             0x0B
+#define LP5860_MAX_LINE_10             0x0A
+#define LP5860_MAX_LINE_9              0x09
+#define LP5860_MAX_LINE_8              0x08
+#define LP5860_MAX_LINE_7              0x07
+#define LP5860_MAX_LINE_6              0x06
+#define LP5860_MAX_LINE_5              0x05
+#define LP5860_MAX_LINE_4              0x04
+#define LP5860_MAX_LINE_3              0x03
+#define LP5860_MAX_LINE_2              0x02
+#define LP5860_MAX_LINE_1              0x01
+
+#define LP5860_MODE_SHIFT              1
+#define LP5860_MODE_MASK               GENMASK(2, 1)
+#define LP5860_MODE_3_1                        0x03
+#define LP5860_MODE_3                  0x02
+#define LP5860_MODE_2                  0x01
+#define LP5860_MODE_1                  0x00
+
+#define LP5860_PWM_FREQUENCY_SHIFT     0
+#define LP5860_PWM_FREQUENCY_MASK      BIT(0)
+#define LP5860_PWM_FREQUENCY_62_5K     0x01
+#define LP5860_PWM_FREQUENCY_125K      0x00
+
+/* Register dev_config1 value */
+#define LP5860_SW_BLK_SHIFT            3
+#define LP5860_SW_BLK_MASK             BIT(3)
+#define LP5860_SW_BLK_05US             0x01
+#define LP5860_SW_BLK_1US              0x00
+
+#define LP5860_PWM_SCALE_MODE_SHIFT    2
+#define LP5860_PWM_SCALE_MODE_MASK     BIT(2)
+#define LP5860_PWM_SCALE_EXPONENTIAL   0x01
+#define LP5860_PWM_SCALE_LINEAR                0x00
+
+#define LP5860_PWM_PHASESHIFT_SHIFT    1
+#define LP5860_PWM_PHASESHIFT_MASK     BIT(1)
+#define LP5860_PWM_PHASESHIFT_ON       0x01
+#define LP5860_PWM_PHASESHIFT_OFF      0x00
+
+#define LP5860_CS_ON_SHIFT_SHIFT       0
+#define LP5860_CS_ON_SHIFT_MASK                BIT(0)
+#define LP5860_CS_DELAY_ON             0x01
+#define LP5860_CS_DELAY_OFF            0x00
+
+/* Register dev_config2 value */
+#define LP5860_COMP_GROUP3_SHIFT       6
+#define LP5860_COMP_GROUP3_MASK                GENMASK(7, 6)
+#define LP5860_COMP_GROUP3_3CLOCK      0x03
+#define LP5860_COMP_GROUP3_2CLOCK      0x02
+#define LP5860_COMP_GROUP3_1CLOCK      0x01
+#define LP5860_COMP_GROUP3_OFF         0x00
+
+#define LP5860_COMP_GROUP2_SHIFT       4
+#define LP5860_COMP_GROUP2_MASK                GENMASK(5, 4)
+#define LP5860_COMP_GROUP2_3CLOCK      0x03
+#define LP5860_COMP_GROUP2_2CLOCK      0x02
+#define LP5860_COMP_GROUP2_1CLOCK      0x01
+#define LP5860_COMP_GROUP2_OFF         0x00
+
+#define LP5860_COMP_GROUP1_SHIFT       2
+#define LP5860_COMP_GROUP1_MASK                GENMASK(3, 2)
+#define LP5860_COMP_GROUP1_3CLOCK      0x03
+#define LP5860_COMP_GROUP1_2CLOCK      0x02
+#define LP5860_COMP_GROUP1_1CLOCK      0x01
+#define LP5860_COMP_GROUP1_OFF         0x00
+
+#define LP5860_LOD_REMOVAL_SHIFT       1
+#define LP5860_LOD_REMOVAL_MASK                BIT(1)
+#define LP5860_LOD_REMOVAL_EN          0x01
+#define LP5860_LOD_REMOVAL_OFF         0x00
+
+#define LP5860_LSD_REMOVAL_SHIFT       0
+#define LP5860_LSD_REMOVAL_MASK                BIT(0)
+#define LP5860_LSD_REMOVAL_EN          0x01
+#define LP5860_LSD_REMOVAL_OFF         0x00
+
+/* Register dev_config3 value */
+#define LP5860_DOWN_DEGHOST_SHIFT      6
+#define LP5860_DOWN_DEGHOST_MASK       GENMASK(7, 6)
+#define LP5860_DOWN_DEGHOST_STRONG     0x03
+#define LP5860_DOWN_DEGHOST_MEDIUM     0x02
+#define LP5860_DOWN_DEGHOST_WEAK       0x01
+#define LP5860_DOWN_DEGHOST_OFF                0x00
+
+#define LP5860_UP_DEGHOST_SHIFT        4
+#define LP5860_UP_DEGHOST_MASK         GENMASK(5, 4)
+#define LP5860_UP_DEGHOST_GND          0x03
+#define LP5860_UP_DEGHOST_3            0x02
+#define LP5860_UP_DEGHOST_2_5          0x01
+#define LP5860_UP_DEGHOST_2            0x00
+
+#define LP5860_MAXIMUM_CURRENT_SHIFT   1
+#define LP5860_MAXIMUM_CURRENT_MASK    GENMASK(3, 1)
+#define LP5860_MAXIMUM_CURRENT_50      0x07
+#define LP5860_MAXIMUM_CURRENT_40      0x06
+#define LP5860_MAXIMUM_CURRENT_30      0x05
+#define LP5860_MAXIMUM_CURRENT_20      0x04
+#define LP5860_MAXIMUM_CURRENT_15      0x03
+#define LP5860_MAXIMUM_CURRENT_10      0x02
+#define LP5860_MAXIMUM_CURRENT_5       0x01
+#define LP5860_MAXIMUM_CURRENT_3       0x00
+
+#define LP5860_UP_DEGHOST_ENABLE_SHIFT 0
+#define LP5860_UP_DEGHOST_ENABLE_MASK  BIT(0)
+#define LP5860_UP_DEGHOST_ENABLE_EN    0x01
+#define LP5860_UP_DEGHOST_ENABLE_OFF   0x00
+
+/* Register PWM */
+#define LP5860_PWM_GLOBAL_MAX          0xff
+#define LP5860_PWM_GROUP_MAX           0xff
+
+/* Register CC group select */
+#define LP5860_CC_GROUP_MASK           GENMASK(7, 0)
+#define LP5860_CC_GROUP_MAX            0x7F
+
+/* Register dot group select */
+#define LP5860_DOT_0_SHIFT             0
+#define LP5860_DOT_1_SHIFT             2
+#define LP5860_DOT_2_SHIFT             4
+#define LP5860_DOT_3_SHIFT             6
+
+#define LP5860_DOT_GROUP3              0x03
+#define LP5860_DOT_GROUP2              0x02
+#define LP5860_DOT_GROUP1              0x01
+#define LP5860_DOT_GROUP_NONE          0x00
+
+#define LP5860_DOT_ALL_ON              0xff
+#define LP5860_DOT_ALL_OFF             0x0
+#define LP5860_PWM_DOT_MAX             0xff
+/* Dot onoff value */
+#define LP5860_DOT_CS0_SHIFT           0
+#define LP5860_DOT_CS1_SHIFT           1
+#define LP5860_DOT_CS2_SHIFT           2
+#define LP5860_DOT_CS3_SHIFT           3
+#define LP5860_DOT_CS4_SHIFT           4
+#define LP5860_DOT_CS5_SHIFT           5
+#define LP5860_DOT_CS6_SHIFT           6
+#define LP5860_DOT_CS7_SHIFT           7
+
+#define LP5860_DOT_CS_ON               0x01
+#define LP5860_DOT_CS_OFF              0x00
+
+/* Dot lod value */
+#define LP5860_DOT_LOD0_SHIFT          0
+#define LP5860_DOT_LOD1_SHIFT          1
+#define LP5860_DOT_LOD2_SHIFT          2
+#define LP5860_DOT_LOD3_SHIFT          3
+#define LP5860_DOT_LOD4_SHIFT          4
+#define LP5860_DOT_LOD5_SHIFT          5
+#define LP5860_DOT_LOD6_SHIFT          6
+#define LP5860_DOT_LOD7_SHIFT          7
+
+#define LP5860_DOT_LOD_ON              0x01
+#define LP5860_DOT_LOD_OFF             0x00
+
+/* dot lsd value */
+#define LP5860_DOT_LSD0_SHIFT          0
+#define LP5860_DOT_LSD1_SHIFT          1
+#define LP5860_DOT_LSD2_SHIFT          2
+#define LP5860_DOT_LSD3_SHIFT          3
+#define LP5860_DOT_LSD4_SHIFT          4
+#define LP5860_DOT_LSD5_SHIFT          5
+#define LP5860_DOT_LSD6_SHIFT          6
+#define LP5860_DOT_LSD7_SHIFT          7
+
+#define LP5860_DOT_LSD_ON              0x01
+#define LP5860_DOT_LSD_OFF             0x00
+
+/* Register lod state */
+#define LP5860_GLOBAL_LOD_SHIFT        1
+#define LP5860_GLOBAL_LOD_STATE                BIT(1)
+#define LP5860_GLOBAL_LSD_SHIFT        0
+#define LP5860_GLOBAL_LSD_STATE                BIT(0)
+
+#define LP5860_FAULT_STATE_ON          0x01
+#define LP5860_FAULT_STATE_OFF         0x00
+
+#define LP5860_GLOBAL_LOD_CLEAR                0x00
+#define LP5860_GLOBAL_LSD_CLEAR                0x00
+
+
+#define LP5860_LOD_CLEAR_EN            0xff
+#define LP5860_LSD_CLEAR_EN            0xff
+#define LP5860_RESET_EN                        0xff
+
+#define LP5860_MAX_BRIGHTNESS          255
+#define LP5860_REG_R_PWM               0x0
+#define LP5860_REG_G_PWM               0x1
+#define LP5860_REG_B_PWM               0x2
+
+#define LP5860_MAX_LED_CONSTANT                18
+#define LP5860_MAX_LED_SCAN            11
+#define LP5860_MAX_LED                 (LP5860_MAX_LED_CONSTANT * LP5860_MAX_LED_SCAN)
+
+#define LP5860_MAX_DOT_ONOFF_GROUP_NUM 8
+
+/*
+ * Theoretically, there is no max channel per LED,
+ * limit this to a reasonable value for RGBW LEDs
+ */
+#define LP5860_MAX_LED_CHANNELS                4
+
+struct lp5860_led {
+       struct lp5860 *chip;
+       struct led_classdev_mc mc_cdev;
+       u8 brightness;
+};
+
+struct lp5860 {
+       struct device *dev;
+       struct regmap *regmap;
+       struct mutex lock;
+
+       DECLARE_FLEX_ARRAY(struct lp5860_led, leds);
+};
+
+int lp5860_device_init(struct device *dev);
+void lp5860_device_remove(struct device *dev);
+
+#endif /* _DRIVERS_LEDS_RGB_LP5860_H */