[PATCH 3/8] sdhci: sdhci-esdhc-imx: support real clock on and off for imx6q
Shawn Guo
shawn.guo at linaro.org
Thu Sep 5 00:32:29 EDT 2013
On Wed, Sep 04, 2013 at 08:54:12PM +0800, Dong Aisheng wrote:
> The signal voltage switch follow requires to shutdown and output
s/follow/flow
> clock in a specific sequence according to standard host controller
> v3.0 spec. In that timing, the card must really receive clock or not.
>
> However, for i.MX6Q, the uSDHC will not output clock even the clock
> is enabled until there is command or data in transfer on the bus,
> which will then cause singal voltage switch always to fail.
>
> For i.MX6Q, we clear ESDHC_VENDOR_SPEC_FRC_SDCLK_ON bit to let
> controller to gate off clock automatically and set that bit
> to force clock output if clock is on.
>
> This is required by SD3.0 support.
>
> Signed-off-by: Dong Aisheng <b29396 at freescale.com>
> ---
> drivers/mmc/host/sdhci-esdhc-imx.c | 3 ---
> drivers/mmc/host/sdhci-esdhc.h | 29 ++++++++++++++++++++++++++---
> 2 files changed, 26 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
> index 1dd5ba8..3118a82 100644
> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> @@ -31,9 +31,6 @@
> #include "sdhci-esdhc.h"
>
> #define ESDHC_CTRL_D3CD 0x08
> -/* VENDOR SPEC register */
> -#define ESDHC_VENDOR_SPEC 0xc0
> -#define ESDHC_VENDOR_SPEC_SDIO_QUIRK (1 << 1)
> #define ESDHC_WTMK_LVL 0x44
> #define ESDHC_MIX_CTRL 0x48
> #define ESDHC_MIX_CTRL_AC23EN (1 << 7)
> diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
> index a2a0642..86fcd5b 100644
> --- a/drivers/mmc/host/sdhci-esdhc.h
> +++ b/drivers/mmc/host/sdhci-esdhc.h
> @@ -14,6 +14,8 @@
> #ifndef _DRIVERS_MMC_SDHCI_ESDHC_H
> #define _DRIVERS_MMC_SDHCI_ESDHC_H
>
> +#include <linux/of.h>
> +
> /*
> * Ops and quirks for the Freescale eSDHC controller.
> */
> @@ -33,6 +35,12 @@
> #define ESDHC_CLOCK_HCKEN 0x00000002
> #define ESDHC_CLOCK_IPGEN 0x00000001
>
> +/* VENDOR SPEC register */
> +#define ESDHC_VENDOR_SPEC 0xc0
> +#define ESDHC_VENDOR_SPEC_SDIO_QUIRK (1 << 1)
> +#define ESDHC_VENDOR_SPEC_VSELECT (1 << 1)
It would be better to introduce the macro only when it's actually being
used.
> +#define ESDHC_VENDOR_SPEC_FRC_SDCLK_ON (1 << 8)
> +
> /* pltfm-specific */
> #define ESDHC_HOST_CONTROL_LE 0x20
>
> @@ -52,12 +60,20 @@
> static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock,
> unsigned int host_clock)
> {
> + struct device *dev;
> int pre_div = 2;
> int div = 1;
> - u32 temp;
> -
> - if (clock == 0)
> + u32 temp, val;
> +
> + dev = mmc_dev(host->mmc);
> + if (clock == 0) {
> + if (of_device_is_compatible(dev->of_node, "fsl,imx6q-usdhc")) {
> + val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
> + writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
> + host->ioaddr + ESDHC_VENDOR_SPEC);
> + }
To me, maintaining this esdhc_set_clock() for both imx and powerpc makes
no sense now. I think it might be the time to have different versions
of the function for imx and powerpc, just in esdhc_pltfm_set_clock() and
esdhc_of_set_clock() respectively.
Shawn
> goto out;
> + }
>
> temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
> temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
> @@ -81,6 +97,13 @@ static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock,
> | (div << ESDHC_DIVIDER_SHIFT)
> | (pre_div << ESDHC_PREDIV_SHIFT));
> sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
> +
> + if (of_device_is_compatible(dev->of_node, "fsl,imx6q-usdhc")) {
> + val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
> + writel(val | ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
> + host->ioaddr + ESDHC_VENDOR_SPEC);
> + }
> +
> mdelay(1);
> out:
> host->clock = clock;
> --
> 1.7.1
>
>
More information about the linux-arm-kernel
mailing list