diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2013-01-21 06:02:28 -0500 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2013-02-24 14:37:03 -0500 |
commit | af51079e68d4759e458b0592df5d1fab373c43ae (patch) | |
tree | 937bb9166c549ab3ebfbdb19c8dc63e76f904584 /drivers/mmc | |
parent | 7bc088d38f92f58df97e1cd9a8430331ee5491bb (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.c | 56 |
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 | ||
387 | static 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 | |||
373 | static struct sdhci_ops sdhci_esdhc_ops = { | 409 | static 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 | ||
385 | static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { | 422 | static 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; |