aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2013-01-21 06:02:28 -0500
committerChris Ball <cjb@laptop.org>2013-02-24 14:37:03 -0500
commitaf51079e68d4759e458b0592df5d1fab373c43ae (patch)
tree937bb9166c549ab3ebfbdb19c8dc63e76f904584 /drivers/mmc
parent7bc088d38f92f58df97e1cd9a8430331ee5491bb (diff)
mmc: sdhci-esdhc-imx: support 8bit mode
The i.MX esdhc has a nonstandard bit layout for the SDHCI_HOST_CONTROL register. To support 8bit bus width on i.MX populate the platform_bus_width callback. This is tested on an i.MX25, but should according to the datasheets work on the other i.MX using this hardware aswell. The i.MX6, while having a SDHCI_SPEC_300 controller, still uses the same nonstandard register layout. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Signed-off-by: Shawn Guo <shawn.guo@linaro.org> Tested-by: Dirk Behme <dirk.behme@de.bosch.com> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c56
1 files changed, 54 insertions, 2 deletions
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 24daaf4e20ba..f7ee5e67516c 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -41,6 +41,13 @@
41#define ESDHC_MIX_CTRL_SDHCI_MASK 0xb7 41#define ESDHC_MIX_CTRL_SDHCI_MASK 0xb7
42 42
43/* 43/*
44 * Our interpretation of the SDHCI_HOST_CONTROL register
45 */
46#define ESDHC_CTRL_4BITBUS (0x1 << 1)
47#define ESDHC_CTRL_8BITBUS (0x2 << 1)
48#define ESDHC_CTRL_BUSWIDTH_MASK (0x3 << 1)
49
50/*
44 * There is an INT DMA ERR mis-match between eSDHC and STD SDHC SPEC: 51 * There is an INT DMA ERR mis-match between eSDHC and STD SDHC SPEC:
45 * Bit25 is used in STD SPEC, and is reserved in fsl eSDHC design, 52 * Bit25 is used in STD SPEC, and is reserved in fsl eSDHC design,
46 * but bit28 is used as the INT DMA ERR in fsl eSDHC design. 53 * but bit28 is used as the INT DMA ERR in fsl eSDHC design.
@@ -294,6 +301,7 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
294 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 301 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
295 struct pltfm_imx_data *imx_data = pltfm_host->priv; 302 struct pltfm_imx_data *imx_data = pltfm_host->priv;
296 u32 new_val; 303 u32 new_val;
304 u32 mask;
297 305
298 switch (reg) { 306 switch (reg) {
299 case SDHCI_POWER_CONTROL: 307 case SDHCI_POWER_CONTROL:
@@ -304,7 +312,7 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
304 return; 312 return;
305 case SDHCI_HOST_CONTROL: 313 case SDHCI_HOST_CONTROL:
306 /* FSL messed up here, so we need to manually compose it. */ 314 /* FSL messed up here, so we need to manually compose it. */
307 new_val = val & (SDHCI_CTRL_LED | SDHCI_CTRL_4BITBUS); 315 new_val = val & SDHCI_CTRL_LED;
308 /* ensure the endianness */ 316 /* ensure the endianness */
309 new_val |= ESDHC_HOST_CONTROL_LE; 317 new_val |= ESDHC_HOST_CONTROL_LE;
310 /* bits 8&9 are reserved on mx25 */ 318 /* bits 8&9 are reserved on mx25 */
@@ -313,7 +321,13 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
313 new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5; 321 new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5;
314 } 322 }
315 323
316 esdhc_clrset_le(host, 0xffff, new_val, reg); 324 /*
325 * Do not touch buswidth bits here. This is done in
326 * esdhc_pltfm_bus_width.
327 */
328 mask = 0xffff & ~ESDHC_CTRL_BUSWIDTH_MASK;
329
330 esdhc_clrset_le(host, mask, new_val, reg);
317 return; 331 return;
318 } 332 }
319 esdhc_clrset_le(host, 0xff, val, reg); 333 esdhc_clrset_le(host, 0xff, val, reg);
@@ -370,6 +384,28 @@ static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
370 return -ENOSYS; 384 return -ENOSYS;
371} 385}
372 386
387static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width)
388{
389 u32 ctrl;
390
391 switch (width) {
392 case MMC_BUS_WIDTH_8:
393 ctrl = ESDHC_CTRL_8BITBUS;
394 break;
395 case MMC_BUS_WIDTH_4:
396 ctrl = ESDHC_CTRL_4BITBUS;
397 break;
398 default:
399 ctrl = 0;
400 break;
401 }
402
403 esdhc_clrset_le(host, ESDHC_CTRL_BUSWIDTH_MASK, ctrl,
404 SDHCI_HOST_CONTROL);
405
406 return 0;
407}
408
373static struct sdhci_ops sdhci_esdhc_ops = { 409static struct sdhci_ops sdhci_esdhc_ops = {
374 .read_l = esdhc_readl_le, 410 .read_l = esdhc_readl_le,
375 .read_w = esdhc_readw_le, 411 .read_w = esdhc_readw_le,
@@ -380,6 +416,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
380 .get_max_clock = esdhc_pltfm_get_max_clock, 416 .get_max_clock = esdhc_pltfm_get_max_clock,
381 .get_min_clock = esdhc_pltfm_get_min_clock, 417 .get_min_clock = esdhc_pltfm_get_min_clock,
382 .get_ro = esdhc_pltfm_get_ro, 418 .get_ro = esdhc_pltfm_get_ro,
419 .platform_bus_width = esdhc_pltfm_bus_width,
383}; 420};
384 421
385static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { 422static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
@@ -417,6 +454,8 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
417 if (gpio_is_valid(boarddata->wp_gpio)) 454 if (gpio_is_valid(boarddata->wp_gpio))
418 boarddata->wp_type = ESDHC_WP_GPIO; 455 boarddata->wp_type = ESDHC_WP_GPIO;
419 456
457 of_property_read_u32(np, "bus-width", &boarddata->max_bus_width);
458
420 return 0; 459 return 0;
421} 460}
422#else 461#else
@@ -548,6 +587,19 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
548 break; 587 break;
549 } 588 }
550 589
590 switch (boarddata->max_bus_width) {
591 case 8:
592 host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA;
593 break;
594 case 4:
595 host->mmc->caps |= MMC_CAP_4_BIT_DATA;
596 break;
597 case 1:
598 default:
599 host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA;
600 break;
601 }
602
551 err = sdhci_add_host(host); 603 err = sdhci_add_host(host);
552 if (err) 604 if (err)
553 goto disable_clk; 605 goto disable_clk;