aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-03-16 01:04:53 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-03-16 01:04:53 -0400
commit9256d5a308c95a50c6e85d682492ae1f86a70f9b (patch)
tree90350aa8bcb69072b9cf9b4606faa320ed2d2a1a
parent13f6f62f61b4d3d5f45bed889128bb7ff3fda5ed (diff)
parent7296c33ed12ef13de50e03c76643382123766f96 (diff)
Merge tag 'leds_for_4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds
Pull LED updates from Jacek Anaszewski: "LED core improvements: - Fix misleading comment after workqueue removal from drivers - Avoid error message when a USB LED device is unplugged - Add helpers for calling brightness_set(_blocking) LED triggers: - Simplify led_trigger_store by using sysfs_streq() LED class drivers improvements: - Improve wording and formatting in a comment: lp3944 - Fix return value check in create_gpio_led(): leds-gpio - Use GPIOF_OUT_INIT_LOW instead of hardcoded zero: leds-gpio - Use devm_led_classdev_register(): leds-lm3533, leds-lm3533, leds-lp8788, leds-wm831x-status, leds-s3c24xx, leds-s3c24xx, leds-max8997. New LED class driver: - Add driver for the ISSI IS31FL32xx family of LED controllers. Device Tree documentation: - of: Add vendor prefixes for Integrated Silicon Solutions Inc. (issi) and Si-En Technology (si-en). - DT: Add common bindings for Si-En Technology SN3216/18 and IS31FL32xx family of LED controllers, since they seem to be the same hardware, just rebranded" * tag 'leds_for_4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds: leds: triggers: simplify led_trigger_store leds: max8997: Use devm_led_classdev_register leds: da903x: Use devm_led_classdev_register leds: s3c24xx: Use devm_led_classdev_register leds: wm831x-status: Use devm_led_classdev_register leds: lp8788: Use devm_led_classdev_register leds: 88pm860x: Use devm_led_classdev_register leds: Add SN3218 and SN3216 support to the IS31FL32XX driver of: Add vendor prefix for Si-En Technology leds: Add driver for the ISSI IS31FL32xx family of LED controllers DT: leds: Add binding for the ISSI IS31FL32xx family of LED controllers DT: Add vendor prefix for Integrated Silicon Solutions Inc. leds: lm3533: Use devm_led_classdev_register leds: gpio: Use GPIOF_OUT_INIT_LOW instead of hardcoded zero leds: core: add helpers for calling brightness_set(_blocking) leds: leds-gpio: Fix return value check in create_gpio_led() leds: lp3944: improve wording and formatting in a comment leds: core: avoid error message when a USB LED device is unplugged leds: core: fix misleading comment after workqueue removal from drivers
-rw-r--r--Documentation/devicetree/bindings/leds/leds-is31fl32xx.txt52
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt2
-rw-r--r--drivers/leds/Kconfig8
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/led-class.c2
-rw-r--r--drivers/leds/led-core.c45
-rw-r--r--drivers/leds/led-triggers.c13
-rw-r--r--drivers/leds/leds-88pm860x.c12
-rw-r--r--drivers/leds/leds-da903x.c12
-rw-r--r--drivers/leds/leds-gpio.c6
-rw-r--r--drivers/leds/leds-is31fl32xx.c508
-rw-r--r--drivers/leds/leds-lm3533.c12
-rw-r--r--drivers/leds/leds-lp3944.c7
-rw-r--r--drivers/leds/leds-lp8788.c14
-rw-r--r--drivers/leds/leds-max8997.c14
-rw-r--r--drivers/leds/leds-s3c24xx.c19
-rw-r--r--drivers/leds/leds-wm831x-status.c13
-rw-r--r--include/linux/leds.h8
18 files changed, 628 insertions, 120 deletions
diff --git a/Documentation/devicetree/bindings/leds/leds-is31fl32xx.txt b/Documentation/devicetree/bindings/leds/leds-is31fl32xx.txt
new file mode 100644
index 000000000000..926c2117942c
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-is31fl32xx.txt
@@ -0,0 +1,52 @@
1Binding for ISSI IS31FL32xx and Si-En SN32xx LED Drivers
2
3The IS31FL32xx/SN32xx family of LED drivers are I2C devices with multiple
4constant-current channels, each with independent 256-level PWM control.
5Each LED is represented as a sub-node of the device.
6
7Required properties:
8- compatible: one of
9 issi,is31fl3236
10 issi,is31fl3235
11 issi,is31fl3218
12 issi,is31fl3216
13 si-en,sn3218
14 si-en,sn3216
15- reg: I2C slave address
16- address-cells : must be 1
17- size-cells : must be 0
18
19LED sub-node properties:
20- reg : LED channel number (1..N)
21- label : (optional)
22 see Documentation/devicetree/bindings/leds/common.txt
23- linux,default-trigger : (optional)
24 see Documentation/devicetree/bindings/leds/common.txt
25
26
27Example:
28
29is31fl3236: led-controller@3c {
30 compatible = "issi,is31fl3236";
31 reg = <0x3c>;
32 #address-cells = <1>;
33 #size-cells = <0>;
34
35 led@1 {
36 reg = <1>;
37 label = "EB:blue:usr0";
38 };
39 led@2 {
40 reg = <2>;
41 label = "EB:blue:usr1";
42 };
43 ...
44 led@36 {
45 reg = <36>;
46 label = "EB:blue:usr35";
47 };
48};
49
50For more product information please see the links below:
51http://www.issi.com/US/product-analog-fxled-driver.shtml
52http://www.si-en.com/product.asp?parentid=890
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 72e2c5a2b327..dd72e0541e83 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -120,6 +120,7 @@ intercontrol Inter Control Group
120invensense InvenSense Inc. 120invensense InvenSense Inc.
121isee ISEE 2007 S.L. 121isee ISEE 2007 S.L.
122isil Intersil 122isil Intersil
123issi Integrated Silicon Solutions Inc.
123jedec JEDEC Solid State Technology Association 124jedec JEDEC Solid State Technology Association
124karo Ka-Ro electronics GmbH 125karo Ka-Ro electronics GmbH
125keymile Keymile GmbH 126keymile Keymile GmbH
@@ -204,6 +205,7 @@ seagate Seagate Technology PLC
204semtech Semtech Corporation 205semtech Semtech Corporation
205sgx SGX Sensortech 206sgx SGX Sensortech
206sharp Sharp Corporation 207sharp Sharp Corporation
208si-en Si-En Technology Ltd.
207sigma Sigma Designs, Inc. 209sigma Sigma Designs, Inc.
208sil Silicon Image 210sil Silicon Image
209silabs Silicon Laboratories 211silabs Silicon Laboratories
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 7f940c24a16b..1f6415168998 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -568,6 +568,14 @@ config LEDS_SEAD3
568 This driver can also be built as a module. If so the module 568 This driver can also be built as a module. If so the module
569 will be called leds-sead3. 569 will be called leds-sead3.
570 570
571config LEDS_IS31FL32XX
572 tristate "LED support for ISSI IS31FL32XX I2C LED controller family"
573 depends on LEDS_CLASS && I2C && OF
574 help
575 Say Y here to include support for ISSI IS31FL32XX and Si-En SN32xx
576 LED controllers. They are I2C devices with multiple constant-current
577 channels, each with independent 256-level PWM control.
578
571comment "LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)" 579comment "LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)"
572 580
573config LEDS_BLINKM 581config LEDS_BLINKM
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index e9d53092765d..cb2013df52d9 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -66,6 +66,7 @@ obj-$(CONFIG_LEDS_MENF21BMC) += leds-menf21bmc.o
66obj-$(CONFIG_LEDS_KTD2692) += leds-ktd2692.o 66obj-$(CONFIG_LEDS_KTD2692) += leds-ktd2692.o
67obj-$(CONFIG_LEDS_POWERNV) += leds-powernv.o 67obj-$(CONFIG_LEDS_POWERNV) += leds-powernv.o
68obj-$(CONFIG_LEDS_SEAD3) += leds-sead3.o 68obj-$(CONFIG_LEDS_SEAD3) += leds-sead3.o
69obj-$(CONFIG_LEDS_IS31FL32XX) += leds-is31fl32xx.o
69 70
70# LED SPI Drivers 71# LED SPI Drivers
71obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o 72obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 14139c337312..aa84e5b37593 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -245,6 +245,8 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
245 up_write(&led_cdev->trigger_lock); 245 up_write(&led_cdev->trigger_lock);
246#endif 246#endif
247 247
248 led_cdev->flags |= LED_UNREGISTERING;
249
248 /* Stop blinking */ 250 /* Stop blinking */
249 led_stop_software_blink(led_cdev); 251 led_stop_software_blink(led_cdev);
250 252
diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
index 19e1e60dfaa3..3495d5d6547f 100644
--- a/drivers/leds/led-core.c
+++ b/drivers/leds/led-core.c
@@ -25,6 +25,26 @@ EXPORT_SYMBOL_GPL(leds_list_lock);
25LIST_HEAD(leds_list); 25LIST_HEAD(leds_list);
26EXPORT_SYMBOL_GPL(leds_list); 26EXPORT_SYMBOL_GPL(leds_list);
27 27
28static int __led_set_brightness(struct led_classdev *led_cdev,
29 enum led_brightness value)
30{
31 if (!led_cdev->brightness_set)
32 return -ENOTSUPP;
33
34 led_cdev->brightness_set(led_cdev, value);
35
36 return 0;
37}
38
39static int __led_set_brightness_blocking(struct led_classdev *led_cdev,
40 enum led_brightness value)
41{
42 if (!led_cdev->brightness_set_blocking)
43 return -ENOTSUPP;
44
45 return led_cdev->brightness_set_blocking(led_cdev, value);
46}
47
28static void led_timer_function(unsigned long data) 48static void led_timer_function(unsigned long data)
29{ 49{
30 struct led_classdev *led_cdev = (void *)data; 50 struct led_classdev *led_cdev = (void *)data;
@@ -91,14 +111,14 @@ static void set_brightness_delayed(struct work_struct *ws)
91 led_cdev->flags &= ~LED_BLINK_DISABLE; 111 led_cdev->flags &= ~LED_BLINK_DISABLE;
92 } 112 }
93 113
94 if (led_cdev->brightness_set) 114 ret = __led_set_brightness(led_cdev, led_cdev->delayed_set_value);
95 led_cdev->brightness_set(led_cdev, led_cdev->delayed_set_value); 115 if (ret == -ENOTSUPP)
96 else if (led_cdev->brightness_set_blocking) 116 ret = __led_set_brightness_blocking(led_cdev,
97 ret = led_cdev->brightness_set_blocking(led_cdev, 117 led_cdev->delayed_set_value);
98 led_cdev->delayed_set_value); 118 if (ret < 0 &&
99 else 119 /* LED HW might have been unplugged, therefore don't warn */
100 ret = -ENOTSUPP; 120 !(ret == -ENODEV && (led_cdev->flags & LED_UNREGISTERING) &&
101 if (ret < 0) 121 (led_cdev->flags & LED_HW_PLUGGABLE)))
102 dev_err(led_cdev->dev, 122 dev_err(led_cdev->dev,
103 "Setting an LED's brightness failed (%d)\n", ret); 123 "Setting an LED's brightness failed (%d)\n", ret);
104} 124}
@@ -233,10 +253,8 @@ void led_set_brightness_nopm(struct led_classdev *led_cdev,
233 enum led_brightness value) 253 enum led_brightness value)
234{ 254{
235 /* Use brightness_set op if available, it is guaranteed not to sleep */ 255 /* Use brightness_set op if available, it is guaranteed not to sleep */
236 if (led_cdev->brightness_set) { 256 if (!__led_set_brightness(led_cdev, value))
237 led_cdev->brightness_set(led_cdev, value);
238 return; 257 return;
239 }
240 258
241 /* If brightness setting can sleep, delegate it to a work queue task */ 259 /* If brightness setting can sleep, delegate it to a work queue task */
242 led_cdev->delayed_set_value = value; 260 led_cdev->delayed_set_value = value;
@@ -267,10 +285,7 @@ int led_set_brightness_sync(struct led_classdev *led_cdev,
267 if (led_cdev->flags & LED_SUSPENDED) 285 if (led_cdev->flags & LED_SUSPENDED)
268 return 0; 286 return 0;
269 287
270 if (led_cdev->brightness_set_blocking) 288 return __led_set_brightness_blocking(led_cdev, led_cdev->brightness);
271 return led_cdev->brightness_set_blocking(led_cdev,
272 led_cdev->brightness);
273 return -ENOTSUPP;
274} 289}
275EXPORT_SYMBOL_GPL(led_set_brightness_sync); 290EXPORT_SYMBOL_GPL(led_set_brightness_sync);
276 291
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index e1e933424ac9..2181581795d3 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -34,9 +34,7 @@ ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
34 const char *buf, size_t count) 34 const char *buf, size_t count)
35{ 35{
36 struct led_classdev *led_cdev = dev_get_drvdata(dev); 36 struct led_classdev *led_cdev = dev_get_drvdata(dev);
37 char trigger_name[TRIG_NAME_MAX];
38 struct led_trigger *trig; 37 struct led_trigger *trig;
39 size_t len;
40 int ret = count; 38 int ret = count;
41 39
42 mutex_lock(&led_cdev->led_access); 40 mutex_lock(&led_cdev->led_access);
@@ -46,21 +44,14 @@ ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
46 goto unlock; 44 goto unlock;
47 } 45 }
48 46
49 trigger_name[sizeof(trigger_name) - 1] = '\0'; 47 if (sysfs_streq(buf, "none")) {
50 strncpy(trigger_name, buf, sizeof(trigger_name) - 1);
51 len = strlen(trigger_name);
52
53 if (len && trigger_name[len - 1] == '\n')
54 trigger_name[len - 1] = '\0';
55
56 if (!strcmp(trigger_name, "none")) {
57 led_trigger_remove(led_cdev); 48 led_trigger_remove(led_cdev);
58 goto unlock; 49 goto unlock;
59 } 50 }
60 51
61 down_read(&triggers_list_lock); 52 down_read(&triggers_list_lock);
62 list_for_each_entry(trig, &trigger_list, next_trig) { 53 list_for_each_entry(trig, &trigger_list, next_trig) {
63 if (!strcmp(trigger_name, trig->name)) { 54 if (sysfs_streq(buf, trig->name)) {
64 down_write(&led_cdev->trigger_lock); 55 down_write(&led_cdev->trigger_lock);
65 led_trigger_set(led_cdev, trig); 56 led_trigger_set(led_cdev, trig);
66 up_write(&led_cdev->trigger_lock); 57 up_write(&led_cdev->trigger_lock);
diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c
index 1ad4d03a0a3c..77a104d2b124 100644
--- a/drivers/leds/leds-88pm860x.c
+++ b/drivers/leds/leds-88pm860x.c
@@ -195,7 +195,6 @@ static int pm860x_led_probe(struct platform_device *pdev)
195 sprintf(data->name, "led1-blue"); 195 sprintf(data->name, "led1-blue");
196 break; 196 break;
197 } 197 }
198 platform_set_drvdata(pdev, data);
199 data->chip = chip; 198 data->chip = chip;
200 data->i2c = (chip->id == CHIP_PM8606) ? chip->client : chip->companion; 199 data->i2c = (chip->id == CHIP_PM8606) ? chip->client : chip->companion;
201 data->port = pdev->id; 200 data->port = pdev->id;
@@ -208,7 +207,7 @@ static int pm860x_led_probe(struct platform_device *pdev)
208 data->cdev.brightness_set_blocking = pm860x_led_set; 207 data->cdev.brightness_set_blocking = pm860x_led_set;
209 mutex_init(&data->lock); 208 mutex_init(&data->lock);
210 209
211 ret = led_classdev_register(chip->dev, &data->cdev); 210 ret = devm_led_classdev_register(chip->dev, &data->cdev);
212 if (ret < 0) { 211 if (ret < 0) {
213 dev_err(&pdev->dev, "Failed to register LED: %d\n", ret); 212 dev_err(&pdev->dev, "Failed to register LED: %d\n", ret);
214 return ret; 213 return ret;
@@ -217,21 +216,12 @@ static int pm860x_led_probe(struct platform_device *pdev)
217 return 0; 216 return 0;
218} 217}
219 218
220static int pm860x_led_remove(struct platform_device *pdev)
221{
222 struct pm860x_led *data = platform_get_drvdata(pdev);
223
224 led_classdev_unregister(&data->cdev);
225
226 return 0;
227}
228 219
229static struct platform_driver pm860x_led_driver = { 220static struct platform_driver pm860x_led_driver = {
230 .driver = { 221 .driver = {
231 .name = "88pm860x-led", 222 .name = "88pm860x-led",
232 }, 223 },
233 .probe = pm860x_led_probe, 224 .probe = pm860x_led_probe,
234 .remove = pm860x_led_remove,
235}; 225};
236 226
237module_platform_driver(pm860x_led_driver); 227module_platform_driver(pm860x_led_driver);
diff --git a/drivers/leds/leds-da903x.c b/drivers/leds/leds-da903x.c
index 4752a2b6ba2b..5ff7d72f73aa 100644
--- a/drivers/leds/leds-da903x.c
+++ b/drivers/leds/leds-da903x.c
@@ -113,21 +113,12 @@ static int da903x_led_probe(struct platform_device *pdev)
113 led->flags = pdata->flags; 113 led->flags = pdata->flags;
114 led->master = pdev->dev.parent; 114 led->master = pdev->dev.parent;
115 115
116 ret = led_classdev_register(led->master, &led->cdev); 116 ret = devm_led_classdev_register(led->master, &led->cdev);
117 if (ret) { 117 if (ret) {
118 dev_err(&pdev->dev, "failed to register LED %d\n", id); 118 dev_err(&pdev->dev, "failed to register LED %d\n", id);
119 return ret; 119 return ret;
120 } 120 }
121 121
122 platform_set_drvdata(pdev, led);
123 return 0;
124}
125
126static int da903x_led_remove(struct platform_device *pdev)
127{
128 struct da903x_led *led = platform_get_drvdata(pdev);
129
130 led_classdev_unregister(&led->cdev);
131 return 0; 122 return 0;
132} 123}
133 124
@@ -136,7 +127,6 @@ static struct platform_driver da903x_led_driver = {
136 .name = "da903x-led", 127 .name = "da903x-led",
137 }, 128 },
138 .probe = da903x_led_probe, 129 .probe = da903x_led_probe,
139 .remove = da903x_led_remove,
140}; 130};
141 131
142module_platform_driver(da903x_led_driver); 132module_platform_driver(da903x_led_driver);
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index 7bc53280dbfd..61143f55597e 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -86,7 +86,7 @@ static int create_gpio_led(const struct gpio_led *template,
86 * still uses GPIO numbers. Ultimately we would like to get 86 * still uses GPIO numbers. Ultimately we would like to get
87 * rid of this block completely. 87 * rid of this block completely.
88 */ 88 */
89 unsigned long flags = 0; 89 unsigned long flags = GPIOF_OUT_INIT_LOW;
90 90
91 /* skip leds that aren't available */ 91 /* skip leds that aren't available */
92 if (!gpio_is_valid(template->gpio)) { 92 if (!gpio_is_valid(template->gpio)) {
@@ -104,8 +104,8 @@ static int create_gpio_led(const struct gpio_led *template,
104 return ret; 104 return ret;
105 105
106 led_dat->gpiod = gpio_to_desc(template->gpio); 106 led_dat->gpiod = gpio_to_desc(template->gpio);
107 if (IS_ERR(led_dat->gpiod)) 107 if (!led_dat->gpiod)
108 return PTR_ERR(led_dat->gpiod); 108 return -EINVAL;
109 } 109 }
110 110
111 led_dat->cdev.name = template->name; 111 led_dat->cdev.name = template->name;
diff --git a/drivers/leds/leds-is31fl32xx.c b/drivers/leds/leds-is31fl32xx.c
new file mode 100644
index 000000000000..c901d132d80c
--- /dev/null
+++ b/drivers/leds/leds-is31fl32xx.c
@@ -0,0 +1,508 @@
1/*
2 * Driver for ISSI IS31FL32xx family of I2C LED controllers
3 *
4 * Copyright 2015 Allworx Corp.
5 *
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * Datasheets:
12 * http://www.issi.com/US/product-analog-fxled-driver.shtml
13 * http://www.si-en.com/product.asp?parentid=890
14 */
15
16#include <linux/device.h>
17#include <linux/i2c.h>
18#include <linux/kernel.h>
19#include <linux/leds.h>
20#include <linux/module.h>
21#include <linux/of.h>
22#include <linux/of_device.h>
23
24/* Used to indicate a device has no such register */
25#define IS31FL32XX_REG_NONE 0xFF
26
27/* Software Shutdown bit in Shutdown Register */
28#define IS31FL32XX_SHUTDOWN_SSD_ENABLE 0
29#define IS31FL32XX_SHUTDOWN_SSD_DISABLE BIT(0)
30
31/* IS31FL3216 has a number of unique registers */
32#define IS31FL3216_CONFIG_REG 0x00
33#define IS31FL3216_LIGHTING_EFFECT_REG 0x03
34#define IS31FL3216_CHANNEL_CONFIG_REG 0x04
35
36/* Software Shutdown bit in 3216 Config Register */
37#define IS31FL3216_CONFIG_SSD_ENABLE BIT(7)
38#define IS31FL3216_CONFIG_SSD_DISABLE 0
39
40struct is31fl32xx_priv;
41struct is31fl32xx_led_data {
42 struct led_classdev cdev;
43 u8 channel; /* 1-based, max priv->cdef->channels */
44 struct is31fl32xx_priv *priv;
45};
46
47struct is31fl32xx_priv {
48 const struct is31fl32xx_chipdef *cdef;
49 struct i2c_client *client;
50 unsigned int num_leds;
51 struct is31fl32xx_led_data leds[0];
52};
53
54/**
55 * struct is31fl32xx_chipdef - chip-specific attributes
56 * @channels : Number of LED channels
57 * @shutdown_reg : address of Shutdown register (optional)
58 * @pwm_update_reg : address of PWM Update register
59 * @global_control_reg : address of Global Control register (optional)
60 * @reset_reg : address of Reset register (optional)
61 * @pwm_register_base : address of first PWM register
62 * @pwm_registers_reversed: : true if PWM registers count down instead of up
63 * @led_control_register_base : address of first LED control register (optional)
64 * @enable_bits_per_led_control_register: number of LEDs enable bits in each
65 * @reset_func: : pointer to reset function
66 *
67 * For all optional register addresses, the sentinel value %IS31FL32XX_REG_NONE
68 * indicates that this chip has no such register.
69 *
70 * If non-NULL, @reset_func will be called during probing to set all
71 * necessary registers to a known initialization state. This is needed
72 * for chips that do not have a @reset_reg.
73 *
74 * @enable_bits_per_led_control_register must be >=1 if
75 * @led_control_register_base != %IS31FL32XX_REG_NONE.
76 */
77struct is31fl32xx_chipdef {
78 u8 channels;
79 u8 shutdown_reg;
80 u8 pwm_update_reg;
81 u8 global_control_reg;
82 u8 reset_reg;
83 u8 pwm_register_base;
84 bool pwm_registers_reversed;
85 u8 led_control_register_base;
86 u8 enable_bits_per_led_control_register;
87 int (*reset_func)(struct is31fl32xx_priv *priv);
88 int (*sw_shutdown_func)(struct is31fl32xx_priv *priv, bool enable);
89};
90
91static const struct is31fl32xx_chipdef is31fl3236_cdef = {
92 .channels = 36,
93 .shutdown_reg = 0x00,
94 .pwm_update_reg = 0x25,
95 .global_control_reg = 0x4a,
96 .reset_reg = 0x4f,
97 .pwm_register_base = 0x01,
98 .led_control_register_base = 0x26,
99 .enable_bits_per_led_control_register = 1,
100};
101
102static const struct is31fl32xx_chipdef is31fl3235_cdef = {
103 .channels = 28,
104 .shutdown_reg = 0x00,
105 .pwm_update_reg = 0x25,
106 .global_control_reg = 0x4a,
107 .reset_reg = 0x4f,
108 .pwm_register_base = 0x05,
109 .led_control_register_base = 0x2a,
110 .enable_bits_per_led_control_register = 1,
111};
112
113static const struct is31fl32xx_chipdef is31fl3218_cdef = {
114 .channels = 18,
115 .shutdown_reg = 0x00,
116 .pwm_update_reg = 0x16,
117 .global_control_reg = IS31FL32XX_REG_NONE,
118 .reset_reg = 0x17,
119 .pwm_register_base = 0x01,
120 .led_control_register_base = 0x13,
121 .enable_bits_per_led_control_register = 6,
122};
123
124static int is31fl3216_reset(struct is31fl32xx_priv *priv);
125static int is31fl3216_software_shutdown(struct is31fl32xx_priv *priv,
126 bool enable);
127static const struct is31fl32xx_chipdef is31fl3216_cdef = {
128 .channels = 16,
129 .shutdown_reg = IS31FL32XX_REG_NONE,
130 .pwm_update_reg = 0xB0,
131 .global_control_reg = IS31FL32XX_REG_NONE,
132 .reset_reg = IS31FL32XX_REG_NONE,
133 .pwm_register_base = 0x10,
134 .pwm_registers_reversed = true,
135 .led_control_register_base = 0x01,
136 .enable_bits_per_led_control_register = 8,
137 .reset_func = is31fl3216_reset,
138 .sw_shutdown_func = is31fl3216_software_shutdown,
139};
140
141static int is31fl32xx_write(struct is31fl32xx_priv *priv, u8 reg, u8 val)
142{
143 int ret;
144
145 dev_dbg(&priv->client->dev, "writing register 0x%02X=0x%02X", reg, val);
146
147 ret = i2c_smbus_write_byte_data(priv->client, reg, val);
148 if (ret) {
149 dev_err(&priv->client->dev,
150 "register write to 0x%02X failed (error %d)",
151 reg, ret);
152 }
153 return ret;
154}
155
156/*
157 * Custom reset function for IS31FL3216 because it does not have a RESET
158 * register the way that the other IS31FL32xx chips do. We don't bother
159 * writing the GPIO and animation registers, because the registers we
160 * do write ensure those will have no effect.
161 */
162static int is31fl3216_reset(struct is31fl32xx_priv *priv)
163{
164 unsigned int i;
165 int ret;
166
167 ret = is31fl32xx_write(priv, IS31FL3216_CONFIG_REG,
168 IS31FL3216_CONFIG_SSD_ENABLE);
169 if (ret)
170 return ret;
171 for (i = 0; i < priv->cdef->channels; i++) {
172 ret = is31fl32xx_write(priv, priv->cdef->pwm_register_base+i,
173 0x00);
174 if (ret)
175 return ret;
176 }
177 ret = is31fl32xx_write(priv, priv->cdef->pwm_update_reg, 0);
178 if (ret)
179 return ret;
180 ret = is31fl32xx_write(priv, IS31FL3216_LIGHTING_EFFECT_REG, 0x00);
181 if (ret)
182 return ret;
183 ret = is31fl32xx_write(priv, IS31FL3216_CHANNEL_CONFIG_REG, 0x00);
184 if (ret)
185 return ret;
186
187 return 0;
188}
189
190/*
191 * Custom Software-Shutdown function for IS31FL3216 because it does not have
192 * a SHUTDOWN register the way that the other IS31FL32xx chips do.
193 * We don't bother doing a read/modify/write on the CONFIG register because
194 * we only ever use a value of '0' for the other fields in that register.
195 */
196static int is31fl3216_software_shutdown(struct is31fl32xx_priv *priv,
197 bool enable)
198{
199 u8 value = enable ? IS31FL3216_CONFIG_SSD_ENABLE :
200 IS31FL3216_CONFIG_SSD_DISABLE;
201
202 return is31fl32xx_write(priv, IS31FL3216_CONFIG_REG, value);
203}
204
205/*
206 * NOTE: A mutex is not needed in this function because:
207 * - All referenced data is read-only after probe()
208 * - The I2C core has a mutex on to protect the bus
209 * - There are no read/modify/write operations
210 * - Intervening operations between the write of the PWM register
211 * and the Update register are harmless.
212 *
213 * Example:
214 * PWM_REG_1 write 16
215 * UPDATE_REG write 0
216 * PWM_REG_2 write 128
217 * UPDATE_REG write 0
218 * vs:
219 * PWM_REG_1 write 16
220 * PWM_REG_2 write 128
221 * UPDATE_REG write 0
222 * UPDATE_REG write 0
223 * are equivalent. Poking the Update register merely applies all PWM
224 * register writes up to that point.
225 */
226static int is31fl32xx_brightness_set(struct led_classdev *led_cdev,
227 enum led_brightness brightness)
228{
229 const struct is31fl32xx_led_data *led_data =
230 container_of(led_cdev, struct is31fl32xx_led_data, cdev);
231 const struct is31fl32xx_chipdef *cdef = led_data->priv->cdef;
232 u8 pwm_register_offset;
233 int ret;
234
235 dev_dbg(led_cdev->dev, "%s: %d\n", __func__, brightness);
236
237 /* NOTE: led_data->channel is 1-based */
238 if (cdef->pwm_registers_reversed)
239 pwm_register_offset = cdef->channels - led_data->channel;
240 else
241 pwm_register_offset = led_data->channel - 1;
242
243 ret = is31fl32xx_write(led_data->priv,
244 cdef->pwm_register_base + pwm_register_offset,
245 brightness);
246 if (ret)
247 return ret;
248
249 return is31fl32xx_write(led_data->priv, cdef->pwm_update_reg, 0);
250}
251
252static int is31fl32xx_reset_regs(struct is31fl32xx_priv *priv)
253{
254 const struct is31fl32xx_chipdef *cdef = priv->cdef;
255 int ret;
256
257 if (cdef->reset_reg != IS31FL32XX_REG_NONE) {
258 ret = is31fl32xx_write(priv, cdef->reset_reg, 0);
259 if (ret)
260 return ret;
261 }
262
263 if (cdef->reset_func)
264 return cdef->reset_func(priv);
265
266 return 0;
267}
268
269static int is31fl32xx_software_shutdown(struct is31fl32xx_priv *priv,
270 bool enable)
271{
272 const struct is31fl32xx_chipdef *cdef = priv->cdef;
273 int ret;
274
275 if (cdef->shutdown_reg != IS31FL32XX_REG_NONE) {
276 u8 value = enable ? IS31FL32XX_SHUTDOWN_SSD_ENABLE :
277 IS31FL32XX_SHUTDOWN_SSD_DISABLE;
278 ret = is31fl32xx_write(priv, cdef->shutdown_reg, value);
279 if (ret)
280 return ret;
281 }
282
283 if (cdef->sw_shutdown_func)
284 return cdef->sw_shutdown_func(priv, enable);
285
286 return 0;
287}
288
289static int is31fl32xx_init_regs(struct is31fl32xx_priv *priv)
290{
291 const struct is31fl32xx_chipdef *cdef = priv->cdef;
292 int ret;
293
294 ret = is31fl32xx_reset_regs(priv);
295 if (ret)
296 return ret;
297
298 /*
299 * Set enable bit for all channels.
300 * We will control state with PWM registers alone.
301 */
302 if (cdef->led_control_register_base != IS31FL32XX_REG_NONE) {
303 u8 value =
304 GENMASK(cdef->enable_bits_per_led_control_register-1, 0);
305 u8 num_regs = cdef->channels /
306 cdef->enable_bits_per_led_control_register;
307 int i;
308
309 for (i = 0; i < num_regs; i++) {
310 ret = is31fl32xx_write(priv,
311 cdef->led_control_register_base+i,
312 value);
313 if (ret)
314 return ret;
315 }
316 }
317
318 ret = is31fl32xx_software_shutdown(priv, false);
319 if (ret)
320 return ret;
321
322 if (cdef->global_control_reg != IS31FL32XX_REG_NONE) {
323 ret = is31fl32xx_write(priv, cdef->global_control_reg, 0x00);
324 if (ret)
325 return ret;
326 }
327
328 return 0;
329}
330
331static inline size_t sizeof_is31fl32xx_priv(int num_leds)
332{
333 return sizeof(struct is31fl32xx_priv) +
334 (sizeof(struct is31fl32xx_led_data) * num_leds);
335}
336
337static int is31fl32xx_parse_child_dt(const struct device *dev,
338 const struct device_node *child,
339 struct is31fl32xx_led_data *led_data)
340{
341 struct led_classdev *cdev = &led_data->cdev;
342 int ret = 0;
343 u32 reg;
344
345 if (of_property_read_string(child, "label", &cdev->name))
346 cdev->name = child->name;
347
348 ret = of_property_read_u32(child, "reg", &reg);
349 if (ret || reg < 1 || reg > led_data->priv->cdef->channels) {
350 dev_err(dev,
351 "Child node %s does not have a valid reg property\n",
352 child->full_name);
353 return -EINVAL;
354 }
355 led_data->channel = reg;
356
357 of_property_read_string(child, "linux,default-trigger",
358 &cdev->default_trigger);
359
360 cdev->brightness_set_blocking = is31fl32xx_brightness_set;
361
362 return 0;
363}
364
365static struct is31fl32xx_led_data *is31fl32xx_find_led_data(
366 struct is31fl32xx_priv *priv,
367 u8 channel)
368{
369 size_t i;
370
371 for (i = 0; i < priv->num_leds; i++) {
372 if (priv->leds[i].channel == channel)
373 return &priv->leds[i];
374 }
375
376 return NULL;
377}
378
379static int is31fl32xx_parse_dt(struct device *dev,
380 struct is31fl32xx_priv *priv)
381{
382 struct device_node *child;
383 int ret = 0;
384
385 for_each_child_of_node(dev->of_node, child) {
386 struct is31fl32xx_led_data *led_data =
387 &priv->leds[priv->num_leds];
388 const struct is31fl32xx_led_data *other_led_data;
389
390 led_data->priv = priv;
391
392 ret = is31fl32xx_parse_child_dt(dev, child, led_data);
393 if (ret)
394 goto err;
395
396 /* Detect if channel is already in use by another child */
397 other_led_data = is31fl32xx_find_led_data(priv,
398 led_data->channel);
399 if (other_led_data) {
400 dev_err(dev,
401 "%s and %s both attempting to use channel %d\n",
402 led_data->cdev.name,
403 other_led_data->cdev.name,
404 led_data->channel);
405 goto err;
406 }
407
408 ret = devm_led_classdev_register(dev, &led_data->cdev);
409 if (ret) {
410 dev_err(dev, "failed to register PWM led for %s: %d\n",
411 led_data->cdev.name, ret);
412 goto err;
413 }
414
415 priv->num_leds++;
416 }
417
418 return 0;
419
420err:
421 of_node_put(child);
422 return ret;
423}
424
425static const struct of_device_id of_is31fl31xx_match[] = {
426 { .compatible = "issi,is31fl3236", .data = &is31fl3236_cdef, },
427 { .compatible = "issi,is31fl3235", .data = &is31fl3235_cdef, },
428 { .compatible = "issi,is31fl3218", .data = &is31fl3218_cdef, },
429 { .compatible = "si-en,sn3218", .data = &is31fl3218_cdef, },
430 { .compatible = "issi,is31fl3216", .data = &is31fl3216_cdef, },
431 { .compatible = "si-en,sn3216", .data = &is31fl3216_cdef, },
432 {},
433};
434
435MODULE_DEVICE_TABLE(of, of_is31fl31xx_match);
436
437static int is31fl32xx_probe(struct i2c_client *client,
438 const struct i2c_device_id *id)
439{
440 const struct is31fl32xx_chipdef *cdef;
441 const struct of_device_id *of_dev_id;
442 struct device *dev = &client->dev;
443 struct is31fl32xx_priv *priv;
444 int count;
445 int ret = 0;
446
447 of_dev_id = of_match_device(of_is31fl31xx_match, dev);
448 if (!of_dev_id)
449 return -EINVAL;
450
451 cdef = of_dev_id->data;
452
453 count = of_get_child_count(dev->of_node);
454 if (!count)
455 return -EINVAL;
456
457 priv = devm_kzalloc(dev, sizeof_is31fl32xx_priv(count),
458 GFP_KERNEL);
459 if (!priv)
460 return -ENOMEM;
461
462 priv->client = client;
463 priv->cdef = cdef;
464 i2c_set_clientdata(client, priv);
465
466 ret = is31fl32xx_init_regs(priv);
467 if (ret)
468 return ret;
469
470 ret = is31fl32xx_parse_dt(dev, priv);
471 if (ret)
472 return ret;
473
474 return 0;
475}
476
477static int is31fl32xx_remove(struct i2c_client *client)
478{
479 struct is31fl32xx_priv *priv = i2c_get_clientdata(client);
480
481 return is31fl32xx_reset_regs(priv);
482}
483
484/*
485 * i2c-core requires that id_table be non-NULL, even though
486 * it is not used for DeviceTree based instantiation.
487 */
488static const struct i2c_device_id is31fl31xx_id[] = {
489 {},
490};
491
492MODULE_DEVICE_TABLE(i2c, is31fl31xx_id);
493
494static struct i2c_driver is31fl32xx_driver = {
495 .driver = {
496 .name = "is31fl32xx",
497 .of_match_table = of_is31fl31xx_match,
498 },
499 .probe = is31fl32xx_probe,
500 .remove = is31fl32xx_remove,
501 .id_table = is31fl31xx_id,
502};
503
504module_i2c_driver(is31fl32xx_driver);
505
506MODULE_AUTHOR("David Rivshin <drivshin@allworx.com>");
507MODULE_DESCRIPTION("ISSI IS31FL32xx LED driver");
508MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds-lm3533.c b/drivers/leds/leds-lm3533.c
index 196dcb5e6004..5b529dc013d2 100644
--- a/drivers/leds/leds-lm3533.c
+++ b/drivers/leds/leds-lm3533.c
@@ -698,7 +698,7 @@ static int lm3533_led_probe(struct platform_device *pdev)
698 698
699 platform_set_drvdata(pdev, led); 699 platform_set_drvdata(pdev, led);
700 700
701 ret = led_classdev_register(pdev->dev.parent, &led->cdev); 701 ret = devm_led_classdev_register(pdev->dev.parent, &led->cdev);
702 if (ret) { 702 if (ret) {
703 dev_err(&pdev->dev, "failed to register LED %d\n", pdev->id); 703 dev_err(&pdev->dev, "failed to register LED %d\n", pdev->id);
704 return ret; 704 return ret;
@@ -708,18 +708,13 @@ static int lm3533_led_probe(struct platform_device *pdev)
708 708
709 ret = lm3533_led_setup(led, pdata); 709 ret = lm3533_led_setup(led, pdata);
710 if (ret) 710 if (ret)
711 goto err_unregister; 711 return ret;
712 712
713 ret = lm3533_ctrlbank_enable(&led->cb); 713 ret = lm3533_ctrlbank_enable(&led->cb);
714 if (ret) 714 if (ret)
715 goto err_unregister; 715 return ret;
716 716
717 return 0; 717 return 0;
718
719err_unregister:
720 led_classdev_unregister(&led->cdev);
721
722 return ret;
723} 718}
724 719
725static int lm3533_led_remove(struct platform_device *pdev) 720static int lm3533_led_remove(struct platform_device *pdev)
@@ -729,7 +724,6 @@ static int lm3533_led_remove(struct platform_device *pdev)
729 dev_dbg(&pdev->dev, "%s\n", __func__); 724 dev_dbg(&pdev->dev, "%s\n", __func__);
730 725
731 lm3533_ctrlbank_disable(&led->cb); 726 lm3533_ctrlbank_disable(&led->cb);
732 led_classdev_unregister(&led->cdev);
733 727
734 return 0; 728 return 0;
735} 729}
diff --git a/drivers/leds/leds-lp3944.c b/drivers/leds/leds-lp3944.c
index 6c758aea1bbd..be60c181222a 100644
--- a/drivers/leds/leds-lp3944.c
+++ b/drivers/leds/leds-lp3944.c
@@ -199,8 +199,11 @@ static int lp3944_led_set(struct lp3944_led_data *led, u8 status)
199 if (status > LP3944_LED_STATUS_DIM1) 199 if (status > LP3944_LED_STATUS_DIM1)
200 return -EINVAL; 200 return -EINVAL;
201 201
202 /* invert only 0 and 1, leave unchanged the other values, 202 /*
203 * remember we are abusing status to set blink patterns 203 * Invert status only when it's < 2 (i.e. 0 or 1) which means it's
204 * controlling the on/off state directly.
205 * When, instead, status is >= 2 don't invert it because it would mean
206 * to mess with the hardware blinking mode.
204 */ 207 */
205 if (led->type == LP3944_LED_TYPE_LED_INVERTED && status < 2) 208 if (led->type == LP3944_LED_TYPE_LED_INVERTED && status < 2)
206 status = 1 - status; 209 status = 1 - status;
diff --git a/drivers/leds/leds-lp8788.c b/drivers/leds/leds-lp8788.c
index 0eee38fc0565..38c253a43700 100644
--- a/drivers/leds/leds-lp8788.c
+++ b/drivers/leds/leds-lp8788.c
@@ -146,15 +146,13 @@ static int lp8788_led_probe(struct platform_device *pdev)
146 146
147 mutex_init(&led->lock); 147 mutex_init(&led->lock);
148 148
149 platform_set_drvdata(pdev, led);
150
151 ret = lp8788_led_init_device(led, led_pdata); 149 ret = lp8788_led_init_device(led, led_pdata);
152 if (ret) { 150 if (ret) {
153 dev_err(dev, "led init device err: %d\n", ret); 151 dev_err(dev, "led init device err: %d\n", ret);
154 return ret; 152 return ret;
155 } 153 }
156 154
157 ret = led_classdev_register(dev, &led->led_dev); 155 ret = devm_led_classdev_register(dev, &led->led_dev);
158 if (ret) { 156 if (ret) {
159 dev_err(dev, "led register err: %d\n", ret); 157 dev_err(dev, "led register err: %d\n", ret);
160 return ret; 158 return ret;
@@ -163,18 +161,8 @@ static int lp8788_led_probe(struct platform_device *pdev)
163 return 0; 161 return 0;
164} 162}
165 163
166static int lp8788_led_remove(struct platform_device *pdev)
167{
168 struct lp8788_led *led = platform_get_drvdata(pdev);
169
170 led_classdev_unregister(&led->led_dev);
171
172 return 0;
173}
174
175static struct platform_driver lp8788_led_driver = { 164static struct platform_driver lp8788_led_driver = {
176 .probe = lp8788_led_probe, 165 .probe = lp8788_led_probe,
177 .remove = lp8788_led_remove,
178 .driver = { 166 .driver = {
179 .name = LP8788_DEV_KEYLED, 167 .name = LP8788_DEV_KEYLED,
180 }, 168 },
diff --git a/drivers/leds/leds-max8997.c b/drivers/leds/leds-max8997.c
index 01b459069358..4edf74f1d6d4 100644
--- a/drivers/leds/leds-max8997.c
+++ b/drivers/leds/leds-max8997.c
@@ -281,30 +281,18 @@ static int max8997_led_probe(struct platform_device *pdev)
281 281
282 mutex_init(&led->mutex); 282 mutex_init(&led->mutex);
283 283
284 platform_set_drvdata(pdev, led); 284 ret = devm_led_classdev_register(&pdev->dev, &led->cdev);
285
286 ret = led_classdev_register(&pdev->dev, &led->cdev);
287 if (ret < 0) 285 if (ret < 0)
288 return ret; 286 return ret;
289 287
290 return 0; 288 return 0;
291} 289}
292 290
293static int max8997_led_remove(struct platform_device *pdev)
294{
295 struct max8997_led *led = platform_get_drvdata(pdev);
296
297 led_classdev_unregister(&led->cdev);
298
299 return 0;
300}
301
302static struct platform_driver max8997_led_driver = { 291static struct platform_driver max8997_led_driver = {
303 .driver = { 292 .driver = {
304 .name = "max8997-led", 293 .name = "max8997-led",
305 }, 294 },
306 .probe = max8997_led_probe, 295 .probe = max8997_led_probe,
307 .remove = max8997_led_remove,
308}; 296};
309 297
310module_platform_driver(max8997_led_driver); 298module_platform_driver(max8997_led_driver);
diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c
index 83641a7b299a..404da451cb88 100644
--- a/drivers/leds/leds-s3c24xx.c
+++ b/drivers/leds/leds-s3c24xx.c
@@ -29,11 +29,6 @@ struct s3c24xx_gpio_led {
29 struct s3c24xx_led_platdata *pdata; 29 struct s3c24xx_led_platdata *pdata;
30}; 30};
31 31
32static inline struct s3c24xx_gpio_led *pdev_to_gpio(struct platform_device *dev)
33{
34 return platform_get_drvdata(dev);
35}
36
37static inline struct s3c24xx_gpio_led *to_gpio(struct led_classdev *led_cdev) 32static inline struct s3c24xx_gpio_led *to_gpio(struct led_classdev *led_cdev)
38{ 33{
39 return container_of(led_cdev, struct s3c24xx_gpio_led, cdev); 34 return container_of(led_cdev, struct s3c24xx_gpio_led, cdev);
@@ -59,15 +54,6 @@ static void s3c24xx_led_set(struct led_classdev *led_cdev,
59 } 54 }
60} 55}
61 56
62static int s3c24xx_led_remove(struct platform_device *dev)
63{
64 struct s3c24xx_gpio_led *led = pdev_to_gpio(dev);
65
66 led_classdev_unregister(&led->cdev);
67
68 return 0;
69}
70
71static int s3c24xx_led_probe(struct platform_device *dev) 57static int s3c24xx_led_probe(struct platform_device *dev)
72{ 58{
73 struct s3c24xx_led_platdata *pdata = dev_get_platdata(&dev->dev); 59 struct s3c24xx_led_platdata *pdata = dev_get_platdata(&dev->dev);
@@ -79,8 +65,6 @@ static int s3c24xx_led_probe(struct platform_device *dev)
79 if (!led) 65 if (!led)
80 return -ENOMEM; 66 return -ENOMEM;
81 67
82 platform_set_drvdata(dev, led);
83
84 led->cdev.brightness_set = s3c24xx_led_set; 68 led->cdev.brightness_set = s3c24xx_led_set;
85 led->cdev.default_trigger = pdata->def_trigger; 69 led->cdev.default_trigger = pdata->def_trigger;
86 led->cdev.name = pdata->name; 70 led->cdev.name = pdata->name;
@@ -104,7 +88,7 @@ static int s3c24xx_led_probe(struct platform_device *dev)
104 88
105 /* register our new led device */ 89 /* register our new led device */
106 90
107 ret = led_classdev_register(&dev->dev, &led->cdev); 91 ret = devm_led_classdev_register(&dev->dev, &led->cdev);
108 if (ret < 0) 92 if (ret < 0)
109 dev_err(&dev->dev, "led_classdev_register failed\n"); 93 dev_err(&dev->dev, "led_classdev_register failed\n");
110 94
@@ -113,7 +97,6 @@ static int s3c24xx_led_probe(struct platform_device *dev)
113 97
114static struct platform_driver s3c24xx_led_driver = { 98static struct platform_driver s3c24xx_led_driver = {
115 .probe = s3c24xx_led_probe, 99 .probe = s3c24xx_led_probe,
116 .remove = s3c24xx_led_remove,
117 .driver = { 100 .driver = {
118 .name = "s3c24xx_led", 101 .name = "s3c24xx_led",
119 }, 102 },
diff --git a/drivers/leds/leds-wm831x-status.c b/drivers/leds/leds-wm831x-status.c
index 64a22263e7fc..be93b20e792a 100644
--- a/drivers/leds/leds-wm831x-status.c
+++ b/drivers/leds/leds-wm831x-status.c
@@ -239,7 +239,6 @@ static int wm831x_status_probe(struct platform_device *pdev)
239 GFP_KERNEL); 239 GFP_KERNEL);
240 if (!drvdata) 240 if (!drvdata)
241 return -ENOMEM; 241 return -ENOMEM;
242 platform_set_drvdata(pdev, drvdata);
243 242
244 drvdata->wm831x = wm831x; 243 drvdata->wm831x = wm831x;
245 drvdata->reg = res->start; 244 drvdata->reg = res->start;
@@ -284,7 +283,7 @@ static int wm831x_status_probe(struct platform_device *pdev)
284 drvdata->cdev.blink_set = wm831x_status_blink_set; 283 drvdata->cdev.blink_set = wm831x_status_blink_set;
285 drvdata->cdev.groups = wm831x_status_groups; 284 drvdata->cdev.groups = wm831x_status_groups;
286 285
287 ret = led_classdev_register(wm831x->dev, &drvdata->cdev); 286 ret = devm_led_classdev_register(wm831x->dev, &drvdata->cdev);
288 if (ret < 0) { 287 if (ret < 0) {
289 dev_err(&pdev->dev, "Failed to register LED: %d\n", ret); 288 dev_err(&pdev->dev, "Failed to register LED: %d\n", ret);
290 return ret; 289 return ret;
@@ -293,21 +292,11 @@ static int wm831x_status_probe(struct platform_device *pdev)
293 return 0; 292 return 0;
294} 293}
295 294
296static int wm831x_status_remove(struct platform_device *pdev)
297{
298 struct wm831x_status *drvdata = platform_get_drvdata(pdev);
299
300 led_classdev_unregister(&drvdata->cdev);
301
302 return 0;
303}
304
305static struct platform_driver wm831x_status_driver = { 295static struct platform_driver wm831x_status_driver = {
306 .driver = { 296 .driver = {
307 .name = "wm831x-status", 297 .name = "wm831x-status",
308 }, 298 },
309 .probe = wm831x_status_probe, 299 .probe = wm831x_status_probe,
310 .remove = wm831x_status_remove,
311}; 300};
312 301
313module_platform_driver(wm831x_status_driver); 302module_platform_driver(wm831x_status_driver);
diff --git a/include/linux/leds.h b/include/linux/leds.h
index bc1476fda96e..f203a8f89d30 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -39,6 +39,7 @@ struct led_classdev {
39 39
40 /* Lower 16 bits reflect status */ 40 /* Lower 16 bits reflect status */
41#define LED_SUSPENDED (1 << 0) 41#define LED_SUSPENDED (1 << 0)
42#define LED_UNREGISTERING (1 << 1)
42 /* Upper 16 bits reflect control information */ 43 /* Upper 16 bits reflect control information */
43#define LED_CORE_SUSPENDRESUME (1 << 16) 44#define LED_CORE_SUSPENDRESUME (1 << 16)
44#define LED_BLINK_ONESHOT (1 << 17) 45#define LED_BLINK_ONESHOT (1 << 17)
@@ -48,9 +49,12 @@ struct led_classdev {
48#define LED_BLINK_DISABLE (1 << 21) 49#define LED_BLINK_DISABLE (1 << 21)
49#define LED_SYSFS_DISABLE (1 << 22) 50#define LED_SYSFS_DISABLE (1 << 22)
50#define LED_DEV_CAP_FLASH (1 << 23) 51#define LED_DEV_CAP_FLASH (1 << 23)
52#define LED_HW_PLUGGABLE (1 << 24)
51 53
52 /* Set LED brightness level */ 54 /* Set LED brightness level
53 /* Must not sleep, use a workqueue if needed */ 55 * Must not sleep. Use brightness_set_blocking for drivers
56 * that can sleep while setting brightness.
57 */
54 void (*brightness_set)(struct led_classdev *led_cdev, 58 void (*brightness_set)(struct led_classdev *led_cdev,
55 enum led_brightness brightness); 59 enum led_brightness brightness);
56 /* 60 /*