diff options
Diffstat (limited to 'drivers/leds/leds-pca955x.c')
| -rw-r--r-- | drivers/leds/leds-pca955x.c | 70 |
1 files changed, 38 insertions, 32 deletions
diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c index 146c06972863..f508729123b5 100644 --- a/drivers/leds/leds-pca955x.c +++ b/drivers/leds/leds-pca955x.c | |||
| @@ -248,11 +248,10 @@ static int __devinit pca955x_probe(struct i2c_client *client, | |||
| 248 | const struct i2c_device_id *id) | 248 | const struct i2c_device_id *id) |
| 249 | { | 249 | { |
| 250 | struct pca955x_led *pca955x; | 250 | struct pca955x_led *pca955x; |
| 251 | int i; | ||
| 252 | int err = -ENODEV; | ||
| 253 | struct pca955x_chipdef *chip; | 251 | struct pca955x_chipdef *chip; |
| 254 | struct i2c_adapter *adapter; | 252 | struct i2c_adapter *adapter; |
| 255 | struct led_platform_data *pdata; | 253 | struct led_platform_data *pdata; |
| 254 | int i, err; | ||
| 256 | 255 | ||
| 257 | chip = &pca955x_chipdefs[id->driver_data]; | 256 | chip = &pca955x_chipdefs[id->driver_data]; |
| 258 | adapter = to_i2c_adapter(client->dev.parent); | 257 | adapter = to_i2c_adapter(client->dev.parent); |
| @@ -282,43 +281,41 @@ static int __devinit pca955x_probe(struct i2c_client *client, | |||
| 282 | } | 281 | } |
| 283 | } | 282 | } |
| 284 | 283 | ||
| 284 | pca955x = kzalloc(sizeof(*pca955x) * chip->bits, GFP_KERNEL); | ||
| 285 | if (!pca955x) | ||
| 286 | return -ENOMEM; | ||
| 287 | |||
| 288 | i2c_set_clientdata(client, pca955x); | ||
| 289 | |||
| 285 | for (i = 0; i < chip->bits; i++) { | 290 | for (i = 0; i < chip->bits; i++) { |
| 286 | pca955x = kzalloc(sizeof(struct pca955x_led), GFP_KERNEL); | 291 | pca955x[i].chipdef = chip; |
| 287 | if (!pca955x) { | 292 | pca955x[i].client = client; |
| 288 | err = -ENOMEM; | 293 | pca955x[i].led_num = i; |
| 289 | goto exit; | ||
| 290 | } | ||
| 291 | 294 | ||
| 292 | pca955x->chipdef = chip; | ||
| 293 | pca955x->client = client; | ||
| 294 | pca955x->led_num = i; | ||
| 295 | /* Platform data can specify LED names and default triggers */ | 295 | /* Platform data can specify LED names and default triggers */ |
| 296 | if (pdata) { | 296 | if (pdata) { |
| 297 | if (pdata->leds[i].name) | 297 | if (pdata->leds[i].name) |
| 298 | snprintf(pca955x->name, 32, "pca955x:%s", | 298 | snprintf(pca955x[i].name, |
| 299 | pdata->leds[i].name); | 299 | sizeof(pca955x[i].name), "pca955x:%s", |
| 300 | pdata->leds[i].name); | ||
| 300 | if (pdata->leds[i].default_trigger) | 301 | if (pdata->leds[i].default_trigger) |
| 301 | pca955x->led_cdev.default_trigger = | 302 | pca955x[i].led_cdev.default_trigger = |
| 302 | pdata->leds[i].default_trigger; | 303 | pdata->leds[i].default_trigger; |
| 303 | } else { | 304 | } else { |
| 304 | snprintf(pca955x->name, 32, "pca955x:%d", i); | 305 | snprintf(pca955x[i].name, sizeof(pca955x[i].name), |
| 306 | "pca955x:%d", i); | ||
| 305 | } | 307 | } |
| 306 | spin_lock_init(&pca955x->lock); | ||
| 307 | 308 | ||
| 308 | pca955x->led_cdev.name = pca955x->name; | 309 | spin_lock_init(&pca955x[i].lock); |
| 309 | pca955x->led_cdev.brightness_set = | ||
| 310 | pca955x_led_set; | ||
| 311 | 310 | ||
| 312 | /* | 311 | pca955x[i].led_cdev.name = pca955x[i].name; |
| 313 | * Client data is a pointer to the _first_ pca955x_led | 312 | pca955x[i].led_cdev.brightness_set = pca955x_led_set; |
| 314 | * struct | ||
| 315 | */ | ||
| 316 | if (i == 0) | ||
| 317 | i2c_set_clientdata(client, pca955x); | ||
| 318 | 313 | ||
| 319 | INIT_WORK(&(pca955x->work), pca955x_led_work); | 314 | INIT_WORK(&pca955x[i].work, pca955x_led_work); |
| 320 | 315 | ||
| 321 | led_classdev_register(&client->dev, &(pca955x->led_cdev)); | 316 | err = led_classdev_register(&client->dev, &pca955x[i].led_cdev); |
| 317 | if (err < 0) | ||
| 318 | goto exit; | ||
| 322 | } | 319 | } |
| 323 | 320 | ||
| 324 | /* Turn off LEDs */ | 321 | /* Turn off LEDs */ |
| @@ -336,23 +333,32 @@ static int __devinit pca955x_probe(struct i2c_client *client, | |||
| 336 | pca955x_write_psc(client, 1, 0); | 333 | pca955x_write_psc(client, 1, 0); |
| 337 | 334 | ||
| 338 | return 0; | 335 | return 0; |
| 336 | |||
| 339 | exit: | 337 | exit: |
| 338 | while (i--) { | ||
| 339 | led_classdev_unregister(&pca955x[i].led_cdev); | ||
| 340 | cancel_work_sync(&pca955x[i].work); | ||
| 341 | } | ||
| 342 | |||
| 343 | kfree(pca955x); | ||
| 344 | i2c_set_clientdata(client, NULL); | ||
| 345 | |||
| 340 | return err; | 346 | return err; |
| 341 | } | 347 | } |
| 342 | 348 | ||
| 343 | static int __devexit pca955x_remove(struct i2c_client *client) | 349 | static int __devexit pca955x_remove(struct i2c_client *client) |
| 344 | { | 350 | { |
| 345 | struct pca955x_led *pca955x = i2c_get_clientdata(client); | 351 | struct pca955x_led *pca955x = i2c_get_clientdata(client); |
| 346 | int leds = pca955x->chipdef->bits; | ||
| 347 | int i; | 352 | int i; |
| 348 | 353 | ||
| 349 | for (i = 0; i < leds; i++) { | 354 | for (i = 0; i < pca955x->chipdef->bits; i++) { |
| 350 | led_classdev_unregister(&(pca955x->led_cdev)); | 355 | led_classdev_unregister(&pca955x[i].led_cdev); |
| 351 | cancel_work_sync(&(pca955x->work)); | 356 | cancel_work_sync(&pca955x[i].work); |
| 352 | kfree(pca955x); | ||
| 353 | pca955x = pca955x + 1; | ||
| 354 | } | 357 | } |
| 355 | 358 | ||
| 359 | kfree(pca955x); | ||
| 360 | i2c_set_clientdata(client, NULL); | ||
| 361 | |||
| 356 | return 0; | 362 | return 0; |
| 357 | } | 363 | } |
| 358 | 364 | ||
