aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/sdhci-of.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host/sdhci-of.c')
-rw-r--r--drivers/mmc/host/sdhci-of.c49
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
26struct sdhci_of_data { 27struct 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
51static u32 esdhc_readl(struct sdhci_host *host, int reg) 54static 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
115static void esdhc_set_clock(struct sdhci_host *host, unsigned int clock) 122static 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
168static 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
175static struct sdhci_of_data sdhci_esdhc = { 173static 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
219static 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
222static int __devinit sdhci_of_probe(struct of_device *ofdev, 228static 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;