diff options
author | Wolfram Sang <w.sang@pengutronix.de> | 2011-02-26 08:44:39 -0500 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2011-03-17 15:35:00 -0400 |
commit | 0c6d49ce53bc18c0ac637fb137f1e01ee9082201 (patch) | |
tree | dd7228fc94fbf638e57ec31352805eb0b2bde95a /drivers/mmc | |
parent | dffc55adfa2676a02a838d56a0cc4edd3809510c (diff) |
mmc: sdhci-esdhc-imx: add write protect on custom GPIO on mx25/35
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
Tested-by: Marc Reilly <marc@cpdesign.com.au>
Tested-by: Eric Benard <eric@eukrea.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/host/sdhci-esdhc-imx.c | 52 |
1 files changed, 41 insertions, 11 deletions
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 9b82910b9db..65df00bb00d 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c | |||
@@ -15,9 +15,11 @@ | |||
15 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
16 | #include <linux/err.h> | 16 | #include <linux/err.h> |
17 | #include <linux/clk.h> | 17 | #include <linux/clk.h> |
18 | #include <linux/gpio.h> | ||
18 | #include <linux/mmc/host.h> | 19 | #include <linux/mmc/host.h> |
19 | #include <linux/mmc/sdhci-pltfm.h> | 20 | #include <linux/mmc/sdhci-pltfm.h> |
20 | #include <mach/hardware.h> | 21 | #include <mach/hardware.h> |
22 | #include <mach/esdhc.h> | ||
21 | #include "sdhci.h" | 23 | #include "sdhci.h" |
22 | #include "sdhci-pltfm.h" | 24 | #include "sdhci-pltfm.h" |
23 | #include "sdhci-esdhc.h" | 25 | #include "sdhci-esdhc.h" |
@@ -100,10 +102,31 @@ static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host) | |||
100 | return clk_get_rate(pltfm_host->clk) / 256 / 16; | 102 | return clk_get_rate(pltfm_host->clk) / 256 / 16; |
101 | } | 103 | } |
102 | 104 | ||
105 | static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) | ||
106 | { | ||
107 | struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data; | ||
108 | |||
109 | if (boarddata && gpio_is_valid(boarddata->wp_gpio)) | ||
110 | return gpio_get_value(boarddata->wp_gpio); | ||
111 | else | ||
112 | return -ENOSYS; | ||
113 | } | ||
114 | |||
115 | static struct sdhci_ops sdhci_esdhc_ops = { | ||
116 | .read_w = esdhc_readw_le, | ||
117 | .write_w = esdhc_writew_le, | ||
118 | .write_b = esdhc_writeb_le, | ||
119 | .set_clock = esdhc_set_clock, | ||
120 | .get_max_clock = esdhc_pltfm_get_max_clock, | ||
121 | .get_min_clock = esdhc_pltfm_get_min_clock, | ||
122 | }; | ||
123 | |||
103 | static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pdata) | 124 | static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pdata) |
104 | { | 125 | { |
105 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | 126 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
127 | struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data; | ||
106 | struct clk *clk; | 128 | struct clk *clk; |
129 | int err; | ||
107 | 130 | ||
108 | clk = clk_get(mmc_dev(host->mmc), NULL); | 131 | clk = clk_get(mmc_dev(host->mmc), NULL); |
109 | if (IS_ERR(clk)) { | 132 | if (IS_ERR(clk)) { |
@@ -116,9 +139,21 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd | |||
116 | if (cpu_is_mx35() || cpu_is_mx51()) | 139 | if (cpu_is_mx35() || cpu_is_mx51()) |
117 | host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; | 140 | host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; |
118 | 141 | ||
119 | /* Fix errata ENGcm07207 which is present on i.MX25 and i.MX35 */ | 142 | if (cpu_is_mx25() || cpu_is_mx35()) { |
120 | if (cpu_is_mx25() || cpu_is_mx35()) | 143 | /* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */ |
121 | host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK; | 144 | host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK; |
145 | /* write_protect can't be routed to controller, use gpio */ | ||
146 | sdhci_esdhc_ops.get_ro = esdhc_pltfm_get_ro; | ||
147 | } | ||
148 | |||
149 | if (boarddata) { | ||
150 | err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP"); | ||
151 | if (err) { | ||
152 | dev_warn(mmc_dev(host->mmc), | ||
153 | "no write-protect pin available!\n"); | ||
154 | boarddata->wp_gpio = err; | ||
155 | } | ||
156 | } | ||
122 | 157 | ||
123 | return 0; | 158 | return 0; |
124 | } | 159 | } |
@@ -126,20 +161,15 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd | |||
126 | static void esdhc_pltfm_exit(struct sdhci_host *host) | 161 | static void esdhc_pltfm_exit(struct sdhci_host *host) |
127 | { | 162 | { |
128 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | 163 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
164 | struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data; | ||
165 | |||
166 | if (boarddata && gpio_is_valid(boarddata->wp_gpio)) | ||
167 | gpio_free(boarddata->wp_gpio); | ||
129 | 168 | ||
130 | clk_disable(pltfm_host->clk); | 169 | clk_disable(pltfm_host->clk); |
131 | clk_put(pltfm_host->clk); | 170 | clk_put(pltfm_host->clk); |
132 | } | 171 | } |
133 | 172 | ||
134 | static struct sdhci_ops sdhci_esdhc_ops = { | ||
135 | .read_w = esdhc_readw_le, | ||
136 | .write_w = esdhc_writew_le, | ||
137 | .write_b = esdhc_writeb_le, | ||
138 | .set_clock = esdhc_set_clock, | ||
139 | .get_max_clock = esdhc_pltfm_get_max_clock, | ||
140 | .get_min_clock = esdhc_pltfm_get_min_clock, | ||
141 | }; | ||
142 | |||
143 | struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { | 173 | struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { |
144 | .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA, | 174 | .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA, |
145 | /* ADMA has issues. Might be fixable */ | 175 | /* ADMA has issues. Might be fixable */ |