diff options
author | Benoit Cousson <b-cousson@ti.com> | 2012-02-29 16:51:32 -0500 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2012-03-22 08:05:55 -0400 |
commit | b8589e2a8065b8e7773742b60ae96b63b757bb69 (patch) | |
tree | ad20ba6cc9205cbaf0e99c444cfca22e1e44db17 /drivers/gpio/gpio-twl4030.c | |
parent | 2d9dd99b4470a2ef05509435465e055f50456330 (diff) |
gpio/twl: Add DT support to gpio-twl4030 driver
Add the DT support for the I2C GPIO expander inside the twl4030.
Note: The pdata parameters still have to be properly adapted using
dedicated bindings.
Signed-off-by: Benoit Cousson <b-cousson@ti.com>
Acked-by: Felipe Balbi <balbi@ti.com>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/gpio/gpio-twl4030.c')
-rw-r--r-- | drivers/gpio/gpio-twl4030.c | 79 |
1 files changed, 50 insertions, 29 deletions
diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index 49e5c6eb403a..94256fe7bf36 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c | |||
@@ -32,6 +32,8 @@ | |||
32 | #include <linux/irq.h> | 32 | #include <linux/irq.h> |
33 | #include <linux/gpio.h> | 33 | #include <linux/gpio.h> |
34 | #include <linux/platform_device.h> | 34 | #include <linux/platform_device.h> |
35 | #include <linux/of.h> | ||
36 | #include <linux/irqdomain.h> | ||
35 | 37 | ||
36 | #include <linux/i2c/twl.h> | 38 | #include <linux/i2c/twl.h> |
37 | 39 | ||
@@ -256,7 +258,8 @@ static int twl_request(struct gpio_chip *chip, unsigned offset) | |||
256 | * and vMMC2 power supplies based on card presence. | 258 | * and vMMC2 power supplies based on card presence. |
257 | */ | 259 | */ |
258 | pdata = chip->dev->platform_data; | 260 | pdata = chip->dev->platform_data; |
259 | value |= pdata->mmc_cd & 0x03; | 261 | if (pdata) |
262 | value |= pdata->mmc_cd & 0x03; | ||
260 | 263 | ||
261 | status = gpio_twl4030_write(REG_GPIO_CTRL, value); | 264 | status = gpio_twl4030_write(REG_GPIO_CTRL, value); |
262 | } | 265 | } |
@@ -395,6 +398,7 @@ static int gpio_twl4030_remove(struct platform_device *pdev); | |||
395 | static int __devinit gpio_twl4030_probe(struct platform_device *pdev) | 398 | static int __devinit gpio_twl4030_probe(struct platform_device *pdev) |
396 | { | 399 | { |
397 | struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; | 400 | struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; |
401 | struct device_node *node = pdev->dev.of_node; | ||
398 | int ret, irq_base; | 402 | int ret, irq_base; |
399 | 403 | ||
400 | /* maybe setup IRQs */ | 404 | /* maybe setup IRQs */ |
@@ -409,6 +413,9 @@ static int __devinit gpio_twl4030_probe(struct platform_device *pdev) | |||
409 | return irq_base; | 413 | return irq_base; |
410 | } | 414 | } |
411 | 415 | ||
416 | irq_domain_add_legacy(node, TWL4030_GPIO_MAX, irq_base, 0, | ||
417 | &irq_domain_simple_ops, NULL); | ||
418 | |||
412 | ret = twl4030_sih_setup(&pdev->dev, TWL4030_MODULE_GPIO, irq_base); | 419 | ret = twl4030_sih_setup(&pdev->dev, TWL4030_MODULE_GPIO, irq_base); |
413 | if (ret < 0) | 420 | if (ret < 0) |
414 | return ret; | 421 | return ret; |
@@ -416,40 +423,45 @@ static int __devinit gpio_twl4030_probe(struct platform_device *pdev) | |||
416 | twl4030_gpio_irq_base = irq_base; | 423 | twl4030_gpio_irq_base = irq_base; |
417 | 424 | ||
418 | no_irqs: | 425 | no_irqs: |
419 | /* | 426 | twl_gpiochip.base = -1; |
420 | * NOTE: boards may waste power if they don't set pullups | ||
421 | * and pulldowns correctly ... default for non-ULPI pins is | ||
422 | * pulldown, and some other pins may have external pullups | ||
423 | * or pulldowns. Careful! | ||
424 | */ | ||
425 | ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns); | ||
426 | if (ret) | ||
427 | dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n", | ||
428 | pdata->pullups, pdata->pulldowns, | ||
429 | ret); | ||
430 | |||
431 | ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd); | ||
432 | if (ret) | ||
433 | dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n", | ||
434 | pdata->debounce, pdata->mmc_cd, | ||
435 | ret); | ||
436 | |||
437 | twl_gpiochip.base = pdata->gpio_base; | ||
438 | twl_gpiochip.ngpio = TWL4030_GPIO_MAX; | 427 | twl_gpiochip.ngpio = TWL4030_GPIO_MAX; |
439 | twl_gpiochip.dev = &pdev->dev; | 428 | twl_gpiochip.dev = &pdev->dev; |
440 | 429 | ||
441 | /* NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE, | 430 | if (pdata) { |
442 | * is (still) clear if use_leds is set. | 431 | twl_gpiochip.base = pdata->gpio_base; |
443 | */ | 432 | |
444 | if (pdata->use_leds) | 433 | /* |
445 | twl_gpiochip.ngpio += 2; | 434 | * NOTE: boards may waste power if they don't set pullups |
435 | * and pulldowns correctly ... default for non-ULPI pins is | ||
436 | * pulldown, and some other pins may have external pullups | ||
437 | * or pulldowns. Careful! | ||
438 | */ | ||
439 | ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns); | ||
440 | if (ret) | ||
441 | dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n", | ||
442 | pdata->pullups, pdata->pulldowns, | ||
443 | ret); | ||
444 | |||
445 | ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd); | ||
446 | if (ret) | ||
447 | dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n", | ||
448 | pdata->debounce, pdata->mmc_cd, | ||
449 | ret); | ||
450 | |||
451 | /* | ||
452 | * NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE, | ||
453 | * is (still) clear if use_leds is set. | ||
454 | */ | ||
455 | if (pdata->use_leds) | ||
456 | twl_gpiochip.ngpio += 2; | ||
457 | } | ||
446 | 458 | ||
447 | ret = gpiochip_add(&twl_gpiochip); | 459 | ret = gpiochip_add(&twl_gpiochip); |
448 | if (ret < 0) { | 460 | if (ret < 0) { |
449 | dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret); | 461 | dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret); |
450 | twl_gpiochip.ngpio = 0; | 462 | twl_gpiochip.ngpio = 0; |
451 | gpio_twl4030_remove(pdev); | 463 | gpio_twl4030_remove(pdev); |
452 | } else if (pdata->setup) { | 464 | } else if (pdata && pdata->setup) { |
453 | int status; | 465 | int status; |
454 | 466 | ||
455 | status = pdata->setup(&pdev->dev, | 467 | status = pdata->setup(&pdev->dev, |
@@ -467,7 +479,7 @@ static int gpio_twl4030_remove(struct platform_device *pdev) | |||
467 | struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; | 479 | struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; |
468 | int status; | 480 | int status; |
469 | 481 | ||
470 | if (pdata->teardown) { | 482 | if (pdata && pdata->teardown) { |
471 | status = pdata->teardown(&pdev->dev, | 483 | status = pdata->teardown(&pdev->dev, |
472 | pdata->gpio_base, TWL4030_GPIO_MAX); | 484 | pdata->gpio_base, TWL4030_GPIO_MAX); |
473 | if (status) { | 485 | if (status) { |
@@ -488,12 +500,21 @@ static int gpio_twl4030_remove(struct platform_device *pdev) | |||
488 | return -EIO; | 500 | return -EIO; |
489 | } | 501 | } |
490 | 502 | ||
503 | static const struct of_device_id twl_gpio_match[] = { | ||
504 | { .compatible = "ti,twl4030-gpio", }, | ||
505 | { }, | ||
506 | }; | ||
507 | MODULE_DEVICE_TABLE(of, twl_gpio_match); | ||
508 | |||
491 | /* Note: this hardware lives inside an I2C-based multi-function device. */ | 509 | /* Note: this hardware lives inside an I2C-based multi-function device. */ |
492 | MODULE_ALIAS("platform:twl4030_gpio"); | 510 | MODULE_ALIAS("platform:twl4030_gpio"); |
493 | 511 | ||
494 | static struct platform_driver gpio_twl4030_driver = { | 512 | static struct platform_driver gpio_twl4030_driver = { |
495 | .driver.name = "twl4030_gpio", | 513 | .driver = { |
496 | .driver.owner = THIS_MODULE, | 514 | .name = "twl4030_gpio", |
515 | .owner = THIS_MODULE, | ||
516 | .of_match_table = of_match_ptr(twl_gpio_match), | ||
517 | }, | ||
497 | .probe = gpio_twl4030_probe, | 518 | .probe = gpio_twl4030_probe, |
498 | .remove = gpio_twl4030_remove, | 519 | .remove = gpio_twl4030_remove, |
499 | }; | 520 | }; |