diff options
author | Alexander Shiyan <shc_work@mail.ru> | 2013-06-10 12:59:30 -0400 |
---|---|---|
committer | Bryan Wu <cooloney@gmail.com> | 2013-06-20 19:21:34 -0400 |
commit | 9d263813c27e2ad3da7ea0877e623f4ff8767ddd (patch) | |
tree | 07eb43efd73190d4d5f117113db12c2ade9afda0 /drivers/leds/leds-mc13783.c | |
parent | fb277f5b3a15c895586545d3938dc869e760bec6 (diff) |
leds: leds-mc13783: Prepare driver to support MC13892 LEDs
This patch rewrite driver code to be ready to add support for
MC13892 LEDs and probe from devicetree.
(cooloney@gmail.com: fix one coding style issue when apply this patch)
Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
Tested-by: Philippe Retornaz <philippe.retornaz@epfl.ch>
Signed-off-by: Bryan Wu <cooloney@gmail.com>
Diffstat (limited to 'drivers/leds/leds-mc13783.c')
-rw-r--r-- | drivers/leds/leds-mc13783.c | 406 |
1 files changed, 156 insertions, 250 deletions
diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c index ea8fc5d432da..da8ec244a641 100644 --- a/drivers/leds/leds-mc13783.c +++ b/drivers/leds/leds-mc13783.c | |||
@@ -22,9 +22,16 @@ | |||
22 | #include <linux/leds.h> | 22 | #include <linux/leds.h> |
23 | #include <linux/workqueue.h> | 23 | #include <linux/workqueue.h> |
24 | #include <linux/mfd/mc13xxx.h> | 24 | #include <linux/mfd/mc13xxx.h> |
25 | #include <linux/slab.h> | ||
26 | 25 | ||
27 | struct mc13783_led { | 26 | #define MC13XXX_REG_LED_CONTROL(x) (51 + (x)) |
27 | |||
28 | struct mc13xxx_led_devtype { | ||
29 | int led_min; | ||
30 | int led_max; | ||
31 | int num_regs; | ||
32 | }; | ||
33 | |||
34 | struct mc13xxx_led { | ||
28 | struct led_classdev cdev; | 35 | struct led_classdev cdev; |
29 | struct work_struct work; | 36 | struct work_struct work; |
30 | struct mc13xxx *master; | 37 | struct mc13xxx *master; |
@@ -32,66 +39,35 @@ struct mc13783_led { | |||
32 | int id; | 39 | int id; |
33 | }; | 40 | }; |
34 | 41 | ||
35 | #define MC13783_REG_LED_CONTROL_0 51 | 42 | struct mc13xxx_leds { |
36 | #define MC13783_LED_C0_ENABLE_BIT (1 << 0) | 43 | struct mc13xxx_led_devtype *devtype; |
37 | #define MC13783_LED_C0_TRIODE_MD_BIT (1 << 7) | 44 | int num_leds; |
38 | #define MC13783_LED_C0_TRIODE_AD_BIT (1 << 8) | 45 | struct mc13xxx_led led[0]; |
39 | #define MC13783_LED_C0_TRIODE_KP_BIT (1 << 9) | 46 | }; |
40 | #define MC13783_LED_C0_BOOST_BIT (1 << 10) | 47 | |
41 | #define MC13783_LED_C0_ABMODE_MASK 0x7 | 48 | static void mc13xxx_led_work(struct work_struct *work) |
42 | #define MC13783_LED_C0_ABMODE 11 | ||
43 | #define MC13783_LED_C0_ABREF_MASK 0x3 | ||
44 | #define MC13783_LED_C0_ABREF 14 | ||
45 | |||
46 | #define MC13783_REG_LED_CONTROL_1 52 | ||
47 | #define MC13783_LED_C1_TC1HALF_BIT (1 << 18) | ||
48 | |||
49 | #define MC13783_REG_LED_CONTROL_2 53 | ||
50 | #define MC13783_LED_C2_BL_P_MASK 0xf | ||
51 | #define MC13783_LED_C2_MD_P 9 | ||
52 | #define MC13783_LED_C2_AD_P 13 | ||
53 | #define MC13783_LED_C2_KP_P 17 | ||
54 | #define MC13783_LED_C2_BL_C_MASK 0x7 | ||
55 | #define MC13783_LED_C2_MD_C 0 | ||
56 | #define MC13783_LED_C2_AD_C 3 | ||
57 | #define MC13783_LED_C2_KP_C 6 | ||
58 | |||
59 | #define MC13783_REG_LED_CONTROL_3 54 | ||
60 | #define MC13783_LED_C3_TC_P 6 | ||
61 | #define MC13783_LED_C3_TC_P_MASK 0x1f | ||
62 | |||
63 | #define MC13783_REG_LED_CONTROL_4 55 | ||
64 | #define MC13783_REG_LED_CONTROL_5 56 | ||
65 | |||
66 | #define MC13783_LED_Cx_PERIOD 21 | ||
67 | #define MC13783_LED_Cx_PERIOD_MASK 0x3 | ||
68 | #define MC13783_LED_Cx_SLEWLIM_BIT (1 << 23) | ||
69 | #define MC13783_LED_Cx_TRIODE_TC_BIT (1 << 23) | ||
70 | #define MC13783_LED_Cx_TC_C_MASK 0x3 | ||
71 | |||
72 | static void mc13783_led_work(struct work_struct *work) | ||
73 | { | 49 | { |
74 | struct mc13783_led *led = container_of(work, struct mc13783_led, work); | 50 | struct mc13xxx_led *led = container_of(work, struct mc13xxx_led, work); |
75 | int reg = 0; | 51 | int reg, mask, value, bank, off, shift; |
76 | int mask = 0; | ||
77 | int value = 0; | ||
78 | int bank, off, shift; | ||
79 | 52 | ||
80 | switch (led->id) { | 53 | switch (led->id) { |
81 | case MC13783_LED_MD: | 54 | case MC13783_LED_MD: |
82 | reg = MC13783_REG_LED_CONTROL_2; | 55 | reg = MC13XXX_REG_LED_CONTROL(2); |
83 | mask = MC13783_LED_C2_BL_P_MASK << MC13783_LED_C2_MD_P; | 56 | shift = 9; |
84 | value = (led->new_brightness >> 4) << MC13783_LED_C2_MD_P; | 57 | mask = 0x0f; |
58 | value = led->new_brightness >> 4; | ||
85 | break; | 59 | break; |
86 | case MC13783_LED_AD: | 60 | case MC13783_LED_AD: |
87 | reg = MC13783_REG_LED_CONTROL_2; | 61 | reg = MC13XXX_REG_LED_CONTROL(2); |
88 | mask = MC13783_LED_C2_BL_P_MASK << MC13783_LED_C2_AD_P; | 62 | shift = 13; |
89 | value = (led->new_brightness >> 4) << MC13783_LED_C2_AD_P; | 63 | mask = 0x0f; |
64 | value = led->new_brightness >> 4; | ||
90 | break; | 65 | break; |
91 | case MC13783_LED_KP: | 66 | case MC13783_LED_KP: |
92 | reg = MC13783_REG_LED_CONTROL_2; | 67 | reg = MC13XXX_REG_LED_CONTROL(2); |
93 | mask = MC13783_LED_C2_BL_P_MASK << MC13783_LED_C2_KP_P; | 68 | shift = 17; |
94 | value = (led->new_brightness >> 4) << MC13783_LED_C2_KP_P; | 69 | mask = 0x0f; |
70 | value = led->new_brightness >> 4; | ||
95 | break; | 71 | break; |
96 | case MC13783_LED_R1: | 72 | case MC13783_LED_R1: |
97 | case MC13783_LED_G1: | 73 | case MC13783_LED_G1: |
@@ -103,57 +79,50 @@ static void mc13783_led_work(struct work_struct *work) | |||
103 | case MC13783_LED_G3: | 79 | case MC13783_LED_G3: |
104 | case MC13783_LED_B3: | 80 | case MC13783_LED_B3: |
105 | off = led->id - MC13783_LED_R1; | 81 | off = led->id - MC13783_LED_R1; |
106 | bank = off/3; | 82 | bank = off / 3; |
107 | reg = MC13783_REG_LED_CONTROL_3 + off/3; | 83 | reg = MC13XXX_REG_LED_CONTROL(3) + bank; |
108 | shift = (off - bank * 3) * 5 + MC13783_LED_C3_TC_P; | 84 | shift = (off - bank * 3) * 5 + 6; |
109 | value = (led->new_brightness >> 3) << shift; | 85 | value = led->new_brightness >> 3; |
110 | mask = MC13783_LED_C3_TC_P_MASK << shift; | 86 | mask = 0x1f; |
111 | break; | 87 | break; |
88 | default: | ||
89 | BUG(); | ||
112 | } | 90 | } |
113 | 91 | ||
114 | mc13xxx_lock(led->master); | 92 | mc13xxx_lock(led->master); |
115 | 93 | mc13xxx_reg_rmw(led->master, reg, mask << shift, value << shift); | |
116 | mc13xxx_reg_rmw(led->master, reg, mask, value); | ||
117 | |||
118 | mc13xxx_unlock(led->master); | 94 | mc13xxx_unlock(led->master); |
119 | } | 95 | } |
120 | 96 | ||
121 | static void mc13783_led_set(struct led_classdev *led_cdev, | 97 | static void mc13xxx_led_set(struct led_classdev *led_cdev, |
122 | enum led_brightness value) | 98 | enum led_brightness value) |
123 | { | 99 | { |
124 | struct mc13783_led *led; | 100 | struct mc13xxx_led *led = |
101 | container_of(led_cdev, struct mc13xxx_led, cdev); | ||
125 | 102 | ||
126 | led = container_of(led_cdev, struct mc13783_led, cdev); | ||
127 | led->new_brightness = value; | 103 | led->new_brightness = value; |
128 | schedule_work(&led->work); | 104 | schedule_work(&led->work); |
129 | } | 105 | } |
130 | 106 | ||
131 | static int mc13783_led_setup(struct mc13783_led *led, int max_current) | 107 | static int __init mc13xxx_led_setup(struct mc13xxx_led *led, int max_current) |
132 | { | 108 | { |
133 | int shift = 0; | 109 | int shift, mask, reg, ret, bank; |
134 | int mask = 0; | ||
135 | int value = 0; | ||
136 | int reg = 0; | ||
137 | int ret, bank; | ||
138 | 110 | ||
139 | switch (led->id) { | 111 | switch (led->id) { |
140 | case MC13783_LED_MD: | 112 | case MC13783_LED_MD: |
141 | shift = MC13783_LED_C2_MD_C; | 113 | reg = MC13XXX_REG_LED_CONTROL(2); |
142 | mask = MC13783_LED_C2_BL_C_MASK; | 114 | shift = 0; |
143 | value = max_current & MC13783_LED_C2_BL_C_MASK; | 115 | mask = 0x07; |
144 | reg = MC13783_REG_LED_CONTROL_2; | ||
145 | break; | 116 | break; |
146 | case MC13783_LED_AD: | 117 | case MC13783_LED_AD: |
147 | shift = MC13783_LED_C2_AD_C; | 118 | reg = MC13XXX_REG_LED_CONTROL(2); |
148 | mask = MC13783_LED_C2_BL_C_MASK; | 119 | shift = 3; |
149 | value = max_current & MC13783_LED_C2_BL_C_MASK; | 120 | mask = 0x07; |
150 | reg = MC13783_REG_LED_CONTROL_2; | ||
151 | break; | 121 | break; |
152 | case MC13783_LED_KP: | 122 | case MC13783_LED_KP: |
153 | shift = MC13783_LED_C2_KP_C; | 123 | reg = MC13XXX_REG_LED_CONTROL(2); |
154 | mask = MC13783_LED_C2_BL_C_MASK; | 124 | shift = 6; |
155 | value = max_current & MC13783_LED_C2_BL_C_MASK; | 125 | mask = 0x07; |
156 | reg = MC13783_REG_LED_CONTROL_2; | ||
157 | break; | 126 | break; |
158 | case MC13783_LED_R1: | 127 | case MC13783_LED_R1: |
159 | case MC13783_LED_G1: | 128 | case MC13783_LED_G1: |
@@ -164,228 +133,165 @@ static int mc13783_led_setup(struct mc13783_led *led, int max_current) | |||
164 | case MC13783_LED_R3: | 133 | case MC13783_LED_R3: |
165 | case MC13783_LED_G3: | 134 | case MC13783_LED_G3: |
166 | case MC13783_LED_B3: | 135 | case MC13783_LED_B3: |
167 | bank = (led->id - MC13783_LED_R1)/3; | 136 | bank = (led->id - MC13783_LED_R1) / 3; |
168 | reg = MC13783_REG_LED_CONTROL_3 + bank; | 137 | reg = MC13XXX_REG_LED_CONTROL(3) + bank; |
169 | shift = ((led->id - MC13783_LED_R1) - bank * 3) * 2; | 138 | shift = ((led->id - MC13783_LED_R1) - bank * 3) * 2; |
170 | mask = MC13783_LED_Cx_TC_C_MASK; | 139 | mask = 0x03; |
171 | value = max_current & MC13783_LED_Cx_TC_C_MASK; | ||
172 | break; | 140 | break; |
141 | default: | ||
142 | BUG(); | ||
173 | } | 143 | } |
174 | 144 | ||
175 | mc13xxx_lock(led->master); | 145 | mc13xxx_lock(led->master); |
176 | |||
177 | ret = mc13xxx_reg_rmw(led->master, reg, mask << shift, | 146 | ret = mc13xxx_reg_rmw(led->master, reg, mask << shift, |
178 | value << shift); | 147 | max_current << shift); |
179 | |||
180 | mc13xxx_unlock(led->master); | 148 | mc13xxx_unlock(led->master); |
181 | return ret; | ||
182 | } | ||
183 | |||
184 | static int mc13783_leds_prepare(struct platform_device *pdev) | ||
185 | { | ||
186 | struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(&pdev->dev); | ||
187 | struct mc13xxx *dev = dev_get_drvdata(pdev->dev.parent); | ||
188 | int ret = 0; | ||
189 | int reg = 0; | ||
190 | |||
191 | mc13xxx_lock(dev); | ||
192 | |||
193 | if (pdata->flags & MC13783_LED_TC1HALF) | ||
194 | reg |= MC13783_LED_C1_TC1HALF_BIT; | ||
195 | |||
196 | if (pdata->flags & MC13783_LED_SLEWLIMTC) | ||
197 | reg |= MC13783_LED_Cx_SLEWLIM_BIT; | ||
198 | |||
199 | ret = mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_1, reg); | ||
200 | if (ret) | ||
201 | goto out; | ||
202 | |||
203 | reg = (pdata->bl_period & MC13783_LED_Cx_PERIOD_MASK) << | ||
204 | MC13783_LED_Cx_PERIOD; | ||
205 | |||
206 | if (pdata->flags & MC13783_LED_SLEWLIMBL) | ||
207 | reg |= MC13783_LED_Cx_SLEWLIM_BIT; | ||
208 | |||
209 | ret = mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_2, reg); | ||
210 | if (ret) | ||
211 | goto out; | ||
212 | |||
213 | reg = (pdata->tc1_period & MC13783_LED_Cx_PERIOD_MASK) << | ||
214 | MC13783_LED_Cx_PERIOD; | ||
215 | |||
216 | if (pdata->flags & MC13783_LED_TRIODE_TC1) | ||
217 | reg |= MC13783_LED_Cx_TRIODE_TC_BIT; | ||
218 | |||
219 | ret = mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_3, reg); | ||
220 | if (ret) | ||
221 | goto out; | ||
222 | 149 | ||
223 | reg = (pdata->tc2_period & MC13783_LED_Cx_PERIOD_MASK) << | ||
224 | MC13783_LED_Cx_PERIOD; | ||
225 | |||
226 | if (pdata->flags & MC13783_LED_TRIODE_TC2) | ||
227 | reg |= MC13783_LED_Cx_TRIODE_TC_BIT; | ||
228 | |||
229 | ret = mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_4, reg); | ||
230 | if (ret) | ||
231 | goto out; | ||
232 | |||
233 | reg = (pdata->tc3_period & MC13783_LED_Cx_PERIOD_MASK) << | ||
234 | MC13783_LED_Cx_PERIOD; | ||
235 | |||
236 | if (pdata->flags & MC13783_LED_TRIODE_TC3) | ||
237 | reg |= MC13783_LED_Cx_TRIODE_TC_BIT; | ||
238 | |||
239 | ret = mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_5, reg); | ||
240 | if (ret) | ||
241 | goto out; | ||
242 | |||
243 | reg = MC13783_LED_C0_ENABLE_BIT; | ||
244 | if (pdata->flags & MC13783_LED_TRIODE_MD) | ||
245 | reg |= MC13783_LED_C0_TRIODE_MD_BIT; | ||
246 | if (pdata->flags & MC13783_LED_TRIODE_AD) | ||
247 | reg |= MC13783_LED_C0_TRIODE_AD_BIT; | ||
248 | if (pdata->flags & MC13783_LED_TRIODE_KP) | ||
249 | reg |= MC13783_LED_C0_TRIODE_KP_BIT; | ||
250 | if (pdata->flags & MC13783_LED_BOOST_EN) | ||
251 | reg |= MC13783_LED_C0_BOOST_BIT; | ||
252 | |||
253 | reg |= (pdata->abmode & MC13783_LED_C0_ABMODE_MASK) << | ||
254 | MC13783_LED_C0_ABMODE; | ||
255 | reg |= (pdata->abref & MC13783_LED_C0_ABREF_MASK) << | ||
256 | MC13783_LED_C0_ABREF; | ||
257 | |||
258 | ret = mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_0, reg); | ||
259 | |||
260 | out: | ||
261 | mc13xxx_unlock(dev); | ||
262 | return ret; | 150 | return ret; |
263 | } | 151 | } |
264 | 152 | ||
265 | static int mc13783_led_probe(struct platform_device *pdev) | 153 | static int __init mc13xxx_led_probe(struct platform_device *pdev) |
266 | { | 154 | { |
267 | struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(&pdev->dev); | 155 | struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(&pdev->dev); |
268 | struct mc13xxx_led_platform_data *led_cur; | 156 | struct mc13xxx *mcdev = dev_get_drvdata(pdev->dev.parent); |
269 | struct mc13783_led *led, *led_dat; | 157 | struct mc13xxx_led_devtype *devtype = |
270 | int ret, i; | 158 | (struct mc13xxx_led_devtype *)pdev->id_entry->driver_data; |
271 | int init_led = 0; | 159 | struct mc13xxx_leds *leds; |
272 | 160 | int i, id, num_leds, ret; | |
273 | if (pdata == NULL) { | 161 | u32 reg, init_led = 0; |
274 | dev_err(&pdev->dev, "missing platform data\n"); | 162 | |
163 | if (!pdata) { | ||
164 | dev_err(&pdev->dev, "Missing platform data\n"); | ||
275 | return -ENODEV; | 165 | return -ENODEV; |
276 | } | 166 | } |
277 | 167 | ||
278 | if (pdata->num_leds < 1 || pdata->num_leds > (MC13783_LED_MAX + 1)) { | 168 | num_leds = pdata->num_leds; |
279 | dev_err(&pdev->dev, "Invalid led count %d\n", pdata->num_leds); | 169 | |
170 | if ((num_leds < 1) || | ||
171 | (num_leds > (devtype->led_max - devtype->led_min + 1))) { | ||
172 | dev_err(&pdev->dev, "Invalid LED count %d\n", num_leds); | ||
280 | return -EINVAL; | 173 | return -EINVAL; |
281 | } | 174 | } |
282 | 175 | ||
283 | led = devm_kzalloc(&pdev->dev, pdata->num_leds * sizeof(*led), | 176 | leds = devm_kzalloc(&pdev->dev, num_leds * sizeof(struct mc13xxx_led) + |
284 | GFP_KERNEL); | 177 | sizeof(struct mc13xxx_leds), GFP_KERNEL); |
285 | if (led == NULL) { | 178 | if (!leds) |
286 | dev_err(&pdev->dev, "failed to alloc memory\n"); | ||
287 | return -ENOMEM; | 179 | return -ENOMEM; |
180 | |||
181 | leds->devtype = devtype; | ||
182 | leds->num_leds = num_leds; | ||
183 | platform_set_drvdata(pdev, leds); | ||
184 | |||
185 | mc13xxx_lock(mcdev); | ||
186 | for (i = 0; i < devtype->num_regs; i++) { | ||
187 | reg = pdata->led_control[i]; | ||
188 | WARN_ON(reg >= (1 << 24)); | ||
189 | ret = mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), reg); | ||
190 | if (ret) | ||
191 | break; | ||
288 | } | 192 | } |
193 | mc13xxx_unlock(mcdev); | ||
289 | 194 | ||
290 | ret = mc13783_leds_prepare(pdev); | ||
291 | if (ret) { | 195 | if (ret) { |
292 | dev_err(&pdev->dev, "unable to init led driver\n"); | 196 | dev_err(&pdev->dev, "Unable to init LED driver\n"); |
293 | return ret; | 197 | return ret; |
294 | } | 198 | } |
295 | 199 | ||
296 | for (i = 0; i < pdata->num_leds; i++) { | 200 | for (i = 0; i < num_leds; i++) { |
297 | led_dat = &led[i]; | 201 | const char *name, *trig; |
298 | led_cur = &pdata->led[i]; | 202 | char max_current; |
299 | 203 | ||
300 | if (led_cur->id > MC13783_LED_MAX || led_cur->id < 0) { | 204 | ret = -EINVAL; |
301 | dev_err(&pdev->dev, "invalid id %d\n", led_cur->id); | 205 | |
302 | ret = -EINVAL; | 206 | id = pdata->led[i].id; |
303 | goto err_register; | 207 | name = pdata->led[i].name; |
208 | trig = pdata->led[i].default_trigger; | ||
209 | max_current = pdata->led[i].max_current; | ||
210 | |||
211 | if ((id > devtype->led_max) || (id < devtype->led_min)) { | ||
212 | dev_err(&pdev->dev, "Invalid ID %i\n", id); | ||
213 | break; | ||
304 | } | 214 | } |
305 | 215 | ||
306 | if (init_led & (1 << led_cur->id)) { | 216 | if (init_led & (1 << id)) { |
307 | dev_err(&pdev->dev, "led %d already initialized\n", | 217 | dev_warn(&pdev->dev, |
308 | led_cur->id); | 218 | "LED %i already initialized\n", id); |
309 | ret = -EINVAL; | 219 | break; |
310 | goto err_register; | ||
311 | } | 220 | } |
312 | 221 | ||
313 | init_led |= 1 << led_cur->id; | 222 | init_led |= 1 << id; |
314 | led_dat->cdev.name = led_cur->name; | 223 | leds->led[i].id = id; |
315 | led_dat->cdev.default_trigger = led_cur->default_trigger; | 224 | leds->led[i].master = mcdev; |
316 | led_dat->cdev.brightness_set = mc13783_led_set; | 225 | leds->led[i].cdev.name = name; |
317 | led_dat->cdev.brightness = LED_OFF; | 226 | leds->led[i].cdev.default_trigger = trig; |
318 | led_dat->id = led_cur->id; | 227 | leds->led[i].cdev.brightness_set = mc13xxx_led_set; |
319 | led_dat->master = dev_get_drvdata(pdev->dev.parent); | 228 | leds->led[i].cdev.brightness = LED_OFF; |
320 | 229 | ||
321 | INIT_WORK(&led_dat->work, mc13783_led_work); | 230 | INIT_WORK(&leds->led[i].work, mc13xxx_led_work); |
322 | 231 | ||
323 | ret = led_classdev_register(pdev->dev.parent, &led_dat->cdev); | 232 | ret = mc13xxx_led_setup(&leds->led[i], max_current); |
324 | if (ret) { | 233 | if (ret) { |
325 | dev_err(&pdev->dev, "failed to register led %d\n", | 234 | dev_err(&pdev->dev, "Unable to setup LED %i\n", id); |
326 | led_dat->id); | 235 | break; |
327 | goto err_register; | ||
328 | } | 236 | } |
329 | 237 | ret = led_classdev_register(pdev->dev.parent, | |
330 | ret = mc13783_led_setup(led_dat, led_cur->max_current); | 238 | &leds->led[i].cdev); |
331 | if (ret) { | 239 | if (ret) { |
332 | dev_err(&pdev->dev, "unable to init led %d\n", | 240 | dev_err(&pdev->dev, "Failed to register LED %i\n", id); |
333 | led_dat->id); | 241 | break; |
334 | i++; | ||
335 | goto err_register; | ||
336 | } | 242 | } |
337 | } | 243 | } |
338 | 244 | ||
339 | platform_set_drvdata(pdev, led); | 245 | if (ret) |
340 | return 0; | 246 | while (--i >= 0) { |
341 | 247 | led_classdev_unregister(&leds->led[i].cdev); | |
342 | err_register: | 248 | cancel_work_sync(&leds->led[i].work); |
343 | for (i = i - 1; i >= 0; i--) { | 249 | } |
344 | led_classdev_unregister(&led[i].cdev); | ||
345 | cancel_work_sync(&led[i].work); | ||
346 | } | ||
347 | 250 | ||
348 | return ret; | 251 | return ret; |
349 | } | 252 | } |
350 | 253 | ||
351 | static int mc13783_led_remove(struct platform_device *pdev) | 254 | static int mc13xxx_led_remove(struct platform_device *pdev) |
352 | { | 255 | { |
353 | struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(&pdev->dev); | 256 | struct mc13xxx *mcdev = dev_get_drvdata(pdev->dev.parent); |
354 | struct mc13783_led *led = platform_get_drvdata(pdev); | 257 | struct mc13xxx_leds *leds = platform_get_drvdata(pdev); |
355 | struct mc13xxx *dev = dev_get_drvdata(pdev->dev.parent); | ||
356 | int i; | 258 | int i; |
357 | 259 | ||
358 | for (i = 0; i < pdata->num_leds; i++) { | 260 | for (i = 0; i < leds->num_leds; i++) { |
359 | led_classdev_unregister(&led[i].cdev); | 261 | led_classdev_unregister(&leds->led[i].cdev); |
360 | cancel_work_sync(&led[i].work); | 262 | cancel_work_sync(&leds->led[i].work); |
361 | } | 263 | } |
362 | 264 | ||
363 | mc13xxx_lock(dev); | 265 | mc13xxx_lock(mcdev); |
364 | 266 | for (i = 0; i < leds->devtype->num_regs; i++) | |
365 | mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_0, 0); | 267 | mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), 0); |
366 | mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_1, 0); | 268 | mc13xxx_unlock(mcdev); |
367 | mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_2, 0); | ||
368 | mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_3, 0); | ||
369 | mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_4, 0); | ||
370 | mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_5, 0); | ||
371 | |||
372 | mc13xxx_unlock(dev); | ||
373 | 269 | ||
374 | return 0; | 270 | return 0; |
375 | } | 271 | } |
376 | 272 | ||
377 | static struct platform_driver mc13783_led_driver = { | 273 | static const struct mc13xxx_led_devtype mc13783_led_devtype = { |
274 | .led_min = MC13783_LED_MD, | ||
275 | .led_max = MC13783_LED_B3, | ||
276 | .num_regs = 6, | ||
277 | }; | ||
278 | |||
279 | static const struct platform_device_id mc13xxx_led_id_table[] = { | ||
280 | { "mc13783-led", (kernel_ulong_t)&mc13783_led_devtype, }, | ||
281 | { } | ||
282 | }; | ||
283 | MODULE_DEVICE_TABLE(platform, mc13xxx_led_id_table); | ||
284 | |||
285 | static struct platform_driver mc13xxx_led_driver = { | ||
378 | .driver = { | 286 | .driver = { |
379 | .name = "mc13783-led", | 287 | .name = "mc13xxx-led", |
380 | .owner = THIS_MODULE, | 288 | .owner = THIS_MODULE, |
381 | }, | 289 | }, |
382 | .probe = mc13783_led_probe, | 290 | .remove = mc13xxx_led_remove, |
383 | .remove = mc13783_led_remove, | 291 | .id_table = mc13xxx_led_id_table, |
384 | }; | 292 | }; |
293 | module_platform_driver_probe(mc13xxx_led_driver, mc13xxx_led_probe); | ||
385 | 294 | ||
386 | module_platform_driver(mc13783_led_driver); | 295 | MODULE_DESCRIPTION("LEDs driver for Freescale MC13XXX PMIC"); |
387 | |||
388 | MODULE_DESCRIPTION("LEDs driver for Freescale MC13783 PMIC"); | ||
389 | MODULE_AUTHOR("Philippe Retornaz <philippe.retornaz@epfl.ch>"); | 296 | MODULE_AUTHOR("Philippe Retornaz <philippe.retornaz@epfl.ch>"); |
390 | MODULE_LICENSE("GPL"); | 297 | MODULE_LICENSE("GPL"); |
391 | MODULE_ALIAS("platform:mc13783-led"); | ||