Re: [PATCH 5/5] sdhci-s3c: Add support no internal clock divider in host controller

Kyungmin Park
2010-09-16T09:08:28Z

Hi,

Well there are two implementations. and no conclusion yet.
as s5pc210 don't support internal SDHCI clock, DMC overrides the
function operation itself when s5pc210. System LSI use the quirks.

Choose any one from MMC maintainer.

Thank you,
Kyungmin Park

On Thu, Sep 16, 2010 at 5:37 PM, Jeongbae Seo <jeongbae.seo@samsung.com> wrote:
> From: Hyuk Lee <hyuk1.lee@samsung.com>
>
> This patch adds to support no internal clock divider in SDHCI.
> The external clock divider can be used to make a proper clock
> because SDHCI doesn't support internal clock divider by itself.
>
> Signed-off-by: Hyuk Lee <hyuk1.lee@samsung.com>
> Signed-off-by: Jeongbae Seo <jeongbae.seo@samsung.com>
> ---
>  drivers/mmc/host/sdhci-s3c.c |   63 ++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 63 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
> index 71ad416..6160960 100644
> --- a/drivers/mmc/host/sdhci-s3c.c
> +++ b/drivers/mmc/host/sdhci-s3c.c
> @@ -96,6 +96,13 @@ static unsigned int sdhci_s3c_get_max_clk(struct sdhci_host *host)
>        unsigned int rate, max;
>        int clk;
>
> +       /*
> +        * There is only one clock source(sclk) if there is no clock divider
> +        * in the host controller
> +        */
> +       if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK)
> +               return clk_round_rate(ourhost->clk_bus[2], UINT_MAX);
No hard-coded index.
> +
>        /* note, a reset will reset the clock source */
>
>        sdhci_s3c_check_sclk(host);
> @@ -130,6 +137,15 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost,
>        if (!clksrc)
>                return UINT_MAX;
>
> +       /*
> +        * There is only one clock source(sclk) if there is no clock divider
> +        * in the host controller
> +        */
> +       if (ourhost->host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) {
> +               rate = clk_round_rate(clksrc, wanted);
> +               return wanted - rate;
> +       }
> +
>        rate = clk_get_rate(clksrc);
>
>        for (div = 1; div < 256; div *= 2) {
> @@ -159,6 +175,7 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock)
>        int best_src = 0;
>        int src;
>        u32 ctrl;
> +       unsigned int timeout;
>
>        /* don't bother if the clock is going off. */
>        if (clock == 0)
> @@ -204,6 +221,35 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock)
>                        (ourhost->pdata->cfg_card)(ourhost->pdev, host->ioaddr,
>                                                   &ios, NULL);
>        }
> +
> +       /*
> +        * There is only one clock source(sclk) if there is no clock divider
> +        * in the host controller
> +        */
> +       if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) {
> +               writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL);
> +               clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock);
> +
> +               writew(SDHCI_CLOCK_INT_EN, host->ioaddr + SDHCI_CLOCK_CONTROL);
> +
> +               /* Wait max 20 ms */
> +               timeout = 20;
> +               while (!((sdhci_readw(host, SDHCI_CLOCK_CONTROL))
> +                       & SDHCI_CLOCK_INT_STABLE)) {
> +                       if (timeout == 0) {
> +                               printk(KERN_ERR "%s: clock never stabilised.\n"
> +                                               , mmc_hostname(host->mmc));
> +                               return;
> +                       }
> +                       timeout--;
> +                       mdelay(1);
> +               }
> +
> +               writew(SDHCI_CLOCK_INT_EN | SDHCI_CLOCK_CARD_EN,
> +                               host->ioaddr + SDHCI_CLOCK_CONTROL);
> +
> +               host->clock = clock;
> +       }
>  }
>
>  /**
> @@ -221,6 +267,13 @@ static unsigned int sdhci_s3c_get_min_clock(struct sdhci_host *host)
>        unsigned int delta, min = UINT_MAX;
>        int src;
>
> +       /*
> +        * There is only one clock source(sclk) if there is no clock divider
> +        * in the host controller
> +        */
> +       if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK)
> +               return clk_round_rate(ourhost->clk_bus[2], 400000);
ditto
> +
>        for (src = 0; src < MAX_BUS_CLK; src++) {
>                delta = sdhci_s3c_consider_clock(ourhost, src, 0);
>                if (delta == UINT_MAX)
> @@ -425,6 +478,16 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
>        /* HSMMC on Samsung SoCs uses SDCLK as timeout clock */
>        host->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK;
>
> +       /*
> +        * If controller does not have internal clock divider,
> +        * we need to use another method with setup a quirk.
> +        */
> +       if (pdata->clk_type)
check the clk_type with external
> +               host->quirks |= SDHCI_QUIRK_NONSTANDARD_CLOCK;
> +
> +       if (pdata->host_caps)
> +               host->mmc->caps |= pdata->host_caps;
> +
>        ret = sdhci_add_host(host);
>        if (ret) {
>                dev_err(dev, "sdhci_add_host() failed\n");
> --
> 1.6.2.5
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>