diff options
Diffstat (limited to 'drivers/leds')
30 files changed, 1001 insertions, 210 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index ed943140e1fd..1c181df24eae 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -30,6 +30,16 @@ config LEDS_CLASS_FLASH for the flash related features of a LED device. It can be built as a module. +config LEDS_CLASS_MULTICOLOR + tristate "LED Multicolor Class Support" + depends on LEDS_CLASS + help + This option enables the multicolor LED sysfs class in /sys/class/leds. + It wraps LED class and adds multicolor LED specific sysfs attributes + and kernel internal API to it. You'll need this to provide support + for multicolor LEDs that are grouped together. This class is not + intended for single color LEDs. It can be built as a module. + config LEDS_BRIGHTNESS_HW_CHANGED bool "LED Class brightness_hw_changed attribute support" depends on LEDS_CLASS @@ -166,6 +176,17 @@ config LEDS_EL15203000 To compile this driver as a module, choose M here: the module will be called leds-el15203000. +config LEDS_TURRIS_OMNIA + tristate "LED support for CZ.NIC's Turris Omnia" + depends on LEDS_CLASS_MULTICOLOR + depends on I2C + depends on MACH_ARMADA_38X || COMPILE_TEST + depends on OF + help + This option enables basic support for the LEDs found on the front + side of CZ.NIC's Turris Omnia router. There are 12 RGB LEDs on the + front panel. + config LEDS_LM3530 tristate "LCD Backlight driver for LM3530" depends on LEDS_CLASS @@ -376,7 +397,9 @@ config LEDS_LP3952 config LEDS_LP55XX_COMMON tristate "Common Driver for TI/National LP5521/5523/55231/5562/8501" - depends on LEDS_LP5521 || LEDS_LP5523 || LEDS_LP5562 || LEDS_LP8501 + depends on LEDS_CLASS_MULTICOLOR || !LEDS_CLASS_MULTICOLOR + depends on OF + depends on I2C select FW_LOADER select FW_LOADER_USER_HELPER help @@ -386,7 +409,7 @@ config LEDS_LP55XX_COMMON config LEDS_LP5521 tristate "LED Support for N.S. LP5521 LED driver chip" depends on LEDS_CLASS && I2C - select LEDS_LP55XX_COMMON + depends on LEDS_LP55XX_COMMON help If you say yes here you get support for the National Semiconductor LP5521 LED driver. It is 3 channel chip with programmable engines. @@ -396,7 +419,7 @@ config LEDS_LP5521 config LEDS_LP5523 tristate "LED Support for TI/National LP5523/55231 LED driver chip" depends on LEDS_CLASS && I2C - select LEDS_LP55XX_COMMON + depends on LEDS_LP55XX_COMMON help If you say yes here you get support for TI/National Semiconductor LP5523/55231 LED driver. @@ -407,7 +430,7 @@ config LEDS_LP5523 config LEDS_LP5562 tristate "LED Support for TI LP5562 LED driver chip" depends on LEDS_CLASS && I2C - select LEDS_LP55XX_COMMON + depends on LEDS_LP55XX_COMMON help If you say yes here you get support for TI LP5562 LED driver. It is 4 channels chip with programmable engines. @@ -417,7 +440,7 @@ config LEDS_LP5562 config LEDS_LP8501 tristate "LED Support for TI LP8501 LED driver chip" depends on LEDS_CLASS && I2C - select LEDS_LP55XX_COMMON + depends on LEDS_LP55XX_COMMON help If you say yes here you get support for TI LP8501 LED driver. It is 9 channel chip with programmable engines. diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index d6b8a792c936..c2c7d7ade0d0 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_NEW_LEDS) += led-core.o obj-$(CONFIG_LEDS_CLASS) += led-class.o obj-$(CONFIG_LEDS_CLASS_FLASH) += led-class-flash.o +obj-$(CONFIG_LEDS_CLASS_MULTICOLOR) += led-class-multicolor.o obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o # LED Platform Drivers (keep this sorted, M-| sort) @@ -86,6 +87,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o +obj-$(CONFIG_LEDS_TURRIS_OMNIA) += leds-turris-omnia.o obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o diff --git a/drivers/leds/led-class-multicolor.c b/drivers/leds/led-class-multicolor.c new file mode 100644 index 000000000000..e317408583df --- /dev/null +++ b/drivers/leds/led-class-multicolor.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-2.0 +// LED Multicolor class interface +// Copyright (C) 2019-20 Texas Instruments Incorporated - http://www.ti.com/ +// Author: Dan Murphy <dmurphy@ti.com> + +#include <linux/device.h> +#include <linux/init.h> +#include <linux/led-class-multicolor.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/uaccess.h> + +#include "leds.h" + +int led_mc_calc_color_components(struct led_classdev_mc *mcled_cdev, + enum led_brightness brightness) +{ + struct led_classdev *led_cdev = &mcled_cdev->led_cdev; + int i; + + for (i = 0; i < mcled_cdev->num_colors; i++) + mcled_cdev->subled_info[i].brightness = brightness * + mcled_cdev->subled_info[i].intensity / + led_cdev->max_brightness; + + return 0; +} +EXPORT_SYMBOL_GPL(led_mc_calc_color_components); + +static ssize_t multi_intensity_store(struct device *dev, + struct device_attribute *intensity_attr, + const char *buf, size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev); + int nrchars, offset = 0; + int intensity_value[LED_COLOR_ID_MAX]; + int i; + ssize_t ret; + + mutex_lock(&led_cdev->led_access); + + for (i = 0; i < mcled_cdev->num_colors; i++) { + ret = sscanf(buf + offset, "%i%n", + &intensity_value[i], &nrchars); + if (ret != 1) { + ret = -EINVAL; + goto err_out; + } + offset += nrchars; + } + + offset++; + if (offset < size) { + ret = -EINVAL; + goto err_out; + } + + for (i = 0; i < mcled_cdev->num_colors; i++) + mcled_cdev->subled_info[i].intensity = intensity_value[i]; + + led_set_brightness(led_cdev, led_cdev->brightness); + ret = size; +err_out: + mutex_unlock(&led_cdev->led_access); + return ret; +} + +static ssize_t multi_intensity_show(struct device *dev, + struct device_attribute *intensity_attr, + char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev); + int len = 0; + int i; + + for (i = 0; i < mcled_cdev->num_colors; i++) { + len += sprintf(buf + len, "%d", + mcled_cdev->subled_info[i].intensity); + if (i < mcled_cdev->num_colors - 1) + len += sprintf(buf + len, " "); + } + + buf[len++] = '\n'; + return len; +} +static DEVICE_ATTR_RW(multi_intensity); + +static ssize_t multi_index_show(struct device *dev, + struct device_attribute *multi_index_attr, + char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev); + int len = 0; + int index; + int i; + + for (i = 0; i < mcled_cdev->num_colors; i++) { + index = mcled_cdev->subled_info[i].color_index; + len += sprintf(buf + len, "%s", led_colors[index]); + if (i < mcled_cdev->num_colors - 1) + len += sprintf(buf + len, " "); + } + + buf[len++] = '\n'; + return len; +} +static DEVICE_ATTR_RO(multi_index); + +static struct attribute *led_multicolor_attrs[] = { + &dev_attr_multi_intensity.attr, + &dev_attr_multi_index.attr, + NULL, +}; +ATTRIBUTE_GROUPS(led_multicolor); + +int led_classdev_multicolor_register_ext(struct device *parent, + struct led_classdev_mc *mcled_cdev, + struct led_init_data *init_data) +{ + struct led_classdev *led_cdev; + + if (!mcled_cdev) + return -EINVAL; + + if (mcled_cdev->num_colors <= 0) + return -EINVAL; + + if (mcled_cdev->num_colors > LED_COLOR_ID_MAX) + return -EINVAL; + + led_cdev = &mcled_cdev->led_cdev; + mcled_cdev->led_cdev.groups = led_multicolor_groups; + + return led_classdev_register_ext(parent, led_cdev, init_data); +} +EXPORT_SYMBOL_GPL(led_classdev_multicolor_register_ext); + +void led_classdev_multicolor_unregister(struct led_classdev_mc *mcled_cdev) +{ + if (!mcled_cdev) + return; + + led_classdev_unregister(&mcled_cdev->led_cdev); +} +EXPORT_SYMBOL_GPL(led_classdev_multicolor_unregister); + +static void devm_led_classdev_multicolor_release(struct device *dev, void *res) +{ + led_classdev_multicolor_unregister(*(struct led_classdev_mc **)res); +} + +int devm_led_classdev_multicolor_register_ext(struct device *parent, + struct led_classdev_mc *mcled_cdev, + struct led_init_data *init_data) +{ + struct led_classdev_mc **dr; + int ret; + + dr = devres_alloc(devm_led_classdev_multicolor_release, + sizeof(*dr), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + ret = led_classdev_multicolor_register_ext(parent, mcled_cdev, + init_data); + if (ret) { + devres_free(dr); + return ret; + } + + *dr = mcled_cdev; + devres_add(parent, dr); + + return 0; +} +EXPORT_SYMBOL_GPL(devm_led_classdev_multicolor_register_ext); + +static int devm_led_classdev_multicolor_match(struct device *dev, + void *res, void *data) +{ + struct led_classdev_mc **p = res; + + if (WARN_ON(!p || !*p)) + return 0; + + return *p == data; +} + +void devm_led_classdev_multicolor_unregister(struct device *dev, + struct led_classdev_mc *mcled_cdev) +{ + WARN_ON(devres_release(dev, + devm_led_classdev_multicolor_release, + devm_led_classdev_multicolor_match, mcled_cdev)); +} +EXPORT_SYMBOL_GPL(devm_led_classdev_multicolor_unregister); + +MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); +MODULE_DESCRIPTION("Multicolor LED class interface"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 3363a6551a70..cc3929f858b6 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -173,6 +173,7 @@ void led_classdev_suspend(struct led_classdev *led_cdev) { led_cdev->flags |= LED_SUSPENDED; led_set_brightness_nopm(led_cdev, 0); + flush_work(&led_cdev->set_brightness_work); } EXPORT_SYMBOL_GPL(led_classdev_suspend); diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c index f1f718dbe0f8..c4e780bdb385 100644 --- a/drivers/leds/led-core.c +++ b/drivers/leds/led-core.c @@ -34,6 +34,8 @@ const char * const led_colors[LED_COLOR_ID_MAX] = { [LED_COLOR_ID_VIOLET] = "violet", [LED_COLOR_ID_YELLOW] = "yellow", [LED_COLOR_ID_IR] = "ir", + [LED_COLOR_ID_MULTI] = "multicolor", + [LED_COLOR_ID_RGB] = "rgb", }; EXPORT_SYMBOL_GPL(led_colors); @@ -423,6 +425,10 @@ int led_compose_name(struct device *dev, struct led_init_data *init_data, struct fwnode_handle *fwnode = init_data->fwnode; const char *devicename = init_data->devicename; + /* We want to label LEDs that can produce full range of colors + * as RGB, not multicolor */ + BUG_ON(props.color == LED_COLOR_ID_MULTI); + if (!led_classdev_name) return -EINVAL; diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index 79e30d2cb7a5..91da90cfb11d 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c @@ -27,6 +27,12 @@ LIST_HEAD(trigger_list); /* Used by LED Class */ +static inline bool +trigger_relevant(struct led_classdev *led_cdev, struct led_trigger *trig) +{ + return !trig->trigger_type || trig->trigger_type == led_cdev->trigger_type; +} + ssize_t led_trigger_write(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t pos, size_t count) @@ -50,7 +56,7 @@ ssize_t led_trigger_write(struct file *filp, struct kobject *kobj, down_read(&triggers_list_lock); list_for_each_entry(trig, &trigger_list, next_trig) { - if (sysfs_streq(buf, trig->name)) { + if (sysfs_streq(buf, trig->name) && trigger_relevant(led_cdev, trig)) { down_write(&led_cdev->trigger_lock); led_trigger_set(led_cdev, trig); up_write(&led_cdev->trigger_lock); @@ -93,8 +99,12 @@ static int led_trigger_format(char *buf, size_t size, led_cdev->trigger ? "none" : "[none]"); list_for_each_entry(trig, &trigger_list, next_trig) { - bool hit = led_cdev->trigger && - !strcmp(led_cdev->trigger->name, trig->name); + bool hit; + + if (!trigger_relevant(led_cdev, trig)) + continue; + + hit = led_cdev->trigger && !strcmp(led_cdev->trigger->name, trig->name); len += led_trigger_snprintf(buf + len, size - len, " %s%s%s", hit ? "[" : "", @@ -243,7 +253,8 @@ void led_trigger_set_default(struct led_classdev *led_cdev) down_read(&triggers_list_lock); down_write(&led_cdev->trigger_lock); list_for_each_entry(trig, &trigger_list, next_trig) { - if (!strcmp(led_cdev->default_trigger, trig->name)) { + if (!strcmp(led_cdev->default_trigger, trig->name) && + trigger_relevant(led_cdev, trig)) { led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER; led_trigger_set(led_cdev, trig); break; @@ -280,7 +291,9 @@ int led_trigger_register(struct led_trigger *trig) down_write(&triggers_list_lock); /* Make sure the trigger's name isn't already in use */ list_for_each_entry(_trig, &trigger_list, next_trig) { - if (!strcmp(_trig->name, trig->name)) { + if (!strcmp(_trig->name, trig->name) && + (trig->trigger_type == _trig->trigger_type || + !trig->trigger_type || !_trig->trigger_type)) { up_write(&triggers_list_lock); return -EEXIST; } @@ -294,7 +307,8 @@ int led_trigger_register(struct led_trigger *trig) list_for_each_entry(led_cdev, &leds_list, node) { down_write(&led_cdev->trigger_lock); if (!led_cdev->trigger && led_cdev->default_trigger && - !strcmp(led_cdev->default_trigger, trig->name)) { + !strcmp(led_cdev->default_trigger, trig->name) && + trigger_relevant(led_cdev, trig)) { led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER; led_trigger_set(led_cdev, trig); } @@ -358,7 +372,7 @@ int devm_led_trigger_register(struct device *dev, } EXPORT_SYMBOL_GPL(devm_led_trigger_register); -/* Simple LED Tigger Interface */ +/* Simple LED Trigger Interface */ void led_trigger_event(struct led_trigger *trig, enum led_brightness brightness) diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c index b3044c9a8120..465c3755cf2e 100644 --- a/drivers/leds/leds-88pm860x.c +++ b/drivers/leds/leds-88pm860x.c @@ -203,21 +203,33 @@ static int pm860x_led_probe(struct platform_device *pdev) data->cdev.brightness_set_blocking = pm860x_led_set; mutex_init(&data->lock); - ret = devm_led_classdev_register(chip->dev, &data->cdev); + ret = led_classdev_register(chip->dev, &data->cdev); if (ret < 0) { dev_err(&pdev->dev, "Failed to register LED: %d\n", ret); return ret; } pm860x_led_set(&data->cdev, 0); + + platform_set_drvdata(pdev, data); + return 0; } +static int pm860x_led_remove(struct platform_device *pdev) +{ + struct pm860x_led *data = platform_get_drvdata(pdev); + + led_classdev_unregister(&data->cdev); + + return 0; +} static struct platform_driver pm860x_led_driver = { .driver = { .name = "88pm860x-led", }, .probe = pm860x_led_probe, + .remove = pm860x_led_remove, }; module_platform_driver(pm860x_led_driver); diff --git a/drivers/leds/leds-bcm6328.c b/drivers/leds/leds-bcm6328.c index 42e1b7598c3a..bad7efb75112 100644 --- a/drivers/leds/leds-bcm6328.c +++ b/drivers/leds/leds-bcm6328.c @@ -24,12 +24,17 @@ #define BCM6328_LED_MAX_COUNT 24 #define BCM6328_LED_DEF_DELAY 500 -#define BCM6328_LED_INTERVAL_MS 20 -#define BCM6328_LED_INTV_MASK 0x3f -#define BCM6328_LED_FAST_INTV_SHIFT 6 -#define BCM6328_LED_FAST_INTV_MASK (BCM6328_LED_INTV_MASK << \ - BCM6328_LED_FAST_INTV_SHIFT) +#define BCM6328_LED_BLINK_DELAYS 2 +#define BCM6328_LED_BLINK_MS 20 + +#define BCM6328_LED_BLINK_MASK 0x3f +#define BCM6328_LED_BLINK1_SHIFT 0 +#define BCM6328_LED_BLINK1_MASK (BCM6328_LED_BLINK_MASK << \ + BCM6328_LED_BLINK1_SHIFT) +#define BCM6328_LED_BLINK2_SHIFT 6 +#define BCM6328_LED_BLINK2_MASK (BCM6328_LED_BLINK_MASK << \ + BCM6328_LED_BLINK2_SHIFT) #define BCM6328_SERIAL_LED_EN BIT(12) #define BCM6328_SERIAL_LED_MUX BIT(13) #define BCM6328_SERIAL_LED_CLK_NPOL BIT(14) @@ -45,8 +50,8 @@ #define BCM6328_LED_MODE_MASK 3 #define BCM6328_LED_MODE_ON 0 -#define BCM6328_LED_MODE_FAST 1 -#define BCM6328_LED_MODE_BLINK 2 +#define BCM6328_LED_MODE_BLINK1 1 +#define BCM6328_LED_MODE_BLINK2 2 #define BCM6328_LED_MODE_OFF 3 #define BCM6328_LED_SHIFT(X) ((X) << 1) @@ -127,12 +132,18 @@ static void bcm6328_led_set(struct led_classdev *led_cdev, unsigned long flags; spin_lock_irqsave(led->lock, flags); - *(led->blink_leds) &= ~BIT(led->pin); + + /* Remove LED from cached HW blinking intervals */ + led->blink_leds[0] &= ~BIT(led->pin); + led->blink_leds[1] &= ~BIT(led->pin); + + /* Set LED on/off */ if ((led->active_low && value == LED_OFF) || (!led->active_low && value != LED_OFF)) bcm6328_led_mode(led, BCM6328_LED_MODE_ON); else bcm6328_led_mode(led, BCM6328_LED_MODE_OFF); + spin_unlock_irqrestore(led->lock, flags); } @@ -140,8 +151,8 @@ static unsigned long bcm6328_blink_delay(unsigned long delay) { unsigned long bcm6328_delay; - bcm6328_delay = delay + BCM6328_LED_INTERVAL_MS / 2; - bcm6328_delay = bcm6328_delay / BCM6328_LED_INTERVAL_MS; + bcm6328_delay = delay + BCM6328_LED_BLINK_MS / 2; + bcm6328_delay = bcm6328_delay / BCM6328_LED_BLINK_MS; if (bcm6328_delay == 0) bcm6328_delay = 1; @@ -168,28 +179,68 @@ static int bcm6328_blink_set(struct led_classdev *led_cdev, return -EINVAL; } - if (delay > BCM6328_LED_INTV_MASK) { + if (delay > BCM6328_LED_BLINK_MASK) { dev_dbg(led_cdev->dev, "fallback to soft blinking (delay > %ums)\n", - BCM6328_LED_INTV_MASK * BCM6328_LED_INTERVAL_MS); + BCM6328_LED_BLINK_MASK * BCM6328_LED_BLINK_MS); return -EINVAL; } spin_lock_irqsave(led->lock, flags); - if (*(led->blink_leds) == 0 || - *(led->blink_leds) == BIT(led->pin) || - *(led->blink_delay) == delay) { + /* + * Check if any of the two configurable HW blinking intervals is + * available: + * 1. No LEDs assigned to the HW blinking interval. + * 2. Only this LED is assigned to the HW blinking interval. + * 3. LEDs with the same delay assigned. + */ + if (led->blink_leds[0] == 0 || + led->blink_leds[0] == BIT(led->pin) || + led->blink_delay[0] == delay) { unsigned long val; - *(led->blink_leds) |= BIT(led->pin); - *(led->blink_delay) = delay; + /* Add LED to the first HW blinking interval cache */ + led->blink_leds[0] |= BIT(led->pin); + + /* Remove LED from the second HW blinking interval cache */ + led->blink_leds[1] &= ~BIT(led->pin); + /* Cache first HW blinking interval delay */ + led->blink_delay[0] = delay; + + /* Update the delay for the first HW blinking interval */ val = bcm6328_led_read(led->mem + BCM6328_REG_INIT); - val &= ~BCM6328_LED_FAST_INTV_MASK; - val |= (delay << BCM6328_LED_FAST_INTV_SHIFT); + val &= ~BCM6328_LED_BLINK1_MASK; + val |= (delay << BCM6328_LED_BLINK1_SHIFT); bcm6328_led_write(led->mem + BCM6328_REG_INIT, val); - bcm6328_led_mode(led, BCM6328_LED_MODE_BLINK); + /* Set the LED to first HW blinking interval */ + bcm6328_led_mode(led, BCM6328_LED_MODE_BLINK1); + + rc = 0; + } else if (led->blink_leds[1] == 0 || + led->blink_leds[1] == BIT(led->pin) || + led->blink_delay[1] == delay) { + unsigned long val; + + /* Remove LED from the first HW blinking interval */ + led->blink_leds[0] &= ~BIT(led->pin); + + /* Add LED to the second HW blinking interval */ + led->blink_leds[1] |= BIT(led->pin); + + /* Cache second HW blinking interval delay */ + led->blink_delay[1] = delay; + + /* Update the delay for the second HW blinking interval */ + val = bcm6328_led_read(led->mem + BCM6328_REG_INIT); + val &= ~BCM6328_LED_BLINK2_MASK; + val |= (delay << BCM6328_LED_BLINK2_SHIFT); + bcm6328_led_write(led->mem + BCM6328_REG_INIT, val); + + /* Set the LED to second HW blinking interval */ + bcm6328_led_mode(led, BCM6328_LED_MODE_BLINK2); + rc = 0; } else { dev_dbg(led_cdev->dev, @@ -358,11 +409,13 @@ static int bcm6328_leds_probe(struct platform_device *pdev) if (!lock) return -ENOMEM; - blink_leds = devm_kzalloc(dev, sizeof(*blink_leds), GFP_KERNEL); + blink_leds = devm_kcalloc(dev, BCM6328_LED_BLINK_DELAYS, + sizeof(*blink_leds), GFP_KERNEL); if (!blink_leds) return -ENOMEM; - blink_delay = devm_kzalloc(dev, sizeof(*blink_delay), GFP_KERNEL); + blink_delay = devm_kcalloc(dev, BCM6328_LED_BLINK_DELAYS, + sizeof(*blink_delay), GFP_KERNEL); if (!blink_delay) return -ENOMEM; diff --git a/drivers/leds/leds-da903x.c b/drivers/leds/leds-da903x.c index ed1b303f699f..2b5fb00438a2 100644 --- a/drivers/leds/leds-da903x.c +++ b/drivers/leds/leds-da903x.c @@ -110,12 +110,23 @@ static int da903x_led_probe(struct platform_device *pdev) led->flags = pdata->flags; led->master = pdev->dev.parent; - ret = devm_led_classdev_register(led->master, &led->cdev); + ret = led_classdev_register(led->master, &led->cdev); if (ret) { dev_err(&pdev->dev, "failed to register LED %d\n", id); return ret; } + platform_set_drvdata(pdev, led); + + return 0; +} + +static int da903x_led_remove(struct platform_device *pdev) +{ + struct da903x_led *led = platform_get_drvdata(pdev); + + led_classdev_unregister(&led->cdev); + return 0; } @@ -124,6 +135,7 @@ static struct platform_driver da903x_led_driver = { .name = "da903x-led", }, .probe = da903x_led_probe, + .remove = da903x_led_remove, }; module_platform_driver(da903x_led_driver); diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index 2bf74595610f..cf84096d88ce 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -125,12 +125,6 @@ struct gpio_leds_priv { struct gpio_led_data leds[]; }; -static inline int sizeof_gpio_leds_priv(int num_leds) -{ - return sizeof(struct gpio_leds_priv) + - (sizeof(struct gpio_led_data) * num_leds); -} - static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -142,7 +136,7 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev) if (!count) return ERR_PTR(-ENODEV); - priv = devm_kzalloc(dev, sizeof_gpio_leds_priv(count), GFP_KERNEL); + priv = devm_kzalloc(dev, struct_size(priv, leds, count), GFP_KERNEL); if (!priv) return ERR_PTR(-ENOMEM); @@ -220,7 +214,7 @@ static struct gpio_desc *gpio_led_get_gpiod(struct device *dev, int idx, * device, this will hit the board file, if any and get * the GPIO from there. */ - gpiod = devm_gpiod_get_index(dev, NULL, idx, flags); + gpiod = devm_gpiod_get_index(dev, NULL, idx, GPIOD_OUT_LOW); if (!IS_ERR(gpiod)) { gpiod_set_consumer_name(gpiod, template->name); return gpiod; @@ -260,9 +254,8 @@ static int gpio_led_probe(struct platform_device *pdev) int i, ret = 0; if (pdata && pdata->num_leds) { - priv = devm_kzalloc(&pdev->dev, - sizeof_gpio_leds_priv(pdata->num_leds), - GFP_KERNEL); + priv = devm_kzalloc(&pdev->dev, struct_size(priv, leds, pdata->num_leds), + GFP_KERNEL); if (!priv) return -ENOMEM; diff --git a/drivers/leds/leds-lm3532.c b/drivers/leds/leds-lm3532.c index aa9bf8cda673..946ad67eaecb 100644 --- a/drivers/leds/leds-lm3532.c +++ b/drivers/leds/leds-lm3532.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 // TI LM3532 LED driver -// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ -// http://www.ti.com/lit/ds/symlink/lm3532.pdf +// Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/ +// https://www.ti.com/lit/ds/symlink/lm3532.pdf #include <linux/i2c.h> #include <linux/leds.h> diff --git a/drivers/leds/leds-lm3533.c b/drivers/leds/leds-lm3533.c index 9504ad405aef..b3edee703193 100644 --- a/drivers/leds/leds-lm3533.c +++ b/drivers/leds/leds-lm3533.c @@ -694,7 +694,7 @@ static int lm3533_led_probe(struct platform_device *pdev) platform_set_drvdata(pdev, led); - ret = devm_led_classdev_register(pdev->dev.parent, &led->cdev); + ret = led_classdev_register(pdev->dev.parent, &led->cdev); if (ret) { dev_err(&pdev->dev, "failed to register LED %d\n", pdev->id); return ret; @@ -704,13 +704,18 @@ static int lm3533_led_probe(struct platform_device *pdev) ret = lm3533_led_setup(led, pdata); if (ret) - return ret; + goto err_deregister; ret = lm3533_ctrlbank_enable(&led->cb); if (ret) - return ret; + goto err_deregister; return 0; + +err_deregister: + led_classdev_unregister(&led->cdev); + + return ret; } static int lm3533_led_remove(struct platform_device *pdev) @@ -720,6 +725,7 @@ static int lm3533_led_remove(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s\n", __func__); lm3533_ctrlbank_disable(&led->cb); + led_classdev_unregister(&led->cdev); return 0; } diff --git a/drivers/leds/leds-lm355x.c b/drivers/leds/leds-lm355x.c index 11ce05249751..1505521249b5 100644 --- a/drivers/leds/leds-lm355x.c +++ b/drivers/leds/leds-lm355x.c @@ -164,18 +164,19 @@ static int lm355x_chip_init(struct lm355x_chip_data *chip) /* input and output pins configuration */ switch (chip->type) { case CHIP_LM3554: - reg_val = pdata->pin_tx2 | pdata->ntc_pin; + reg_val = (u32)pdata->pin_tx2 | (u32)pdata->ntc_pin; ret = regmap_update_bits(chip->regmap, 0xE0, 0x28, reg_val); if (ret < 0) goto out; - reg_val = pdata->pass_mode; + reg_val = (u32)pdata->pass_mode; ret = regmap_update_bits(chip->regmap, 0xA0, 0x04, reg_val); if (ret < 0) goto out; break; case CHIP_LM3556: - reg_val = pdata->pin_tx2 | pdata->ntc_pin | pdata->pass_mode; + reg_val = (u32)pdata->pin_tx2 | (u32)pdata->ntc_pin | + (u32)pdata->pass_mode; ret = regmap_update_bits(chip->regmap, 0x0A, 0xC4, reg_val); if (ret < 0) goto out; @@ -452,8 +453,7 @@ static int lm355x_probe(struct i2c_client *client, chip->cdev_flash.max_brightness = 16; chip->cdev_flash.brightness_set_blocking = lm355x_strobe_brightness_set; chip->cdev_flash.default_trigger = "flash"; - err = led_classdev_register((struct device *) - &client->dev, &chip->cdev_flash); + err = led_classdev_register(&client->dev, &chip->cdev_flash); if (err < 0) goto err_out; /* torch */ @@ -461,8 +461,7 @@ static int lm355x_probe(struct i2c_client *client, chip->cdev_torch.max_brightness = 8; chip->cdev_torch. |