summaryrefslogtreecommitdiffstats
path: root/drivers/leds
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/leds')
-rw-r--r--drivers/leds/Kconfig33
-rw-r--r--drivers/leds/Makefile2
-rw-r--r--drivers/leds/led-class-flash.c59
-rw-r--r--drivers/leds/led-class.c161
-rw-r--r--drivers/leds/led-core.c136
-rw-r--r--drivers/leds/led-triggers.c95
-rw-r--r--drivers/leds/leds-aat1290.c16
-rw-r--r--drivers/leds/leds-an30259a.c36
-rw-r--r--drivers/leds/leds-apu.c157
-rw-r--r--drivers/leds/leds-as3645a.c77
-rw-r--r--drivers/leds/leds-bcm6328.c7
-rw-r--r--drivers/leds/leds-bcm6358.c7
-rw-r--r--drivers/leds/leds-bd2802.c27
-rw-r--r--drivers/leds/leds-cr0014114.c33
-rw-r--r--drivers/leds/leds-el15203000.c357
-rw-r--r--drivers/leds/leds-gpio.c36
-rw-r--r--drivers/leds/leds-is31fl319x.c3
-rw-r--r--drivers/leds/leds-is31fl32xx.c8
-rw-r--r--drivers/leds/leds-ktd2692.c4
-rw-r--r--drivers/leds/leds-lm3532.c149
-rw-r--r--drivers/leds/leds-lm3601x.c38
-rw-r--r--drivers/leds/leds-lm36274.c4
-rw-r--r--drivers/leds/leds-lm3642.c37
-rw-r--r--drivers/leds/leds-lm3692x.c225
-rw-r--r--drivers/leds/leds-lm3697.c5
-rw-r--r--drivers/leds/leds-lp5562.c6
-rw-r--r--drivers/leds/leds-lp8860.c35
-rw-r--r--drivers/leds/leds-lt3593.c20
-rw-r--r--drivers/leds/leds-max77650.c51
-rw-r--r--drivers/leds/leds-mlxreg.c4
-rw-r--r--drivers/leds/leds-netxbig.c76
-rw-r--r--drivers/leds/leds-ns2.c21
-rw-r--r--drivers/leds/leds-pca9532.c16
-rw-r--r--drivers/leds/leds-pca963x.c8
-rw-r--r--drivers/leds/leds-pwm.c11
-rw-r--r--drivers/leds/leds-rb532.c1
-rw-r--r--drivers/leds/leds-sc27xx-bltc.c22
-rw-r--r--drivers/leds/leds-syscon.c2
-rw-r--r--drivers/leds/leds-ti-lmu-common.c15
-rw-r--r--drivers/leds/leds-tlc591xx.c90
-rw-r--r--drivers/leds/leds-tps6105x.c89
-rw-r--r--drivers/leds/leds.h7
-rw-r--r--drivers/leds/trigger/ledtrig-activity.c14
-rw-r--r--drivers/leds/trigger/ledtrig-gpio.c12
-rw-r--r--drivers/leds/trigger/ledtrig-netdev.c5
-rw-r--r--drivers/leds/trigger/ledtrig-pattern.c4
46 files changed, 1510 insertions, 711 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index b0fdeef10bd9..d82f1dea3711 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -17,7 +17,7 @@ if NEW_LEDS
config LEDS_CLASS
tristate "LED Class Support"
help
- This option enables the led sysfs class in /sys/class/leds. You'll
+ This option enables the LED sysfs class in /sys/class/leds. You'll
need this to do anything useful with LEDs. If unsure, say N.
config LEDS_CLASS_FLASH
@@ -35,7 +35,7 @@ config LEDS_BRIGHTNESS_HW_CHANGED
depends on LEDS_CLASS
help
This option enables support for the brightness_hw_changed attribute
- for led sysfs class devices under /sys/class/leds.
+ for LED sysfs class devices under /sys/class/leds.
See Documentation/ABI/testing/sysfs-class-led for details.
@@ -74,9 +74,12 @@ config LEDS_APU
depends on LEDS_CLASS
depends on X86 && DMI
help
- This driver makes the PC Engines APU/APU2/APU3 front panel LEDs
+ This driver makes the PC Engines APU1 front panel LEDs
accessible from userspace programs through the LED subsystem.
+ If you're looking for APU2/3, use the pcengines-apu2 driver.
+ (symbol CONFIG_PCENGINES_APU2)
+
To compile this driver as a module, choose M here: the
module will be called leds-apu.
@@ -129,6 +132,19 @@ config LEDS_CR0014114
To compile this driver as a module, choose M here: the module
will be called leds-cr0014114.
+config LEDS_EL15203000
+ tristate "LED Support for Crane EL15203000"
+ depends on LEDS_CLASS
+ depends on SPI
+ depends on OF
+ help
+ This option enables support for EL15203000 LED Board
+ (aka RED LED board) which is widely used in coffee vending
+ machines produced by Crane Merchandising Systems.
+
+ To compile this driver as a module, choose M here: the module
+ will be called leds-el15203000.
+
config LEDS_LM3530
tristate "LCD Backlight driver for LM3530"
depends on LEDS_CLASS
@@ -587,6 +603,7 @@ config LEDS_NETXBIG
tristate "LED support for Big Network series LEDs"
depends on LEDS_CLASS
depends on MACH_KIRKWOOD
+ depends on OF_GPIO
default y
help
This option enables support for LEDs found on the LaCie 2Big
@@ -819,6 +836,16 @@ config LEDS_LM36274
Say Y to enable the LM36274 LED driver for TI LMU devices.
This supports the LED device LM36274.
+config LEDS_TPS6105X
+ tristate "LED support for TI TPS6105X"
+ depends on LEDS_CLASS
+ depends on TPS6105X
+ default y if TPS6105X
+ help
+ This driver supports TPS61050/TPS61052 LED chips.
+ It is a single boost converter primarily for white LEDs and
+ audio amplifiers.
+
comment "LED Triggers"
source "drivers/leds/trigger/Kconfig"
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 41fb073a39c1..d7e1107753fb 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -85,10 +85,12 @@ obj-$(CONFIG_LEDS_LM3601X) += leds-lm3601x.o
obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o
obj-$(CONFIG_LEDS_LM3697) += leds-lm3697.o
obj-$(CONFIG_LEDS_LM36274) += leds-lm36274.o
+obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o
# LED SPI Drivers
obj-$(CONFIG_LEDS_CR0014114) += leds-cr0014114.o
obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
+obj-$(CONFIG_LEDS_EL15203000) += leds-el15203000.o
# LED Userspace Drivers
obj-$(CONFIG_LEDS_USER) += uleds.o
diff --git a/drivers/leds/led-class-flash.c b/drivers/leds/led-class-flash.c
index 94980c654d89..6eeb9effcf65 100644
--- a/drivers/leds/led-class-flash.c
+++ b/drivers/leds/led-class-flash.c
@@ -282,8 +282,9 @@ static void led_flash_init_sysfs_groups(struct led_classdev_flash *fled_cdev)
led_cdev->groups = flash_groups;
}
-int led_classdev_flash_register(struct device *parent,
- struct led_classdev_flash *fled_cdev)
+int led_classdev_flash_register_ext(struct device *parent,
+ struct led_classdev_flash *fled_cdev,
+ struct led_init_data *init_data)
{
struct led_classdev *led_cdev;
const struct led_flash_ops *ops;
@@ -309,13 +310,13 @@ int led_classdev_flash_register(struct device *parent,
}
/* Register led class device */
- ret = led_classdev_register(parent, led_cdev);
+ ret = led_classdev_register_ext(parent, led_cdev, init_data);
if (ret < 0)
return ret;
return 0;
}
-EXPORT_SYMBOL_GPL(led_classdev_flash_register);
+EXPORT_SYMBOL_GPL(led_classdev_flash_register_ext);
void led_classdev_flash_unregister(struct led_classdev_flash *fled_cdev)
{
@@ -326,6 +327,56 @@ void led_classdev_flash_unregister(struct led_classdev_flash *fled_cdev)
}
EXPORT_SYMBOL_GPL(led_classdev_flash_unregister);
+static void devm_led_classdev_flash_release(struct device *dev, void *res)
+{
+ led_classdev_flash_unregister(*(struct led_classdev_flash **)res);
+}
+
+int devm_led_classdev_flash_register_ext(struct device *parent,
+ struct led_classdev_flash *fled_cdev,
+ struct led_init_data *init_data)
+{
+ struct led_classdev_flash **dr;
+ int ret;
+
+ dr = devres_alloc(devm_led_classdev_flash_release, sizeof(*dr),
+ GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ ret = led_classdev_flash_register_ext(parent, fled_cdev, init_data);
+ if (ret) {
+ devres_free(dr);
+ return ret;
+ }
+
+ *dr = fled_cdev;
+ devres_add(parent, dr);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(devm_led_classdev_flash_register_ext);
+
+static int devm_led_classdev_flash_match(struct device *dev,
+ void *res, void *data)
+{
+ struct led_classdev_flash **p = res;
+
+ if (WARN_ON(!p || !*p))
+ return 0;
+
+ return *p == data;
+}
+
+void devm_led_classdev_flash_unregister(struct device *dev,
+ struct led_classdev_flash *fled_cdev)
+{
+ WARN_ON(devres_release(dev,
+ devm_led_classdev_flash_release,
+ devm_led_classdev_flash_match, fled_cdev));
+}
+EXPORT_SYMBOL_GPL(devm_led_classdev_flash_unregister);
+
static void led_clamp_align(struct led_flash_setting *s)
{
u32 v, offset;
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 4793e77808e2..1fc40e8af75e 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -14,10 +14,12 @@
#include <linux/leds.h>
#include <linux/list.h>
#include <linux/module.h>
+#include <linux/property.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <uapi/linux/uleds.h>
+#include <linux/of.h>
#include "leds.h"
static struct class *leds_class;
@@ -73,13 +75,13 @@ static ssize_t max_brightness_show(struct device *dev,
static DEVICE_ATTR_RO(max_brightness);
#ifdef CONFIG_LEDS_TRIGGERS
-static DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
-static struct attribute *led_trigger_attrs[] = {
- &dev_attr_trigger.attr,
+static BIN_ATTR(trigger, 0644, led_trigger_read, led_trigger_write, 0);
+static struct bin_attribute *led_trigger_bin_attrs[] = {
+ &bin_attr_trigger,
NULL,
};
static const struct attribute_group led_trigger_group = {
- .attrs = led_trigger_attrs,
+ .bin_attrs = led_trigger_bin_attrs,
};
#endif
@@ -213,12 +215,97 @@ static int led_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(leds_class_dev_pm_ops, led_suspend, led_resume);
-static int match_name(struct device *dev, const void *data)
+/**
+ * of_led_get() - request a LED device via the LED framework
+ * @np: device node to get the LED device from
+ * @index: the index of the LED
+ *
+ * Returns the LED device parsed from the phandle specified in the "leds"
+ * property of a device tree node or a negative error-code on failure.
+ */
+struct led_classdev *of_led_get(struct device_node *np, int index)
{
- if (!dev_name(dev))
- return 0;
- return !strcmp(dev_name(dev), (char *)data);
+ struct device *led_dev;
+ struct led_classdev *led_cdev;
+ struct device_node *led_node;
+
+ led_node = of_parse_phandle(np, "leds", index);
+ if (!led_node)
+ return ERR_PTR(-ENOENT);
+
+ led_dev = class_find_device_by_of_node(leds_class, led_node);
+ of_node_put(led_node);
+
+ if (!led_dev)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ led_cdev = dev_get_drvdata(led_dev);
+
+ if (!try_module_get(led_cdev->dev->parent->driver->owner))
+ return ERR_PTR(-ENODEV);
+
+ return led_cdev;
+}
+EXPORT_SYMBOL_GPL(of_led_get);
+
+/**
+ * led_put() - release a LED device
+ * @led_cdev: LED device
+ */
+void led_put(struct led_classdev *led_cdev)
+{
+ module_put(led_cdev->dev->parent->driver->owner);
+}
+EXPORT_SYMBOL_GPL(led_put);
+
+static void devm_led_release(struct device *dev, void *res)
+{
+ struct led_classdev **p = res;
+
+ led_put(*p);
+}
+
+/**
+ * devm_of_led_get - Resource-managed request of a LED device
+ * @dev: LED consumer
+ * @index: index of the LED to obtain in the consumer
+ *
+ * The device node of the device is parse to find the request LED device.
+ * The LED device returned from this function is automatically released
+ * on driver detach.
+ *
+ * @return a pointer to a LED device or ERR_PTR(errno) on failure.
+ */
+struct led_classdev *__must_check devm_of_led_get(struct device *dev,
+ int index)
+{
+ struct led_classdev *led;
+ struct led_classdev **dr;
+
+ if (!dev)
+ return ERR_PTR(-EINVAL);
+
+ /* Not using device tree? */
+ if (!IS_ENABLED(CONFIG_OF) || !dev->of_node)
+ return ERR_PTR(-ENOTSUPP);
+
+ led = of_led_get(dev->of_node, index);
+ if (IS_ERR(led))
+ return led;
+
+ dr = devres_alloc(devm_led_release, sizeof(struct led_classdev *),
+ GFP_KERNEL);
+ if (!dr) {
+ led_put(led);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ *dr = led;
+ devres_add(dev, dr);
+
+ return led;
}
+EXPORT_SYMBOL_GPL(devm_of_led_get);
static int led_classdev_next_name(const char *init_name, char *name,
size_t len)
@@ -230,7 +317,7 @@ static int led_classdev_next_name(const char *init_name, char *name,
strlcpy(name, init_name, len);
while ((ret < len) &&
- (dev = class_find_device(leds_class, NULL, name, match_name))) {
+ (dev = class_find_device_by_name(leds_class, name))) {
put_device(dev);
ret = snprintf(name, len, "%s_%u", init_name, ++i);
}
@@ -242,31 +329,50 @@ static int led_classdev_next_name(const char *init_name, char *name,
}
/**
- * of_led_classdev_register - register a new object of led_classdev class.
+ * led_classdev_register_ext - register a new object of led_classdev class
+ * with init data.
*
* @parent: parent of LED device
* @led_cdev: the led_classdev structure for this device.
- * @np: DT node describing this LED
+ * @init_data: LED class device initialization data
*/
-int of_led_classdev_register(struct device *parent, struct device_node *np,
- struct led_classdev *led_cdev)
+int led_classdev_register_ext(struct device *parent,
+ struct led_classdev *led_cdev,
+ struct led_init_data *init_data)
{
- char name[LED_MAX_NAME_SIZE];
+ char composed_name[LED_MAX_NAME_SIZE];
+ char final_name[LED_MAX_NAME_SIZE];
+ const char *proposed_name = composed_name;
int ret;
- ret = led_classdev_next_name(led_cdev->name, name, sizeof(name));
+ if (init_data) {
+ if (init_data->devname_mandatory && !init_data->devicename) {
+ dev_err(parent, "Mandatory device name is missing");
+ return -EINVAL;
+ }
+ ret = led_compose_name(parent, init_data, composed_name);
+ if (ret < 0)
+ return ret;
+ } else {
+ proposed_name = led_cdev->name;
+ }
+
+ ret = led_classdev_next_name(proposed_name, final_name, sizeof(final_name));
if (ret < 0)
return ret;
mutex_init(&led_cdev->led_access);
mutex_lock(&led_cdev->led_access);
led_cdev->dev = device_create_with_groups(leds_class, parent, 0,
- led_cdev, led_cdev->groups, "%s", name);
+ led_cdev, led_cdev->groups, "%s", final_name);
if (IS_ERR(led_cdev->dev)) {
mutex_unlock(&led_cdev->led_access);
return PTR_ERR(led_cdev->dev);
}
- led_cdev->dev->of_node = np;
+ if (init_data && init_data->fwnode) {
+ led_cdev->dev->fwnode = init_data->fwnode;
+ led_cdev->dev->of_node = to_of_node(init_data->fwnode);
+ }
if (ret)
dev_warn(parent, "Led %s renamed to %s due to name collision",
@@ -276,6 +382,7 @@ int of_led_classdev_register(struct device *parent, struct device_node *np,
ret = led_add_brightness_hw_changed(led_cdev);
if (ret) {
device_unregister(led_cdev->dev);
+ led_cdev->dev = NULL;
mutex_unlock(&led_cdev->led_access);
return ret;
}
@@ -311,7 +418,7 @@ int of_led_classdev_register(struct device *parent, struct device_node *np,
return 0;
}
-EXPORT_SYMBOL_GPL(of_led_classdev_register);
+EXPORT_SYMBOL_GPL(led_classdev_register_ext);
/**
* led_classdev_unregister - unregisters a object of led_properties class.
@@ -321,6 +428,9 @@ EXPORT_SYMBOL_GPL(of_led_classdev_register);
*/
void led_classdev_unregister(struct led_classdev *led_cdev)
{
+ if (IS_ERR_OR_NULL(led_cdev->dev))
+ return;
+
#ifdef CONFIG_LEDS_TRIGGERS
down_write(&led_cdev->trigger_lock);
if (led_cdev->trigger)
@@ -356,14 +466,15 @@ static void devm_led_classdev_release(struct device *dev, void *res)
}
/**
- * devm_of_led_classdev_register - resource managed led_classdev_register()
+ * devm_led_classdev_register_ext - resource managed led_classdev_register_ext()
*
* @parent: parent of LED device
* @led_cdev: the led_classdev structure for this device.
+ * @init_data: LED class device initialization data
*/
-int devm_of_led_classdev_register(struct device *parent,
- struct device_node *np,
- struct led_classdev *led_cdev)
+int devm_led_classdev_register_ext(struct device *parent,
+ struct led_classdev *led_cdev,
+ struct led_init_data *init_data)
{
struct led_classdev **dr;
int rc;
@@ -372,7 +483,7 @@ int devm_of_led_classdev_register(struct device *parent,
if (!dr)
return -ENOMEM;
- rc = of_led_classdev_register(parent, np, led_cdev);
+ rc = led_classdev_register_ext(parent, led_cdev, init_data);
if (rc) {
devres_free(dr);
return rc;
@@ -383,11 +494,11 @@ int devm_of_led_classdev_register(struct device *parent,
return 0;
}
-EXPORT_SYMBOL_GPL(devm_of_led_classdev_register);
+EXPORT_SYMBOL_GPL(devm_led_classdev_register_ext);
static int devm_led_classdev_match(struct device *dev, void *res, void *data)
{
- struct led_cdev **p = res;
+ struct led_classdev **p = res;
if (WARN_ON(!p || !*p))
return 0;
diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
index 7107cd7e87cf..f1f718dbe0f8 100644
--- a/drivers/leds/led-core.c
+++ b/drivers/leds/led-core.c
@@ -13,8 +13,10 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
+#include <linux/property.h>
#include <linux/rwsem.h>
#include <linux/slab.h>
+#include <uapi/linux/uleds.h>
#include "leds.h"
DECLARE_RWSEM(leds_list_lock);
@@ -23,6 +25,18 @@ EXPORT_SYMBOL_GPL(leds_list_lock);
LIST_HEAD(leds_list);
EXPORT_SYMBOL_GPL(leds_list);
+const char * const led_colors[LED_COLOR_ID_MAX] = {
+ [LED_COLOR_ID_WHITE] = "white",
+ [LED_COLOR_ID_RED] = "red",
+ [LED_COLOR_ID_GREEN] = "green",
+ [LED_COLOR_ID_BLUE] = "blue",
+ [LED_COLOR_ID_AMBER] = "amber",
+ [LED_COLOR_ID_VIOLET] = "violet",
+ [LED_COLOR_ID_YELLOW] = "yellow",
+ [LED_COLOR_ID_IR] = "ir",
+};
+EXPORT_SYMBOL_GPL(led_colors);
+
static int __led_set_brightness(struct led_classdev *led_cdev,
enum led_brightness value)
{
@@ -310,14 +324,11 @@ EXPORT_SYMBOL_GPL(led_update_brightness);
u32 *led_get_default_pattern(struct led_classdev *led_cdev, unsigned int *size)
{
- struct device_node *np = dev_of_node(led_cdev->dev);
+ struct fwnode_handle *fwnode = led_cdev->dev->fwnode;
u32 *pattern;
int count;
- if (!np)
- return NULL;
-
- count = of_property_count_u32_elems(np, "led-pattern");
+ count = fwnode_property_count_u32(fwnode, "led-pattern");
if (count < 0)
return NULL;
@@ -325,7 +336,7 @@ u32 *led_get_default_pattern(struct led_classdev *led_cdev, unsigned int *size)
if (!pattern)
return NULL;
- if (of_property_read_u32_array(np, "led-pattern", pattern, count)) {
+ if (fwnode_property_read_u32_array(fwnode, "led-pattern", pattern, count)) {
kfree(pattern);
return NULL;
}
@@ -353,3 +364,116 @@ void led_sysfs_enable(struct led_classdev *led_cdev)
led_cdev->flags &= ~LED_SYSFS_DISABLE;
}
EXPORT_SYMBOL_GPL(led_sysfs_enable);
+
+static void led_parse_fwnode_props(struct device *dev,
+ struct fwnode_handle *fwnode,
+ struct led_properties *props)
+{
+ int ret;
+
+ if (!fwnode)
+ return;
+
+ if (fwnode_property_present(fwnode, "label")) {
+ ret = fwnode_property_read_string(fwnode, "label", &props->label);
+ if (ret)
+ dev_err(dev, "Error parsing 'label' property (%d)\n", ret);
+ return;
+ }
+
+ if (fwnode_property_present(fwnode, "color")) {
+ ret = fwnode_property_read_u32(fwnode, "color", &props->color);
+ if (ret)
+ dev_err(dev, "Error parsing 'color' property (%d)\n", ret);
+ else if (props->color >= LED_COLOR_ID_MAX)
+ dev_err(dev, "LED color identifier out of range\n");
+ else
+ props->color_present = true;
+ }
+
+
+ if (!fwnode_property_present(fwnode, "function"))
+ return;
+
+ ret = fwnode_property_read_string(fwnode, "function", &props->function);
+ if (ret) {
+ dev_err(dev,
+ "Error parsing 'function' property (%d)\n",
+ ret);
+ }
+
+ if (!fwnode_property_present(fwnode, "function-enumerator"))
+ return;
+
+ ret = fwnode_property_read_u32(fwnode, "function-enumerator",
+ &props->func_enum);
+ if (ret) {
+ dev_err(dev,
+ "Error parsing 'function-enumerator' property (%d)\n",
+ ret);
+ } else {
+ props->func_enum_present = true;
+ }
+}
+
+int led_compose_name(struct device *dev, struct led_init_data *init_data,
+ char *led_classdev_name)
+{
+ struct led_properties props = {};
+ struct fwnode_handle *fwnode = init_data->fwnode;
+ const char *devicename = init_data->devicename;
+
+ if (!led_classdev_name)
+ return -EINVAL;
+
+ led_parse_fwnode_props(dev, fwnode, &props);
+
+ if (props.label) {
+ /*
+ * If init_data.devicename is NULL, then it indicates that
+ * DT label should be used as-is for LED class device name.
+ * Otherwise the label is prepended with devicename to compose
+ * the final LED class device name.
+ */
+ if (!devicename) {
+ strscpy(led_classdev_name, props.label,
+ LED_MAX_NAME_SIZE);
+ } else {
+ snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s:%s",
+ devicename, props.label);
+ }
+ } else if (props.function || props.color_present) {
+ char tmp_buf[LED_MAX_NAME_SIZE];
+
+ if (props.func_enum_present) {
+ snprintf(tmp_buf, LED_MAX_NAME_SIZE, "%s:%s-%d",
+ props.color_present ? led_colors[props.color] : "",
+ props.function ?: "", props.func_enum);
+ } else {
+ snprintf(tmp_buf, LED_MAX_NAME_SIZE, "%s:%s",
+ props.color_present ? led_colors[props.color] : "",
+ props.function ?: "");
+ }
+ if (init_data->devname_mandatory) {
+ snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s:%s",
+ devicename, tmp_buf);
+ } else {
+ strscpy(led_classdev_name, tmp_buf, LED_MAX_NAME_SIZE);
+
+ }
+ } else if (init_data->default_label) {
+ if (!devicename) {
+ dev_err(dev, "Legacy LED naming requires devicename segment");
+ return -EINVAL;
+ }
+ snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s:%s",
+ devicename, init_data->default_label);
+ } else if (is_of_node(fwnode)) {
+ strscpy(led_classdev_name, to_of_node(fwnode)->name,
+ LED_MAX_NAME_SIZE);
+ } else
+ return -EINVAL;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(led_compose_name);
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index 8d11a5e23227..79e30d2cb7a5 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -16,6 +16,7 @@
#include <linux/rwsem.h>
#include <linux/leds.h>
#include <linux/slab.h>
+#include <linux/mm.h>
#include "leds.h"
/*
@@ -26,9 +27,11 @@ LIST_HEAD(trigger_list);
/* Used by LED Class */
-ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+ssize_t led_trigger_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t pos, size_t count)
{
+ struct device *dev = kobj_to_dev(kobj);
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_trigger *trig;
int ret = count;
@@ -64,39 +67,82 @@ unlock:
mutex_unlock(&led_cdev->led_access);
return ret;
}
-EXPORT_SYMBOL_GPL(led_trigger_store);
+EXPORT_SYMBOL_GPL(led_trigger_write);
-ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
- char *buf)
+__printf(3, 4)
+static int led_trigger_snprintf(char *buf, ssize_t size, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ if (size <= 0)
+ i = vsnprintf(NULL, 0, fmt, args);
+ else
+ i = vscnprintf(buf, size, fmt, args);
+ va_end(args);
+
+ return i;
+}
+
+static int led_trigger_format(char *buf, size_t size,
+ struct led_classdev *led_cdev)
{
- struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_trigger *trig;
- int len = 0;
+ int len = led_trigger_snprintf(buf, size, "%s",
+ 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);
+
+ len += led_trigger_snprintf(buf + len, size - len,
+ " %s%s%s", hit ? "[" : "",
+ trig->name, hit ? "]" : "");
+ }
+
+ len += led_trigger_snprintf(buf + len, size - len, "\n");
+
+ return len;
+}
+
+/*
+ * It was stupid to create 10000 cpu triggers, but we are stuck with it now.
+ * Don't make that mistake again. We work around it here by creating binary
+ * attribute, which is not limited by length. This is _not_ good design, do not
+ * copy it.
+ */
+ssize_t led_trigger_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t pos, size_t count)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ void *data;
+ int len;
down_read(&triggers_list_lock);
down_read(&led_cdev->trigger_lock);
- if (!led_cdev->trigger)
- len += scnprintf(buf+len, PAGE_SIZE - len, "[none] ");
- else
- len += scnprintf(buf+len, PAGE_SIZE - len, "none ");
-
- list_for_each_entry(trig, &trigger_list, next_trig) {
- if (led_cdev->trigger && !strcmp(led_cdev->trigger->name,
- trig->name))
- len += scnprintf(buf+len, PAGE_SIZE - len, "[%s] ",
- trig->name);
- else
- len += scnprintf(buf+len, PAGE_SIZE - len, "%s ",
- trig->name);
+ len = led_trigger_format(NULL, 0, led_cdev);
+ data = kvmalloc(len + 1, GFP_KERNEL);
+ if (!data) {
+ up_read(&led_cdev->trigger_lock);
+ up_read(&triggers_list_lock);
+ return -ENOMEM;
}
+ len = led_trigger_format(data, len + 1, led_cdev);
+
up_read(&led_cdev->trigger_lock);
up_read(&triggers_list_lock);
- len += scnprintf(len+buf, PAGE_SIZE - len, "\n");
+ len = memory_read_from_buffer(buf, count, &pos, data, len);
+
+ kvfree(data);
+
return len;
}
-EXPORT_SYMBOL_GPL(led_trigger_show);
+EXPORT_SYMBOL_GPL(led_trigger_read);
/* Caller must ensure led_cdev->trigger_lock held */
int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
@@ -167,12 +213,13 @@ err_add_groups:
trig->deactivate(led_cdev);
err_activate:
- led_cdev->trigger = NULL;
- led_cdev->trigger_data = NULL;
write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags);
list_del(&led_cdev->trig_list);
write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock, flags);
+ led_cdev->trigger = NULL;
+ led_cdev->trigger_data = NULL;
led_set_brightness(led_cdev, LED_OFF);
+ kfree(event);
return ret;
}
diff --git a/drivers/leds/leds-aat1290.c b/drivers/leds/leds-aat1290.c
index bf26f5bed1f0..5a0fe7b7b8bc 100644
--- a/drivers/leds/leds-aat1290.c
+++ b/drivers/leds/leds-aat1290.c
@@ -42,6 +42,8 @@
#define AAT1290_FLASH_TM_NUM_LEVELS 16
#define AAT1290_MM_CURRENT_SCALE_SIZE 15
+#define AAT1290_NAME "aat1290"
+
struct aat1290_led_config_data {
/* maximum LED current in movie mode */
@@ -75,7 +77,6 @@ struct aat1290_led {
int *mm_current_scale;
/* device mode */
bool movie_mode;
-
/* brightness cache */
unsigned int torch_brightness;
};
@@ -215,7 +216,6 @@ static int aat1290_led_parse_dt(struct aat1290_led *led,
struct aat1290_led_config_data *cfg,
struct device_node **sub_node)
{
- struct led_classdev *led_cdev = &led->fled_cdev.led_cdev;
struct device *dev = &led->pdev->dev;
struct device_node *child_node;
#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
@@ -254,9 +254,6 @@ static int aat1290_led_parse_dt(struct aat1290_led *led,
return -EINVAL;
}
- led_cdev->name = of_get_property(child_node, "label", NULL) ? :
- child_node->name;
-
ret = of_property_read_u32(child_node, "led-max-microamp",
&cfg->max_mm_current);
/*
@@ -428,7 +425,7 @@ static void aat1290_init_v4l2_flash_config(struct aat1290_led *led,
struct led_classdev *led_cdev = &led->fled_cdev.led_cdev;
struct led_flash_setting *s;
- strlcpy(v4l2_sd_cfg->dev_name, led_cdev->name,
+ strlcpy(v4l2_sd_cfg->dev_name, led_cdev->dev->kobj.name,
sizeof(v4l2_sd_cfg->dev_name));
s = &v4l2_sd_cfg->intensity;
@@ -466,6 +463,7 @@ static int aat1290_led_probe(struct platform_device *pdev)
struct aat1290_led *led;
struct led_classdev *led_cdev;
struct led_classdev_flash *fled_cdev;
+ struct led_init_data init_data = {};
struct aat1290_led_config_data led_cfg = {};
struct v4l2_flash_config v4l2_sd_cfg = {};
int ret;
@@ -494,8 +492,12 @@ static int aat1290_led_probe(struct platform_device *pdev)
aat1290_init_flash_timeout(led, &led_cfg);
+ init_data.fwnode = of_fwnode_handle(sub_node);
+ init_data.devicename = AAT1290_NAME;
+
/* Register LED Flash class device */
- ret = led_classdev_flash_register(&pdev->dev, fled_cdev);
+ ret = led_classdev_flash_register_ext(&pdev->dev, fled_cdev,
+ &init_data);
if (ret < 0)
goto err_flash_register;
diff --git a/drivers/leds/leds-an30259a.c b/drivers/leds/leds-an30259a.c
index 1c1f0c8c56f4..82350a28a564 100644
--- a/drivers/leds/leds-an30259a.c
+++ b/drivers/leds/leds-an30259a.c
@@ -13,7 +13,6 @@
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/regmap.h>
-#include <uapi/linux/uleds.h>
#define AN30259A_MAX_LEDS 3
@@ -54,6 +53,8 @@
#define AN30259A_BLINK_MAX_TIME 7500 /* ms */
#define AN30259A_SLOPE_RESOLUTION 500 /* ms */
+#define AN30259A_NAME "an30259a"
+
#define STATE_OFF 0
#define STATE_KEEP 1
#define STATE_ON 2
@@ -62,11 +63,11 @@ struct an30259a;
struct an30259a_led {
struct an30259a *chip;
+ struct fwnode_handle *fwnode;
struct led_classdev cdev;
u32 num;
u32 default_state;
bool sloping;
- char label[LED_MAX_NAME_SIZE];
};
struct an30259a {
@@ -226,14 +227,7 @@ static int an30259a_dt_init(struct i2c_client *client,
led->num = source;
led->chip = chip;
-
- if (of_property_read_string(child, "label", &str))
- snprintf(led->label, sizeof(led->label), "an30259a::");
- else
- snprintf(led->label, sizeof(led->label), "an30259a:%s",
- str);
-
- led->cdev.name = led->label;
+ led->fwnode = of_fwnode_handle(child);
if (!of_property_read_string(child, "default-state", &str)) {
if (!strcmp(str, "on"))
@@ -311,14 +305,28 @@ static int an30259a_probe(struct i2c_client *client)
chip->regmap = devm_regmap_init_i2c(client, &an30259a_regmap_config);
+ if (IS_ERR(chip->regmap)) {
+ err = PTR_ERR(chip->regmap);
+ dev_err(&client->dev, "Failed to allocate register map: %d\n",
+ err);
+ goto exit;
+ }
+
for (i = 0; i < chip->num_leds; i++) {
+ struct led_init_data init_data = {};
+
an30259a_init_default_state(&chip->leds[i]);
chip->leds[i].cdev.brightness_set_blocking =
an30259a_brightness_set;
chip->leds[i].cdev.blink_set = an30259a_blink_set;
- err = devm_led_classdev_register(&client->dev,
- &chip->leds[i].cdev);
+ init_data.fwnode = chip->leds[i].fwnode;
+ init_data.devicename = AN30259A_NAME;
+ init_data.default_label = ":";
+
+ err = devm_led_classdev_register_ext(&client->dev,
+ &chip->leds[i].cdev,
+ &init_data);
if (err < 0)
goto exit;
}
@@ -353,7 +361,7 @@ MODULE_DEVICE_TABLE(i2c, an30259a_id);
static struct i2c_driver an30259a_driver = {
.driver = {
- .name = "leds-an32059a",
+ .name = "leds-an30259a",
.of_match_table = of_match_ptr(an30259a_match_table),
},
.probe_new = an30259a_probe,
@@ -364,5 +372,5 @@ static struct i2c_driver an30259a_driver = {
module_i2c_driver(an30259a_driver);
MODULE_AUTHOR("Simon Shields <simon@lineageos.org>");
-MODULE_DESCRIPTION("AN32059A LED driver");
+MODULE_DESCRIPTION("AN30259A LED driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds-apu.c b/drivers/leds/leds-apu.c
index 8d42e46e2de3..7fd557aceff6 100644
--- a/drivers/leds/leds-apu.c
+++ b/drivers/leds/leds-apu.c
@@ -31,6 +31,8 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/dmi.h>
#include <linux/err.h>
#include <linux/init.h>
@@ -47,12 +49,6 @@
#define APU1_NUM_GPIO 3
#define APU1_IOSIZE sizeof(u8)
-#define APU2_FCH_ACPI_MMIO_BASE 0xFED80000
-#define APU2_FCH_GPIO_BASE (APU2_FCH_ACPI_MMIO_BASE + 0x1500)
-#define APU2_GPIO_BIT_WRITE 22
-#define APU2_APU2_NUM_GPIO 4
-#define APU2_IOSIZE sizeof(u32)
-
/* LED access parameters */
struct apu_param {
void __iomem *addr; /* for ioread/iowrite */
@@ -72,19 +68,9 @@ struct apu_led_profile {
unsigned long offset; /* for devm_ioremap */
};
-/* Supported platform types */
-enum apu_led_platform_types {
- APU1_LED_PLATFORM,
- APU2_LED_PLATFORM,
-};
-
struct apu_led_pdata {
struct platform_device *pdev;
struct apu_led_priv *pled;
- const struct apu_led_profile *profile;
- enum apu_led_platform_types platform;
- int num_led_instances;
- int iosize; /* for devm_ioremap() */
spinlock_t lock;
};
@@ -96,19 +82,6 @@ static const struct apu_led_profile apu1_led_profile[] = {
{ "apu:green:3", LED_OFF, APU1_FCH_GPIO_BASE + 2 * APU1_IOSIZE },
};
-static const struct apu_led_profile apu2_led_profile[] = {
- { "apu2:green:1", LED_ON, APU2_FCH_GPIO_BASE + 68 * APU2_IOSIZE },
- { "apu2:green:2", LED_OFF, APU2_FCH_GPIO_BASE + 69 * APU2_IOSIZE },
- { "apu2:green:3", LED_OFF, APU2_FCH_GPIO_BASE + 70 * APU2_IOSIZE },
-};
-
-/* Same as apu2_led_profile, but with "3" in the LED names. */
-static const struct apu_led_profile apu3_led_profile[] = {
- { "apu3:green:1", LED_ON, APU2_FCH_GPIO_BASE + 68 * APU2_IOSIZE },
- { "apu3:green:2", LED_OFF, APU2_FCH_GPIO_BASE + 69 * APU2_IOSIZE },
- { "apu3:green:3", LED_OFF, APU2_FCH_GPIO_BASE + 70 * APU2_IOSIZE },
-};
-
static const struct dmi_system_id apu_led_dmi_table[] __initconst = {
{
.ident = "apu",
@@ -117,54 +90,6 @@ static const struct dmi_system_id apu_led_dmi_table[] __initconst = {
DMI_MATCH(DMI_PRODUCT_NAME, "APU")
}
},
- /* PC Engines APU2 with "Legacy" bios < 4.0.8 */
- {
- .ident = "apu2",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
- DMI_MATCH(DMI_BOARD_NAME, "APU2")
- }
- },
- /* PC Engines APU2 with "Legacy" bios >= 4.0.8 */
- {
- .ident = "apu2",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
- DMI_MATCH(DMI_BOARD_NAME, "apu2")
- }
- },
- /* PC Engines APU2 with "Mainline" bios */
- {
- .ident = "apu2",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
- DMI_MATCH(DMI_BOARD_NAME, "PC Engines apu2")
- }
- },
- /* PC Engines APU3 with "Legacy" bios < 4.0.8 */
- {
- .ident = "apu3",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
- DMI_MATCH(DMI_BOARD_NAME, "APU3")
- }
- },
- /* PC Engines APU3 with "Legacy" bios >= 4.0.8 */
- {
- .ident = "apu3",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
- DMI_MATCH(DMI_BOARD_NAME, "apu3")
- }
- },
- /* PC Engines APU2 with "Mainline" bios */
- {
- .ident = "apu3",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
- DMI_MATCH(DMI_BOARD_NAME, "PC Engines apu3")
- }
- },
{}
};
MODULE_DEVICE_TABLE(dmi, apu_led_dmi_table);
@@ -178,52 +103,30 @@ static void apu1_led_brightness_set(struct led_classdev *led, enum led_brightnes
spin_unlock(&apu_led->lock);
}
-static void apu2_led_brightness_set(struct led_classdev *led, enum led_brightness value)
-{
- struct apu_led_priv *pled = cdev_to_priv(led);
- u32 value_new;
-
- spin_lock(&apu_led->lock);
-
- value_new = ioread32(pled->param.addr);
-
- if (value)
- value_new &= ~BIT(APU2_GPIO_BIT_WRITE);
- else
- value_new |= BIT(APU2_GPIO_BIT_WRITE);
-
- iowrite32(value_new, pled->param.addr);
-
- spin_unlock(&apu_led->lock);
-}
-
static int apu_led_config(struct device *dev, struct apu_led_pdata *apuld)
{
int i;
int err;
apu_led->pled = devm_kcalloc(dev,
- apu_led->num_led_instances, sizeof(struct apu_led_priv),
+ ARRAY_SIZE(apu1_led_profile), sizeof(struct apu_led_priv),
GFP_KERNEL);
if (!apu_led->pled)
return -ENOMEM;
- for (i = 0; i < apu_led->num_led_instances; i++) {
+ for (i = 0; i < ARRAY_SIZE(apu1_led_profile); i++) {
struct apu_led_priv *pled = &apu_led->pled[i];
struct led_classdev *led_cdev = &pled->cdev;
- led_cdev->name = apu_led->profile[i].name;
- led_cdev->brightness = apu_led->profile[i].brightness;
+ led_cdev->name = apu1_led_profile[i].name;
+ led_cdev->brightness = apu1_led_profile[i].brightness;
led_cdev->max_brightness = 1;
led_cdev->flags = LED_CORE_SUSPENDRESUME;
- if (apu_led->platform == APU1_LED_PLATFORM)
- led_cdev->brightness_set = apu1_led_brightness_set;
- else if (apu_led->platform == APU2_LED_PLATFORM)
- led_cdev->brightness_set = apu2_led_brightness_set;
+ led_cdev->brightness_set = apu1_led_brightness_set;
pled->param.addr = devm_ioremap(dev,
- apu_led->profile[i].offset, apu_led->iosize);
+ apu1_led_profile[i].offset, APU1_IOSIZE);
if (!pled->param.addr) {
err = -ENOMEM;
goto error;
@@ -233,7 +136,7 @@ static int apu_led_config(struct device *dev, struct apu_led_pdata *apuld)
if (err)
goto error;
- led_cdev->brightness_set(led_cdev, apu_led->profile[i].brightness);
+ apu1_led_brightness_set(led_cdev, apu1_led_profile[i].brightness);
}
return 0;
@@ -254,28 +157,6 @@ static int __init apu_led_probe(struct platform_device *pdev)
apu_led->pdev = pdev;
- if (dmi_match(DMI_PRODUCT_NAME, "APU")) {
- apu_led->profile = apu1_led_profile;
- apu_led->platform = APU1_LED_PLATFORM;
- apu_led->num_led_instances = ARRAY_SIZE(apu1_led_profile);
- apu_led->iosize = APU1_IOSIZE;
- } else if (dmi_match(DMI_BOARD_NAME, "APU2") ||
- dmi_match(DMI_BOARD_NAME, "apu2") ||
- dmi_match(DMI_BOARD_NAME, "PC Engines apu2")) {
- apu_led->profile = apu2_led_profile;
- apu_led->platform = APU2_LED_PLATFORM;
- apu_led->num_led_instances = ARRAY_SIZE(apu2_led_profile);
- apu_led->iosize = APU2_IOSIZE;
- } else if (dmi_match(DMI_BOARD_NAME, "APU3") ||
- dmi_match(DMI_BOARD_NAME, "apu3") ||
- dmi_match(DMI_BOARD_NAME, "PC Engines apu3")) {
- apu_led->profile = apu3_led_profile;
- /* Otherwise identical to APU2. */
- apu_led->platform = APU2_LED_PLATFORM;
- apu_led->num_led_instances = ARRAY_SIZE(apu3_led_profile);
- apu_led->iosize = APU2_IOSIZE;
- }
-
spin_lock_init(&apu_led->lock);
return apu_led_config(&pdev->dev, apu_led);
}
@@ -291,19 +172,9 @@ static int __init apu_led_init(void)
struct platform_device *pdev;
int err;
- if (!dmi_match(DMI_SYS_VENDOR, "PC Engines")) {
- pr_err("No PC Engines board detected\n");
- return -ENODEV;
- }
- if (!(dmi_match(DMI_PRODUCT_NAME, "APU") ||
- dmi_match(DMI_PRODUCT_NAME, "APU2") ||
- dmi_match(DMI_PRODUCT_NAME, "apu2") ||
- dmi_match(DMI_PRODUCT_NAME, "PC Engines apu2") ||
- dmi_match(DMI_PRODUCT_NAME, "APU3") ||
- dmi_match(DMI_PRODUCT_NAME, "apu3") ||
- dmi_match(DMI_PRODUCT_NAME, "PC Engines apu3"))) {
- pr_err("Unknown PC Engines board: %s\n",
- dmi_get_system_info(DMI_PRODUCT_NAME));
+ if (!(dmi_match(DMI_SYS_VENDOR, "PC Engines") &&
+ dmi_match(DMI_PRODUCT_NAME, "APU"))) {
+ pr_err("No PC Engines APUv1 board detected. For APUv2,3 support, enable CONFIG_PCENGINES_APU2\n");
return -ENODEV;
}
@@ -326,7 +197,7 @@ static void __exit apu_led_exit(void)
{
int i;
- for (i = 0; i < apu_led->num_led_instances; i++)
+ for (i = 0; i < ARRAY_SIZE(apu1_led_profile); i++)
led_classdev_unregister(&apu_led->pled[i].cdev);
platform_device_unregister(apu_led->pdev);
@@ -337,6 +208,6 @@ module_init(apu_led_init);
module_exit(apu_led_exit);
MODULE_AUTHOR("Alan Mizrahi");
-MODULE_DESCRIPTION("PC Engines APU family LED driver");
+MODULE_DESCRIPTION("PC Engines APU1 front LED driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:leds_apu");
diff --git a/drivers/leds/leds-as3645a.c b/drivers/leds/leds-as3645a.c
index 14ab6b0e4de9..e8922fa03379 100644
--- a/drivers/leds/leds-as3645a.c
+++ b/drivers/leds/leds-as3645a.c
@@ -124,11 +124,6 @@ struct as3645a_config {
u32 peak;
};
-struct as3645a_names {
- char flash[32];
- char indicator[32];
-};
-
struct as3645a {
struct i2c_client *client;
@@ -484,12 +479,10 @@ static int as3645a_detect(struct as3645a *flash)
}
static int as3645a_parse_node(struct as3645a *flash,
- struct as3645a_names *names,
struct fwnode_handle *fwnode)
{
struct as3645a_config *cfg = &flash->cfg;
struct fwnode_handle *child;
- const char *name;
int rval;
fwnode_for_each_child_node(fwnode, child) {
@@ -500,16 +493,17 @@ static int as3645a_parse_node(struct as3645a *flash,
switch (id) {
case AS_LED_FLASH:
flash->flash_node = child;
+ fwnode_handle_get(child);
break;
case AS_LED_INDICATOR:
flash->indicator_node = child;
+ fwnode_handle_get(child);
break;
default:
dev_warn(&flash->client->dev,
"unknown LED %u encountered, ignoring\n", id);
break;
}
- fwnode_handle_get(child);
}
if (!flash->flash_node) {
@@ -517,17 +511,6 @@ static int as3645a_parse_node(struct as3645a *flash,
return -ENODEV;
}
- rval = fwnode_property_read_string(flash->flash_node, "label", &name);
- if (!rval) {
- strlcpy(names->flash, name, sizeof(names->flash));
- } else if (is_of_node(fwnode)) {
- snprintf(names->flash, sizeof(names->flash),
- "%pOFn:flash", to_of_node(fwnode));
- } else {
- dev_err(&flash->client->dev, "flash node has no label!\n");
- return -EINVAL;
- }
-
rval = fwnode_property_read_u32(flash->flash_node, "flash-timeout-us",
&cfg->flash_timeout_us);
if (rval < 0) {
@@ -565,17 +548,6 @@ static int as3645a_parse_node(struct as3645a *flash,
goto out_err;
}
- rval = fwnode_property_read_string(flash->indicator_node, "label",
- &name);
- if (!rval) {
- strlcpy(names->indicator, name, sizeof(names->indicator));
- } else if (is_of_node(fwnode)) {
- snprintf(names->indicator, sizeof(names->indicator),
- "%pOFn:indicator", to_of_node(fwnode));
- } else {
- dev_err(&flash->client->dev, "indicator node has no label!\n");
- return -EINVAL;
- }
rval = fwnode_property_read_u32(flash->indicator_node,
"led-max-microamp",
@@ -595,21 +567,25 @@ out_err:
return rval;
}
-static int as3645a_led_class_setup(struct as3645a *flash,
- struct as3645a_names *names)
+static int as3645a_led_class_setup(struct as3645a *flash)
{
struct led_classdev *fled_cdev = &flash->fled.led_cdev;
struct led_classdev *iled_cdev = &flash->iled_cdev;
+ struct led_init_data init_data = {};
struct led_flash_setting *cfg;
int rval;
- iled_cdev->name = names->indicator;
iled_cdev->brightness_set_blocking = as3645a_set_indicator_brightness;
iled_cdev->max_brightness =
flash->cfg.indicator_max_ua / AS_INDICATOR_INTENSITY_STEP;
iled_cdev->flags = LED_CORE_SUSPENDRESUME;
- rval = led_classdev_register(&flash->client->dev, iled_cdev);
+ init_data.fwnode = flash->indicator_node;
+ init_data.devicename = AS_NAME;
+ init_data.default_label = "indicator";
+
+ rval = led_classdev_register_ext(&flash->client->dev, iled_cdev,
+ &init_data);
if (rval < 0)
return rval;
@@ -627,7 +603,6 @@ static int as3645a_led_class_setup(struct as3645a *flash,
flash->fled.ops = &as3645a_led_flash_ops;
- fled_cdev->name = names->flash;
fled_cdev->brightness_set_blocking = as3645a_set_assist_brightness;
/* Value 0 is off in LED class. */
fled_cdev->max_brightness =
@@ -635,15 +610,23 @@ static int as3645a_led_class_setup(struct as3645a *flash,
flash->cfg.assist_max_ua) + 1;
fled_cdev->flags = LED_DEV_CAP_FLASH | LED_CORE_SUSPENDRESUME;
- rval = led_classdev_flash_register(&flash->client->dev, &flash->fled);
- if (rval) {
- led_classdev_unregister(iled_cdev);
- dev_err(&flash->client->dev,
- "led_classdev_flash_register() failed, error %d\n",
- rval);
- }
+ init_data.fwnode = flash->flash_node;
+ init_data.devicename = AS_NAME;
+ init_data.default_label = "flash";
+
+ rval = led_classdev_flash_register_ext(&flash->client->dev,
+ &flash->fled, &init_data);
+ if (rval)
+ goto out_err;
return rval;
+
+out_err:
+ led_classdev_unregister(iled_cdev);
+ dev_err(&flash->client->dev,
+ "led_classdev_flash_register() failed, error %d\n",
+ rval);
+ return rval;
}
static int as3645a_v4l2_setup(struct as3645a *flash)
@@ -667,8 +650,9 @@ static int as3645a_v4l2_setup(struct as3645a *flash)
},
};
- strlcpy(cfg.dev_name, led->name, sizeof(cfg.dev_name));
- strlcpy(cfgind.dev_name, flash->iled_cdev.name, sizeof(cfg.dev_name));
+ strlcpy(cfg.dev_name, led->dev->kobj.name, sizeof(cfg.dev_name));
+ strlcpy(cfgind.dev_name, flash->iled_cdev.dev->kobj.name,
+ sizeof(cfgind.dev_name));
flash->vf = v4l2_flash_init(
&flash->client->dev, flash->flash_node, &flash->fled, NULL,
@@ -689,7 +673,6 @@ static int as3645a_v4l2_setup(struct as3645a *flash)
static int as3645a_probe(struct i2c_client *client)
{
- struct as3645a_names names;
struct as3645a *flash;
int rval;
@@ -702,7 +685,7 @@ static int as3645a_probe(struct i2c_client *client)
flash->client = client;
- rval = as3645a_parse_node(flash, &names, dev_fwnode(&client->dev));
+ rval = as3645a_parse_node(flash, dev_fwnode(&client->dev));
if (rval < 0)
return rval;
@@ -717,7 +700,7 @@ static int as3645a_probe(struct i2c_client *client)
if (rval)
goto out_mutex_destroy;
- rval = as3645a_led_class_setup(flash, &names);
+ rval = as3645a_led_class_setup(flash);
if (rval)
goto out_mutex_destroy;
diff --git a/drivers/leds/leds-bcm6328.c b/drivers/leds/leds-bcm6328.c
index c50d34e2b098..42e1b7598c3a 100644
--- a/drivers/leds/leds-bcm6328.c
+++ b/drivers/leds/leds-bcm6328.c
@@ -346,16 +346,11 @@ static int bcm6328_leds_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = pdev->dev.of_node;
struct device_node *child;
- struct resource *mem_r;
void __iomem *mem;
spinlock_t *lock; /* memory lock */
unsigned long val, *blink_leds, *blink_delay;
- mem_r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem_r)
- return -EINVAL;
-
- mem = devm_ioremap_resource(dev, mem_r);
+ mem = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(mem))
return PTR_ERR(mem);
diff --git a/drivers/leds/leds-bcm6358.c b/drivers/leds/leds-bcm6358.c
index aec285fd21c0..94fefd456ba0 100644
--- a/drivers/leds/leds-bcm6358.c
+++ b/drivers/leds/leds-bcm6358.c
@@ -151,17 +151,12 @@ static int bcm6358_leds_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = pdev->dev.of_node;
struct device_node *child;
- struct resource *mem_r;
void __iomem *mem;
spinlock_t *lock; /* memory lock */
unsigned long val;
u32 clk_div;
- mem_r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem_r)
- return -EINVAL;
-
- mem = devm_ioremap_resource(dev, mem_r);
+ mem = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(mem))
return PTR_ERR(mem);
diff --git a/drivers/leds/leds-bd2802.c b/drivers/leds/leds-bd2802.c
index e7ec6bff2b5f..bd61a823d0ca 100644
--- a/drivers/leds/leds-bd2802.c
+++ b/drivers/leds/leds-bd2802.c
@@ -10,7 +10,7 @@
#include <linux/module.h>
#include <linux/i2c.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <linux/leds.h>
#include <linux/leds-bd2802.h>
@@ -67,6 +67,7 @@ struct led_state {
struct bd2802_led {
struct bd2802_led_platform_data *pdata;
struct i2c_client *client;
+ struct gpio_desc *reset;
struct rw_semaphore rwsem;
struct led_state led[2];
@@ -200,7 +201,7 @@ static void bd2802_update_state(struct bd2802_led *led, enum led_ids id,
return;
if (bd2802_is_all_off(led) && !led->adf_on) {
- gpio_set_value(led->pdata->reset_gpio, 0);
+ gpiod_set_value(led->reset, 1);
return;
}
@@ -226,7 +227,7 @@ static void bd2802_configure(struct bd2802_led *led)
static void bd2802_reset_cancel(struct bd2802_led *led)
{
- gpio_set_value(led->pdata->reset_gpio, 1);
+ gpiod_set_value(led->reset, 0);
udelay(100);
bd2802_configure(led);
}
@@ -420,7 +421,7 @@ static void bd2802_disable_adv_conf(struct bd2802_led *led)
bd2802_addr_attributes[i]);
if (bd2802_is_all_off(led))
- gpio_set_value(led->pdata->reset_gpio, 0);
+ gpiod_set_value(led->reset, 1);
led->adf_on = 0;
}
@@ -670,8 +671,16 @@ static int bd2802_probe(struct i2c_client *client,
pdata = led->pdata = dev_get_platdata(&client->dev);
i2c_set_clientdata(client, led);
- /* Configure RESET GPIO (L: RESET, H: RESET cancel) */
- gpio_request_one(pdata->reset_gpio, GPIOF_OUT_INIT_HIGH, "RGB_RESETB");
+ /*
+ * Configure RESET GPIO (L: RESET, H: RESET cancel)
+ *
+ * We request the reset GPIO as OUT_LOW which means de-asserted,
+ * board files specifying this GPIO line in a machine descriptor
+ * table should take care to specify GPIO_ACTIVE_LOW for this line.
+ */
+ led->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(led->reset))
+ return PTR_ERR(led->reset);
/* Tacss = min 0.1ms */
udelay(100);
@@ -685,7 +694,7 @@ static int bd2802_probe(struct i2c_client *client,
dev_info(&client->dev, "return 0x%02x\n", ret);
/* To save the power, reset BD2802 after detecting */
- gpio_set_value(led->pdata->reset_gpio, 0);
+ gpiod_set_value(led->reset, 1);
/* Default attributes */
led->wave_pattern = BD2802_PATTERN_HALF;
@@ -720,7 +729,7 @@ static int bd2802_remove(struct i2c_client *client)
struct bd2802_led *led = i2c_get_clientdata(client);
int i;
- gpio_set_value(led->pdata->reset_gpio, 0);
+ gpiod_set_value(led->reset, 1);
bd2802_unregister_led_classdev(led);
if (led->adf_on)
bd2802_disable_adv_conf(led);
@@ -750,7 +759,7 @@ static int bd2802_suspend(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct bd2802_led *led = i2c_get_clientdata(client);
- gpio_set_value(led->pdata->reset_gpio, 0);
+ gpiod_set_value(led->reset, 1);
return 0;
}
diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c
index 0e4262462cb9..2da448ae718e 100644
--- a/drivers/leds/leds-cr0014114.c
+++ b/drivers/leds/leds-cr0014114.c
@@ -8,7 +8,6 @@
#include <linux/of_device.h>
#include <linux/spi/spi.h>
#include <linux/workqueue.h>
-#include <uapi/linux/uleds.h>
/*
* CR0014114 SPI protocol descrtiption:
@@ -40,8 +39,9 @@
#define CR_FW_DELAY_MSEC 10
#define CR_RECOUNT_DELAY (HZ * 3600)
+#define CR_DEV_NAME "cr0014114"
+
struct cr0014114_led {
- char name[LED_MAX_NAME_SIZE];
struct cr0014114 *priv;
struct led_classdev ldev;
u8 brightness;
@@ -167,8 +167,7 @@ static int cr0014114_set_sync(struct led_classdev *ldev,
struct cr0014114_led,
ldev);
- dev_dbg(led->priv->dev, "Set brightness of %s to %d\n",
- led->name, brightness);
+ dev_dbg(led->priv->dev, "Set brightness to %d\n", brightness);
mutex_lock(&led->priv->lock);
led->brightness = (u8)brightness;
@@ -183,42 +182,32 @@ static int cr0014114_probe_dt(struct cr0014114 *priv)
size_t i = 0;
struct cr0014114_led *led;
struct fwnode_handle *child;
- struct device_node *np;
+ struct led_init_data init_data = {};
int ret;
- const char *str;
device_for_each_child_node(priv->dev, child) {
- np = to_of_node(child);
led = &priv->leds[i];
- ret = fwnode_property_read_string(child, "label", &str);
- if (ret)
- snprintf(led->name, sizeof(led->name),
- "cr0014114::");
- else
- snprintf(led->name, sizeof(led->name),
- "cr0014114:%s", str);
-
fwnode_property_read_string(child, "linux,default-trigger",
&led->ldev.default_trigger);
led->priv = priv;
- led->ldev.name = led->name;
led->ldev.max_brightness = CR_MAX_BRIGHTNESS;
led->ldev.brightness_set_blocking = cr0014114_set_sync;
- ret = devm_of_led_classdev_register(priv->dev, np,
- &led->ldev);
+ init_data.fwnode = child;
+ init_data.devicename = CR_DEV_NAME;
+ init_data.default_label = ":";
+
+ ret = devm_led_classdev_register_ext(priv->dev, &led->ldev,
+ &init_data);
if (ret) {
dev_err(priv->dev,
- "failed to register LED device %s, err %d",
- led->name, ret);
+ "failed to register LED device, err %d", ret);
fwnode_handle_put(child);
return ret;
}
- led->ldev.dev->of_node = np;
-
i++;
}
diff --git a/drivers/leds/leds-el15203000.c b/drivers/leds/leds-el15203000.c
new file mode 100644
index 000000000000..298b13e4807a
--- /dev/null
+++ b/drivers/leds/leds-el15203000.c
@@ -0,0 +1,357 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019 Crane Merchandising Systems. All rights reserved.
+// Copyright (C) 2019 Oleh Kravchenko <oleg@kaa.org.ua>
+
+#include <linux/delay.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/spi/spi.h>
+
+/*
+ * EL15203000 SPI protocol description:
+ * +-----+---------+
+ * | LED | COMMAND |
+ * +-----+---------+
+ * | 1 | 1 |
+ * +-----+---------+
+ * (*) LEDs MCU board expects 20 msec delay per byte.
+ *
+ * LEDs:
+ * +----------+--------------+-------------------------------------------+
+ * | ID | NAME | DESCRIPTION |
+ * +----------+--------------+-------------------------------------------+
+ * | 'P' 0x50 | Pipe | Consists from 5 LEDs, controlled by board |
+ * +----------+--------------+-------------------------------------------+
+ * | 'S' 0x53 | Screen frame | Light tube around the screen |
+ * +----------+--------------+-------------------------------------------+
+ * | 'V' 0x56 | Vending area | Highlights a cup of coffee |
+ * +----------+--------------+-------------------------------------------+
+ *
+ * COMMAND:
+ * +----------+-----------------+--------------+--------------+
+ * | VALUES | PIPE | SCREEN FRAME | VENDING AREA |
+ * +----------+-----------------+--------------+--------------+
+ * | '0' 0x30 | Off |
+ * +----------+-----------------------------------------------+
+ * | '1' 0x31 | On |
+ * +----------+-----------------+--------------+--------------+
+ * | '2' 0x32 | Cascade | Breathing |
+ * +----------+-----------------+--------------+
+ * | '3' 0x33 | Inverse cascade |
+ * +----------+-----------------+
+ * | '4' 0x34 | Bounce |
+ * +----------+-----------------+
+ * | '5' 0x35 | Inverse bounce |
+ * +----------+-----------------+
+ */
+
+/* EL15203000 default settings */
+#define EL_FW_DELAY_USEC 20000ul
+#define EL_PATTERN_DELAY_MSEC 800u
+#define EL_PATTERN_LEN 10u
+#define EL_PATTERN_HALF_LEN (EL_PATTERN_LEN / 2)
+
+enum el15203000_command {
+ /* for all LEDs */
+ EL_OFF = '0',
+ EL_ON = '1',
+
+ /* for Screen LED */
+ EL_SCREEN_BREATHING = '2',
+
+ /* for Pipe LED */
+ EL_PIPE_CASCADE = '2',
+ EL_PIPE_INV_CASCADE = '3',
+ EL_PIPE_BOUNCE = '4',
+ EL_PIPE_INV_BOUNCE = '5',
+};
+
+struct el15203000_led {
+ struct el15203000 *priv;
+ struct led_classdev ldev;
+ u32 reg;
+};
+
+struct el15203000 {
+ struct device *dev;
+ struct mutex lock;
+ struct spi_device *spi;
+ unsigned long delay;
+ size_t count;
+ struct el15203000_led leds[];
+};
+
+static int el15203000_cmd(struct el15203000_led *led, u8 brightness)
+{
+ int ret;
+ u8 cmd[2];
+ size_t i;
+
+ mutex_lock(&led->priv->lock);
+
+ dev_dbg(led->priv->dev, "Set brightness of 0x%02x(%c) to 0x%02x(%c)",
+ led->reg, led->reg, brightness, brightness);
+
+ /* to avoid SPI mistiming with firmware we should wait some time */
+ if (time_after(led->priv->delay, jiffies)) {
+ dev_dbg(led->priv->dev, "Wait %luus to sync",
+ EL_FW_DELAY_USEC);
+
+ usleep_range(EL_FW_DELAY_USEC,
+ EL_FW_DELAY_USEC + 1);
+ }
+
+ cmd[0] = led->reg;
+ cmd[1] = brightness;
+
+ for (i = 0; i < ARRAY_SIZE(cmd); i++) {
+ if (i)
+ usleep_range(EL_FW_DELAY_USEC,
+ EL_FW_DELAY_USEC + 1);
+
+ ret = spi_write(led->priv->spi, &cmd[i], sizeof(cmd[i]));
+ if (ret) {
+ dev_err(led->priv->dev,
+ "spi_write() error %d", ret);
+ break;
+ }
+ }
+
+ led->priv->delay = jiffies + usecs_to_jiffies(EL_FW_DELAY_USEC);
+
+ mutex_unlock(&led->priv->lock);
+
+ return ret;
+}
+
+static int el15203000_set_blocking(struct led_classdev *ldev,
+ enum led_brightness brightness)
+{
+ struct el15203000_led *led = container_of(ldev,
+ struct el15203000_led,
+ ldev);
+
+ return el15203000_cmd(led, brightness == LED_OFF ? EL_OFF : EL_ON);
+}
+
+static int el15203000_pattern_set_S(struct led_classdev *ldev,
+ struct led_pattern *pattern,
+ u32 len, int repeat)
+{
+ struct el15203000_led *led = container_of(ldev,
+ struct el15203000_led,
+ ldev);
+
+ if (repeat > 0 || len != 2 ||
+ pattern[0].delta_t != 4000 || pattern[0].brightness != 0 ||
+ pattern[1].delta_t != 4000 || pattern[1].brightness != 1)
+ return -EINVAL;
+
+ dev_dbg(led->priv->dev, "Breathing mode for 0x%02x(%c)",
+ led->reg, led->reg);
+
+ return el15203000_cmd(led, EL_SCREEN_BREATHING);
+}
+
+static bool is_cascade(const struct led_pattern *pattern, u32 len,
+ bool inv, bool right)
+{
+ int val, t;
+ u32 i;
+
+ if (len != EL_PATTERN_HALF_LEN)
+ return false;
+
+ val = right ? BIT(4) : BIT(0);
+
+ for (i = 0; i < len; i++) {
+ t = inv ? ~val & GENMASK(4, 0) : val;
+
+ if (pattern[i].delta_t != EL_PATTERN_DELAY_MSEC ||
+ pattern[i].brightness != t)
+ return false;
+
+ val = right ? val >> 1 : val << 1;
+ }
+
+ return true;
+}
+
+static bool is_bounce(const struct led_pattern *pattern, u32 len, bool inv)
+{
+ if (len != EL_PATTERN_LEN)
+ return false;
+
+ return is_cascade(pattern, EL_PATTERN_HALF_LEN, inv, false) &&
+ is_cascade(pattern + EL_PATTERN_HALF_LEN,
+ EL_PATTERN_HALF_LEN, inv, true);
+}
+
+static int el15203000_pattern_set_P(struct led_classdev *ldev,
+ struct led_pattern *pattern,
+ u32 len, int repeat)
+{
+ u8 cmd;
+ struct el15203000_led *led = container_of(ldev,
+ struct el15203000_led,
+ ldev);
+
+ if (repeat > 0)
+ return -EINVAL;
+
+ if (is_cascade(pattern, len, false, false)) {
+ dev_dbg(led->priv->dev, "Cascade mode for 0x%02x(%c)",
+ led->reg, led->reg);
+
+ cmd = EL_PIPE_CASCADE;
+ } else if (is_cascade(pattern, len, true, false)) {
+ dev_dbg(led->priv->dev, "Inverse cascade mode for 0x%02x(%c)",
+ led->reg, led->reg);
+
+ cmd = EL_PIPE_INV_CASCADE;
+ } else if (is_bounce(pattern, len, false)) {
+ dev_dbg(led->priv->dev, "Bounce mode for 0x%02x(%c)",
+ led->reg, led->reg);
+
+ cmd = EL_PIPE_BOUNCE;
+ } else if (is_bounce(pattern, len, true)) {
+ dev_dbg(led->priv->dev, "Inverse bounce mode for 0x%02x(%c)",
+ led->reg, led->reg);
+
+ cmd = EL_PIPE_INV_BOUNCE;
+ } else {
+ dev_err(led->priv->dev, "Invalid hw_pattern for 0x%02x(%c)!",
+ led->reg, led->reg);
+
+ return -EINVAL;
+ }
+
+ return el15203000_cmd(led, cmd);
+}
+
+static int el15203000_pattern_clear(struct led_classdev *ldev)
+{
+ struct el15203000_led *led = container_of(ldev,
+ struct el15203000_led,
+ ldev);
+
+ return el15203000_cmd(led, EL_OFF);
+}
+
+static int el15203000_probe_dt(struct el15203000 *priv)
+{
+ struct el15203000_led *led = priv->leds;
+ struct fwnode_handle *child;
+ int ret;
+
+ device_for_each_child_node(priv->dev, child) {
+ struct led_init_data init_data = {};
+
+ ret = fwnode_property_read_u32(child, "reg", &led->reg);
+ if (ret) {
+ dev_err(priv->dev, "LED without ID number");
+ fwnode_handle_put(child);
+
+ break;
+ }
+
+ if (led->reg > U8_MAX) {
+ dev_err(priv->dev, "LED value %d is invalid", led->reg);
+ fwnode_handle_put(child);
+
+ return -EINVAL;
+ }
+
+ fwnode_property_read_string(child, "linux,default-trigger",
+ &led->ldev.default_trigger);
+
+ led->priv = priv;
+ led->ldev.max_brightness = LED_ON;
+ led->ldev.brightness_set_blocking = el15203000_set_blocking;
+
+ if (led->reg == 'S') {
+ led->ldev.pattern_set = el15203000_pattern_set_S;
+ led->ldev.pattern_clear = el15203000_pattern_clear;
+ } else if (led->reg == 'P') {
+ led->ldev.pattern_set = el15203000_pattern_set_P;
+ led->ldev.pattern_clear = el15203000_pattern_clear;
+ }
+
+ init_data.fwnode = child;
+ ret = devm_led_classdev_register_ext(priv->dev, &led->ldev,
+ &init_data);
+ if (ret) {
+ dev_err(priv->dev,
+ "failed to register LED device %s, err %d",
+ led->ldev.name, ret);
+ fwnode_handle_put(child);
+
+ break;
+ }
+
+ led++;
+ }
+
+ return ret;
+}
+
+static int el15203000_probe(struct spi_device *spi)
+{
+ struct el15203000 *priv;
+ size_t count;
+
+ count = device_get_child_node_count(&spi->dev);
+ if (!count) {
+ dev_err(&spi->dev, "LEDs are not defined in device tree!");
+ return -ENODEV;
+ }
+
+ priv = devm_kzalloc(&spi->dev, struct_size(priv, leds, count),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ mutex_init(&priv->lock);
+ priv->count = count;
+ priv->dev = &spi->dev;
+ priv->spi = spi;
+ priv->delay = jiffies -
+ usecs_to_jiffies(EL_FW_DELAY_USEC);
+
+ spi_set_drvdata(spi, priv);
+
+ return el15203000_probe_dt(priv);
+}
+
+static int el15203000_remove(struct spi_device *spi)
+{
+ struct el15203000 *priv = spi_get_drvdata(spi);
+
+ mutex_destroy(&priv->lock);
+
+ return 0;
+}
+
+static const struct of_device_id el15203000_dt_ids[] = {
+ { .compatible = "crane,el15203000", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, el15203000_dt_ids);
+
+static struct spi_driver el15203000_driver = {
+ .probe = el15203000_probe,
+ .remove = el15203000_remove,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = el15203000_dt_ids,
+ },
+};
+
+module_spi_driver(el15203000_driver);
+
+MODULE_AUTHOR("Oleh Kravchenko <oleg@kaa.org.ua>");
+MODULE_DESCRIPTION("el15203000 LED driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:el15203000");
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index bdc98ddca1dc..2bf74595610f 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -73,11 +73,11 @@ static int gpio_blink_set(struct led_classdev *led_cdev,
static int create_gpio_led(const struct gpio_led *template,
struct gpio_led_data *led_dat, struct device *parent,
- struct device_node *np, gpio_blink_set_t blink_set)
+ struct fwnode_handle *fwnode, gpio_blink_set_t blink_set)
{
+ struct led_init_data init_data = {};
int ret, state;
- led_dat->cdev.name = template->name;
led_dat->cdev.default_trigger = template->default_trigger;
led_dat->can_sleep = gpiod_cansleep(led_dat->gpiod);
if (!led_dat->can_sleep)
@@ -108,7 +108,16 @@ static int create_gpio_led(const struct gpio_led *template,
if (ret < 0)
return ret;
- return devm_of_led_classdev_register(parent, np, &led_dat->cdev);
+ if (template->name) {
+ led_dat->cdev.name = template->name;
+ ret = devm_led_classdev_register(parent, &led_dat->cdev);
+ } else {
+ init_data.fwnode = fwnode;
+ ret = devm_led_classdev_register_ext(parent, &led_dat->cdev,
+ &init_data);
+ }
+
+ return ret;
}
struct gpio_leds_priv {
@@ -141,19 +150,15 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
struct gpio_led_data *led_dat = &priv->leds[priv->num_leds];
struct gpio_led led = {};
const char *state = NULL;
- struct device_node *np = to_of_node(child);
-
- ret = fwnode_property_read_string(child, "label", &led.name);
- if (ret && IS_ENABLED(CONFIG_OF) && np)
- led.name = np->name;
- if (!led.name) {
- fwnode_handle_put(child);
- return ERR_PTR(-EINVAL);
- }
+ /*
+ * Acquire gpiod from DT with uninitialized label, which
+ * will be updated after LED class device is registered,
+ * Only then the final LED name is known.
+ */
led.gpiod = devm_fwnode_get_gpiod_from_child(dev, NULL, child,
GPIOD_ASIS,
- led.name);
+ NULL);
if (IS_ERR(led.gpiod)) {
fwnode_handle_put(child);
return ERR_CAST(led.gpiod);
@@ -181,11 +186,14 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
if (fwnode_property_present(child, "panic-indicator"))
led.panic_indicator = 1;
- ret = create_gpio_led(&led, led_dat, dev, np, NULL);
+ ret = create_gpio_led(&led, led_dat, dev, child, NULL);
if (ret < 0) {
fwnode_handle_put(child);
return ERR_PTR(ret);
}
+ /* Set gpiod label to match the corresponding LED name. */
+ gpiod_set_consumer_name(led_dat->gpiod,
+ led_dat->cdev.dev->kobj.name);
priv->num_leds++;
}
diff --git a/drivers/leds/leds-is31fl319x.c b/drivers/leds/leds-is31fl319x.c
index 2d077b8edd0e..ca6634b8683c 100644
--- a/drivers/leds/leds-is31fl319x.c
+++ b/drivers/leds/leds-is31fl319x.c
@@ -333,12 +333,11 @@ static int is31fl319x_probe(struct i2c_client *client,
{
struct is31fl319x_chip *is31;
struct device *dev = &client->dev;
- struct i2c_adapter *adapter = to_i2c_adapter(dev->parent);
int err;
int i = 0;
u32 aggregated_led_microamp = IS31FL319X_CURRENT_MAX;
- if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -EIO;
is31 = devm_kzalloc(&client->dev, sizeof(*is31), GFP_KERNEL);
diff --git a/drivers/leds/leds-is31fl32xx.c b/drivers/leds/leds-is31fl32xx.c
index 6fbab70dfb04..6f29b8943913 100644
--- a/drivers/leds/leds-is31fl32xx.c
+++ b/drivers/leds/leds-is31fl32xx.c
@@ -324,12 +324,6 @@ static int is31fl32xx_init_regs(struct is31fl32xx_priv *priv)
return 0;
}
-static inline size_t sizeof_is31fl32xx_priv(int num_leds)
-{
- return sizeof(struct is31fl32xx_priv) +
- (sizeof(struct is31fl32xx_led_data) * num_leds);
-}
-
static int is31fl32xx_parse_child_dt(const struct device *dev,
const struct device_node *child,
struct is31fl32xx_led_data *led_data)
@@ -450,7 +444,7 @@ static int is31fl32xx_probe(struct i2c_client *client,
if (!count)
return -EINVAL;
- priv = devm_kzalloc(dev, sizeof_is31fl32xx_priv(count),
+ priv = devm_kzalloc(dev, struct_size(priv, leds, count),
GFP_KERNEL);
if (!priv)
return -ENOMEM;
diff --git a/drivers/leds/leds-ktd2692.c b/drivers/leds/leds-ktd2692.c
index f63918206bfb..670efee9b131 100644
--- a/drivers/leds/leds-ktd2692.c
+++ b/drivers/leds/leds-ktd2692.c
@@ -19,7 +19,7 @@
/* Value related the movie mode */
#define KTD2692_MOVIE_MODE_CURRENT_LEVELS 16
#define KTD2692_MM_TO_FL_RATIO(x) ((x) / 3)
-#define KTD2962_MM_MIN_CURR_THRESHOLD_SCALE 8
+#define KTD2692_MM_MIN_CURR_THRESHOLD_SCALE 8
/* Value related the flash mode */
#define KTD2692_FLASH_MODE_TIMEOUT_LEVELS 8
@@ -250,7 +250,7 @@ static void ktd2692_setup(struct ktd2692_context *led)
ktd2692_expresswire_reset(led);
gpiod_direction_output(led->aux_gpio, KTD2692_LOW);
- ktd2692_expresswire_write(led, (KTD2962_MM_MIN_CURR_THRESHOLD_SCALE - 1)
+ ktd2692_expresswire_write(led, (KTD2692_MM_MIN_CURR_THRESHOLD_SCALE - 1)
| KTD2692_REG_MM_MIN_CURR_THRESHOLD_BASE);
ktd2692_expresswire_write(led, KTD2692_FLASH_MODE_CURR_PERCENT(45)
| KTD2692_REG_FLASH_CURRENT_BASE);
diff --git a/drivers/leds/leds-lm3532.c b/drivers/leds/leds-lm3532.c
index 180895b83b88..188a57da981a 100644
--- a/drivers/leds/leds-lm3532.c
+++ b/drivers/leds/leds-lm3532.c
@@ -1,6 +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
#include <linux/i2c.h>
#include <linux/leds.h>
@@ -23,11 +24,11 @@
#define LM3532_REG_PWM_B_CFG 0x14
#define LM3532_REG_PWM_C_CFG 0x15
#define LM3532_REG_ZONE_CFG_A 0x16
-#define LM3532_REG_CTRL_A_BRT 0x17
+#define LM3532_REG_CTRL_A_FS_CURR 0x17
#define LM3532_REG_ZONE_CFG_B 0x18
-#define LM3532_REG_CTRL_B_BRT 0x19
+#define LM3532_REG_CTRL_B_FS_CURR 0x19
#define LM3532_REG_ZONE_CFG_C 0x1a
-#define LM3532_REG_CTRL_C_BRT 0x1b
+#define LM3532_REG_CTRL_C_FS_CURR 0x1b
#define LM3532_REG_ENABLE 0x1d
#define LM3532_ALS_CONFIG 0x23
#define LM3532_REG_ZN_0_HI 0x60
@@ -38,9 +39,12 @@
#define LM3532_REG_ZN_2_LO 0x65
#define LM3532_REG_ZN_3_HI 0x66
#define LM3532_REG_ZN_3_LO 0x67
+#define LM3532_REG_ZONE_TRGT_A 0x70
+#define LM3532_REG_ZONE_TRGT_B 0x75
+#define LM3532_REG_ZONE_TRGT_C 0x7a
#define LM3532_REG_MAX 0x7e
-/* Contorl Enable */
+/* Control Enable */
#define LM3532_CTRL_A_ENABLE BIT(0)
#define LM3532_CTRL_B_ENABLE BIT(1)
#define LM3532_CTRL_C_ENABLE BIT(2)
@@ -86,6 +90,10 @@
#define LM3532_NUM_AVG_VALS 8
#define LM3532_NUM_IMP_VALS 32
+#define LM3532_FS_CURR_MIN 5000
+#define LM3532_FS_CURR_MAX 29800
+#define LM3532_FS_CURR_STEP 800
+
/*
* struct lm3532_als_data
* @config - value of ALS configuration register
@@ -116,8 +124,11 @@ struct lm3532_als_data {
* @priv - Pointer the device data structure
* @control_bank - Control bank the LED is associated to
* @mode - Mode of the LED string
+ * @ctrl_brt_pointer - Zone target register that controls the sink
* @num_leds - Number of LED strings are supported in this array
+ * @full_scale_current - The full-scale current setting for the current sink.
* @led_strings - The LED strings supported in this array
+ * @enabled - Enabled status
* @label - LED label
*/
struct lm3532_led {
@@ -126,7 +137,10 @@ struct lm3532_led {
int control_bank;
int mode;
+ int ctrl_brt_pointer;
int num_leds;
+ int full_scale_current;
+ int enabled:1;
u32 led_strings[LM3532_MAX_CONTROL_BANKS];
char label[LED_MAX_NAME_SIZE];
};
@@ -168,11 +182,11 @@ static const struct reg_default lm3532_reg_defs[] = {
{LM3532_REG_PWM_B_CFG, 0x82},
{LM3532_REG_PWM_C_CFG, 0x82},
{LM3532_REG_ZONE_CFG_A, 0xf1},
- {LM3532_REG_CTRL_A_BRT, 0xf3},
+ {LM3532_REG_CTRL_A_FS_CURR, 0xf3},
{LM3532_REG_ZONE_CFG_B, 0xf1},
- {LM3532_REG_CTRL_B_BRT, 0xf3},
+ {LM3532_REG_CTRL_B_FS_CURR, 0xf3},
{LM3532_REG_ZONE_CFG_C, 0xf1},
- {LM3532_REG_CTRL_C_BRT, 0xf3},
+ {LM3532_REG_CTRL_C_FS_CURR, 0xf3},
{LM3532_REG_ENABLE, 0xf8},
{LM3532_ALS_CONFIG, 0x44},
{LM3532_REG_ZN_0_HI, 0x35},
@@ -195,7 +209,7 @@ static const struct regmap_config lm3532_regmap_config = {
.cache_type = REGCACHE_FLAT,
};
-const static int als_imp_table[LM3532_NUM_IMP_VALS] = {37000, 18500, 12330,
+static const int als_imp_table[LM3532_NUM_IMP_VALS] = {37000, 18500, 12330,
92500, 7400, 6170, 5290,
4630, 4110, 3700, 3360,
3080, 2850, 2640, 2440,
@@ -252,7 +266,7 @@ static int lm3532_get_index(const int table[], int size, int value)
return -EINVAL;
}
-const static int als_avrg_table[LM3532_NUM_AVG_VALS] = {17920, 35840, 71680,
+static const int als_avrg_table[LM3532_NUM_AVG_VALS] = {17920, 35840, 71680,
1433360, 286720, 573440,
1146880, 2293760};
static int lm3532_get_als_avg_index(int avg_time)
@@ -267,7 +281,7 @@ static int lm3532_get_als_avg_index(int avg_time)
avg_time);
}
-const static int ramp_table[LM3532_NUM_RAMP_VALS] = { 8, 1024, 2048, 4096, 8192,
+static const int ramp_table[LM3532_NUM_RAMP_VALS] = { 8, 1024, 2048, 4096, 8192,
16384, 32768, 65536};
static int lm3532_get_ramp_index(int ramp_time)
{
@@ -281,11 +295,15 @@ static int lm3532_get_ramp_index(int ramp_time)
ramp_time);
}
+/* Caller must take care of locking */
static int lm3532_led_enable(struct lm3532_led *led_data)
{
int ctrl_en_val = BIT(led_data->control_bank);
int ret;
+ if (led_data->enabled)
+ return 0;
+
ret = regmap_update_bits(led_data->priv->regmap, LM3532_REG_ENABLE,
ctrl_en_val, ctrl_en_val);
if (ret) {
@@ -293,22 +311,38 @@ static int lm3532_led_enable(struct lm3532_led *led_data)
return ret;
}
- return regulator_enable(led_data->priv->regulator);
+ ret = regulator_enable(led_data->priv->regulator);
+ if (ret < 0)
+ return ret;
+
+ led_data->enabled = 1;
+
+ return 0;
}
+/* Caller must take care of locking */
static int lm3532_led_disable(struct lm3532_led *led_data)
{
int ctrl_en_val = BIT(led_data->control_bank);
int ret;
+ if (!led_data->enabled)
+ return 0;
+
ret = regmap_update_bits(led_data->priv->regmap, LM3532_REG_ENABLE,
- ctrl_en_val, ~ctrl_en_val);
+ ctrl_en_val, 0);
if (ret) {
dev_err(led_data->priv->dev, "Failed to set ctrl:%d\n", ret);
return ret;
}
- return regulator_disable(led_data->priv->regulator);
+ ret = regulator_disable(led_data->priv->regulator);
+ if (ret < 0)
+ return ret;
+
+ led_data->enabled = 0;
+
+ return 0;
}
static int lm3532_brightness_set(struct led_classdev *led_cdev,
@@ -321,7 +355,7 @@ static int lm3532_brightness_set(struct led_classdev *led_cdev,
mutex_lock(&led->priv->lock);
- if (led->mode == LM3532_BL_MODE_ALS) {
+ if (led->mode == LM3532_ALS_CTRL) {
if (brt_val > LED_OFF)
ret = lm3532_led_enable(led);
else
@@ -339,8 +373,8 @@ static int lm3532_brightness_set(struct led_classdev *led_cdev,
if (ret)
goto unlock;
- brightness_reg = LM3532_REG_CTRL_A_BRT + led->control_bank * 2;
- brt_val = brt_val / LM3532_BRT_VAL_ADJUST;
+ brightness_reg = LM3532_REG_ZONE_TRGT_A + led->control_bank * 5 +
+ (led->ctrl_brt_pointer >> 2);
ret = regmap_write(led->priv->regmap, brightness_reg, brt_val);
@@ -356,8 +390,43 @@ static int lm3532_init_registers(struct lm3532_led *led)
unsigned int output_cfg_val = 0;
unsigned int output_cfg_shift = 0;
unsigned int output_cfg_mask = 0;
+ unsigned int brightness_config_reg;
+ unsigned int brightness_config_val;
+ int fs_current_reg;
+ int fs_current_val;
int ret, i;
+ if (drvdata->enable_gpio)
+ gpiod_direction_output(drvdata->enable_gpio, 1);
+
+ brightness_config_reg = LM3532_REG_ZONE_CFG_A + led->control_bank * 2;
+ /*
+ * This could be hard coded to the default value but the control
+ * brightness register may have changed during boot.
+ */
+ ret = regmap_read(drvdata->regmap, brightness_config_reg,
+ &led->ctrl_brt_pointer);
+ if (ret)
+ return ret;
+
+ led->ctrl_brt_pointer &= LM3532_ZONE_MASK;
+ brightness_config_val = led->ctrl_brt_pointer | led->mode;
+ ret = regmap_write(drvdata->regmap, brightness_config_reg,
+ brightness_config_val);
+ if (ret)
+ return ret;
+
+ if (led->full_scale_current) {
+ fs_current_reg = LM3532_REG_CTRL_A_FS_CURR + led->control_bank * 2;
+ fs_current_val = (led->full_scale_current - LM3532_FS_CURR_MIN) /
+ LM3532_FS_CURR_STEP;
+
+ ret = regmap_write(drvdata->regmap, fs_current_reg,
+ fs_current_val);
+ if (ret)
+ return ret;
+ }
+
for (i = 0; i < led->num_leds; i++) {
output_cfg_shift = led->led_strings[i] * 2;
output_cfg_val |= (led->control_bank << output_cfg_shift);
@@ -382,7 +451,6 @@ static int lm3532_als_configure(struct lm3532_data *priv,
struct lm3532_als_data *als = priv->als_data;
u32 als_vmin, als_vmax, als_vstep;
int zone_reg = LM3532_REG_ZN_0_HI;
- int brightnes_config_reg;
int ret;
int i;
@@ -411,14 +479,7 @@ static int lm3532_als_configure(struct lm3532_data *priv,
als->config = (als->als_avrg_time | (LM3532_ENABLE_ALS) |
(als->als_input_mode << LM3532_ALS_SEL_SHIFT));
- ret = regmap_write(priv->regmap, LM3532_ALS_CONFIG, als->config);
- if (ret)
- return ret;
-
- brightnes_config_reg = LM3532_REG_ZONE_CFG_A + led->control_bank * 2;
-
- return regmap_update_bits(priv->regmap, brightnes_config_reg,
- LM3532_I2C_CTRL, LM3532_ALS_CTRL);
+ return regmap_write(priv->regmap, LM3532_ALS_CONFIG, als->config);
}
static int lm3532_parse_als(struct lm3532_data *priv)
@@ -517,6 +578,12 @@ static int lm3532_parse_node(struct lm3532_data *priv)
priv->runtime_ramp_down = lm3532_get_ramp_index(ramp_time);
device_for_each_child_node(priv->dev, child) {
+ struct led_init_data idata = {
+ .fwnode = child,
+ .default_label = ":",
+ .devicename = priv->client->name,
+ };
+
led = &priv->leds[i];
ret = fwnode_property_read_u32(child, "reg", &control_bank);
@@ -541,20 +608,29 @@ static int lm3532_parse_node(struct lm3532_data *priv)
goto child_out;
}
+ if (fwnode_property_present(child, "led-max-microamp") &&
+ fwnode_property_read_u32(child, "led-max-microamp",
+ &led->full_scale_current))
+ dev_err(&priv->client->dev,
+ "Failed getting led-max-microamp\n");
+ else
+ led->full_scale_current = min(led->full_scale_current,
+ LM3532_FS_CURR_MAX);
+
if (led->mode == LM3532_BL_MODE_ALS) {
+ led->mode = LM3532_ALS_CTRL;
ret = lm3532_parse_als(priv);
if (ret)
dev_err(&priv->client->dev, "Failed to parse als\n");
else
lm3532_als_configure(priv, led);
+ } else {
+ led->mode = LM3532_I2C_CTRL;
}
- led->num_leds = fwnode_property_read_u32_array(child,
- "led-sources",
- NULL, 0);
-
+ led->num_leds = fwnode_property_count_u32(child, "led-sources");
if (led->num_leds > LM3532_MAX_LED_STRINGS) {
- dev_err(&priv->client->dev, "To many LED string defined\n");
+ dev_err(&priv->client->dev, "Too many LED string defined\n");
continue;
}
@@ -582,7 +658,7 @@ static int lm3532_parse_node(struct lm3532_data *priv)
led->led_dev.name = led->label;
led->led_dev.brightness_set_blocking = lm3532_brightness_set;
- ret = devm_led_classdev_register(priv->dev, &led->led_dev);
+ ret = devm_led_classdev_register_ext(priv->dev, &led->led_dev, &idata);
if (ret) {
dev_err(&priv->client->dev, "led register err: %d\n",
ret);
@@ -590,7 +666,13 @@ static int lm3532_parse_node(struct lm3532_data *priv)
goto child_out;
}
- lm3532_init_registers(led);
+ ret = lm3532_init_registers(led);
+ if (ret) {
+ dev_err(&priv->client->dev, "register init err: %d\n",
+ ret);
+ fwnode_handle_put(child);
+ goto child_out;
+ }
i++;
}
@@ -637,9 +719,6 @@ static int lm3532_probe(struct i2c_client *client,
return ret;
}
- if (drvdata->enable_gpio)
- gpiod_direction_output(drvdata->enable_gpio, 1);
-
return ret;
}
diff --git a/drivers/leds/leds-lm3601x.c b/drivers/leds/leds-lm3601x.c
index 081aa71e43a3..fce89f2a2d92 100644
--- a/drivers/leds/leds-lm3601x.c
+++ b/drivers/leds/leds-lm3601x.c
@@ -10,7 +10,6 @@
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/slab.h>
-#include <uapi/linux/uleds.h>
#define LM3601X_LED_IR 0x0
#define LM3601X_LED_TORCH 0x1
@@ -90,8 +89,6 @@ struct lm3601x_led {
struct regmap *regmap;
struct mutex lock;
- char led_name[LED_MAX_NAME_SIZE];
-
unsigned int flash_timeout;
unsigned int last_flag;
@@ -322,10 +319,12 @@ static const struct led_flash_ops flash_ops = {
.fault_get = lm3601x_flash_fault_get,
};
-static int lm3601x_register_leds(struct lm3601x_led *led)
+static int lm3601x_register_leds(struct lm3601x_led *led,
+ struct fwnode_handle *fwnode)
{
struct led_classdev *led_cdev;
struct led_flash_setting *setting;
+ struct led_init_data init_data = {};
led->fled_cdev.ops = &flash_ops;
@@ -342,20 +341,24 @@ static int lm3601x_register_leds(struct lm3601x_led *led)
setting->val = led->flash_current_max;
led_cdev = &led->fled_cdev.led_cdev;
- led_cdev->name = led->led_name;
led_cdev->brightness_set_blocking = lm3601x_brightness_set;
led_cdev->max_brightness = DIV_ROUND_UP(led->torch_current_max,
LM3601X_TORCH_REG_DIV);
led_cdev->flags |= LED_DEV_CAP_FLASH;
- return led_classdev_flash_register(&led->client->dev, &led->fled_cdev);
+ init_data.fwnode = fwnode;
+ init_data.devicename = led->client->name;
+ init_data.default_label = (led->led_mode == LM3601X_LED_TORCH) ?
+ "torch" : "infrared";
+ return devm_led_classdev_flash_register_ext(&led->client->dev,
+ &led->fled_cdev, &init_data);
}
-static int lm3601x_parse_node(struct lm3601x_led *led)
+static int lm3601x_parse_node(struct lm3601x_led *led,
+ struct fwnode_handle **fwnode)
{
struct fwnode_handle *child = NULL;
int ret = -ENODEV;
- const char *name;
child = device_get_next_child_node(&led->client->dev, child);
if (!child) {
@@ -376,17 +379,6 @@ static int lm3601x_parse_node(struct lm3601x_led *led)
goto out_err;
}
- ret = fwnode_property_read_string(child, "label", &name);
- if (ret) {
- if (led->led_mode == LM3601X_LED_TORCH)
- name = "torch";
- else
- name = "infrared";
- }
-
- snprintf(led->led_name, sizeof(led->led_name),
- "%s:%s", led->client->name, name);
-
ret = fwnode_property_read_u32(child, "led-max-microamp",
&led->torch_current_max);
if (ret) {
@@ -411,6 +403,8 @@ static int lm3601x_parse_node(struct lm3601x_led *led)
goto out_err;
}
+ *fwnode = child;
+
out_err:
fwnode_handle_put(child);
return ret;
@@ -419,6 +413,7 @@ out_err:
static int lm3601x_probe(struct i2c_client *client)
{
struct lm3601x_led *led;
+ struct fwnode_handle *fwnode;
int ret;
led = devm_kzalloc(&client->dev, sizeof(*led), GFP_KERNEL);
@@ -428,7 +423,7 @@ static int lm3601x_probe(struct i2c_client *client)
led->client = client;
i2c_set_clientdata(client, led);
- ret = lm3601x_parse_node(led);
+ ret = lm3601x_parse_node(led, &fwnode);
if (ret)
return -ENODEV;
@@ -442,14 +437,13 @@ static int lm3601x_probe(struct i2c_client *client)
mutex_init(&led->lock);
- return lm3601x_register_leds(led);
+ return lm3601x_register_leds(led, fwnode);
}
static int lm3601x_remove(struct i2c_client *client)
{
struct lm3601x_led *led = i2c_get_clientdata(client);
- led_classdev_flash_unregister(&led->fled_cdev);
mutex_destroy(&led->lock);
return regmap_update_bits(led->regmap, LM3601X_ENABLE_REG,
diff --git a/drivers/leds/leds-lm36274.c b/drivers/leds/leds-lm36274.c
index ed9dc857ec8f..836b60c9a2b8 100644
--- a/drivers/leds/leds-lm36274.c
+++ b/drivers/leds/leds-lm36274.c
@@ -90,9 +90,7 @@ static int lm36274_parse_dt(struct lm36274 *lm36274_data)
snprintf(label, sizeof(label),
"%s:%s", lm36274_data->pdev->name, name);
- lm36274_data->num_leds = fwnode_property_read_u32_array(child,
- "led-sources",
- NULL, 0);
+ lm36274_data->num_leds = fwnode_property_count_u32(child, "led-sources");
if (lm36274_data->num_leds <= 0)
return -ENODEV;
diff --git a/drivers/leds/leds-lm3642.c b/drivers/leds/leds-lm3642.c
index 480575442ed8..4232906fcb75 100644
--- a/drivers/leds/leds-lm3642.c
+++ b/drivers/leds/leds-lm3642.c
@@ -106,7 +106,7 @@ static int lm3642_control(struct lm3642_chip_data *chip,
ret = regmap_read(chip->regmap, REG_FLAG, &chip->last_flag);
if (ret < 0) {
dev_err(chip->dev, "Failed to read REG_FLAG Register\n");
- goto out;
+ return ret;
}
if (chip->last_flag)
@@ -146,11 +146,11 @@ static int lm3642_control(struct lm3642_chip_data *chip,
break;
default:
- return ret;
+ return -EINVAL;
}
if (ret < 0) {
dev_err(chip->dev, "Failed to write REG_I_CTRL Register\n");
- goto out;
+ return ret;
}
if (chip->tx_pin)
@@ -159,13 +159,12 @@ static int lm3642_control(struct lm3642_chip_data *chip,
ret = regmap_update_bits(chip->regmap, REG_ENABLE,
MODE_BITS_MASK << MODE_BITS_SHIFT,
opmode << MODE_BITS_SHIFT);
-out:
return ret;
}
/* torch */
-/* torch pin config for lm3642*/
+/* torch pin config for lm3642 */
static ssize_t lm3642_torch_pin_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
@@ -178,7 +177,7 @@ static ssize_t lm3642_torch_pin_store(struct device *dev,
ret = kstrtouint(buf, 10, &state);
if (ret)
- goto out_strtoint;
+ return ret;
if (state != 0)
state = 0x01 << TORCH_PIN_EN_SHIFT;
@@ -186,16 +185,12 @@ static ssize_t lm3642_torch_pin_store(struct device *dev,
ret = regmap_update_bits(chip->regmap, REG_ENABLE,
TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT,
state);
- if (ret < 0)
- goto out;
+ if (ret < 0) {
+ dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
+ return ret;
+ }
return size;
-out:
- dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
- return ret;
-out_strtoint:
- dev_err(chip->dev, "%s: fail to change str to int\n", __func__);
- return ret;
}
static DEVICE_ATTR(torch_pin, S_IWUSR, NULL, lm3642_torch_pin_store);
@@ -229,7 +224,7 @@ static ssize_t lm3642_strobe_pin_store(struct device *dev,
ret = kstrtouint(buf, 10, &state);
if (ret)
- goto out_strtoint;
+ return ret;
if (state != 0)
state = 0x01 << STROBE_PIN_EN_SHIFT;
@@ -237,16 +232,12 @@ static ssize_t lm3642_strobe_pin_store(struct device *dev,
ret = regmap_update_bits(chip->regmap, REG_ENABLE,
STROBE_PIN_EN_MASK << STROBE_PIN_EN_SHIFT,
state);
- if (ret < 0)
- goto out;
+ if (ret < 0) {
+ dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
+ return ret;
+ }
return size;
-out:
- dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
- return ret;
-out_strtoint:
- dev_err(chip->dev, "%s: fail to change str to int\n", __func__);
- return ret;
}
static DEVICE_ATTR(strobe_pin, S_IWUSR, NULL, lm3642_strobe_pin_store);
diff --git a/drivers/leds/leds-lm3692x.c b/drivers/leds/leds-lm3692x.c
index 4f413a7c5f05..28a51aeb28de 100644
--- a/drivers/leds/leds-lm3692x.c
+++ b/drivers/leds/leds-lm3692x.c
@@ -6,6 +6,7 @@
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/leds.h>
+#include <linux/log2.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
@@ -13,7 +14,6 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
-#include <uapi/linux/uleds.h>
#define LM36922_MODEL 0
#define LM36923_MODEL 1
@@ -103,7 +103,6 @@
* @regmap - Devices register map
* @enable_gpio - VDDIO/EN gpio to enable communication interface
* @regulator - LED supply regulator pointer
- * @label - LED label
* @led_enable - LED sync to be enabled
* @model_id - Current device model ID enumerated
*/
@@ -114,9 +113,11 @@ struct lm3692x_led {
struct regmap *regmap;
struct gpio_desc *enable_gpio;
struct regulator *regulator;
- char label[LED_MAX_NAME_SIZE];
int led_enable;
int model_id;
+
+ u8 boost_ctrl, brightness_ctrl;
+ bool enabled;
};
static const struct reg_default lm3692x_reg_defs[] = {
@@ -165,48 +166,19 @@ static int lm3692x_fault_check(struct lm3692x_led *led)
return read_buf;
}
-static int lm3692x_brightness_set(struct led_classdev *led_cdev,
- enum led_brightness brt_val)
-{
- struct lm3692x_led *led =
- container_of(led_cdev, struct lm3692x_led, led_dev);
- int ret;
- int led_brightness_lsb = (brt_val >> 5);
-
- mutex_lock(&led->lock);
-
- ret = lm3692x_fault_check(led);
- if (ret) {
- dev_err(&led->client->dev, "Cannot read/clear faults\n");
- goto out;
- }
-
- ret = regmap_write(led->regmap, LM3692X_BRT_MSB, brt_val);
- if (ret) {
- dev_err(&led->client->dev, "Cannot write MSB\n");
- goto out;
- }
-
- ret = regmap_write(led->regmap, LM3692X_BRT_LSB, led_brightness_lsb);
- if (ret) {
- dev_err(&led->client->dev, "Cannot write LSB\n");
- goto out;
- }
-out:
- mutex_unlock(&led->lock);
- return ret;
-}
-
-static int lm3692x_init(struct lm3692x_led *led)
+static int lm3692x_leds_enable(struct lm3692x_led *led)
{
int enable_state;
- int ret;
+ int ret, reg_ret;
+
+ if (led->enabled)
+ return 0;
if (led->regulator) {
ret = regulator_enable(led->regulator);
if (ret) {
dev_err(&led->client->dev,
- "Failed to enable regulator\n");
+ "Failed to enable regulator: %d\n", ret);
return ret;
}
}
@@ -216,7 +188,8 @@ static int lm3692x_init(struct lm3692x_led *led)
ret = lm3692x_fault_check(led);
if (ret) {
- dev_err(&led->client->dev, "Cannot read/clear faults\n");
+ dev_err(&led->client->dev, "Cannot read/clear faults: %d\n",
+ ret);
goto out;
}
@@ -250,10 +223,7 @@ static int lm3692x_init(struct lm3692x_led *led)
if (ret)
goto out;
- ret = regmap_write(led->regmap, LM3692X_BOOST_CTRL,
- LM3692X_BRHT_MODE_RAMP_MULTI |
- LM3692X_BL_ADJ_POL |
- LM3692X_RAMP_RATE_250us);
+ ret = regmap_write(led->regmap, LM3692X_BOOST_CTRL, led->boost_ctrl);
if (ret)
goto out;
@@ -270,7 +240,7 @@ static int lm3692x_init(struct lm3692x_led *led)
goto out;
ret = regmap_write(led->regmap, LM3692X_BRT_CTRL,
- LM3692X_BL_ADJ_POL | LM3692X_PWM_HYSTER_4LSB);
+ LM3692X_BL_ADJ_POL | LM3692X_RAMP_EN);
if (ret)
goto out;
@@ -306,6 +276,7 @@ static int lm3692x_init(struct lm3692x_led *led)
ret = regmap_update_bits(led->regmap, LM3692X_EN, LM3692X_ENABLE_MASK,
enable_state | LM3692X_DEVICE_EN);
+ led->enabled = true;
return ret;
out:
dev_err(&led->client->dev, "Fail writing initialization values\n");
@@ -314,18 +285,101 @@ out:
gpiod_direction_output(led->enable_gpio, 0);
if (led->regulator) {
+ reg_ret = regulator_disable(led->regulator);
+ if (reg_ret)
+ dev_err(&led->client->dev,
+ "Failed to disable regulator: %d\n", reg_ret);
+ }
+
+ return ret;
+}
+
+static int lm3692x_leds_disable(struct lm3692x_led *led)
+{
+ int ret;
+
+ if (!led->enabled)
+ return 0;
+
+ ret = regmap_update_bits(led->regmap, LM3692X_EN, LM3692X_DEVICE_EN, 0);
+ if (ret) {
+ dev_err(&led->client->dev, "Failed to disable regulator: %d\n",
+ ret);
+ return ret;
+ }
+
+ if (led->enable_gpio)
+ gpiod_direction_output(led->enable_gpio, 0);
+
+ if (led->regulator) {
ret = regulator_disable(led->regulator);
if (ret)
dev_err(&led->client->dev,
- "Failed to disable regulator\n");
+ "Failed to disable regulator: %d\n", ret);
}
+ led->enabled = false;
return ret;
}
+
+static int lm3692x_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness brt_val)
+{
+ struct lm3692x_led *led =
+ container_of(led_cdev, struct lm3692x_led, led_dev);
+ int ret;
+ int led_brightness_lsb = (brt_val >> 5);
+
+ mutex_lock(&led->lock);
+
+ if (brt_val == 0) {
+ ret = lm3692x_leds_disable(led);
+ goto out;
+ } else {
+ lm3692x_leds_enable(led);
+ }
+
+ ret = lm3692x_fault_check(led);
+ if (ret) {
+ dev_err(&led->client->dev, "Cannot read/clear faults: %d\n",
+ ret);
+ goto out;
+ }
+
+ ret = regmap_write(led->regmap, LM3692X_BRT_MSB, brt_val);
+ if (ret) {
+ dev_err(&led->client->dev, "Cannot write MSB: %d\n", ret);
+ goto out;
+ }
+
+ ret = regmap_write(led->regmap, LM3692X_BRT_LSB, led_brightness_lsb);
+ if (ret) {
+ dev_err(&led->client->dev, "Cannot write LSB: %d\n", ret);
+ goto out;
+ }
+out:
+ mutex_unlock(&led->lock);
+ return ret;
+}
+
+static enum led_brightness lm3692x_max_brightness(struct lm3692x_led *led,
+ u32 max_cur)
+{
+ u32 max_code;
+
+ /* see p.12 of LM36922 data sheet for brightness formula */
+ max_code = ((max_cur * 1000) - 37806) / 12195;
+ if (max_code > 0x7FF)
+ max_code = 0x7FF;
+
+ return max_code >> 3;
+}
+
static int lm3692x_probe_dt(struct lm3692x_led *led)
{
struct fwnode_handle *child = NULL;
- const char *name;
+ struct led_init_data init_data = {};
+ u32 ovp, max_cur;
int ret;
led->enable_gpio = devm_gpiod_get_optional(&led->client->dev,
@@ -337,9 +391,44 @@ static int lm3692x_probe_dt(struct lm3692x_led *led)
return ret;
}
- led->regulator = devm_regulator_get(&led->client->dev, "vled");
- if (IS_ERR(led->regulator))
+ led->regulator = devm_regulator_get_optional(&led->client->dev, "vled");
+ if (IS_ERR(led->regulator)) {
+ ret = PTR_ERR(led->regulator);
+ if (ret != -ENODEV) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(&led->client->dev,
+ "Failed to get vled regulator: %d\n",
+ ret);
+ return ret;
+ }
led->regulator = NULL;
+ }
+
+ led->boost_ctrl = LM3692X_BOOST_SW_1MHZ |
+ LM3692X_BOOST_SW_NO_SHIFT |
+ LM3692X_OCP_PROT_1_5A;
+ ret = device_property_read_u32(&led->client->dev,
+ "ti,ovp-microvolt", &ovp);
+ if (ret) {
+ led->boost_ctrl |= LM3692X_OVP_29V;
+ } else {
+ switch (ovp) {
+ case 17000000:
+ break;
+ case 21000000:
+ led->boost_ctrl |= LM3692X_OVP_21V;
+ break;
+ case 25000000:
+ led->boost_ctrl |= LM3692X_OVP_25V;
+ break;
+ case 29000000:
+ led->boost_ctrl |= LM3692X_OVP_29V;
+ break;
+ default:
+ dev_err(&led->client->dev, "Invalid OVP %d\n", ovp);
+ return -EINVAL;
+ }
+ }
child = device_get_next_child_node(&led->client->dev, child);
if (!child) {
@@ -350,30 +439,27 @@ static int lm3692x_probe_dt(struct lm3692x_led *led)
fwnode_property_read_string(child, "linux,default-trigger",
&led->led_dev.default_trigger);
- ret = fwnode_property_read_string(child, "label", &name);
- if (ret)
- snprintf(led->label, sizeof(led->label),
- "%s::", led->client->name);
- else
- snprintf(led->label, sizeof(led->label),
- "%s:%s", led->client->name, name);
-
ret = fwnode_property_read_u32(child, "reg", &led->led_enable);
if (ret) {
dev_err(&led->client->dev, "reg DT property missing\n");
return ret;
}
- led->led_dev.name = led->label;
+ ret = fwnode_property_read_u32(child, "led-max-microamp", &max_cur);
+ led->led_dev.max_brightness = ret ? LED_FULL :
+ lm3692x_max_brightness(led, max_cur);
+
+ init_data.fwnode = child;
+ init_data.devicename = led->client->name;
+ init_data.default_label = ":";
- ret = devm_led_classdev_register(&led->client->dev, &led->led_dev);
+ ret = devm_led_classdev_register_ext(&led->client->dev, &led->led_dev,
+ &init_data);
if (ret) {
dev_err(&led->client->dev, "led register err: %d\n", ret);
return ret;
}
- led->led_dev.dev->of_node = to_of_node(child);
-
return 0;
}
@@ -405,7 +491,7 @@ static int lm3692x_probe(struct i2c_client *client,
if (ret)
return ret;
- ret = lm3692x_init(led);
+ ret = lm3692x_leds_enable(led);
if (ret)
return ret;
@@ -417,22 +503,9 @@ static int lm3692x_remove(struct i2c_client *client)
struct lm3692x_led *led = i2c_get_clientdata(client);
int ret;
- ret = regmap_update_bits(led->regmap, LM3692X_EN, LM3692X_DEVICE_EN, 0);
- if (ret) {
- dev_err(&led->client->dev, "Failed to disable regulator\n");
+ ret = lm3692x_leds_disable(led);
+ if (ret)
return ret;
- }
-
- if (led->enable_gpio)
- gpiod_direction_output(led->enable_gpio, 0);
-
- if (led->regulator) {
- ret = regulator_disable(led->regulator);
- if (ret)
- dev_err(&led->client->dev,
- "Failed to disable regulator\n");
- }
-
mutex_destroy(&led->lock);
return 0;
diff --git a/drivers/leds/leds-lm3697.c b/drivers/leds/leds-lm3697.c
index 54e0e35df824..b71711aff8a3 100644
--- a/drivers/leds/leds-lm3697.c
+++ b/drivers/leds/leds-lm3697.c
@@ -244,10 +244,7 @@ static int lm3697_probe_dt(struct lm3697 *priv)
led->lmu_data.lsb_brightness_reg = LM3697_CTRL_A_BRT_LSB +
led->control_bank * 2;
- led->num_leds = fwnode_property_read_u32_array(child,
- "led-sources",
- NULL, 0);
-
+ led->num_leds = fwnode_property_count_u32(child, "led-sources");
if (led->num_leds > LM3697_MAX_LED_STRINGS) {
dev_err(&priv->client->dev, "To many LED strings defined\n");
continue;
diff --git a/drivers/leds/leds-lp5562.c b/drivers/leds/leds-lp5562.c
index 37632fc63741..edb57c42e8b1 100644
--- a/drivers/leds/leds-lp5562.c
+++ b/drivers/leds/leds-lp5562.c
@@ -260,7 +260,11 @@ static void lp5562_firmware_loaded(struct lp55xx_chip *chip)
{
const struct firmware *fw = chip->fw;
- if (fw->size > LP5562_PROGRAM_LENGTH) {
+ /*
+ * the firmware is encoded in ascii hex character, with 2 chars
+ * per byte
+ */
+ if (fw->size > (LP5562_PROGRAM_LENGTH * 2)) {
dev_err(&chip->cl->dev, "firmware data size overflow: %zu\n",
fw->size);
return;
diff --git a/drivers/leds/leds-lp8860.c b/drivers/leds/leds-lp8860.c
index ed680d0c15b0..ac2f5d6272dc 100644
--- a/drivers/leds/leds-lp8860.c
+++ b/drivers/leds/leds-lp8860.c
@@ -18,7 +18,6 @@
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/slab.h>
-#include <uapi/linux/uleds.h>
#define LP8860_DISP_CL1_BRT_MSB 0x00
#define LP8860_DISP_CL1_BRT_LSB 0x01
@@ -83,6 +82,8 @@
#define LP8860_CLEAR_FAULTS 0x01
+#define LP8860_NAME "lp8860"
+
/**
* struct lp8860_led -
* @lock - Lock for reading/writing the device
@@ -92,7 +93,6 @@
* @eeprom_regmap - EEPROM register map
* @enable_gpio - VDDIO/EN gpio to enable communication interface
* @regulator - LED supply regulator pointer
- * @label - LED label
*/
struct lp8860_led {
struct mutex lock;
@@ -102,7 +102,6 @@ struct lp8860_led {
struct regmap *eeprom_regmap;
struct gpio_desc *enable_gpio;
struct regulator *regulator;
- char label[LED_MAX_NAME_SIZE];
};
struct lp8860_eeprom_reg {
@@ -383,25 +382,19 @@ static int lp8860_probe(struct i2c_client *client,
struct lp8860_led *led;
struct device_node *np = client->dev.of_node;
struct device_node *child_node;
- const char *name;
+ struct led_init_data init_data = {};
led = devm_kzalloc(&client->dev, sizeof(*led), GFP_KERNEL);
if (!led)
return -ENOMEM;
- for_each_available_child_of_node(np, child_node) {
- led->led_dev.default_trigger = of_get_property(child_node,
- "linux,default-trigger",
- NULL);
-
- ret = of_property_read_string(child_node, "label", &name);
- if (!ret)
- snprintf(led->label, sizeof(led->label), "%s:%s",
- id->name, name);
- else
- snprintf(led->label, sizeof(led->label),
- "%s::display_cluster", id->name);
- }
+ child_node = of_get_next_available_child(np, NULL);
+ if (!child_node)
+ return -EINVAL;
+
+ led->led_dev.default_trigger = of_get_property(child_node,
+ "linux,default-trigger",
+ NULL);
led->enable_gpio = devm_gpiod_get_optional(&client->dev,
"enable", GPIOD_OUT_LOW);
@@ -416,7 +409,6 @@ static int lp8860_probe(struct i2c_client *client,
led->regulator = NULL;
led->client = client;
- led->led_dev.name = led->label;
led->led_dev.brightness_set_blocking = lp8860_brightness_set;
mutex_init(&led->lock);
@@ -443,7 +435,12 @@ static int lp8860_probe(struct i2c_client *client,
if (ret)
return ret;
- ret = devm_led_classdev_register(&client->dev, &led->led_dev);
+ init_data.fwnode = of_fwnode_handle(child_node);
+ init_data.devicename = LP8860_NAME;
+ init_data.default_label = ":display_cluster";
+
+ ret = devm_led_classdev_register_ext(&client->dev, &led->led_dev,
+ &init_data);
if (ret) {
dev_err(&client->dev, "led register err: %d\n", ret);
return ret;
diff --git a/drivers/leds/leds-lt3593.c b/drivers/leds/leds-lt3593.c
index 83e8e58d81cb..c94995f0daa2 100644
--- a/drivers/leds/leds-lt3593.c
+++ b/drivers/leds/leds-lt3593.c
@@ -10,10 +10,10 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <uapi/linux/uleds.h>
+
+#define LED_LT3593_NAME "lt3593"
struct lt3593_led_data {
- char name[LED_MAX_NAME_SIZE];
struct led_classdev cdev;
struct gpio_desc *gpiod;
};
@@ -66,6 +66,7 @@ static int lt3593_led_probe(struct platform_device *pdev)
struct lt3593_led_data *led_data;
struct fwnode_handle *child;
int ret, state = LEDS_GPIO_DEFSTATE_OFF;
+ struct led_init_data init_data = {};
const char *tmp;
if (!dev->of_node)
@@ -86,14 +87,6 @@ static int lt3593_led_probe(struct platform_device *pdev)
child = device_get_next_child_node(dev, NULL);
- ret = fwnode_property_read_string(child, "label", &tmp);
- if (ret < 0)
- snprintf(led_data->name, sizeof(led_data->name),
- "lt3593::");
- else
- snprintf(led_data->name, sizeof(led_data->name),
- "lt3593:%s", tmp);
-
fwnode_property_read_string(child, "linux,default-trigger",
&led_data->cdev.default_trigger);
@@ -102,11 +95,14 @@ static int lt3593_led_probe(struct platform_device *pdev)
state = LEDS_GPIO_DEFSTATE_ON;
}
- led_data->cdev.name = led_data->name;
led_data->cdev.brightness_set_blocking = lt3593_led_set;
led_data->cdev.brightness = state ? LED_FULL : LED_OFF;
- ret = devm_led_classdev_register(dev, &led_data->cdev);
+ init_data.fwnode = child;
+ init_data.devicename = LED_LT3593_NAME;
+ init_data.default_label = ":";
+
+ ret = devm_led_classdev_register_ext(dev, &led_data->cdev, &init_data);
if (ret < 0) {
fwnode_handle_put(child);
return ret;
diff --git a/drivers/leds/leds-max77650.c b/drivers/leds/leds-max77650.c
index 8a8e5c65b157..a0d4b725c917 100644
--- a/drivers/leds/leds-max77650.c
+++ b/drivers/leds/leds-max77650.c
@@ -62,7 +62,7 @@ static int max77650_led_brightness_set(struct led_classdev *cdev,
static int max77650_led_probe(struct platform_device *pdev)
{
- struct device_node *of_node, *child;
+ struct fwnode_handle *child;
struct max77650_led *leds, *led;
struct device *dev;
struct regmap *map;
@@ -71,10 +71,6 @@ static int max77650_led_probe(struct platform_device *pdev)
u32 reg;
dev = &pdev->dev;
- of_node = dev->of_node;
-
- if (!of_node)
- return -ENODEV;
leds = devm_kcalloc(dev, sizeof(*leds),
MAX77650_LED_NUM_LEDS, GFP_KERNEL);
@@ -85,14 +81,16 @@ static int max77650_led_probe(struct platform_device *pdev)
if (!map)
return -ENODEV;
- num_leds = of_get_child_count(of_node);
+ num_leds = device_get_child_node_count(dev);
if (!num_leds || num_leds > MAX77650_LED_NUM_LEDS)
return -ENODEV;
- for_each_child_of_node(of_node, child) {
- rv = of_property_read_u32(child, "reg", &reg);
- if (rv || reg >= MAX77650_LED_NUM_LEDS)
- return -EINVAL;
+ device_for_each_child_node(dev, child) {
+ rv = fwnode_property_read_u32(child, "reg", &reg);
+ if (rv || reg >= MAX77650_LED_NUM_LEDS) {
+ rv = -EINVAL;
+ goto err_node_put;
+ }
led = &leds[reg];
led->map = map;
@@ -101,40 +99,52 @@ static int max77650_led_probe(struct platform_device *pdev)
led->cdev.brightness_set_blocking = max77650_led_brightness_set;
led->cdev.max_brightness = MAX77650_LED_MAX_BRIGHTNESS;
- label = of_get_property(child, "label", NULL);
- if (!label) {
+ rv = fwnode_property_read_string(child, "label", &label);
+ if (rv) {
led->cdev.name = "max77650::";
} else {
led->cdev.name = devm_kasprintf(dev, GFP_KERNEL,
"max77650:%s", label);
- if (!led->cdev.name)
- return -ENOMEM;
+ if (!led->cdev.name) {
+ rv = -ENOMEM;
+ goto err_node_put;
+ }
}
- of_property_read_string(child, "linux,default-trigger",
- &led->cdev.default_trigger);
+ fwnode_property_read_string(child, "linux,default-trigger",
+ &led->cdev.default_trigger);
- rv = devm_of_led_classdev_register(dev, child, &led->cdev);
+ rv = devm_led_classdev_register(dev, &led->cdev);
if (rv)
- return rv;
+ goto err_node_put;
rv = regmap_write(map, led->regA, MAX77650_LED_A_DEFAULT);
if (rv)
- return rv;
+ goto err_node_put;
rv = regmap_write(map, led->regB, MAX77650_LED_B_DEFAULT);
if (rv)
- return rv;
+ goto err_node_put;
}
return regmap_write(map,
MAX77650_REG_CNFG_LED_TOP,
MAX77650_LED_TOP_DEFAULT);
+err_node_put:
+ fwnode_handle_put(child);
+ return rv;
}
+static const struct of_device_id max77650_led_of_match[] = {
+ { .compatible = "maxim,max77650-led" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max77650_led_of_match);
+
static struct platform_driver max77650_led_driver = {
.driver = {
.name = "max77650-led",
+ .of_match_table = max77650_led_of_match,
},
.probe = max77650_led_probe,
};
@@ -143,3 +153,4 @@ module_platform_driver(max77650_led_driver);
MODULE_DESCRIPTION("MAXIM 77650/77651 LED driver");
MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:max77650-led");
diff --git a/drivers/leds/leds-mlxreg.c b/drivers/leds/leds-mlxreg.c
index cabe379071a7..82aea1cd0c12 100644
--- a/drivers/leds/leds-mlxreg.c
+++ b/drivers/leds/leds-mlxreg.c
@@ -228,8 +228,8 @@ static int mlxreg_led_config(struct mlxreg_led_priv_data *priv)
brightness = LED_OFF;
led_data->base_color = MLXREG_LED_GREEN_SOLID;
}
- sprintf(led_data->led_cdev_name, "%s:%s", "mlxreg",
- data->label);
+ snprintf(led_data->led_cdev_name, sizeof(led_data->led_cdev_name),
+ "mlxreg:%s", data->label);
led_cdev->name = led_data->led_cdev_name;
led_cdev->brightness = brightness;
led_cdev->max_brightness = LED_ON;
diff --git a/drivers/leds/leds-netxbig.c b/drivers/leds/leds-netxbig.c
index 10497a466775..14ef4ccdda3a 100644
--- a/drivers/leds/leds-netxbig.c
+++ b/drivers/leds/leds-netxbig.c
@@ -15,7 +15,48 @@
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/leds.h>
-#include <linux/platform_data/leds-kirkwood-netxbig.h>
+
+struct netxbig_gpio_ext {
+ unsigned int *addr;
+ int num_addr;
+ unsigned int *data;
+ int num_data;
+ unsigned int enable;
+};
+
+enum netxbig_led_mode {
+ NETXBIG_LED_OFF,
+ NETXBIG_LED_ON,
+ NETXBIG_LED_SATA,
+ NETXBIG_LED_TIMER1,
+ NETXBIG_LED_TIMER2,
+ NETXBIG_LED_MODE_NUM,
+};
+
+#define NETXBIG_LED_INVALID_MODE NETXBIG_LED_MODE_NUM
+
+struct netxbig_led_timer {
+ unsigned long delay_on;
+ unsigned long delay_off;
+ enum netxbig_led_mode mode;
+};
+
+struct netxbig_led {
+ const char *name;
+ const char *default_trigger;
+ int mode_addr;
+ int *mode_val;
+ int bright_addr;
+ int bright_max;
+};
+
+struct netxbig_led_platform_data {
+ struct netxbig_gpio_ext *gpio_ext;
+ struct netxbig_led_timer *timer;
+ int num_timer;
+ struct netxbig_led *leds;
+ int num_leds;
+};
/*
* GPIO extension bus.
@@ -306,7 +347,6 @@ static int create_netxbig_led(struct platform_device *pdev,
return devm_led_classdev_register(&pdev->dev, &led_dat->cdev);
}
-#ifdef CONFIG_OF_GPIO
static int gpio_ext_get_of_pdata(struct device *dev, struct device_node *np,
struct netxbig_gpio_ext *gpio_ext)
{
@@ -388,12 +428,14 @@ static int netxbig_leds_get_of_pdata(struct device *dev,
}
gpio_ext = devm_kzalloc(dev, sizeof(*gpio_ext), GFP_KERNEL);
- if (!gpio_ext)
+ if (!gpio_ext) {
+ of_node_put(gpio_ext_np);
return -ENOMEM;
+ }
ret = gpio_ext_get_of_pdata(dev, gpio_ext_np, gpio_ext);
+ of_node_put(gpio_ext_np);
if (ret)
return ret;
- of_node_put(gpio_ext_np);
pdata->gpio_ext = gpio_ext;
/* Timers (optional) */
@@ -522,30 +564,20 @@ static const struct of_device_id of_netxbig_leds_match[] = {
{},
};
MODULE_DEVICE_TABLE(of, of_netxbig_leds_match);
-#else
-static inline int
-netxbig_leds_get_of_pdata(struct device *dev,
- struct netxbig_led_platform_data *pdata)
-{
- return -ENODEV;
-}
-#endif /* CONFIG_OF_GPIO */
static int netxbig_led_probe(struct platform_device *pdev)
{
- struct netxbig_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
+ struct netxbig_led_platform_data *pdata;
struct netxbig_led_data *leds_data;
int i;
int ret;
- if (!pdata) {
- pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata)
- return -ENOMEM;
- ret = netxbig_leds_get_of_pdata(&pdev->dev, pdata);
- if (ret)
- return ret;
- }
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+ ret = netxbig_leds_get_of_pdata(&pdev->dev, pdata);
+ if (ret)
+ return ret;
leds_data = devm_kcalloc(&pdev->dev,
pdata->num_leds, sizeof(*leds_data),
@@ -571,7 +603,7 @@ static struct platform_driver netxbig_led_driver = {
.probe = netxbig_led_probe,
.driver = {
.name = "leds-netxbig",
- .of_match_table = of_match_ptr(of_netxbig_leds_match),
+ .of_match_table = of_netxbig_leds_match,
},
};
diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c
index f92e2c07c1c6..7c500dfdcfa3 100644
--- a/drivers/leds/leds-ns2.c
+++ b/drivers/leds/leds-ns2.c
@@ -245,7 +245,7 @@ ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata)
struct device_node *np = dev->of_node;
struct device_node *child;
struct ns2_led *led, *leds;
- int num_leds = 0;
+ int ret, num_leds = 0;
num_leds = of_get_child_count(np);
if (!num_leds)
@@ -259,16 +259,16 @@ ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata)
led = leds;
for_each_child_of_node(np, child) {
const char *string;
- int ret, i, num_modes;
+ int i, num_modes;
struct ns2_led_modval *modval;
ret = of_get_named_gpio(child, "cmd-gpio", 0);
if (ret < 0)
- return ret;
+ goto err_node_put;
led->cmd = ret;
ret = of_get_named_gpio(child, "slow-gpio", 0);
if (ret < 0)
- return ret;
+ goto err_node_put;
led->slow = ret;
ret = of_property_read_string(child, "label", &string);
led->name = (ret == 0) ? string : child->name;
@@ -281,7 +281,8 @@ ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata)
if (ret < 0 || ret % 3) {
dev_err(dev,
"Missing or malformed modes-map property\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_node_put;
}
num_modes = ret / 3;
@@ -289,8 +290,10 @@ ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata)
num_modes,
sizeof(struct ns2_led_modval),
GFP_KERNEL);
- if (!modval)
- return -ENOMEM;
+ if (!modval) {
+ ret = -ENOMEM;
+ goto err_node_put;
+ }
for (i = 0; i < num_modes; i++) {
of_property_read_u32_index(child,
@@ -314,6 +317,10 @@ ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata)
pdata->num_leds = num_leds;
return 0;
+
+err_node_put:
+ of_node_put(child);
+ return ret;
}
static const struct of_device_id of_ns2_leds_match[] = {
diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c
index 290871072d65..7d515d5e57bd 100644
--- a/drivers/leds/leds-pca9532.c
+++ b/drivers/leds/leds-pca9532.c
@@ -16,7 +16,7 @@
#include <linux/mutex.h>
#include <linux/workqueue.h>
#include <linux/leds-pca9532.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -467,16 +467,11 @@ pca9532_of_populate_pdata(struct device *dev, struct device_node *np)
{
struct pca9532_platform_data *pdata;
struct device_node *child;
- const struct of_device_id *match;
int devid, maxleds;
int i = 0;
const char *state;
- match = of_match_device(of_pca9532_leds_match, dev);
- if (!match)
- return ERR_PTR(-ENODEV);
-
- devid = (int)(uintptr_t)match->data;
+ devid = (int)(uintptr_t)of_device_get_match_data(dev);
maxleds = pca9532_chip_info_tbl[devid].num_leds;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
@@ -509,7 +504,6 @@ static int pca9532_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int devid;
- const struct of_device_id *of_id;
struct pca9532_data *data = i2c_get_clientdata(client);
struct pca9532_platform_data *pca9532_pdata =
dev_get_platdata(&client->dev);
@@ -525,11 +519,7 @@ static int pca9532_probe(struct i2c_client *client,
dev_err(&client->dev, "no platform data\n");
return -EINVAL;
}
- of_id = of_match_device(of_pca9532_leds_match,
- &client->dev);
- if (unlikely(!of_id))
- return -EINVAL;
- devid = (int)(uintptr_t) of_id->data;
+ devid = (int)(uintptr_t)of_device_get_match_data(&client->dev);
} else {
devid = id->driver_data;
}
diff --git a/drivers/leds/leds-pca963x.c b/drivers/leds/leds-pca963x.c
index 4afc317901a8..66cdc003b8f4 100644
--- a/drivers/leds/leds-pca963x.c
+++ b/drivers/leds/leds-pca963x.c
@@ -40,6 +40,8 @@
#define PCA963X_LED_PWM 0x2 /* Controlled through PWM */
#define PCA963X_LED_GRP_PWM 0x3 /* Controlled through PWM/GRPPWM */
+#define PCA963X_MODE2_OUTDRV 0x04 /* Open-drain or totem pole */
+#define PCA963X_MODE2_INVRT 0x10 /* Normal or inverted direction */
#define PCA963X_MODE2_DMBLNK 0x20 /* Enable blinking */
#define PCA963X_MODE1 0x00
@@ -438,12 +440,12 @@ static int pca963x_probe(struct i2c_client *client,
PCA963X_MODE2);
/* Configure output: open-drain or totem pole (push-pull) */
if (pdata->outdrv == PCA963X_OPEN_DRAIN)
- mode2 |= 0x01;
+ mode2 &= ~PCA963X_MODE2_OUTDRV;
else
- mode2 |= 0x05;
+ mode2 |= PCA963X_MODE2_OUTDRV;
/* Configure direction: normal or inverted */
if (pdata->dir == PCA963X_INVERTED)
- mode2 |= 0x10;
+ mode2 |= PCA963X_MODE2_INVRT;
i2c_smbus_write_byte_data(pca963x->chip->client, PCA963X_MODE2,
mode2);
}
diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
index 48d068f80f11..8b6965a563e9 100644
--- a/drivers/leds/leds-pwm.c
+++ b/drivers/leds/leds-pwm.c
@@ -65,12 +65,6 @@ static int led_pwm_set(struct led_classdev *led_cdev,
return 0;
}
-static inline size_t sizeof_pwm_leds_priv(int num_leds)
-{
- return sizeof(struct led_pwm_priv) +
- (sizeof(struct led_pwm_data) * num_leds);
-}
-
static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
struct led_pwm *led, struct fwnode_handle *fwnode)
{
@@ -111,8 +105,7 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
if (!led_data->period && (led->pwm_period_ns > 0))
led_data->period = led->pwm_period_ns;
- ret = devm_of_led_classdev_register(dev, to_of_node(fwnode),
- &led_data->cdev);
+ ret = devm_led_classdev_register(dev, &led_data->cdev);
if (ret == 0) {
priv->num_leds++;
led_pwm_set(&led_data->cdev, led_data->cdev.brightness);
@@ -175,7 +168,7 @@ static int led_pwm_probe(struct platform_device *pdev)
if (!count)
return -EINVAL;
- priv = devm_kzalloc(&pdev->dev, sizeof_pwm_leds_priv(count),
+ priv = devm_kzalloc(&pdev->dev, struct_size(priv, leds, count),
GFP_KERNEL);
if (!priv)
return -ENOMEM;
diff --git a/drivers/leds/leds-rb532.c b/drivers/leds/leds-rb532.c
index db5af83f0cec..b6447c1721b4 100644
--- a/drivers/leds/leds-rb532.c
+++ b/drivers/leds/leds-rb532.c
@@ -21,7 +21,6 @@ static void rb532_led_set(struct led_classdev *cdev,
{
if (brightness)
set_latch_u5(LO_ULED, 0);
-
else
set_latch_u5(0, LO_ULED);
}
diff --git a/drivers/leds/leds-sc27xx-bltc.c b/drivers/leds/leds-sc27xx-bltc.c
index fecf27fb1cdc..0ede87420bfc 100644
--- a/drivers/leds/leds-sc27xx-bltc.c
+++ b/drivers/leds/leds-sc27xx-bltc.c
@@ -6,7 +6,6 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
-#include <uapi/linux/uleds.h>
/* PMIC global control register definition */
#define SC27XX_MODULE_EN0 0xc08
@@ -46,7 +45,7 @@
#define SC27XX_DELTA_T_MAX (SC27XX_LEDS_STEP * 255)
struct sc27xx_led {
- char name[LED_MAX_NAME_SIZE];
+ struct fwnode_handle *fwnode;
struct led_classdev ldev;
struct sc27xx_led_priv *priv;
u8 line;
@@ -249,19 +248,24 @@ static int sc27xx_led_register(struct device *dev, struct sc27xx_led_priv *priv)
for (i = 0; i < SC27XX_LEDS_MAX; i++) {
struct sc27xx_led *led = &priv->leds[i];
+ struct led_init_data init_data = {};
if (!led->active)
continue;
led->line = i;
led->priv = priv;
- led->ldev.name = led->name;
led->ldev.brightness_set_blocking = sc27xx_led_set;
led->ldev.pattern_set = sc27xx_led_pattern_set;
led->ldev.pattern_clear = sc27xx_led_pattern_clear;
led->ldev.default_trigger = "pattern";
- err = devm_led_classdev_register(dev, &led->ldev);
+ init_data.fwnode = led->fwnode;
+ init_data.devicename = "sc27xx";
+ init_data.default_label = ":";
+
+ err = devm_led_classdev_register_ext(dev, &led->ldev,
+ &init_data);
if (err)
return err;
}
@@ -274,7 +278,6 @@ static int sc27xx_led_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node, *child;
struct sc27xx_led_priv *priv;
- const char *str;
u32 base, count, reg;
int err;
@@ -316,15 +319,8 @@ static int sc27xx_led_probe(struct platform_device *pdev)
return -EINVAL;
}
+ priv->leds[reg].fwnode = of_fwnode_handle(child);
priv->leds[reg].active = true;
-
- err = of_property_read_string(child, "label", &str);
- if (err)
- snprintf(priv->leds[reg].name, LED_MAX_NAME_SIZE,
- "sc27xx::");
- else
- snprintf(priv->leds[reg].name, LED_MAX_NAME_SIZE,
- "sc27xx:%s", str);
}
err = sc27xx_led_register(dev, priv);
diff --git a/drivers/leds/leds-syscon.c b/drivers/leds/leds-syscon.c
index e35dff0050f0..b58f3cafe16f 100644
--- a/drivers/leds/leds-syscon.c
+++ b/drivers/leds/leds-syscon.c
@@ -115,7 +115,7 @@ static int syscon_led_probe(struct platform_device *pdev)
}
sled->cdev.brightness_set = syscon_led_set;
- ret = led_classdev_register(dev, &sled->cdev);
+ ret = devm_led_classdev_register(dev, &sled->cdev);
if (ret < 0)
return ret;
diff --git a/drivers/leds/leds-ti-lmu-common.c b/drivers/leds/leds-ti-lmu-common.c
index adc7293004f1..d7f10ad721ba 100644
--- a/drivers/leds/leds-ti-lmu-common.c
+++ b/drivers/leds/leds-ti-lmu-common.c
@@ -11,10 +11,10 @@
#include <linux/leds-ti-lmu-common.h>
-const static int ramp_table[16] = {2048, 262000, 524000, 1049000, 2090000,
- 4194000, 8389000, 16780000, 33550000, 41940000,
- 50330000, 58720000, 67110000, 83880000,
- 100660000, 117440000};
+static const unsigned int ramp_table[16] = {2048, 262000, 524000, 1049000,
+ 2090000, 4194000, 8389000, 16780000, 33550000,
+ 41940000, 50330000, 58720000, 67110000,
+ 83880000, 100660000, 117440000};
static int ti_lmu_common_update_brightness(struct ti_lmu_bank *lmu_bank,
int brightness)
@@ -54,7 +54,7 @@ int ti_lmu_common_set_brightness(struct ti_lmu_bank *lmu_bank, int brightness)
}
EXPORT_SYMBOL(ti_lmu_common_set_brightness);
-static int ti_lmu_common_convert_ramp_to_index(unsigned int usec)
+static unsigned int ti_lmu_common_convert_ramp_to_index(unsigned int usec)
{
int size = ARRAY_SIZE(ramp_table);
int i;
@@ -78,7 +78,7 @@ static int ti_lmu_common_convert_ramp_to_index(unsigned int usec)
}
}
- return -EINVAL;
+ return 0;
}
int ti_lmu_common_set_ramp(struct ti_lmu_bank *lmu_bank)
@@ -94,9 +94,6 @@ int ti_lmu_common_set_ramp(struct ti_lmu_bank *lmu_bank)
ramp_down = ti_lmu_common_convert_ramp_to_index(lmu_bank->ramp_down_usec);
}
- if (ramp_up < 0 || ramp_down < 0)
- return -EINVAL;
-
ramp = (ramp_up << 4) | ramp_down;
return regmap_write(regmap, lmu_bank->runtime_ramp_reg, ramp);
diff --git a/drivers/leds/leds-tlc591xx.c b/drivers/leds/leds-tlc591xx.c
index 59ff088c7d75..a8911ebd30e5 100644
--- a/drivers/leds/leds-tlc591xx.c
+++ b/drivers/leds/leds-tlc591xx.c
@@ -13,6 +13,7 @@
#include <linux/slab.h>
#define TLC591XX_MAX_LEDS 16
+#define TLC591XX_MAX_BRIGHTNESS 256
#define TLC591XX_REG_MODE1 0x00
#define MODE1_RESPON_ADDR_MASK 0xF0
@@ -112,11 +113,11 @@ tlc591xx_brightness_set(struct led_classdev *led_cdev,
struct tlc591xx_priv *priv = led->priv;
int err;
- switch (brightness) {
+ switch ((int)brightness) {
case 0:
err = tlc591xx_set_ledout(priv, led, LEDOUT_OFF);
break;
- case LED_FULL:
+ case TLC591XX_MAX_BRIGHTNESS:
err = tlc591xx_set_ledout(priv, led, LEDOUT_ON);
break;
default:
@@ -128,51 +129,6 @@ tlc591xx_brightness_set(struct led_classdev *led_cdev,
return err;
}
-static void
-tlc591xx_destroy_devices(struct tlc591xx_priv *priv, unsigned int j)
-{
- int i = j;
-
- while (--i >= 0) {
- if (priv->leds[i].active)
- led_classdev_unregister(&priv->leds[i].ldev);
- }
-}
-
-static int
-tlc591xx_configure(struct device *dev,
- struct tlc591xx_priv *priv,
- const struct tlc591xx *tlc591xx)
-{
- unsigned int i;
- int err = 0;
-
- tlc591xx_set_mode(priv->regmap, MODE2_DIM);
- for (i = 0; i < TLC591XX_MAX_LEDS; i++) {
- struct tlc591xx_led *led = &priv->leds[i];
-
- if (!led->active)
- continue;
-
- led->priv = priv;
- led->led_no = i;
- led->ldev.brightness_set_blocking = tlc591xx_brightness_set;
- led->ldev.max_brightness = LED_FULL;
- err = led_classdev_register(dev, &led->ldev);
- if (err < 0) {
- dev_err(dev, "couldn't register LED %s\n",
- led->ldev.name);
- goto exit;
- }
- }
-
- return 0;
-
-exit:
- tlc591xx_destroy_devices(priv, i);
- return err;
-}
-
static const struct regmap_config tlc591xx_regmap = {
.reg_bits = 8,
.val_bits = 8,
@@ -225,7 +181,16 @@ tlc591xx_probe(struct i2c_client *client,
i2c_set_clientdata(client, priv);
+ err = tlc591xx_set_mode(priv->regmap, MODE2_DIM);
+ if (err < 0)
+ return err;
+
for_each_child_of_node(np, child) {
+ struct tlc591xx_led *led;
+ struct led_init_data init_data = {};
+
+ init_data.fwnode = of_fwnode_handle(child);
+
err = of_property_read_u32(child, "reg", &reg);
if (err) {
of_node_put(child);
@@ -236,22 +201,24 @@ tlc591xx_probe(struct i2c_client *client,
of_node_put(child);
return -EINVAL;
}
- priv->leds[reg].active = true;
- priv->leds[reg].ldev.name =
- of_get_property(child, "label", NULL) ? : child->name;
- priv->leds[reg].ldev.default_trigger =
- of_get_property(child, "linux,default-trigger", NULL);
- }
- return tlc591xx_configure(dev, priv, tlc591xx);
-}
+ led = &priv->leds[reg];
-static int
-tlc591xx_remove(struct i2c_client *client)
-{
- struct tlc591xx_priv *priv = i2c_get_clientdata(client);
-
- tlc591xx_destroy_devices(priv, TLC591XX_MAX_LEDS);
+ led->active = true;
+ led->ldev.default_trigger =
+ of_get_property(child, "linux,default-trigger", NULL);
+ led->priv = priv;
+ led->led_no = reg;
+ led->ldev.brightness_set_blocking = tlc591xx_brightness_set;
+ led->ldev.max_brightness = TLC591XX_MAX_BRIGHTNESS;
+ err = devm_led_classdev_register_ext(dev, &led->ldev,
+ &init_data);
+ if (err < 0) {
+ dev_err(dev, "couldn't register LED %s\n",
+ led->ldev.name);
+ return err;
+ }
+ }
return 0;
}
@@ -268,7 +235,6 @@ static struct i2c_driver tlc591xx_driver = {
.of_match_table = of_match_ptr(of_tlc591xx_leds_match),
},
.probe = tlc591xx_probe,
- .remove = tlc591xx_remove,
.id_table = tlc591xx_id,
};
diff --git a/drivers/leds/leds-tps6105x.c b/drivers/leds/leds-tps6105x.c
new file mode 100644
index 000000000000..09fd88a6c8f0
--- /dev/null
+++ b/drivers/leds/leds-tps6105x.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2019 Sven Van Asbroeck
+ */
+
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/tps6105x.h>
+#include <linux/regmap.h>
+
+struct tps6105x_priv {
+ struct regmap *regmap;
+ struct led_classdev cdev;
+ struct fwnode_handle *fwnode;
+};
+
+static void tps6105x_handle_put(void *data)
+{
+ struct tps6105x_priv *priv = data;
+
+ fwnode_handle_put(priv->fwnode);
+}
+
+static int tps6105x_brightness_set(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ struct tps6105x_priv *priv = container_of(cdev, struct tps6105x_priv,
+ cdev);
+
+ return regmap_update_bits(priv->regmap, TPS6105X_REG_0,
+ TPS6105X_REG0_TORCHC_MASK,
+ brightness << TPS6105X_REG0_TORCHC_SHIFT);
+}
+
+static int tps6105x_led_probe(struct platform_device *pdev)
+{
+ struct tps6105x *tps6105x = dev_get_platdata(&pdev->dev);
+ struct tps6105x_platform_data *pdata = tps6105x->pdata;
+ struct led_init_data init_data = { };
+ struct tps6105x_priv *priv;
+ int ret;
+
+ /* This instance is not set for torch mode so bail out */
+ if (pdata->mode != TPS6105X_MODE_TORCH) {
+ dev_info(&pdev->dev,
+ "chip not in torch mode, exit probe");
+ return -EINVAL;
+ }
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ /* fwnode/devicetree is optional. NULL is allowed for priv->fwnode */
+ priv->fwnode = device_get_next_child_node(pdev->dev.parent, NULL);
+ ret = devm_add_action_or_reset(&pdev->dev, tps6105x_handle_put, priv);
+ if (ret)
+ return ret;
+ priv->regmap = tps6105x->regmap;
+ priv->cdev.brightness_set_blocking = tps6105x_brightness_set;
+ priv->cdev.max_brightness = 7;
+ init_data.devicename = "tps6105x";
+ init_data.default_label = ":torch";
+ init_data.fwnode = priv->fwnode;
+
+ ret = regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
+ TPS6105X_REG0_MODE_MASK |
+ TPS6105X_REG0_TORCHC_MASK,
+ TPS6105X_REG0_MODE_TORCH <<
+ TPS6105X_REG0_MODE_SHIFT);
+ if (ret)
+ return ret;
+
+ return devm_led_classdev_register_ext(&pdev->dev, &priv->cdev,
+ &init_data);
+}
+
+static struct platform_driver led_driver = {
+ .probe = tps6105x_led_probe,
+ .driver = {
+ .name = "tps6105x-leds",
+ },
+};
+
+module_platform_driver(led_driver);
+
+MODULE_DESCRIPTION("TPS6105x LED driver");
+MODULE_AUTHOR("Sven Van Asbroeck <TheSven73@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h
index 47b229469069..2d9eb48bbed9 100644
--- a/drivers/leds/leds.h
+++ b/drivers/leds/leds.h
@@ -23,9 +23,16 @@ void led_set_brightness_nopm(struct led_classdev *led_cdev,
enum led_brightness value);
void led_set_brightness_nosleep(struct led_classdev *led_cdev,
enum led_brightness value);
+ssize_t led_trigger_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t pos, size_t count);
+ssize_t led_trigger_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t pos, size_t count);
extern struct rw_semaphore leds_list_lock;
extern struct list_head leds_list;
extern struct list_head trigger_list;
+extern const char * const led_colors[LED_COLOR_ID_MAX];
#endif /* __LEDS_H_INCLUDED */
diff --git a/drivers/leds/trigger/ledtrig-activity.c b/drivers/leds/trigger/ledtrig-activity.c
index 6a72b7e13719..14ba7faaed9e 100644
--- a/drivers/leds/trigger/ledtrig-activity.c
+++ b/drivers/leds/trigger/ledtrig-activity.c
@@ -57,11 +57,15 @@ static void led_activity_function(struct timer_list *t)
curr_used = 0;
for_each_possible_cpu(i) {
- curr_used += kcpustat_cpu(i).cpustat[CPUTIME_USER]
- + kcpustat_cpu(i).cpustat[CPUTIME_NICE]
- + kcpustat_cpu(i).cpustat[CPUTIME_SYSTEM]
- + kcpustat_cpu(i).cpustat[CPUTIME_SOFTIRQ]
- + kcpustat_cpu(i).cpustat[CPUTIME_IRQ];
+ struct kernel_cpustat kcpustat;
+
+ kcpustat_cpu_fetch(&kcpustat, i);
+
+ curr_used += kcpustat.cpustat[CPUTIME_USER]
+ + kcpustat.cpustat[CPUTIME_NICE]
+ + kcpustat.cpustat[CPUTIME_SYSTEM]
+ + kcpustat.cpustat[CPUTIME_SOFTIRQ]
+ + kcpustat.cpustat[CPUTIME_IRQ];
cpus++;
}
diff --git a/drivers/leds/trigger/ledtrig-gpio.c b/drivers/leds/trigger/ledtrig-gpio.c
index 33cc99a1a16a..dc64679b1a92 100644
--- a/drivers/leds/trigger/ledtrig-gpio.c
+++ b/drivers/leds/trigger/ledtrig-gpio.c
@@ -131,10 +131,10 @@ static ssize_t gpio_trig_gpio_store(struct device *dev,
if (gpio_data->gpio == gpio)
return n;
- if (!gpio) {
- if (gpio_data->gpio != 0)
+ if (!gpio_is_valid(gpio)) {
+ if (gpio_is_valid(gpio_data->gpio))
free_irq(gpio_to_irq(gpio_data->gpio), led);
- gpio_data->gpio = 0;
+ gpio_data->gpio = gpio;
return n;
}
@@ -144,7 +144,7 @@ static ssize_t gpio_trig_gpio_store(struct device *dev,
if (ret) {
dev_err(dev, "request_irq failed with error %d\n", ret);
} else {
- if (gpio_data->gpio != 0)
+ if (gpio_is_valid(gpio_data->gpio))
free_irq(gpio_to_irq(gpio_data->gpio), led);
gpio_data->gpio = gpio;
/* After changing the GPIO, we need to update the LED. */
@@ -172,6 +172,8 @@ static int gpio_trig_activate(struct led_classdev *led)
return -ENOMEM;
gpio_data->led = led;
+ gpio_data->gpio = -ENOENT;
+
led_set_trigger_data(led, gpio_data);
return 0;
@@ -181,7 +183,7 @@ static void gpio_trig_deactivate(struct led_classdev *led)
{
struct gpio_trig_data *gpio_data = led_get_trigger_data(led);
- if (gpio_data->gpio != 0)
+ if (gpio_is_valid(gpio_data->gpio))
free_irq(gpio_to_irq(gpio_data->gpio), led);
kfree(gpio_data);
}
diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c
index 136f86a1627d..d5e774d83021 100644
--- a/drivers/leds/trigger/ledtrig-netdev.c
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -302,10 +302,12 @@ static int netdev_trig_notify(struct notifier_block *nb,
container_of(nb, struct led_netdev_data, notifier);
if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE
- && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER)
+ && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER
+ && evt != NETDEV_CHANGENAME)
return NOTIFY_DONE;
if (!(dev == trigger_data->net_dev ||
+ (evt == NETDEV_CHANGENAME && !strcmp(dev->name, trigger_data->device_name)) ||
(evt == NETDEV_REGISTER && !strcmp(dev->name, trigger_data->device_name))))
return NOTIFY_DONE;
@@ -315,6 +317,7 @@ static int netdev_trig_notify(struct notifier_block *nb,
clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
switch (evt) {
+ case NETDEV_CHANGENAME:
case NETDEV_REGISTER:
if (trigger_data->net_dev)
dev_put(trigger_data->net_dev);
diff --git a/drivers/leds/trigger/ledtrig-pattern.c b/drivers/leds/trigger/ledtrig-pattern.c
index 718729c89440..3abcafe46278 100644
--- a/drivers/leds/trigger/ledtrig-pattern.c
+++ b/drivers/leds/trigger/ledtrig-pattern.c
@@ -455,7 +455,7 @@ static void __exit pattern_trig_exit(void)
module_init(pattern_trig_init);
module_exit(pattern_trig_exit);
-MODULE_AUTHOR("Raphael Teysseyre <rteysseyre@gmail.com");
-MODULE_AUTHOR("Baolin Wang <baolin.wang@linaro.org");
+MODULE_AUTHOR("Raphael Teysseyre <rteysseyre@gmail.com>");
+MODULE_AUTHOR("Baolin Wang <baolin.wang@linaro.org>");
MODULE_DESCRIPTION("LED Pattern trigger");
MODULE_LICENSE("GPL v2");
OpenPOWER on IntegriCloud