diff mbox

[v2,4/7] clk: Add simple gated clock

Message ID 1316730422-20027-5-git-send-email-mturquette@ti.com
State New
Headers show

Commit Message

Mike Turquette Sept. 22, 2011, 10:26 p.m. UTC
From: Jeremy Kerr <jeremy.kerr@canonical.com>

Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Jamie Iles <jamie@jamieiles.com>
Signed-off-by: Mike Turquette <mturquette@ti.com>
---
Changes since v1:
Add copyright header
Fold in Jamie's patch for set-to-disable clks
Use BIT macro instead of shift

 drivers/clk/Kconfig    |    4 ++
 drivers/clk/Makefile   |    1 +
 drivers/clk/clk-gate.c |   78 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/clk.h    |   13 ++++++++
 4 files changed, 96 insertions(+), 0 deletions(-)
 create mode 100644 drivers/clk/clk-gate.c

Comments

Grant Likely Sept. 25, 2011, 4:02 a.m. UTC | #1
On Thu, Sep 22, 2011 at 03:26:59PM -0700, Mike Turquette wrote:
> From: Jeremy Kerr <jeremy.kerr@canonical.com>
> 
> Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
> Signed-off-by: Jamie Iles <jamie@jamieiles.com>
> Signed-off-by: Mike Turquette <mturquette@ti.com>
> ---
> Changes since v1:
> Add copyright header
> Fold in Jamie's patch for set-to-disable clks
> Use BIT macro instead of shift
> 
>  drivers/clk/Kconfig    |    4 ++
>  drivers/clk/Makefile   |    1 +
>  drivers/clk/clk-gate.c |   78 ++++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/clk.h    |   13 ++++++++
>  4 files changed, 96 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/clk/clk-gate.c
> 
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index d8313d7..a78967c 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -12,3 +12,7 @@ config GENERIC_CLK
>  config GENERIC_CLK_FIXED
>  	bool
>  	depends on GENERIC_CLK
> +
> +config GENERIC_CLK_GATE
> +	bool
> +	depends on GENERIC_CLK

I see zero documentation on what a "gated clock" is supposed to be or
how it works, and there are zero comments in the code.  It's kind of
hard to review that way, and even harder to use.

g.
Mike Turquette Sept. 25, 2011, 5:27 a.m. UTC | #2
On Sat, Sep 24, 2011 at 9:02 PM, Grant Likely <grant.likely@secretlab.ca> wrote:
> On Thu, Sep 22, 2011 at 03:26:59PM -0700, Mike Turquette wrote:
>> From: Jeremy Kerr <jeremy.kerr@canonical.com>
>>
>> Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
>> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
>> Signed-off-by: Jamie Iles <jamie@jamieiles.com>
>> Signed-off-by: Mike Turquette <mturquette@ti.com>
>> ---
>> Changes since v1:
>> Add copyright header
>> Fold in Jamie's patch for set-to-disable clks
>> Use BIT macro instead of shift
>>
>>  drivers/clk/Kconfig    |    4 ++
>>  drivers/clk/Makefile   |    1 +
>>  drivers/clk/clk-gate.c |   78 ++++++++++++++++++++++++++++++++++++++++++++++++
>>  include/linux/clk.h    |   13 ++++++++
>>  4 files changed, 96 insertions(+), 0 deletions(-)
>>  create mode 100644 drivers/clk/clk-gate.c
>>
>> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
>> index d8313d7..a78967c 100644
>> --- a/drivers/clk/Kconfig
>> +++ b/drivers/clk/Kconfig
>> @@ -12,3 +12,7 @@ config GENERIC_CLK
>>  config GENERIC_CLK_FIXED
>>       bool
>>       depends on GENERIC_CLK
>> +
>> +config GENERIC_CLK_GATE
>> +     bool
>> +     depends on GENERIC_CLK
>
> I see zero documentation on what a "gated clock" is supposed to be or
> how it works, and there are zero comments in the code.  It's kind of
> hard to review that way, and even harder to use.

Will add Documentation and re-post.

Thanks,
Mike

> g.
>
Rob Herring Sept. 26, 2011, 6:33 p.m. UTC | #3
Mike,

On 09/22/2011 05:26 PM, Mike Turquette wrote:
> From: Jeremy Kerr <jeremy.kerr@canonical.com>
> 
> Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
> Signed-off-by: Jamie Iles <jamie@jamieiles.com>
> Signed-off-by: Mike Turquette <mturquette@ti.com>
> ---
> Changes since v1:
> Add copyright header
> Fold in Jamie's patch for set-to-disable clks
> Use BIT macro instead of shift
> 
>  drivers/clk/Kconfig    |    4 ++
>  drivers/clk/Makefile   |    1 +
>  drivers/clk/clk-gate.c |   78 ++++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/clk.h    |   13 ++++++++
>  4 files changed, 96 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/clk/clk-gate.c
> 
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index d8313d7..a78967c 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -12,3 +12,7 @@ config GENERIC_CLK
>  config GENERIC_CLK_FIXED
>  	bool
>  	depends on GENERIC_CLK
> +
> +config GENERIC_CLK_GATE
> +	bool
> +	depends on GENERIC_CLK
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index 9a3325a..d186446 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -2,3 +2,4 @@
>  obj-$(CONFIG_CLKDEV_LOOKUP)	+= clkdev.o
>  obj-$(CONFIG_GENERIC_CLK)	+= clk.o
>  obj-$(CONFIG_GENERIC_CLK_FIXED)	+= clk-fixed.o
> +obj-$(CONFIG_GENERIC_CLK_GATE)	+= clk-gate.o
> diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
> new file mode 100644
> index 0000000..a1d8e79
> --- /dev/null
> +++ b/drivers/clk/clk-gate.c
> @@ -0,0 +1,78 @@
> +/*
> + * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * Simple clk gate implementation
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/module.h>
> +#include <asm/io.h>

use linux/io.h

> +
> +#define to_clk_gate(clk) container_of(clk, struct clk_gate, hw)
> +
> +static unsigned long clk_gate_get_rate(struct clk_hw *clk)
> +{
> +	return clk_get_rate(clk_get_parent(clk->clk));
> +}
> +
> +static void clk_gate_set_bit(struct clk_hw *clk)
> +{
> +	struct clk_gate *gate = to_clk_gate(clk);
> +	u32 reg;
> +
> +	reg = __raw_readl(gate->reg);
> +	reg |= BIT(gate->bit_idx);
> +	__raw_writel(reg, gate->reg);

Don't these read-mod-writes need a spinlock around it?

It's possible to have an enable bits and dividers in the same register.
If you did a set_rate and while doing an enable/disable, there would be
a problem. Also, it may be 2 different clocks in the same register, so
the spinlock needs to be shared and not per clock.

> +}
> +
> +static void clk_gate_clear_bit(struct clk_hw *clk)
> +{
> +	struct clk_gate *gate = to_clk_gate(clk);
> +	u32 reg;
> +
> +	reg = __raw_readl(gate->reg);
> +	reg &= ~BIT(gate->bit_idx);
> +	__raw_writel(reg, gate->reg);
> +}
> +
> +static int clk_gate_enable_set(struct clk_hw *clk)
> +{
> +	clk_gate_set_bit(clk);
> +
> +	return 0;
> +}
> +
> +static void clk_gate_disable_clear(struct clk_hw *clk)
> +{
> +	clk_gate_clear_bit(clk);
> +}
> +
> +struct clk_hw_ops clk_gate_set_enable_ops = {

const?

> +	.recalc_rate = clk_gate_get_rate,
> +	.enable = clk_gate_enable_set,
> +	.disable = clk_gate_disable_clear,
> +};
> +EXPORT_SYMBOL_GPL(clk_gate_set_enable_ops);
> +
> +static int clk_gate_enable_clear(struct clk_hw *clk)
> +{
> +	clk_gate_clear_bit(clk);
> +
> +	return 0;
> +}
> +
> +static void clk_gate_disable_set(struct clk_hw *clk)
> +{
> +	clk_gate_set_bit(clk);
> +}

Are these wrapper functions really needed? Just assign set_bit and
clear_bit functions directly to the ops structs. Only the ops struct
name is exposed to the user.

> +
> +struct clk_hw_ops clk_gate_set_disable_ops = {

const?

Rob
Jamie Iles Sept. 26, 2011, 6:40 p.m. UTC | #4
Hi Rob,

On Mon, Sep 26, 2011 at 01:33:08PM -0500, Rob Herring wrote:
> Mike,
> 
> On 09/22/2011 05:26 PM, Mike Turquette wrote:
> > From: Jeremy Kerr <jeremy.kerr@canonical.com>
> > 
> > Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
> > Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
> > Signed-off-by: Jamie Iles <jamie@jamieiles.com>
> > Signed-off-by: Mike Turquette <mturquette@ti.com>
> > ---
> > Changes since v1:
> > Add copyright header
> > Fold in Jamie's patch for set-to-disable clks
> > Use BIT macro instead of shift
> > 
> >  drivers/clk/Kconfig    |    4 ++
> >  drivers/clk/Makefile   |    1 +
> >  drivers/clk/clk-gate.c |   78 ++++++++++++++++++++++++++++++++++++++++++++++++
> >  include/linux/clk.h    |   13 ++++++++
> >  4 files changed, 96 insertions(+), 0 deletions(-)
> >  create mode 100644 drivers/clk/clk-gate.c
> > 
> > diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> > index d8313d7..a78967c 100644
> > --- a/drivers/clk/Kconfig
> > +++ b/drivers/clk/Kconfig
> > @@ -12,3 +12,7 @@ config GENERIC_CLK
> >  config GENERIC_CLK_FIXED
> >  	bool
> >  	depends on GENERIC_CLK
> > +
> > +config GENERIC_CLK_GATE
> > +	bool
> > +	depends on GENERIC_CLK
> > diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> > index 9a3325a..d186446 100644
> > --- a/drivers/clk/Makefile
> > +++ b/drivers/clk/Makefile
> > @@ -2,3 +2,4 @@
> >  obj-$(CONFIG_CLKDEV_LOOKUP)	+= clkdev.o
> >  obj-$(CONFIG_GENERIC_CLK)	+= clk.o
> >  obj-$(CONFIG_GENERIC_CLK_FIXED)	+= clk-fixed.o
> > +obj-$(CONFIG_GENERIC_CLK_GATE)	+= clk-gate.o
> > diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
> > new file mode 100644
> > index 0000000..a1d8e79
> > --- /dev/null
> > +++ b/drivers/clk/clk-gate.c
> > @@ -0,0 +1,78 @@
> > +/*
> > + * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + *
> > + * Simple clk gate implementation
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/module.h>
> > +#include <asm/io.h>
> 
> use linux/io.h
> 
> > +
> > +#define to_clk_gate(clk) container_of(clk, struct clk_gate, hw)
> > +
> > +static unsigned long clk_gate_get_rate(struct clk_hw *clk)
> > +{
> > +	return clk_get_rate(clk_get_parent(clk->clk));
> > +}
> > +
> > +static void clk_gate_set_bit(struct clk_hw *clk)
> > +{
> > +	struct clk_gate *gate = to_clk_gate(clk);
> > +	u32 reg;
> > +
> > +	reg = __raw_readl(gate->reg);
> > +	reg |= BIT(gate->bit_idx);
> > +	__raw_writel(reg, gate->reg);
> 
> Don't these read-mod-writes need a spinlock around it?
> 
> It's possible to have an enable bits and dividers in the same register.
> If you did a set_rate and while doing an enable/disable, there would be
> a problem. Also, it may be 2 different clocks in the same register, so
> the spinlock needs to be shared and not per clock.

Well the prepare lock will be held here and I believe that would be 
sufficient.

> > +}
> > +
> > +static void clk_gate_clear_bit(struct clk_hw *clk)
> > +{
> > +	struct clk_gate *gate = to_clk_gate(clk);
> > +	u32 reg;
> > +
> > +	reg = __raw_readl(gate->reg);
> > +	reg &= ~BIT(gate->bit_idx);
> > +	__raw_writel(reg, gate->reg);
> > +}
> > +
> > +static int clk_gate_enable_set(struct clk_hw *clk)
> > +{
> > +	clk_gate_set_bit(clk);
> > +
> > +	return 0;
> > +}
> > +
> > +static void clk_gate_disable_clear(struct clk_hw *clk)
> > +{
> > +	clk_gate_clear_bit(clk);
> > +}
> > +
> > +struct clk_hw_ops clk_gate_set_enable_ops = {
> 
> const?

Yup.

> > +	.recalc_rate = clk_gate_get_rate,
> > +	.enable = clk_gate_enable_set,
> > +	.disable = clk_gate_disable_clear,
> > +};
> > +EXPORT_SYMBOL_GPL(clk_gate_set_enable_ops);
> > +
> > +static int clk_gate_enable_clear(struct clk_hw *clk)
> > +{
> > +	clk_gate_clear_bit(clk);
> > +
> > +	return 0;
> > +}
> > +
> > +static void clk_gate_disable_set(struct clk_hw *clk)
> > +{
> > +	clk_gate_set_bit(clk);
> > +}
> 
> Are these wrapper functions really needed? Just assign set_bit and
> clear_bit functions directly to the ops structs. Only the ops struct
> name is exposed to the user.

I used the wrappers because the .enable method has to return an int, but 
the disable needs to return void.  It's either that or open code the 
set/clear in each.

> > +
> > +struct clk_hw_ops clk_gate_set_disable_ops = {
> 
> const?

Yes.

Jamie
Rob Herring Sept. 26, 2011, 7:10 p.m. UTC | #5
On 09/26/2011 01:40 PM, Jamie Iles wrote:
> Hi Rob,
> 
> On Mon, Sep 26, 2011 at 01:33:08PM -0500, Rob Herring wrote:
>> Mike,
>>
>> On 09/22/2011 05:26 PM, Mike Turquette wrote:
>>> From: Jeremy Kerr <jeremy.kerr@canonical.com>
>>>
>>> Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
>>> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
>>> Signed-off-by: Jamie Iles <jamie@jamieiles.com>
>>> Signed-off-by: Mike Turquette <mturquette@ti.com>
>>> ---
>>> Changes since v1:
>>> Add copyright header
>>> Fold in Jamie's patch for set-to-disable clks
>>> Use BIT macro instead of shift
>>>
>>>  drivers/clk/Kconfig    |    4 ++
>>>  drivers/clk/Makefile   |    1 +
>>>  drivers/clk/clk-gate.c |   78 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>  include/linux/clk.h    |   13 ++++++++
>>>  4 files changed, 96 insertions(+), 0 deletions(-)
>>>  create mode 100644 drivers/clk/clk-gate.c
>>>
>>> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
>>> index d8313d7..a78967c 100644
>>> --- a/drivers/clk/Kconfig
>>> +++ b/drivers/clk/Kconfig
>>> @@ -12,3 +12,7 @@ config GENERIC_CLK
>>>  config GENERIC_CLK_FIXED
>>>  	bool
>>>  	depends on GENERIC_CLK
>>> +
>>> +config GENERIC_CLK_GATE
>>> +	bool
>>> +	depends on GENERIC_CLK
>>> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
>>> index 9a3325a..d186446 100644
>>> --- a/drivers/clk/Makefile
>>> +++ b/drivers/clk/Makefile
>>> @@ -2,3 +2,4 @@
>>>  obj-$(CONFIG_CLKDEV_LOOKUP)	+= clkdev.o
>>>  obj-$(CONFIG_GENERIC_CLK)	+= clk.o
>>>  obj-$(CONFIG_GENERIC_CLK_FIXED)	+= clk-fixed.o
>>> +obj-$(CONFIG_GENERIC_CLK_GATE)	+= clk-gate.o
>>> diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
>>> new file mode 100644
>>> index 0000000..a1d8e79
>>> --- /dev/null
>>> +++ b/drivers/clk/clk-gate.c
>>> @@ -0,0 +1,78 @@
>>> +/*
>>> + * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License version 2 as
>>> + * published by the Free Software Foundation.
>>> + *
>>> + * Simple clk gate implementation
>>> + */
>>> +
>>> +#include <linux/clk.h>
>>> +#include <linux/module.h>
>>> +#include <asm/io.h>
>>
>> use linux/io.h
>>
>>> +
>>> +#define to_clk_gate(clk) container_of(clk, struct clk_gate, hw)
>>> +
>>> +static unsigned long clk_gate_get_rate(struct clk_hw *clk)
>>> +{
>>> +	return clk_get_rate(clk_get_parent(clk->clk));
>>> +}
>>> +
>>> +static void clk_gate_set_bit(struct clk_hw *clk)
>>> +{
>>> +	struct clk_gate *gate = to_clk_gate(clk);
>>> +	u32 reg;
>>> +
>>> +	reg = __raw_readl(gate->reg);
>>> +	reg |= BIT(gate->bit_idx);
>>> +	__raw_writel(reg, gate->reg);
>>
>> Don't these read-mod-writes need a spinlock around it?
>>
>> It's possible to have an enable bits and dividers in the same register.
>> If you did a set_rate and while doing an enable/disable, there would be
>> a problem. Also, it may be 2 different clocks in the same register, so
>> the spinlock needs to be shared and not per clock.
> 
> Well the prepare lock will be held here and I believe that would be 
> sufficient.

No, the enable spinlock is protecting enable/disable. But set_rate is
protected by the prepare mutex. So you clearly don't need locking if you
have a register of only 1 bit enables. If you have a register accessed
by both enable/disable and prepare/unprepare/set_rate, then you need
some protection.


> 
>>> +}
>>> +
>>> +static void clk_gate_clear_bit(struct clk_hw *clk)
>>> +{
>>> +	struct clk_gate *gate = to_clk_gate(clk);
>>> +	u32 reg;
>>> +
>>> +	reg = __raw_readl(gate->reg);
>>> +	reg &= ~BIT(gate->bit_idx);
>>> +	__raw_writel(reg, gate->reg);
>>> +}
>>> +
>>> +static int clk_gate_enable_set(struct clk_hw *clk)
>>> +{
>>> +	clk_gate_set_bit(clk);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static void clk_gate_disable_clear(struct clk_hw *clk)
>>> +{
>>> +	clk_gate_clear_bit(clk);
>>> +}
>>> +
>>> +struct clk_hw_ops clk_gate_set_enable_ops = {
>>
>> const?
> 
> Yup.
> 
>>> +	.recalc_rate = clk_gate_get_rate,
>>> +	.enable = clk_gate_enable_set,
>>> +	.disable = clk_gate_disable_clear,
>>> +};
>>> +EXPORT_SYMBOL_GPL(clk_gate_set_enable_ops);
>>> +
>>> +static int clk_gate_enable_clear(struct clk_hw *clk)
>>> +{
>>> +	clk_gate_clear_bit(clk);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static void clk_gate_disable_set(struct clk_hw *clk)
>>> +{
>>> +	clk_gate_set_bit(clk);
>>> +}
>>
>> Are these wrapper functions really needed? Just assign set_bit and
>> clear_bit functions directly to the ops structs. Only the ops struct
>> name is exposed to the user.
> 
> I used the wrappers because the .enable method has to return an int, but 
> the disable needs to return void.  It's either that or open code the 
> set/clear in each.

Okay. I missed that detail...

Rob
Jamie Iles Sept. 26, 2011, 7:37 p.m. UTC | #6
On Mon, Sep 26, 2011 at 02:10:32PM -0500, Rob Herring wrote:
> On 09/26/2011 01:40 PM, Jamie Iles wrote:
> > On Mon, Sep 26, 2011 at 01:33:08PM -0500, Rob Herring wrote:
> >>> +static void clk_gate_set_bit(struct clk_hw *clk)
> >>> +{
> >>> +	struct clk_gate *gate = to_clk_gate(clk);
> >>> +	u32 reg;
> >>> +
> >>> +	reg = __raw_readl(gate->reg);
> >>> +	reg |= BIT(gate->bit_idx);
> >>> +	__raw_writel(reg, gate->reg);
> >>
> >> Don't these read-mod-writes need a spinlock around it?
> >>
> >> It's possible to have an enable bits and dividers in the same register.
> >> If you did a set_rate and while doing an enable/disable, there would be
> >> a problem. Also, it may be 2 different clocks in the same register, so
> >> the spinlock needs to be shared and not per clock.
> > 
> > Well the prepare lock will be held here and I believe that would be 
> > sufficient.
> 
> No, the enable spinlock is protecting enable/disable. But set_rate is
> protected by the prepare mutex. So you clearly don't need locking if you
> have a register of only 1 bit enables. If you have a register accessed
> by both enable/disable and prepare/unprepare/set_rate, then you need
> some protection.

OK fair point, but I would guess that if you had a clock like this then 
you probably wouldn't use this simple gated clock would you?  (speaking 
from my world where we have quite simple clocks ;-))

Jamie
Mike Turquette Sept. 26, 2011, 10:37 p.m. UTC | #7
On Mon, Sep 26, 2011 at 12:37 PM, Jamie Iles <jamie@jamieiles.com> wrote:
> On Mon, Sep 26, 2011 at 02:10:32PM -0500, Rob Herring wrote:
>> On 09/26/2011 01:40 PM, Jamie Iles wrote:
>> > On Mon, Sep 26, 2011 at 01:33:08PM -0500, Rob Herring wrote:
>> >>> +static void clk_gate_set_bit(struct clk_hw *clk)
>> >>> +{
>> >>> + struct clk_gate *gate = to_clk_gate(clk);
>> >>> + u32 reg;
>> >>> +
>> >>> + reg = __raw_readl(gate->reg);
>> >>> + reg |= BIT(gate->bit_idx);
>> >>> + __raw_writel(reg, gate->reg);
>> >>
>> >> Don't these read-mod-writes need a spinlock around it?
>> >>
>> >> It's possible to have an enable bits and dividers in the same register.
>> >> If you did a set_rate and while doing an enable/disable, there would be
>> >> a problem. Also, it may be 2 different clocks in the same register, so
>> >> the spinlock needs to be shared and not per clock.
>> >
>> > Well the prepare lock will be held here and I believe that would be
>> > sufficient.
>>
>> No, the enable spinlock is protecting enable/disable. But set_rate is
>> protected by the prepare mutex. So you clearly don't need locking if you
>> have a register of only 1 bit enables. If you have a register accessed
>> by both enable/disable and prepare/unprepare/set_rate, then you need
>> some protection.
>
> OK fair point, but I would guess that if you had a clock like this then
> you probably wouldn't use this simple gated clock would you?  (speaking
> from my world where we have quite simple clocks ;-))

I think it is a safe assumption that if a register controls both
enable/disable and some programmable divider then,

1) those controls are probably for the same clock
2) that clock won't be using the cookie-cutter gated-clock
implementation anyways

Rob, do you feel these assumptions are OK and locking can remain the
same in this patch?

Regards,
Mike

> Jamie
>
Rob Herring Sept. 26, 2011, 11:30 p.m. UTC | #8
On 09/26/2011 05:37 PM, Turquette, Mike wrote:
> On Mon, Sep 26, 2011 at 12:37 PM, Jamie Iles <jamie@jamieiles.com> wrote:
>> On Mon, Sep 26, 2011 at 02:10:32PM -0500, Rob Herring wrote:
>>> On 09/26/2011 01:40 PM, Jamie Iles wrote:
>>>> On Mon, Sep 26, 2011 at 01:33:08PM -0500, Rob Herring wrote:
>>>>>> +static void clk_gate_set_bit(struct clk_hw *clk)
>>>>>> +{
>>>>>> + struct clk_gate *gate = to_clk_gate(clk);
>>>>>> + u32 reg;
>>>>>> +
>>>>>> + reg = __raw_readl(gate->reg);
>>>>>> + reg |= BIT(gate->bit_idx);
>>>>>> + __raw_writel(reg, gate->reg);
>>>>>
>>>>> Don't these read-mod-writes need a spinlock around it?
>>>>>
>>>>> It's possible to have an enable bits and dividers in the same register.
>>>>> If you did a set_rate and while doing an enable/disable, there would be
>>>>> a problem. Also, it may be 2 different clocks in the same register, so
>>>>> the spinlock needs to be shared and not per clock.
>>>>
>>>> Well the prepare lock will be held here and I believe that would be
>>>> sufficient.
>>>
>>> No, the enable spinlock is protecting enable/disable. But set_rate is
>>> protected by the prepare mutex. So you clearly don't need locking if you
>>> have a register of only 1 bit enables. If you have a register accessed
>>> by both enable/disable and prepare/unprepare/set_rate, then you need
>>> some protection.
>>
>> OK fair point, but I would guess that if you had a clock like this then
>> you probably wouldn't use this simple gated clock would you?  (speaking
>> from my world where we have quite simple clocks ;-))
> 
> I think it is a safe assumption that if a register controls both
> enable/disable and some programmable divider then,
> 
> 1) those controls are probably for the same clock
> 2) that clock won't be using the cookie-cutter gated-clock
> implementation anyways

By definition of simple gated clock, the other bits have to be for
another clock. The restriction is that all the other bits can only be
clock gate bits.

> 
> Rob, do you feel these assumptions are OK and locking can remain the
> same in this patch?

Perhaps it is rare enough that it is not worth it use generic code in
this case. If so, the documentation should be clear about this
constraint. It is not something anyone will have hit before because
everyone used a single global lock. Now with the api being split between
2 locks, this adds a new complexity.

I think the simple gated clock code should be usable for any clock
controlled by a single bit in a 32-bit register independent of other
things in that register.

One example is MX1 in (mach-imx/clock-imx1.c). The CSCR register has
single bit enable for clk16m while hclk and clk48m have dividers in that
register.

Rob
Saravana Kannan Oct. 5, 2011, 1:41 a.m. UTC | #9
On 09/26/2011 04:30 PM, Rob Herring wrote:
> On 09/26/2011 05:37 PM, Turquette, Mike wrote:
>> On Mon, Sep 26, 2011 at 12:37 PM, Jamie Iles<jamie@jamieiles.com>  wrote:
>>> On Mon, Sep 26, 2011 at 02:10:32PM -0500, Rob Herring wrote:
>>>> On 09/26/2011 01:40 PM, Jamie Iles wrote:
>>>>> On Mon, Sep 26, 2011 at 01:33:08PM -0500, Rob Herring wrote:
>>>>>>> +static void clk_gate_set_bit(struct clk_hw *clk)
>>>>>>> +{
>>>>>>> + struct clk_gate *gate = to_clk_gate(clk);
>>>>>>> + u32 reg;
>>>>>>> +
>>>>>>> + reg = __raw_readl(gate->reg);
>>>>>>> + reg |= BIT(gate->bit_idx);
>>>>>>> + __raw_writel(reg, gate->reg);
>>>>>>
>>>>>> Don't these read-mod-writes need a spinlock around it?
>>>>>>
>>>>>> It's possible to have an enable bits and dividers in the same register.
>>>>>> If you did a set_rate and while doing an enable/disable, there would be
>>>>>> a problem. Also, it may be 2 different clocks in the same register, so
>>>>>> the spinlock needs to be shared and not per clock.
>>>>>
>>>>> Well the prepare lock will be held here and I believe that would be
>>>>> sufficient.
>>>>
>>>> No, the enable spinlock is protecting enable/disable. But set_rate is
>>>> protected by the prepare mutex. So you clearly don't need locking if you
>>>> have a register of only 1 bit enables. If you have a register accessed
>>>> by both enable/disable and prepare/unprepare/set_rate, then you need
>>>> some protection.
>>>
>>> OK fair point, but I would guess that if you had a clock like this then
>>> you probably wouldn't use this simple gated clock would you?  (speaking
>>> from my world where we have quite simple clocks ;-))
>>
>> I think it is a safe assumption that if a register controls both
>> enable/disable and some programmable divider then,
>>
>> 1) those controls are probably for the same clock
>> 2) that clock won't be using the cookie-cutter gated-clock
>> implementation anyways
>
> By definition of simple gated clock, the other bits have to be for
> another clock. The restriction is that all the other bits can only be
> clock gate bits.
>
>>
>> Rob, do you feel these assumptions are OK and locking can remain the
>> same in this patch?
>
> Perhaps it is rare enough that it is not worth it use generic code in
> this case. If so, the documentation should be clear about this
> constraint. It is not something anyone will have hit before because
> everyone used a single global lock. Now with the api being split between
> 2 locks, this adds a new complexity.

I kinda agree with Rob on this. There are very few, if any, such simple 
clocks on MSM chips. It's very easy to a SoC clock developer to 
accidentally use these simple clocks without realizing the point that 
Rob brings up.

> I think the simple gated clock code should be usable for any clock
> controlled by a single bit in a 32-bit register independent of other
> things in that register.

To take care of the scenario Rob bring up, the prepare/unprepare and 
enable/disable code will have to grab a per-tree register-lock before 
accessing any registers. The prepare/unprepare code should obviously be 
written to hold this register-lock for as small of a duration as 
possible. For example, if the prepare code is doing voltage increase, 
the register-lock should be grabber _after_ the voltage is increased. At 
least, this is approximately how the MSM clock code can be mapped onto 
this generic framework.

I think we should just go ahead and implement the per-tree register lock 
so that the generic clock implementations are more useful. The lock will 
really be held only for a very short time and hence shouldn't matter 
that there is a single lock for all the clocks in a tree.

Thomas,

Did you get a chance to send out your patches with support for per-tree 
locking? I would really like to see that as part of the first patch 
series that gets pulled in.

Thanks,
Saravana
Richard Zhao Oct. 12, 2011, 6:46 a.m. UTC | #10
On Thu, Sep 22, 2011 at 03:26:59PM -0700, Mike Turquette wrote:
> From: Jeremy Kerr <jeremy.kerr@canonical.com>
> 
> Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
> Signed-off-by: Jamie Iles <jamie@jamieiles.com>
> Signed-off-by: Mike Turquette <mturquette@ti.com>
> ---
> Changes since v1:
> Add copyright header
> Fold in Jamie's patch for set-to-disable clks
> Use BIT macro instead of shift
> 
>  drivers/clk/Kconfig    |    4 ++
>  drivers/clk/Makefile   |    1 +
>  drivers/clk/clk-gate.c |   78 ++++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/clk.h    |   13 ++++++++
>  4 files changed, 96 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/clk/clk-gate.c

I feel hard to tell the tree the clk parent, at register/init time. For the
simple gate clk, the only way is to set .get_parent. But normally, for clk
without any divider we set .get_parent to NULL. Maybe we can put .parent to
struct clk_hw?

Thanks
Richard
> 
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index d8313d7..a78967c 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -12,3 +12,7 @@ config GENERIC_CLK
>  config GENERIC_CLK_FIXED
>  	bool
>  	depends on GENERIC_CLK
> +
> +config GENERIC_CLK_GATE
> +	bool
> +	depends on GENERIC_CLK
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index 9a3325a..d186446 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -2,3 +2,4 @@
>  obj-$(CONFIG_CLKDEV_LOOKUP)	+= clkdev.o
>  obj-$(CONFIG_GENERIC_CLK)	+= clk.o
>  obj-$(CONFIG_GENERIC_CLK_FIXED)	+= clk-fixed.o
> +obj-$(CONFIG_GENERIC_CLK_GATE)	+= clk-gate.o
> diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
> new file mode 100644
> index 0000000..a1d8e79
> --- /dev/null
> +++ b/drivers/clk/clk-gate.c
> @@ -0,0 +1,78 @@
> +/*
> + * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * Simple clk gate implementation
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/module.h>
> +#include <asm/io.h>
> +
> +#define to_clk_gate(clk) container_of(clk, struct clk_gate, hw)
> +
> +static unsigned long clk_gate_get_rate(struct clk_hw *clk)
> +{
> +	return clk_get_rate(clk_get_parent(clk->clk));
> +}
> +
> +static void clk_gate_set_bit(struct clk_hw *clk)
> +{
> +	struct clk_gate *gate = to_clk_gate(clk);
> +	u32 reg;
> +
> +	reg = __raw_readl(gate->reg);
> +	reg |= BIT(gate->bit_idx);
> +	__raw_writel(reg, gate->reg);
> +}
> +
> +static void clk_gate_clear_bit(struct clk_hw *clk)
> +{
> +	struct clk_gate *gate = to_clk_gate(clk);
> +	u32 reg;
> +
> +	reg = __raw_readl(gate->reg);
> +	reg &= ~BIT(gate->bit_idx);
> +	__raw_writel(reg, gate->reg);
> +}
> +
> +static int clk_gate_enable_set(struct clk_hw *clk)
> +{
> +	clk_gate_set_bit(clk);
> +
> +	return 0;
> +}
> +
> +static void clk_gate_disable_clear(struct clk_hw *clk)
> +{
> +	clk_gate_clear_bit(clk);
> +}
> +
> +struct clk_hw_ops clk_gate_set_enable_ops = {
> +	.recalc_rate = clk_gate_get_rate,
> +	.enable = clk_gate_enable_set,
> +	.disable = clk_gate_disable_clear,
> +};
> +EXPORT_SYMBOL_GPL(clk_gate_set_enable_ops);
> +
> +static int clk_gate_enable_clear(struct clk_hw *clk)
> +{
> +	clk_gate_clear_bit(clk);
> +
> +	return 0;
> +}
> +
> +static void clk_gate_disable_set(struct clk_hw *clk)
> +{
> +	clk_gate_set_bit(clk);
> +}
> +
> +struct clk_hw_ops clk_gate_set_disable_ops = {
> +	.recalc_rate = clk_gate_get_rate,
> +	.enable = clk_gate_enable_clear,
> +	.disable = clk_gate_disable_set,
> +};
> +EXPORT_SYMBOL_GPL(clk_gate_set_disable_ops);
> diff --git a/include/linux/clk.h b/include/linux/clk.h
> index 1903dd8..626fd0d 100644
> --- a/include/linux/clk.h
> +++ b/include/linux/clk.h
> @@ -124,6 +124,19 @@ extern struct clk_hw_ops clk_fixed_ops;
>  
>  #endif /* CONFIG_GENERIC_CLK_FIXED */
>  
> +#ifdef CONFIG_GENERIC_CLK_GATE
> +
> +struct clk_gate {
> +	struct clk_hw	hw;
> +	void __iomem	*reg;
> +	u8		bit_idx;
> +};
> +
> +extern struct clk_hw_ops clk_gate_set_enable_ops;
> +extern struct clk_hw_ops clk_gate_set_disable_ops;
> +
> +#endif /* CONFIG_GENERIC_CLK_GATE */
> +
>  /**
>   * clk_register - register and initialize a new clock
>   *
> -- 
> 1.7.4.1
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
Mike Turquette Oct. 12, 2011, 2:59 p.m. UTC | #11
On Tue, Oct 11, 2011 at 11:46 PM, Richard Zhao
<richard.zhao@freescale.com> wrote:
> On Thu, Sep 22, 2011 at 03:26:59PM -0700, Mike Turquette wrote:
>> From: Jeremy Kerr <jeremy.kerr@canonical.com>
>>
>> Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
>> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
>> Signed-off-by: Jamie Iles <jamie@jamieiles.com>
>> Signed-off-by: Mike Turquette <mturquette@ti.com>
>> ---
>> Changes since v1:
>> Add copyright header
>> Fold in Jamie's patch for set-to-disable clks
>> Use BIT macro instead of shift
>>
>>  drivers/clk/Kconfig    |    4 ++
>>  drivers/clk/Makefile   |    1 +
>>  drivers/clk/clk-gate.c |   78 ++++++++++++++++++++++++++++++++++++++++++++++++
>>  include/linux/clk.h    |   13 ++++++++
>>  4 files changed, 96 insertions(+), 0 deletions(-)
>>  create mode 100644 drivers/clk/clk-gate.c
>
> I feel hard to tell the tree the clk parent, at register/init time. For the
> simple gate clk, the only way is to set .get_parent. But normally, for clk
> without any divider we set .get_parent to NULL. Maybe we can put .parent to
> struct clk_hw?

For non-mux clocks, whose parent is *always* going to be the same, you
should create a duplicate .parent in the clk_hw_* structure and then
have .get_parent return clk_hw_*->parent.

This is analogous to the way clk_hw_fixed returns clk_hw_fixed->rate
when .recalc is called on it.

Regards,
Mike

> Thanks
> Richard
>>
>> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
>> index d8313d7..a78967c 100644
>> --- a/drivers/clk/Kconfig
>> +++ b/drivers/clk/Kconfig
>> @@ -12,3 +12,7 @@ config GENERIC_CLK
>>  config GENERIC_CLK_FIXED
>>       bool
>>       depends on GENERIC_CLK
>> +
>> +config GENERIC_CLK_GATE
>> +     bool
>> +     depends on GENERIC_CLK
>> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
>> index 9a3325a..d186446 100644
>> --- a/drivers/clk/Makefile
>> +++ b/drivers/clk/Makefile
>> @@ -2,3 +2,4 @@
>>  obj-$(CONFIG_CLKDEV_LOOKUP)  += clkdev.o
>>  obj-$(CONFIG_GENERIC_CLK)    += clk.o
>>  obj-$(CONFIG_GENERIC_CLK_FIXED)      += clk-fixed.o
>> +obj-$(CONFIG_GENERIC_CLK_GATE)       += clk-gate.o
>> diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
>> new file mode 100644
>> index 0000000..a1d8e79
>> --- /dev/null
>> +++ b/drivers/clk/clk-gate.c
>> @@ -0,0 +1,78 @@
>> +/*
>> + * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * Simple clk gate implementation
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/module.h>
>> +#include <asm/io.h>
>> +
>> +#define to_clk_gate(clk) container_of(clk, struct clk_gate, hw)
>> +
>> +static unsigned long clk_gate_get_rate(struct clk_hw *clk)
>> +{
>> +     return clk_get_rate(clk_get_parent(clk->clk));
>> +}
>> +
>> +static void clk_gate_set_bit(struct clk_hw *clk)
>> +{
>> +     struct clk_gate *gate = to_clk_gate(clk);
>> +     u32 reg;
>> +
>> +     reg = __raw_readl(gate->reg);
>> +     reg |= BIT(gate->bit_idx);
>> +     __raw_writel(reg, gate->reg);
>> +}
>> +
>> +static void clk_gate_clear_bit(struct clk_hw *clk)
>> +{
>> +     struct clk_gate *gate = to_clk_gate(clk);
>> +     u32 reg;
>> +
>> +     reg = __raw_readl(gate->reg);
>> +     reg &= ~BIT(gate->bit_idx);
>> +     __raw_writel(reg, gate->reg);
>> +}
>> +
>> +static int clk_gate_enable_set(struct clk_hw *clk)
>> +{
>> +     clk_gate_set_bit(clk);
>> +
>> +     return 0;
>> +}
>> +
>> +static void clk_gate_disable_clear(struct clk_hw *clk)
>> +{
>> +     clk_gate_clear_bit(clk);
>> +}
>> +
>> +struct clk_hw_ops clk_gate_set_enable_ops = {
>> +     .recalc_rate = clk_gate_get_rate,
>> +     .enable = clk_gate_enable_set,
>> +     .disable = clk_gate_disable_clear,
>> +};
>> +EXPORT_SYMBOL_GPL(clk_gate_set_enable_ops);
>> +
>> +static int clk_gate_enable_clear(struct clk_hw *clk)
>> +{
>> +     clk_gate_clear_bit(clk);
>> +
>> +     return 0;
>> +}
>> +
>> +static void clk_gate_disable_set(struct clk_hw *clk)
>> +{
>> +     clk_gate_set_bit(clk);
>> +}
>> +
>> +struct clk_hw_ops clk_gate_set_disable_ops = {
>> +     .recalc_rate = clk_gate_get_rate,
>> +     .enable = clk_gate_enable_clear,
>> +     .disable = clk_gate_disable_set,
>> +};
>> +EXPORT_SYMBOL_GPL(clk_gate_set_disable_ops);
>> diff --git a/include/linux/clk.h b/include/linux/clk.h
>> index 1903dd8..626fd0d 100644
>> --- a/include/linux/clk.h
>> +++ b/include/linux/clk.h
>> @@ -124,6 +124,19 @@ extern struct clk_hw_ops clk_fixed_ops;
>>
>>  #endif /* CONFIG_GENERIC_CLK_FIXED */
>>
>> +#ifdef CONFIG_GENERIC_CLK_GATE
>> +
>> +struct clk_gate {
>> +     struct clk_hw   hw;
>> +     void __iomem    *reg;
>> +     u8              bit_idx;
>> +};
>> +
>> +extern struct clk_hw_ops clk_gate_set_enable_ops;
>> +extern struct clk_hw_ops clk_gate_set_disable_ops;
>> +
>> +#endif /* CONFIG_GENERIC_CLK_GATE */
>> +
>>  /**
>>   * clk_register - register and initialize a new clock
>>   *
>> --
>> 1.7.4.1
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>
>
>
Russell King - ARM Linux Oct. 13, 2011, 2:45 p.m. UTC | #12
On Thu, Sep 22, 2011 at 03:26:59PM -0700, Mike Turquette wrote:
> diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
> new file mode 100644
> index 0000000..a1d8e79
> --- /dev/null
> +++ b/drivers/clk/clk-gate.c
> @@ -0,0 +1,78 @@
> +/*
> + * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * Simple clk gate implementation
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/module.h>
> +#include <asm/io.h>

linux/io.h please.
Mike Turquette Oct. 13, 2011, 5:18 p.m. UTC | #13
On Thu, Oct 13, 2011 at 7:45 AM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Thu, Sep 22, 2011 at 03:26:59PM -0700, Mike Turquette wrote:
>> diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
>> new file mode 100644
>> index 0000000..a1d8e79
>> --- /dev/null
>> +++ b/drivers/clk/clk-gate.c
>> @@ -0,0 +1,78 @@
>> +/*
>> + * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * Simple clk gate implementation
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/module.h>
>> +#include <asm/io.h>
>
> linux/io.h please.
>

Will roll into v3.

Thanks for reviewing,
Mike
Sascha Hauer Oct. 16, 2011, 6:26 p.m. UTC | #14
On Wed, Oct 12, 2011 at 07:59:19AM -0700, Turquette, Mike wrote:
> On Tue, Oct 11, 2011 at 11:46 PM, Richard Zhao
> <richard.zhao@freescale.com> wrote:
> > On Thu, Sep 22, 2011 at 03:26:59PM -0700, Mike Turquette wrote:
> >> From: Jeremy Kerr <jeremy.kerr@canonical.com>
> >>
> >> Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
> >> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
> >> Signed-off-by: Jamie Iles <jamie@jamieiles.com>
> >> Signed-off-by: Mike Turquette <mturquette@ti.com>
> >> ---
> >> Changes since v1:
> >> Add copyright header
> >> Fold in Jamie's patch for set-to-disable clks
> >> Use BIT macro instead of shift
> >>
> >>  drivers/clk/Kconfig    |    4 ++
> >>  drivers/clk/Makefile   |    1 +
> >>  drivers/clk/clk-gate.c |   78 ++++++++++++++++++++++++++++++++++++++++++++++++
> >>  include/linux/clk.h    |   13 ++++++++
> >>  4 files changed, 96 insertions(+), 0 deletions(-)
> >>  create mode 100644 drivers/clk/clk-gate.c
> >
> > I feel hard to tell the tree the clk parent, at register/init time. For the
> > simple gate clk, the only way is to set .get_parent. But normally, for clk
> > without any divider we set .get_parent to NULL. Maybe we can put .parent to
> > struct clk_hw?
> 
> For non-mux clocks, whose parent is *always* going to be the same, you
> should create a duplicate .parent in the clk_hw_* structure and then
> have .get_parent return clk_hw_*->parent.

Maybe I do not understand what you mean here, but I think there is
something missing in the gate.

> 
> This is analogous to the way clk_hw_fixed returns clk_hw_fixed->rate
> when .recalc is called on it.
> 
> >> +
> >> +static unsigned long clk_gate_get_rate(struct clk_hw *clk)
> >> +{
> >> +     return clk_get_rate(clk_get_parent(clk->clk));
> >> +}

clk_get_parent goes down to clk_gate_set_enable_ops.get_parent below...

> >> +
> >> +
> >> +struct clk_hw_ops clk_gate_set_enable_ops = {
> >> +     .recalc_rate = clk_gate_get_rate,
> >> +     .enable = clk_gate_enable_set,
> >> +     .disable = clk_gate_disable_clear,
> >> +};

...but this does not have a get_parent pointer, so clk_get_parent()
for a gate always returns NULL which means that a gate never has
a valid rate.

Sascha
diff mbox

Patch

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index d8313d7..a78967c 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -12,3 +12,7 @@  config GENERIC_CLK
 config GENERIC_CLK_FIXED
 	bool
 	depends on GENERIC_CLK
+
+config GENERIC_CLK_GATE
+	bool
+	depends on GENERIC_CLK
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 9a3325a..d186446 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -2,3 +2,4 @@ 
 obj-$(CONFIG_CLKDEV_LOOKUP)	+= clkdev.o
 obj-$(CONFIG_GENERIC_CLK)	+= clk.o
 obj-$(CONFIG_GENERIC_CLK_FIXED)	+= clk-fixed.o
+obj-$(CONFIG_GENERIC_CLK_GATE)	+= clk-gate.o
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
new file mode 100644
index 0000000..a1d8e79
--- /dev/null
+++ b/drivers/clk/clk-gate.c
@@ -0,0 +1,78 @@ 
+/*
+ * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Simple clk gate implementation
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <asm/io.h>
+
+#define to_clk_gate(clk) container_of(clk, struct clk_gate, hw)
+
+static unsigned long clk_gate_get_rate(struct clk_hw *clk)
+{
+	return clk_get_rate(clk_get_parent(clk->clk));
+}
+
+static void clk_gate_set_bit(struct clk_hw *clk)
+{
+	struct clk_gate *gate = to_clk_gate(clk);
+	u32 reg;
+
+	reg = __raw_readl(gate->reg);
+	reg |= BIT(gate->bit_idx);
+	__raw_writel(reg, gate->reg);
+}
+
+static void clk_gate_clear_bit(struct clk_hw *clk)
+{
+	struct clk_gate *gate = to_clk_gate(clk);
+	u32 reg;
+
+	reg = __raw_readl(gate->reg);
+	reg &= ~BIT(gate->bit_idx);
+	__raw_writel(reg, gate->reg);
+}
+
+static int clk_gate_enable_set(struct clk_hw *clk)
+{
+	clk_gate_set_bit(clk);
+
+	return 0;
+}
+
+static void clk_gate_disable_clear(struct clk_hw *clk)
+{
+	clk_gate_clear_bit(clk);
+}
+
+struct clk_hw_ops clk_gate_set_enable_ops = {
+	.recalc_rate = clk_gate_get_rate,
+	.enable = clk_gate_enable_set,
+	.disable = clk_gate_disable_clear,
+};
+EXPORT_SYMBOL_GPL(clk_gate_set_enable_ops);
+
+static int clk_gate_enable_clear(struct clk_hw *clk)
+{
+	clk_gate_clear_bit(clk);
+
+	return 0;
+}
+
+static void clk_gate_disable_set(struct clk_hw *clk)
+{
+	clk_gate_set_bit(clk);
+}
+
+struct clk_hw_ops clk_gate_set_disable_ops = {
+	.recalc_rate = clk_gate_get_rate,
+	.enable = clk_gate_enable_clear,
+	.disable = clk_gate_disable_set,
+};
+EXPORT_SYMBOL_GPL(clk_gate_set_disable_ops);
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1903dd8..626fd0d 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -124,6 +124,19 @@  extern struct clk_hw_ops clk_fixed_ops;
 
 #endif /* CONFIG_GENERIC_CLK_FIXED */
 
+#ifdef CONFIG_GENERIC_CLK_GATE
+
+struct clk_gate {
+	struct clk_hw	hw;
+	void __iomem	*reg;
+	u8		bit_idx;
+};
+
+extern struct clk_hw_ops clk_gate_set_enable_ops;
+extern struct clk_hw_ops clk_gate_set_disable_ops;
+
+#endif /* CONFIG_GENERIC_CLK_GATE */
+
 /**
  * clk_register - register and initialize a new clock
  *