aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/leds
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/leds')
-rw-r--r--drivers/leds/Kconfig29
-rw-r--r--drivers/leds/Makefile3
-rw-r--r--drivers/leds/led-class.c21
-rw-r--r--drivers/leds/leds-da9052.c214
-rw-r--r--drivers/leds/leds-lm3530.c100
-rw-r--r--drivers/leds/leds-lm3533.c785
-rw-r--r--drivers/leds/leds-lp5521.c12
-rw-r--r--drivers/leds/leds-mc13783.c2
-rw-r--r--drivers/leds/leds-pca955x.c95
-rw-r--r--drivers/leds/ledtrig-backlight.c4
-rw-r--r--drivers/leds/ledtrig-gpio.c4
-rw-r--r--drivers/leds/ledtrig-heartbeat.c32
-rw-r--r--drivers/leds/ledtrig-timer.c54
-rw-r--r--drivers/leds/ledtrig-transient.c237
14 files changed, 1461 insertions, 131 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index ff4b8cfda585..04cb8c88d74b 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -50,6 +50,19 @@ config LEDS_LM3530
50 controlled manually or using PWM input or using ambient 50 controlled manually or using PWM input or using ambient
51 light automatically. 51 light automatically.
52 52
53config LEDS_LM3533
54 tristate "LED support for LM3533"
55 depends on LEDS_CLASS
56 depends on MFD_LM3533
57 help
58 This option enables support for the LEDs on National Semiconductor /
59 TI LM3533 Lighting Power chips.
60
61 The LEDs can be controlled directly, through PWM input, or by the
62 ambient-light-sensor interface. The chip supports
63 hardware-accelerated blinking with maximum on and off periods of 9.8
64 and 77 seconds respectively.
65
53config LEDS_LOCOMO 66config LEDS_LOCOMO
54 tristate "LED Support for Locomo device" 67 tristate "LED Support for Locomo device"
55 depends on LEDS_CLASS 68 depends on LEDS_CLASS
@@ -259,6 +272,14 @@ config LEDS_DA903X
259 This option enables support for on-chip LED drivers found 272 This option enables support for on-chip LED drivers found
260 on Dialog Semiconductor DA9030/DA9034 PMICs. 273 on Dialog Semiconductor DA9030/DA9034 PMICs.
261 274
275config LEDS_DA9052
276 tristate "Dialog DA9052/DA9053 LEDS"
277 depends on LEDS_CLASS
278 depends on PMIC_DA9052
279 help
280 This option enables support for on-chip LED drivers found
281 on Dialog Semiconductor DA9052-BC and DA9053-AA/Bx PMICs.
282
262config LEDS_DAC124S085 283config LEDS_DAC124S085
263 tristate "LED Support for DAC124S085 SPI DAC" 284 tristate "LED Support for DAC124S085 SPI DAC"
264 depends on LEDS_CLASS 285 depends on LEDS_CLASS
@@ -471,4 +492,12 @@ config LEDS_TRIGGER_DEFAULT_ON
471comment "iptables trigger is under Netfilter config (LED target)" 492comment "iptables trigger is under Netfilter config (LED target)"
472 depends on LEDS_TRIGGERS 493 depends on LEDS_TRIGGERS
473 494
495config LEDS_TRIGGER_TRANSIENT
496 tristate "LED Transient Trigger"
497 depends on LEDS_TRIGGERS
498 help
499 This allows one time activation of a transient state on
500 GPIO/PWM based hadrware.
501 If unsure, say Y.
502
474endif # NEW_LEDS 503endif # NEW_LEDS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 890481cb09f6..f8958cd6cf6e 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_LEDS_ATMEL_PWM) += leds-atmel-pwm.o
10obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o 10obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o
11obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o 11obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o
12obj-$(CONFIG_LEDS_LM3530) += leds-lm3530.o 12obj-$(CONFIG_LEDS_LM3530) += leds-lm3530.o
13obj-$(CONFIG_LEDS_LM3533) += leds-lm3533.o
13obj-$(CONFIG_LEDS_MIKROTIK_RB532) += leds-rb532.o 14obj-$(CONFIG_LEDS_MIKROTIK_RB532) += leds-rb532.o
14obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o 15obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o
15obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o 16obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
@@ -31,6 +32,7 @@ obj-$(CONFIG_LEDS_FSG) += leds-fsg.o
31obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o 32obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o
32obj-$(CONFIG_LEDS_PCA9633) += leds-pca9633.o 33obj-$(CONFIG_LEDS_PCA9633) += leds-pca9633.o
33obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o 34obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o
35obj-$(CONFIG_LEDS_DA9052) += leds-da9052.o
34obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o 36obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o
35obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o 37obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o
36obj-$(CONFIG_LEDS_PWM) += leds-pwm.o 38obj-$(CONFIG_LEDS_PWM) += leds-pwm.o
@@ -56,3 +58,4 @@ obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o
56obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o 58obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o
57obj-$(CONFIG_LEDS_TRIGGER_GPIO) += ledtrig-gpio.o 59obj-$(CONFIG_LEDS_TRIGGER_GPIO) += ledtrig-gpio.o
58obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o 60obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o
61obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT) += ledtrig-transient.o
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 5bff8439dc68..8ee92c81aec2 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -44,23 +44,18 @@ static ssize_t led_brightness_store(struct device *dev,
44 struct device_attribute *attr, const char *buf, size_t size) 44 struct device_attribute *attr, const char *buf, size_t size)
45{ 45{
46 struct led_classdev *led_cdev = dev_get_drvdata(dev); 46 struct led_classdev *led_cdev = dev_get_drvdata(dev);
47 unsigned long state;
47 ssize_t ret = -EINVAL; 48 ssize_t ret = -EINVAL;
48 char *after;
49 unsigned long state = simple_strtoul(buf, &after, 10);
50 size_t count = after - buf;
51 49
52 if (isspace(*after)) 50 ret = kstrtoul(buf, 10, &state);
53 count++; 51 if (ret)
52 return ret;
54 53
55 if (count == size) { 54 if (state == LED_OFF)
56 ret = count; 55 led_trigger_remove(led_cdev);
56 led_set_brightness(led_cdev, state);
57 57
58 if (state == LED_OFF) 58 return size;
59 led_trigger_remove(led_cdev);
60 led_set_brightness(led_cdev, state);
61 }
62
63 return ret;
64} 59}
65 60
66static ssize_t led_max_brightness_show(struct device *dev, 61static ssize_t led_max_brightness_show(struct device *dev,
diff --git a/drivers/leds/leds-da9052.c b/drivers/leds/leds-da9052.c
new file mode 100644
index 000000000000..58a5244c437e
--- /dev/null
+++ b/drivers/leds/leds-da9052.c
@@ -0,0 +1,214 @@
1/*
2 * LED Driver for Dialog DA9052 PMICs.
3 *
4 * Copyright(c) 2012 Dialog Semiconductor Ltd.
5 *
6 * Author: David Dajun Chen <dchen@diasemi.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 */
14
15#include <linux/module.h>
16#include <linux/kernel.h>
17#include <linux/init.h>
18#include <linux/platform_device.h>
19#include <linux/leds.h>
20#include <linux/workqueue.h>
21#include <linux/slab.h>
22
23#include <linux/mfd/da9052/reg.h>
24#include <linux/mfd/da9052/da9052.h>
25#include <linux/mfd/da9052/pdata.h>
26
27#define DA9052_OPENDRAIN_OUTPUT 2
28#define DA9052_SET_HIGH_LVL_OUTPUT (1 << 3)
29#define DA9052_MASK_UPPER_NIBBLE 0xF0
30#define DA9052_MASK_LOWER_NIBBLE 0x0F
31#define DA9052_NIBBLE_SHIFT 4
32#define DA9052_MAX_BRIGHTNESS 0x5f
33
34struct da9052_led {
35 struct led_classdev cdev;
36 struct work_struct work;
37 struct da9052 *da9052;
38 unsigned char led_index;
39 unsigned char id;
40 int brightness;
41};
42
43static unsigned char led_reg[] = {
44 DA9052_LED_CONT_4_REG,
45 DA9052_LED_CONT_5_REG,
46};
47
48static int da9052_set_led_brightness(struct da9052_led *led)
49{
50 u8 val;
51 int error;
52
53 val = (led->brightness & 0x7f) | DA9052_LED_CONT_DIM;
54
55 error = da9052_reg_write(led->da9052, led_reg[led->led_index], val);
56 if (error < 0)
57 dev_err(led->da9052->dev, "Failed to set led brightness, %d\n",
58 error);
59 return error;
60}
61
62static void da9052_led_work(struct work_struct *work)
63{
64 struct da9052_led *led = container_of(work, struct da9052_led, work);
65
66 da9052_set_led_brightness(led);
67}
68
69static void da9052_led_set(struct led_classdev *led_cdev,
70 enum led_brightness value)
71{
72 struct da9052_led *led;
73
74 led = container_of(led_cdev, struct da9052_led, cdev);
75 led->brightness = value;
76 schedule_work(&led->work);
77}
78
79static int da9052_configure_leds(struct da9052 *da9052)
80{
81 int error;
82 unsigned char register_value = DA9052_OPENDRAIN_OUTPUT
83 | DA9052_SET_HIGH_LVL_OUTPUT;
84
85 error = da9052_reg_update(da9052, DA9052_GPIO_14_15_REG,
86 DA9052_MASK_LOWER_NIBBLE,
87 register_value);
88
89 if (error < 0) {
90 dev_err(da9052->dev, "Failed to write GPIO 14-15 reg, %d\n",
91 error);
92 return error;
93 }
94
95 error = da9052_reg_update(da9052, DA9052_GPIO_14_15_REG,
96 DA9052_MASK_UPPER_NIBBLE,
97 register_value << DA9052_NIBBLE_SHIFT);
98 if (error < 0)
99 dev_err(da9052->dev, "Failed to write GPIO 14-15 reg, %d\n",
100 error);
101
102 return error;
103}
104
105static int __devinit da9052_led_probe(struct platform_device *pdev)
106{
107 struct da9052_pdata *pdata;
108 struct da9052 *da9052;
109 struct led_platform_data *pled;
110 struct da9052_led *led = NULL;
111 int error = -ENODEV;
112 int i;
113
114 da9052 = dev_get_drvdata(pdev->dev.parent);
115 pdata = da9052->dev->platform_data;
116 if (pdata == NULL) {
117 dev_err(&pdev->dev, "No platform data\n");
118 goto err;
119 }
120
121 pled = pdata->pled;
122 if (pled == NULL) {
123 dev_err(&pdev->dev, "No platform data for LED\n");
124 goto err;
125 }
126
127 led = devm_kzalloc(&pdev->dev,
128 sizeof(struct da9052_led) * pled->num_leds,
129 GFP_KERNEL);
130 if (led == NULL) {
131 dev_err(&pdev->dev, "Failed to alloc memory\n");
132 error = -ENOMEM;
133 goto err;
134 }
135
136 for (i = 0; i < pled->num_leds; i++) {
137 led[i].cdev.name = pled->leds[i].name;
138 led[i].cdev.brightness_set = da9052_led_set;
139 led[i].cdev.brightness = LED_OFF;
140 led[i].cdev.max_brightness = DA9052_MAX_BRIGHTNESS;
141 led[i].brightness = LED_OFF;
142 led[i].led_index = pled->leds[i].flags;
143 led[i].da9052 = dev_get_drvdata(pdev->dev.parent);
144 INIT_WORK(&led[i].work, da9052_led_work);
145
146 error = led_classdev_register(pdev->dev.parent, &led[i].cdev);
147 if (error) {
148 dev_err(&pdev->dev, "Failed to register led %d\n",
149 led[i].led_index);
150 goto err_register;
151 }
152
153 error = da9052_set_led_brightness(&led[i]);
154 if (error) {
155 dev_err(&pdev->dev, "Unable to init led %d\n",
156 led[i].led_index);
157 continue;
158 }
159 }
160 error = da9052_configure_leds(led->da9052);
161 if (error) {
162 dev_err(&pdev->dev, "Failed to configure GPIO LED%d\n", error);
163 goto err_register;
164 }
165
166 platform_set_drvdata(pdev, led);
167
168 return 0;
169
170err_register:
171 for (i = i - 1; i >= 0; i--) {
172 led_classdev_unregister(&led[i].cdev);
173 cancel_work_sync(&led[i].work);
174 }
175err:
176 return error;
177}
178
179static int __devexit da9052_led_remove(struct platform_device *pdev)
180{
181 struct da9052_led *led = platform_get_drvdata(pdev);
182 struct da9052_pdata *pdata;
183 struct da9052 *da9052;
184 struct led_platform_data *pled;
185 int i;
186
187 da9052 = dev_get_drvdata(pdev->dev.parent);
188 pdata = da9052->dev->platform_data;
189 pled = pdata->pled;
190
191 for (i = 0; i < pled->num_leds; i++) {
192 led[i].brightness = 0;
193 da9052_set_led_brightness(&led[i]);
194 led_classdev_unregister(&led[i].cdev);
195 cancel_work_sync(&led[i].work);
196 }
197
198 return 0;
199}
200
201static struct platform_driver da9052_led_driver = {
202 .driver = {
203 .name = "da9052-leds",
204 .owner = THIS_MODULE,
205 },
206 .probe = da9052_led_probe,
207 .remove = __devexit_p(da9052_led_remove),
208};
209
210module_platform_driver(da9052_led_driver);
211
212MODULE_AUTHOR("Dialog Semiconductor Ltd <dchen@diasemi.com>");
213MODULE_DESCRIPTION("LED driver for Dialog DA9052 PMIC");
214MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-lm3530.c b/drivers/leds/leds-lm3530.c
index 968fd5fef4fc..84ba6de8039c 100644
--- a/drivers/leds/leds-lm3530.c
+++ b/drivers/leds/leds-lm3530.c
@@ -113,6 +113,18 @@ struct lm3530_data {
113 bool enable; 113 bool enable;
114}; 114};
115 115
116/*
117 * struct lm3530_als_data
118 * @config : value of ALS configuration register
119 * @imp_sel : value of ALS resistor select register
120 * @zone : values of ALS ZB(Zone Boundary) registers
121 */
122struct lm3530_als_data {
123 u8 config;
124 u8 imp_sel;
125 u8 zones[LM3530_ALS_ZB_MAX];
126};
127
116static const u8 lm3530_reg[LM3530_REG_MAX] = { 128static const u8 lm3530_reg[LM3530_REG_MAX] = {
117 LM3530_GEN_CONFIG, 129 LM3530_GEN_CONFIG,
118 LM3530_ALS_CONFIG, 130 LM3530_ALS_CONFIG,
@@ -141,29 +153,65 @@ static int lm3530_get_mode_from_str(const char *str)
141 return -1; 153 return -1;
142} 154}
143 155
156static void lm3530_als_configure(struct lm3530_platform_data *pdata,
157 struct lm3530_als_data *als)
158{
159 int i;
160 u32 als_vmin, als_vmax, als_vstep;
161
162 if (pdata->als_vmax == 0) {
163 pdata->als_vmin = 0;
164 pdata->als_vmax = LM3530_ALS_WINDOW_mV;
165 }
166
167 als_vmin = pdata->als_vmin;
168 als_vmax = pdata->als_vmax;
169
170 if ((als_vmax - als_vmin) > LM3530_ALS_WINDOW_mV)
171 pdata->als_vmax = als_vmax = als_vmin + LM3530_ALS_WINDOW_mV;
172
173 /* n zone boundary makes n+1 zones */
174 als_vstep = (als_vmax - als_vmin) / (LM3530_ALS_ZB_MAX + 1);
175
176 for (i = 0; i < LM3530_ALS_ZB_MAX; i++)
177 als->zones[i] = (((als_vmin + LM3530_ALS_OFFSET_mV) +
178 als_vstep + (i * als_vstep)) * LED_FULL) / 1000;
179
180 als->config =
181 (pdata->als_avrg_time << LM3530_ALS_AVG_TIME_SHIFT) |
182 (LM3530_ENABLE_ALS) |
183 (pdata->als_input_mode << LM3530_ALS_SEL_SHIFT);
184
185 als->imp_sel =
186 (pdata->als1_resistor_sel << LM3530_ALS1_IMP_SHIFT) |
187 (pdata->als2_resistor_sel << LM3530_ALS2_IMP_SHIFT);
188}
189
144static int lm3530_init_registers(struct lm3530_data *drvdata) 190static int lm3530_init_registers(struct lm3530_data *drvdata)
145{ 191{
146 int ret = 0; 192 int ret = 0;
147 int i; 193 int i;
148 u8 gen_config; 194 u8 gen_config;
149 u8 als_config = 0;
150 u8 brt_ramp; 195 u8 brt_ramp;
151 u8 als_imp_sel = 0;
152 u8 brightness; 196 u8 brightness;
153 u8 reg_val[LM3530_REG_MAX]; 197 u8 reg_val[LM3530_REG_MAX];
154 u8 zones[LM3530_ALS_ZB_MAX];
155 u32 als_vmin, als_vmax, als_vstep;
156 struct lm3530_platform_data *pdata = drvdata->pdata; 198 struct lm3530_platform_data *pdata = drvdata->pdata;
157 struct i2c_client *client = drvdata->client; 199 struct i2c_client *client = drvdata->client;
158 struct lm3530_pwm_data *pwm = &pdata->pwm_data; 200 struct lm3530_pwm_data *pwm = &pdata->pwm_data;
201 struct lm3530_als_data als;
202
203 memset(&als, 0, sizeof(struct lm3530_als_data));
159 204
160 gen_config = (pdata->brt_ramp_law << LM3530_RAMP_LAW_SHIFT) | 205 gen_config = (pdata->brt_ramp_law << LM3530_RAMP_LAW_SHIFT) |
161 ((pdata->max_current & 7) << LM3530_MAX_CURR_SHIFT); 206 ((pdata->max_current & 7) << LM3530_MAX_CURR_SHIFT);
162 207
163 switch (drvdata->mode) { 208 switch (drvdata->mode) {
164 case LM3530_BL_MODE_MANUAL: 209 case LM3530_BL_MODE_MANUAL:
210 gen_config |= LM3530_ENABLE_I2C;
211 break;
165 case LM3530_BL_MODE_ALS: 212 case LM3530_BL_MODE_ALS:
166 gen_config |= LM3530_ENABLE_I2C; 213 gen_config |= LM3530_ENABLE_I2C;
214 lm3530_als_configure(pdata, &als);
167 break; 215 break;
168 case LM3530_BL_MODE_PWM: 216 case LM3530_BL_MODE_PWM:
169 gen_config |= LM3530_ENABLE_PWM | LM3530_ENABLE_PWM_SIMPLE | 217 gen_config |= LM3530_ENABLE_PWM | LM3530_ENABLE_PWM_SIMPLE |
@@ -171,38 +219,6 @@ static int lm3530_init_registers(struct lm3530_data *drvdata)
171 break; 219 break;
172 } 220 }
173 221
174 if (drvdata->mode == LM3530_BL_MODE_ALS) {
175 if (pdata->als_vmax == 0) {
176 pdata->als_vmin = 0;
177 pdata->als_vmax = LM3530_ALS_WINDOW_mV;
178 }
179
180 als_vmin = pdata->als_vmin;
181 als_vmax = pdata->als_vmax;
182
183 if ((als_vmax - als_vmin) > LM3530_ALS_WINDOW_mV)
184 pdata->als_vmax = als_vmax =
185 als_vmin + LM3530_ALS_WINDOW_mV;
186
187 /* n zone boundary makes n+1 zones */
188 als_vstep = (als_vmax - als_vmin) / (LM3530_ALS_ZB_MAX + 1);
189
190 for (i = 0; i < LM3530_ALS_ZB_MAX; i++)
191 zones[i] = (((als_vmin + LM3530_ALS_OFFSET_mV) +
192 als_vstep + (i * als_vstep)) * LED_FULL)
193 / 1000;
194
195 als_config =
196 (pdata->als_avrg_time << LM3530_ALS_AVG_TIME_SHIFT) |
197 (LM3530_ENABLE_ALS) |
198 (pdata->als_input_mode << LM3530_ALS_SEL_SHIFT);
199
200 als_imp_sel =
201 (pdata->als1_resistor_sel << LM3530_ALS1_IMP_SHIFT) |
202 (pdata->als2_resistor_sel << LM3530_ALS2_IMP_SHIFT);
203
204 }
205
206 brt_ramp = (pdata->brt_ramp_fall << LM3530_BRT_RAMP_FALL_SHIFT) | 222 brt_ramp = (pdata->brt_ramp_fall << LM3530_BRT_RAMP_FALL_SHIFT) |
207 (pdata->brt_ramp_rise << LM3530_BRT_RAMP_RISE_SHIFT); 223 (pdata->brt_ramp_rise << LM3530_BRT_RAMP_RISE_SHIFT);
208 224
@@ -215,14 +231,14 @@ static int lm3530_init_registers(struct lm3530_data *drvdata)
215 brightness = drvdata->led_dev.max_brightness; 231 brightness = drvdata->led_dev.max_brightness;
216 232
217 reg_val[0] = gen_config; /* LM3530_GEN_CONFIG */ 233 reg_val[0] = gen_config; /* LM3530_GEN_CONFIG */
218 reg_val[1] = als_config; /* LM3530_ALS_CONFIG */ 234 reg_val[1] = als.config; /* LM3530_ALS_CONFIG */
219 reg_val[2] = brt_ramp; /* LM3530_BRT_RAMP_RATE */ 235 reg_val[2] = brt_ramp; /* LM3530_BRT_RAMP_RATE */
220 reg_val[3] = als_imp_sel; /* LM3530_ALS_IMP_SELECT */ 236 reg_val[3] = als.imp_sel; /* LM3530_ALS_IMP_SELECT */
221 reg_val[4] = brightness; /* LM3530_BRT_CTRL_REG */ 237 reg_val[4] = brightness; /* LM3530_BRT_CTRL_REG */
222 reg_val[5] = zones[0]; /* LM3530_ALS_ZB0_REG */ 238 reg_val[5] = als.zones[0]; /* LM3530_ALS_ZB0_REG */
223 reg_val[6] = zones[1]; /* LM3530_ALS_ZB1_REG */ 239 reg_val[6] = als.zones[1]; /* LM3530_ALS_ZB1_REG */
224 reg_val[7] = zones[2]; /* LM3530_ALS_ZB2_REG */ 240 reg_val[7] = als.zones[2]; /* LM3530_ALS_ZB2_REG */
225 reg_val[8] = zones[3]; /* LM3530_ALS_ZB3_REG */ 241 reg_val[8] = als.zones[3]; /* LM3530_ALS_ZB3_REG */
226 reg_val[9] = LM3530_DEF_ZT_0; /* LM3530_ALS_Z0T_REG */ 242 reg_val[9] = LM3530_DEF_ZT_0; /* LM3530_ALS_Z0T_REG */
227 reg_val[10] = LM3530_DEF_ZT_1; /* LM3530_ALS_Z1T_REG */ 243 reg_val[10] = LM3530_DEF_ZT_1; /* LM3530_ALS_Z1T_REG */
228 reg_val[11] = LM3530_DEF_ZT_2; /* LM3530_ALS_Z2T_REG */ 244 reg_val[11] = LM3530_DEF_ZT_2; /* LM3530_ALS_Z2T_REG */
diff --git a/drivers/leds/leds-lm3533.c b/drivers/leds/leds-lm3533.c
new file mode 100644
index 000000000000..f56b6e7ffdac
--- /dev/null
+++ b/drivers/leds/leds-lm3533.c
@@ -0,0 +1,785 @@
1/*
2 * leds-lm3533.c -- LM3533 LED driver
3 *
4 * Copyright (C) 2011-2012 Texas Instruments
5 *
6 * Author: Johan Hovold <jhovold@gmail.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 */
13
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/leds.h>
17#include <linux/mfd/core.h>
18#include <linux/mutex.h>
19#include <linux/platform_device.h>
20#include <linux/slab.h>
21#include <linux/workqueue.h>
22
23#include <linux/mfd/lm3533.h>
24
25
26#define LM3533_LVCTRLBANK_MIN 2
27#define LM3533_LVCTRLBANK_MAX 5
28#define LM3533_LVCTRLBANK_COUNT 4
29#define LM3533_RISEFALLTIME_MAX 7
30#define LM3533_ALS_CHANNEL_LV_MIN 1
31#define LM3533_ALS_CHANNEL_LV_MAX 2
32
33#define LM3533_REG_CTRLBANK_BCONF_BASE 0x1b
34#define LM3533_REG_PATTERN_ENABLE 0x28
35#define LM3533_REG_PATTERN_LOW_TIME_BASE 0x71
36#define LM3533_REG_PATTERN_HIGH_TIME_BASE 0x72
37#define LM3533_REG_PATTERN_RISETIME_BASE 0x74
38#define LM3533_REG_PATTERN_FALLTIME_BASE 0x75
39
40#define LM3533_REG_PATTERN_STEP 0x10
41
42#define LM3533_REG_CTRLBANK_BCONF_MAPPING_MASK 0x04
43#define LM3533_REG_CTRLBANK_BCONF_ALS_EN_MASK 0x02
44#define LM3533_REG_CTRLBANK_BCONF_ALS_CHANNEL_MASK 0x01
45
46#define LM3533_LED_FLAG_PATTERN_ENABLE 1
47
48
49struct lm3533_led {
50 struct lm3533 *lm3533;
51 struct lm3533_ctrlbank cb;
52 struct led_classdev cdev;
53 int id;
54
55 struct mutex mutex;
56 unsigned long flags;
57
58 struct work_struct work;
59 u8 new_brightness;
60};
61
62
63static inline struct lm3533_led *to_lm3533_led(struct led_classdev *cdev)
64{
65 return container_of(cdev, struct lm3533_led, cdev);
66}
67
68static inline int lm3533_led_get_ctrlbank_id(struct lm3533_led *led)
69{
70 return led->id + 2;
71}
72
73static inline u8 lm3533_led_get_lv_reg(struct lm3533_led *led, u8 base)
74{
75 return base + led->id;
76}
77
78static inline u8 lm3533_led_get_pattern(struct lm3533_led *led)
79{
80 return led->id;
81}
82
83static inline u8 lm3533_led_get_pattern_reg(struct lm3533_led *led,
84 u8 base)
85{
86 return base + lm3533_led_get_pattern(led) * LM3533_REG_PATTERN_STEP;
87}
88
89static int lm3533_led_pattern_enable(struct lm3533_led *led, int enable)
90{
91 u8 mask;
92 u8 val;
93 int pattern;
94 int state;
95 int ret = 0;
96
97 dev_dbg(led->cdev.dev, "%s - %d\n", __func__, enable);
98
99 mutex_lock(&led->mutex);
100
101 state = test_bit(LM3533_LED_FLAG_PATTERN_ENABLE, &led->flags);
102 if ((enable && state) || (!enable && !state))
103 goto out;
104
105 pattern = lm3533_led_get_pattern(led);
106 mask = 1 << (2 * pattern);
107
108 if (enable)
109 val = mask;
110 else
111 val = 0;
112
113 ret = lm3533_update(led->lm3533, LM3533_REG_PATTERN_ENABLE, val, mask);
114 if (ret) {
115 dev_err(led->cdev.dev, "failed to enable pattern %d (%d)\n",
116 pattern, enable);
117 goto out;
118 }
119
120 __change_bit(LM3533_LED_FLAG_PATTERN_ENABLE, &led->flags);
121out:
122 mutex_unlock(&led->mutex);
123
124 return ret;
125}
126
127static void lm3533_led_work(struct work_struct *work)
128{
129 struct lm3533_led *led = container_of(work, struct lm3533_led, work);
130
131 dev_dbg(led->cdev.dev, "%s - %u\n", __func__, led->new_brightness);
132
133 if (led->new_brightness == 0)
134 lm3533_led_pattern_enable(led, 0); /* disable blink */
135
136 lm3533_ctrlbank_set_brightness(&led->cb, led->new_brightness);
137}
138
139static void lm3533_led_set(struct led_classdev *cdev,
140 enum led_brightness value)
141{
142 struct lm3533_led *led = to_lm3533_led(cdev);
143
144 dev_dbg(led->cdev.dev, "%s - %d\n", __func__, value);
145
146 led->new_brightness = value;
147 schedule_work(&led->work);
148}
149
150static enum led_brightness lm3533_led_get(struct led_classdev *cdev)
151{
152 struct lm3533_led *led = to_lm3533_led(cdev);
153 u8 val;
154 int ret;
155
156 ret = lm3533_ctrlbank_get_brightness(&led->cb, &val);
157 if (ret)
158 return ret;
159
160 dev_dbg(led->cdev.dev, "%s - %u\n", __func__, val);
161
162 return val;
163}
164
165/* Pattern generator defines (delays in us). */
166#define LM3533_LED_DELAY1_VMIN 0x00
167#define LM3533_LED_DELAY2_VMIN 0x3d
168#define LM3533_LED_DELAY3_VMIN 0x80
169
170#define LM3533_LED_DELAY1_VMAX (LM3533_LED_DELAY2_VMIN - 1)
171#define LM3533_LED_DELAY2_VMAX (LM3533_LED_DELAY3_VMIN - 1)
172#define LM3533_LED_DELAY3_VMAX 0xff
173
174#define LM3533_LED_DELAY1_TMIN 16384U
175#define LM3533_LED_DELAY2_TMIN 1130496U
176#define LM3533_LED_DELAY3_TMIN 10305536U
177
178#define LM3533_LED_DELAY1_TMAX 999424U
179#define LM3533_LED_DELAY2_TMAX 9781248U
180#define LM3533_LED_DELAY3_TMAX 76890112U
181
182/* t_step = (t_max - t_min) / (v_max - v_min) */
183#define LM3533_LED_DELAY1_TSTEP 16384
184#define LM3533_LED_DELAY2_TSTEP 131072
185#define LM3533_LED_DELAY3_TSTEP 524288
186
187/* Delay limits for hardware accelerated blinking (in ms). */
188#define LM3533_LED_DELAY_ON_MAX \
189 ((LM3533_LED_DELAY2_TMAX + LM3533_LED_DELAY2_TSTEP / 2) / 1000)
190#define LM3533_LED_DELAY_OFF_MAX \
191 ((LM3533_LED_DELAY3_TMAX + LM3533_LED_DELAY3_TSTEP / 2) / 1000)
192
193/*
194 * Returns linear map of *t from [t_min,t_max] to [v_min,v_max] with a step
195 * size of t_step, where
196 *
197 * t_step = (t_max - t_min) / (v_max - v_min)
198 *
199 * and updates *t to reflect the mapped value.
200 */
201static u8 time_to_val(unsigned *t, unsigned t_min, unsigned t_step,
202 u8 v_min, u8 v_max)
203{
204 unsigned val;
205
206 val = (*t + t_step / 2 - t_min) / t_step + v_min;
207
208 *t = t_step * (val - v_min) + t_min;
209
210 return (u8)val;
211}
212
213/*
214 * Returns time code corresponding to *delay (in ms) and updates *delay to
215 * reflect actual hardware delay.
216 *
217 * Hardware supports 256 discrete delay times, divided into three groups with
218 * the following ranges and step-sizes:
219 *
220 * [ 16, 999] [0x00, 0x3e] step 16 ms
221 * [ 1130, 9781] [0x3d, 0x7f] step 131 ms
222 * [10306, 76890] [0x80, 0xff] step 524 ms
223 *
224 * Note that delay group 3 is only available for delay_off.
225 */
226static u8 lm3533_led_get_hw_delay(unsigned *delay)
227{
228 unsigned t;
229 u8 val;
230
231 t = *delay * 1000;
232
233 if (t >= (LM3533_LED_DELAY2_TMAX + LM3533_LED_DELAY3_TMIN) / 2) {
234 t = clamp(t, LM3533_LED_DELAY3_TMIN, LM3533_LED_DELAY3_TMAX);
235 val = time_to_val(&t, LM3533_LED_DELAY3_TMIN,
236 LM3533_LED_DELAY3_TSTEP,
237 LM3533_LED_DELAY3_VMIN,
238 LM3533_LED_DELAY3_VMAX);
239 } else if (t >= (LM3533_LED_DELAY1_TMAX + LM3533_LED_DELAY2_TMIN) / 2) {
240 t = clamp(t, LM3533_LED_DELAY2_TMIN, LM3533_LED_DELAY2_TMAX);
241 val = time_to_val(&t, LM3533_LED_DELAY2_TMIN,
242 LM3533_LED_DELAY2_TSTEP,
243 LM3533_LED_DELAY2_VMIN,
244 LM3533_LED_DELAY2_VMAX);
245 } else {
246 t = clamp(t, LM3533_LED_DELAY1_TMIN, LM3533_LED_DELAY1_TMAX);
247 val = time_to_val(&t, LM3533_LED_DELAY1_TMIN,
248 LM3533_LED_DELAY1_TSTEP,
249 LM3533_LED_DELAY1_VMIN,
250 LM3533_LED_DELAY1_VMAX);
251 }
252
253 *delay = (t + 500) / 1000;
254
255 return val;
256}
257
258/*
259 * Set delay register base to *delay (in ms) and update *delay to reflect
260 * actual hardware delay used.
261 */
262static u8 lm3533_led_delay_set(struct lm3533_led *led, u8 base,
263 unsigned long *delay)
264{
265 unsigned t;
266 u8 val;
267 u8 reg;
268 int ret;
269
270 t = (unsigned)*delay;
271
272 /* Delay group 3 is only available for low time (delay off). */
273 if (base != LM3533_REG_PATTERN_LOW_TIME_BASE)
274 t = min(t, LM3533_LED_DELAY2_TMAX / 1000);
275
276 val = lm3533_led_get_hw_delay(&t);
277
278 dev_dbg(led->cdev.dev, "%s - %lu: %u (0x%02x)\n", __func__,
279 *delay, t, val);
280 reg = lm3533_led_get_pattern_reg(led, base);
281 ret = lm3533_write(led->lm3533, reg, val);
282 if (ret)
283 dev_err(led->cdev.dev, "failed to set delay (%02x)\n", reg);
284
285 *delay = t;
286
287 return ret;
288}
289
290static int lm3533_led_delay_on_set(struct lm3533_led *led, unsigned long *t)
291{
292 return lm3533_led_delay_set(led, LM3533_REG_PATTERN_HIGH_TIME_BASE, t);
293}
294
295static int lm3533_led_delay_off_set(struct lm3533_led *led, unsigned long *t)
296{
297 return lm3533_led_delay_set(led, LM3533_REG_PATTERN_LOW_TIME_BASE, t);
298}
299
300static int lm3533_led_blink_set(struct led_classdev *cdev,
301 unsigned long *delay_on,
302 unsigned long *delay_off)
303{
304 struct lm3533_led *led = to_lm3533_led(cdev);
305 int ret;
306
307 dev_dbg(led->cdev.dev, "%s - on = %lu, off = %lu\n", __func__,
308 *delay_on, *delay_off);
309
310 if (*delay_on > LM3533_LED_DELAY_ON_MAX ||
311 *delay_off > LM3533_LED_DELAY_OFF_MAX)
312 return -EINVAL;
313
314 if (*delay_on == 0 && *delay_off == 0) {
315 *delay_on = 500;
316 *delay_off = 500;
317 }
318
319 ret = lm3533_led_delay_on_set(led, delay_on);
320 if (ret)
321 return ret;
322
323 ret = lm3533_led_delay_off_set(led, delay_off);
324 if (ret)
325 return ret;
326
327 return lm3533_led_pattern_enable(led, 1);
328}
329
330static ssize_t show_id(struct device *dev,
331 struct device_attribute *attr, char *buf)
332{
333 struct led_classdev *led_cdev = dev_get_drvdata(dev);
334 struct lm3533_led *led = to_lm3533_led(led_cdev);
335
336 return scnprintf(buf, PAGE_SIZE, "%d\n", led->id);
337}
338
339/*
340 * Pattern generator rise/fall times:
341 *
342 * 0 - 2048 us (default)
343 * 1 - 262 ms
344 * 2 - 524 ms
345 * 3 - 1.049 s
346 * 4 - 2.097 s
347 * 5 - 4.194 s
348 * 6 - 8.389 s
349 * 7 - 16.78 s
350 */
351static ssize_t show_risefalltime(struct device *dev,
352 struct device_attribute *attr,
353 char *buf, u8 base)
354{
355 struct led_classdev *led_cdev = dev_get_drvdata(dev);
356 struct lm3533_led *led = to_lm3533_led(led_cdev);
357 ssize_t ret;
358 u8 reg;
359 u8 val;
360
361 reg = lm3533_led_get_pattern_reg(led, base);
362 ret = lm3533_read(led->lm3533, reg, &val);
363 if (ret)
364 return ret;
365
366 return scnprintf(buf, PAGE_SIZE, "%x\n", val);
367}
368
369static ssize_t show_risetime(struct device *dev,
370 struct device_attribute *attr, char *buf)
371{
372 return show_risefalltime(dev, attr, buf,
373 LM3533_REG_PATTERN_RISETIME_BASE);
374}
375
376static ssize_t show_falltime(struct device *dev,
377 struct device_attribute *attr, char *buf)
378{
379 return show_risefalltime(dev, attr, buf,
380 LM3533_REG_PATTERN_FALLTIME_BASE);
381}
382
383static ssize_t store_risefalltime(struct device *dev,
384 struct device_attribute *attr,
385 const char *buf, size_t len, u8 base)
386{
387 struct led_classdev *led_cdev = dev_get_drvdata(dev);
388 struct lm3533_led *led = to_lm3533_led(led_cdev);
389 u8 val;
390 u8 reg;
391 int ret;
392
393 if (kstrtou8(buf, 0, &val) || val > LM3533_RISEFALLTIME_MAX)
394 return -EINVAL;
395
396 reg = lm3533_led_get_pattern_reg(led, base);
397 ret = lm3533_write(led->lm3533, reg, val);
398 if (ret)
399 return ret;
400
401 return len;
402}
403
404static ssize_t store_risetime(struct device *dev,
405 struct device_attribute *attr,
406 const char *buf, size_t len)
407{
408 return store_risefalltime(dev, attr, buf, len,
409 LM3533_REG_PATTERN_RISETIME_BASE);
410}
411
412static ssize_t store_falltime(struct device *dev,
413 struct device_attribute *attr,
414 const char *buf, size_t len)
415{
416 return store_risefalltime(dev, attr, buf, len,
417 LM3533_REG_PATTERN_FALLTIME_BASE);
418}
419
420static ssize_t show_als_channel(struct device *dev,
421 struct device_attribute *attr, char *buf)
422{
423 struct led_classdev *led_cdev = dev_get_drvdata(dev);
424 struct lm3533_led *led = to_lm3533_led(led_cdev);
425 unsigned channel;
426 u8 reg;
427 u8 val;
428 int ret;
429
430 reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE);
431 ret = lm3533_read(led->lm3533, reg, &val);
432 if (ret)
433 return ret;
434
435 channel = (val & LM3533_REG_CTRLBANK_BCONF_ALS_CHANNEL_MASK) + 1;
436
437 return scnprintf(buf, PAGE_SIZE, "%u\n", channel);
438}
439
440static ssize_t store_als_channel(struct device *dev,
441 struct device_attribute *attr,
442 const char *buf, size_t len)
443{
444 struct led_classdev *led_cdev = dev_get_drvdata(dev);
445 struct lm3533_led *led = to_lm3533_led(led_cdev);
446 unsigned channel;
447 u8 reg;
448 u8 val;
449 u8 mask;
450 int ret;
451
452 if (kstrtouint(buf, 0, &channel))
453 return -EINVAL;
454
455 if (channel < LM3533_ALS_CHANNEL_LV_MIN ||
456 channel > LM3533_ALS_CHANNEL_LV_MAX)
457 return -EINVAL;
458
459 reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE);
460 mask = LM3533_REG_CTRLBANK_BCONF_ALS_CHANNEL_MASK;
461 val = channel - 1;
462
463 ret = lm3533_update(led->lm3533, reg, val, mask);
464 if (ret)
465 return ret;
466
467 return len;
468}
469
470static ssize_t show_als_en(struct device *dev,
471 struct device_attribute *attr, char *buf)
472{
473 struct led_classdev *led_cdev = dev_get_drvdata(dev);
474 struct lm3533_led *led = to_lm3533_led(led_cdev);
475 bool enable;
476 u8 reg;
477 u8 val;
478 int ret;
479
480 reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE);
481 ret = lm3533_read(led->lm3533, reg, &val);
482 if (ret)
483 return ret;
484
485 enable = val & LM3533_REG_CTRLBANK_BCONF_ALS_EN_MASK;
486
487 return scnprintf(buf, PAGE_SIZE, "%d\n", enable);
488}
489
490static ssize_t store_als_en(struct device *dev,
491 struct device_attribute *attr,
492 const char *buf, size_t len)
493{
494 struct led_classdev *led_cdev = dev_get_drvdata(dev);
495 struct lm3533_led *led = to_lm3533_led(led_cdev);
496 unsigned enable;
497 u8 reg;
498 u8 mask;
499 u8 val;
500 int ret;
501
502 if (kstrtouint(buf, 0, &enable))
503 return -EINVAL;
504
505 reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE);
506 mask = LM3533_REG_CTRLBANK_BCONF_ALS_EN_MASK;
507
508 if (enable)
509 val = mask;
510 else
511 val = 0;
512
513 ret = lm3533_update(led->lm3533, reg, val, mask);
514 if (ret)
515 return ret;
516
517 return len;
518}
519
520static ssize_t show_linear(struct device *dev,
521 struct device_attribute *attr, char *buf)
522{
523 struct led_classdev *led_cdev = dev_get_drvdata(dev);
524 struct lm3533_led *led = to_lm3533_led(led_cdev);
525 u8 reg;
526 u8 val;
527 int linear;
528 int ret;
529
530 reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE);
531 ret = lm3533_read(led->lm3533, reg, &val);
532 if (ret)
533 return ret;
534
535 if (val & LM3533_REG_CTRLBANK_BCONF_MAPPING_MASK)
536 linear = 1;
537 else
538 linear = 0;
539
540 return scnprintf(buf, PAGE_SIZE, "%x\n", linear);
541}
542
543static ssize_t store_linear(struct device *dev,
544 struct device_attribute *attr,
545 const char *buf, size_t len)
546{
547 struct led_classdev *led_cdev = dev_get_drvdata(dev);
548 struct lm3533_led *led = to_lm3533_led(led_cdev);
549 unsigned long linear;
550 u8 reg;
551 u8 mask;
552 u8 val;
553 int ret;
554
555 if (kstrtoul(buf, 0, &linear))
556 return -EINVAL;
557
558 reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE);
559 mask = LM3533_REG_CTRLBANK_BCONF_MAPPING_MASK;
560
561 if (linear)
562 val = mask;
563 else
564 val = 0;
565
566 ret = lm3533_update(led->lm3533, reg, val, mask);
567 if (ret)
568 return ret;
569
570 return len;
571}
572
573static ssize_t show_pwm(struct device *dev,
574 struct device_attribute *attr,
575 char *buf)
576{
577 struct led_classdev *led_cdev = dev_get_drvdata(dev);
578 struct lm3533_led *led = to_lm3533_led(led_cdev);
579 u8 val;
580 int ret;
581
582 ret = lm3533_ctrlbank_get_pwm(&led->cb, &val);
583 if (ret)
584 return ret;
585
586 return scnprintf(buf, PAGE_SIZE, "%u\n", val);
587}
588
589static ssize_t store_pwm(struct device *dev,
590 struct device_attribute *attr,
591 const char *buf, size_t len)
592{
593 struct led_classdev *led_cdev = dev_get_drvdata(dev);
594 struct lm3533_led *led = to_lm3533_led(led_cdev);
595 u8 val;
596 int ret;
597
598 if (kstrtou8(buf, 0, &val))
599 return -EINVAL;
600
601 ret = lm3533_ctrlbank_set_pwm(&led->cb, val);
602 if (ret)
603 return ret;
604
605 return len;
606}
607
608static LM3533_ATTR_RW(als_channel);
609static LM3533_ATTR_RW(als_en);
610static LM3533_ATTR_RW(falltime);
611static LM3533_ATTR_RO(id);
612static LM3533_ATTR_RW(linear);
613static LM3533_ATTR_RW(pwm);
614static LM3533_ATTR_RW(risetime);
615
616static struct attribute *lm3533_led_attributes[] = {
617 &dev_attr_als_channel.attr,
618 &dev_attr_als_en.attr,
619 &dev_attr_falltime.attr,
620 &dev_attr_id.attr,
621 &dev_attr_linear.attr,
622 &dev_attr_pwm.attr,
623 &dev_attr_risetime.attr,
624 NULL,
625};
626
627static umode_t lm3533_led_attr_is_visible(struct kobject *kobj,
628 struct attribute *attr, int n)
629{
630 struct device *dev = container_of(kobj, struct device, kobj);
631 struct led_classdev *led_cdev = dev_get_drvdata(dev);
632 struct lm3533_led *led = to_lm3533_led(led_cdev);
633 umode_t mode = attr->mode;
634
635 if (attr == &dev_attr_als_channel.attr ||
636 attr == &dev_attr_als_en.attr) {
637 if (!led->lm3533->have_als)
638 mode = 0;
639 }
640
641 return mode;
642};
643
644static struct attribute_group lm3533_led_attribute_group = {
645 .is_visible = lm3533_led_attr_is_visible,
646 .attrs = lm3533_led_attributes
647};
648
649static int __devinit lm3533_led_setup(struct lm3533_led *led,
650 struct lm3533_led_platform_data *pdata)
651{
652 int ret;
653
654 ret = lm3533_ctrlbank_set_max_current(&led->cb, pdata->max_current);
655 if (ret)
656 return ret;
657
658 return lm3533_ctrlbank_set_pwm(&led->cb, pdata->pwm);
659}
660
661static int __devinit lm3533_led_probe(struct platform_device *pdev)
662{
663 struct lm3533 *lm3533;
664 struct lm3533_led_platform_data *pdata;
665 struct lm3533_led *led;
666 int ret;
667
668 dev_dbg(&pdev->dev, "%s\n", __func__);
669
670 lm3533 = dev_get_drvdata(pdev->dev.parent);
671 if (!lm3533)
672 return -EINVAL;
673
674 pdata = pdev->dev.platform_data;
675 if (!pdata) {
676 dev_err(&pdev->dev, "no platform data\n");
677 return -EINVAL;
678 }
679
680 if (pdev->id < 0 || pdev->id >= LM3533_LVCTRLBANK_COUNT) {
681 dev_err(&pdev->dev, "illegal LED id %d\n", pdev->id);
682 return -EINVAL;
683 }
684
685 led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
686 if (!led)
687 return -ENOMEM;
688
689 led->lm3533 = lm3533;
690 led->cdev.name = pdata->name;
691 led->cdev.default_trigger = pdata->default_trigger;
692 led->cdev.brightness_set = lm3533_led_set;
693 led->cdev.brightness_get = lm3533_led_get;
694 led->cdev.blink_set = lm3533_led_blink_set;
695 led->cdev.brightness = LED_OFF;
696 led->id = pdev->id;
697
698 mutex_init(&led->mutex);
699 INIT_WORK(&led->work, lm3533_led_work);
700
701 /* The class framework makes a callback to get brightness during
702 * registration so use parent device (for error reporting) until
703 * registered.
704 */
705 led->cb.lm3533 = lm3533;
706 led->cb.id = lm3533_led_get_ctrlbank_id(led);
707 led->cb.dev = lm3533->dev;
708
709 platform_set_drvdata(pdev, led);
710
711 ret = led_classdev_register(pdev->dev.parent, &led->cdev);
712 if (ret) {
713 dev_err(&pdev->dev, "failed to register LED %d\n", pdev->id);
714 return ret;
715 }
716
717 led->cb.dev = led->cdev.dev;
718
719 ret = sysfs_create_group(&led->cdev.dev->kobj,
720 &lm3533_led_attribute_group);
721 if (ret < 0) {
722 dev_err(&pdev->dev, "failed to create sysfs attributes\n");
723 goto err_unregister;
724 }
725
726 ret = lm3533_led_setup(led, pdata);
727 if (ret)
728 goto err_sysfs_remove;
729
730 ret = lm3533_ctrlbank_enable(&led->cb);
731 if (ret)
732 goto err_sysfs_remove;
733
734 return 0;
735
736err_sysfs_remove:
737 sysfs_remove_group(&led->cdev.dev->kobj, &lm3533_led_attribute_group);
738err_unregister:
739 led_classdev_unregister(&led->cdev);
740 flush_work_sync(&led->work);
741
742 return ret;
743}
744
745static int __devexit lm3533_led_remove(struct platform_device *pdev)
746{
747 struct lm3533_led *led = platform_get_drvdata(pdev);
748
749 dev_dbg(&pdev->dev, "%s\n", __func__);
750
751 lm3533_ctrlbank_disable(&led->cb);
752 sysfs_remove_group(&led->cdev.dev->kobj, &lm3533_led_attribute_group);
753 led_classdev_unregister(&led->cdev);
754 flush_work_sync(&led->work);
755
756 return 0;
757}
758
759static void lm3533_led_shutdown(struct platform_device *pdev)
760{
761
762 struct lm3533_led *led = platform_get_drvdata(pdev);
763
764 dev_dbg(&pdev->dev, "%s\n", __func__);
765
766 lm3533_ctrlbank_disable(&led->cb);
767 lm3533_led_set(&led->cdev, LED_OFF); /* disable blink */
768 flush_work_sync(&led->work);
769}
770
771static struct platform_driver lm3533_led_driver = {
772 .driver = {
773 .name = "lm3533-leds",
774 .owner = THIS_MODULE,
775 },
776 .probe = lm3533_led_probe,
777 .remove = __devexit_p(lm3533_led_remove),
778 .shutdown = lm3533_led_shutdown,
779};
780module_platform_driver(lm3533_led_driver);
781
782MODULE_AUTHOR("Johan Hovold <jhovold@gmail.com>");
783MODULE_DESCRIPTION("LM3533 LED driver");
784MODULE_LICENSE("GPL");
785MODULE_ALIAS("platform:lm3533-leds");
diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c
index 410a723b8691..23815624f35e 100644
--- a/drivers/leds/leds-lp5521.c
+++ b/drivers/leds/leds-lp5521.c
@@ -193,9 +193,14 @@ static int lp5521_load_program(struct lp5521_engine *eng, const u8 *pattern)
193 193
194 /* move current engine to direct mode and remember the state */ 194 /* move current engine to direct mode and remember the state */
195 ret = lp5521_set_engine_mode(eng, LP5521_CMD_DIRECT); 195 ret = lp5521_set_engine_mode(eng, LP5521_CMD_DIRECT);
196 if (ret)
197 return ret;
198
196 /* Mode change requires min 500 us delay. 1 - 2 ms with margin */ 199 /* Mode change requires min 500 us delay. 1 - 2 ms with margin */
197 usleep_range(1000, 2000); 200 usleep_range(1000, 2000);
198 ret |= lp5521_read(client, LP5521_REG_OP_MODE, &mode); 201 ret = lp5521_read(client, LP5521_REG_OP_MODE, &mode);
202 if (ret)
203 return ret;
199 204
200 /* For loading, all the engines to load mode */ 205 /* For loading, all the engines to load mode */
201 lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT); 206 lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT);
@@ -211,8 +216,7 @@ static int lp5521_load_program(struct lp5521_engine *eng, const u8 *pattern)
211 LP5521_PROG_MEM_SIZE, 216 LP5521_PROG_MEM_SIZE,
212 pattern); 217 pattern);
213 218
214 ret |= lp5521_write(client, LP5521_REG_OP_MODE, mode); 219 return lp5521_write(client, LP5521_REG_OP_MODE, mode);
215 return ret;
216} 220}
217 221
218static int lp5521_set_led_current(struct lp5521_chip *chip, int led, u8 curr) 222static int lp5521_set_led_current(struct lp5521_chip *chip, int led, u8 curr)
@@ -785,7 +789,7 @@ static int __devinit lp5521_probe(struct i2c_client *client,
785 * LP5521_REG_ENABLE register will not have any effect - strange! 789 * LP5521_REG_ENABLE register will not have any effect - strange!
786 */ 790 */
787 ret = lp5521_read(client, LP5521_REG_R_CURRENT, &buf); 791 ret = lp5521_read(client, LP5521_REG_R_CURRENT, &buf);
788 if (buf != LP5521_REG_R_CURR_DEFAULT) { 792 if (ret || buf != LP5521_REG_R_CURR_DEFAULT) {
789 dev_err(&client->dev, "error in resetting chip\n"); 793 dev_err(&client->dev, "error in resetting chip\n");
790 goto fail2; 794 goto fail2;
791 } 795 }
diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c
index 8bc491541550..4cc6a2e3df34 100644
--- a/drivers/leds/leds-mc13783.c
+++ b/drivers/leds/leds-mc13783.c
@@ -280,7 +280,7 @@ static int __devinit mc13783_led_probe(struct platform_device *pdev)
280 return -EINVAL; 280 return -EINVAL;
281 } 281 }
282 282
283 led = kzalloc(sizeof(*led) * pdata->num_leds, GFP_KERNEL); 283 led = kcalloc(pdata->num_leds, sizeof(*led), GFP_KERNEL);
284 if (led == NULL) { 284 if (led == NULL) {
285 dev_err(&pdev->dev, "failed to alloc memory\n"); 285 dev_err(&pdev->dev, "failed to alloc memory\n");
286 return -ENOMEM; 286 return -ENOMEM;
diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c
index dcc3bc3d38db..5f462dbf0dbb 100644
--- a/drivers/leds/leds-pca955x.c
+++ b/drivers/leds/leds-pca955x.c
@@ -101,11 +101,16 @@ static const struct i2c_device_id pca955x_id[] = {
101}; 101};
102MODULE_DEVICE_TABLE(i2c, pca955x_id); 102MODULE_DEVICE_TABLE(i2c, pca955x_id);
103 103
104struct pca955x_led { 104struct pca955x {
105 struct mutex lock;
106 struct pca955x_led *leds;
105 struct pca955x_chipdef *chipdef; 107 struct pca955x_chipdef *chipdef;
106 struct i2c_client *client; 108 struct i2c_client *client;
109};
110
111struct pca955x_led {
112 struct pca955x *pca955x;
107 struct work_struct work; 113 struct work_struct work;
108 spinlock_t lock;
109 enum led_brightness brightness; 114 enum led_brightness brightness;
110 struct led_classdev led_cdev; 115 struct led_classdev led_cdev;
111 int led_num; /* 0 .. 15 potentially */ 116 int led_num; /* 0 .. 15 potentially */
@@ -140,7 +145,7 @@ static inline u8 pca955x_ledsel(u8 oldval, int led_num, int state)
140 */ 145 */
141static void pca955x_write_psc(struct i2c_client *client, int n, u8 val) 146static void pca955x_write_psc(struct i2c_client *client, int n, u8 val)
142{ 147{
143 struct pca955x_led *pca955x = i2c_get_clientdata(client); 148 struct pca955x *pca955x = i2c_get_clientdata(client);
144 149
145 i2c_smbus_write_byte_data(client, 150 i2c_smbus_write_byte_data(client,
146 pca95xx_num_input_regs(pca955x->chipdef->bits) + 2*n, 151 pca95xx_num_input_regs(pca955x->chipdef->bits) + 2*n,
@@ -156,7 +161,7 @@ static void pca955x_write_psc(struct i2c_client *client, int n, u8 val)
156 */ 161 */
157static void pca955x_write_pwm(struct i2c_client *client, int n, u8 val) 162static void pca955x_write_pwm(struct i2c_client *client, int n, u8 val)
158{ 163{
159 struct pca955x_led *pca955x = i2c_get_clientdata(client); 164 struct pca955x *pca955x = i2c_get_clientdata(client);
160 165
161 i2c_smbus_write_byte_data(client, 166 i2c_smbus_write_byte_data(client,
162 pca95xx_num_input_regs(pca955x->chipdef->bits) + 1 + 2*n, 167 pca95xx_num_input_regs(pca955x->chipdef->bits) + 1 + 2*n,
@@ -169,7 +174,7 @@ static void pca955x_write_pwm(struct i2c_client *client, int n, u8 val)
169 */ 174 */
170static void pca955x_write_ls(struct i2c_client *client, int n, u8 val) 175static void pca955x_write_ls(struct i2c_client *client, int n, u8 val)
171{ 176{
172 struct pca955x_led *pca955x = i2c_get_clientdata(client); 177 struct pca955x *pca955x = i2c_get_clientdata(client);
173 178
174 i2c_smbus_write_byte_data(client, 179 i2c_smbus_write_byte_data(client,
175 pca95xx_num_input_regs(pca955x->chipdef->bits) + 4 + n, 180 pca95xx_num_input_regs(pca955x->chipdef->bits) + 4 + n,
@@ -182,7 +187,7 @@ static void pca955x_write_ls(struct i2c_client *client, int n, u8 val)
182 */ 187 */
183static u8 pca955x_read_ls(struct i2c_client *client, int n) 188static u8 pca955x_read_ls(struct i2c_client *client, int n)
184{ 189{
185 struct pca955x_led *pca955x = i2c_get_clientdata(client); 190 struct pca955x *pca955x = i2c_get_clientdata(client);
186 191
187 return (u8) i2c_smbus_read_byte_data(client, 192 return (u8) i2c_smbus_read_byte_data(client,
188 pca95xx_num_input_regs(pca955x->chipdef->bits) + 4 + n); 193 pca95xx_num_input_regs(pca955x->chipdef->bits) + 4 + n);
@@ -190,18 +195,23 @@ static u8 pca955x_read_ls(struct i2c_client *client, int n)
190 195
191static void pca955x_led_work(struct work_struct *work) 196static void pca955x_led_work(struct work_struct *work)
192{ 197{
193 struct pca955x_led *pca955x; 198 struct pca955x_led *pca955x_led;
199 struct pca955x *pca955x;
194 u8 ls; 200 u8 ls;
195 int chip_ls; /* which LSx to use (0-3 potentially) */ 201 int chip_ls; /* which LSx to use (0-3 potentially) */
196 int ls_led; /* which set of bits within LSx to use (0-3) */ 202 int ls_led; /* which set of bits within LSx to use (0-3) */
197 203
198 pca955x = container_of(work, struct pca955x_led, work); 204 pca955x_led = container_of(work, struct pca955x_led, work);
199 chip_ls = pca955x->led_num / 4; 205 pca955x = pca955x_led->pca955x;
200 ls_led = pca955x->led_num % 4; 206
207 chip_ls = pca955x_led->led_num / 4;
208 ls_led = pca955x_led->led_num % 4;
209
210 mutex_lock(&pca955x->lock);
201 211
202 ls = pca955x_read_ls(pca955x->client, chip_ls); 212 ls = pca955x_read_ls(pca955x->client, chip_ls);
203 213
204 switch (pca955x->brightness) { 214 switch (pca955x_led->brightness) {
205 case LED_FULL: 215 case LED_FULL:
206 ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_LED_ON); 216 ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_LED_ON);
207 break; 217 break;
@@ -219,12 +229,15 @@ static void pca955x_led_work(struct work_struct *work)
219 * OFF, HALF, or FULL. But, this is probably better than 229 * OFF, HALF, or FULL. But, this is probably better than
220 * just turning off for all other values. 230 * just turning off for all other values.
221 */ 231 */
222 pca955x_write_pwm(pca955x->client, 1, 255-pca955x->brightness); 232 pca955x_write_pwm(pca955x->client, 1,
233 255 - pca955x_led->brightness);
223 ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_BLINK1); 234 ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_BLINK1);
224 break; 235 break;
225 } 236 }
226 237
227 pca955x_write_ls(pca955x->client, chip_ls, ls); 238 pca955x_write_ls(pca955x->client, chip_ls, ls);
239
240 mutex_unlock(&pca955x->lock);
228} 241}
229 242
230static void pca955x_led_set(struct led_classdev *led_cdev, enum led_brightness value) 243static void pca955x_led_set(struct led_classdev *led_cdev, enum led_brightness value)
@@ -233,7 +246,6 @@ static void pca955x_led_set(struct led_classdev *led_cdev, enum led_brightness v
233 246
234 pca955x = container_of(led_cdev, struct pca955x_led, led_cdev); 247 pca955x = container_of(led_cdev, struct pca955x_led, led_cdev);
235 248
236 spin_lock(&pca955x->lock);
237 pca955x->brightness = value; 249 pca955x->brightness = value;
238 250
239 /* 251 /*
@@ -241,14 +253,13 @@ static void pca955x_led_set(struct led_classdev *led_cdev, enum led_brightness v
241 * can sleep. 253 * can sleep.
242 */ 254 */
243 schedule_work(&pca955x->work); 255 schedule_work(&pca955x->work);
244
245 spin_unlock(&pca955x->lock);
246} 256}
247 257
248static int __devinit pca955x_probe(struct i2c_client *client, 258static int __devinit pca955x_probe(struct i2c_client *client,
249 const struct i2c_device_id *id) 259 const struct i2c_device_id *id)
250{ 260{
251 struct pca955x_led *pca955x; 261 struct pca955x *pca955x;
262 struct pca955x_led *pca955x_led;
252 struct pca955x_chipdef *chip; 263 struct pca955x_chipdef *chip;
253 struct i2c_adapter *adapter; 264 struct i2c_adapter *adapter;
254 struct led_platform_data *pdata; 265 struct led_platform_data *pdata;
@@ -282,39 +293,48 @@ static int __devinit pca955x_probe(struct i2c_client *client,
282 } 293 }
283 } 294 }
284 295
285 pca955x = kzalloc(sizeof(*pca955x) * chip->bits, GFP_KERNEL); 296 pca955x = kzalloc(sizeof(*pca955x), GFP_KERNEL);
286 if (!pca955x) 297 if (!pca955x)
287 return -ENOMEM; 298 return -ENOMEM;
288 299
300 pca955x->leds = kzalloc(sizeof(*pca955x_led) * chip->bits, GFP_KERNEL);
301 if (!pca955x->leds) {
302 err = -ENOMEM;
303 goto exit_nomem;
304 }
305
289 i2c_set_clientdata(client, pca955x); 306 i2c_set_clientdata(client, pca955x);
290 307
308 mutex_init(&pca955x->lock);
309 pca955x->client = client;
310 pca955x->chipdef = chip;
311
291 for (i = 0; i < chip->bits; i++) { 312 for (i = 0; i < chip->bits; i++) {
292 pca955x[i].chipdef = chip; 313 pca955x_led = &pca955x->leds[i];
293 pca955x[i].client = client; 314 pca955x_led->led_num = i;
294 pca955x[i].led_num = i; 315 pca955x_led->pca955x = pca955x;
295 316
296 /* Platform data can specify LED names and default triggers */ 317 /* Platform data can specify LED names and default triggers */
297 if (pdata) { 318 if (pdata) {
298 if (pdata->leds[i].name) 319 if (pdata->leds[i].name)
299 snprintf(pca955x[i].name, 320 snprintf(pca955x_led->name,
300 sizeof(pca955x[i].name), "pca955x:%s", 321 sizeof(pca955x_led->name), "pca955x:%s",
301 pdata->leds[i].name); 322 pdata->leds[i].name);
302 if (pdata->leds[i].default_trigger) 323 if (pdata->leds[i].default_trigger)
303 pca955x[i].led_cdev.default_trigger = 324 pca955x_led->led_cdev.default_trigger =
304 pdata->leds[i].default_trigger; 325 pdata->leds[i].default_trigger;
305 } else { 326 } else {
306 snprintf(pca955x[i].name, sizeof(pca955x[i].name), 327 snprintf(pca955x_led->name, sizeof(pca955x_led->name),
307 "pca955x:%d", i); 328 "pca955x:%d", i);
308 } 329 }
309 330
310 spin_lock_init(&pca955x[i].lock); 331 pca955x_led->led_cdev.name = pca955x_led->name;
311 332 pca955x_led->led_cdev.brightness_set = pca955x_led_set;
312 pca955x[i].led_cdev.name = pca955x[i].name;
313 pca955x[i].led_cdev.brightness_set = pca955x_led_set;
314 333
315 INIT_WORK(&pca955x[i].work, pca955x_led_work); 334 INIT_WORK(&pca955x_led->work, pca955x_led_work);
316 335
317 err = led_classdev_register(&client->dev, &pca955x[i].led_cdev); 336 err = led_classdev_register(&client->dev,
337 &pca955x_led->led_cdev);
318 if (err < 0) 338 if (err < 0)
319 goto exit; 339 goto exit;
320 } 340 }
@@ -337,10 +357,12 @@ static int __devinit pca955x_probe(struct i2c_client *client,
337 357
338exit: 358exit:
339 while (i--) { 359 while (i--) {
340 led_classdev_unregister(&pca955x[i].led_cdev); 360 led_classdev_unregister(&pca955x->leds[i].led_cdev);
341 cancel_work_sync(&pca955x[i].work); 361 cancel_work_sync(&pca955x->leds[i].work);
342 } 362 }
343 363
364 kfree(pca955x->leds);
365exit_nomem:
344 kfree(pca955x); 366 kfree(pca955x);
345 367
346 return err; 368 return err;
@@ -348,14 +370,15 @@ exit:
348 370
349static int __devexit pca955x_remove(struct i2c_client *client) 371static int __devexit pca955x_remove(struct i2c_client *client)
350{ 372{
351 struct pca955x_led *pca955x = i2c_get_clientdata(client); 373 struct pca955x *pca955x = i2c_get_clientdata(client);
352 int i; 374 int i;
353 375
354 for (i = 0; i < pca955x->chipdef->bits; i++) { 376 for (i = 0; i < pca955x->chipdef->bits; i++) {
355 led_classdev_unregister(&pca955x[i].led_cdev); 377 led_classdev_unregister(&pca955x->leds[i].led_cdev);
356 cancel_work_sync(&pca955x[i].work); 378 cancel_work_sync(&pca955x->leds[i].work);
357 } 379 }
358 380
381 kfree(pca955x->leds);
359 kfree(pca955x); 382 kfree(pca955x);
360 383
361 return 0; 384 return 0;
diff --git a/drivers/leds/ledtrig-backlight.c b/drivers/leds/ledtrig-backlight.c
index 2b513a2ad7de..e2726867c5d4 100644
--- a/drivers/leds/ledtrig-backlight.c
+++ b/drivers/leds/ledtrig-backlight.c
@@ -120,6 +120,7 @@ static void bl_trig_activate(struct led_classdev *led)
120 ret = fb_register_client(&n->notifier); 120 ret = fb_register_client(&n->notifier);
121 if (ret) 121 if (ret)
122 dev_err(led->dev, "unable to register backlight trigger\n"); 122 dev_err(led->dev, "unable to register backlight trigger\n");
123 led->activated = true;
123 124
124 return; 125 return;
125 126
@@ -133,10 +134,11 @@ static void bl_trig_deactivate(struct led_classdev *led)
133 struct bl_trig_notifier *n = 134 struct bl_trig_notifier *n =
134 (struct bl_trig_notifier *) led->trigger_data; 135 (struct bl_trig_notifier *) led->trigger_data;
135 136
136 if (n) { 137 if (led->activated) {
137 device_remove_file(led->dev, &dev_attr_inverted); 138 device_remove_file(led->dev, &dev_attr_inverted);
138 fb_unregister_client(&n->notifier); 139 fb_unregister_client(&n->notifier);
139 kfree(n); 140 kfree(n);
141 led->activated = false;
140 } 142 }
141} 143}
142 144
diff --git a/drivers/leds/ledtrig-gpio.c b/drivers/leds/ledtrig-gpio.c
index ecc4bf3f37a9..f057c101b896 100644
--- a/drivers/leds/ledtrig-gpio.c
+++ b/drivers/leds/ledtrig-gpio.c
@@ -200,6 +200,7 @@ static void gpio_trig_activate(struct led_classdev *led)
200 gpio_data->led = led; 200 gpio_data->led = led;
201 led->trigger_data = gpio_data; 201 led->trigger_data = gpio_data;
202 INIT_WORK(&gpio_data->work, gpio_trig_work); 202 INIT_WORK(&gpio_data->work, gpio_trig_work);
203 led->activated = true;
203 204
204 return; 205 return;
205 206
@@ -217,7 +218,7 @@ static void gpio_trig_deactivate(struct led_classdev *led)
217{ 218{
218 struct gpio_trig_data *gpio_data = led->trigger_data; 219 struct gpio_trig_data *gpio_data = led->trigger_data;
219 220
220 if (gpio_data) { 221 if (led->activated) {
221 device_remove_file(led->dev, &dev_attr_gpio); 222 device_remove_file(led->dev, &dev_attr_gpio);
222 device_remove_file(led->dev, &dev_attr_inverted); 223 device_remove_file(led->dev, &dev_attr_inverted);
223 device_remove_file(led->dev, &dev_attr_desired_brightness); 224 device_remove_file(led->dev, &dev_attr_desired_brightness);
@@ -225,6 +226,7 @@ static void gpio_trig_deactivate(struct led_classdev *led)
225 if (gpio_data->gpio != 0) 226 if (gpio_data->gpio != 0)
226 free_irq(gpio_to_irq(gpio_data->gpio), led); 227 free_irq(gpio_to_irq(gpio_data->gpio), led);
227 kfree(gpio_data); 228 kfree(gpio_data);
229 led->activated = false;
228 } 230 }
229} 231}
230 232
diff --git a/drivers/leds/ledtrig-heartbeat.c b/drivers/leds/ledtrig-heartbeat.c
index 759c0bba4a8f..41dc76db4311 100644
--- a/drivers/leds/ledtrig-heartbeat.c
+++ b/drivers/leds/ledtrig-heartbeat.c
@@ -18,6 +18,7 @@
18#include <linux/timer.h> 18#include <linux/timer.h>
19#include <linux/sched.h> 19#include <linux/sched.h>
20#include <linux/leds.h> 20#include <linux/leds.h>
21#include <linux/reboot.h>
21#include "leds.h" 22#include "leds.h"
22 23
23struct heartbeat_trig_data { 24struct heartbeat_trig_data {
@@ -83,15 +84,17 @@ static void heartbeat_trig_activate(struct led_classdev *led_cdev)
83 led_heartbeat_function, (unsigned long) led_cdev); 84 led_heartbeat_function, (unsigned long) led_cdev);
84 heartbeat_data->phase = 0; 85 heartbeat_data->phase = 0;
85 led_heartbeat_function(heartbeat_data->timer.data); 86 led_heartbeat_function(heartbeat_data->timer.data);
87 led_cdev->activated = true;
86} 88}
87 89
88static void heartbeat_trig_deactivate(struct led_classdev *led_cdev) 90static void heartbeat_trig_deactivate(struct led_classdev *led_cdev)
89{ 91{
90 struct heartbeat_trig_data *heartbeat_data = led_cdev->trigger_data; 92 struct heartbeat_trig_data *heartbeat_data = led_cdev->trigger_data;
91 93
92 if (heartbeat_data) { 94 if (led_cdev->activated) {
93 del_timer_sync(&heartbeat_data->timer); 95 del_timer_sync(&heartbeat_data->timer);
94 kfree(heartbeat_data); 96 kfree(heartbeat_data);
97 led_cdev->activated = false;
95 } 98 }
96} 99}
97 100
@@ -101,13 +104,38 @@ static struct led_trigger heartbeat_led_trigger = {
101 .deactivate = heartbeat_trig_deactivate, 104 .deactivate = heartbeat_trig_deactivate,
102}; 105};
103 106
107static int heartbeat_reboot_notifier(struct notifier_block *nb,
108 unsigned long code, void *unused)
109{
110 led_trigger_unregister(&heartbeat_led_trigger);
111 return NOTIFY_DONE;
112}
113
114static struct notifier_block heartbeat_reboot_nb = {
115 .notifier_call = heartbeat_reboot_notifier,
116};
117
118static struct notifier_block heartbeat_panic_nb = {
119 .notifier_call = heartbeat_reboot_notifier,
120};
121
104static int __init heartbeat_trig_init(void) 122static int __init heartbeat_trig_init(void)
105{ 123{
106 return led_trigger_register(&heartbeat_led_trigger); 124 int rc = led_trigger_register(&heartbeat_led_trigger);
125
126 if (!rc) {
127 atomic_notifier_chain_register(&panic_notifier_list,
128 &heartbeat_panic_nb);
129 register_reboot_notifier(&heartbeat_reboot_nb);
130 }
131 return rc;
107} 132}
108 133
109static void __exit heartbeat_trig_exit(void) 134static void __exit heartbeat_trig_exit(void)
110{ 135{
136 unregister_reboot_notifier(&heartbeat_reboot_nb);
137 atomic_notifier_chain_unregister(&panic_notifier_list,
138 &heartbeat_panic_nb);
111 led_trigger_unregister(&heartbeat_led_trigger); 139 led_trigger_unregister(&heartbeat_led_trigger);
112} 140}
113 141
diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c
index 328c64c0841c..9010f7abaf2c 100644
--- a/drivers/leds/ledtrig-timer.c
+++ b/drivers/leds/ledtrig-timer.c
@@ -31,21 +31,17 @@ static ssize_t led_delay_on_store(struct device *dev,
31 struct device_attribute *attr, const char *buf, size_t size) 31 struct device_attribute *attr, const char *buf, size_t size)
32{ 32{
33 struct led_classdev *led_cdev = dev_get_drvdata(dev); 33 struct led_classdev *led_cdev = dev_get_drvdata(dev);
34 int ret = -EINVAL; 34 unsigned long state;
35 char *after; 35 ssize_t ret = -EINVAL;
36 unsigned long state = simple_strtoul(buf, &after, 10); 36
37 size_t count = after - buf; 37 ret = kstrtoul(buf, 10, &state);
38 38 if (ret)
39 if (isspace(*after)) 39 return ret;
40 count++;
41
42 if (count == size) {
43 led_blink_set(led_cdev, &state, &led_cdev->blink_delay_off);
44 led_cdev->blink_delay_on = state;
45 ret = count;
46 }
47 40
48 return ret; 41 led_blink_set(led_cdev, &state, &led_cdev->blink_delay_off);
42 led_cdev->blink_delay_on = state;
43
44 return size;
49} 45}
50 46
51static ssize_t led_delay_off_show(struct device *dev, 47static ssize_t led_delay_off_show(struct device *dev,
@@ -60,21 +56,17 @@ static ssize_t led_delay_off_store(struct device *dev,
60 struct device_attribute *attr, const char *buf, size_t size) 56 struct device_attribute *attr, const char *buf, size_t size)
61{ 57{
62 struct led_classdev *led_cdev = dev_get_drvdata(dev); 58 struct led_classdev *led_cdev = dev_get_drvdata(dev);
63 int ret = -EINVAL; 59 unsigned long state;
64 char *after; 60 ssize_t ret = -EINVAL;
65 unsigned long state = simple_strtoul(buf, &after, 10);
66 size_t count = after - buf;
67
68 if (isspace(*after))
69 count++;
70
71 if (count == size) {
72 led_blink_set(led_cdev, &led_cdev->blink_delay_on, &state);
73 led_cdev->blink_delay_off = state;
74 ret = count;
75 }
76 61
77 return ret; 62 ret = kstrtoul(buf, 10, &state);
63 if (ret)
64 return ret;
65
66 led_blink_set(led_cdev, &led_cdev->blink_delay_on, &state);
67 led_cdev->blink_delay_off = state;
68
69 return size;
78} 70}
79 71
80static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store); 72static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store);
@@ -95,8 +87,7 @@ static void timer_trig_activate(struct led_classdev *led_cdev)
95 87
96 led_blink_set(led_cdev, &led_cdev->blink_delay_on, 88 led_blink_set(led_cdev, &led_cdev->blink_delay_on,
97 &led_cdev->blink_delay_off); 89 &led_cdev->blink_delay_off);
98 90 led_cdev->activated = true;
99 led_cdev->trigger_data = (void *)1;
100 91
101 return; 92 return;
102 93
@@ -106,9 +97,10 @@ err_out_delayon:
106 97
107static void timer_trig_deactivate(struct led_classdev *led_cdev) 98static void timer_trig_deactivate(struct led_classdev *led_cdev)
108{ 99{
109 if (led_cdev->trigger_data) { 100 if (led_cdev->activated) {
110 device_remove_file(led_cdev->dev, &dev_attr_delay_on); 101 device_remove_file(led_cdev->dev, &dev_attr_delay_on);
111 device_remove_file(led_cdev->dev, &dev_attr_delay_off); 102 device_remove_file(led_cdev->dev, &dev_attr_delay_off);
103 led_cdev->activated = false;
112 } 104 }
113 105
114 /* Stop blinking */ 106 /* Stop blinking */
diff --git a/drivers/leds/ledtrig-transient.c b/drivers/leds/ledtrig-transient.c
new file mode 100644
index 000000000000..83179f435e1e
--- /dev/null
+++ b/drivers/leds/ledtrig-transient.c
@@ -0,0 +1,237 @@
1/*
2 * LED Kernel Transient Trigger
3 *
4 * Copyright (C) 2012 Shuah Khan <shuahkhan@gmail.com>
5 *
6 * Based on Richard Purdie's ledtrig-timer.c and Atsushi Nemoto's
7 * ledtrig-heartbeat.c
8 * Design and use-case input from Jonas Bonn <jonas@southpole.se> and
9 * Neil Brown <neilb@suse.de>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 *
15 */
16/*
17 * Transient trigger allows one shot timer activation. Please refer to
18 * Documentation/leds/ledtrig-transient.txt for details
19*/
20
21#include <linux/module.h>
22#include <linux/kernel.h>
23#include <linux/init.h>
24#include <linux/device.h>
25#include <linux/slab.h>
26#include <linux/timer.h>
27#include <linux/leds.h>
28#include "leds.h"
29
30struct transient_trig_data {
31 int activate;
32 int state;
33 int restore_state;
34 unsigned long duration;
35 struct timer_list timer;
36};
37
38static void transient_timer_function(unsigned long data)
39{
40 struct led_classdev *led_cdev = (struct led_classdev *) data;
41 struct transient_trig_data *transient_data = led_cdev->trigger_data;
42
43 transient_data->activate = 0;
44 led_set_brightness(led_cdev, transient_data->restore_state);
45}
46
47static ssize_t transient_activate_show(struct device *dev,
48 struct device_attribute *attr, char *buf)
49{
50 struct led_classdev *led_cdev = dev_get_drvdata(dev);
51 struct transient_trig_data *transient_data = led_cdev->trigger_data;
52
53 return sprintf(buf, "%d\n", transient_data->activate);
54}
55
56static ssize_t transient_activate_store(struct device *dev,
57 struct device_attribute *attr, const char *buf, size_t size)
58{
59 struct led_classdev *led_cdev = dev_get_drvdata(dev);
60 struct transient_trig_data *transient_data = led_cdev->trigger_data;
61 unsigned long state;
62 ssize_t ret;
63
64 ret = kstrtoul(buf, 10, &state);
65 if (ret)
66 return ret;
67
68 if (state != 1 && state != 0)
69 return -EINVAL;
70
71 /* cancel the running timer */
72 if (state == 0 && transient_data->activate == 1) {
73 del_timer(&transient_data->timer);
74 transient_data->activate = state;
75 led_set_brightness(led_cdev, transient_data->restore_state);
76 return size;
77 }
78
79 /* start timer if there is no active timer */
80 if (state == 1 && transient_data->activate == 0 &&
81 transient_data->duration != 0) {
82 transient_data->activate = state;
83 led_set_brightness(led_cdev, transient_data->state);
84 transient_data->restore_state =
85 (transient_data->state == LED_FULL) ? LED_OFF : LED_FULL;
86 mod_timer(&transient_data->timer,
87 jiffies + transient_data->duration);
88 }
89
90 /* state == 0 && transient_data->activate == 0
91 timer is not active - just return */
92 /* state == 1 && transient_data->activate == 1
93 timer is already active - just return */
94
95 return size;
96}
97
98static ssize_t transient_duration_show(struct device *dev,
99 struct device_attribute *attr, char *buf)
100{
101 struct led_classdev *led_cdev = dev_get_drvdata(dev);
102 struct transient_trig_data *transient_data = led_cdev->trigger_data;
103
104 return sprintf(buf, "%lu\n", transient_data->duration);
105}
106
107static ssize_t transient_duration_store(struct device *dev,
108 struct device_attribute *attr, const char *buf, size_t size)
109{
110 struct led_classdev *led_cdev = dev_get_drvdata(dev);
111 struct transient_trig_data *transient_data = led_cdev->trigger_data;
112 unsigned long state;
113 ssize_t ret;
114
115 ret = kstrtoul(buf, 10, &state);
116 if (ret)
117 return ret;
118
119 transient_data->duration = state;
120 return size;
121}
122
123static ssize_t transient_state_show(struct device *dev,
124 struct device_attribute *attr, char *buf)
125{
126 struct led_classdev *led_cdev = dev_get_drvdata(dev);
127 struct transient_trig_data *transient_data = led_cdev->trigger_data;
128 int state;
129
130 state = (transient_data->state == LED_FULL) ? 1 : 0;
131 return sprintf(buf, "%d\n", state);
132}
133
134static ssize_t transient_state_store(struct device *dev,
135 struct device_attribute *attr, const char *buf, size_t size)
136{
137 struct led_classdev *led_cdev = dev_get_drvdata(dev);
138 struct transient_trig_data *transient_data = led_cdev->trigger_data;
139 unsigned long state;
140 ssize_t ret;
141
142 ret = kstrtoul(buf, 10, &state);
143 if (ret)
144 return ret;
145
146 if (state != 1 && state != 0)
147 return -EINVAL;
148
149 transient_data->state = (state == 1) ? LED_FULL : LED_OFF;
150 return size;
151}
152
153static DEVICE_ATTR(activate, 0644, transient_activate_show,
154 transient_activate_store);
155static DEVICE_ATTR(duration, 0644, transient_duration_show,
156 transient_duration_store);
157static DEVICE_ATTR(state, 0644, transient_state_show, transient_state_store);
158
159static void transient_trig_activate(struct led_classdev *led_cdev)
160{
161 int rc;
162 struct transient_trig_data *tdata;
163
164 tdata = kzalloc(sizeof(struct transient_trig_data), GFP_KERNEL);
165 if (!tdata) {
166 dev_err(led_cdev->dev,
167 "unable to allocate transient trigger\n");
168 return;
169 }
170 led_cdev->trigger_data = tdata;
171
172 rc = device_create_file(led_cdev->dev, &dev_attr_activate);
173 if (rc)
174 goto err_out;
175
176 rc = device_create_file(led_cdev->dev, &dev_attr_duration);
177 if (rc)
178 goto err_out_duration;
179
180 rc = device_create_file(led_cdev->dev, &dev_attr_state);
181 if (rc)
182 goto err_out_state;
183
184 setup_timer(&tdata->timer, transient_timer_function,
185 (unsigned long) led_cdev);
186 led_cdev->activated = true;
187
188 return;
189
190err_out_state:
191 device_remove_file(led_cdev->dev, &dev_attr_duration);
192err_out_duration:
193 device_remove_file(led_cdev->dev, &dev_attr_activate);
194err_out:
195 dev_err(led_cdev->dev, "unable to register transient trigger\n");
196 led_cdev->trigger_data = NULL;
197 kfree(tdata);
198}
199
200static void transient_trig_deactivate(struct led_classdev *led_cdev)
201{
202 struct transient_trig_data *transient_data = led_cdev->trigger_data;
203
204 if (led_cdev->activated) {
205 del_timer_sync(&transient_data->timer);
206 led_set_brightness(led_cdev, transient_data->restore_state);
207 device_remove_file(led_cdev->dev, &dev_attr_activate);
208 device_remove_file(led_cdev->dev, &dev_attr_duration);
209 device_remove_file(led_cdev->dev, &dev_attr_state);
210 led_cdev->trigger_data = NULL;
211 led_cdev->activated = false;
212 kfree(transient_data);
213 }
214}
215
216static struct led_trigger transient_trigger = {
217 .name = "transient",
218 .activate = transient_trig_activate,
219 .deactivate = transient_trig_deactivate,
220};
221
222static int __init transient_trig_init(void)
223{
224 return led_trigger_register(&transient_trigger);
225}
226
227static void __exit transient_trig_exit(void)
228{
229 led_trigger_unregister(&transient_trigger);
230}
231
232module_init(transient_trig_init);
233module_exit(transient_trig_exit);
234
235MODULE_AUTHOR("Shuah Khan <shuahkhan@gmail.com>");
236MODULE_DESCRIPTION("Transient LED trigger");
237MODULE_LICENSE("GPL");