summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/leds/Kconfig33
-rw-r--r--drivers/leds/Makefile2
-rw-r--r--drivers/leds/led-class-multicolor.c203
-rw-r--r--drivers/leds/led-class.c1
-rw-r--r--drivers/leds/led-core.c6
-rw-r--r--drivers/leds/led-triggers.c28
-rw-r--r--drivers/leds/leds-88pm860x.c14
-rw-r--r--drivers/leds/leds-bcm6328.c97
-rw-r--r--drivers/leds/leds-da903x.c14
-rw-r--r--drivers/leds/leds-gpio.c15
-rw-r--r--drivers/leds/leds-lm3532.c4
-rw-r--r--drivers/leds/leds-lm3533.c12
-rw-r--r--drivers/leds/leds-lm355x.c16
-rw-r--r--drivers/leds/leds-lm3601x.c2
-rw-r--r--drivers/leds/leds-lm36274.c17
-rw-r--r--drivers/leds/leds-lm3642.c9
-rw-r--r--drivers/leds/leds-lm3692x.c2
-rw-r--r--drivers/leds/leds-lm3697.c2
-rw-r--r--drivers/leds/leds-lp5521.c43
-rw-r--r--drivers/leds/leds-lp5523.c62
-rw-r--r--drivers/leds/leds-lp5562.c22
-rw-r--r--drivers/leds/leds-lp55xx-common.c239
-rw-r--r--drivers/leds/leds-lp55xx-common.h16
-rw-r--r--drivers/leds/leds-lp8501.c23
-rw-r--r--drivers/leds/leds-ns2.c9
-rw-r--r--drivers/leds/leds-pca955x.c2
-rw-r--r--drivers/leds/leds-turris-omnia.c295
-rw-r--r--drivers/leds/leds-wm831x-status.c14
-rw-r--r--drivers/leds/trigger/ledtrig-gpio.c3
-rw-r--r--drivers/leds/trigger/ledtrig-pattern.c6
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.brightness_set_blocking = lm355x_torch_brightness_set;
chip->cdev_torch.default_trigger = "torch";
- err