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 1e8aa590bb3..01ab916c280 100644 --- a/drivers/mmc/host/sdhci-of.c +++ b/drivers/mmc/host/sdhci-of.c @@ -21,6 +21,7 @@ #include <linux/of.h> #include <linux/of_platform.h> #include <linux/mmc/host.h> +#include <asm/machdep.h> #include "sdhci.h" struct sdhci_of_data { @@ -48,6 +49,8 @@ struct sdhci_of_host { #define ESDHC_CLOCK_HCKEN 0x00000002 #define ESDHC_CLOCK_IPGEN 0x00000001 +#define ESDHC_HOST_CONTROL_RES 0x05 + static u32 esdhc_readl(struct sdhci_host *host, int reg) { return in_be32(host->ioaddr + reg); @@ -109,13 +112,17 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg) int base = reg & ~0x3; int shift = (reg & 0x3) * 8; + /* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */ + if (reg == SDHCI_HOST_CONTROL) + val &= ~ESDHC_HOST_CONTROL_RES; + clrsetbits_be32(host->ioaddr + base , 0xff << shift, val << shift); } static void esdhc_set_clock(struct sdhci_host *host, unsigned int clock) { - int div; int pre_div = 2; + int div = 1; clrbits32(host->ioaddr + ESDHC_SYSTEM_CONTROL, ESDHC_CLOCK_IPGEN | 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) if (clock == 0) goto out; - if (host->max_clk / 16 > clock) { - for (; pre_div < 256; pre_div *= 2) { - if (host->max_clk / pre_div < clock * 16) - break; - } - } + while (host->max_clk / pre_div / 16 > clock && pre_div < 256) + pre_div *= 2; - for (div = 1; div <= 16; div++) { - if (host->max_clk / (div * pre_div) <= clock) - break; - } + while (host->max_clk / pre_div / div > clock && div < 16) + div++; + + dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n", + clock, host->max_clk / pre_div / div); pre_div >>= 1; + div--; setbits32(host->ioaddr + ESDHC_SYSTEM_CONTROL, ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN | @@ -165,19 +170,12 @@ static unsigned int esdhc_get_min_clock(struct sdhci_host *host) return of_host->clock / 256 / 16; } -static unsigned int esdhc_get_timeout_clock(struct sdhci_host *host) -{ - struct sdhci_of_host *of_host = sdhci_priv(host); - - return of_host->clock / 1000; -} - static struct sdhci_of_data sdhci_esdhc = { .quirks = SDHCI_QUIRK_FORCE_BLK_SZ_2048 | SDHCI_QUIRK_BROKEN_CARD_DETECTION | - SDHCI_QUIRK_INVERTED_WRITE_PROTECT | SDHCI_QUIRK_NO_BUSY_IRQ | SDHCI_QUIRK_NONSTANDARD_CLOCK | + SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | SDHCI_QUIRK_PIO_NEEDS_DELAY | SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET | SDHCI_QUIRK_NO_CARD_NO_RESET, @@ -192,7 +190,6 @@ static struct sdhci_of_data sdhci_esdhc = { .enable_dma = esdhc_enable_dma, .get_max_clock = esdhc_get_max_clock, .get_min_clock = esdhc_get_min_clock, - .get_timeout_clock = esdhc_get_timeout_clock, }, }; @@ -219,6 +216,15 @@ static int sdhci_of_resume(struct of_device *ofdev) #endif +static bool __devinit sdhci_of_wp_inverted(struct device_node *np) +{ + if (of_get_property(np, "sdhci,wp-inverted", NULL)) + return true; + + /* Old device trees don't have the wp-inverted property. */ + return machine_is(mpc837x_rdb) || machine_is(mpc837x_mds); +} + static int __devinit sdhci_of_probe(struct of_device *ofdev, const struct of_device_id *match) { @@ -261,6 +267,9 @@ static int __devinit sdhci_of_probe(struct of_device *ofdev, if (of_get_property(np, "sdhci,1-bit-only", NULL)) host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA; + if (sdhci_of_wp_inverted(np)) + host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT; + clk = of_get_property(np, "clock-frequency", &size); if (clk && size == sizeof(*clk) && *clk) of_host->clock = *clk; |