[PATCH 1/3] mmc: sdhci-s3c: Remove usage of clk_type member in platform data

Thomas Abraham thomas.abraham at linaro.org
Tue Oct 4 04:15:06 EDT 2011


Hi Mr. Park,

On 4 October 2011 13:23, Kyungmin Park <kmpark at infradead.org> wrote:
> Hi,
>
> On Tue, Oct 4, 2011 at 4:28 PM, Thomas Abraham
> <thomas.abraham at linaro.org> wrote:
>> SDHCI controllers on Exynos4 do not include the sdclk divider as per the
>> sdhci controller specification. This case can be represented using the
>> sdhci quirk SDHCI_QUIRK_NONSTANDARD_CLOCK instead of using an additional
>> enum type definition 'clk_types'.
>>
>> Hence, usage of clk_type member in platform data is removed and the sdhci
>> quirk is used. In addition to that, since this qurik is SoC specific,
>> driver data is introduced to represent controllers on SoC's that require
>> this quirk.
> Right.
>>
>> Cc: Ben Dooks <ben-linux at fluff.org>
>> Cc: Jeongbae Seo <jeongbae.seo at samsung.com>
>> Signed-off-by: Thomas Abraham <thomas.abraham at linaro.org>
>> ---
>> In the function 'sdhci_cmu_set_clock', the code that waits for a stable
>> sdclk clock is replicated from 'sdhci_set_clock' function. This portion
>> of code is replicated in sdhci-cns3xxx driver as well. This duplication
>> could have been avoid by adding a new function in sdhci host controller
>> driver that waits for stable sdclk and sdhci-s3c/sdhci-cns3xxx can be
>> the users of the new function. If adding a new function in sdhci host
>> controller driver is acceptable, an additional patch in this series
>> can be added that creates the new function that waits for stable sdclk.
>>
>>  drivers/mmc/host/sdhci-s3c.c |   74 +++++++++++++++++++++++++++++++++++++++--
>>  1 files changed, 70 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
>> index 82709b6..b29e734 100644
>> --- a/drivers/mmc/host/sdhci-s3c.c
>> +++ b/drivers/mmc/host/sdhci-s3c.c
>> @@ -53,6 +53,18 @@ struct sdhci_s3c {
>>        struct clk              *clk_bus[MAX_BUS_CLK];
>>  };
>>
>> +/**
>> + * struct sdhci_s3c_driver_data - S3C SDHCI platform specific driver data
>> + * @sdhci_quirks: sdhci host specific quirks.
>> + *
>> + * Specifies platform specific configuration of sdhci controller.
>> + * Note: A structure for driver specific platform data is used for future
>> + * expansion of its usage.
>> + */
>> +struct sdhci_s3c_drv_data {
>> +       unsigned int    sdhci_quirks;
>> +};
>> +
>>  static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host)
>>  {
>>        return sdhci_priv(host);
>> @@ -132,10 +144,10 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost,
>>                return UINT_MAX;
>>
>>        /*
>> -        * Clock divider's step is different as 1 from that of host controller
>> -        * when 'clk_type' is S3C_SDHCI_CLK_DIV_EXTERNAL.
>> +        * If controller uses a non-standard clock division, find the best clock
>> +        * speed possible with selected clock source and skip the division.
>>         */
>> -       if (ourhost->pdata->clk_type) {
>> +       if (ourhost->host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) {
>>                rate = clk_round_rate(clksrc, wanted);
>>                return wanted - rate;
>>        }
>> @@ -272,6 +284,8 @@ static unsigned int sdhci_cmu_get_min_clock(struct sdhci_host *host)
>>  static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
>>  {
>>        struct sdhci_s3c *ourhost = to_s3c(host);
>> +       unsigned long timeout;
>> +       u16 clk = 0;
>>
>>        /* don't bother if the clock is going off */
>>        if (clock == 0)
>> @@ -282,6 +296,25 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
>>        clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock);
>>
>>        host->clock = clock;
>> +
>> +       clk = SDHCI_CLOCK_INT_EN;
>> +       sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
>> +
>> +       /* Wait max 20 ms */
>> +       timeout = 20;
>> +       while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
>> +               & SDHCI_CLOCK_INT_STABLE)) {
>> +               if (timeout == 0) {
>> +                       printk(KERN_ERR "%s: Internal clock never "
>> +                               "stabilised.\n", mmc_hostname(host->mmc));
>> +                       return;
>> +               }
>> +               timeout--;
>> +               mdelay(1);
>> +       }
>> +
>> +       clk |= SDHCI_CLOCK_CARD_EN;
>> +       sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
>>  }
>>
>>  /**
>> @@ -382,9 +415,17 @@ static void sdhci_s3c_setup_card_detect_gpio(struct sdhci_s3c *sc)
>>        }
>>  }
>>
>> +static inline struct sdhci_s3c_drv_data *sdhci_s3c_get_driver_data(
>> +                       struct platform_device *pdev)
>> +{
>> +       return (struct sdhci_s3c_drv_data *)
>> +                       platform_get_device_id(pdev)->driver_data;
>> +}
>> +
>>  static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
>>  {
>>        struct s3c_sdhci_platdata *pdata = pdev->dev.platform_data;
>> +       struct sdhci_s3c_drv_data *drv_data;
>>        struct device *dev = &pdev->dev;
>>        struct sdhci_host *host;
>>        struct sdhci_s3c *sc;
>> @@ -414,6 +455,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
>>                return PTR_ERR(host);
>>        }
>>
>> +       drv_data = sdhci_s3c_get_driver_data(pdev);
>>        sc = sdhci_priv(host);
>>
>>        sc->host = host;
>> @@ -494,6 +536,8 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
>>        /* Setup quirks for the controller */
>>        host->quirks |= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC;
>>        host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT;
>> +       if (drv_data)
>> +               host->quirks |= drv_data->sdhci_quirks;
>>
>>  #ifndef CONFIG_MMC_SDHCI_S3C_DMA
>>
>> @@ -534,7 +578,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
>>         * If controller does not have internal clock divider,
>>         * we can use overriding functions instead of default.
>>         */
>> -       if (pdata->clk_type) {
>> +       if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) {
>>                sdhci_s3c_ops.set_clock = sdhci_cmu_set_clock;
>>                sdhci_s3c_ops.get_min_clock = sdhci_cmu_get_min_clock;
>>                sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock;
>> @@ -639,9 +683,31 @@ static int sdhci_s3c_resume(struct platform_device *dev)
>>  #define sdhci_s3c_resume NULL
>>  #endif
>>
>> +#if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS4212)
>> +static struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = {
>> +       .sdhci_quirks = SDHCI_QUIRK_NONSTANDARD_CLOCK,
>> +};
>> +#define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)&exynos4_sdhci_drv_data)
>> +#else
>> +#define EXYNOS4_SDHCI_DRV_DATA (kernel_ulong_t)NULL
>> +#endif
> It's too small to save the memory. I think no need to guard the exynos
> driver data with ifdef/endif.


There could be other elements added to the 'sdhci_s3c_drv_data'
structure as new variants of sdhci-s3c controller would appear in
future SoC. I am not aware of any such variations in the upcoming
SoC's but this was done taking into consideration that there could be
slight variations which the driver would have to support.


>> +
>> +static struct platform_device_id sdhci_s3c_driver_ids[] = {
>> +       {
>> +               .name           = "s3c-sdhci",
>> +               .driver_data    = (kernel_ulong_t)NULL,
>> +       },
>> +       {
>> +               .name           = "exynos4-sdhci",
>> +               .driver_data    = EXYNOS4_SDHCI_DRV_DATA,
>> +       },
>> +};
>> +MODULE_DEVICE_TABLE(platform, sdhci_s3c_driver_ids);
>
> Do you have a plan to use the sdhci-pltfm.c as other drivers did?
> some drivers are already use it and support OF features.

I did check few months back if sdhci-pltfm.c can be used for sdhci-s3c
drivers but due to slightly complex operations which sdhci-s3c
handles, I did not try to base samsung sdhci driver support on
sdhci-pltfm.c. So, at present, I do not have a plan to move to
sdhci-pltfm.c.

>
> Thank you,
> Kyungmin Park


Thanks for your review and comments.

Regards,
Thomas.

>> +
>>  static struct platform_driver sdhci_s3c_driver = {
>>        .probe          = sdhci_s3c_probe,
>>        .remove         = __devexit_p(sdhci_s3c_remove),
>> +       .id_table       = sdhci_s3c_driver_ids,
>>        .suspend        = sdhci_s3c_suspend,
>>        .resume         = sdhci_s3c_resume,
>>        .driver         = {
>> --
>> 1.6.6.rc2
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
>



More information about the linux-arm-kernel mailing list