diff options
| author | Pavel Machek <pavel@ucw.cz> | 2015-03-13 16:48:40 -0400 |
|---|---|---|
| committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-04-08 16:46:54 -0400 |
| commit | b6100f10bdc2019a65297d2597c388de2f7dd653 (patch) | |
| tree | 2d0f8eceee0963d7ce1008355c6112e333d290ee /drivers/media | |
| parent | 09f50121e3b96a613e7c9724e7bbf31fdec640f7 (diff) | |
[media] Add device tree support to adp1653 flash driver
Nokia N900 is switching to device tree, make sure we can use flash
there, too.
Signed-off-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Diffstat (limited to 'drivers/media')
| -rw-r--r-- | drivers/media/i2c/adp1653.c | 90 |
1 files changed, 81 insertions, 9 deletions
diff --git a/drivers/media/i2c/adp1653.c b/drivers/media/i2c/adp1653.c index 873fe1949e98..0341009d71fc 100644 --- a/drivers/media/i2c/adp1653.c +++ b/drivers/media/i2c/adp1653.c | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | * Contributors: | 8 | * Contributors: |
| 9 | * Sakari Ailus <sakari.ailus@iki.fi> | 9 | * Sakari Ailus <sakari.ailus@iki.fi> |
| 10 | * Tuukka Toivonen <tuukkat76@gmail.com> | 10 | * Tuukka Toivonen <tuukkat76@gmail.com> |
| 11 | * Pavel Machek <pavel@ucw.cz> | ||
| 11 | * | 12 | * |
| 12 | * This program is free software; you can redistribute it and/or | 13 | * This program is free software; you can redistribute it and/or |
| 13 | * modify it under the terms of the GNU General Public License | 14 | * modify it under the terms of the GNU General Public License |
| @@ -34,6 +35,8 @@ | |||
| 34 | #include <linux/module.h> | 35 | #include <linux/module.h> |
| 35 | #include <linux/i2c.h> | 36 | #include <linux/i2c.h> |
| 36 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
| 38 | #include <linux/of_gpio.h> | ||
| 39 | #include <linux/gpio.h> | ||
| 37 | #include <media/adp1653.h> | 40 | #include <media/adp1653.h> |
| 38 | #include <media/v4l2-device.h> | 41 | #include <media/v4l2-device.h> |
| 39 | 42 | ||
| @@ -306,9 +309,17 @@ adp1653_init_device(struct adp1653_flash *flash) | |||
| 306 | static int | 309 | static int |
| 307 | __adp1653_set_power(struct adp1653_flash *flash, int on) | 310 | __adp1653_set_power(struct adp1653_flash *flash, int on) |
| 308 | { | 311 | { |
| 309 | int ret; | 312 | int ret = 0; |
| 313 | |||
| 314 | if (flash->platform_data->power) { | ||
| 315 | ret = flash->platform_data->power(&flash->subdev, on); | ||
| 316 | } else { | ||
| 317 | gpio_set_value(flash->platform_data->power_gpio, on); | ||
| 318 | if (on) | ||
| 319 | /* Some delay is apparently required. */ | ||
| 320 | udelay(20); | ||
| 321 | } | ||
| 310 | 322 | ||
| 311 | ret = flash->platform_data->power(&flash->subdev, on); | ||
| 312 | if (ret < 0) | 323 | if (ret < 0) |
| 313 | return ret; | 324 | return ret; |
| 314 | 325 | ||
| @@ -316,8 +327,13 @@ __adp1653_set_power(struct adp1653_flash *flash, int on) | |||
| 316 | return 0; | 327 | return 0; |
| 317 | 328 | ||
| 318 | ret = adp1653_init_device(flash); | 329 | ret = adp1653_init_device(flash); |
| 319 | if (ret < 0) | 330 | if (ret >= 0) |
| 331 | return ret; | ||
| 332 | |||
| 333 | if (flash->platform_data->power) | ||
| 320 | flash->platform_data->power(&flash->subdev, 0); | 334 | flash->platform_data->power(&flash->subdev, 0); |
| 335 | else | ||
| 336 | gpio_set_value(flash->platform_data->power_gpio, 0); | ||
| 321 | 337 | ||
| 322 | return ret; | 338 | return ret; |
| 323 | } | 339 | } |
| @@ -407,21 +423,77 @@ static int adp1653_resume(struct device *dev) | |||
| 407 | 423 | ||
| 408 | #endif /* CONFIG_PM */ | 424 | #endif /* CONFIG_PM */ |
| 409 | 425 | ||
| 426 | static int adp1653_of_init(struct i2c_client *client, | ||
| 427 | struct adp1653_flash *flash, | ||
| 428 | struct device_node *node) | ||
| 429 | { | ||
| 430 | u32 val; | ||
| 431 | struct adp1653_platform_data *pd; | ||
| 432 | enum of_gpio_flags flags; | ||
| 433 | int gpio; | ||
| 434 | struct device_node *child; | ||
| 435 | |||
| 436 | if (!node) | ||
| 437 | return -EINVAL; | ||
| 438 | |||
| 439 | pd = devm_kzalloc(&client->dev, sizeof(*pd), GFP_KERNEL); | ||
| 440 | if (!pd) | ||
| 441 | return -ENOMEM; | ||
| 442 | flash->platform_data = pd; | ||
| 443 | |||
| 444 | child = of_get_child_by_name(node, "flash"); | ||
| 445 | if (!child) | ||
| 446 | return -EINVAL; | ||
| 447 | if (of_property_read_u32(child, "flash-timeout-microsec", &val)) | ||
| 448 | return -EINVAL; | ||
| 449 | |||
| 450 | pd->max_flash_timeout = val; | ||
| 451 | if (of_property_read_u32(child, "flash-max-microamp", &val)) | ||
| 452 | return -EINVAL; | ||
| 453 | pd->max_flash_intensity = val/1000; | ||
| 454 | |||
| 455 | if (of_property_read_u32(child, "max-microamp", &val)) | ||
| 456 | return -EINVAL; | ||
| 457 | pd->max_torch_intensity = val/1000; | ||
| 458 | |||
| 459 | child = of_get_child_by_name(node, "indicator"); | ||
| 460 | if (!child) | ||
| 461 | return -EINVAL; | ||
| 462 | if (of_property_read_u32(child, "max-microamp", &val)) | ||
| 463 | return -EINVAL; | ||
| 464 | pd->max_indicator_intensity = val; | ||
| 465 | |||
| 466 | if (!of_find_property(node, "gpios", NULL)) { | ||
| 467 | dev_err(&client->dev, "No gpio node\n"); | ||
| 468 | return -EINVAL; | ||
| 469 | } | ||
| 470 | |||
| 471 | pd->power_gpio = of_get_gpio_flags(node, 0, &flags); | ||
| 472 | if (pd->power_gpio < 0) { | ||
| 473 | dev_err(&client->dev, "Error getting GPIO\n"); | ||
| 474 | return -EINVAL; | ||
| 475 | } | ||
| 476 | |||
| 477 | return 0; | ||
| 478 | } | ||
| 479 | |||
| 480 | |||
| 410 | static int adp1653_probe(struct i2c_client *client, | 481 | static int adp1653_probe(struct i2c_client *client, |
| 411 | const struct i2c_device_id *devid) | 482 | const struct i2c_device_id *devid) |
| 412 | { | 483 | { |
| 413 | struct adp1653_flash *flash; | 484 | struct adp1653_flash *flash; |
| 414 | int ret; | 485 | int ret; |
| 415 | 486 | ||
| 416 | /* we couldn't work without platform data */ | ||
| 417 | if (client->dev.platform_data == NULL) | ||
| 418 | return -ENODEV; | ||
| 419 | |||
| 420 | flash = devm_kzalloc(&client->dev, sizeof(*flash), GFP_KERNEL); | 487 | flash = devm_kzalloc(&client->dev, sizeof(*flash), GFP_KERNEL); |
| 421 | if (flash == NULL) | 488 | if (flash == NULL) |
| 422 | return -ENOMEM; | 489 | return -ENOMEM; |
| 423 | 490 | ||
| 424 | flash->platform_data = client->dev.platform_data; | 491 | flash->platform_data = client->dev.platform_data; |
| 492 | if (!flash->platform_data) { | ||
| 493 | ret = adp1653_of_init(client, flash, client->dev.of_node); | ||
| 494 | if (ret) | ||
| 495 | return ret; | ||
| 496 | } | ||
| 425 | 497 | ||
| 426 | mutex_init(&flash->power_lock); | 498 | mutex_init(&flash->power_lock); |
| 427 | 499 | ||
| @@ -438,10 +510,10 @@ static int adp1653_probe(struct i2c_client *client, | |||
| 438 | goto free_and_quit; | 510 | goto free_and_quit; |
| 439 | 511 | ||
| 440 | flash->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH; | 512 | flash->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH; |
| 441 | |||
| 442 | return 0; | 513 | return 0; |
| 443 | 514 | ||
| 444 | free_and_quit: | 515 | free_and_quit: |
| 516 | dev_err(&client->dev, "adp1653: failed to register device\n"); | ||
| 445 | v4l2_ctrl_handler_free(&flash->ctrls); | 517 | v4l2_ctrl_handler_free(&flash->ctrls); |
| 446 | return ret; | 518 | return ret; |
| 447 | } | 519 | } |
| @@ -464,7 +536,7 @@ static const struct i2c_device_id adp1653_id_table[] = { | |||
| 464 | }; | 536 | }; |
| 465 | MODULE_DEVICE_TABLE(i2c, adp1653_id_table); | 537 | MODULE_DEVICE_TABLE(i2c, adp1653_id_table); |
| 466 | 538 | ||
| 467 | static struct dev_pm_ops adp1653_pm_ops = { | 539 | static const struct dev_pm_ops adp1653_pm_ops = { |
| 468 | .suspend = adp1653_suspend, | 540 | .suspend = adp1653_suspend, |
| 469 | .resume = adp1653_resume, | 541 | .resume = adp1653_resume, |
| 470 | }; | 542 | }; |
