diff mbox

[1/7] mmc: dw_mmc: lookup for optional biu and ciu clocks

Message ID 1335935266-25289-2-git-send-email-thomas.abraham@linaro.org
State New
Headers show

Commit Message

thomas.abraham@linaro.org May 2, 2012, 5:07 a.m. UTC
Some platforms allow for clock gating and control of bus interface unit clock
and card interface unit clock. Add support for clock lookup of optional biu
and ciu clocks for clock gating and clock speed determination.

Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
---
 drivers/mmc/host/dw_mmc.c  |   35 +++++++++++++++++++++++++++++++----
 include/linux/mmc/dw_mmc.h |    4 ++++
 2 files changed, 35 insertions(+), 4 deletions(-)

Comments

Will Newton May 2, 2012, 9:17 a.m. UTC | #1
On Wed, May 2, 2012 at 6:07 AM, Thomas Abraham
<thomas.abraham@linaro.org> wrote:
> Some platforms allow for clock gating and control of bus interface unit clock
> and card interface unit clock. Add support for clock lookup of optional biu
> and ciu clocks for clock gating and clock speed determination.
>
> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
> ---
>  drivers/mmc/host/dw_mmc.c  |   35 +++++++++++++++++++++++++++++++----
>  include/linux/mmc/dw_mmc.h |    4 ++++
>  2 files changed, 35 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index 1532357..036846f 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -1938,19 +1938,35 @@ int dw_mci_probe(struct dw_mci *host)
>                return -ENODEV;
>        }
>
> -       if (!host->pdata->bus_hz) {
> +       host->biu_clk = clk_get(&host->dev, "biu");
> +       if (IS_ERR(host->biu_clk))
> +               dev_info(&host->dev, "biu clock not available\n");
> +       else
> +               clk_enable(host->biu_clk);
> +
> +       host->ciu_clk = clk_get(&host->dev, "ciu");
> +       if (IS_ERR(host->ciu_clk))
> +               dev_info(&host->dev, "ciu clock not available\n");

Should these printks be at debug level? I'm not 100% sure either way
but it could be a little noisy on systems that do not use these
clocks.

> +       else
> +               clk_enable(host->ciu_clk);
> +
> +       if (IS_ERR(host->ciu_clk))
> +               host->bus_hz = host->pdata->bus_hz;
> +       else
> +               host->bus_hz = clk_get_rate(host->ciu_clk);
> +
> +       if (!host->bus_hz) {
>                dev_err(&host->dev,
>                        "Platform data must supply bus speed\n");
> -               return -ENODEV;
> +               ret = -ENODEV;
> +               goto err_clk;
>        }
>
> -       host->bus_hz = host->pdata->bus_hz;
>        host->quirks = host->pdata->quirks;
>
>        spin_lock_init(&host->lock);
>        INIT_LIST_HEAD(&host->queue);
>
> -
>        host->dma_ops = host->pdata->dma_ops;
>        dw_mci_init_dma(host);
>
> @@ -2095,6 +2111,13 @@ err_dmaunmap:
>                regulator_disable(host->vmmc);
>                regulator_put(host->vmmc);
>        }
> +       kfree(host);
> +
> +err_clk:
> +       clk_disable(host->ciu_clk);
> +       clk_disable(host->biu_clk);
> +       clk_put(host->ciu_clk);
> +       clk_put(host->biu_clk);

Are these calls safe, or do we need to check IS_ERR as above?

>        return ret;
>  }
>  EXPORT_SYMBOL(dw_mci_probe);
> @@ -2128,6 +2151,10 @@ void dw_mci_remove(struct dw_mci *host)
>                regulator_put(host->vmmc);
>        }
>
> +       clk_disable(host->ciu_clk);
> +       clk_disable(host->biu_clk);
> +       clk_put(host->ciu_clk);
> +       clk_put(host->biu_clk);

Likewise.

>  }
>  EXPORT_SYMBOL(dw_mci_remove);
>
> diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
> index 7a7ebd3..fa9a139 100644
> --- a/include/linux/mmc/dw_mmc.h
> +++ b/include/linux/mmc/dw_mmc.h
> @@ -78,6 +78,8 @@ struct mmc_data;
>  * @data_offset: Set the offset of DATA register according to VERID.
>  * @dev: Device associated with the MMC controller.
>  * @pdata: Platform data associated with the MMC controller.
> + * @biu_clk: Pointer to bus interface unit clock instance.
> + * @ciu_clk: Pointer to card interface unit clock instance.
>  * @slot: Slots sharing this MMC controller.
>  * @fifo_depth: depth of FIFO.
>  * @data_shift: log2 of FIFO item size.
> @@ -158,6 +160,8 @@ struct dw_mci {
>        u16                     data_offset;
>        struct device           dev;
>        struct dw_mci_board     *pdata;
> +       struct clk              *biu_clk;
> +       struct clk              *ciu_clk;
>        struct dw_mci_slot      *slot[MAX_MCI_SLOTS];
>
>        /* FIFO push and pull */
> --
> 1.7.5.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
Russell King - ARM Linux May 2, 2012, 9:53 a.m. UTC | #2
On Tue, May 01, 2012 at 10:07:40PM -0700, Thomas Abraham wrote:
> Some platforms allow for clock gating and control of bus interface unit clock
> and card interface unit clock. Add support for clock lookup of optional biu
> and ciu clocks for clock gating and clock speed determination.

As we're moving progressively towards the common clk API, which requires
the new clk_prepare/clk_unprepare calls, new code should be using the
dated API.  Please update this to do so (eg, by using clk_prepare_enable()
instead of clk_enable() for the simple solution.)  Better solutions
involve decoupling the two and only using clk_enable()/clk_disable() where
you really need the clock to be on.
James Hogan May 2, 2012, 2:53 p.m. UTC | #3
Hi

On 2 May 2012 06:07, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> Some platforms allow for clock gating and control of bus interface unit clock
> and card interface unit clock. Add support for clock lookup of optional biu
> and ciu clocks for clock gating and clock speed determination.
>
> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
> ---
>  drivers/mmc/host/dw_mmc.c  |   35 +++++++++++++++++++++++++++++++----
>  include/linux/mmc/dw_mmc.h |    4 ++++
>  2 files changed, 35 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index 1532357..036846f 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -1938,19 +1938,35 @@ int dw_mci_probe(struct dw_mci *host)
>                return -ENODEV;
>        }
>
> -       if (!host->pdata->bus_hz) {
> +       host->biu_clk = clk_get(&host->dev, "biu");

These clock names sound quite platform specific (what if they're
called something else on another platform, or another platform has
separate ones for different instantiations of the block?). Perhaps the
clk names should get passed in through platform data. I haven't looked
how other drivers handle that though.

> +       if (IS_ERR(host->biu_clk))
> +               dev_info(&host->dev, "biu clock not available\n");

In this case, should it set host->biu_clk to NULL or are clk_disable
and clk_put guaranteed to handle an IS_ERR value?

> +       else
> +               clk_enable(host->biu_clk);
> +
> +       host->ciu_clk = clk_get(&host->dev, "ciu");
> +       if (IS_ERR(host->ciu_clk))
> +               dev_info(&host->dev, "ciu clock not available\n");

same here

> +       else
> +               clk_enable(host->ciu_clk);
> +
> +       if (IS_ERR(host->ciu_clk))
> +               host->bus_hz = host->pdata->bus_hz;
> +       else
> +               host->bus_hz = clk_get_rate(host->ciu_clk);
> +
> +       if (!host->bus_hz) {
>                dev_err(&host->dev,
>                        "Platform data must supply bus speed\n");
> -               return -ENODEV;
> +               ret = -ENODEV;
> +               goto err_clk;
>        }
>
> -       host->bus_hz = host->pdata->bus_hz;
>        host->quirks = host->pdata->quirks;
>
>        spin_lock_init(&host->lock);
>        INIT_LIST_HEAD(&host->queue);
>
> -
>        host->dma_ops = host->pdata->dma_ops;
>        dw_mci_init_dma(host);
>
> @@ -2095,6 +2111,13 @@ err_dmaunmap:
>                regulator_disable(host->vmmc);
>                regulator_put(host->vmmc);
>        }
> +       kfree(host);

what's this about?

> +
> +err_clk:
> +       clk_disable(host->ciu_clk);
> +       clk_disable(host->biu_clk);
> +       clk_put(host->ciu_clk);
> +       clk_put(host->biu_clk);
>        return ret;
>  }
>  EXPORT_SYMBOL(dw_mci_probe);
> @@ -2128,6 +2151,10 @@ void dw_mci_remove(struct dw_mci *host)
>                regulator_put(host->vmmc);
>        }
>
> +       clk_disable(host->ciu_clk);
> +       clk_disable(host->biu_clk);
> +       clk_put(host->ciu_clk);
> +       clk_put(host->biu_clk);
>  }
>  EXPORT_SYMBOL(dw_mci_remove);
>
> diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
> index 7a7ebd3..fa9a139 100644
> --- a/include/linux/mmc/dw_mmc.h
> +++ b/include/linux/mmc/dw_mmc.h
> @@ -78,6 +78,8 @@ struct mmc_data;
>  * @data_offset: Set the offset of DATA register according to VERID.
>  * @dev: Device associated with the MMC controller.
>  * @pdata: Platform data associated with the MMC controller.
> + * @biu_clk: Pointer to bus interface unit clock instance.
> + * @ciu_clk: Pointer to card interface unit clock instance.
>  * @slot: Slots sharing this MMC controller.
>  * @fifo_depth: depth of FIFO.
>  * @data_shift: log2 of FIFO item size.
> @@ -158,6 +160,8 @@ struct dw_mci {
>        u16                     data_offset;
>        struct device           dev;
>        struct dw_mci_board     *pdata;
> +       struct clk              *biu_clk;
> +       struct clk              *ciu_clk;
>        struct dw_mci_slot      *slot[MAX_MCI_SLOTS];
>
>        /* FIFO push and pull */
> --
> 1.7.5.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
thomas.abraham@linaro.org May 10, 2012, 9:11 a.m. UTC | #4
On 2 May 2012 14:47, Will Newton <will.newton@gmail.com> wrote:
> On Wed, May 2, 2012 at 6:07 AM, Thomas Abraham
> <thomas.abraham@linaro.org> wrote:
>> Some platforms allow for clock gating and control of bus interface unit clock
>> and card interface unit clock. Add support for clock lookup of optional biu
>> and ciu clocks for clock gating and clock speed determination.
>>
>> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
>> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
>> ---
>>  drivers/mmc/host/dw_mmc.c  |   35 +++++++++++++++++++++++++++++++----
>>  include/linux/mmc/dw_mmc.h |    4 ++++
>>  2 files changed, 35 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
>> index 1532357..036846f 100644
>> --- a/drivers/mmc/host/dw_mmc.c
>> +++ b/drivers/mmc/host/dw_mmc.c
>> @@ -1938,19 +1938,35 @@ int dw_mci_probe(struct dw_mci *host)
>>                return -ENODEV;
>>        }
>>
>> -       if (!host->pdata->bus_hz) {
>> +       host->biu_clk = clk_get(&host->dev, "biu");
>> +       if (IS_ERR(host->biu_clk))
>> +               dev_info(&host->dev, "biu clock not available\n");
>> +       else
>> +               clk_enable(host->biu_clk);
>> +
>> +       host->ciu_clk = clk_get(&host->dev, "ciu");
>> +       if (IS_ERR(host->ciu_clk))
>> +               dev_info(&host->dev, "ciu clock not available\n");
>
> Should these printks be at debug level? I'm not 100% sure either way
> but it could be a little noisy on systems that do not use these
> clocks.

Right. I will change dev_info to dev_dbg.

>
>> +       else
>> +               clk_enable(host->ciu_clk);
>> +
>> +       if (IS_ERR(host->ciu_clk))
>> +               host->bus_hz = host->pdata->bus_hz;
>> +       else
>> +               host->bus_hz = clk_get_rate(host->ciu_clk);
>> +
>> +       if (!host->bus_hz) {
>>                dev_err(&host->dev,
>>                        "Platform data must supply bus speed\n");
>> -               return -ENODEV;
>> +               ret = -ENODEV;
>> +               goto err_clk;
>>        }
>>
>> -       host->bus_hz = host->pdata->bus_hz;
>>        host->quirks = host->pdata->quirks;
>>
>>        spin_lock_init(&host->lock);
>>        INIT_LIST_HEAD(&host->queue);
>>
>> -
>>        host->dma_ops = host->pdata->dma_ops;
>>        dw_mci_init_dma(host);
>>
>> @@ -2095,6 +2111,13 @@ err_dmaunmap:
>>                regulator_disable(host->vmmc);
>>                regulator_put(host->vmmc);
>>        }
>> +       kfree(host);
>> +
>> +err_clk:
>> +       clk_disable(host->ciu_clk);
>> +       clk_disable(host->biu_clk);
>> +       clk_put(host->ciu_clk);
>> +       clk_put(host->biu_clk);
>
> Are these calls safe, or do we need to check IS_ERR as above?

The clk_disable is safe on Samsung platforms but it cannot be assumed
for other platforms. So, the IS_ERR check will be added before
clk_disable. clk_put will not need the IS_ERR check. Thanks for
pointing this out.

>
>>        return ret;
>>  }
>>  EXPORT_SYMBOL(dw_mci_probe);
>> @@ -2128,6 +2151,10 @@ void dw_mci_remove(struct dw_mci *host)
>>                regulator_put(host->vmmc);
>>        }
>>
>> +       clk_disable(host->ciu_clk);
>> +       clk_disable(host->biu_clk);
>> +       clk_put(host->ciu_clk);
>> +       clk_put(host->biu_clk);
>
> Likewise.

Yes, will be fixed.

Thanks,
Thomas.

[...]
thomas.abraham@linaro.org May 10, 2012, 9:12 a.m. UTC | #5
On 2 May 2012 15:23, Russell King - ARM Linux <linux@arm.linux.org.uk> wrote:
> On Tue, May 01, 2012 at 10:07:40PM -0700, Thomas Abraham wrote:
>> Some platforms allow for clock gating and control of bus interface unit clock
>> and card interface unit clock. Add support for clock lookup of optional biu
>> and ciu clocks for clock gating and clock speed determination.
>
> As we're moving progressively towards the common clk API, which requires
> the new clk_prepare/clk_unprepare calls, new code should be using the
> dated API.  Please update this to do so (eg, by using clk_prepare_enable()
> instead of clk_enable() for the simple solution.)  Better solutions
> involve decoupling the two and only using clk_enable()/clk_disable() where
> you really need the clock to be on.

Thanks for your suggestion. I will modify this to use the
clk_prepare_enable and clk_disable_unprepare calls for now.

Thanks,
Thomas.
thomas.abraham@linaro.org May 10, 2012, 9:20 a.m. UTC | #6
On 2 May 2012 20:23, James Hogan <james@albanarts.com> wrote:
> Hi
>
> On 2 May 2012 06:07, Thomas Abraham <thomas.abraham@linaro.org> wrote:
>> Some platforms allow for clock gating and control of bus interface unit clock
>> and card interface unit clock. Add support for clock lookup of optional biu
>> and ciu clocks for clock gating and clock speed determination.
>>
>> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
>> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
>> ---
>>  drivers/mmc/host/dw_mmc.c  |   35 +++++++++++++++++++++++++++++++----
>>  include/linux/mmc/dw_mmc.h |    4 ++++
>>  2 files changed, 35 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
>> index 1532357..036846f 100644
>> --- a/drivers/mmc/host/dw_mmc.c
>> +++ b/drivers/mmc/host/dw_mmc.c
>> @@ -1938,19 +1938,35 @@ int dw_mci_probe(struct dw_mci *host)
>>                return -ENODEV;
>>        }
>>
>> -       if (!host->pdata->bus_hz) {
>> +       host->biu_clk = clk_get(&host->dev, "biu");
>
> These clock names sound quite platform specific (what if they're
> called something else on another platform, or another platform has
> separate ones for different instantiations of the block?). Perhaps the
> clk names should get passed in through platform data. I haven't looked
> how other drivers handle that though.

The clock names 'biu' and 'ciu' are derived from the terminology used
by the data sheet of the mshc controller. The 'biu' clock is the
source clock for the bus interface unit and 'ciu' clock is the clock
source for card interface unit of the controller. So these names are
generic and not specific to a platform. Passing clock names from
platform data is generally frowned upon.

>
>> +       if (IS_ERR(host->biu_clk))
>> +               dev_info(&host->dev, "biu clock not available\n");
>
> In this case, should it set host->biu_clk to NULL or are clk_disable
> and clk_put guaranteed to handle an IS_ERR value?

Yes, the clk_disable will have to be preceded with a IS_ERR check. I
will fix this.

>
>> +       else
>> +               clk_enable(host->biu_clk);
>> +
>> +       host->ciu_clk = clk_get(&host->dev, "ciu");
>> +       if (IS_ERR(host->ciu_clk))
>> +               dev_info(&host->dev, "ciu clock not available\n");
>
> same here

Ok, this also will be fixed.

>
>> +       else
>> +               clk_enable(host->ciu_clk);
>> +
>> +       if (IS_ERR(host->ciu_clk))
>> +               host->bus_hz = host->pdata->bus_hz;
>> +       else
>> +               host->bus_hz = clk_get_rate(host->ciu_clk);
>> +
>> +       if (!host->bus_hz) {
>>                dev_err(&host->dev,
>>                        "Platform data must supply bus speed\n");
>> -               return -ENODEV;
>> +               ret = -ENODEV;
>> +               goto err_clk;
>>        }
>>
>> -       host->bus_hz = host->pdata->bus_hz;
>>        host->quirks = host->pdata->quirks;
>>
>>        spin_lock_init(&host->lock);
>>        INIT_LIST_HEAD(&host->queue);
>>
>> -
>>        host->dma_ops = host->pdata->dma_ops;
>>        dw_mci_init_dma(host);
>>
>> @@ -2095,6 +2111,13 @@ err_dmaunmap:
>>                regulator_disable(host->vmmc);
>>                regulator_put(host->vmmc);
>>        }
>> +       kfree(host);
>
> what's this about?

This is wrong. It should not have been here. I will fix this. Thanks
for pointing this out.

Thanks,
Thomas.
diff mbox

Patch

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 1532357..036846f 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1938,19 +1938,35 @@  int dw_mci_probe(struct dw_mci *host)
 		return -ENODEV;
 	}
 
-	if (!host->pdata->bus_hz) {
+	host->biu_clk = clk_get(&host->dev, "biu");
+	if (IS_ERR(host->biu_clk))
+		dev_info(&host->dev, "biu clock not available\n");
+	else
+		clk_enable(host->biu_clk);
+
+	host->ciu_clk = clk_get(&host->dev, "ciu");
+	if (IS_ERR(host->ciu_clk))
+		dev_info(&host->dev, "ciu clock not available\n");
+	else
+		clk_enable(host->ciu_clk);
+
+	if (IS_ERR(host->ciu_clk))
+		host->bus_hz = host->pdata->bus_hz;
+	else
+		host->bus_hz = clk_get_rate(host->ciu_clk);
+
+	if (!host->bus_hz) {
 		dev_err(&host->dev,
 			"Platform data must supply bus speed\n");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto err_clk;
 	}
 
-	host->bus_hz = host->pdata->bus_hz;
 	host->quirks = host->pdata->quirks;
 
 	spin_lock_init(&host->lock);
 	INIT_LIST_HEAD(&host->queue);
 
-
 	host->dma_ops = host->pdata->dma_ops;
 	dw_mci_init_dma(host);
 
@@ -2095,6 +2111,13 @@  err_dmaunmap:
 		regulator_disable(host->vmmc);
 		regulator_put(host->vmmc);
 	}
+	kfree(host);
+
+err_clk:
+	clk_disable(host->ciu_clk);
+	clk_disable(host->biu_clk);
+	clk_put(host->ciu_clk);
+	clk_put(host->biu_clk);
 	return ret;
 }
 EXPORT_SYMBOL(dw_mci_probe);
@@ -2128,6 +2151,10 @@  void dw_mci_remove(struct dw_mci *host)
 		regulator_put(host->vmmc);
 	}
 
+	clk_disable(host->ciu_clk);
+	clk_disable(host->biu_clk);
+	clk_put(host->ciu_clk);
+	clk_put(host->biu_clk);
 }
 EXPORT_SYMBOL(dw_mci_remove);
 
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index 7a7ebd3..fa9a139 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -78,6 +78,8 @@  struct mmc_data;
  * @data_offset: Set the offset of DATA register according to VERID.
  * @dev: Device associated with the MMC controller.
  * @pdata: Platform data associated with the MMC controller.
+ * @biu_clk: Pointer to bus interface unit clock instance.
+ * @ciu_clk: Pointer to card interface unit clock instance.
  * @slot: Slots sharing this MMC controller.
  * @fifo_depth: depth of FIFO.
  * @data_shift: log2 of FIFO item size.
@@ -158,6 +160,8 @@  struct dw_mci {
 	u16			data_offset;
 	struct device		dev;
 	struct dw_mci_board	*pdata;
+	struct clk		*biu_clk;
+	struct clk		*ciu_clk;
 	struct dw_mci_slot	*slot[MAX_MCI_SLOTS];
 
 	/* FIFO push and pull */