From b2043827efd7b2c9675387cd81dfde7ef276fad6 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 17 Nov 2023 02:01:34 +0000 Subject: [PATCH] mediatek: import driver for Adtran SmartRG RGB LED Import driver for I2C-connected HolTek MCU controlling the RGB LED found in Adtran SmartRG devices. Signed-off-by: Daniel Golle --- .../files/drivers/leds/leds-smartrg-system.c | 249 ++++++++++++++++++ target/linux/mediatek/filogic/config-5.15 | 1 + target/linux/mediatek/filogic/config-6.1 | 1 + target/linux/mediatek/mt7622/config-5.15 | 1 + target/linux/mediatek/mt7622/config-6.1 | 1 + target/linux/mediatek/mt7623/config-5.15 | 1 + target/linux/mediatek/mt7623/config-6.1 | 1 + target/linux/mediatek/mt7629/config-5.15 | 1 + target/linux/mediatek/mt7629/config-6.1 | 1 + .../950-smartrg-i2c-led-driver.patch | 34 +++ 10 files changed, 291 insertions(+) create mode 100644 target/linux/mediatek/files/drivers/leds/leds-smartrg-system.c create mode 100644 target/linux/mediatek/patches-5.15/950-smartrg-i2c-led-driver.patch diff --git a/target/linux/mediatek/files/drivers/leds/leds-smartrg-system.c b/target/linux/mediatek/files/drivers/leds/leds-smartrg-system.c new file mode 100644 index 0000000000..55d19c1f19 --- /dev/null +++ b/target/linux/mediatek/files/drivers/leds/leds-smartrg-system.c @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * Driver for SmartRG RGBW LED microcontroller. + * RGBW LED is connected to a Holtek HT45F0062 that is on the I2C bus. + * + */ + +struct srg_led { + struct mutex lock; + struct i2c_client *client; + struct led_classdev led_red; + struct led_classdev led_green; + struct led_classdev led_blue; + struct led_classdev led_white; + u8 index_red; + u8 index_green; + u8 index_blue; + u8 index_white; + u8 control[5]; +}; + + +static int +srg_led_i2c_write(struct srg_led *sysled, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(sysled->client, reg, value); +} + +/* + * MC LED Command: 0 = OFF, 1 = ON, 2 = Flash, 3 = Pulse, 4 = Blink + * */ +static int +srg_led_control_sync(struct srg_led *sysled) +{ + int i, ret; + + for (i = 1; i < 5; i++) { + if (sysled->control[i] > 1) { + ret = srg_led_i2c_write(sysled, i, sysled->control[i]); + if (i < 4) { + msleep(1); + } + } + } + return ret; +} + +/* + * This function overrides the led driver timer trigger to offload + * flashing to the micro-controller. The negative effect of this + * is the inability to configure the delay_on and delay_off periods. + * + * */ +#define SRG_LED_RGBW_PULSE(color) \ +static int \ +srg_led_set_##color##_pulse(struct led_classdev *led_cdev, \ + unsigned long *delay_on, \ + unsigned long *delay_off) \ +{ \ + struct srg_led *sysled = container_of(led_cdev, \ + struct srg_led, \ + led_##color); \ + int ret; \ + mutex_lock(&sysled->lock); \ + sysled->control[sysled->index_##color] = 3; \ + ret = srg_led_control_sync(sysled); \ + mutex_unlock(&sysled->lock); \ + return ret; \ +} + +SRG_LED_RGBW_PULSE(red); +SRG_LED_RGBW_PULSE(green); +SRG_LED_RGBW_PULSE(blue); +SRG_LED_RGBW_PULSE(white); + +#define SRG_LED_CONTROL_RGBW(color) \ +static int \ +srg_led_set_##color##_brightness(struct led_classdev *led_cdev, \ + enum led_brightness value) \ +{ \ + struct srg_led *sysled = container_of(led_cdev, \ + struct srg_led, \ + led_##color); \ + int ret, index, control=value; \ + mutex_lock(&sysled->lock); \ + if (value == 255) { \ + control = 1; \ + } \ + if (control > 4) { \ + index = sysled->index_##color + 4; \ + ret = srg_led_i2c_write(sysled, index, control); \ + } else { \ + sysled->control[sysled->index_##color] = control; \ + ret = srg_led_i2c_write(sysled, sysled->index_##color, control); \ + msleep(1); \ + } \ + mutex_unlock(&sysled->lock); \ + return ret; \ +} + +SRG_LED_CONTROL_RGBW(red); +SRG_LED_CONTROL_RGBW(green); +SRG_LED_CONTROL_RGBW(blue); +SRG_LED_CONTROL_RGBW(white); + + +static u8 +srg_led_init_led(struct device_node *np, struct srg_led *sysled, + struct led_classdev *led_cdev) +{ + struct led_init_data init_data = {}; + int ret; + int index; + + if (!np) + return 0; + + init_data.fwnode = of_fwnode_handle(np); + + led_cdev->name = of_get_property(np, "label", NULL) ? : np->name; + led_cdev->brightness = LED_OFF; + led_cdev->max_brightness = LED_FULL; + + ret = devm_led_classdev_register_ext(&sysled->client->dev, + led_cdev, &init_data); + if (ret) { + dev_err(&sysled->client->dev, + "srg_led_init_led: led register %s error ret %d!n", + led_cdev->name, ret); + return 0; + } + + ret = of_property_read_u32(np, "reg", &index); + if (ret) { + dev_err(&sysled->client->dev, + "srg_led_init_led: no reg defined in np!\n"); + return 0; + } + + return index; +} + +static int +srg_led_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct device_node *np = client->dev.of_node; + struct srg_led *sysled; + int ret = 0; + + sysled = devm_kzalloc(&client->dev, sizeof(*sysled), GFP_KERNEL); + if (!sysled) + return -ENOMEM; + + sysled->client = client; + + mutex_init(&sysled->lock); + + i2c_set_clientdata(client, sysled); + + sysled->led_red.brightness_set_blocking = srg_led_set_red_brightness; + sysled->led_red.blink_set = srg_led_set_red_pulse; + sysled->index_red = srg_led_init_led(of_get_child_by_name(np, "system_red"), + sysled, &sysled->led_red); + + srg_led_set_red_brightness(&sysled->led_red, LED_OFF); + msleep(5); + + sysled->led_green.brightness_set_blocking = srg_led_set_green_brightness; + sysled->led_green.blink_set = srg_led_set_green_pulse; + sysled->index_green = srg_led_init_led(of_get_child_by_name(np, "system_green"), + sysled, &sysled->led_green); + + srg_led_set_green_brightness(&sysled->led_green, LED_OFF); + msleep(5); + + sysled->led_blue.brightness_set_blocking = srg_led_set_blue_brightness; + sysled->led_blue.blink_set = srg_led_set_blue_pulse; + sysled->index_blue = srg_led_init_led(of_get_child_by_name(np, "system_blue"), + sysled, &sysled->led_blue); + + srg_led_set_blue_brightness(&sysled->led_blue, LED_OFF); + msleep(5); + + sysled->led_white.brightness_set_blocking = srg_led_set_white_brightness; + sysled->led_white.blink_set = srg_led_set_white_pulse; + sysled->index_white = srg_led_init_led(of_get_child_by_name(np, "system_white"), + sysled, &sysled->led_white); + + srg_led_set_white_brightness(&sysled->led_white, LED_OFF); + + dev_err(&client->dev, "srg_led_probe done\n"); + return ret; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,16,0) +static void +#else +static int +#endif +srg_led_remove(struct i2c_client *client) +{ + struct srg_led *sysled = i2c_get_clientdata(client); + int ret = 0; + + mutex_destroy(&sysled->lock); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,16,0) + return ret; +#endif +} + + +static const struct i2c_device_id srg_led_id[] = { + { "srg-sysled", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, srg_led_id); + +static const struct of_device_id of_srg_led_match[] = { + { .compatible = "srg,sysled", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_srg_led_match); + +static struct i2c_driver srg_sysled_driver = { + .driver = { + .name = "srg-sysled", + .of_match_table = of_srg_led_match, + }, + .probe = srg_led_probe, + .remove = srg_led_remove, + .id_table = srg_led_id, +}; +module_i2c_driver(srg_sysled_driver); + + +MODULE_DESCRIPTION("SmartRG system LED driver"); +MODULE_AUTHOR("Shen Loh "); +MODULE_LICENSE("GPL v2"); diff --git a/target/linux/mediatek/filogic/config-5.15 b/target/linux/mediatek/filogic/config-5.15 index 2ffc466b7c..a8dae79166 100644 --- a/target/linux/mediatek/filogic/config-5.15 +++ b/target/linux/mediatek/filogic/config-5.15 @@ -193,6 +193,7 @@ CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_IRQ_WORK=y CONFIG_JBD2=y CONFIG_JUMP_LABEL=y +CONFIG_LEDS_SMARTRG_LED=y CONFIG_LIBFDT=y CONFIG_LOCK_DEBUGGING_SUPPORT=y CONFIG_LOCK_SPIN_ON_OWNER=y diff --git a/target/linux/mediatek/filogic/config-6.1 b/target/linux/mediatek/filogic/config-6.1 index 36cb9c1e4e..cccb15a18a 100644 --- a/target/linux/mediatek/filogic/config-6.1 +++ b/target/linux/mediatek/filogic/config-6.1 @@ -210,6 +210,7 @@ CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_IRQ_WORK=y CONFIG_JBD2=y CONFIG_JUMP_LABEL=y +CONFIG_LEDS_SMARTRG_LED=y CONFIG_LIBFDT=y CONFIG_LOCK_DEBUGGING_SUPPORT=y CONFIG_LOCK_SPIN_ON_OWNER=y diff --git a/target/linux/mediatek/mt7622/config-5.15 b/target/linux/mediatek/mt7622/config-5.15 index 643eaa45b6..18f972e949 100644 --- a/target/linux/mediatek/mt7622/config-5.15 +++ b/target/linux/mediatek/mt7622/config-5.15 @@ -215,6 +215,7 @@ CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_IRQ_WORK=y CONFIG_JBD2=y CONFIG_JUMP_LABEL=y +# CONFIG_LEDS_SMARTRG_LED is not set CONFIG_LIBFDT=y CONFIG_LOCK_DEBUGGING_SUPPORT=y CONFIG_LOCK_SPIN_ON_OWNER=y diff --git a/target/linux/mediatek/mt7622/config-6.1 b/target/linux/mediatek/mt7622/config-6.1 index 7055e4d728..6272a3bac6 100644 --- a/target/linux/mediatek/mt7622/config-6.1 +++ b/target/linux/mediatek/mt7622/config-6.1 @@ -216,6 +216,7 @@ CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_IRQ_WORK=y CONFIG_JBD2=y CONFIG_JUMP_LABEL=y +# CONFIG_LEDS_SMARTRG_LED is not set CONFIG_LIBFDT=y CONFIG_LOCK_DEBUGGING_SUPPORT=y CONFIG_LOCK_SPIN_ON_OWNER=y diff --git a/target/linux/mediatek/mt7623/config-5.15 b/target/linux/mediatek/mt7623/config-5.15 index 039a904f19..2f12488327 100644 --- a/target/linux/mediatek/mt7623/config-5.15 +++ b/target/linux/mediatek/mt7623/config-5.15 @@ -297,6 +297,7 @@ CONFIG_KMAP_LOCAL_NON_LINEAR_PTE_ARRAY=y CONFIG_LCD_CLASS_DEVICE=y CONFIG_LCD_PLATFORM=y CONFIG_LEDS_MT6323=y +# CONFIG_LEDS_SMARTRG_LED is not set CONFIG_LIBFDT=y CONFIG_LOCK_DEBUGGING_SUPPORT=y CONFIG_LOCK_SPIN_ON_OWNER=y diff --git a/target/linux/mediatek/mt7623/config-6.1 b/target/linux/mediatek/mt7623/config-6.1 index b6a75ab80a..218016b200 100644 --- a/target/linux/mediatek/mt7623/config-6.1 +++ b/target/linux/mediatek/mt7623/config-6.1 @@ -317,6 +317,7 @@ CONFIG_LCD_CLASS_DEVICE=y CONFIG_LCD_PLATFORM=y CONFIG_LEDS_MT6323=y # CONFIG_LEDS_QCOM_LPG is not set +# CONFIG_LEDS_SMARTRG_LED is not set CONFIG_LIBFDT=y CONFIG_LOCK_DEBUGGING_SUPPORT=y CONFIG_LOCK_SPIN_ON_OWNER=y diff --git a/target/linux/mediatek/mt7629/config-5.15 b/target/linux/mediatek/mt7629/config-5.15 index 08089dde2a..8cddb04d66 100644 --- a/target/linux/mediatek/mt7629/config-5.15 +++ b/target/linux/mediatek/mt7629/config-5.15 @@ -149,6 +149,7 @@ CONFIG_IRQ_FORCED_THREADING=y CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_IRQ_WORK=y # CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set +# CONFIG_LEDS_SMARTRG_LED is not set CONFIG_LIBFDT=y CONFIG_LOCK_DEBUGGING_SUPPORT=y CONFIG_LOCK_SPIN_ON_OWNER=y diff --git a/target/linux/mediatek/mt7629/config-6.1 b/target/linux/mediatek/mt7629/config-6.1 index c0c501e59e..ad79b5ba9e 100644 --- a/target/linux/mediatek/mt7629/config-6.1 +++ b/target/linux/mediatek/mt7629/config-6.1 @@ -165,6 +165,7 @@ CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_IRQ_WORK=y # CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set CONFIG_LIBFDT=y +# CONFIG_LEDS_SMARTRG_LED is not set CONFIG_LOCK_DEBUGGING_SUPPORT=y CONFIG_LOCK_SPIN_ON_OWNER=y CONFIG_LZO_COMPRESS=y diff --git a/target/linux/mediatek/patches-5.15/950-smartrg-i2c-led-driver.patch b/target/linux/mediatek/patches-5.15/950-smartrg-i2c-led-driver.patch new file mode 100644 index 0000000000..9f7b4ef338 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/950-smartrg-i2c-led-driver.patch @@ -0,0 +1,34 @@ +--- + drivers/leds/Kconfig | 10 ++++++++++ + drivers/leds/Makefile | 1 + + 2 files changed, 11 insertions(+) + +--- a/drivers/leds/Kconfig ++++ b/drivers/leds/Kconfig +@@ -877,6 +877,16 @@ source "drivers/leds/blink/Kconfig" + comment "Flash and Torch LED drivers" + source "drivers/leds/flash/Kconfig" + ++config LEDS_SMARTRG_LED ++ tristate "LED support for Adtran SmartRG" ++ depends on LEDS_CLASS && I2C && OF ++ help ++ This option enables support for the Adtran SmartRG platform ++ system LED driver. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called leds-smartrg-system. ++ + comment "LED Triggers" + source "drivers/leds/trigger/Kconfig" + +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -77,6 +77,7 @@ obj-$(CONFIG_LEDS_PWM) += leds-pwm.o + obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o + obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o + obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o ++obj-$(CONFIG_LEDS_SMARTRG_LED) += leds-smartrg-system.o + obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o + obj-$(CONFIG_LEDS_SYSCON) += leds-syscon.o + obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o -- 2.30.2