diff options
author | David Brownell <dbrownell@users.sourceforge.net> | 2008-02-04 12:12:48 -0500 |
---|---|---|
committer | Pierre Ossman <drzeus@drzeus.cx> | 2008-02-08 03:02:47 -0500 |
commit | 6e996ee8e730a50eef51cdb072b166fe8f80831e (patch) | |
tree | 5cbe1dfe5dd33dead44c9f02d21dd78fd5b39b7e | |
parent | 541ceb5b8b4a90f7862ef24e4058fce520247827 (diff) |
at91_mci: use generic GPIO calls
Update the AT91 MMC driver to use the generic GPIO calls instead of the
AT91-specific calls; and to request (and release) those GPIO signals.
That required updating the probe() fault cleanup codepaths. Now there
is a single sequence for freeing resources, in reverse order of their
allocation. Also that code uses use dev_*() for messaging, and has less
abuse of KERN_ERR.
Likewise with updating remove() cleanup. This had to free the GPIOs,
and while adding that code I noticed and fixed two other problems: it
was poking at a workqueue owned by the mmc core; and in one (rare)
case would try freeing an IRQ that it didn't allocate.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
-rw-r--r-- | drivers/mmc/host/at91_mci.c | 114 |
1 files changed, 80 insertions, 34 deletions
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index b1edcefdd4f..21acecc9fe3 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c | |||
@@ -70,10 +70,11 @@ | |||
70 | 70 | ||
71 | #include <asm/io.h> | 71 | #include <asm/io.h> |
72 | #include <asm/irq.h> | 72 | #include <asm/irq.h> |
73 | #include <asm/gpio.h> | ||
74 | |||
73 | #include <asm/mach/mmc.h> | 75 | #include <asm/mach/mmc.h> |
74 | #include <asm/arch/board.h> | 76 | #include <asm/arch/board.h> |
75 | #include <asm/arch/cpu.h> | 77 | #include <asm/arch/cpu.h> |
76 | #include <asm/arch/gpio.h> | ||
77 | #include <asm/arch/at91_mci.h> | 78 | #include <asm/arch/at91_mci.h> |
78 | 79 | ||
79 | #define DRIVER_NAME "at91_mci" | 80 | #define DRIVER_NAME "at91_mci" |
@@ -659,11 +660,11 @@ static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
659 | if (host->board->vcc_pin) { | 660 | if (host->board->vcc_pin) { |
660 | switch (ios->power_mode) { | 661 | switch (ios->power_mode) { |
661 | case MMC_POWER_OFF: | 662 | case MMC_POWER_OFF: |
662 | at91_set_gpio_value(host->board->vcc_pin, 0); | 663 | gpio_set_value(host->board->vcc_pin, 0); |
663 | break; | 664 | break; |
664 | case MMC_POWER_UP: | 665 | case MMC_POWER_UP: |
665 | case MMC_POWER_ON: | 666 | case MMC_POWER_ON: |
666 | at91_set_gpio_value(host->board->vcc_pin, 1); | 667 | gpio_set_value(host->board->vcc_pin, 1); |
667 | break; | 668 | break; |
668 | } | 669 | } |
669 | } | 670 | } |
@@ -768,7 +769,7 @@ static irqreturn_t at91_mci_irq(int irq, void *devid) | |||
768 | static irqreturn_t at91_mmc_det_irq(int irq, void *_host) | 769 | static irqreturn_t at91_mmc_det_irq(int irq, void *_host) |
769 | { | 770 | { |
770 | struct at91mci_host *host = _host; | 771 | struct at91mci_host *host = _host; |
771 | int present = !at91_get_gpio_value(irq); | 772 | int present = !gpio_get_value(irq_to_gpio(irq)); |
772 | 773 | ||
773 | /* | 774 | /* |
774 | * we expect this irq on both insert and remove, | 775 | * we expect this irq on both insert and remove, |
@@ -793,7 +794,7 @@ static int at91_mci_get_ro(struct mmc_host *mmc) | |||
793 | struct at91mci_host *host = mmc_priv(mmc); | 794 | struct at91mci_host *host = mmc_priv(mmc); |
794 | 795 | ||
795 | if (host->board->wp_pin) { | 796 | if (host->board->wp_pin) { |
796 | read_only = at91_get_gpio_value(host->board->wp_pin); | 797 | read_only = gpio_get_value(host->board->wp_pin); |
797 | printk(KERN_WARNING "%s: card is %s\n", mmc_hostname(mmc), | 798 | printk(KERN_WARNING "%s: card is %s\n", mmc_hostname(mmc), |
798 | (read_only ? "read-only" : "read-write") ); | 799 | (read_only ? "read-only" : "read-write") ); |
799 | } | 800 | } |
@@ -820,8 +821,6 @@ static int __init at91_mci_probe(struct platform_device *pdev) | |||
820 | struct resource *res; | 821 | struct resource *res; |
821 | int ret; | 822 | int ret; |
822 | 823 | ||
823 | pr_debug("Probe MCI devices\n"); | ||
824 | |||
825 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 824 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
826 | if (!res) | 825 | if (!res) |
827 | return -ENXIO; | 826 | return -ENXIO; |
@@ -831,9 +830,9 @@ static int __init at91_mci_probe(struct platform_device *pdev) | |||
831 | 830 | ||
832 | mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev); | 831 | mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev); |
833 | if (!mmc) { | 832 | if (!mmc) { |
834 | pr_debug("Failed to allocate mmc host\n"); | 833 | ret = -ENOMEM; |
835 | release_mem_region(res->start, res->end - res->start + 1); | 834 | dev_dbg(&pdev->dev, "couldn't allocate mmc host\n"); |
836 | return -ENOMEM; | 835 | goto fail6; |
837 | } | 836 | } |
838 | 837 | ||
839 | mmc->ops = &at91_mci_ops; | 838 | mmc->ops = &at91_mci_ops; |
@@ -853,19 +852,44 @@ static int __init at91_mci_probe(struct platform_device *pdev) | |||
853 | if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) | 852 | if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) |
854 | mmc->caps |= MMC_CAP_4_BIT_DATA; | 853 | mmc->caps |= MMC_CAP_4_BIT_DATA; |
855 | else | 854 | else |
856 | printk("AT91 MMC: 4 wire bus mode not supported" | 855 | dev_warn(&pdev->dev, "4 wire bus mode not supported" |
857 | " - using 1 wire\n"); | 856 | " - using 1 wire\n"); |
858 | } | 857 | } |
859 | 858 | ||
860 | /* | 859 | /* |
860 | * Reserve GPIOs ... board init code makes sure these pins are set | ||
861 | * up as GPIOs with the right direction (input, except for vcc) | ||
862 | */ | ||
863 | if (host->board->det_pin) { | ||
864 | ret = gpio_request(host->board->det_pin, "mmc_detect"); | ||
865 | if (ret < 0) { | ||
866 | dev_dbg(&pdev->dev, "couldn't claim card detect pin\n"); | ||
867 | goto fail5; | ||
868 | } | ||
869 | } | ||
870 | if (host->board->wp_pin) { | ||
871 | ret = gpio_request(host->board->wp_pin, "mmc_wp"); | ||
872 | if (ret < 0) { | ||
873 | dev_dbg(&pdev->dev, "couldn't claim wp sense pin\n"); | ||
874 | goto fail4; | ||
875 | } | ||
876 | } | ||
877 | if (host->board->vcc_pin) { | ||
878 | ret = gpio_request(host->board->vcc_pin, "mmc_vcc"); | ||
879 | if (ret < 0) { | ||
880 | dev_dbg(&pdev->dev, "couldn't claim vcc switch pin\n"); | ||
881 | goto fail3; | ||
882 | } | ||
883 | } | ||
884 | |||
885 | /* | ||
861 | * Get Clock | 886 | * Get Clock |
862 | */ | 887 | */ |
863 | host->mci_clk = clk_get(&pdev->dev, "mci_clk"); | 888 | host->mci_clk = clk_get(&pdev->dev, "mci_clk"); |
864 | if (IS_ERR(host->mci_clk)) { | 889 | if (IS_ERR(host->mci_clk)) { |
865 | printk(KERN_ERR "AT91 MMC: no clock defined.\n"); | 890 | ret = -ENODEV; |
866 | mmc_free_host(mmc); | 891 | dev_dbg(&pdev->dev, "no mci_clk?\n"); |
867 | release_mem_region(res->start, res->end - res->start + 1); | 892 | goto fail2; |
868 | return -ENODEV; | ||
869 | } | 893 | } |
870 | 894 | ||
871 | /* | 895 | /* |
@@ -873,10 +897,8 @@ static int __init at91_mci_probe(struct platform_device *pdev) | |||
873 | */ | 897 | */ |
874 | host->baseaddr = ioremap(res->start, res->end - res->start + 1); | 898 | host->baseaddr = ioremap(res->start, res->end - res->start + 1); |
875 | if (!host->baseaddr) { | 899 | if (!host->baseaddr) { |
876 | clk_put(host->mci_clk); | 900 | ret = -ENOMEM; |
877 | mmc_free_host(mmc); | 901 | goto fail1; |
878 | release_mem_region(res->start, res->end - res->start + 1); | ||
879 | return -ENOMEM; | ||
880 | } | 902 | } |
881 | 903 | ||
882 | /* | 904 | /* |
@@ -890,15 +912,11 @@ static int __init at91_mci_probe(struct platform_device *pdev) | |||
890 | * Allocate the MCI interrupt | 912 | * Allocate the MCI interrupt |
891 | */ | 913 | */ |
892 | host->irq = platform_get_irq(pdev, 0); | 914 | host->irq = platform_get_irq(pdev, 0); |
893 | ret = request_irq(host->irq, at91_mci_irq, IRQF_SHARED, DRIVER_NAME, host); | 915 | ret = request_irq(host->irq, at91_mci_irq, IRQF_SHARED, |
916 | mmc_hostname(mmc), host); | ||
894 | if (ret) { | 917 | if (ret) { |
895 | printk(KERN_ERR "AT91 MMC: Failed to request MCI interrupt\n"); | 918 | dev_dbg(&pdev->dev, "request MCI interrupt failed\n"); |
896 | clk_disable(host->mci_clk); | 919 | goto fail0; |
897 | clk_put(host->mci_clk); | ||
898 | mmc_free_host(mmc); | ||
899 | iounmap(host->baseaddr); | ||
900 | release_mem_region(res->start, res->end - res->start + 1); | ||
901 | return ret; | ||
902 | } | 920 | } |
903 | 921 | ||
904 | platform_set_drvdata(pdev, mmc); | 922 | platform_set_drvdata(pdev, mmc); |
@@ -907,8 +925,7 @@ static int __init at91_mci_probe(struct platform_device *pdev) | |||
907 | * Add host to MMC layer | 925 | * Add host to MMC layer |
908 | */ | 926 | */ |
909 | if (host->board->det_pin) { | 927 | if (host->board->det_pin) { |
910 | host->present = !at91_get_gpio_value(host->board->det_pin); | 928 | host->present = !gpio_get_value(host->board->det_pin); |
911 | device_init_wakeup(&pdev->dev, 1); | ||
912 | } | 929 | } |
913 | else | 930 | else |
914 | host->present = -1; | 931 | host->present = -1; |
@@ -919,15 +936,38 @@ static int __init at91_mci_probe(struct platform_device *pdev) | |||
919 | * monitor card insertion/removal if we can | 936 | * monitor card insertion/removal if we can |
920 | */ | 937 | */ |
921 | if (host->board->det_pin) { | 938 | if (host->board->det_pin) { |
922 | ret = request_irq(host->board->det_pin, at91_mmc_det_irq, | 939 | ret = request_irq(gpio_to_irq(host->board->det_pin), |
923 | 0, DRIVER_NAME, host); | 940 | at91_mmc_det_irq, 0, mmc_hostname(mmc), host); |
924 | if (ret) | 941 | if (ret) |
925 | printk(KERN_ERR "AT91 MMC: Couldn't allocate MMC detect irq\n"); | 942 | dev_warn(&pdev->dev, "request MMC detect irq failed\n"); |
943 | else | ||
944 | device_init_wakeup(&pdev->dev, 1); | ||
926 | } | 945 | } |
927 | 946 | ||
928 | pr_debug("Added MCI driver\n"); | 947 | pr_debug("Added MCI driver\n"); |
929 | 948 | ||
930 | return 0; | 949 | return 0; |
950 | |||
951 | fail0: | ||
952 | clk_disable(host->mci_clk); | ||
953 | iounmap(host->baseaddr); | ||
954 | fail1: | ||
955 | clk_put(host->mci_clk); | ||
956 | fail2: | ||
957 | if (host->board->vcc_pin) | ||
958 | gpio_free(host->board->vcc_pin); | ||
959 | fail3: | ||
960 | if (host->board->wp_pin) | ||
961 | gpio_free(host->board->wp_pin); | ||
962 | fail4: | ||
963 | if (host->board->det_pin) | ||
964 | gpio_free(host->board->det_pin); | ||
965 | fail5: | ||
966 | mmc_free_host(mmc); | ||
967 | fail6: | ||
968 | release_mem_region(res->start, res->end - res->start + 1); | ||
969 | dev_err(&pdev->dev, "probe failed, err %d\n", ret); | ||
970 | return ret; | ||
931 | } | 971 | } |
932 | 972 | ||
933 | /* | 973 | /* |
@@ -945,9 +985,10 @@ static int __exit at91_mci_remove(struct platform_device *pdev) | |||
945 | host = mmc_priv(mmc); | 985 | host = mmc_priv(mmc); |
946 | 986 | ||
947 | if (host->board->det_pin) { | 987 | if (host->board->det_pin) { |
988 | if (device_can_wakeup(&pdev->dev)) | ||
989 | free_irq(gpio_to_irq(host->board->det_pin), host); | ||
948 | device_init_wakeup(&pdev->dev, 0); | 990 | device_init_wakeup(&pdev->dev, 0); |
949 | free_irq(host->board->det_pin, host); | 991 | gpio_free(host->board->det_pin); |
950 | cancel_delayed_work(&host->mmc->detect); | ||
951 | } | 992 | } |
952 | 993 | ||
953 | at91_mci_disable(host); | 994 | at91_mci_disable(host); |
@@ -957,6 +998,11 @@ static int __exit at91_mci_remove(struct platform_device *pdev) | |||
957 | clk_disable(host->mci_clk); /* Disable the peripheral clock */ | 998 | clk_disable(host->mci_clk); /* Disable the peripheral clock */ |
958 | clk_put(host->mci_clk); | 999 | clk_put(host->mci_clk); |
959 | 1000 | ||
1001 | if (host->board->vcc_pin) | ||
1002 | gpio_free(host->board->vcc_pin); | ||
1003 | if (host->board->wp_pin) | ||
1004 | gpio_free(host->board->wp_pin); | ||
1005 | |||
960 | iounmap(host->baseaddr); | 1006 | iounmap(host->baseaddr); |
961 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1007 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
962 | release_mem_region(res->start, res->end - res->start + 1); | 1008 | release_mem_region(res->start, res->end - res->start + 1); |