aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/leds
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/leds')
-rw-r--r--drivers/leds/Kconfig11
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/led-class.c29
-rw-r--r--drivers/leds/led-core.c36
-rw-r--r--drivers/leds/led-triggers.c16
-rw-r--r--drivers/leds/leds-88pm860x.c1
-rw-r--r--drivers/leds/leds-adp5520.c1
-rw-r--r--drivers/leds/leds-asic3.c1
-rw-r--r--drivers/leds/leds-clevo-mail.c1
-rw-r--r--drivers/leds/leds-cobalt-qube.c1
-rw-r--r--drivers/leds/leds-cobalt-raq.c1
-rw-r--r--drivers/leds/leds-da903x.c1
-rw-r--r--drivers/leds/leds-da9052.c1
-rw-r--r--drivers/leds/leds-gpio.c151
-rw-r--r--drivers/leds/leds-hp6xx.c1
-rw-r--r--drivers/leds/leds-lm3533.c1
-rw-r--r--drivers/leds/leds-lp8788.c1
-rw-r--r--drivers/leds/leds-lp8860.c491
-rw-r--r--drivers/leds/leds-lt3593.c1
-rw-r--r--drivers/leds/leds-max8997.c1
-rw-r--r--drivers/leds/leds-mc13783.c1
-rw-r--r--drivers/leds/leds-menf21bmc.c1
-rw-r--r--drivers/leds/leds-net48xx.c1
-rw-r--r--drivers/leds/leds-netxbig.c1
-rw-r--r--drivers/leds/leds-ns2.c1
-rw-r--r--drivers/leds/leds-ot200.c1
-rw-r--r--drivers/leds/leds-pwm.c1
-rw-r--r--drivers/leds/leds-rb532.c1
-rw-r--r--drivers/leds/leds-regulator.c19
-rw-r--r--drivers/leds/leds-s3c24xx.c1
-rw-r--r--drivers/leds/leds-sunfire.c2
-rw-r--r--drivers/leds/leds-syscon.c71
-rw-r--r--drivers/leds/leds-wm831x-status.c1
-rw-r--r--drivers/leds/leds-wm8350.c1
-rw-r--r--drivers/leds/leds-wrap.c1
-rw-r--r--drivers/leds/leds.h20
-rw-r--r--drivers/leds/trigger/ledtrig-backlight.c8
-rw-r--r--drivers/leds/trigger/ledtrig-default-on.c2
-rw-r--r--drivers/leds/trigger/ledtrig-gpio.c6
-rw-r--r--drivers/leds/trigger/ledtrig-heartbeat.c2
-rw-r--r--drivers/leds/trigger/ledtrig-oneshot.c4
-rw-r--r--drivers/leds/trigger/ledtrig-transient.c10
42 files changed, 722 insertions, 182 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index a210338cfeb1..a6c3d2f153f3 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -250,6 +250,17 @@ config LEDS_LP8788
help
This option enables support for the Keyboard LEDs on the LP8788 PMIC.
+config LEDS_LP8860
+ tristate "LED support for the TI LP8860 4 channel LED driver"
+ depends on LEDS_CLASS && I2C
+ select REGMAP_I2C
+ help
+ If you say yes here you get support for the TI LP8860 4 channel
+ LED driver.
+ This option enables support for the display cluster LEDs
+ on the LP8860 4 channel LED driver using the I2C communication
+ bus.
+
config LEDS_CLEVO_MAIL
tristate "Mail LED on Clevo notebook"
depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index a2b164741465..1c65a191d907 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_LEDS_LP5523) += leds-lp5523.o
obj-$(CONFIG_LEDS_LP5562) += leds-lp5562.o
obj-$(CONFIG_LEDS_LP8501) += leds-lp8501.o
obj-$(CONFIG_LEDS_LP8788) += leds-lp8788.o
+obj-$(CONFIG_LEDS_LP8860) += leds-lp8860.o
obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o
obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o
obj-$(CONFIG_LEDS_IPAQ_MICRO) += leds-ipaq-micro.o
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 7440c58b8e6f..dbeebac38d31 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -40,17 +40,27 @@ static ssize_t brightness_store(struct device *dev,
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
unsigned long state;
- ssize_t ret = -EINVAL;
+ ssize_t ret;
+
+ mutex_lock(&led_cdev->led_access);
+
+ if (led_sysfs_is_disabled(led_cdev)) {
+ ret = -EBUSY;
+ goto unlock;
+ }
ret = kstrtoul(buf, 10, &state);
if (ret)
- return ret;
+ goto unlock;
if (state == LED_OFF)
led_trigger_remove(led_cdev);
- __led_set_brightness(led_cdev, state);
+ led_set_brightness(led_cdev, state);
- return size;
+ ret = size;
+unlock:
+ mutex_unlock(&led_cdev->led_access);
+ return ret;
}
static DEVICE_ATTR_RW(brightness);
@@ -99,7 +109,7 @@ static void led_timer_function(unsigned long data)
unsigned long delay;
if (!led_cdev->blink_delay_on || !led_cdev->blink_delay_off) {
- __led_set_brightness(led_cdev, LED_OFF);
+ led_set_brightness_async(led_cdev, LED_OFF);
return;
}
@@ -122,7 +132,7 @@ static void led_timer_function(unsigned long data)
delay = led_cdev->blink_delay_off;
}
- __led_set_brightness(led_cdev, brightness);
+ led_set_brightness_async(led_cdev, brightness);
/* Return in next iteration if led is in one-shot mode and we are in
* the final blink state so that the led is toggled each delay_on +
@@ -148,7 +158,7 @@ static void set_brightness_delayed(struct work_struct *ws)
led_stop_software_blink(led_cdev);
- __led_set_brightness(led_cdev, led_cdev->delayed_set_value);
+ led_set_brightness_async(led_cdev, led_cdev->delayed_set_value);
}
/**
@@ -214,6 +224,7 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
#ifdef CONFIG_LEDS_TRIGGERS
init_rwsem(&led_cdev->trigger_lock);
#endif
+ mutex_init(&led_cdev->led_access);
/* add to the list of leds */
down_write(&leds_list_lock);
list_add_tail(&led_cdev->node, &leds_list);
@@ -222,6 +233,8 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
if (!led_cdev->max_brightness)
led_cdev->max_brightness = LED_FULL;
+ led_cdev->flags |= SET_BRIGHTNESS_ASYNC;
+
led_update_brightness(led_cdev);
INIT_WORK(&led_cdev->set_brightness_work, set_brightness_delayed);
@@ -267,6 +280,8 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
down_write(&leds_list_lock);
list_del(&led_cdev->node);
up_write(&leds_list_lock);
+
+ mutex_destroy(&led_cdev->led_access);
}
EXPORT_SYMBOL_GPL(led_classdev_unregister);
diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
index aaa8eba9099f..9886dace5ad2 100644
--- a/drivers/leds/led-core.c
+++ b/drivers/leds/led-core.c
@@ -42,13 +42,13 @@ static void led_set_software_blink(struct led_classdev *led_cdev,
/* never on - just set to off */
if (!delay_on) {
- __led_set_brightness(led_cdev, LED_OFF);
+ led_set_brightness_async(led_cdev, LED_OFF);
return;
}
/* never off - just set to brightness */
if (!delay_off) {
- __led_set_brightness(led_cdev, led_cdev->blink_brightness);
+ led_set_brightness_async(led_cdev, led_cdev->blink_brightness);
return;
}
@@ -117,6 +117,8 @@ EXPORT_SYMBOL_GPL(led_stop_software_blink);
void led_set_brightness(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
+ int ret = 0;
+
/* delay brightness setting if need to stop soft-blink timer */
if (led_cdev->blink_delay_on || led_cdev->blink_delay_off) {
led_cdev->delayed_set_value = brightness;
@@ -124,7 +126,17 @@ void led_set_brightness(struct led_classdev *led_cdev,
return;
}
- __led_set_brightness(led_cdev, brightness);
+ if (led_cdev->flags & SET_BRIGHTNESS_ASYNC) {
+ led_set_brightness_async(led_cdev, brightness);
+ return;
+ } else if (led_cdev->flags & SET_BRIGHTNESS_SYNC)
+ ret = led_set_brightness_sync(led_cdev, brightness);
+ else
+ ret = -EINVAL;
+
+ if (ret < 0)
+ dev_dbg(led_cdev->dev, "Setting LED brightness failed (%d)\n",
+ ret);
}
EXPORT_SYMBOL(led_set_brightness);
@@ -143,3 +155,21 @@ int led_update_brightness(struct led_classdev *led_cdev)
return ret;
}
EXPORT_SYMBOL(led_update_brightness);
+
+/* Caller must ensure led_cdev->led_access held */
+void led_sysfs_disable(struct led_classdev *led_cdev)
+{
+ lockdep_assert_held(&led_cdev->led_access);
+
+ led_cdev->flags |= LED_SYSFS_DISABLE;
+}
+EXPORT_SYMBOL_GPL(led_sysfs_disable);
+
+/* Caller must ensure led_cdev->led_access held */
+void led_sysfs_enable(struct led_classdev *led_cdev)
+{
+ lockdep_assert_held(&led_cdev->led_access);
+
+ led_cdev->flags &= ~LED_SYSFS_DISABLE;
+}
+EXPORT_SYMBOL_GPL(led_sysfs_enable);
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index c3734f10fdd5..e8b1120f486d 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -37,6 +37,14 @@ ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
char trigger_name[TRIG_NAME_MAX];
struct led_trigger *trig;
size_t len;
+ int ret = count;
+
+ mutex_lock(&led_cdev->led_access);
+
+ if (led_sysfs_is_disabled(led_cdev)) {
+ ret = -EBUSY;
+ goto unlock;
+ }
trigger_name[sizeof(trigger_name) - 1] = '\0';
strncpy(trigger_name, buf, sizeof(trigger_name) - 1);
@@ -47,7 +55,7 @@ ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
if (!strcmp(trigger_name, "none")) {
led_trigger_remove(led_cdev);
- return count;
+ goto unlock;
}
down_read(&triggers_list_lock);
@@ -58,12 +66,14 @@ ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
up_write(&led_cdev->trigger_lock);
up_read(&triggers_list_lock);
- return count;
+ goto unlock;
}
}
up_read(&triggers_list_lock);
- return -EINVAL;
+unlock:
+ mutex_unlock(&led_cdev->led_access);
+ return ret;
}
EXPORT_SYMBOL_GPL(led_trigger_store);
diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c
index c2def5551ce1..1497a09166d6 100644
--- a/drivers/leds/leds-88pm860x.c
+++ b/drivers/leds/leds-88pm860x.c
@@ -237,7 +237,6 @@ static int pm860x_led_remove(struct platform_device *pdev)
static struct platform_driver pm860x_led_driver = {
.driver = {
.name = "88pm860x-led",
- .owner = THIS_MODULE,
},
.probe = pm860x_led_probe,
.remove = pm860x_led_remove,
diff --git a/drivers/leds/leds-adp5520.c b/drivers/leds/leds-adp5520.c
index 5036d7b4f82e..07e66cae32d3 100644
--- a/drivers/leds/leds-adp5520.c
+++ b/drivers/leds/leds-adp5520.c
@@ -201,7 +201,6 @@ static int adp5520_led_remove(struct platform_device *pdev)
static struct platform_driver adp5520_led_driver = {
.driver = {
.name = "adp5520-led",
- .owner = THIS_MODULE,
},
.probe = adp5520_led_probe,
.remove = adp5520_led_remove,
diff --git a/drivers/leds/leds-asic3.c b/drivers/leds/leds-asic3.c
index 70c74a7f0dfe..1b71eac639f0 100644
--- a/drivers/leds/leds-asic3.c
+++ b/drivers/leds/leds-asic3.c
@@ -168,7 +168,6 @@ static struct platform_driver asic3_led_driver = {
.remove = asic3_led_remove,
.driver = {
.name = "leds-asic3",
- .owner = THIS_MODULE,
.pm = &asic3_led_pm_ops,
},
};
diff --git a/drivers/leds/leds-clevo-mail.c b/drivers/leds/leds-clevo-mail.c
index f58a354428e3..0f9ed1ea0e89 100644
--- a/drivers/leds/leds-clevo-mail.c
+++ b/drivers/leds/leds-clevo-mail.c
@@ -168,7 +168,6 @@ static struct platform_driver clevo_mail_led_driver = {
.remove = clevo_mail_led_remove,
.driver = {
.name = KBUILD_MODNAME,
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/leds/leds-cobalt-qube.c b/drivers/leds/leds-cobalt-qube.c
index 910339d86edf..d97522080491 100644
--- a/drivers/leds/leds-cobalt-qube.c
+++ b/drivers/leds/leds-cobalt-qube.c
@@ -76,7 +76,6 @@ static struct platform_driver cobalt_qube_led_driver = {
.remove = cobalt_qube_led_remove,
.driver = {
.name = "cobalt-qube-leds",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/leds/leds-cobalt-raq.c b/drivers/leds/leds-cobalt-raq.c
index 001088b31373..06dbe18a2065 100644
--- a/drivers/leds/leds-cobalt-raq.c
+++ b/drivers/leds/leds-cobalt-raq.c
@@ -124,7 +124,6 @@ static struct platform_driver cobalt_raq_led_driver = {
.remove = cobalt_raq_led_remove,
.driver = {
.name = "cobalt-raq-leds",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/leds/leds-da903x.c b/drivers/leds/leds-da903x.c
index 54b8b5216b8b..952ba96e5b38 100644
--- a/drivers/leds/leds-da903x.c
+++ b/drivers/leds/leds-da903x.c
@@ -144,7 +144,6 @@ static int da903x_led_remove(struct platform_device *pdev)
static struct platform_driver da903x_led_driver = {
.driver = {
.name = "da903x-led",
- .owner = THIS_MODULE,
},
.probe = da903x_led_probe,
.remove = da903x_led_remove,
diff --git a/drivers/leds/leds-da9052.c b/drivers/leds/leds-da9052.c
index e4da1f460ac5..28291b6acc8e 100644
--- a/drivers/leds/leds-da9052.c
+++ b/drivers/leds/leds-da9052.c
@@ -199,7 +199,6 @@ static int da9052_led_remove(struct platform_device *pdev)
static struct platform_driver da9052_led_driver = {
.driver = {
.name = "da9052-leds",
- .owner = THIS_MODULE,
},
.probe = da9052_led_probe,
.remove = da9052_led_remove,
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index b4518c8751c8..8a8ba11c5c14 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -12,25 +12,23 @@
*/
#include <linux/err.h>
#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/leds.h>
#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
-#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
struct gpio_led_data {
struct led_classdev cdev;
- unsigned gpio;
+ struct gpio_desc *gpiod;
struct work_struct work;
u8 new_level;
u8 can_sleep;
- u8 active_low;
u8 blinking;
- int (*platform_gpio_blink_set)(unsigned gpio, int state,
+ int (*platform_gpio_blink_set)(struct gpio_desc *desc, int state,
unsigned long *delay_on, unsigned long *delay_off);
};
@@ -40,12 +38,11 @@ static void gpio_led_work(struct work_struct *work)
container_of(work, struct gpio_led_data, work);
if (led_dat->blinking) {
- led_dat->platform_gpio_blink_set(led_dat->gpio,
- led_dat->new_level,
- NULL, NULL);
+ led_dat->platform_gpio_blink_set(led_dat->gpiod,
+ led_dat->new_level, NULL, NULL);
led_dat->blinking = 0;
} else
- gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level);
+ gpiod_set_value_cansleep(led_dat->gpiod, led_dat->new_level);
}
static void gpio_led_set(struct led_classdev *led_cdev,
@@ -60,9 +57,6 @@ static void gpio_led_set(struct led_classdev *led_cdev,
else
level = 1;
- if (led_dat->active_low)
- level = !level;
-
/* Setting GPIOs with I2C/etc requires a task context, and we don't
* seem to have a reliable way to know if we're already in one; so
* let's just assume the worst.
@@ -72,11 +66,11 @@ static void gpio_led_set(struct led_classdev *led_cdev,
schedule_work(&led_dat->work);
} else {
if (led_dat->blinking) {
- led_dat->platform_gpio_blink_set(led_dat->gpio, level,
+ led_dat->platform_gpio_blink_set(led_dat->gpiod, level,
NULL, NULL);
led_dat->blinking = 0;
} else
- gpio_set_value(led_dat->gpio, level);
+ gpiod_set_value(led_dat->gpiod, level);
}
}
@@ -87,34 +81,49 @@ static int gpio_blink_set(struct led_classdev *led_cdev,
container_of(led_cdev, struct gpio_led_data, cdev);
led_dat->blinking = 1;
- return led_dat->platform_gpio_blink_set(led_dat->gpio, GPIO_LED_BLINK,
+ return led_dat->platform_gpio_blink_set(led_dat->gpiod, GPIO_LED_BLINK,
delay_on, delay_off);
}
static int create_gpio_led(const struct gpio_led *template,
struct gpio_led_data *led_dat, struct device *parent,
- int (*blink_set)(unsigned, int, unsigned long *, unsigned long *))
+ int (*blink_set)(struct gpio_desc *, int, unsigned long *,
+ unsigned long *))
{
int ret, state;
- led_dat->gpio = -1;
+ led_dat->gpiod = template->gpiod;
+ if (!led_dat->gpiod) {
+ /*
+ * This is the legacy code path for platform code that
+ * still uses GPIO numbers. Ultimately we would like to get
+ * rid of this block completely.
+ */
+ unsigned long flags = 0;
+
+ /* skip leds that aren't available */
+ if (!gpio_is_valid(template->gpio)) {
+ dev_info(parent, "Skipping unavailable LED gpio %d (%s)\n",
+ template->gpio, template->name);
+ return 0;
+ }
- /* skip leds that aren't available */
- if (!gpio_is_valid(template->gpio)) {
- dev_info(parent, "Skipping unavailable LED gpio %d (%s)\n",
- template->gpio, template->name);
- return 0;
- }
+ if (template->active_low)
+ flags |= GPIOF_ACTIVE_LOW;
- ret = devm_gpio_request(parent, template->gpio, template->name);
- if (ret < 0)
- return ret;
+ ret = devm_gpio_request_one(parent, template->gpio, flags,
+ template->name);
+ if (ret < 0)
+ return ret;
+
+ led_dat->gpiod = gpio_to_desc(template->gpio);
+ if (IS_ERR(led_dat->gpiod))
+ return PTR_ERR(led_dat->gpiod);
+ }
led_dat->cdev.name = template->name;
led_dat->cdev.default_trigger = template->default_trigger;
- led_dat->gpio = template->gpio;
- led_dat->can_sleep = gpio_cansleep(template->gpio);
- led_dat->active_low = template->active_low;
+ led_dat->can_sleep = gpiod_cansleep(led_dat->gpiod);
led_dat->blinking = 0;
if (blink_set) {
led_dat->platform_gpio_blink_set = blink_set;
@@ -122,30 +131,24 @@ static int create_gpio_led(const struct gpio_led *template,
}
led_dat->cdev.brightness_set = gpio_led_set;
if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP)
- state = !!gpio_get_value_cansleep(led_dat->gpio) ^ led_dat->active_low;
+ state = !!gpiod_get_value_cansleep(led_dat->gpiod);
else
state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
if (!template->retain_state_suspended)
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
- ret = gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state);
+ ret = gpiod_direction_output(led_dat->gpiod, state);
if (ret < 0)
return ret;
INIT_WORK(&led_dat->work, gpio_led_work);
- ret = led_classdev_register(parent, &led_dat->cdev);
- if (ret < 0)
- return ret;
-
- return 0;
+ return led_classdev_register(parent, &led_dat->cdev);
}
static void delete_gpio_led(struct gpio_led_data *led)
{
- if (!gpio_is_valid(led->gpio))
- return;
led_classdev_unregister(&led->cdev);
cancel_work_sync(&led->work);
}
@@ -161,40 +164,47 @@ static inline int sizeof_gpio_leds_priv(int num_leds)
(sizeof(struct gpio_led_data) * num_leds);
}
-/* Code to create from OpenFirmware platform devices */
-#ifdef CONFIG_OF_GPIO
-static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
+static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node, *child;
+ struct device *dev = &pdev->dev;
+ struct fwnode_handle *child;
struct gpio_leds_priv *priv;
int count, ret;
+ struct device_node *np;
- /* count LEDs in this device, so we know how much to allocate */
- count = of_get_available_child_count(np);
+ count = device_get_child_node_count(dev);
if (!count)
return ERR_PTR(-ENODEV);
- for_each_available_child_of_node(np, child)
- if (of_get_gpio(child, 0) == -EPROBE_DEFER)
- return ERR_PTR(-EPROBE_DEFER);
-
- priv = devm_kzalloc(&pdev->dev, sizeof_gpio_leds_priv(count),
- GFP_KERNEL);
+ priv = devm_kzalloc(dev, sizeof_gpio_leds_priv(count), GFP_KERNEL);
if (!priv)
return ERR_PTR(-ENOMEM);
- for_each_available_child_of_node(np, child) {
+ device_for_each_child_node(dev, child) {
struct gpio_led led = {};
- enum of_gpio_flags flags;
- const char *state;
-
- led.gpio = of_get_gpio_flags(child, 0, &flags);
- led.active_low = flags & OF_GPIO_ACTIVE_LOW;
- led.name = of_get_property(child, "label", NULL) ? : child->name;
- led.default_trigger =
- of_get_property(child, "linux,default-trigger", NULL);
- state = of_get_property(child, "default-state", NULL);
- if (state) {
+ const char *state = NULL;
+
+ led.gpiod = devm_get_gpiod_from_child(dev, child);
+ if (IS_ERR(led.gpiod)) {
+ fwnode_handle_put(child);
+ goto err;
+ }
+
+ np = of_node(child);
+
+ if (fwnode_property_present(child, "label")) {
+ fwnode_property_read_string(child, "label", &led.name);
+ } else {
+ if (IS_ENABLED(CONFIG_OF) && !led.name && np)
+ led.name = np->name;
+ if (!led.name)
+ return ERR_PTR(-EINVAL);
+ }
+ fwnode_property_read_string(child, "linux,default-trigger",
+ &led.default_trigger);
+
+ if (!fwnode_property_read_string(child, "linux,default_state",
+ &state)) {
if (!strcmp(state, "keep"))
led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
else if (!strcmp(state, "on"))
@@ -203,13 +213,13 @@ static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
led.default_state = LEDS_GPIO_DEFSTATE_OFF;
}
- if (of_get_property(child, "retain-state-suspended", NULL))
+ if (fwnode_property_present(child, "retain-state-suspended"))
led.retain_state_suspended = 1;
ret = create_gpio_led(&led, &priv->leds[priv->num_leds++],
- &pdev->dev, NULL);
+ dev, NULL);
if (ret < 0) {
- of_node_put(child);
+ fwnode_handle_put(child);
goto err;
}
}
@@ -228,12 +238,6 @@ static const struct of_device_id of_gpio_leds_match[] = {
};
MODULE_DEVICE_TABLE(of, of_gpio_leds_match);
-#else /* CONFIG_OF_GPIO */
-static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
-{
- return ERR_PTR(-ENODEV);
-}
-#endif /* CONFIG_OF_GPIO */
static int gpio_led_probe(struct platform_device *pdev)
{
@@ -261,7 +265,7 @@ static int gpio_led_probe(struct platform_device *pdev)
}
}
} else {
- priv = gpio_leds_create_of(pdev);
+ priv = gpio_leds_create(pdev);
if (IS_ERR(priv))
return PTR_ERR(priv);
}
@@ -287,8 +291,7 @@ static struct platform_driver gpio_led_driver = {
.remove = gpio_led_remove,
.driver = {
.name = "leds-gpio",
- .owner = THIS_MODULE,
- .of_match_table = of_match_ptr(of_gpio_leds_match),
+ .of_match_table = of_gpio_leds_match,
},
};
diff --git a/drivers/leds/leds-hp6xx.c b/drivers/leds/leds-hp6xx.c
index d61a98896c71..0b84c0113126 100644
--- a/drivers/leds/leds-hp6xx.c
+++ b/drivers/leds/leds-hp6xx.c
@@ -83,7 +83,6 @@ static struct platform_driver hp6xxled_driver = {
.remove = hp6xxled_remove,
.driver = {
.name = "hp6xx-led",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/leds/leds-lm3533.c b/drivers/leds/leds-lm3533.c
index cbf61a40137d..6e2e02035dd7 100644
--- a/drivers/leds/leds-lm3533.c
+++ b/drivers/leds/leds-lm3533.c
@@ -766,7 +766,6 @@ static void lm3533_led_shutdown(struct platform_device *pdev)
static struct platform_driver lm3533_led_driver = {
.driver = {
.name = "lm3533-leds",
- .owner = THIS_MODULE,
},
.probe = lm3533_led_probe,
.remove = lm3533_led_remove,
diff --git a/drivers/leds/leds-lp8788.c b/drivers/leds/leds-lp8788.c
index 7c2cb384e7ae..3409f03c1fa8 100644
--- a/drivers/leds/leds-lp8788.c
+++ b/drivers/leds/leds-lp8788.c
@@ -183,7 +183,6 @@ static struct platform_driver lp8788_led_driver = {
.remove = lp8788_led_remove,
.driver = {
.name = LP8788_DEV_KEYLED,
- .owner = THIS_MODULE,
},
};
module_platform_driver(lp8788_led_driver);
diff --git a/drivers/leds/leds-lp8860.c b/drivers/leds/leds-lp8860.c
new file mode 100644
index 000000000000..840e93f3ab3e
--- /dev/null
+++ b/drivers/leds/leds-lp8860.c
@@ -0,0 +1,491 @@
+/*
+ * TI LP8860 4-Channel LED Driver
+ *
+ * Copyright (C) 2014 Texas Instruments
+ *
+ * Author: Dan Murphy <dmurphy@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/leds.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/slab.h>
+
+#define LP8860_DISP_CL1_BRT_MSB 0x00
+#define LP8860_DISP_CL1_BRT_LSB 0x01
+#define LP8860_DISP_CL1_CURR_MSB 0x02
+#define LP8860_DISP_CL1_CURR_LSB 0x03
+#define LP8860_CL2_BRT_MSB 0x04
+#define LP8860_CL2_BRT_LSB 0x05
+#define LP8860_CL2_CURRENT 0x06
+#define LP8860_CL3_BRT_MSB 0x07
+#define LP8860_CL3_BRT_LSB 0x08
+#define LP8860_CL3_CURRENT 0x09
+#define LP8860_CL4_BRT_MSB 0x0a
+#define LP8860_CL4_BRT_LSB 0x0b
+#define LP8860_CL4_CURRENT 0x0c
+#define LP8860_CONFIG 0x0d
+#define LP8860_STATUS 0x0e
+#define LP8860_FAULT 0x0f
+#define LP8860_LED_FAULT 0x10
+#define LP8860_FAULT_CLEAR 0x11
+#define LP8860_ID 0x12
+#define LP8860_TEMP_MSB 0x13
+#define LP8860_TEMP_LSB 0x14
+#define LP8860_DISP_LED_CURR_MSB 0x15
+#define LP8860_DISP_LED_CURR_LSB 0x16
+#define LP8860_DISP_LED_PWM_MSB 0x17
+#define LP8860_DISP_LED_PWM_LSB 0x18
+#define LP8860_EEPROM_CNTRL 0x19
+#define LP8860_EEPROM_UNLOCK 0x1a
+
+#define LP8860_EEPROM_REG_0 0x60
+#define LP8860_EEPROM_REG_1 0x61
+#define LP8860_EEPROM_REG_2 0x62
+#define LP8860_EEPROM_REG_3 0x63
+#define LP8860_EEPROM_REG_4 0x64
+#define LP8860_EEPROM_REG_5 0x65
+#define LP8860_EEPROM_REG_6 0x66
+#define LP8860_EEPROM_REG_7 0x67
+#define LP8860_EEPROM_REG_8 0x68
+#define LP8860_EEPROM_REG_9 0x69
+#define LP8860_EEPROM_REG_10 0x6a
+#define LP8860_EEPROM_REG_11 0x6b
+#define LP8860_EEPROM_REG_12 0x6c
+#define LP8860_EEPROM_REG_13 0x6d
+#define LP8860_EEPROM_REG_14 0x6e
+#define LP8860_EEPROM_REG_15 0x6f
+#define LP8860_EEPROM_REG_16 0x70
+#define LP8860_EEPROM_REG_17 0x71
+#define LP8860_EEPROM_REG_18 0x72
+#define LP8860_EEPROM_REG_19 0x73
+#define LP8860_EEPROM_REG_20 0x74
+#define LP8860_EEPROM_REG_21 0x75
+#define LP8860_EEPROM_REG_22 0x76
+#define LP8860_EEPROM_REG_23 0x77
+#define LP8860_EEPROM_REG_24 0x78
+
+#define LP8860_LOCK_EEPROM 0x00
+#define LP8860_UNLOCK_EEPROM 0x01
+#define LP8860_PROGRAM_EEPROM 0x02
+#define LP8860_EEPROM_CODE_1 0x08
+#define LP8860_EEPROM_CODE_2 0xba
+#define LP8860_EEPROM_CODE_3 0xef
+
+#define LP8860_CLEAR_FAULTS 0x01
+
+#define LP8860_DISP_LED_NAME "display_cluster"
+
+/**
+ * struct lp8860_led -
+ * @lock - Lock for reading/writing the device
+ * @work - Work item used to off load the brightness register writes
+ * @client - Pointer to the I2C client
+ * @led_dev - led class device pointer
+ * @regmap - Devices register map
+ * @eeprom_regmap - EEPROM register map
+ * @enable_gpio - VDDIO/EN gpio to enable communication interface
+ * @regulator - LED supply regulator pointer
+ * @brightness - Current brightness value requested
+ * @label - LED label
+**/
+struct lp8860_led {
+ struct mutex lock;
+ struct work_struct work;
+ struct i2c_client *client;
+ struct led_classdev led_dev;
+ struct regmap *regmap;
+ struct regmap *eeprom_regmap;
+ struct gpio_desc *enable_gpio;
+ struct regulator *regulator;
+ enum led_brightness brightness;
+ const char *label;
+};
+
+struct lp8860_eeprom_reg {
+ uint8_t reg;
+ uint8_t value;
+};
+
+static struct lp8860_eeprom_reg lp8860_eeprom_disp_regs[] = {
+ { LP8860_EEPROM_REG_0, 0xed },
+ { LP8860_EEPROM_REG_1, 0xdf },
+ { LP8860_EEPROM_REG_2, 0xdc },
+ { LP8860_EEPROM_REG_3, 0xf0 },
+ { LP8860_EEPROM_REG_4, 0xdf },
+ { LP8860_EEPROM_REG_5, 0xe5 },
+ { LP8860_EEPROM_REG_6, 0xf2 },
+ { LP8860_EEPROM_REG_7, 0x77 },
+ { LP8860_EEPROM_REG_8, 0x77 },
+ { LP8860_EEPROM_REG_9, 0x71 },
+ { LP8860_EEPROM_REG_10, 0x3f },
+ { LP8860_EEPROM_REG_11, 0xb7 },
+ { LP8860_EEPROM_REG_12, 0x17 },
+ { LP8860_EEPROM_REG_13, 0xef },
+ { LP8860_EEPROM_REG_14, 0xb0 },
+ { LP8860_EEPROM_REG_15, 0x87 },
+ { LP8860_EEPROM_REG_16, 0xce },
+ { LP8860_EEPROM_REG_17, 0x72 },
+ { LP8860_EEPROM_REG_18, 0xe5 },
+ { LP8860_EEPROM_REG_19, 0xdf },
+ { LP8860_EEPROM_REG_20, 0x35 },
+ { LP8860_EEPROM_REG_21, 0x06 },
+ { LP8860_EEPROM_REG_22, 0xdc },
+ { LP8860_EEPROM_REG_23, 0x88 },
+ { LP8860_EEPROM_REG_24, 0x3E },
+};
+
+static int lp8860_unlock_eeprom(struct lp8860_led *led, int lock)
+{
+ int ret;
+
+ mutex_lock(&led->lock);
+
+ if (lock == LP8860_UNLOCK_EEPROM) {
+ ret = regmap_write(led->regmap,
+ LP8860_EEPROM_UNLOCK,
+ LP8860_EEPROM_CODE_1);
+ if (ret) {
+ dev_err(&led->client->dev, "EEPROM Unlock failed\n");
+ goto out;
+ }
+
+ ret = regmap_write(led->regmap,
+ LP8860_EEPROM_UNLOCK,
+ LP8860_EEPROM_CODE_2);
+ if (ret) {
+ dev_err(&led->client->dev, "EEPROM Unlock failed\n");
+ goto out;
+ }
+ ret = regmap_write(led->regmap,
+ LP8860_EEPROM_UNLOCK,
+ LP8860_EEPROM_CODE_3);
+ if (ret) {
+ dev_err(&led->client->dev, "EEPROM Unlock failed\n");
+ goto out;
+ }
+ } else {
+ ret = regmap_write(led->regmap,
+ LP8860_EEPROM_UNLOCK,
+ LP8860_LOCK_EEPROM);
+ }
+
+out:
+ mutex_unlock(&led->lock);
+ return ret;
+}
+
+static int lp8860_fault_check(struct lp8860_led *led)
+{
+ int ret, fault;
+ unsigned int read_buf;
+
+ ret = regmap_read(led->regmap, LP8860_LED_FAULT, &read_buf);
+ if (ret)
+ goto out;
+
+ fault = read_buf;
+
+ ret = regmap_read(led->regmap, LP8860_FAULT, &read_buf);
+ if (ret)
+ goto out;
+
+ fault |= read_buf;
+
+ /* Attempt to clear any faults */
+ if (fault)
+ ret = regmap_write(led->regmap, LP8860_FAULT_CLEAR,
+ LP8860_CLEAR_FAULTS);
+out:
+ return ret;
+}
+
+static void lp8860_led_brightness_work(struct work_struct *work)
+{
+ struct lp8860_led *led = container_of(work, struct lp8860_led, work);
+ int ret;
+ int disp_brightness = led->brightness * 255;
+
+ mutex_lock(&led->lock);
+
+ ret = lp8860_fault_check(led);
+ if (ret) {
+ dev_err(&led->client->dev, "Cannot read/clear faults\n");
+ goto out;
+ }
+
+ ret = regmap_write(led->regmap, LP8860_DISP_CL1_BRT_MSB,
+ (disp_brightness & 0xff00) >> 8);
+ if (ret) {
+ dev_err(&led->client->dev, "Cannot write CL1 MSB\n");
+ goto out;
+ }
+
+ ret = regmap_write(led->regmap, LP8860_DISP_CL1_BRT_LSB,
+ disp_brightness & 0xff);
+ if (ret) {
+ dev_err(&led->client->dev, "Cannot write CL1 LSB\n");
+ goto out;
+ }
+out:
+ mutex_unlock(&led->lock);
+}
+
+static void lp8860_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness brt_val)
+{
+ struct lp8860_led *led =
+ container_of(led_cdev, struct lp8860_led, led_dev);
+
+ led->brightness = brt_val;
+ schedule_work(&led->work);
+}
+
+static int lp8860_init(struct lp8860_led *led)
+{
+ unsigned int read_buf;
+ int ret, i, reg_count;
+
+ if (led->enable_gpio)
+ gpiod_direction_output(led->enable_gpio, 1);
+
+ ret = lp8860_fault_check(led);
+ if (ret)
+ goto out;
+
+ ret = regmap_read(led->regmap, LP8860_STATUS, &read_buf);
+ if (ret)
+ goto out;
+
+ ret = lp8860_unlock_eeprom(led, LP8860_UNLOCK_EEPROM);
+ if (ret) {
+ dev_err(&led->client->dev, "Failed unlocking EEPROM\n");
+ goto out;
+ }
+
+ reg_count = ARRAY_SIZE(lp8860_eeprom_disp_regs) / sizeof(lp8860_eeprom_disp_regs[0]);
+ for (i = 0; i < reg_count; i++) {
+ ret = regmap_write(led->eeprom_regmap,
+ lp8860_eeprom_disp_regs[i].reg,
+ lp8860_eeprom_disp_regs[i].value);
+ if (ret) {
+ dev_err(&led->client->dev, "Failed writing EEPROM\n");
+ goto out;
+ }
+ }
+
+ ret = lp8860_unlock_eeprom(led, LP8860_LOCK_EEPROM);
+ if (ret)
+ goto out;
+
+ ret = regmap_write(led->regmap,
+ LP8860_EEPROM_CNTRL,
+ LP8860_PROGRAM_EEPROM);
+ if (ret)
+ dev_err(&led->client->dev, "Failed programming EEPROM\n");
+out:
+ if (ret)
+ if (led->enable_gpio)
+ gpiod_direction_output(led->enable_gpio, 0);
+ return ret;
+}
+
+static struct reg_default lp8860_reg_defs[] = {
+ { LP8860_DISP_CL1_BRT_MSB, 0x00},
+ { LP8860_DISP_CL1_BRT_LSB, 0x00},
+ { LP8860_DISP_CL1_CURR_MSB, 0x00},
+ { LP8860_DISP_CL1_CURR_LSB, 0x00},
+ { LP8860_CL2_BRT_MSB, 0x00},
+ { LP8860_CL2_BRT_LSB, 0x00},
+ { LP8860_CL2_CURRENT, 0x00},
+ { LP8860_CL3_BRT_MSB, 0x00},
+ { LP8860_CL3_BRT_LSB, 0x00},
+ { LP8860_CL3_CURRENT, 0x00},
+ { LP8860_CL4_BRT_MSB, 0x00},
+ { LP8860_CL4_BRT_LSB, 0x00},
+ { LP8860_CL4_CURRENT, 0x00},
+ { LP8860_CONFIG, 0x00},
+ { LP8860_FAULT_CLEAR, 0x00},
+ { LP8860_EEPROM_CNTRL, 0x80},
+ { LP8860_EEPROM_UNLOCK, 0x00},
+};
+
+static const struct regmap_config lp8860_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = LP8860_EEPROM_UNLOCK,
+ .reg_defaults = lp8860_reg_defs,
+ .num_reg_defaults = ARRAY_SIZE(lp8860_reg_defs),
+ .cache_type = REGCACHE_NONE,
+};
+
+static struct reg_default lp8860_eeprom_defs[] = {
+ { LP8860_EEPROM_REG_0, 0x00 },
+ { LP8860_EEPROM_REG_1, 0x00 },
+ { LP8860_EEPROM_REG_2, 0x00 },
+ { LP8860_EEPROM_REG_3, 0x00 },
+ { LP8860_EEPROM_REG_4, 0x00 },
+ { LP8860_EEPROM_REG_5, 0x00 },
+ { LP8860_EEPROM_REG_6, 0x00 },
+ { LP8860_EEPROM_REG_7, 0x00 },
+ { LP8860_EEPROM_REG_8, 0x00 },
+ { LP8860_EEPROM_REG_9, 0x00 },
+ { LP8860_EEPROM_REG_10, 0x00 },
+ { LP8860_EEPROM_REG_11, 0x00 },
+ { LP8860_EEPROM_REG_12, 0x00 },
+ { LP8860_EEPROM_REG_13, 0x00 },
+ { LP8860_EEPROM_REG_14, 0x00 },
+ { LP8860_EEPROM_REG_15, 0x00 },
+ { LP8860_EEPROM_REG_16, 0x00 },
+ { LP8860_EEPROM_REG_17, 0x00 },
+ { LP8860_EEPROM_REG_18, 0x00 },
+ { LP8860_EEPROM_REG_19, 0x00 },
+ { LP8860_EEPROM_REG_20, 0x00 },
+ { LP8860_EEPROM_REG_21, 0x00 },
+ { LP8860_EEPROM_REG_22, 0x00 },
+ { LP8860_EEPROM_REG_23, 0x00 },
+ { LP8860_EEPROM_REG_24, 0x00 },
+};
+
+static const struct regmap_config lp8860_eeprom_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = LP8860_EEPROM_REG_24,
+ .reg_defaults = lp8860_eeprom_defs,
+ .num_reg_defaults = ARRAY_SIZE(lp8860_eeprom_defs),
+ .cache_type = REGCACHE_NONE,
+};
+
+static int lp8860_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret;
+ struct lp8860_led *led;
+ struct device_node *np = client->dev.of_node;
+
+ led = devm_kzalloc(&client->dev, sizeof(*led), GFP_KERNEL);
+ if (!led)
+ return -ENOMEM;
+
+ led->label = LP8860_DISP_LED_NAME;
+
+ if (client->dev.of_node) {
+ ret = of_property_read_string(np, "label", &led->label);
+ if (ret) {
+ dev_err(&client->dev, "Missing label in dt\n");
+ return -EINVAL;
+ }
+ }
+
+ led->enable_gpio = devm_gpiod_get(&client->dev, "enable");
+ if (IS_ERR(led->enable_gpio))
+ led->enable_gpio = NULL;
+ else
+ gpiod_direction_output(led->enable_gpio, 0);
+
+ led->regulator = devm_regulator_get(&client->dev, "vled");
+ if (IS_ERR(led->regulator))
+ led->regulator = NULL;
+
+ led->client = client;
+ led->led_dev.name = led->label;
+ led->led_dev.max_brightness = LED_FULL;
+ led->led_dev.brightness_set = lp8860_brightness_set;
+
+ mutex_init(&led->lock);
+ INIT_WORK(&led->work, lp8860_led_brightness_work);
+
+ i2c_set_clientdata(client, led);
+
+ led->regmap = devm_regmap_init_i2c(client, &lp8860_regmap_config);
+ if (IS_ERR(led->regmap)) {
+ ret = PTR_ERR(led->regmap);
+ dev_err(&client->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ led->eeprom_regmap = devm_regmap_init_i2c(client, &lp8860_eeprom_regmap_config);
+ if (IS_ERR(led->eeprom_regmap)) {
+ ret = PTR_ERR(led->eeprom_regmap);
+ dev_err(&client->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = lp8860_init(led);
+ if (ret)
+ return ret;
+
+ ret = led_classdev_register(&client->dev, &led->led_dev);
+ if (ret) {
+ dev_err(&client->dev, "led register err: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int lp8860_remove(struct i2c_client *client)
+{
+ struct lp8860_led *led = i2c_get_clientdata(client);
+ int ret;
+
+ led_classdev_unregister(&led->led_dev);
+ cancel_work_sync(&led->work);
+
+ 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");
+ }
+
+ return 0;
+}
+
+static const struct i2c_device_id lp8860_id[] = {
+ { "lp8860", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, lp8860_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id of_lp8860_leds_match[] = {
+ { .compatible = "ti,lp8860", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, of_lp8860_leds_match);
+#endif
+
+static struct i2c_driver lp8860_driver = {
+ .driver = {
+ .name = "lp8860",
+ .of_match_table = of_match_ptr(of_lp8860_leds_match),
+ },
+ .probe = lp8860_probe,
+ .remove = lp8860_remove,
+ .id_table = lp8860_id,
+};
+module_i2c_driver(lp8860_driver);
+
+MODULE_DESCRIPTION("Texas Instruments LP8860 LED drvier");
+MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-lt3593.c b/drivers/leds/leds-lt3593.c
index 059f5b1f3553..9f41124765cc 100644
--- a/drivers/leds/leds-lt3593.c
+++ b/drivers/leds/leds-lt3593.c
@@ -184,7 +184,6 @@ static struct platform_driver lt3593_led_driver = {
.remove = lt3593_led_remove,
.driver = {
.name = "leds-lt3593",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/leds/leds-max8997.c b/drivers/leds/leds-max8997.c
index 607bc2755aba..c592aa5662bb 100644
--- a/drivers/leds/leds-max8997.c
+++ b/drivers/leds/leds-max8997.c
@@ -303,7 +303,6 @@ static int max8997_led_remove(struct platform_device *pdev)
static struct platform_driver max8997_led_driver = {
.driver = {
.name = "max8997-led",
- .owner = THIS_MODULE,
},
.probe = max8997_led_probe,
.remove = max8997_led_remove,
diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c
index f1db88e25138..85c3714e1b5a 100644
--- a/drivers/leds/leds-mc13783.c
+++ b/drivers/leds/leds-mc13783.c
@@ -325,7 +325,6 @@ MODULE_DEVICE_TABLE(platform, mc13xxx_led_id_table);
static struct platform_driver mc13xxx_led_driver = {
.driver = {
.name = "mc13xxx-led",
- .owner = THIS_MODULE,
},
.remove = mc13xxx_led_remove,
.id_table = mc13xxx_led_id_table,
diff --git a/drivers/leds/leds-menf21bmc.c b/drivers/leds/leds-menf21bmc.c
index 89dd57769e3b..4b9eea815b1a 100644
--- a/drivers/leds/leds-menf21bmc.c
+++ b/drivers/leds/leds-menf21bmc.c
@@ -119,7 +119,6 @@ static struct platform_driver menf21bmc_led = {
.remove = menf21bmc_led_remove,
.driver = {
.name = "menf21bmc_led",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/leds/leds-net48xx.c b/drivers/leds/leds-net48xx.c
index 27d06c528246..ec3a2e8adcae 100644
--- a/drivers/leds/leds-net48xx.c
+++ b/drivers/leds/leds-net48xx.c
@@ -53,7 +53,6 @@ static struct platform_driver net48xx_led_driver = {
.remove = net48xx_led_remove,
.driver = {
.name = DRVNAME,
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/leds/leds-netxbig.c b/drivers/leds/leds-netxbig.c
index 64fde485dcaa..26515c27ea8c 100644
--- a/drivers/leds/leds-netxbig.c
+++ b/drivers/leds/leds-netxbig.c
@@ -404,7 +404,6 @@ static struct platform_driver netxbig_led_driver = {
.remove = netxbig_led_remove,
.driver = {
.name = "leds-netxbig",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c
index 231993d1fe21..1fd6adbb43b7 100644
--- a/drivers/leds/leds-ns2.c
+++ b/drivers/leds/leds-ns2.c
@@ -380,7 +380,6 @@ static struct platform_driver ns2_led_driver = {
.remove = ns2_led_remove,
.driver = {
.name = "leds-ns2",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(of_ns2_leds_match),
},
};
diff --git a/drivers/leds/leds-ot200.c b/drivers/leds/leds-ot200.c
index c9d906098466..39870de20a26 100644
--- a/drivers/leds/leds-ot200.c
+++ b/drivers/leds/leds-ot200.c
@@ -158,7 +158,6 @@ static struct platform_driver ot200_led_driver = {
.remove = ot200_led_remove,
.driver = {
.name = "leds-ot200",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
index d672bb4480f6..f668500a2157 100644
--- a/drivers/leds/leds-pwm.c
+++ b/drivers/leds/leds-pwm.c
@@ -232,7 +232,6 @@ static struct platform_driver led_pwm_driver = {
.remove = led_pwm_remove,
.driver = {
.name = "leds_pwm",
- .owner = THIS_MODULE,
.of_match_table = of_pwm_leds_match,
},
};
diff --git a/drivers/leds/leds-rb532.c b/drivers/leds/leds-rb532.c
index 2e746d257b02..fcd1215b64a2 100644
--- a/drivers/leds/leds-rb532.c
+++ b/drivers/leds/leds-rb532.c
@@ -53,7 +53,6 @@ static struct platform_driver rb532_led_driver = {
.remove = rb532_led_remove,
.driver = {
.name = "rb532-led",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/leds/leds-regulator.c b/drivers/leds/leds-regulator.c
index 358430db6e66..ffc21397a675 100644
--- a/drivers/leds/leds-regulator.c
+++ b/drivers/leds/leds-regulator.c
@@ -153,24 +153,21 @@ static int regulator_led_probe(struct platform_device *pdev)
return -ENODEV;
}
- vcc = regulator_get_exclusive(&pdev->dev, "vled");
+ vcc = devm_regulator_get_exclusive(&pdev->dev, "vled");
if (IS_ERR(vcc)) {
dev_err(&pdev->dev, "Cannot get vcc for %s\n", pdata->name);
return PTR_ERR(vcc);
}
led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
- if (led == NULL) {
- ret = -ENOMEM;
- goto err_vcc;
- }
+ if (led == NULL)
+ return -ENOMEM;
led->cdev.max_brightness = led_regulator_get_max_brightness(vcc);
if (pdata->brightness > led->cdev.max_brightness) {
dev_err(&pdev->dev, "Invalid default brightness %d\n",
pdata->brightness);
- ret = -EINVAL;
- goto err_vcc;
+ return -EINVAL;
}
led->value = pdata->brightness;
@@ -191,7 +188,7 @@ static int regulator_led_probe(struct platform_device *pdev)
ret = led_classdev_register(&pdev->dev, &led->cdev);
if (ret < 0) {
cancel_work_sync(&led->work);
- goto err_vcc;
+ return ret;
}
/* to expose the default value to userspace */
@@ -201,10 +198,6 @@ static int regulator_led_probe(struct platform_device *pdev)
regulator_led_set_value(led);
return 0;
-
-err_vcc:
- regulator_put(vcc);
- return ret;
}
static int regulator_led_remove(struct platform_device *pdev)
@@ -214,14 +207,12 @@ static int regulator_led_remove(struct platform_device *pdev)
led_classdev_unregister(&led->cdev);
cancel_work_sync(&led->work);
regulator_led_disable(led);
- regulator_put(led->vcc);
return 0;
}
static struct platform_driver regulator_led_driver = {
.driver = {
.name = "leds-regulator",
- .owner = THIS_MODULE,
},
.probe = regulator_led_probe,
.remove = regulator_led_remove,
diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c
index 785eb53a87fc..83641a7b299a 100644
--- a/drivers/leds/leds-s3c24xx.c
+++ b/drivers/leds/leds-s3c24xx.c
@@ -116,7 +116,6 @@ static struct platform_driver s3c24xx_led_driver = {
.remove = s3c24xx_led_remove,
.driver = {
.name = "s3c24xx_led",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/leds/leds-sunfire.c b/drivers/leds/leds-sunfire.c
index 0b8cc4a021a6..c2553c54f2cf 100644
--- a/drivers/leds/leds-sunfire.c
+++ b/drivers/leds/leds-sunfire.c
@@ -223,7 +223,6 @@ static struct platform_driver sunfire_clockboard_led_driver = {
.remove = sunfire_led_generic_remove,
.driver = {
.name = "sunfire-clockboard-leds",
- .owner = THIS_MODULE,
},
};
@@ -232,7 +231,6 @@ static struct platform_driver sunfire_fhc_led_driver = {
.remove = sunfire_led_generic_remove,
.driver = {
.name = "sunfire-fhc-leds",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/leds/leds-syscon.c b/drivers/leds/leds-syscon.c
index 3afec79c43f4..6896e2d9ba58 100644
--- a/drivers/leds/leds-syscon.c
+++ b/drivers/leds/leds-syscon.c
@@ -18,10 +18,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
- *
- * This driver provides system reboot functionality for APM X-Gene SoC.
- * For system shutdown, this is board specify. If a board designer
- * implements GPIO shutdown, use the gpio-poweroff.c driver.
*/
#include <linux/io.h>
#include <linux/of_device.h>
@@ -70,39 +66,13 @@ static void syscon_led_set(struct led_classdev *led_cdev,
dev_err(sled->cdev.dev, "error updating LED status\n");
}
-static const struct of_device_id syscon_match[] = {
- { .compatible = "syscon", },
- {},
-};
-
-static int __init syscon_leds_init(void)
+static int __init syscon_leds_spawn(struct device_node *np,
+ struct device *dev,
+ struct regmap *map)
{
- const struct of_device_id *devid;
- struct device_node *np;
struct device_node *child;
- struct regmap *map;
- struct platform_device *pdev;
- struct device *dev;
int ret;
- np = of_find_matching_node_and_match(NULL, syscon_match,
- &devid);
- if (!np)
- return -ENODEV;
-
- map = syscon_node_to_regmap(np);
- if (IS_ERR(map))
- return PTR_ERR(map);
-
- /*
- * If the map is there, the device should be there, we allocate
- * memory on the syscon device's behalf here.
- */
- pdev = of_find_device_by_node(np);
- if (!pdev)
- return -ENODEV;
- dev = &pdev->dev;
-
for_each_available_child_of_node(np, child) {
struct syscon_led *sled;
const char *state;
@@ -150,7 +120,6 @@ static int __init syscon_leds_init(void)
if (ret < 0)
return ret;
}
-
}
sled->cdev.brightness_set = syscon_led_set;
@@ -160,7 +129,39 @@ static int __init syscon_leds_init(void)
dev_info(dev, "registered LED %s\n", sled->cdev.name);
}
+ return 0;
+}
+
+static int __init syscon_leds_init(void)
+{
+ struct device_node *np;
+
+ for_each_of_allnodes(np) {
+ struct platform_device *pdev;
+ struct regmap *map;
+ int ret;
+
+ if (!of_device_is_compatible(np, "syscon"))
+ continue;
+
+ map = syscon_node_to_regmap(np);
+ if (IS_ERR(map)) {
+ pr_err("error getting regmap for syscon LEDs\n");
+ continue;
+ }
+
+ /*
+ * If the map is there, the device should be there, we allocate
+ * memory on the syscon device's behalf here.
+ */
+ pdev = of_find_device_by_node(np);
+ if (!pdev)
+ return -ENODEV;
+ ret = syscon_leds_spawn(np, &pdev->dev, map);
+ if (ret)
+ dev_err(&pdev->dev, "could not spawn syscon LEDs\n");
+ }
- return 0;
+ return 0;
}
device_initcall(syscon_leds_init);
diff --git a/drivers/leds/leds-wm831x-status.c b/drivers/leds/leds-wm831x-status.c
index 1b71e0701002..56027ef7c7e8 100644
--- a/drivers/leds/leds-wm831x-status.c
+++ b/drivers/leds/leds-wm831x-status.c
@@ -312,7 +312,6 @@ static int wm831x_status_remove(struct platform_device *pdev)
static struct platform_driver wm831x_status_driver = {
.driver = {
.name = "wm831x-status",
- .owner = THIS_MODULE,
},
.probe = wm831x_status_probe,
.remove = wm831x_status_remove,
diff --git a/drivers/leds/leds-wm8350.c b/drivers/leds/leds-wm8350.c
index 4133ffe29015..0d121835673f 100644
--- a/drivers/leds/leds-wm8350.c
+++ b/drivers/leds/leds-wm8350.c
@@ -272,7 +272,6 @@ static int wm8350_led_remove(struct platform_device *pdev)
static struct platform_driver wm8350_led_driver = {
.driver = {
.name = "wm8350-led",
- .owner = THIS_MODULE,
},
.probe = wm8350_led_probe,
.remove = wm8350_led_remove,
diff --git a/drivers/leds/leds-wrap.c b/drivers/leds/leds-wrap.c
index b358cc05eff5..1ba3defdd460 100644
--- a/drivers/leds/leds-wrap.c
+++ b/drivers/leds/leds-wrap.c
@@ -111,7 +111,6 @@ static struct platform_driver wrap_led_driver = {
.remove = wrap_led_remove,
.driver = {
.name = DRVNAME,
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h
index 4c50365344a9..2348dbda5269 100644
--- a/drivers/leds/leds.h
+++ b/drivers/leds/leds.h
@@ -17,16 +17,28 @@
#include <linux/rwsem.h>
#include <linux/leds.h>
-static inline void __led_set_brightness(struct led_classdev *led_cdev,
+static inline void led_set_brightness_async(struct led_classdev *led_cdev,
enum led_brightness value)
{
- if (value > led_cdev->max_brightness)
- value = led_cdev->max_brightness;
- led_cdev->brightness = value;
+ led_cdev->brightness = min(value, led_cdev->max_brightness);
+
if (!(led_cdev->flags & LED_SUSPENDED))
led_cdev->brightness_set(led_cdev, value);
}
+static inline int led_set_brightness_sync(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ int ret = 0;
+
+ led_cdev->brightness = min(value, led_cdev->max_brightness);
+
+ if (!(led_cdev->flags & LED_SUSPENDED))
+ ret = led_cdev->brightness_set_sync(led_cdev,
+ led_cdev->brightness);
+ return ret;
+}
+
static inline int led_get_brightness(struct led_classdev *led_cdev)
{
return led_cdev->brightness;
diff --git a/drivers/leds/trigger/ledtrig-backlight.c b/drivers/leds/trigger/ledtrig-backlight.c
index 47e55aa9eefa..59eca17d9661 100644
--- a/drivers/leds/trigger/ledtrig-backlight.c
+++ b/drivers/leds/trigger/ledtrig-backlight.c
@@ -51,9 +51,9 @@ static int fb_notifier_callback(struct notifier_block *p,
if ((n->old_status == UNBLANK) ^ n->invert) {
n->brightness = led->brightness;
- __led_set_brightness(led, LED_OFF);
+ led_set_brightness_async(led, LED_OFF);
} else {
- __led_set_brightness(led, n->brightness);
+ led_set_brightness_async(led, n->brightness);
}
n->old_status = new_status;
@@ -89,9 +89,9 @@ static ssize_t bl_trig_invert_store(struct device *dev,
/* After inverting, we need to update the LED. */
if ((n->old_status == BLANK) ^ n->invert)
- __led_set_brightness(led, LED_OFF);
+ led_set_brightness_async(led, LED_OFF);
else
- __led_set_brightness(led, n->brightness);
+ led_set_brightness_async(led, n->brightness);
return num;
}
diff --git a/drivers/leds/trigger/ledtrig-default-on.c b/drivers/leds/trigger/ledtrig-default-on.c
index 81a91be8e18d..6f38f883aaf1 100644
--- a/drivers/leds/trigger/ledtrig-default-on.c
+++ b/drivers/leds/trigger/ledtrig-default-on.c
@@ -19,7 +19,7 @@
static void defon_trig_activate(struct led_classdev *led_cdev)
{
- __led_set_brightness(led_cdev, led_cdev->max_brightness);
+ led_set_brightness_async(led_cdev, led_cdev->max_brightness);
}
static struct led_trigger defon_led_trigger = {
diff --git a/drivers/leds/trigger/ledtrig-gpio.c b/drivers/leds/trigger/ledtrig-gpio.c
index c86c41826476..4cc7040746c6 100644
--- a/drivers/leds/trigger/ledtrig-gpio.c
+++ b/drivers/leds/trigger/ledtrig-gpio.c
@@ -54,12 +54,12 @@ static void gpio_trig_work(struct work_struct *work)
if (tmp) {
if (gpio_data->desired_brightness)
- __led_set_brightness(gpio_data->led,
+ led_set_brightness_async(gpio_data->led,
gpio_data->desired_brightness);
else
- __led_set_brightness(gpio_data->led, LED_FULL);
+ led_set_brightness_async(gpio_data->led, LED_FULL);
} else {
- __led_set_brightness(gpio_data->led, LED_OFF);
+ led_set_brightness_async(gpio_data->led, LED_OFF);
}
}
diff --git a/drivers/leds/trigger/ledtrig-heartbeat.c b/drivers/leds/trigger/ledtrig-heartbeat.c
index 5c8464a33172..fea6871d2609 100644
--- a/drivers/leds/trigger/ledtrig-heartbeat.c
+++ b/drivers/leds/trigger/ledtrig-heartbeat.c
@@ -74,7 +74,7 @@ static void led_heartbeat_function(unsigned long data)
break;
}
- __led_set_brightness(led_cdev, brightness);
+ led_set_brightness_async(led_cdev, brightness);
mod_timer(&heartbeat_data->timer, jiffies + delay);
}
diff --git a/drivers/leds/trigger/ledtrig-oneshot.c b/drivers/leds/trigger/ledtrig-oneshot.c
index cb4c7466692a..fbd02cdc3ad7 100644
--- a/drivers/leds/trigger/ledtrig-oneshot.c
+++ b/drivers/leds/trigger/ledtrig-oneshot.c
@@ -63,9 +63,9 @@ static ssize_t led_invert_store(struct device *dev,
oneshot_data->invert = !!state;
if (oneshot_data->invert)
- __led_set_brightness(led_cdev, LED_FULL);
+ led_set_brightness_async(led_cdev, LED_FULL);
else
- __led_set_brightness(led_cdev, LED_OFF);
+ led_set_brightness_async(led_cdev, LED_OFF);
return size;
}
diff --git a/drivers/leds/trigger/ledtrig-transient.c b/drivers/leds/trigger/ledtrig-transient.c
index e5abc00bb00c..3c34de404d18 100644
--- a/drivers/leds/trigger/ledtrig-transient.c
+++ b/drivers/leds/trigger/ledtrig-transient.c
@@ -41,7 +41,7 @@ static void transient_timer_function(unsigned long data)
struct transient_trig_data *transient_data = led_cdev->trigger_data;
transient_data->activate = 0;
- __led_set_brightness(led_cdev, transient_data->restore_state);
+ led_set_brightness_async(led_cdev, transient_data->restore_state);
}
static ssize_t transient_activate_show(struct device *dev,
@@ -72,7 +72,8 @@ static ssize_t transient_activate_store(struct device *dev,
if (state == 0 && transient_data->activate == 1) {
del_timer(&transient_data->timer);
transient_data->activate = state;
- __led_set_brightness(led_cdev, transient_data->restore_state);
+ led_set_brightness_async(led_cdev,
+ transient_data->restore_state);
return size;
}
@@ -80,7 +81,7 @@ static ssize_t transient_activate_store(struct device *dev,
if (state == 1 && transient_data->activate == 0 &&
transient_data->duration != 0) {
transient_data->activate = state;
- __led_set_brightness(led_cdev, transient_data->state);
+ led_set_brightness_async(led_cdev, transient_data->state);
transient_data->restore_state =
(transient_data->state == LED_FULL) ? LED_OFF : LED_FULL;
mod_timer(&transient_data->timer,
@@ -203,7 +204,8 @@ static void transient_trig_deactivate(struct led_classdev *led_cdev)
if (led_cdev->activated) {
del_timer_sync(&transient_data->timer);
- __led_set_brightness(led_cdev, transient_data->restore_state);
+ led_set_brightness_async(led_cdev,
+ transient_data->restore_state);
device_remove_file(led_cdev->dev, &dev_attr_activate);
device_remove_file(led_cdev->dev, &dev_attr_duration);
device_remove_file(led_cdev->dev, &dev_attr_state);