diff options
Diffstat (limited to 'drivers/mmc/host/sdhci-of.c')
-rw-r--r-- | drivers/mmc/host/sdhci-of.c | 49 |
1 files changed, 29 insertions, 20 deletions
diff --git a/drivers/mmc/host/sdhci-of.c b/drivers/mmc/host/sdhci-of.c index 1e8aa590bb39..01ab916c2802 100644 --- a/drivers/mmc/host/sdhci-of.c +++ b/drivers/mmc/host/sdhci-of.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/of.h> | 21 | #include <linux/of.h> |
22 | #include <linux/of_platform.h> | 22 | #include <linux/of_platform.h> |
23 | #include <linux/mmc/host.h> | 23 | #include <linux/mmc/host.h> |
24 | #include <asm/machdep.h> | ||
24 | #include "sdhci.h" | 25 | #include "sdhci.h" |
25 | 26 | ||
26 | struct sdhci_of_data { | 27 | struct sdhci_of_data { |
@@ -48,6 +49,8 @@ struct sdhci_of_host { | |||
48 | #define ESDHC_CLOCK_HCKEN 0x00000002 | 49 | #define ESDHC_CLOCK_HCKEN 0x00000002 |
49 | #define ESDHC_CLOCK_IPGEN 0x00000001 | 50 | #define ESDHC_CLOCK_IPGEN 0x00000001 |
50 | 51 | ||
52 | #define ESDHC_HOST_CONTROL_RES 0x05 | ||
53 | |||
51 | static u32 esdhc_readl(struct sdhci_host *host, int reg) | 54 | static u32 esdhc_readl(struct sdhci_host *host, int reg) |
52 | { | 55 | { |
53 | return in_be32(host->ioaddr + reg); | 56 | return in_be32(host->ioaddr + reg); |
@@ -109,13 +112,17 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg) | |||
109 | int base = reg & ~0x3; | 112 | int base = reg & ~0x3; |
110 | int shift = (reg & 0x3) * 8; | 113 | int shift = (reg & 0x3) * 8; |
111 | 114 | ||
115 | /* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */ | ||
116 | if (reg == SDHCI_HOST_CONTROL) | ||
117 | val &= ~ESDHC_HOST_CONTROL_RES; | ||
118 | |||
112 | clrsetbits_be32(host->ioaddr + base , 0xff << shift, val << shift); | 119 | clrsetbits_be32(host->ioaddr + base , 0xff << shift, val << shift); |
113 | } | 120 | } |
114 | 121 | ||
115 | static void esdhc_set_clock(struct sdhci_host *host, unsigned int clock) | 122 | static void esdhc_set_clock(struct sdhci_host *host, unsigned int clock) |
116 | { | 123 | { |
117 | int div; | ||
118 | int pre_div = 2; | 124 | int pre_div = 2; |
125 | int div = 1; | ||
119 | 126 | ||
120 | clrbits32(host->ioaddr + ESDHC_SYSTEM_CONTROL, ESDHC_CLOCK_IPGEN | | 127 | clrbits32(host->ioaddr + ESDHC_SYSTEM_CONTROL, ESDHC_CLOCK_IPGEN | |
121 | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK); | 128 | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK); |
@@ -123,19 +130,17 @@ static void esdhc_set_clock(struct sdhci_host *host, unsigned int clock) | |||
123 | if (clock == 0) | 130 | if (clock == 0) |
124 | goto out; | 131 | goto out; |
125 | 132 | ||
126 | if (host->max_clk / 16 > clock) { | 133 | while (host->max_clk / pre_div / 16 > clock && pre_div < 256) |
127 | for (; pre_div < 256; pre_div *= 2) { | 134 | pre_div *= 2; |
128 | if (host->max_clk / pre_div < clock * 16) | ||
129 | break; | ||
130 | } | ||
131 | } | ||
132 | 135 | ||
133 | for (div = 1; div <= 16; div++) { | 136 | while (host->max_clk / pre_div / div > clock && div < 16) |
134 | if (host->max_clk / (div * pre_div) <= clock) | 137 | div++; |
135 | break; | 138 | |
136 | } | 139 | dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n", |
140 | clock, host->max_clk / pre_div / div); | ||
137 | 141 | ||
138 | pre_div >>= 1; | 142 | pre_div >>= 1; |
143 | div--; | ||
139 | 144 | ||
140 | setbits32(host->ioaddr + ESDHC_SYSTEM_CONTROL, ESDHC_CLOCK_IPGEN | | 145 | setbits32(host->ioaddr + ESDHC_SYSTEM_CONTROL, ESDHC_CLOCK_IPGEN | |
141 | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN | | 146 | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN | |
@@ -165,19 +170,12 @@ static unsigned int esdhc_get_min_clock(struct sdhci_host *host) | |||
165 | return of_host->clock / 256 / 16; | 170 | return of_host->clock / 256 / 16; |
166 | } | 171 | } |
167 | 172 | ||
168 | static unsigned int esdhc_get_timeout_clock(struct sdhci_host *host) | ||
169 | { | ||
170 | struct sdhci_of_host *of_host = sdhci_priv(host); | ||
171 | |||
172 | return of_host->clock / 1000; | ||
173 | } | ||
174 | |||
175 | static struct sdhci_of_data sdhci_esdhc = { | 173 | static struct sdhci_of_data sdhci_esdhc = { |
176 | .quirks = SDHCI_QUIRK_FORCE_BLK_SZ_2048 | | 174 | .quirks = SDHCI_QUIRK_FORCE_BLK_SZ_2048 | |
177 | SDHCI_QUIRK_BROKEN_CARD_DETECTION | | 175 | SDHCI_QUIRK_BROKEN_CARD_DETECTION | |
178 | SDHCI_QUIRK_INVERTED_WRITE_PROTECT | | ||
179 | SDHCI_QUIRK_NO_BUSY_IRQ | | 176 | SDHCI_QUIRK_NO_BUSY_IRQ | |
180 | SDHCI_QUIRK_NONSTANDARD_CLOCK | | 177 | SDHCI_QUIRK_NONSTANDARD_CLOCK | |
178 | SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | | ||
181 | SDHCI_QUIRK_PIO_NEEDS_DELAY | | 179 | SDHCI_QUIRK_PIO_NEEDS_DELAY | |
182 | SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET | | 180 | SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET | |
183 | SDHCI_QUIRK_NO_CARD_NO_RESET, | 181 | SDHCI_QUIRK_NO_CARD_NO_RESET, |
@@ -192,7 +190,6 @@ static struct sdhci_of_data sdhci_esdhc = { | |||
192 | .enable_dma = esdhc_enable_dma, | 190 | .enable_dma = esdhc_enable_dma, |
193 | .get_max_clock = esdhc_get_max_clock, | 191 | .get_max_clock = esdhc_get_max_clock, |
194 | .get_min_clock = esdhc_get_min_clock, | 192 | .get_min_clock = esdhc_get_min_clock, |
195 | .get_timeout_clock = esdhc_get_timeout_clock, | ||
196 | }, | 193 | }, |
197 | }; | 194 | }; |
198 | 195 | ||
@@ -219,6 +216,15 @@ static int sdhci_of_resume(struct of_device *ofdev) | |||
219 | 216 | ||
220 | #endif | 217 | #endif |
221 | 218 | ||
219 | static bool __devinit sdhci_of_wp_inverted(struct device_node *np) | ||
220 | { | ||
221 | if (of_get_property(np, "sdhci,wp-inverted", NULL)) | ||
222 | return true; | ||
223 | |||
224 | /* Old device trees don't have the wp-inverted property. */ | ||
225 | return machine_is(mpc837x_rdb) || machine_is(mpc837x_mds); | ||
226 | } | ||
227 | |||
222 | static int __devinit sdhci_of_probe(struct of_device *ofdev, | 228 | static int __devinit sdhci_of_probe(struct of_device *ofdev, |
223 | const struct of_device_id *match) | 229 | const struct of_device_id *match) |
224 | { | 230 | { |
@@ -261,6 +267,9 @@ static int __devinit sdhci_of_probe(struct of_device *ofdev, | |||
261 | if (of_get_property(np, "sdhci,1-bit-only", NULL)) | 267 | if (of_get_property(np, "sdhci,1-bit-only", NULL)) |
262 | host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA; | 268 | host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA; |
263 | 269 | ||
270 | if (sdhci_of_wp_inverted(np)) | ||
271 | host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT; | ||
272 | |||
264 | clk = of_get_property(np, "clock-frequency", &size); | 273 | clk = of_get_property(np, "clock-frequency", &size); |
265 | if (clk && size == sizeof(*clk) && *clk) | 274 | if (clk && size == sizeof(*clk) && *clk) |
266 | of_host->clock = *clk; | 275 | of_host->clock = *clk; |