diff options
Diffstat (limited to 'drivers/mmc/host/pxamci.c')
-rw-r--r-- | drivers/mmc/host/pxamci.c | 104 |
1 files changed, 93 insertions, 11 deletions
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index e55ac792d68c..5e0b1529964d 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 | ||
@@ -725,20 +804,20 @@ static int pxamci_remove(struct platform_device *pdev) | |||
725 | } | 804 | } |
726 | 805 | ||
727 | #ifdef CONFIG_PM | 806 | #ifdef CONFIG_PM |
728 | static int pxamci_suspend(struct platform_device *dev, pm_message_t state) | 807 | static int pxamci_suspend(struct device *dev) |
729 | { | 808 | { |
730 | struct mmc_host *mmc = platform_get_drvdata(dev); | 809 | struct mmc_host *mmc = dev_get_drvdata(dev); |
731 | int ret = 0; | 810 | int ret = 0; |
732 | 811 | ||
733 | if (mmc) | 812 | if (mmc) |
734 | ret = mmc_suspend_host(mmc, state); | 813 | ret = mmc_suspend_host(mmc, PMSG_SUSPEND); |
735 | 814 | ||
736 | return ret; | 815 | return ret; |
737 | } | 816 | } |
738 | 817 | ||
739 | static int pxamci_resume(struct platform_device *dev) | 818 | static int pxamci_resume(struct device *dev) |
740 | { | 819 | { |
741 | struct mmc_host *mmc = platform_get_drvdata(dev); | 820 | struct mmc_host *mmc = dev_get_drvdata(dev); |
742 | int ret = 0; | 821 | int ret = 0; |
743 | 822 | ||
744 | if (mmc) | 823 | if (mmc) |
@@ -746,19 +825,22 @@ static int pxamci_resume(struct platform_device *dev) | |||
746 | 825 | ||
747 | return ret; | 826 | return ret; |
748 | } | 827 | } |
749 | #else | 828 | |
750 | #define pxamci_suspend NULL | 829 | static struct dev_pm_ops pxamci_pm_ops = { |
751 | #define pxamci_resume NULL | 830 | .suspend = pxamci_suspend, |
831 | .resume = pxamci_resume, | ||
832 | }; | ||
752 | #endif | 833 | #endif |
753 | 834 | ||
754 | static struct platform_driver pxamci_driver = { | 835 | static struct platform_driver pxamci_driver = { |
755 | .probe = pxamci_probe, | 836 | .probe = pxamci_probe, |
756 | .remove = pxamci_remove, | 837 | .remove = pxamci_remove, |
757 | .suspend = pxamci_suspend, | ||
758 | .resume = pxamci_resume, | ||
759 | .driver = { | 838 | .driver = { |
760 | .name = DRIVER_NAME, | 839 | .name = DRIVER_NAME, |
761 | .owner = THIS_MODULE, | 840 | .owner = THIS_MODULE, |
841 | #ifdef CONFIG_PM | ||
842 | .pm = &pxamci_pm_ops, | ||
843 | #endif | ||
762 | }, | 844 | }, |
763 | }; | 845 | }; |
764 | 846 | ||