aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/plat-mxc/include/mach/esdhc.h10
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c52
2 files changed, 50 insertions, 12 deletions
diff --git a/arch/arm/plat-mxc/include/mach/esdhc.h b/arch/arm/plat-mxc/include/mach/esdhc.h
index a48a9aaa56b1..47da109ce09b 100644
--- a/arch/arm/plat-mxc/include/mach/esdhc.h
+++ b/arch/arm/plat-mxc/include/mach/esdhc.h
@@ -10,7 +10,15 @@
10#ifndef __ASM_ARCH_IMX_ESDHC_H 10#ifndef __ASM_ARCH_IMX_ESDHC_H
11#define __ASM_ARCH_IMX_ESDHC_H 11#define __ASM_ARCH_IMX_ESDHC_H
12 12
13/**
14 * struct esdhc_platform_data - optional platform data for esdhc on i.MX
15 *
16 * strongly recommended for i.MX25/35, not needed for other variants
17 *
18 * @wp_gpio: gpio for write_protect (-EINVAL if unused)
19 */
20
13struct esdhc_platform_data { 21struct esdhc_platform_data {
14 unsigned int wp_gpio; /* write protect pin */ 22 unsigned int wp_gpio;
15}; 23};
16#endif /* __ASM_ARCH_IMX_ESDHC_H */ 24#endif /* __ASM_ARCH_IMX_ESDHC_H */
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 9b82910b9dbb..65df00bb00dd 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
105static 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
115static 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
103static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pdata) 124static 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
126static void esdhc_pltfm_exit(struct sdhci_host *host) 161static 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
134static 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
143struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { 173struct 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 */