]>
Commit | Line | Data |
---|---|---|
36edc939 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
75cb2e1d PM |
2 | /* |
3 | * Copyright 2011 bct electronic GmbH | |
af67384f | 4 | * Copyright 2013 Qtechnology/AS |
75cb2e1d PM |
5 | * |
6 | * Author: Peter Meerwald <[email protected]> | |
af67384f | 7 | * Author: Ricardo Ribalda <[email protected]> |
75cb2e1d PM |
8 | * |
9 | * Based on leds-pca955x.c | |
10 | * | |
75cb2e1d | 11 | * LED driver for the PCA9633 I2C LED driver (7-bit slave address 0x62) |
3dfedb9d | 12 | * LED driver for the PCA9634/5 I2C LED driver (7-bit slave address set by hw.) |
75cb2e1d | 13 | * |
8465b018 MG |
14 | * Note that hardware blinking violates the leds infrastructure driver |
15 | * interface since the hardware only supports blinking all LEDs with the | |
16 | * same delay_on/delay_off rates. That is, only the LEDs that are set to | |
17 | * blink will actually blink but all LEDs that are set to blink will blink | |
18 | * in identical fashion. The delay_on/delay_off values of the last LED | |
19 | * that is set to blink will be used for all of the blinking LEDs. | |
20 | * Hardware blinking is disabled by default but can be enabled by setting | |
56a1740c | 21 | * the 'blink_type' member in the platform_data struct to 'PCA963X_HW_BLINK' |
8465b018 | 22 | * or by adding the 'nxp,hw-blink' property to the DTS. |
75cb2e1d PM |
23 | */ |
24 | ||
25 | #include <linux/module.h> | |
26 | #include <linux/delay.h> | |
27 | #include <linux/string.h> | |
28 | #include <linux/ctype.h> | |
29 | #include <linux/leds.h> | |
30 | #include <linux/err.h> | |
31 | #include <linux/i2c.h> | |
0b6034d8 | 32 | #include <linux/property.h> |
75cb2e1d | 33 | #include <linux/slab.h> |
81d22878 | 34 | #include <linux/of.h> |
56a1740c | 35 | #include <linux/platform_data/leds-pca963x.h> |
75cb2e1d PM |
36 | |
37 | /* LED select registers determine the source that drives LED outputs */ | |
56a1740c RR |
38 | #define PCA963X_LED_OFF 0x0 /* LED driver off */ |
39 | #define PCA963X_LED_ON 0x1 /* LED driver on */ | |
40 | #define PCA963X_LED_PWM 0x2 /* Controlled through PWM */ | |
41 | #define PCA963X_LED_GRP_PWM 0x3 /* Controlled through PWM/GRPPWM */ | |
75cb2e1d | 42 | |
56a1740c | 43 | #define PCA963X_MODE2_DMBLNK 0x20 /* Enable blinking */ |
8465b018 | 44 | |
56a1740c RR |
45 | #define PCA963X_MODE1 0x00 |
46 | #define PCA963X_MODE2 0x01 | |
47 | #define PCA963X_PWM_BASE 0x02 | |
af67384f | 48 | |
56a1740c | 49 | enum pca963x_type { |
af67384f RR |
50 | pca9633, |
51 | pca9634, | |
3dfedb9d | 52 | pca9635, |
af67384f RR |
53 | }; |
54 | ||
56a1740c | 55 | struct pca963x_chipdef { |
af67384f RR |
56 | u8 grppwm; |
57 | u8 grpfreq; | |
58 | u8 ledout_base; | |
59 | int n_leds; | |
35c7d301 | 60 | unsigned int scaling; |
af67384f RR |
61 | }; |
62 | ||
56a1740c | 63 | static struct pca963x_chipdef pca963x_chipdefs[] = { |
af67384f RR |
64 | [pca9633] = { |
65 | .grppwm = 0x6, | |
66 | .grpfreq = 0x7, | |
67 | .ledout_base = 0x8, | |
68 | .n_leds = 4, | |
69 | }, | |
70 | [pca9634] = { | |
71 | .grppwm = 0xa, | |
72 | .grpfreq = 0xb, | |
73 | .ledout_base = 0xc, | |
74 | .n_leds = 8, | |
75 | }, | |
3dfedb9d PM |
76 | [pca9635] = { |
77 | .grppwm = 0x12, | |
78 | .grpfreq = 0x13, | |
79 | .ledout_base = 0x14, | |
80 | .n_leds = 16, | |
81 | }, | |
af67384f | 82 | }; |
75cb2e1d | 83 | |
8465b018 | 84 | /* Total blink period in milliseconds */ |
56a1740c RR |
85 | #define PCA963X_BLINK_PERIOD_MIN 42 |
86 | #define PCA963X_BLINK_PERIOD_MAX 10667 | |
8465b018 | 87 | |
56a1740c | 88 | static const struct i2c_device_id pca963x_id[] = { |
af67384f RR |
89 | { "pca9632", pca9633 }, |
90 | { "pca9633", pca9633 }, | |
91 | { "pca9634", pca9634 }, | |
3dfedb9d | 92 | { "pca9635", pca9635 }, |
75cb2e1d PM |
93 | { } |
94 | }; | |
56a1740c | 95 | MODULE_DEVICE_TABLE(i2c, pca963x_id); |
75cb2e1d | 96 | |
56a1740c | 97 | struct pca963x_led; |
a7d0e988 | 98 | |
56a1740c RR |
99 | struct pca963x { |
100 | struct pca963x_chipdef *chipdef; | |
a7d0e988 RR |
101 | struct mutex mutex; |
102 | struct i2c_client *client; | |
56a1740c | 103 | struct pca963x_led *leds; |
a8c170b0 | 104 | unsigned long leds_on; |
a7d0e988 RR |
105 | }; |
106 | ||
56a1740c RR |
107 | struct pca963x_led { |
108 | struct pca963x *chip; | |
75cb2e1d | 109 | struct led_classdev led_cdev; |
3dfedb9d | 110 | int led_num; /* 0 .. 15 potentially */ |
75cb2e1d | 111 | char name[32]; |
8465b018 MG |
112 | u8 gdc; |
113 | u8 gfrq; | |
75cb2e1d PM |
114 | }; |
115 | ||
5029a2e3 AL |
116 | static int pca963x_brightness(struct pca963x_led *pca963x, |
117 | enum led_brightness brightness) | |
75cb2e1d | 118 | { |
56a1740c RR |
119 | u8 ledout_addr = pca963x->chip->chipdef->ledout_base |
120 | + (pca963x->led_num / 4); | |
af67384f | 121 | u8 ledout; |
56a1740c | 122 | int shift = 2 * (pca963x->led_num % 4); |
75cb2e1d | 123 | u8 mask = 0x3 << shift; |
5029a2e3 | 124 | int ret; |
75cb2e1d | 125 | |
56a1740c | 126 | ledout = i2c_smbus_read_byte_data(pca963x->chip->client, ledout_addr); |
5029a2e3 | 127 | switch (brightness) { |
75cb2e1d | 128 | case LED_FULL: |
5029a2e3 AL |
129 | ret = i2c_smbus_write_byte_data(pca963x->chip->client, |
130 | ledout_addr, | |
56a1740c | 131 | (ledout & ~mask) | (PCA963X_LED_ON << shift)); |
75cb2e1d PM |
132 | break; |
133 | case LED_OFF: | |
5029a2e3 AL |
134 | ret = i2c_smbus_write_byte_data(pca963x->chip->client, |
135 | ledout_addr, ledout & ~mask); | |
75cb2e1d PM |
136 | break; |
137 | default: | |
5029a2e3 | 138 | ret = i2c_smbus_write_byte_data(pca963x->chip->client, |
56a1740c | 139 | PCA963X_PWM_BASE + pca963x->led_num, |
5029a2e3 AL |
140 | brightness); |
141 | if (ret < 0) | |
a8c170b0 | 142 | return ret; |
5029a2e3 AL |
143 | ret = i2c_smbus_write_byte_data(pca963x->chip->client, |
144 | ledout_addr, | |
56a1740c | 145 | (ledout & ~mask) | (PCA963X_LED_PWM << shift)); |
75cb2e1d PM |
146 | break; |
147 | } | |
a8c170b0 | 148 | |
5029a2e3 | 149 | return ret; |
75cb2e1d PM |
150 | } |
151 | ||
5029a2e3 | 152 | static void pca963x_blink(struct pca963x_led *pca963x) |
8465b018 | 153 | { |
56a1740c RR |
154 | u8 ledout_addr = pca963x->chip->chipdef->ledout_base + |
155 | (pca963x->led_num / 4); | |
a7d0e988 | 156 | u8 ledout; |
56a1740c RR |
157 | u8 mode2 = i2c_smbus_read_byte_data(pca963x->chip->client, |
158 | PCA963X_MODE2); | |
159 | int shift = 2 * (pca963x->led_num % 4); | |
8465b018 MG |
160 | u8 mask = 0x3 << shift; |
161 | ||
56a1740c RR |
162 | i2c_smbus_write_byte_data(pca963x->chip->client, |
163 | pca963x->chip->chipdef->grppwm, pca963x->gdc); | |
8465b018 | 164 | |
56a1740c RR |
165 | i2c_smbus_write_byte_data(pca963x->chip->client, |
166 | pca963x->chip->chipdef->grpfreq, pca963x->gfrq); | |
8465b018 | 167 | |
56a1740c RR |
168 | if (!(mode2 & PCA963X_MODE2_DMBLNK)) |
169 | i2c_smbus_write_byte_data(pca963x->chip->client, PCA963X_MODE2, | |
170 | mode2 | PCA963X_MODE2_DMBLNK); | |
8465b018 | 171 | |
56a1740c RR |
172 | mutex_lock(&pca963x->chip->mutex); |
173 | ledout = i2c_smbus_read_byte_data(pca963x->chip->client, ledout_addr); | |
174 | if ((ledout & mask) != (PCA963X_LED_GRP_PWM << shift)) | |
175 | i2c_smbus_write_byte_data(pca963x->chip->client, ledout_addr, | |
176 | (ledout & ~mask) | (PCA963X_LED_GRP_PWM << shift)); | |
177 | mutex_unlock(&pca963x->chip->mutex); | |
8465b018 MG |
178 | } |
179 | ||
a8c170b0 MR |
180 | static int pca963x_power_state(struct pca963x_led *pca963x) |
181 | { | |
182 | unsigned long *leds_on = &pca963x->chip->leds_on; | |
183 | unsigned long cached_leds = pca963x->chip->leds_on; | |
184 | ||
185 | if (pca963x->led_cdev.brightness) | |
186 | set_bit(pca963x->led_num, leds_on); | |
187 | else | |
188 | clear_bit(pca963x->led_num, leds_on); | |
189 | ||
190 | if (!(*leds_on) != !cached_leds) | |
191 | return i2c_smbus_write_byte_data(pca963x->chip->client, | |
192 | PCA963X_MODE1, *leds_on ? 0 : BIT(4)); | |
193 | ||
194 | return 0; | |
195 | } | |
196 | ||
5029a2e3 | 197 | static int pca963x_led_set(struct led_classdev *led_cdev, |
75cb2e1d PM |
198 | enum led_brightness value) |
199 | { | |
56a1740c | 200 | struct pca963x_led *pca963x; |
a8c170b0 | 201 | int ret; |
75cb2e1d | 202 | |
56a1740c | 203 | pca963x = container_of(led_cdev, struct pca963x_led, led_cdev); |
75cb2e1d | 204 | |
a8c170b0 MR |
205 | mutex_lock(&pca963x->chip->mutex); |
206 | ||
207 | ret = pca963x_brightness(pca963x, value); | |
208 | if (ret < 0) | |
209 | goto unlock; | |
210 | ret = pca963x_power_state(pca963x); | |
211 | ||
212 | unlock: | |
213 | mutex_unlock(&pca963x->chip->mutex); | |
214 | return ret; | |
75cb2e1d PM |
215 | } |
216 | ||
35c7d301 MR |
217 | static unsigned int pca963x_period_scale(struct pca963x_led *pca963x, |
218 | unsigned int val) | |
219 | { | |
220 | unsigned int scaling = pca963x->chip->chipdef->scaling; | |
221 | ||
222 | return scaling ? DIV_ROUND_CLOSEST(val * scaling, 1000) : val; | |
223 | } | |
224 | ||
56a1740c | 225 | static int pca963x_blink_set(struct led_classdev *led_cdev, |
8465b018 MG |
226 | unsigned long *delay_on, unsigned long *delay_off) |
227 | { | |
56a1740c | 228 | struct pca963x_led *pca963x; |
8465b018 MG |
229 | unsigned long time_on, time_off, period; |
230 | u8 gdc, gfrq; | |
231 | ||
56a1740c | 232 | pca963x = container_of(led_cdev, struct pca963x_led, led_cdev); |
8465b018 MG |
233 | |
234 | time_on = *delay_on; | |
235 | time_off = *delay_off; | |
236 | ||
237 | /* If both zero, pick reasonable defaults of 500ms each */ | |
238 | if (!time_on && !time_off) { | |
239 | time_on = 500; | |
240 | time_off = 500; | |
241 | } | |
242 | ||
35c7d301 | 243 | period = pca963x_period_scale(pca963x, time_on + time_off); |
8465b018 MG |
244 | |
245 | /* If period not supported by hardware, default to someting sane. */ | |
56a1740c RR |
246 | if ((period < PCA963X_BLINK_PERIOD_MIN) || |
247 | (period > PCA963X_BLINK_PERIOD_MAX)) { | |
8465b018 MG |
248 | time_on = 500; |
249 | time_off = 500; | |
35c7d301 | 250 | period = pca963x_period_scale(pca963x, 1000); |
8465b018 MG |
251 | } |
252 | ||
253 | /* | |
254 | * From manual: duty cycle = (GDC / 256) -> | |
255 | * (time_on / period) = (GDC / 256) -> | |
256 | * GDC = ((time_on * 256) / period) | |
257 | */ | |
35c7d301 | 258 | gdc = (pca963x_period_scale(pca963x, time_on) * 256) / period; |
8465b018 MG |
259 | |
260 | /* | |
261 | * From manual: period = ((GFRQ + 1) / 24) in seconds. | |
262 | * So, period (in ms) = (((GFRQ + 1) / 24) * 1000) -> | |
263 | * GFRQ = ((period * 24 / 1000) - 1) | |
264 | */ | |
265 | gfrq = (period * 24 / 1000) - 1; | |
266 | ||
56a1740c RR |
267 | pca963x->gdc = gdc; |
268 | pca963x->gfrq = gfrq; | |
8465b018 | 269 | |
5029a2e3 | 270 | pca963x_blink(pca963x); |
8465b018 MG |
271 | |
272 | *delay_on = time_on; | |
273 | *delay_off = time_off; | |
274 | ||
275 | return 0; | |
276 | } | |
277 | ||
56a1740c | 278 | static struct pca963x_platform_data * |
0b6034d8 | 279 | pca963x_get_pdata(struct i2c_client *client, struct pca963x_chipdef *chip) |
81d22878 | 280 | { |
56a1740c RR |
281 | struct pca963x_platform_data *pdata; |
282 | struct led_info *pca963x_leds; | |
0b6034d8 | 283 | struct fwnode_handle *child; |
81d22878 TL |
284 | int count; |
285 | ||
0b6034d8 | 286 | count = device_get_child_node_count(&client->dev); |
af67384f | 287 | if (!count || count > chip->n_leds) |
81d22878 TL |
288 | return ERR_PTR(-ENODEV); |
289 | ||
a86854d0 KC |
290 | pca963x_leds = devm_kcalloc(&client->dev, |
291 | chip->n_leds, sizeof(struct led_info), GFP_KERNEL); | |
56a1740c | 292 | if (!pca963x_leds) |
81d22878 TL |
293 | return ERR_PTR(-ENOMEM); |
294 | ||
0b6034d8 | 295 | device_for_each_child_node(&client->dev, child) { |
a44b0f5e | 296 | struct led_info led = {}; |
81d22878 TL |
297 | u32 reg; |
298 | int res; | |
299 | ||
0b6034d8 | 300 | res = fwnode_property_read_u32(child, "reg", ®); |
8a6acd64 RR |
301 | if ((res != 0) || (reg >= chip->n_leds)) |
302 | continue; | |
0b6034d8 AS |
303 | |
304 | res = fwnode_property_read_string(child, "label", &led.name); | |
305 | if ((res != 0) && is_of_node(child)) | |
306 | led.name = to_of_node(child)->name; | |
307 | ||
308 | fwnode_property_read_string(child, "linux,default-trigger", | |
309 | &led.default_trigger); | |
310 | ||
56a1740c | 311 | pca963x_leds[reg] = led; |
81d22878 TL |
312 | } |
313 | pdata = devm_kzalloc(&client->dev, | |
56a1740c | 314 | sizeof(struct pca963x_platform_data), GFP_KERNEL); |
81d22878 TL |
315 | if (!pdata) |
316 | return ERR_PTR(-ENOMEM); | |
317 | ||
56a1740c | 318 | pdata->leds.leds = pca963x_leds; |
8a6acd64 | 319 | pdata->leds.num_leds = chip->n_leds; |
81d22878 TL |
320 | |
321 | /* default to open-drain unless totem pole (push-pull) is specified */ | |
0b6034d8 | 322 | if (device_property_read_bool(&client->dev, "nxp,totem-pole")) |
56a1740c | 323 | pdata->outdrv = PCA963X_TOTEM_POLE; |
81d22878 | 324 | else |
56a1740c | 325 | pdata->outdrv = PCA963X_OPEN_DRAIN; |
81d22878 | 326 | |
8465b018 | 327 | /* default to software blinking unless hardware blinking is specified */ |
0b6034d8 | 328 | if (device_property_read_bool(&client->dev, "nxp,hw-blink")) |
56a1740c | 329 | pdata->blink_type = PCA963X_HW_BLINK; |
8465b018 | 330 | else |
56a1740c | 331 | pdata->blink_type = PCA963X_SW_BLINK; |
8465b018 | 332 | |
0b6034d8 AS |
333 | if (device_property_read_u32(&client->dev, "nxp,period-scale", |
334 | &chip->scaling)) | |
35c7d301 MR |
335 | chip->scaling = 1000; |
336 | ||
bb29b9cc | 337 | /* default to non-inverted output, unless inverted is specified */ |
0b6034d8 | 338 | if (device_property_read_bool(&client->dev, "nxp,inverted-out")) |
bb29b9cc AD |
339 | pdata->dir = PCA963X_INVERTED; |
340 | else | |
341 | pdata->dir = PCA963X_NORMAL; | |
342 | ||
81d22878 TL |
343 | return pdata; |
344 | } | |
345 | ||
56a1740c | 346 | static const struct of_device_id of_pca963x_match[] = { |
af67384f RR |
347 | { .compatible = "nxp,pca9632", }, |
348 | { .compatible = "nxp,pca9633", }, | |
349 | { .compatible = "nxp,pca9634", }, | |
3dfedb9d | 350 | { .compatible = "nxp,pca9635", }, |
81d22878 TL |
351 | {}, |
352 | }; | |
4d59ed85 | 353 | MODULE_DEVICE_TABLE(of, of_pca963x_match); |
81d22878 | 354 | |
56a1740c | 355 | static int pca963x_probe(struct i2c_client *client, |
75cb2e1d PM |
356 | const struct i2c_device_id *id) |
357 | { | |
56a1740c RR |
358 | struct pca963x *pca963x_chip; |
359 | struct pca963x_led *pca963x; | |
360 | struct pca963x_platform_data *pdata; | |
361 | struct pca963x_chipdef *chip; | |
75cb2e1d PM |
362 | int i, err; |
363 | ||
c90fbae3 | 364 | chip = &pca963x_chipdefs[id->driver_data]; |
87aae1ea | 365 | pdata = dev_get_platdata(&client->dev); |
75cb2e1d | 366 | |
81d22878 | 367 | if (!pdata) { |
0b6034d8 | 368 | pdata = pca963x_get_pdata(client, chip); |
81d22878 TL |
369 | if (IS_ERR(pdata)) { |
370 | dev_warn(&client->dev, "could not parse configuration\n"); | |
371 | pdata = NULL; | |
372 | } | |
373 | } | |
374 | ||
af67384f RR |
375 | if (pdata && (pdata->leds.num_leds < 1 || |
376 | pdata->leds.num_leds > chip->n_leds)) { | |
377 | dev_err(&client->dev, "board info must claim 1-%d LEDs", | |
378 | chip->n_leds); | |
379 | return -EINVAL; | |
75cb2e1d PM |
380 | } |
381 | ||
56a1740c | 382 | pca963x_chip = devm_kzalloc(&client->dev, sizeof(*pca963x_chip), |
a7d0e988 | 383 | GFP_KERNEL); |
56a1740c | 384 | if (!pca963x_chip) |
a7d0e988 | 385 | return -ENOMEM; |
a86854d0 | 386 | pca963x = devm_kcalloc(&client->dev, chip->n_leds, sizeof(*pca963x), |
af67384f | 387 | GFP_KERNEL); |
56a1740c | 388 | if (!pca963x) |
75cb2e1d PM |
389 | return -ENOMEM; |
390 | ||
56a1740c | 391 | i2c_set_clientdata(client, pca963x_chip); |
a7d0e988 | 392 | |
56a1740c RR |
393 | mutex_init(&pca963x_chip->mutex); |
394 | pca963x_chip->chipdef = chip; | |
395 | pca963x_chip->client = client; | |
396 | pca963x_chip->leds = pca963x; | |
a7d0e988 RR |
397 | |
398 | /* Turn off LEDs by default*/ | |
3dfedb9d PM |
399 | for (i = 0; i < chip->n_leds / 4; i++) |
400 | i2c_smbus_write_byte_data(client, chip->ledout_base + i, 0x00); | |
75cb2e1d | 401 | |
af67384f | 402 | for (i = 0; i < chip->n_leds; i++) { |
56a1740c RR |
403 | pca963x[i].led_num = i; |
404 | pca963x[i].chip = pca963x_chip; | |
75cb2e1d PM |
405 | |
406 | /* Platform data can specify LED names and default triggers */ | |
2f73c392 PM |
407 | if (pdata && i < pdata->leds.num_leds) { |
408 | if (pdata->leds.leds[i].name) | |
56a1740c RR |
409 | snprintf(pca963x[i].name, |
410 | sizeof(pca963x[i].name), "pca963x:%s", | |
2f73c392 PM |
411 | pdata->leds.leds[i].name); |
412 | if (pdata->leds.leds[i].default_trigger) | |
56a1740c | 413 | pca963x[i].led_cdev.default_trigger = |
2f73c392 | 414 | pdata->leds.leds[i].default_trigger; |
75cb2e1d | 415 | } |
a5cd98b7 RR |
416 | if (!pdata || i >= pdata->leds.num_leds || |
417 | !pdata->leds.leds[i].name) | |
56a1740c RR |
418 | snprintf(pca963x[i].name, sizeof(pca963x[i].name), |
419 | "pca963x:%d:%.2x:%d", client->adapter->nr, | |
a5cd98b7 | 420 | client->addr, i); |
75cb2e1d | 421 | |
56a1740c | 422 | pca963x[i].led_cdev.name = pca963x[i].name; |
5029a2e3 | 423 | pca963x[i].led_cdev.brightness_set_blocking = pca963x_led_set; |
75cb2e1d | 424 | |
56a1740c RR |
425 | if (pdata && pdata->blink_type == PCA963X_HW_BLINK) |
426 | pca963x[i].led_cdev.blink_set = pca963x_blink_set; | |
8465b018 | 427 | |
56a1740c | 428 | err = led_classdev_register(&client->dev, &pca963x[i].led_cdev); |
75cb2e1d PM |
429 | if (err < 0) |
430 | goto exit; | |
431 | } | |
432 | ||
a8c170b0 MR |
433 | /* Disable LED all-call address, and power down initially */ |
434 | i2c_smbus_write_byte_data(client, PCA963X_MODE1, BIT(4)); | |
75cb2e1d | 435 | |
0c62f42d | 436 | if (pdata) { |
bb29b9cc AD |
437 | u8 mode2 = i2c_smbus_read_byte_data(pca963x->chip->client, |
438 | PCA963X_MODE2); | |
0c62f42d PM |
439 | /* Configure output: open-drain or totem pole (push-pull) */ |
440 | if (pdata->outdrv == PCA963X_OPEN_DRAIN) | |
bb29b9cc | 441 | mode2 |= 0x01; |
0c62f42d | 442 | else |
bb29b9cc AD |
443 | mode2 |= 0x05; |
444 | /* Configure direction: normal or inverted */ | |
445 | if (pdata->dir == PCA963X_INVERTED) | |
446 | mode2 |= 0x10; | |
447 | i2c_smbus_write_byte_data(pca963x->chip->client, PCA963X_MODE2, | |
448 | mode2); | |
0c62f42d | 449 | } |
2f73c392 | 450 | |
75cb2e1d PM |
451 | return 0; |
452 | ||
453 | exit: | |
5029a2e3 | 454 | while (i--) |
56a1740c | 455 | led_classdev_unregister(&pca963x[i].led_cdev); |
75cb2e1d | 456 | |
75cb2e1d PM |
457 | return err; |
458 | } | |
459 | ||
56a1740c | 460 | static int pca963x_remove(struct i2c_client *client) |
75cb2e1d | 461 | { |
56a1740c | 462 | struct pca963x *pca963x = i2c_get_clientdata(client); |
75cb2e1d PM |
463 | int i; |
464 | ||
5029a2e3 | 465 | for (i = 0; i < pca963x->chipdef->n_leds; i++) |
56a1740c | 466 | led_classdev_unregister(&pca963x->leds[i].led_cdev); |
75cb2e1d | 467 | |
75cb2e1d PM |
468 | return 0; |
469 | } | |
470 | ||
56a1740c | 471 | static struct i2c_driver pca963x_driver = { |
75cb2e1d | 472 | .driver = { |
56a1740c | 473 | .name = "leds-pca963x", |
0b6034d8 | 474 | .of_match_table = of_pca963x_match, |
75cb2e1d | 475 | }, |
56a1740c RR |
476 | .probe = pca963x_probe, |
477 | .remove = pca963x_remove, | |
478 | .id_table = pca963x_id, | |
75cb2e1d PM |
479 | }; |
480 | ||
56a1740c | 481 | module_i2c_driver(pca963x_driver); |
75cb2e1d PM |
482 | |
483 | MODULE_AUTHOR("Peter Meerwald <[email protected]>"); | |
56a1740c | 484 | MODULE_DESCRIPTION("PCA963X LED driver"); |
75cb2e1d | 485 | MODULE_LICENSE("GPL v2"); |