diff mbox

[v3,02/11] clk: davinci - add PSC clock driver

Message ID 1351181518-11882-3-git-send-email-m-karicheri2@ti.com (mailing list archive)
State New, archived
Headers show

Commit Message

Murali Karicheri Oct. 25, 2012, 4:11 p.m. UTC
This is the driver for the Power Sleep Controller (PSC) hardware
found on DM SoCs as well Keystone SoCs (c6x). This driver borrowed
code from arch/arm/mach-davinci/psc.c and implemented the driver
as per common clock provider API. The PSC module is responsible for
enabling/disabling the Power Domain and Clock domain for different IPs
present in the SoC. The driver is configured through the clock data
passed to the driver through struct clk_psc_data.

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
---
 drivers/clk/davinci/clk-psc.c |  207 +++++++++++++++++++++++++++++++++++++++++
 drivers/clk/davinci/clk-psc.h |   46 +++++++++
 2 files changed, 253 insertions(+)
 create mode 100644 drivers/clk/davinci/clk-psc.c
 create mode 100644 drivers/clk/davinci/clk-psc.h

Comments

Linus Walleij Oct. 28, 2012, 7:24 p.m. UTC | #1
On Thu, Oct 25, 2012 at 6:11 PM, Murali Karicheri <m-karicheri2@ti.com> wrote:

> This is the driver for the Power Sleep Controller (PSC) hardware
> found on DM SoCs as well Keystone SoCs (c6x). This driver borrowed
> code from arch/arm/mach-davinci/psc.c and implemented the driver
> as per common clock provider API. The PSC module is responsible for
> enabling/disabling the Power Domain and Clock domain for different IPs
> present in the SoC. The driver is configured through the clock data
> passed to the driver through struct clk_psc_data.
>
> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Here is some pedantic stuff if you're really bored:

> diff --git a/drivers/clk/davinci/clk-psc.c b/drivers/clk/davinci/clk-psc.c
(...)
> +               ptcmd = 1 << domain;

ptcmd = BIT(domain);

> +               pdctl = readl(psc_base + PDCTL + 4 * domain);
> +               pdctl |= 0x100;

pdctl |= BIT(8); /* and here a comment explaing what on earth that means */

> +       } else {
> +               ptcmd = 1 << domain;

ptcmd = BIT(domain);

Yours,
Linus Walleij
Murali Karicheri Oct. 31, 2012, 1:23 p.m. UTC | #2
On 10/28/2012 03:24 PM, Linus Walleij wrote:
> On Thu, Oct 25, 2012 at 6:11 PM, Murali Karicheri <m-karicheri2@ti.com> wrote:
>
>> This is the driver for the Power Sleep Controller (PSC) hardware
>> found on DM SoCs as well Keystone SoCs (c6x). This driver borrowed
>> code from arch/arm/mach-davinci/psc.c and implemented the driver
>> as per common clock provider API. The PSC module is responsible for
>> enabling/disabling the Power Domain and Clock domain for different IPs
>> present in the SoC. The driver is configured through the clock data
>> passed to the driver through struct clk_psc_data.
>>
>> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
> Acked-by: Linus Walleij <linus.walleij@linaro.org>
>
> Here is some pedantic stuff if you're really bored:
>
>> diff --git a/drivers/clk/davinci/clk-psc.c b/drivers/clk/davinci/clk-psc.c
> (...)
>> +               ptcmd = 1 << domain;
> ptcmd = BIT(domain);
>
>> +               pdctl = readl(psc_base + PDCTL + 4 * domain);
>> +               pdctl |= 0x100;
> pdctl |= BIT(8); /* and here a comment explaing what on earth that means */
>
>> +       } else {
>> +               ptcmd = 1 << domain;
> ptcmd = BIT(domain);
>
> Yours,
> Linus Walleij
>
>
Linus,

Thanks. I will fix the above and add your Acked-by in the next revision 
of the patch.

Murali
Sekhar Nori Nov. 3, 2012, 12:07 p.m. UTC | #3
On 10/25/2012 9:41 PM, Murali Karicheri wrote:
> This is the driver for the Power Sleep Controller (PSC) hardware
> found on DM SoCs as well Keystone SoCs (c6x). This driver borrowed
> code from arch/arm/mach-davinci/psc.c and implemented the driver
> as per common clock provider API. The PSC module is responsible for
> enabling/disabling the Power Domain and Clock domain for different IPs
> present in the SoC. The driver is configured through the clock data
> passed to the driver through struct clk_psc_data.
> 
> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
> ---

> +/**
> + * struct clk_psc - DaVinci PSC clock driver data
> + *
> + * @hw: clk_hw for the psc
> + * @psc_data: Driver specific data
> + */
> +struct clk_psc {
> +	struct clk_hw hw;
> +	struct clk_psc_data *psc_data;

> +	spinlock_t *lock;

Unused member? I don't see this being used.

Thanks,
Sekhar
Murali Karicheri Nov. 5, 2012, 3:10 p.m. UTC | #4
On 11/03/2012 08:07 AM, Sekhar Nori wrote:
> On 10/25/2012 9:41 PM, Murali Karicheri wrote:
>> This is the driver for the Power Sleep Controller (PSC) hardware
>> found on DM SoCs as well Keystone SoCs (c6x). This driver borrowed
>> code from arch/arm/mach-davinci/psc.c and implemented the driver
>> as per common clock provider API. The PSC module is responsible for
>> enabling/disabling the Power Domain and Clock domain for different IPs
>> present in the SoC. The driver is configured through the clock data
>> passed to the driver through struct clk_psc_data.
>>
>> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>> ---
>> +/**
>> + * struct clk_psc - DaVinci PSC clock driver data
>> + *
>> + * @hw: clk_hw for the psc
>> + * @psc_data: Driver specific data
>> + */
>> +struct clk_psc {
>> +	struct clk_hw hw;
>> +	struct clk_psc_data *psc_data;
>> +	spinlock_t *lock;
> Unused member? I don't see this being used.

OK. Will remove.
>
> Thanks,
> Sekhar
>
Mike Turquette Nov. 10, 2012, 2:22 a.m. UTC | #5
Quoting Murali Karicheri (2012-11-05 07:10:52)
> On 11/03/2012 08:07 AM, Sekhar Nori wrote:
> > On 10/25/2012 9:41 PM, Murali Karicheri wrote:
> >> This is the driver for the Power Sleep Controller (PSC) hardware
> >> found on DM SoCs as well Keystone SoCs (c6x). This driver borrowed
> >> code from arch/arm/mach-davinci/psc.c and implemented the driver
> >> as per common clock provider API. The PSC module is responsible for
> >> enabling/disabling the Power Domain and Clock domain for different IPs
> >> present in the SoC. The driver is configured through the clock data
> >> passed to the driver through struct clk_psc_data.
> >>
> >> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
> >> ---
> >> +/**
> >> + * struct clk_psc - DaVinci PSC clock driver data
> >> + *
> >> + * @hw: clk_hw for the psc
> >> + * @psc_data: Driver specific data
> >> + */
> >> +struct clk_psc {
> >> +    struct clk_hw hw;
> >> +    struct clk_psc_data *psc_data;
> >> +    spinlock_t *lock;
> > Unused member? I don't see this being used.
> 
> OK. Will remove.

Those locks are only used for the case where a register might contain
bits for several clocks.  Thus RMW operations are protected.  On OMAP
this isn't necessary due to a very generous register layout (typically
one 32-bit reg per module) controlling clocks.  Seems tha tmaybe this is
not needed for PSC module either?

Regards,
Mike

> >
> > Thanks,
> > Sekhar
> >
Sekhar Nori Nov. 27, 2012, 3:05 p.m. UTC | #6
Hi Mike,

On 11/10/2012 7:52 AM, Mike Turquette wrote:
> Quoting Murali Karicheri (2012-11-05 07:10:52)
>> On 11/03/2012 08:07 AM, Sekhar Nori wrote:
>>> On 10/25/2012 9:41 PM, Murali Karicheri wrote:
>>>> This is the driver for the Power Sleep Controller (PSC) hardware
>>>> found on DM SoCs as well Keystone SoCs (c6x). This driver borrowed
>>>> code from arch/arm/mach-davinci/psc.c and implemented the driver
>>>> as per common clock provider API. The PSC module is responsible for
>>>> enabling/disabling the Power Domain and Clock domain for different IPs
>>>> present in the SoC. The driver is configured through the clock data
>>>> passed to the driver through struct clk_psc_data.
>>>>
>>>> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>>>> ---
>>>> +/**
>>>> + * struct clk_psc - DaVinci PSC clock driver data
>>>> + *
>>>> + * @hw: clk_hw for the psc
>>>> + * @psc_data: Driver specific data
>>>> + */
>>>> +struct clk_psc {
>>>> +    struct clk_hw hw;
>>>> +    struct clk_psc_data *psc_data;
>>>> +    spinlock_t *lock;
>>> Unused member? I don't see this being used.
>>
>> OK. Will remove.
> 
> Those locks are only used for the case where a register might contain
> bits for several clocks.  Thus RMW operations are protected.  On OMAP
> this isn't necessary due to a very generous register layout (typically
> one 32-bit reg per module) controlling clocks.  Seems tha tmaybe this is
> not needed for PSC module either?

Sorry about the late reply. The above is not totally true for PSC. There
are some registers (like PTCMD) which are common for all clocks.

There is an enable_lock used in drivers/clk/clk.c which serializes all
enable/disable calls across the clock tree. Since that is done, further
locking at clk-psc level is not really needed, no?

Thanks,
Sekhar
Mike Turquette Nov. 27, 2012, 5:29 p.m. UTC | #7
Quoting Sekhar Nori (2012-11-27 07:05:21)
> Hi Mike,
> 
> On 11/10/2012 7:52 AM, Mike Turquette wrote:
> > Quoting Murali Karicheri (2012-11-05 07:10:52)
> >> On 11/03/2012 08:07 AM, Sekhar Nori wrote:
> >>> On 10/25/2012 9:41 PM, Murali Karicheri wrote:
> >>>> This is the driver for the Power Sleep Controller (PSC) hardware
> >>>> found on DM SoCs as well Keystone SoCs (c6x). This driver borrowed
> >>>> code from arch/arm/mach-davinci/psc.c and implemented the driver
> >>>> as per common clock provider API. The PSC module is responsible for
> >>>> enabling/disabling the Power Domain and Clock domain for different IPs
> >>>> present in the SoC. The driver is configured through the clock data
> >>>> passed to the driver through struct clk_psc_data.
> >>>>
> >>>> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
> >>>> ---
> >>>> +/**
> >>>> + * struct clk_psc - DaVinci PSC clock driver data
> >>>> + *
> >>>> + * @hw: clk_hw for the psc
> >>>> + * @psc_data: Driver specific data
> >>>> + */
> >>>> +struct clk_psc {
> >>>> +    struct clk_hw hw;
> >>>> +    struct clk_psc_data *psc_data;
> >>>> +    spinlock_t *lock;
> >>> Unused member? I don't see this being used.
> >>
> >> OK. Will remove.
> > 
> > Those locks are only used for the case where a register might contain
> > bits for several clocks.  Thus RMW operations are protected.  On OMAP
> > this isn't necessary due to a very generous register layout (typically
> > one 32-bit reg per module) controlling clocks.  Seems tha tmaybe this is
> > not needed for PSC module either?
> 
> Sorry about the late reply. The above is not totally true for PSC. There
> are some registers (like PTCMD) which are common for all clocks.
> 
> There is an enable_lock used in drivers/clk/clk.c which serializes all
> enable/disable calls across the clock tree. Since that is done, further
> locking at clk-psc level is not really needed, no?
> 

I haven't finished looking through the PSC design document yet, but my
answer to your question is this:

If a register is only used for clk_enable/disable calls (not touched by
anything held under the prepare_lock mutex) and if that register isn't
used anywhere else in the code (outside of the clk framework) then yes,
the enable_lock spinlock is enough for you.

Also have you looked into regmap?  Since you are defining your own clock
type that might be something nice for you.

Regards,
Mike

> Thanks,
> Sekhar
Murali Karicheri Nov. 27, 2012, 8:38 p.m. UTC | #8
On 11/27/2012 12:29 PM, Mike Turquette wrote:
> Quoting Sekhar Nori (2012-11-27 07:05:21)
>> Hi Mike,
>>
>> On 11/10/2012 7:52 AM, Mike Turquette wrote:
>>> Quoting Murali Karicheri (2012-11-05 07:10:52)
>>>> On 11/03/2012 08:07 AM, Sekhar Nori wrote:
>>>>> On 10/25/2012 9:41 PM, Murali Karicheri wrote:
>>>>>> This is the driver for the Power Sleep Controller (PSC) hardware
>>>>>> found on DM SoCs as well Keystone SoCs (c6x). This driver borrowed
>>>>>> code from arch/arm/mach-davinci/psc.c and implemented the driver
>>>>>> as per common clock provider API. The PSC module is responsible for
>>>>>> enabling/disabling the Power Domain and Clock domain for different IPs
>>>>>> present in the SoC. The driver is configured through the clock data
>>>>>> passed to the driver through struct clk_psc_data.
>>>>>>
>>>>>> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>>>>>> ---
>>>>>> +/**
>>>>>> + * struct clk_psc - DaVinci PSC clock driver data
>>>>>> + *
>>>>>> + * @hw: clk_hw for the psc
>>>>>> + * @psc_data: Driver specific data
>>>>>> + */
>>>>>> +struct clk_psc {
>>>>>> +    struct clk_hw hw;
>>>>>> +    struct clk_psc_data *psc_data;
>>>>>> +    spinlock_t *lock;
>>>>> Unused member? I don't see this being used.
>>>> OK. Will remove.
>>> Those locks are only used for the case where a register might contain
>>> bits for several clocks.  Thus RMW operations are protected.  On OMAP
>>> this isn't necessary due to a very generous register layout (typically
>>> one 32-bit reg per module) controlling clocks.  Seems tha tmaybe this is
>>> not needed for PSC module either?
>> Sorry about the late reply. The above is not totally true for PSC. There
>> are some registers (like PTCMD) which are common for all clocks.
>>
>> There is an enable_lock used in drivers/clk/clk.c which serializes all
>> enable/disable calls across the clock tree. Since that is done, further
>> locking at clk-psc level is not really needed, no?
>>
> I haven't finished looking through the PSC design document yet, but my
> answer to your question is this:
>
> If a register is only used for clk_enable/disable calls (not touched by
> anything held under the prepare_lock mutex) and if that register isn't
> used anywhere else in the code (outside of the clk framework) then yes,
> the enable_lock spinlock is enough for you.
The psc clocks share registers such as PTCMD in addition to the clock 
specific register. So if there are multiple concurrent paths to 
clk_enable()/clk_disable() possible, then PTCMD write is not protected 
through the main enable()/disable() lock. Now I am not sure if there are 
multiple concurrent paths possible such as invoking the API in the 
context of a user process, kernel thread etc. If this is a possibility
then IMO, a lock is needed.

Murali
> Also have you looked into regmap?  Since you are defining your own clock
> type that might be something nice for you.
>
> Regards,
> Mike
>
>> Thanks,
>> Sekhar
>
Sekhar Nori Nov. 28, 2012, 1:22 p.m. UTC | #9
On 11/27/2012 10:59 PM, Mike Turquette wrote:
> Quoting Sekhar Nori (2012-11-27 07:05:21)
>> Hi Mike,
>>
>> On 11/10/2012 7:52 AM, Mike Turquette wrote:
>>> Quoting Murali Karicheri (2012-11-05 07:10:52)
>>>> On 11/03/2012 08:07 AM, Sekhar Nori wrote:
>>>>> On 10/25/2012 9:41 PM, Murali Karicheri wrote:
>>>>>> This is the driver for the Power Sleep Controller (PSC) hardware
>>>>>> found on DM SoCs as well Keystone SoCs (c6x). This driver borrowed
>>>>>> code from arch/arm/mach-davinci/psc.c and implemented the driver
>>>>>> as per common clock provider API. The PSC module is responsible for
>>>>>> enabling/disabling the Power Domain and Clock domain for different IPs
>>>>>> present in the SoC. The driver is configured through the clock data
>>>>>> passed to the driver through struct clk_psc_data.
>>>>>>
>>>>>> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>>>>>> ---
>>>>>> +/**
>>>>>> + * struct clk_psc - DaVinci PSC clock driver data
>>>>>> + *
>>>>>> + * @hw: clk_hw for the psc
>>>>>> + * @psc_data: Driver specific data
>>>>>> + */
>>>>>> +struct clk_psc {
>>>>>> +    struct clk_hw hw;
>>>>>> +    struct clk_psc_data *psc_data;
>>>>>> +    spinlock_t *lock;
>>>>> Unused member? I don't see this being used.
>>>>
>>>> OK. Will remove.
>>>
>>> Those locks are only used for the case where a register might contain
>>> bits for several clocks.  Thus RMW operations are protected.  On OMAP
>>> this isn't necessary due to a very generous register layout (typically
>>> one 32-bit reg per module) controlling clocks.  Seems tha tmaybe this is
>>> not needed for PSC module either?
>>
>> Sorry about the late reply. The above is not totally true for PSC. There
>> are some registers (like PTCMD) which are common for all clocks.
>>
>> There is an enable_lock used in drivers/clk/clk.c which serializes all
>> enable/disable calls across the clock tree. Since that is done, further
>> locking at clk-psc level is not really needed, no?
>>
> 
> I haven't finished looking through the PSC design document yet, but my
> answer to your question is this:
> 
> If a register is only used for clk_enable/disable calls (not touched by

This is right, all PSC registers are only touched in clk_enable/disable
calls. clk-psc.c also populates .is_enabled, but that's only a regsiter
read anyway. Plus looks like even that is always accessed under enable_lock.

> anything held under the prepare_lock mutex) and if that register isn't

The requirement that these registers should not be touched when held
under prepare_lock mutex is not met because functions like
clk_disabled_unused_subtree() which are called under prepare_lock mutex
will end up calling clk_disable() anyway.

Perhaps you meant: not touched by anything under 'prepare_lock' mutex
while being outside of the 'enable_lock' spinlock?

> used anywhere else in the code (outside of the clk framework) then yes,
> the enable_lock spinlock is enough for you.

No, they are not accessed out side of clk framework. At least currently.
PSC can also be used to provide a "reset" to some IPs, but there is no
"reset framework" which uses this feature.

> Also have you looked into regmap?  Since you are defining your own clock
> type that might be something nice for you.

No, haven't looked at regmap yet. Will look at that.

Thanks,
Sekhar
Sekhar Nori March 19, 2013, 10:57 a.m. UTC | #10
On 10/29/2012 12:54 AM, Linus Walleij wrote:
> On Thu, Oct 25, 2012 at 6:11 PM, Murali Karicheri <m-karicheri2@ti.com> wrote:
> 
>> This is the driver for the Power Sleep Controller (PSC) hardware
>> found on DM SoCs as well Keystone SoCs (c6x). This driver borrowed
>> code from arch/arm/mach-davinci/psc.c and implemented the driver
>> as per common clock provider API. The PSC module is responsible for
>> enabling/disabling the Power Domain and Clock domain for different IPs
>> present in the SoC. The driver is configured through the clock data
>> passed to the driver through struct clk_psc_data.
>>
>> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
> 
> Acked-by: Linus Walleij <linus.walleij@linaro.org>
> 
> Here is some pedantic stuff if you're really bored:
> 
>> diff --git a/drivers/clk/davinci/clk-psc.c b/drivers/clk/davinci/clk-psc.c
> (...)
>> +               ptcmd = 1 << domain;
> 
> ptcmd = BIT(domain);
> 
>> +               pdctl = readl(psc_base + PDCTL + 4 * domain);
>> +               pdctl |= 0x100;
> 
> pdctl |= BIT(8); /* and here a comment explaing what on earth that means */

It turns out this piece of code is superfluous and the exact same thing
is being done again just down below.

Thanks,
Sekhar
Sekhar Nori March 22, 2013, 11:20 a.m. UTC | #11
Mike,

On 11/28/2012 6:52 PM, Sekhar Nori wrote:
> On 11/27/2012 10:59 PM, Mike Turquette wrote:

>> Also have you looked into regmap?  Since you are defining your own clock
>> type that might be something nice for you.
> 
> No, haven't looked at regmap yet. Will look at that.

I could get to this only now. regmap needs a valid struct device. We
aren't modelling psc clocks as device so regmap cannot be used here.

Thanks,
Sekhar
Mike Turquette March 22, 2013, 8:37 p.m. UTC | #12
Quoting Sekhar Nori (2013-03-22 04:20:28)
> Mike,
> 
> On 11/28/2012 6:52 PM, Sekhar Nori wrote:
> > On 11/27/2012 10:59 PM, Mike Turquette wrote:
> 
> >> Also have you looked into regmap?  Since you are defining your own clock
> >> type that might be something nice for you.
> > 
> > No, haven't looked at regmap yet. Will look at that.
> 
> I could get to this only now. regmap needs a valid struct device. We
> aren't modelling psc clocks as device so regmap cannot be used here.
> 

According to Murali's reply back in November it was still not known if
the PTCMD register was going to be concurrently accessed by sources
outside the clock framework.  If this is so then neither the existing
framework-level lock (e.g. enable_lock) nor the shared clock driver lock
(e.g. spinlock in struct clk_psc) are adequate.  You may need a device
driver which represents the PSC and use accessor functions to write to
those register which provide coordination.

Regards,
Mike

> Thanks,
> Sekhar
Sekhar Nori March 25, 2013, 6:50 a.m. UTC | #13
Hi Mike,

On 3/23/2013 2:07 AM, Mike Turquette wrote:
> Quoting Sekhar Nori (2013-03-22 04:20:28)
>> Mike,
>>
>> On 11/28/2012 6:52 PM, Sekhar Nori wrote:
>>> On 11/27/2012 10:59 PM, Mike Turquette wrote:
>>
>>>> Also have you looked into regmap?  Since you are defining your own clock
>>>> type that might be something nice for you.
>>>
>>> No, haven't looked at regmap yet. Will look at that.
>>
>> I could get to this only now. regmap needs a valid struct device. We
>> aren't modelling psc clocks as device so regmap cannot be used here.
>>
> 
> According to Murali's reply back in November it was still not known if
> the PTCMD register was going to be concurrently accessed by sources
> outside the clock framework.  If this is so then neither the existing

I can confirm that PTCMD is a PSC specific register and it is not
accessed outside of clock framework.

> framework-level lock (e.g. enable_lock) nor the shared clock driver lock
> (e.g. spinlock in struct clk_psc) are adequate.  You may need a device
> driver which represents the PSC and use accessor functions to write to
> those register which provide coordination.

Well the only reason to access *any* PSC register outside of clock
framework would be to handle the corner case where DSP needs to be reset
using its PSC.

In this case, there needs to be an access to MDCTL register specific to
that module (ie the DSP). Right now this functionality is implemented
using the function davinci_psc_reset().

When moving to common clock framework, I think this can be moved to
drivers/clk/davinci/clk-psc.c (it will be similar to the way
tegra_periph_reset() is handled in drivers/clk/tegra/clk-periph-gate.c).

And in this case I do agree we need a spinlock local to clk-psc.c (like
the periph_ref_lock spinlock used in tegra implementation). That said,
the current series only enables DM644x and does not really implement the
reset stuff needed for DA850. So we can either add the spinlock now, or
defer it to later when DA850 get supported (so there is a clear history
trace of why it was added).

Thanks,
Sekhar
diff mbox

Patch

diff --git a/drivers/clk/davinci/clk-psc.c b/drivers/clk/davinci/clk-psc.c
new file mode 100644
index 0000000..40d5f06
--- /dev/null
+++ b/drivers/clk/davinci/clk-psc.c
@@ -0,0 +1,207 @@ 
+/*
+ * PSC clk driver for DaVinci devices
+ *
+ * Copyright (C) 2006-2012 Texas Instruments.
+ * Copyright (C) 2008-2009 Deep Root Systems, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include "clk-psc.h"
+
+/* PSC register offsets */
+#define EPCPR				0x070
+#define PTCMD				0x120
+#define PTSTAT				0x128
+#define PDSTAT				0x200
+#define PDCTL				0x300
+#define MDSTAT				0x800
+#define MDCTL				0xA00
+
+/* PSC module states */
+#define PSC_STATE_SWRSTDISABLE		0
+#define PSC_STATE_SYNCRST		1
+#define PSC_STATE_DISABLE		2
+#define PSC_STATE_ENABLE		3
+
+#define MDSTAT_STATE_MASK		0x3f
+#define PDSTAT_STATE_MASK		0x1f
+#define MDCTL_FORCE			BIT(31)
+#define PDCTL_NEXT			BIT(0)
+#define PDCTL_EPCGOOD			BIT(8)
+
+/**
+ * struct clk_psc - DaVinci PSC clock driver data
+ *
+ * @hw: clk_hw for the psc
+ * @psc_data: Driver specific data
+ */
+struct clk_psc {
+	struct clk_hw hw;
+	struct clk_psc_data *psc_data;
+	spinlock_t *lock;
+};
+
+#define to_clk_psc(_hw) container_of(_hw, struct clk_psc, hw)
+
+/**
+ * clk_psc_config() - configure psc hardware
+ *
+ * @base: io mapped base address of the psc
+ * @domain: Power Domain id of the module
+ * @id: lpsc id
+ * @enable: 1 - enable psc, 0 - disable psc
+ * @flags: psc driver specific flags
+ */
+static void clk_psc_config(void __iomem *base, unsigned int domain,
+		unsigned int id, bool enable, u32 flags)
+{
+	u32 epcpr, ptcmd, ptstat, pdstat, pdctl, mdstat, mdctl;
+	u32 next_state = PSC_STATE_ENABLE;
+	void __iomem *psc_base = base;
+
+	if (!enable) {
+		if (flags & CLK_PSC_SWRSTDISABLE)
+			next_state = PSC_STATE_SWRSTDISABLE;
+		else
+			next_state = PSC_STATE_DISABLE;
+	}
+
+	mdctl = readl(psc_base + MDCTL + 4 * id);
+	mdctl &= ~MDSTAT_STATE_MASK;
+	mdctl |= next_state;
+	if (flags & CLK_PSC_FORCE)
+		mdctl |= MDCTL_FORCE;
+	writel(mdctl, psc_base + MDCTL + 4 * id);
+
+	pdstat = readl(psc_base + PDSTAT + 4 * domain);
+	if ((pdstat & PDSTAT_STATE_MASK) == 0) {
+		pdctl = readl(psc_base + PDCTL + 4 * domain);
+		pdctl |= PDCTL_NEXT;
+		writel(pdctl, psc_base + PDCTL + 4 * domain);
+
+		ptcmd = 1 << domain;
+		writel(ptcmd, psc_base + PTCMD);
+
+		if (flags & CLK_PSC_HAS_EXT_POWER_CNTL) {
+			do {
+				epcpr = readl(psc_base + EPCPR);
+			} while ((((epcpr >> domain) & 1) == 0));
+		}
+
+		pdctl = readl(psc_base + PDCTL + 4 * domain);
+		pdctl |= 0x100;
+		writel(pdctl, psc_base + PDCTL + 4 * domain);
+
+		pdctl = readl(psc_base + PDCTL + 4 * domain);
+		pdctl |= PDCTL_EPCGOOD;
+		writel(pdctl, psc_base + PDCTL + 4 * domain);
+	} else {
+		ptcmd = 1 << domain;
+		writel(ptcmd, psc_base + PTCMD);
+	}
+
+	do {
+		ptstat = readl(psc_base + PTSTAT);
+	} while (!(((ptstat >> domain) & 1) == 0));
+
+	do {
+		mdstat = readl(psc_base + MDSTAT + 4 * id);
+	} while (!((mdstat & MDSTAT_STATE_MASK) == next_state));
+}
+
+/**
+ * clk_psc_is_enabled() - Is psc clock enabled
+ *
+ * @hw: clk hw for the psc
+ */
+static int clk_psc_is_enabled(struct clk_hw *hw)
+{
+	struct clk_psc *psc = to_clk_psc(hw);
+	struct clk_psc_data *psc_data = psc->psc_data;
+	u32 mdstat;
+
+	mdstat = readl(psc_data->reg_base + MDSTAT + 4 * psc_data->lpsc_id);
+
+	/* if clocked, state can be "Enable" or "SyncReset" */
+	return (mdstat & BIT(12)) ? 1 : 0;
+}
+
+/**
+ * clk_psc_enable() - Enable psc clock
+ *
+ * @hw: clk hw for the psc
+ */
+static int clk_psc_enable(struct clk_hw *hw)
+{
+	struct clk_psc *psc = to_clk_psc(hw);
+	struct clk_psc_data *psc_data = psc->psc_data;
+
+	clk_psc_config(psc_data->reg_base, psc_data->domain_id,
+			psc_data->lpsc_id, 1, psc_data->psc_flags);
+	return 0;
+}
+
+/**
+ * clk_psc_disable() - disable psc clock
+ *
+ * @hw: clk hw for the psc
+ */
+static void clk_psc_disable(struct clk_hw *hw)
+{
+	struct clk_psc *psc = to_clk_psc(hw);
+	struct clk_psc_data *psc_data = psc->psc_data;
+
+	clk_psc_config(psc_data->reg_base, psc_data->domain_id,
+			psc_data->lpsc_id, 0, psc_data->psc_flags);
+}
+
+static const struct clk_ops clk_psc_ops = {
+	.enable = clk_psc_enable,
+	.disable = clk_psc_disable,
+	.is_enabled = clk_psc_is_enabled,
+};
+
+/**
+ * clk_register_davinci_psc() - register function for DaVinci PSC clock
+ *
+ * @dev: clk device
+ * @name: name of the clock
+ * @parent_name: name of the parent clock
+ * @psc_data: ptr to psc clk data
+ */
+struct clk *clk_register_davinci_psc(struct device *dev, const char *name,
+			const char *parent_name, struct clk_psc_data *psc_data)
+{
+	struct clk_init_data init;
+	struct clk_psc *psc;
+	struct clk *clk;
+
+	psc = kzalloc(sizeof(*psc), GFP_KERNEL);
+	if (!psc)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &clk_psc_ops;
+	init.flags = psc_data->flags;
+	init.parent_names = (parent_name ? &parent_name : NULL);
+	init.num_parents = (parent_name ? 1 : 0);
+
+	psc->psc_data = psc_data;
+	psc->hw.init = &init;
+
+	clk = clk_register(NULL, &psc->hw);
+	if (IS_ERR(clk))
+		kfree(psc);
+
+	return clk;
+}
diff --git a/drivers/clk/davinci/clk-psc.h b/drivers/clk/davinci/clk-psc.h
new file mode 100644
index 0000000..26327d6
--- /dev/null
+++ b/drivers/clk/davinci/clk-psc.h
@@ -0,0 +1,46 @@ 
+/*
+ * PSC clk driver for DaVinci devices
+ *
+ * Copyright (C) 2006-2012 Texas Instruments.
+ * Copyright (C) 2008-2009 Deep Root Systems, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef __CLK_DAVINCI_PSC_H
+#define __CLK_DAVINCI_PSC_H
+
+/* PSC flags */
+
+/* Disable state is SwRstDisable */
+#define CLK_PSC_SWRSTDISABLE		BIT(0)
+/* Force module state transtition */
+#define CLK_PSC_FORCE			BIT(1)
+/* PSC has external power control available (for DM6446 SoC) */
+#define CLK_PSC_HAS_EXT_POWER_CNTL	BIT(2)
+
+/**
+ * struct clk_psc_data - configuration for DaVinci psc clk driver
+ *
+ * @reg_base:	io mapped address of psc register base
+ * @flags: clk driver base flags
+ * @psc_flags: clk_psc driver flags
+ * @lpsc_id: local power sleep controller id
+ * @gpsc_id: global power sleep controller id
+ * @domain_id: Power domain id
+ */
+struct clk_psc_data {
+	void __iomem *reg_base;
+	u32	flags;
+	u32	psc_flags;
+	u8	lpsc_id;
+	u8	gpsc_id;
+	u8	domain_id;
+};
+
+struct clk *clk_register_davinci_psc(struct device *dev,
+			const char *name, const char *parent_name,
+			struct clk_psc_data *psc_data);
+#endif /* __CLK_DAVINCI_PSC_H */