diff options
| author | Robert Jarzmik <robert.jarzmik@free.fr> | 2009-06-23 17:21:03 -0400 |
|---|---|---|
| committer | Eric Miao <eric.y.miao@gmail.com> | 2009-09-10 06:49:29 -0400 |
| commit | b405db6c015fe8e4c9d8199a0355bb16d95d7049 (patch) | |
| tree | 691c77f067e550deb36e973952144ed3378bc2b9 | |
| parent | 53eff4175f1eb25f97425b1526774fecb81444d4 (diff) | |
[ARM] pxamci: add simple gpio controls
The MMC block needs 3 external datas to work :
- is the MMC card put in "read-only mode" ?
- is a MMC card inserted or removed ?
- enable power towards the MMC card
Several platforms provide these controls through
gpios. Expand the platform_data to request and use these
gpios is set up by board code.
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
Acked-by: Pierre.Ossman <pierre@ossman.eu>
Signed-off-by: Eric Miao <eric.y.miao@gmail.com>
| -rw-r--r-- | arch/arm/mach-pxa/include/mach/mmc.h | 5 | ||||
| -rw-r--r-- | drivers/mmc/host/pxamci.c | 81 |
2 files changed, 85 insertions, 1 deletions
diff --git a/arch/arm/mach-pxa/include/mach/mmc.h b/arch/arm/mach-pxa/include/mach/mmc.h index 6d1304c9270f..02a69dc2ee63 100644 --- a/arch/arm/mach-pxa/include/mach/mmc.h +++ b/arch/arm/mach-pxa/include/mach/mmc.h | |||
| @@ -14,6 +14,11 @@ struct pxamci_platform_data { | |||
| 14 | int (*get_ro)(struct device *); | 14 | int (*get_ro)(struct device *); |
| 15 | void (*setpower)(struct device *, unsigned int); | 15 | void (*setpower)(struct device *, unsigned int); |
| 16 | void (*exit)(struct device *, void *); | 16 | void (*exit)(struct device *, void *); |
| 17 | int gpio_card_detect; /* gpio detecting card insertion */ | ||
| 18 | int gpio_card_ro; /* gpio detecting read only toggle */ | ||
| 19 | bool gpio_card_ro_invert; /* gpio ro is inverted */ | ||
| 20 | int gpio_power; /* gpio powering up MMC bus */ | ||
| 21 | bool gpio_power_invert; /* gpio power is inverted */ | ||
| 17 | }; | 22 | }; |
| 18 | 23 | ||
| 19 | extern void pxa_set_mci_info(struct pxamci_platform_data *info); | 24 | extern void pxa_set_mci_info(struct pxamci_platform_data *info); |
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index e55ac792d68c..972efa8d2c8e 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | #include <linux/mmc/host.h> | 28 | #include <linux/mmc/host.h> |
| 29 | #include <linux/io.h> | 29 | #include <linux/io.h> |
| 30 | #include <linux/regulator/consumer.h> | 30 | #include <linux/regulator/consumer.h> |
| 31 | #include <linux/gpio.h> | ||
| 31 | 32 | ||
| 32 | #include <asm/sizes.h> | 33 | #include <asm/sizes.h> |
| 33 | 34 | ||
| @@ -96,10 +97,18 @@ static inline void pxamci_init_ocr(struct pxamci_host *host) | |||
| 96 | 97 | ||
| 97 | static inline void pxamci_set_power(struct pxamci_host *host, unsigned int vdd) | 98 | static inline void pxamci_set_power(struct pxamci_host *host, unsigned int vdd) |
| 98 | { | 99 | { |
| 100 | int on; | ||
| 101 | |||
| 99 | #ifdef CONFIG_REGULATOR | 102 | #ifdef CONFIG_REGULATOR |
| 100 | if (host->vcc) | 103 | if (host->vcc) |
| 101 | mmc_regulator_set_ocr(host->vcc, vdd); | 104 | mmc_regulator_set_ocr(host->vcc, vdd); |
| 102 | #endif | 105 | #endif |
| 106 | if (!host->vcc && host->pdata && | ||
| 107 | gpio_is_valid(host->pdata->gpio_power)) { | ||
| 108 | on = ((1 << vdd) & host->pdata->ocr_mask); | ||
| 109 | gpio_set_value(host->pdata->gpio_power, | ||
| 110 | !!on ^ host->pdata->gpio_power_invert); | ||
| 111 | } | ||
| 103 | if (!host->vcc && host->pdata && host->pdata->setpower) | 112 | if (!host->vcc && host->pdata && host->pdata->setpower) |
| 104 | host->pdata->setpower(mmc_dev(host->mmc), vdd); | 113 | host->pdata->setpower(mmc_dev(host->mmc), vdd); |
| 105 | } | 114 | } |
| @@ -421,6 +430,12 @@ static int pxamci_get_ro(struct mmc_host *mmc) | |||
| 421 | { | 430 | { |
| 422 | struct pxamci_host *host = mmc_priv(mmc); | 431 | struct pxamci_host *host = mmc_priv(mmc); |
| 423 | 432 | ||
| 433 | if (host->pdata && gpio_is_valid(host->pdata->gpio_card_ro)) { | ||
| 434 | if (host->pdata->gpio_card_ro_invert) | ||
| 435 | return !gpio_get_value(host->pdata->gpio_card_ro); | ||
| 436 | else | ||
| 437 | return gpio_get_value(host->pdata->gpio_card_ro); | ||
| 438 | } | ||
| 424 | if (host->pdata && host->pdata->get_ro) | 439 | if (host->pdata && host->pdata->get_ro) |
| 425 | return !!host->pdata->get_ro(mmc_dev(mmc)); | 440 | return !!host->pdata->get_ro(mmc_dev(mmc)); |
| 426 | /* | 441 | /* |
| @@ -534,7 +549,7 @@ static int pxamci_probe(struct platform_device *pdev) | |||
| 534 | struct mmc_host *mmc; | 549 | struct mmc_host *mmc; |
| 535 | struct pxamci_host *host = NULL; | 550 | struct pxamci_host *host = NULL; |
| 536 | struct resource *r, *dmarx, *dmatx; | 551 | struct resource *r, *dmarx, *dmatx; |
| 537 | int ret, irq; | 552 | int ret, irq, gpio_cd = -1, gpio_ro = -1, gpio_power = -1; |
| 538 | 553 | ||
| 539 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 554 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 540 | irq = platform_get_irq(pdev, 0); | 555 | irq = platform_get_irq(pdev, 0); |
| @@ -661,13 +676,63 @@ static int pxamci_probe(struct platform_device *pdev) | |||
| 661 | } | 676 | } |
| 662 | host->dma_drcmrtx = dmatx->start; | 677 | host->dma_drcmrtx = dmatx->start; |
| 663 | 678 | ||
| 679 | if (host->pdata) { | ||
| 680 | gpio_cd = host->pdata->gpio_card_detect; | ||
| 681 | gpio_ro = host->pdata->gpio_card_ro; | ||
| 682 | gpio_power = host->pdata->gpio_power; | ||
| 683 | } | ||
| 684 | if (gpio_is_valid(gpio_power)) { | ||
| 685 | ret = gpio_request(gpio_power, "mmc card power"); | ||
| 686 | if (ret) { | ||
| 687 | dev_err(&pdev->dev, "Failed requesting gpio_power %d\n", gpio_power); | ||
| 688 | goto out; | ||
| 689 | } | ||
| 690 | gpio_direction_output(gpio_power, | ||
| 691 | host->pdata->gpio_power_invert); | ||
| 692 | } | ||
| 693 | if (gpio_is_valid(gpio_ro)) { | ||
| 694 | ret = gpio_request(gpio_ro, "mmc card read only"); | ||
| 695 | if (ret) { | ||
| 696 | dev_err(&pdev->dev, "Failed requesting gpio_ro %d\n", gpio_power); | ||
| 697 | goto err_gpio_ro; | ||
| 698 | } | ||
| 699 | gpio_direction_input(gpio_ro); | ||
| 700 | } | ||
| 701 | if (gpio_is_valid(gpio_cd)) { | ||
| 702 | ret = gpio_request(gpio_cd, "mmc card detect"); | ||
| 703 | if (ret) { | ||
| 704 | dev_err(&pdev->dev, "Failed requesting gpio_cd %d\n", gpio_power); | ||
| 705 | goto err_gpio_cd; | ||
| 706 | } | ||
| 707 | gpio_direction_input(gpio_cd); | ||
| 708 | |||
| 709 | ret = request_irq(gpio_to_irq(gpio_cd), pxamci_detect_irq, | ||
| 710 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, | ||
| 711 | "mmc card detect", mmc); | ||
| 712 | if (ret) { | ||
| 713 | dev_err(&pdev->dev, "failed to request card detect IRQ\n"); | ||
| 714 | goto err_request_irq; | ||
| 715 | } | ||
| 716 | } | ||
| 717 | |||
| 664 | if (host->pdata && host->pdata->init) | 718 | if (host->pdata && host->pdata->init) |
| 665 | host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc); | 719 | host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc); |
| 666 | 720 | ||
| 721 | if (gpio_is_valid(gpio_power) && host->pdata->setpower) | ||
| 722 | dev_warn(&pdev->dev, "gpio_power and setpower() both defined\n"); | ||
| 723 | if (gpio_is_valid(gpio_ro) && host->pdata->get_ro) | ||
| 724 | dev_warn(&pdev->dev, "gpio_ro and get_ro() both defined\n"); | ||
| 725 | |||
| 667 | mmc_add_host(mmc); | 726 | mmc_add_host(mmc); |
| 668 | 727 | ||
| 669 | return 0; | 728 | return 0; |
| 670 | 729 | ||
| 730 | err_request_irq: | ||
| 731 | gpio_free(gpio_cd); | ||
| 732 | err_gpio_cd: | ||
| 733 | gpio_free(gpio_ro); | ||
| 734 | err_gpio_ro: | ||
| 735 | gpio_free(gpio_power); | ||
| 671 | out: | 736 | out: |
| 672 | if (host) { | 737 | if (host) { |
| 673 | if (host->dma >= 0) | 738 | if (host->dma >= 0) |
| @@ -688,12 +753,26 @@ static int pxamci_probe(struct platform_device *pdev) | |||
| 688 | static int pxamci_remove(struct platform_device *pdev) | 753 | static int pxamci_remove(struct platform_device *pdev) |
| 689 | { | 754 | { |
| 690 | struct mmc_host *mmc = platform_get_drvdata(pdev); | 755 | struct mmc_host *mmc = platform_get_drvdata(pdev); |
| 756 | int gpio_cd = -1, gpio_ro = -1, gpio_power = -1; | ||
| 691 | 757 | ||
| 692 | platform_set_drvdata(pdev, NULL); | 758 | platform_set_drvdata(pdev, NULL); |
| 693 | 759 | ||
| 694 | if (mmc) { | 760 | if (mmc) { |
| 695 | struct pxamci_host *host = mmc_priv(mmc); | 761 | struct pxamci_host *host = mmc_priv(mmc); |
| 696 | 762 | ||
| 763 | if (host->pdata) { | ||
| 764 | gpio_cd = host->pdata->gpio_card_detect; | ||
| 765 | gpio_ro = host->pdata->gpio_card_ro; | ||
| 766 | gpio_power = host->pdata->gpio_power; | ||
| 767 | } | ||
| 768 | if (gpio_is_valid(gpio_cd)) { | ||
| 769 | free_irq(gpio_to_irq(gpio_cd), mmc); | ||
| 770 | gpio_free(gpio_cd); | ||
| 771 | } | ||
| 772 | if (gpio_is_valid(gpio_ro)) | ||
| 773 | gpio_free(gpio_ro); | ||
| 774 | if (gpio_is_valid(gpio_power)) | ||
| 775 | gpio_free(gpio_power); | ||
| 697 | if (host->vcc) | 776 | if (host->vcc) |
| 698 | regulator_put(host->vcc); | 777 | regulator_put(host->vcc); |
| 699 | 778 | ||
