From a467484ee963486ba9b527c6ca2dafd0f3b34eda Mon Sep 17 00:00:00 2001 From: Sahitya Tummala Date: Mon, 10 Jun 2013 16:32:51 +0530 Subject: mmc: sdhci-msm: calculate timeout value based on the base clock The driver currently uses fixed timeout value from capabilities register (bit 5-0) to calculate the timeout which is advertized as 50MHz. But the driver uses SDHCI_QUIRK2_ALWAYS_USE_BASE_CLOCK and controls the base clock (MCLK) directly. So during card initialization, the frequency would be 400KHz but still timeout is calculated at 50MHz which is wrong. This patch fixes this by using the current base clock frequency to calculate the timeout. The controller internally multiplies the timeout control register value by 4 with the assumption that driver always uses fixed timeout clock value from capabilities register. Add a quirk SDHCI_QUIRK2_DIVIDE_TOUT_BY_4 to avoid this multiplicaiton in case base clock is used for timeout calculation. CRs-fixed: 498159 Change-Id: I503fd16132bf17e590239997d6970b9b730d4202 Signed-off-by: Sahitya Tummala [subhashj@codeaurora.org: fixed minor merge conflict] Signed-off-by: Subhash Jadavani --- drivers/mmc/host/sdhci-msm.c | 3 +++ drivers/mmc/host/sdhci.c | 10 +++++++++- drivers/mmc/host/sdhci.h | 13 +++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index ed64d1846d61..9cac755d36e2 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -2261,6 +2261,9 @@ static int sdhci_msm_probe(struct platform_device *pdev) host->quirks2 |= SDHCI_QUIRK2_BROKEN_PRESET_VALUE; host->quirks2 |= SDHCI_QUIRK2_USE_RESERVED_MAX_TIMEOUT; + if (host->quirks2 & SDHCI_QUIRK2_ALWAYS_USE_BASE_CLOCK) + host->quirks2 |= SDHCI_QUIRK2_DIVIDE_TOUT_BY_4; + host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION)); dev_dbg(&pdev->dev, "Host Version: 0x%x Vendor Version 0x%x\n", host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 176cc39e6dd5..de0bcb9149d2 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -670,6 +670,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) u8 count; struct mmc_data *data = cmd->data; unsigned target_timeout, current_timeout; + u32 curr_clk = 0; /* In KHz */ /* * If the host controller provides us with an incorrect timeout @@ -704,7 +705,14 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) * (1) / (2) > 2^6 */ count = 0; - current_timeout = (1 << 13) * 1000 / host->timeout_clk; + if (host->quirks2 & SDHCI_QUIRK2_ALWAYS_USE_BASE_CLOCK) { + curr_clk = host->clock / 1000; + if (host->quirks2 & SDHCI_QUIRK2_DIVIDE_TOUT_BY_4) + curr_clk /= 4; + current_timeout = (1 << 13) * 1000 / curr_clk; + } else { + current_timeout = (1 << 13) * 1000 / host->timeout_clk; + } while (current_timeout < target_timeout) { count++; current_timeout <<= 1; diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 4335837f7c17..1a39c46439c5 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -458,6 +458,19 @@ struct sdhci_host { * specification. */ #define SDHCI_QUIRK2_USE_RESERVED_MAX_TIMEOUT (1<<23) +/* + * This is applicable for controllers that advertize timeout clock + * value in capabilities register (bit 5-0) as just 50MHz whereas the + * base clock frequency is 200MHz. So, the controller internally + * multiplies the value in timeout control register by 4 with the + * assumption that driver always uses fixed timeout clock value from + * capabilities register to calculate the timeout. But when the driver + * uses SDHCI_QUIRK2_ALWAYS_USE_BASE_CLOCK base clock frequency is directly + * controller by driver and it's rate varies upto max. 200MHz. This new quirk + * will be used in such cases to avoid controller mulplication when timeout is + * calculated based on the base clock. + */ +#define SDHCI_QUIRK2_DIVIDE_TOUT_BY_4 (1 << 23) int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ -- cgit v1.2.3