diff mbox

[U-Boot] clk: convert API to match reset/mailbox style

Message ID 20160523174710.1712-1-swarren@wwwdotorg.org
State Superseded
Delegated to: Simon Glass
Headers show

Commit Message

Stephen Warren May 23, 2016, 5:47 p.m. UTC
From: Stephen Warren <swarren@nvidia.com>

The following changes are made to the clock API:
* The concept of "clocks" and "peripheral clocks" are unified; each clock
  provider now implements a single set of clocks. This provides a simpler
  conceptual interface to clients, and better aligns with device tree
  clock bindings.
* Clocks are now identified with a single "struct clk", rather than
  requiring clients to store the clock provider device and clock identity
  values separately. For simple clock consumers, this isolates clients
  from internal details of the clock API.
* clk.h is split into clk_client.h and clk_uclass.h to make it obvious
  which parts are relevant to consumers and providers. This aligns with
  the recently added reset and mailbox APIs.
* clk_ops .of_xlate(), .request(), and .free() are added so providers
  can customize these operations if needed. This also aligns with the
  recently added reset and mailbox APIs.
* clk_disable() is added.
* All users of the current clock APIs are updated.
* Sandbox clock tests are updated to exercise clock lookup via DT, and
  clock enable/disable.
* rkclk_get_clk() is removed and replaced with standard APIs.

Buildman shows no clock-related errors for any board for which buildman
can download a toolchain.

test/py passes for sandbox (which invokes the dm clk test amongst
others).

Cc: Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
Cc: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
Cc: Purna Chandra Mandal <purna.mandal@microchip.com>
Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
---
 arch/arm/include/asm/arch-rockchip/clock.h   |  12 --
 arch/arm/mach-rockchip/board.c               |  41 +++++-
 arch/arm/mach-rockchip/rk3288/sdram_rk3288.c |  17 ++-
 arch/arm/mach-snapdragon/clock-apq8016.c     |  10 +-
 arch/arm/mach-zynq/clk.c                     |   1 -
 arch/mips/mach-pic32/cpu.c                   |  47 +++---
 arch/sandbox/dts/test.dts                    |  17 ++-
 arch/sandbox/include/asm/clk.h               |  39 +++++
 arch/sandbox/include/asm/test.h              |   9 --
 board/microchip/pic32mzda/pic32mzda.c        |  23 ++-
 cmd/clk.c                                    |   2 +-
 drivers/clk/Makefile                         |   1 +
 drivers/clk/clk-uclass.c                     | 204 +++++++++++++++++++--------
 drivers/clk/clk_fixed_rate.c                 |  13 +-
 drivers/clk/clk_pic32.c                      |  32 ++---
 drivers/clk/clk_rk3036.c                     |  83 +++--------
 drivers/clk/clk_rk3288.c                     | 141 ++++--------------
 drivers/clk/clk_sandbox.c                    |  85 ++++++-----
 drivers/clk/clk_sandbox_test.c               | 101 +++++++++++++
 drivers/clk/uniphier/clk-uniphier-core.c     |  26 ++--
 drivers/clk/uniphier/clk-uniphier-mio.c      |   1 -
 drivers/gpio/rk_gpio.c                       |   1 -
 drivers/i2c/rk_i2c.c                         |   8 +-
 drivers/mmc/msm_sdhci.c                      |  15 +-
 drivers/mmc/rockchip_dw_mmc.c                |   8 +-
 drivers/mmc/uniphier-sd.c                    |  17 +--
 drivers/serial/serial_msm.c                  |  15 +-
 drivers/serial/serial_pic32.c                |   9 +-
 drivers/spi/rk_spi.c                         |   8 +-
 drivers/usb/host/ehci-generic.c              |  16 +--
 drivers/video/rockchip/rk_edp.c              |  13 +-
 drivers/video/rockchip/rk_hdmi.c             |  14 +-
 drivers/video/rockchip/rk_lvds.c             |   1 -
 drivers/video/rockchip/rk_vop.c              |  13 +-
 include/clk.h                                | 132 -----------------
 include/clk_client.h                         | 174 +++++++++++++++++++++++
 include/clk_uclass.h                         |  95 +++++++++++++
 test/dm/clk.c                                | 110 ++++++++++-----
 38 files changed, 948 insertions(+), 606 deletions(-)
 create mode 100644 arch/sandbox/include/asm/clk.h
 create mode 100644 drivers/clk/clk_sandbox_test.c
 delete mode 100644 include/clk.h
 create mode 100644 include/clk_client.h
 create mode 100644 include/clk_uclass.h

Comments

Stephen Warren June 2, 2016, 5 p.m. UTC | #1
On 05/23/2016 11:47 AM, Stephen Warren wrote:
> From: Stephen Warren <swarren@nvidia.com>
>
> The following changes are made to the clock API:
> * The concept of "clocks" and "peripheral clocks" are unified; each clock
>    provider now implements a single set of clocks. This provides a simpler
>    conceptual interface to clients, and better aligns with device tree
>    clock bindings.
> * Clocks are now identified with a single "struct clk", rather than
>    requiring clients to store the clock provider device and clock identity
>    values separately. For simple clock consumers, this isolates clients
>    from internal details of the clock API.
> * clk.h is split into clk_client.h and clk_uclass.h to make it obvious
>    which parts are relevant to consumers and providers. This aligns with
>    the recently added reset and mailbox APIs.
> * clk_ops .of_xlate(), .request(), and .free() are added so providers
>    can customize these operations if needed. This also aligns with the
>    recently added reset and mailbox APIs.
> * clk_disable() is added.
> * All users of the current clock APIs are updated.
> * Sandbox clock tests are updated to exercise clock lookup via DT, and
>    clock enable/disable.
> * rkclk_get_clk() is removed and replaced with standard APIs.
>
> Buildman shows no clock-related errors for any board for which buildman
> can download a toolchain.
>
> test/py passes for sandbox (which invokes the dm clk test amongst
> others).

Simon, does this look good?

(Note I'll be away on vacation Jun 4-15 so won't be able to respond for 
a while)
Daniel Schwierzeck June 2, 2016, 5:48 p.m. UTC | #2
Hi Stephen,

2016-06-02 19:00 GMT+02:00 Stephen Warren <swarren@wwwdotorg.org>:
> On 05/23/2016 11:47 AM, Stephen Warren wrote:
>>
>> From: Stephen Warren <swarren@nvidia.com>
>>
>> The following changes are made to the clock API:
>> * The concept of "clocks" and "peripheral clocks" are unified; each clock
>>    provider now implements a single set of clocks. This provides a simpler
>>    conceptual interface to clients, and better aligns with device tree
>>    clock bindings.
>> * Clocks are now identified with a single "struct clk", rather than
>>    requiring clients to store the clock provider device and clock identity
>>    values separately. For simple clock consumers, this isolates clients
>>    from internal details of the clock API.
>> * clk.h is split into clk_client.h and clk_uclass.h to make it obvious
>>    which parts are relevant to consumers and providers. This aligns with
>>    the recently added reset and mailbox APIs.
>> * clk_ops .of_xlate(), .request(), and .free() are added so providers
>>    can customize these operations if needed. This also aligns with the
>>    recently added reset and mailbox APIs.
>> * clk_disable() is added.
>> * All users of the current clock APIs are updated.
>> * Sandbox clock tests are updated to exercise clock lookup via DT, and
>>    clock enable/disable.
>> * rkclk_get_clk() is removed and replaced with standard APIs.
>>
>> Buildman shows no clock-related errors for any board for which buildman
>> can download a toolchain.
>>
>> test/py passes for sandbox (which invokes the dm clk test amongst
>> others).
>
>
> Simon, does this look good?
>

could you rebase the patch to current mainline?. I couldn't apply it
some days ago. Thanks.
Stephen Warren June 2, 2016, 8:03 p.m. UTC | #3
On 06/02/2016 11:48 AM, Daniel Schwierzeck wrote:
> Hi Stephen,
>
> 2016-06-02 19:00 GMT+02:00 Stephen Warren <swarren@wwwdotorg.org>:
>> On 05/23/2016 11:47 AM, Stephen Warren wrote:
>>>
>>> From: Stephen Warren <swarren@nvidia.com>
>>>
>>> The following changes are made to the clock API:
>>> * The concept of "clocks" and "peripheral clocks" are unified; each clock
>>>     provider now implements a single set of clocks. This provides a simpler
>>>     conceptual interface to clients, and better aligns with device tree
>>>     clock bindings.
>>> * Clocks are now identified with a single "struct clk", rather than
>>>     requiring clients to store the clock provider device and clock identity
>>>     values separately. For simple clock consumers, this isolates clients
>>>     from internal details of the clock API.
>>> * clk.h is split into clk_client.h and clk_uclass.h to make it obvious
>>>     which parts are relevant to consumers and providers. This aligns with
>>>     the recently added reset and mailbox APIs.
>>> * clk_ops .of_xlate(), .request(), and .free() are added so providers
>>>     can customize these operations if needed. This also aligns with the
>>>     recently added reset and mailbox APIs.
>>> * clk_disable() is added.
>>> * All users of the current clock APIs are updated.
>>> * Sandbox clock tests are updated to exercise clock lookup via DT, and
>>>     clock enable/disable.
>>> * rkclk_get_clk() is removed and replaced with standard APIs.
>>>
>>> Buildman shows no clock-related errors for any board for which buildman
>>> can download a toolchain.
>>>
>>> test/py passes for sandbox (which invokes the dm clk test amongst
>>> others).
>>
>>
>> Simon, does this look good?
>>
>
> could you rebase the patch to current mainline?. I couldn't apply it
> some days ago. Thanks.

It seems to work fine for me; see log below. What problem are you seeing?

[swarren@swarren-lx1 u-boot]$ git checkout u-boot/master
HEAD is now at 8b528709c5bb... spl: fit: Fix load address of fit header

[swarren@swarren-lx1 u-boot]$ git am -3 -s ~/\[U-Boot\]\ \[PATCH\]\ 
clk\:\ convert\ API\ to\ match\ reset_mailbox\ style.eml
Applying: clk: convert API to match reset/mailbox style
Using index info to reconstruct a base tree...
M	arch/sandbox/dts/test.dts
M	drivers/clk/clk_rk3288.c
M	drivers/clk/uniphier/clk-uniphier-mio.c
M	drivers/gpio/rk_gpio.c
M	drivers/mmc/rockchip_dw_mmc.c
M	drivers/mmc/uniphier-sd.c
M	drivers/video/rockchip/rk_vop.c
Falling back to patching base and 3-way merge...
Removing include/clk.h
Auto-merging drivers/video/rockchip/rk_vop.c
Auto-merging drivers/mmc/uniphier-sd.c
Auto-merging drivers/mmc/rockchip_dw_mmc.c
Auto-merging drivers/gpio/rk_gpio.c
Auto-merging drivers/clk/uniphier/clk-uniphier-mio.c
Auto-merging drivers/clk/clk_rk3288.c
Auto-merging arch/sandbox/dts/test.dts
Simon Glass June 2, 2016, 9:20 p.m. UTC | #4
Hi Stephen,

On 3 June 2016 at 05:00, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 05/23/2016 11:47 AM, Stephen Warren wrote:
>>
>> From: Stephen Warren <swarren@nvidia.com>
>>
>> The following changes are made to the clock API:
>> * The concept of "clocks" and "peripheral clocks" are unified; each clock
>>    provider now implements a single set of clocks. This provides a simpler
>>    conceptual interface to clients, and better aligns with device tree
>>    clock bindings.
>> * Clocks are now identified with a single "struct clk", rather than
>>    requiring clients to store the clock provider device and clock identity
>>    values separately. For simple clock consumers, this isolates clients
>>    from internal details of the clock API.
>> * clk.h is split into clk_client.h and clk_uclass.h to make it obvious
>>    which parts are relevant to consumers and providers. This aligns with
>>    the recently added reset and mailbox APIs.
>> * clk_ops .of_xlate(), .request(), and .free() are added so providers
>>    can customize these operations if needed. This also aligns with the
>>    recently added reset and mailbox APIs.
>> * clk_disable() is added.
>> * All users of the current clock APIs are updated.
>> * Sandbox clock tests are updated to exercise clock lookup via DT, and
>>    clock enable/disable.
>> * rkclk_get_clk() is removed and replaced with standard APIs.
>>
>> Buildman shows no clock-related errors for any board for which buildman
>> can download a toolchain.
>>
>> test/py passes for sandbox (which invokes the dm clk test amongst
>> others).
>
>
> Simon, does this look good?
>
> (Note I'll be away on vacation Jun 4-15 so won't be able to respond for a
> while)

I am back next week, so will take a look then. I will give it a try on
the rockchip device.

Regards,
Simon
Daniel Schwierzeck June 2, 2016, 9:46 p.m. UTC | #5
Am 02.06.2016 um 22:03 schrieb Stephen Warren:
>> could you rebase the patch to current mainline?. I couldn't apply it
>> some days ago. Thanks.
> 
> It seems to work fine for me; see log below. What problem are you seeing?
> 
> [swarren@swarren-lx1 u-boot]$ git checkout u-boot/master
> HEAD is now at 8b528709c5bb... spl: fit: Fix load address of fit header
> 
> [swarren@swarren-lx1 u-boot]$ git am -3 -s ~/\[U-Boot\]\ \[PATCH\]\
> clk\:\ convert\ API\ to\ match\ reset_mailbox\ style.eml
> Applying: clk: convert API to match reset/mailbox style
> Using index info to reconstruct a base tree...
> M    arch/sandbox/dts/test.dts
> M    drivers/clk/clk_rk3288.c
> M    drivers/clk/uniphier/clk-uniphier-mio.c
> M    drivers/gpio/rk_gpio.c
> M    drivers/mmc/rockchip_dw_mmc.c
> M    drivers/mmc/uniphier-sd.c
> M    drivers/video/rockchip/rk_vop.c
> Falling back to patching base and 3-way merge...
> Removing include/clk.h
> Auto-merging drivers/video/rockchip/rk_vop.c
> Auto-merging drivers/mmc/uniphier-sd.c
> Auto-merging drivers/mmc/rockchip_dw_mmc.c
> Auto-merging drivers/gpio/rk_gpio.c
> Auto-merging drivers/clk/uniphier/clk-uniphier-mio.c
> Auto-merging drivers/clk/clk_rk3288.c
> Auto-merging arch/sandbox/dts/test.dts
> 

I always get this:

daniel@workstation:/work/u-boot$ pwclient get 625342
Saved patch to U-Boot-clk-convert-API-to-match-reset-mailbox-style.patch

daniel@workstation:/work/u-boot$ git am -3 U-Boot-clk-convert-API-to-match-reset-mailbox-style.patch
Applying: clk: convert API to match reset/mailbox style
fatal: sha1 information is lacking or useless (arch/sandbox/dts/test.dts).
error: could not build fake ancestor
Patch failed at 0001 clk: convert API to match reset/mailbox style
The copy of the patch that failed is found in: .git/rebase-apply/patch
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".

I'm seeing the same error with "[PATCH] clk: convert API to match reset_mailbox style.eml". 

I've tried with git 2.7.4 and 2.8.3 and also with a fresh git clone but nothing helps.
Stephen Warren June 2, 2016, 10:02 p.m. UTC | #6
On 06/02/2016 03:46 PM, Daniel Schwierzeck wrote:
>
>
> Am 02.06.2016 um 22:03 schrieb Stephen Warren:
>>> could you rebase the patch to current mainline?. I couldn't apply it
>>> some days ago. Thanks.
>>
>> It seems to work fine for me; see log below. What problem are you seeing?
>>
>> [swarren@swarren-lx1 u-boot]$ git checkout u-boot/master
>> HEAD is now at 8b528709c5bb... spl: fit: Fix load address of fit header
>>
>> [swarren@swarren-lx1 u-boot]$ git am -3 -s ~/\[U-Boot\]\ \[PATCH\]\
>> clk\:\ convert\ API\ to\ match\ reset_mailbox\ style.eml
>> Applying: clk: convert API to match reset/mailbox style
>> Using index info to reconstruct a base tree...
>> M    arch/sandbox/dts/test.dts
>> M    drivers/clk/clk_rk3288.c
>> M    drivers/clk/uniphier/clk-uniphier-mio.c
>> M    drivers/gpio/rk_gpio.c
>> M    drivers/mmc/rockchip_dw_mmc.c
>> M    drivers/mmc/uniphier-sd.c
>> M    drivers/video/rockchip/rk_vop.c
>> Falling back to patching base and 3-way merge...
>> Removing include/clk.h
>> Auto-merging drivers/video/rockchip/rk_vop.c
>> Auto-merging drivers/mmc/uniphier-sd.c
>> Auto-merging drivers/mmc/rockchip_dw_mmc.c
>> Auto-merging drivers/gpio/rk_gpio.c
>> Auto-merging drivers/clk/uniphier/clk-uniphier-mio.c
>> Auto-merging drivers/clk/clk_rk3288.c
>> Auto-merging arch/sandbox/dts/test.dts
>>
>
> I always get this:
>
> daniel@workstation:/work/u-boot$ pwclient get 625342
> Saved patch to U-Boot-clk-convert-API-to-match-reset-mailbox-style.patch
>
> daniel@workstation:/work/u-boot$ git am -3 U-Boot-clk-convert-API-to-match-reset-mailbox-style.patch
> Applying: clk: convert API to match reset/mailbox style
> fatal: sha1 information is lacking or useless (arch/sandbox/dts/test.dts).
> error: could not build fake ancestor
> Patch failed at 0001 clk: convert API to match reset/mailbox style
> The copy of the patch that failed is found in: .git/rebase-apply/patch
> When you have resolved this problem, run "git am --continue".
> If you prefer to skip this patch, run "git am --skip" instead.
> To restore the original branch and stop patching, run "git am --abort".
>
> I'm seeing the same error with "[PATCH] clk: convert API to match reset_mailbox style.eml".
>
> I've tried with git 2.7.4 and 2.8.3 and also with a fresh git clone but nothing helps.

Oh right, it looks like "-3" is required to make the commit apply 
correctly since there have been some minor context changes since I 
created the patch, and that option uses the file SHA information in the 
patch, and when I ran "git format-patch" the commit wasn't based 
directly on upstream (I had some irrelevant intervening commits) so the 
file SHAs in the patch don't exist outside my local repo, and hence the 
messages you see.

You can resolve this by:

git fetch git://github.com/swarren/u-boot.git tmp
git cherry-pick d0b430a197317dd843a09e33359c251ea5f41e6c

It's probably not worth my reposting the patch until it has comments.
Daniel Schwierzeck June 2, 2016, 10:08 p.m. UTC | #7
Am 03.06.2016 um 00:02 schrieb Stephen Warren:
> On 06/02/2016 03:46 PM, Daniel Schwierzeck wrote:
>>
>>
>> Am 02.06.2016 um 22:03 schrieb Stephen Warren:
>>>> could you rebase the patch to current mainline?. I couldn't apply it
>>>> some days ago. Thanks.
>>>
>>> It seems to work fine for me; see log below. What problem are you
>>> seeing?
>>>
>>> [swarren@swarren-lx1 u-boot]$ git checkout u-boot/master
>>> HEAD is now at 8b528709c5bb... spl: fit: Fix load address of fit header
>>>
>>> [swarren@swarren-lx1 u-boot]$ git am -3 -s ~/\[U-Boot\]\ \[PATCH\]\
>>> clk\:\ convert\ API\ to\ match\ reset_mailbox\ style.eml
>>> Applying: clk: convert API to match reset/mailbox style
>>> Using index info to reconstruct a base tree...
>>> M    arch/sandbox/dts/test.dts
>>> M    drivers/clk/clk_rk3288.c
>>> M    drivers/clk/uniphier/clk-uniphier-mio.c
>>> M    drivers/gpio/rk_gpio.c
>>> M    drivers/mmc/rockchip_dw_mmc.c
>>> M    drivers/mmc/uniphier-sd.c
>>> M    drivers/video/rockchip/rk_vop.c
>>> Falling back to patching base and 3-way merge...
>>> Removing include/clk.h
>>> Auto-merging drivers/video/rockchip/rk_vop.c
>>> Auto-merging drivers/mmc/uniphier-sd.c
>>> Auto-merging drivers/mmc/rockchip_dw_mmc.c
>>> Auto-merging drivers/gpio/rk_gpio.c
>>> Auto-merging drivers/clk/uniphier/clk-uniphier-mio.c
>>> Auto-merging drivers/clk/clk_rk3288.c
>>> Auto-merging arch/sandbox/dts/test.dts
>>>
>>
>> I always get this:
>>
>> daniel@workstation:/work/u-boot$ pwclient get 625342
>> Saved patch to U-Boot-clk-convert-API-to-match-reset-mailbox-style.patch
>>
>> daniel@workstation:/work/u-boot$ git am -3
>> U-Boot-clk-convert-API-to-match-reset-mailbox-style.patch
>> Applying: clk: convert API to match reset/mailbox style
>> fatal: sha1 information is lacking or useless
>> (arch/sandbox/dts/test.dts).
>> error: could not build fake ancestor
>> Patch failed at 0001 clk: convert API to match reset/mailbox style
>> The copy of the patch that failed is found in: .git/rebase-apply/patch
>> When you have resolved this problem, run "git am --continue".
>> If you prefer to skip this patch, run "git am --skip" instead.
>> To restore the original branch and stop patching, run "git am --abort".
>>
>> I'm seeing the same error with "[PATCH] clk: convert API to match
>> reset_mailbox style.eml".
>>
>> I've tried with git 2.7.4 and 2.8.3 and also with a fresh git clone
>> but nothing helps.
> 
> Oh right, it looks like "-3" is required to make the commit apply
> correctly since there have been some minor context changes since I
> created the patch, and that option uses the file SHA information in the
> patch, and when I ran "git format-patch" the commit wasn't based
> directly on upstream (I had some irrelevant intervening commits) so the
> file SHAs in the patch don't exist outside my local repo, and hence the
> messages you see.
> 
> You can resolve this by:
> 
> git fetch git://github.com/swarren/u-boot.git tmp
> git cherry-pick d0b430a197317dd843a09e33359c251ea5f41e6c
> 
> It's probably not worth my reposting the patch until it has comments.
> 

ok, that worked. Thanks.
Simon Glass June 8, 2016, 2:43 a.m. UTC | #8
Hi Stephen,

On 23 May 2016 at 10:47, Stephen Warren <swarren@wwwdotorg.org> wrote:
> From: Stephen Warren <swarren@nvidia.com>
>
> The following changes are made to the clock API:
> * The concept of "clocks" and "peripheral clocks" are unified; each clock
>   provider now implements a single set of clocks. This provides a simpler
>   conceptual interface to clients, and better aligns with device tree
>   clock bindings.
> * Clocks are now identified with a single "struct clk", rather than
>   requiring clients to store the clock provider device and clock identity
>   values separately. For simple clock consumers, this isolates clients
>   from internal details of the clock API.
> * clk.h is split into clk_client.h and clk_uclass.h to make it obvious
>   which parts are relevant to consumers and providers. This aligns with
>   the recently added reset and mailbox APIs.
> * clk_ops .of_xlate(), .request(), and .free() are added so providers
>   can customize these operations if needed. This also aligns with the
>   recently added reset and mailbox APIs.
> * clk_disable() is added.
> * All users of the current clock APIs are updated.
> * Sandbox clock tests are updated to exercise clock lookup via DT, and
>   clock enable/disable.
> * rkclk_get_clk() is removed and replaced with standard APIs.
>
> Buildman shows no clock-related errors for any board for which buildman
> can download a toolchain.
>
> test/py passes for sandbox (which invokes the dm clk test amongst
> others).

Sorry for the delay on this. It took more thinking and testing than I
had time for before I went away.

It looks really clean to me. Just some minor things I'd like to change.

Acked-by: Simon Glass <sjg@chromium.org>

>
> Cc: Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
> Cc: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
> Cc: Purna Chandra Mandal <purna.mandal@microchip.com>
> Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
> Signed-off-by: Stephen Warren <swarren@nvidia.com>
> ---
>  arch/arm/include/asm/arch-rockchip/clock.h   |  12 --
>  arch/arm/mach-rockchip/board.c               |  41 +++++-
>  arch/arm/mach-rockchip/rk3288/sdram_rk3288.c |  17 ++-
>  arch/arm/mach-snapdragon/clock-apq8016.c     |  10 +-
>  arch/arm/mach-zynq/clk.c                     |   1 -
>  arch/mips/mach-pic32/cpu.c                   |  47 +++---
>  arch/sandbox/dts/test.dts                    |  17 ++-
>  arch/sandbox/include/asm/clk.h               |  39 +++++
>  arch/sandbox/include/asm/test.h              |   9 --
>  board/microchip/pic32mzda/pic32mzda.c        |  23 ++-
>  cmd/clk.c                                    |   2 +-
>  drivers/clk/Makefile                         |   1 +
>  drivers/clk/clk-uclass.c                     | 204 +++++++++++++++++++--------
>  drivers/clk/clk_fixed_rate.c                 |  13 +-
>  drivers/clk/clk_pic32.c                      |  32 ++---
>  drivers/clk/clk_rk3036.c                     |  83 +++--------
>  drivers/clk/clk_rk3288.c                     | 141 ++++--------------
>  drivers/clk/clk_sandbox.c                    |  85 ++++++-----
>  drivers/clk/clk_sandbox_test.c               | 101 +++++++++++++
>  drivers/clk/uniphier/clk-uniphier-core.c     |  26 ++--
>  drivers/clk/uniphier/clk-uniphier-mio.c      |   1 -
>  drivers/gpio/rk_gpio.c                       |   1 -
>  drivers/i2c/rk_i2c.c                         |   8 +-
>  drivers/mmc/msm_sdhci.c                      |  15 +-
>  drivers/mmc/rockchip_dw_mmc.c                |   8 +-
>  drivers/mmc/uniphier-sd.c                    |  17 +--
>  drivers/serial/serial_msm.c                  |  15 +-
>  drivers/serial/serial_pic32.c                |   9 +-
>  drivers/spi/rk_spi.c                         |   8 +-
>  drivers/usb/host/ehci-generic.c              |  16 +--
>  drivers/video/rockchip/rk_edp.c              |  13 +-
>  drivers/video/rockchip/rk_hdmi.c             |  14 +-
>  drivers/video/rockchip/rk_lvds.c             |   1 -
>  drivers/video/rockchip/rk_vop.c              |  13 +-
>  include/clk.h                                | 132 -----------------
>  include/clk_client.h                         | 174 +++++++++++++++++++++++
>  include/clk_uclass.h                         |  95 +++++++++++++

Can we use clk.h and clk-uclass.h instead? I'm not keen on the _client
suffix. Client should be the defauilt.

>  test/dm/clk.c                                | 110 ++++++++++-----
>  38 files changed, 948 insertions(+), 606 deletions(-)
>  create mode 100644 arch/sandbox/include/asm/clk.h
>  create mode 100644 drivers/clk/clk_sandbox_test.c
>  delete mode 100644 include/clk.h
>  create mode 100644 include/clk_client.h
>  create mode 100644 include/clk_uclass.h
>
> diff --git a/arch/arm/include/asm/arch-rockchip/clock.h b/arch/arm/include/asm/arch-rockchip/clock.h
> index d66b26f18ef3..317e5128ed2b 100644
> --- a/arch/arm/include/asm/arch-rockchip/clock.h
> +++ b/arch/arm/include/asm/arch-rockchip/clock.h
> @@ -62,18 +62,6 @@ static inline u32 clk_get_divisor(ulong input_rate, uint output_rate)
>   */
>  void *rockchip_get_cru(void);
>
> -/**
> - * rkclk_get_clk() - get a pointer to a given clock
> - *
> - * This is an internal function - use outside the clock subsystem indicates
> - * that work is needed!
> - *
> - * @clk_id:    Clock requested
> - * @devp:      Returns a pointer to that clock
> - * @return 0 if OK, -ve on error
> - */
> -int rkclk_get_clk(enum rk_clk_id clk_id, struct udevice **devp);
> -
>  struct rk3288_cru;
>  struct rk3288_grf;
>

[snip]

> diff --git a/arch/sandbox/include/asm/clk.h b/arch/sandbox/include/asm/clk.h
> new file mode 100644
> index 000000000000..7fd2868f9080
> --- /dev/null
> +++ b/arch/sandbox/include/asm/clk.h
> @@ -0,0 +1,39 @@
> +/*
> + * Copyright (c) 2016, NVIDIA CORPORATION.
> + *
> + * SPDX-License-Identifier: GPL-2.0
> + */
> +
> +#ifndef __SANDBOX_CLK_H
> +#define __SANDBOX_CLK_H
> +
> +#include <common.h>
> +
> +struct udevice;
> +
> +enum {
> +       SANDBOX_CLK_ID_SPI,
> +       SANDBOX_CLK_ID_I2C,
> +
> +       SANDBOX_CLK_ID_COUNT,
> +};
> +
> +enum {
> +       SANDBOX_CLK_TEST_ID_FIXED,
> +       SANDBOX_CLK_TEST_ID_SPI,
> +       SANDBOX_CLK_TEST_ID_I2C,
> +
> +       SANDBOX_CLK_TEST_ID_COUNT,

What's the difference between these two enums? Can you add a comment to each?

> +};
> +
> +ulong sandbox_clk_query_rate(struct udevice *dev, int id);
> +int sandbox_clk_query_enable(struct udevice *dev, int id);

Can you add function comments for these?

> +
> +int sandbox_clk_test_get(struct udevice *dev);
> +ulong sandbox_clk_test_get_rate(struct udevice *dev, int id);
> +ulong sandbox_clk_test_set_rate(struct udevice *dev, int id, ulong rate);
> +int sandbox_clk_test_enable(struct udevice *dev, int id);
> +int sandbox_clk_test_disable(struct udevice *dev, int id);
> +int sandbox_clk_test_free(struct udevice *dev);

and these?

> +
> +#endif

Regards,
Simon
Simon Glass June 8, 2016, 4:42 a.m. UTC | #9
Hi Stephen,

On 7 June 2016 at 19:43, Simon Glass <sjg@chromium.org> wrote:
> Hi Stephen,
>
> On 23 May 2016 at 10:47, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> From: Stephen Warren <swarren@nvidia.com>
>>
>> The following changes are made to the clock API:
>> * The concept of "clocks" and "peripheral clocks" are unified; each clock
>>   provider now implements a single set of clocks. This provides a simpler
>>   conceptual interface to clients, and better aligns with device tree
>>   clock bindings.
>> * Clocks are now identified with a single "struct clk", rather than
>>   requiring clients to store the clock provider device and clock identity
>>   values separately. For simple clock consumers, this isolates clients
>>   from internal details of the clock API.
>> * clk.h is split into clk_client.h and clk_uclass.h to make it obvious
>>   which parts are relevant to consumers and providers. This aligns with
>>   the recently added reset and mailbox APIs.
>> * clk_ops .of_xlate(), .request(), and .free() are added so providers
>>   can customize these operations if needed. This also aligns with the
>>   recently added reset and mailbox APIs.
>> * clk_disable() is added.
>> * All users of the current clock APIs are updated.
>> * Sandbox clock tests are updated to exercise clock lookup via DT, and
>>   clock enable/disable.
>> * rkclk_get_clk() is removed and replaced with standard APIs.
>>
>> Buildman shows no clock-related errors for any board for which buildman
>> can download a toolchain.
>>
>> test/py passes for sandbox (which invokes the dm clk test amongst
>> others).
>
> Sorry for the delay on this. It took more thinking and testing than I
> had time for before I went away.
>
> It looks really clean to me. Just some minor things I'd like to change.
>
> Acked-by: Simon Glass <sjg@chromium.org>
>
>>
>> Cc: Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
>> Cc: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
>> Cc: Purna Chandra Mandal <purna.mandal@microchip.com>
>> Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
>> Signed-off-by: Stephen Warren <swarren@nvidia.com>
>> ---
>>  arch/arm/include/asm/arch-rockchip/clock.h   |  12 --
>>  arch/arm/mach-rockchip/board.c               |  41 +++++-
>>  arch/arm/mach-rockchip/rk3288/sdram_rk3288.c |  17 ++-
>>  arch/arm/mach-snapdragon/clock-apq8016.c     |  10 +-
>>  arch/arm/mach-zynq/clk.c                     |   1 -
>>  arch/mips/mach-pic32/cpu.c                   |  47 +++---
>>  arch/sandbox/dts/test.dts                    |  17 ++-
>>  arch/sandbox/include/asm/clk.h               |  39 +++++
>>  arch/sandbox/include/asm/test.h              |   9 --
>>  board/microchip/pic32mzda/pic32mzda.c        |  23 ++-
>>  cmd/clk.c                                    |   2 +-
>>  drivers/clk/Makefile                         |   1 +
>>  drivers/clk/clk-uclass.c                     | 204 +++++++++++++++++++--------
>>  drivers/clk/clk_fixed_rate.c                 |  13 +-
>>  drivers/clk/clk_pic32.c                      |  32 ++---
>>  drivers/clk/clk_rk3036.c                     |  83 +++--------
>>  drivers/clk/clk_rk3288.c                     | 141 ++++--------------
>>  drivers/clk/clk_sandbox.c                    |  85 ++++++-----
>>  drivers/clk/clk_sandbox_test.c               | 101 +++++++++++++
>>  drivers/clk/uniphier/clk-uniphier-core.c     |  26 ++--
>>  drivers/clk/uniphier/clk-uniphier-mio.c      |   1 -
>>  drivers/gpio/rk_gpio.c                       |   1 -
>>  drivers/i2c/rk_i2c.c                         |   8 +-
>>  drivers/mmc/msm_sdhci.c                      |  15 +-
>>  drivers/mmc/rockchip_dw_mmc.c                |   8 +-
>>  drivers/mmc/uniphier-sd.c                    |  17 +--
>>  drivers/serial/serial_msm.c                  |  15 +-
>>  drivers/serial/serial_pic32.c                |   9 +-
>>  drivers/spi/rk_spi.c                         |   8 +-
>>  drivers/usb/host/ehci-generic.c              |  16 +--
>>  drivers/video/rockchip/rk_edp.c              |  13 +-
>>  drivers/video/rockchip/rk_hdmi.c             |  14 +-
>>  drivers/video/rockchip/rk_lvds.c             |   1 -
>>  drivers/video/rockchip/rk_vop.c              |  13 +-
>>  include/clk.h                                | 132 -----------------
>>  include/clk_client.h                         | 174 +++++++++++++++++++++++
>>  include/clk_uclass.h                         |  95 +++++++++++++
>
> Can we use clk.h and clk-uclass.h instead? I'm not keen on the _client
> suffix. Client should be the defauilt.
>
>>  test/dm/clk.c                                | 110 ++++++++++-----
>>  38 files changed, 948 insertions(+), 606 deletions(-)
>>  create mode 100644 arch/sandbox/include/asm/clk.h
>>  create mode 100644 drivers/clk/clk_sandbox_test.c
>>  delete mode 100644 include/clk.h
>>  create mode 100644 include/clk_client.h
>>  create mode 100644 include/clk_uclass.h
>>
>> diff --git a/arch/arm/include/asm/arch-rockchip/clock.h b/arch/arm/include/asm/arch-rockchip/clock.h
>> index d66b26f18ef3..317e5128ed2b 100644
>> --- a/arch/arm/include/asm/arch-rockchip/clock.h
>> +++ b/arch/arm/include/asm/arch-rockchip/clock.h
>> @@ -62,18 +62,6 @@ static inline u32 clk_get_divisor(ulong input_rate, uint output_rate)
>>   */
>>  void *rockchip_get_cru(void);
>>
>> -/**
>> - * rkclk_get_clk() - get a pointer to a given clock
>> - *
>> - * This is an internal function - use outside the clock subsystem indicates
>> - * that work is needed!
>> - *
>> - * @clk_id:    Clock requested
>> - * @devp:      Returns a pointer to that clock
>> - * @return 0 if OK, -ve on error
>> - */
>> -int rkclk_get_clk(enum rk_clk_id clk_id, struct udevice **devp);
>> -
>>  struct rk3288_cru;
>>  struct rk3288_grf;
>>
>
> [snip]
>
>> diff --git a/arch/sandbox/include/asm/clk.h b/arch/sandbox/include/asm/clk.h
>> new file mode 100644
>> index 000000000000..7fd2868f9080
>> --- /dev/null
>> +++ b/arch/sandbox/include/asm/clk.h
>> @@ -0,0 +1,39 @@
>> +/*
>> + * Copyright (c) 2016, NVIDIA CORPORATION.
>> + *
>> + * SPDX-License-Identifier: GPL-2.0
>> + */
>> +
>> +#ifndef __SANDBOX_CLK_H
>> +#define __SANDBOX_CLK_H
>> +
>> +#include <common.h>
>> +
>> +struct udevice;
>> +
>> +enum {
>> +       SANDBOX_CLK_ID_SPI,
>> +       SANDBOX_CLK_ID_I2C,
>> +
>> +       SANDBOX_CLK_ID_COUNT,
>> +};
>> +
>> +enum {
>> +       SANDBOX_CLK_TEST_ID_FIXED,
>> +       SANDBOX_CLK_TEST_ID_SPI,
>> +       SANDBOX_CLK_TEST_ID_I2C,
>> +
>> +       SANDBOX_CLK_TEST_ID_COUNT,
>
> What's the difference between these two enums? Can you add a comment to each?
>
>> +};
>> +
>> +ulong sandbox_clk_query_rate(struct udevice *dev, int id);
>> +int sandbox_clk_query_enable(struct udevice *dev, int id);
>
> Can you add function comments for these?
>
>> +
>> +int sandbox_clk_test_get(struct udevice *dev);
>> +ulong sandbox_clk_test_get_rate(struct udevice *dev, int id);
>> +ulong sandbox_clk_test_set_rate(struct udevice *dev, int id, ulong rate);
>> +int sandbox_clk_test_enable(struct udevice *dev, int id);
>> +int sandbox_clk_test_disable(struct udevice *dev, int id);
>> +int sandbox_clk_test_free(struct udevice *dev);
>
> and these?
>
>> +
>> +#endif
>

Also can you please take a look at these build errors?

08: sandbox: gpio: doc: Fix parameter documentation
   aarch64:  +   uniphier_ld11 espresso7420
      mips:  +   tplink_wdr4300
  blackfin:  +   cm-bf527
       arm:  +   uniphier_ld4_sld8 s5pc210_universal uniphier_sld3
smdkc100 odroid peach-pit smdkv310 peach-pi smdk5250 smdk5420 origen
odroid-xu3 snow s5p_goni spring arndale trats trats2
-arm-unknown-linux-gnueabi-ld.bfd: region `.sram' overflowed by 44 bytes
+   ret = clk_get_by_index(dev, i, &clk);
+         ^
+In file included from ../drivers/usb/host/ehci-generic.c:8:0:
+../include/clk_client.h:78:5: note: expected 'struct clk *' but
argument is of type 'struct clk **'
+ int clk_get_by_index(struct udevice *dev, int index, struct clk *clk);
+     ^
+   if (clk_enable(&clk))
+       ^
+../include/clk_client.h:161:5: note: expected 'struct clk *' but
argument is of type 'struct clk **'
+ int clk_enable(struct clk *clk);
+   clk_free(&clk);
+   ^
+../include/clk_client.h:133:5: note: expected 'struct clk *' but
argument is of type 'struct clk **'
+ int clk_free(struct clk *clk);
+/usr/local/google/c/big/buildall.c/toolchains/bfin-uclinux/bin/../bfin-uclinux/bin/ld.real:
region ram is full (u-boot section .bss)
+make[1]: *** [u-boot] Error 1
+../drivers/serial/serial_s5p.c:20:17: fatal error: clk.h: No such
file or directory
+ #include <clk.h>
+                 ^
+compilation terminated.
+make[2]: *** [drivers/serial/serial_s5p.o] Error 1
+make[1]: *** [drivers/serial] Error 2
+../drivers/clk/exynos/clk-exynos7420.c:12:17: fatal error: clk.h: No
such file or directory
+make[4]: *** [drivers/clk/exynos/clk-exynos7420.o] Error 1
+make[3]: *** [drivers/clk/exynos] Error 2
+make[2]: *** [drivers/clk] Error 2
+make[1]: *** [drivers] Error 2
+arm-unknown-linux-gnueabi-ld.bfd: region `.sram' overflowed by 60 bytes
w+../drivers/usb/host/ehci-generic.c: In function 'ehci_usb_probe':
w+../drivers/usb/host/ehci-generic.c:32:9: warning: passing argument 3
of 'clk_get_by_index' from incompatible pointer type
w+../drivers/usb/host/ehci-generic.c:35:7: warning: passing argument 1
of 'clk_enable' from incompatible pointer type
w+../drivers/usb/host/ehci-generic.c:37:3: warning: passing argument 1
of 'clk_free' from incompatible pointer type

(also firefly-rk3288)

Regards,
Simon
diff mbox

Patch

diff --git a/arch/arm/include/asm/arch-rockchip/clock.h b/arch/arm/include/asm/arch-rockchip/clock.h
index d66b26f18ef3..317e5128ed2b 100644
--- a/arch/arm/include/asm/arch-rockchip/clock.h
+++ b/arch/arm/include/asm/arch-rockchip/clock.h
@@ -62,18 +62,6 @@  static inline u32 clk_get_divisor(ulong input_rate, uint output_rate)
  */
 void *rockchip_get_cru(void);
 
-/**
- * rkclk_get_clk() - get a pointer to a given clock
- *
- * This is an internal function - use outside the clock subsystem indicates
- * that work is needed!
- *
- * @clk_id:	Clock requested
- * @devp:	Returns a pointer to that clock
- * @return 0 if OK, -ve on error
- */
-int rkclk_get_clk(enum rk_clk_id clk_id, struct udevice **devp);
-
 struct rk3288_cru;
 struct rk3288_grf;
 
diff --git a/arch/arm/mach-rockchip/board.c b/arch/arm/mach-rockchip/board.c
index 133d66341bf4..6824e0db6690 100644
--- a/arch/arm/mach-rockchip/board.c
+++ b/arch/arm/mach-rockchip/board.c
@@ -5,10 +5,11 @@ 
  */
 
 #include <common.h>
-#include <clk.h>
+#include <clk_client.h>
 #include <dm.h>
 #include <ram.h>
 #include <asm/io.h>
+#include <asm/arch/clock.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -54,15 +55,43 @@  void lowlevel_init(void)
 static int do_clock(cmd_tbl_t *cmdtp, int flag, int argc,
 		       char * const argv[])
 {
+	static const struct {
+		char *name;
+		int id;
+	} clks[] = {
+		{ "osc", CLK_OSC },
+		{ "apll", CLK_ARM },
+		{ "dpll", CLK_DDR },
+		{ "cpll", CLK_CODEC },
+		{ "gpll", CLK_GENERAL },
+#ifdef CONFIG_ROCKCHIP_RK3036
+		{ "mpll", CLK_NEW },
+#else
+		{ "npll", CLK_NEW },
+#endif
+	};
+	int ret, i;
 	struct udevice *dev;
 
-	for (uclass_first_device(UCLASS_CLK, &dev);
-	     dev;
-	     uclass_next_device(&dev)) {
+	ret = uclass_get_device(UCLASS_CLK, 0, &dev);
+	if (ret) {
+		printf("clk-uclass not found\n");
+		return 0;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(clks); i++) {
+		struct clk clk;
 		ulong rate;
 
-		rate = clk_get_rate(dev);
-		printf("%s: %lu\n", dev->name, rate);
+		clk.id = clks[i].id;
+		ret = clk_request(dev, &clk);
+		if (ret < 0)
+			continue;
+
+		rate = clk_get_rate(&clk);
+		printf("%s: %lu\n", clks[i].name, rate);
+
+		clk_free(&clk);
 	}
 
 	return 0;
diff --git a/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c b/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c
index 2e212823352e..6161be17017c 100644
--- a/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c
+++ b/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c
@@ -8,7 +8,7 @@ 
  */
 
 #include <common.h>
-#include <clk.h>
+#include <clk_client.h>
 #include <dm.h>
 #include <errno.h>
 #include <ram.h>
@@ -36,7 +36,7 @@  struct chan_info {
 struct dram_info {
 	struct chan_info chan[2];
 	struct ram_info info;
-	struct udevice *ddr_clk;
+	struct clk ddr_clk;
 	struct rk3288_cru *cru;
 	struct rk3288_grf *grf;
 	struct rk3288_sgrf *sgrf;
@@ -576,7 +576,7 @@  static void dram_all_config(const struct dram_info *dram,
 	rk_clrsetreg(&dram->sgrf->soc_con2, 0x1f, sdram_params->base.stride);
 }
 
-static int sdram_init(const struct dram_info *dram,
+static int sdram_init(struct dram_info *dram,
 		      const struct rk3288_sdram_params *sdram_params)
 {
 	int channel;
@@ -592,8 +592,8 @@  static int sdram_init(const struct dram_info *dram,
 		return -E2BIG;
 	}
 
-	debug("ddr clk %s\n", dram->ddr_clk->name);
-	ret = clk_set_rate(dram->ddr_clk, sdram_params->base.ddr_freq);
+	debug("ddr clk dpll\n");
+	ret = clk_set_rate(&dram->ddr_clk, sdram_params->base.ddr_freq);
 	debug("ret=%d\n", ret);
 	if (ret) {
 		debug("Could not set DDR clock\n");
@@ -836,6 +836,7 @@  static int rk3288_dmc_probe(struct udevice *dev)
 	struct dram_info *priv = dev_get_priv(dev);
 	struct regmap *map;
 	int ret;
+	struct udevice *dev_clk;
 
 	map = syscon_get_regmap_by_driver_data(ROCKCHIP_SYSCON_NOC);
 	if (IS_ERR(map))
@@ -856,7 +857,11 @@  static int rk3288_dmc_probe(struct udevice *dev)
 	priv->chan[1].pctl = regmap_get_range(map, 2);
 	priv->chan[1].publ = regmap_get_range(map, 3);
 
-	ret = uclass_get_device(UCLASS_CLK, CLK_DDR, &priv->ddr_clk);
+	ret = uclass_get_device(UCLASS_CLK, 0, &dev_clk);
+	if (ret)
+		return ret;
+	priv->ddr_clk.id = CLK_DDR;
+	ret = clk_request(dev_clk, &priv->ddr_clk);
 	if (ret)
 		return ret;
 
diff --git a/arch/arm/mach-snapdragon/clock-apq8016.c b/arch/arm/mach-snapdragon/clock-apq8016.c
index d548d757d37b..aeccbc271502 100644
--- a/arch/arm/mach-snapdragon/clock-apq8016.c
+++ b/arch/arm/mach-snapdragon/clock-apq8016.c
@@ -9,7 +9,7 @@ 
  */
 
 #include <common.h>
-#include <clk.h>
+#include <clk_uclass.h>
 #include <dm.h>
 #include <errno.h>
 #include <asm/io.h>
@@ -212,11 +212,11 @@  static int clk_init_uart(struct msm_clk_priv *priv)
 	return 0;
 }
 
-ulong msm_set_periph_rate(struct udevice *dev, int periph, ulong rate)
+ulong msm_set_rate(struct clk *clk, ulong rate)
 {
-	struct msm_clk_priv *priv = dev_get_priv(dev);
+	struct msm_clk_priv *priv = dev_get_priv(clk->dev);
 
-	switch (periph) {
+	switch (clk->id) {
 	case 0: /* SDC1 */
 		return clk_init_sdc(priv, 0, rate);
 		break;
@@ -243,7 +243,7 @@  static int msm_clk_probe(struct udevice *dev)
 }
 
 static struct clk_ops msm_clk_ops = {
-	.set_periph_rate = msm_set_periph_rate,
+	.set_rate = msm_set_rate,
 };
 
 static const struct udevice_id msm_clk_ids[] = {
diff --git a/arch/arm/mach-zynq/clk.c b/arch/arm/mach-zynq/clk.c
index 6444be8f0325..40383c11c914 100644
--- a/arch/arm/mach-zynq/clk.c
+++ b/arch/arm/mach-zynq/clk.c
@@ -6,7 +6,6 @@ 
  */
 #include <common.h>
 #include <errno.h>
-#include <clk.h>
 #include <asm/io.h>
 #include <asm/arch/hardware.h>
 #include <asm/arch/clk.h>
diff --git a/arch/mips/mach-pic32/cpu.c b/arch/mips/mach-pic32/cpu.c
index f2ee911df4d1..2483a52adc65 100644
--- a/arch/mips/mach-pic32/cpu.c
+++ b/arch/mips/mach-pic32/cpu.c
@@ -6,7 +6,7 @@ 
  *
  */
 #include <common.h>
-#include <clk.h>
+#include <clk_client.h>
 #include <dm.h>
 #include <mach/pic32.h>
 #include <mach/ddr.h>
@@ -23,18 +23,34 @@ 
 
 DECLARE_GLOBAL_DATA_PTR;
 
-static ulong clk_get_cpu_rate(void)
+static ulong rate(int id)
 {
 	int ret;
 	struct udevice *dev;
+	struct clk clk;
+	ulong rate;
 
 	ret = uclass_get_device(UCLASS_CLK, 0, &dev);
 	if (ret) {
-		panic("uclass-clk: device not found\n");
+		printf("clk-uclass not found\n");
 		return 0;
 	}
 
-	return clk_get_rate(dev);
+	clk.id = id;
+	ret = clk_request(dev, &clk);
+	if (ret < 0)
+		return ret;
+
+	rate = clk_get_rate(&clk);
+
+	clk_free(&clk);
+
+	return rate;
+}
+
+static ulong clk_get_cpu_rate(void)
+{
+	return rate(PB7CLK);
 }
 
 /* initialize prefetch module related to cpu_clk */
@@ -127,30 +143,25 @@  const char *get_core_name(void)
 }
 #endif
 #ifdef CONFIG_CMD_CLK
+
 int soc_clk_dump(void)
 {
-	int i, ret;
-	struct udevice *dev;
-
-	ret = uclass_get_device(UCLASS_CLK, 0, &dev);
-	if (ret) {
-		printf("clk-uclass not found\n");
-		return ret;
-	}
+	int i;
 
 	printf("PLL Speed: %lu MHz\n",
-	       CLK_MHZ(clk_get_periph_rate(dev, PLLCLK)));
-	printf("CPU Speed: %lu MHz\n", CLK_MHZ(clk_get_rate(dev)));
-	printf("MPLL Speed: %lu MHz\n",
-	       CLK_MHZ(clk_get_periph_rate(dev, MPLL)));
+	       CLK_MHZ(rate(PLLCLK)));
+
+	printf("CPU Speed: %lu MHz\n", CLK_MHZ(rate(PB7CLK)));
+
+	printf("MPLL Speed: %lu MHz\n", CLK_MHZ(rate(MPLL)));
 
 	for (i = PB1CLK; i <= PB7CLK; i++)
 		printf("PB%d Clock Speed: %lu MHz\n", i - PB1CLK + 1,
-		       CLK_MHZ(clk_get_periph_rate(dev, i)));
+		       CLK_MHZ(rate(i)));
 
 	for (i = REF1CLK; i <= REF5CLK; i++)
 		printf("REFO%d Clock Speed: %lu MHz\n", i - REF1CLK + 1,
-		       CLK_MHZ(clk_get_periph_rate(dev, i)));
+		       CLK_MHZ(rate(i)));
 	return 0;
 }
 #endif
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 879b30e3ccc6..9e46f9e815a6 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -108,8 +108,23 @@ 
 		compatible = "denx,u-boot-fdt-test";
 	};
 
-	clk@0 {
+	clk_fixed: clk-fixed {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <1234>;
+	};
+
+	clk_sandbox: clk-sbox {
 		compatible = "sandbox,clk";
+		#clock-cells = <1>;
+	};
+
+	clk-test {
+		compatible = "sandbox,clk-test";
+		clocks = <&clk_fixed>,
+			 <&clk_sandbox 1>,
+			 <&clk_sandbox 0>;
+		clock-names = "fixed", "i2c", "spi";
 	};
 
 	eth@10002000 {
diff --git a/arch/sandbox/include/asm/clk.h b/arch/sandbox/include/asm/clk.h
new file mode 100644
index 000000000000..7fd2868f9080
--- /dev/null
+++ b/arch/sandbox/include/asm/clk.h
@@ -0,0 +1,39 @@ 
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef __SANDBOX_CLK_H
+#define __SANDBOX_CLK_H
+
+#include <common.h>
+
+struct udevice;
+
+enum {
+	SANDBOX_CLK_ID_SPI,
+	SANDBOX_CLK_ID_I2C,
+
+	SANDBOX_CLK_ID_COUNT,
+};
+
+enum {
+	SANDBOX_CLK_TEST_ID_FIXED,
+	SANDBOX_CLK_TEST_ID_SPI,
+	SANDBOX_CLK_TEST_ID_I2C,
+
+	SANDBOX_CLK_TEST_ID_COUNT,
+};
+
+ulong sandbox_clk_query_rate(struct udevice *dev, int id);
+int sandbox_clk_query_enable(struct udevice *dev, int id);
+
+int sandbox_clk_test_get(struct udevice *dev);
+ulong sandbox_clk_test_get_rate(struct udevice *dev, int id);
+ulong sandbox_clk_test_set_rate(struct udevice *dev, int id, ulong rate);
+int sandbox_clk_test_enable(struct udevice *dev, int id);
+int sandbox_clk_test_disable(struct udevice *dev, int id);
+int sandbox_clk_test_free(struct udevice *dev);
+
+#endif
diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h
index 224b0ebaf955..451a78e590e3 100644
--- a/arch/sandbox/include/asm/test.h
+++ b/arch/sandbox/include/asm/test.h
@@ -19,15 +19,6 @@ 
 
 #define SANDBOX_CLK_RATE		32768
 
-enum {
-	PERIPH_ID_FIRST = 0,
-	PERIPH_ID_SPI = PERIPH_ID_FIRST,
-	PERIPH_ID_I2C,
-	PERIPH_ID_PCI,
-
-	PERIPH_ID_COUNT,
-};
-
 /* System controller driver data */
 enum {
 	SYSCON0		= 32,
diff --git a/board/microchip/pic32mzda/pic32mzda.c b/board/microchip/pic32mzda/pic32mzda.c
index afe2ab8b7133..ab059a10bc35 100644
--- a/board/microchip/pic32mzda/pic32mzda.c
+++ b/board/microchip/pic32mzda/pic32mzda.c
@@ -10,21 +10,32 @@ 
 
 #include <common.h>
 #include <dm.h>
-#include <clk.h>
+#include <clk_client.h>
+#include <dt-bindings/clock/microchip,clock.h>
 #include <mach/pic32.h>
 
 #ifdef CONFIG_DISPLAY_BOARDINFO
 int checkboard(void)
 {
-	ulong rate = 0;
+	ulong rate;
 	struct udevice *dev;
+	struct clk clk;
+	int ret;
 
 	printf("Core: %s\n", get_core_name());
 
-	if (!uclass_get_device(UCLASS_CLK, 0, &dev)) {
-		rate = clk_get_rate(dev);
-		printf("CPU Speed: %lu MHz\n", rate / 1000000);
-	}
+	if (uclass_get_device(UCLASS_CLK, 0, &dev))
+		return 0;
+
+	clk.id = PB7CLK;
+	ret = clk_request(dev, &clk);
+	if (ret < 0)
+		return 0;
+
+	rate = clk_get_rate(&clk);
+	printf("CPU Speed: %lu MHz\n", rate / 1000000);
+
+	clk_free(&clk);
 
 	return 0;
 }
diff --git a/cmd/clk.c b/cmd/clk.c
index 6d3d46a18447..96aaad3d1aff 100644
--- a/cmd/clk.c
+++ b/cmd/clk.c
@@ -5,7 +5,7 @@ 
  */
 #include <common.h>
 #include <command.h>
-#include <clk.h>
+#include <clk_client.h>
 
 int __weak soc_clk_dump(void)
 {
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index c51db1562b64..645f06c99d0d 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -9,5 +9,6 @@  obj-$(CONFIG_CLK) += clk-uclass.o clk_fixed_rate.o
 obj-$(CONFIG_ROCKCHIP_RK3036) += clk_rk3036.o
 obj-$(CONFIG_ROCKCHIP_RK3288) += clk_rk3288.o
 obj-$(CONFIG_SANDBOX) += clk_sandbox.o
+obj-$(CONFIG_SANDBOX) += clk_sandbox_test.o
 obj-$(CONFIG_MACH_PIC32) += clk_pic32.o
 obj-$(CONFIG_CLK_UNIPHIER) += uniphier/
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index b483c1ef33bd..ad019b40455f 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -1,91 +1,78 @@ 
 /*
  * Copyright (C) 2015 Google, Inc
  * Written by Simon Glass <sjg@chromium.org>
+ * Copyright (c) 2016, NVIDIA CORPORATION.
  *
  * SPDX-License-Identifier:	GPL-2.0+
  */
 
 #include <common.h>
-#include <clk.h>
+#include <clk_client.h>
+#include <clk_uclass.h>
 #include <dm.h>
 #include <errno.h>
-#include <dm/lists.h>
-#include <dm/root.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
-ulong clk_get_rate(struct udevice *dev)
+static inline struct clk_ops *clk_dev_ops(struct udevice *dev)
 {
-	struct clk_ops *ops = clk_get_ops(dev);
-
-	if (!ops->get_rate)
-		return -ENOSYS;
-
-	return ops->get_rate(dev);
+	return (struct clk_ops *)dev->driver->ops;
 }
 
-ulong clk_set_rate(struct udevice *dev, ulong rate)
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+#ifdef CONFIG_SPL_BUILD
+int clk_get_by_index(struct udevice *dev, int index, struct clk *clk)
 {
-	struct clk_ops *ops = clk_get_ops(dev);
+	int ret;
+	u32 cell[2];
 
-	if (!ops->set_rate)
+	if (index != 0)
 		return -ENOSYS;
-
-	return ops->set_rate(dev, rate);
+	assert(clk);
+	ret = uclass_get_device(UCLASS_CLK, 0, &clk->dev);
+	if (ret)
+		return ret;
+	ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "clocks",
+				   cell, 2);
+	if (ret)
+		return ret;
+	clk->id = cell[1];
+	return 0;
 }
 
-int clk_enable(struct udevice *dev, int periph)
+int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk)
 {
-	struct clk_ops *ops = clk_get_ops(dev);
-
-	if (!ops->enable)
-		return -ENOSYS;
-
-	return ops->enable(dev, periph);
+	return -ENOSYS;
 }
-
-ulong clk_get_periph_rate(struct udevice *dev, int periph)
+#else
+static int clk_of_xlate_default(struct clk *clk,
+				struct fdtdec_phandle_args *args)
 {
-	struct clk_ops *ops = clk_get_ops(dev);
+	debug("%s(clk=%p)\n", __func__, clk);
 
-	if (!ops->get_periph_rate)
-		return -ENOSYS;
-
-	return ops->get_periph_rate(dev, periph);
-}
-
-ulong clk_set_periph_rate(struct udevice *dev, int periph, ulong rate)
-{
-	struct clk_ops *ops = clk_get_ops(dev);
+	if (args->args_count > 1) {
+		debug("Invaild args_count: %d\n", args->args_count);
+		return -EINVAL;
+	}
 
-	if (!ops->set_periph_rate)
-		return -ENOSYS;
+	if (args->args_count)
+		clk->id = args->args[0];
+	else
+		clk->id = 0;
 
-	return ops->set_periph_rate(dev, periph, rate);
+	return 0;
 }
 
-#if CONFIG_IS_ENABLED(OF_CONTROL)
-int clk_get_by_index(struct udevice *dev, int index, struct udevice **clk_devp)
+int clk_get_by_index(struct udevice *dev, int index, struct clk *clk)
 {
 	int ret;
-#ifdef CONFIG_SPL_BUILD
-	u32 cell[2];
-
-	if (index != 0)
-		return -ENOSYS;
-	assert(*clk_devp);
-	ret = uclass_get_device(UCLASS_CLK, 0, clk_devp);
-	if (ret)
-		return ret;
-	ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "clocks",
-				   cell, 2);
-	if (ret)
-		return ret;
-	return cell[1];
-#else
 	struct fdtdec_phandle_args args;
+	struct udevice *dev_clk;
+	struct clk_ops *ops;
+
+	debug("%s(dev=%p, index=%d, clk=%p)\n", __func__, dev, index, clk);
 
-	assert(*clk_devp);
+	assert(clk);
 	ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset,
 					     "clocks", "#clock-cells", 0, index,
 					     &args);
@@ -95,16 +82,117 @@  int clk_get_by_index(struct udevice *dev, int index, struct udevice **clk_devp)
 		return ret;
 	}
 
-	ret = uclass_get_device_by_of_offset(UCLASS_CLK, args.node, clk_devp);
+	ret = uclass_get_device_by_of_offset(UCLASS_CLK, args.node, &dev_clk);
 	if (ret) {
 		debug("%s: uclass_get_device_by_of_offset failed: err=%d\n",
 		      __func__, ret);
 		return ret;
 	}
-	return args.args_count > 0 ? args.args[0] : 0;
-#endif
+	ops = clk_dev_ops(dev_clk);
+
+	if (ops->of_xlate)
+		ret = ops->of_xlate(clk, &args);
+	else
+		ret = clk_of_xlate_default(clk, &args);
+	if (ret) {
+		debug("of_xlate() failed: %d\n", ret);
+		return ret;
+	}
+
+	return clk_request(dev_clk, clk);
+}
+
+int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk)
+{
+	int index;
+
+	debug("%s(dev=%p, name=%s, clk=%p)\n", __func__, dev, name, clk);
+
+	index = fdt_find_string(gd->fdt_blob, dev->of_offset, "clock-names",
+				name);
+	if (index < 0) {
+		debug("fdt_find_string() failed: %d\n", index);
+		return index;
+	}
+
+	return clk_get_by_index(dev, index, clk);
 }
 #endif
+#endif
+
+int clk_request(struct udevice *dev, struct clk *clk)
+{
+	struct clk_ops *ops = clk_dev_ops(dev);
+
+	debug("%s(dev=%p, clk=%p)\n", __func__, dev, clk);
+
+	clk->dev = dev;
+
+	if (!ops->request)
+		return 0;
+
+	return ops->request(clk);
+}
+
+int clk_free(struct clk *clk)
+{
+	struct clk_ops *ops = clk_dev_ops(clk->dev);
+
+	debug("%s(clk=%p)\n", __func__, clk);
+
+	if (!ops->free)
+		return 0;
+
+	return ops->free(clk);
+}
+
+ulong clk_get_rate(struct clk *clk)
+{
+	struct clk_ops *ops = clk_dev_ops(clk->dev);
+
+	debug("%s(clk=%p)\n", __func__, clk);
+
+	if (!ops->get_rate)
+		return -ENOSYS;
+
+	return ops->get_rate(clk);
+}
+
+ulong clk_set_rate(struct clk *clk, ulong rate)
+{
+	struct clk_ops *ops = clk_dev_ops(clk->dev);
+
+	debug("%s(clk=%p, rate=%lu)\n", __func__, clk, rate);
+
+	if (!ops->set_rate)
+		return -ENOSYS;
+
+	return ops->set_rate(clk, rate);
+}
+
+int clk_enable(struct clk *clk)
+{
+	struct clk_ops *ops = clk_dev_ops(clk->dev);
+
+	debug("%s(clk=%p)\n", __func__, clk);
+
+	if (!ops->enable)
+		return -ENOSYS;
+
+	return ops->enable(clk);
+}
+
+int clk_disable(struct clk *clk)
+{
+	struct clk_ops *ops = clk_dev_ops(clk->dev);
+
+	debug("%s(clk=%p)\n", __func__, clk);
+
+	if (!ops->disable)
+		return -ENOSYS;
+
+	return ops->disable(clk);
+}
 
 UCLASS_DRIVER(clk) = {
 	.id		= UCLASS_CLK,
diff --git a/drivers/clk/clk_fixed_rate.c b/drivers/clk/clk_fixed_rate.c
index 8beda9cb5572..d12f9e260b05 100644
--- a/drivers/clk/clk_fixed_rate.c
+++ b/drivers/clk/clk_fixed_rate.c
@@ -5,7 +5,7 @@ 
  */
 
 #include <common.h>
-#include <clk.h>
+#include <clk_uclass.h>
 #include <dm/device.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -16,19 +16,16 @@  struct clk_fixed_rate {
 
 #define to_clk_fixed_rate(dev)	((struct clk_fixed_rate *)dev_get_platdata(dev))
 
-static ulong clk_fixed_rate_get_rate(struct udevice *dev)
+static ulong clk_fixed_rate_get_rate(struct clk *clk)
 {
-	return to_clk_fixed_rate(dev)->fixed_rate;
-}
+	if (clk->id != 0)
+		return -EINVAL;
 
-static ulong clk_fixed_rate_get_periph_rate(struct udevice *dev, int periph)
-{
-	return clk_fixed_rate_get_rate(dev);
+	return to_clk_fixed_rate(clk->dev)->fixed_rate;
 }
 
 const struct clk_ops clk_fixed_rate_ops = {
 	.get_rate = clk_fixed_rate_get_rate,
-	.get_periph_rate = clk_fixed_rate_get_periph_rate,
 };
 
 static int clk_fixed_rate_ofdata_to_platdata(struct udevice *dev)
diff --git a/drivers/clk/clk_pic32.c b/drivers/clk/clk_pic32.c
index 5d883544d513..8dac1b47efac 100644
--- a/drivers/clk/clk_pic32.c
+++ b/drivers/clk/clk_pic32.c
@@ -6,7 +6,7 @@ 
  */
 
 #include <common.h>
-#include <clk.h>
+#include <clk_uclass.h>
 #include <dm.h>
 #include <div64.h>
 #include <wait_bit.h>
@@ -339,24 +339,17 @@  static void pic32_clk_init(struct udevice *dev)
 	pic32_mpll_init(priv);
 }
 
-static ulong pic32_clk_get_rate(struct udevice *dev)
+static ulong pic32_get_rate(struct clk *clk)
 {
-	struct pic32_clk_priv *priv = dev_get_priv(dev);
-
-	return pic32_get_cpuclk(priv);
-}
-
-static ulong pic32_get_periph_rate(struct udevice *dev, int periph)
-{
-	struct pic32_clk_priv *priv = dev_get_priv(dev);
+	struct pic32_clk_priv *priv = dev_get_priv(clk->dev);
 	ulong rate;
 
-	switch (periph) {
+	switch (clk->id) {
 	case PB1CLK ... PB7CLK:
-		rate = pic32_get_pbclk(priv, periph);
+		rate = pic32_get_pbclk(priv, clk->id);
 		break;
 	case REF1CLK ... REF5CLK:
-		rate = pic32_get_refclk(priv, periph);
+		rate = pic32_get_refclk(priv, clk->id);
 		break;
 	case PLLCLK:
 		rate = pic32_get_pll_rate(priv);
@@ -372,15 +365,15 @@  static ulong pic32_get_periph_rate(struct udevice *dev, int periph)
 	return rate;
 }
 
-static ulong pic32_set_periph_rate(struct udevice *dev, int periph, ulong rate)
+static ulong pic32_set_rate(struct clk *clk, ulong rate)
 {
-	struct pic32_clk_priv *priv = dev_get_priv(dev);
+	struct pic32_clk_priv *priv = dev_get_priv(clk->dev);
 	ulong pll_hz;
 
-	switch (periph) {
+	switch (clk->id) {
 	case REF1CLK ... REF5CLK:
 		pll_hz = pic32_get_pll_rate(priv);
-		pic32_set_refclk(priv, periph, pll_hz, rate, ROCLK_SRC_SPLL);
+		pic32_set_refclk(priv, clk->id, pll_hz, rate, ROCLK_SRC_SPLL);
 		break;
 	default:
 		break;
@@ -390,9 +383,8 @@  static ulong pic32_set_periph_rate(struct udevice *dev, int periph, ulong rate)
 }
 
 static struct clk_ops pic32_pic32_clk_ops = {
-	.get_rate = pic32_clk_get_rate,
-	.set_periph_rate = pic32_set_periph_rate,
-	.get_periph_rate = pic32_get_periph_rate,
+	.set_rate = pic32_set_rate,
+	.get_rate = pic32_get_rate,
 };
 
 static int pic32_clk_probe(struct udevice *dev)
diff --git a/drivers/clk/clk_rk3036.c b/drivers/clk/clk_rk3036.c
index 7ec65bdff029..7a66172c66b6 100644
--- a/drivers/clk/clk_rk3036.c
+++ b/drivers/clk/clk_rk3036.c
@@ -5,7 +5,7 @@ 
  */
 
 #include <common.h>
-#include <clk.h>
+#include <clk_uclass.h>
 #include <dm.h>
 #include <errno.h>
 #include <syscon.h>
@@ -18,10 +18,6 @@ 
 
 DECLARE_GLOBAL_DATA_PTR;
 
-struct rk3036_clk_plat {
-	enum rk_clk_id clk_id;
-};
-
 struct rk3036_clk_priv {
 	struct rk3036_cru *cru;
 	ulong rate;
@@ -315,31 +311,30 @@  static ulong rockchip_mmc_set_clk(struct rk3036_cru *cru, uint clk_general_rate,
 	return rockchip_mmc_get_clk(cru, clk_general_rate, periph);
 }
 
-static ulong rk3036_clk_get_rate(struct udevice *dev)
-{
-	struct rk3036_clk_plat *plat = dev_get_platdata(dev);
-	struct rk3036_clk_priv *priv = dev_get_priv(dev);
-
-	debug("%s\n", dev->name);
-	return rkclk_pll_get_rate(priv->cru, plat->clk_id);
-}
-
-static ulong rk3036_clk_set_rate(struct udevice *dev, ulong rate)
+static ulong rk3036_clk_get_rate(struct clk *clk)
 {
-	debug("%s\n", dev->name);
+	struct rk3036_clk_priv *priv = dev_get_priv(clk->dev);
 
-	return 0;
+	switch (clk->id) {
+	case 0 ... 63:
+		return rkclk_pll_get_rate(priv->cru, clk->id);
+	default:
+		return -ENOENT;
+	}
 }
 
-static ulong rk3036_set_periph_rate(struct udevice *dev, int periph, ulong rate)
+static ulong rk3036_clk_set_rate(struct clk *clk, ulong rate)
 {
-	struct rk3036_clk_priv *priv = dev_get_priv(dev);
-	ulong new_rate;
+	struct rk3036_clk_priv *priv = dev_get_priv(clk->dev);
+	ulong new_rate, gclk_rate;
 
-	switch (periph) {
+	gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL);
+	switch (clk->id) {
+	case 0 ... 63:
+		return 0;
 	case HCLK_EMMC:
-		new_rate = rockchip_mmc_set_clk(priv->cru, clk_get_rate(dev),
-						periph, rate);
+		new_rate = rockchip_mmc_set_clk(priv->cru, gclk_rate,
+						clk->id, rate);
 		break;
 	default:
 		return -ENOENT;
@@ -351,60 +346,21 @@  static ulong rk3036_set_periph_rate(struct udevice *dev, int periph, ulong rate)
 static struct clk_ops rk3036_clk_ops = {
 	.get_rate	= rk3036_clk_get_rate,
 	.set_rate	= rk3036_clk_set_rate,
-	.set_periph_rate = rk3036_set_periph_rate,
 };
 
 static int rk3036_clk_probe(struct udevice *dev)
 {
-	struct rk3036_clk_plat *plat = dev_get_platdata(dev);
 	struct rk3036_clk_priv *priv = dev_get_priv(dev);
 
-	if (plat->clk_id != CLK_OSC) {
-		struct rk3036_clk_priv *parent_priv = dev_get_priv(dev->parent);
-
-		priv->cru = parent_priv->cru;
-		return 0;
-	}
 	priv->cru = (struct rk3036_cru *)dev_get_addr(dev);
 	rkclk_init(priv->cru);
 
 	return 0;
 }
 
-static const char *const clk_name[] = {
-	"osc",
-	"apll",
-	"dpll",
-	"cpll",
-	"gpll",
-	"mpll",
-};
-
 static int rk3036_clk_bind(struct udevice *dev)
 {
-	struct rk3036_clk_plat *plat = dev_get_platdata(dev);
-	int pll, ret;
-
-	/* We only need to set up the root clock */
-	if (dev->of_offset == -1) {
-		plat->clk_id = CLK_OSC;
-		return 0;
-	}
-
-	/* Create devices for P main clocks */
-	for (pll = 1; pll < CLK_COUNT; pll++) {
-		struct udevice *child;
-		struct rk3036_clk_plat *cplat;
-
-		debug("%s %s\n", __func__, clk_name[pll]);
-		ret = device_bind_driver(dev, "clk_rk3036", clk_name[pll],
-					 &child);
-		if (ret)
-			return ret;
-
-		cplat = dev_get_platdata(child);
-		cplat->clk_id = pll;
-	}
+	int ret;
 
 	/* The reset driver does not have a device node, so bind it here */
 	ret = device_bind_driver(gd->dm_root, "rk3036_sysreset", "reset", &dev);
@@ -424,7 +380,6 @@  U_BOOT_DRIVER(clk_rk3036) = {
 	.id		= UCLASS_CLK,
 	.of_match	= rk3036_clk_ids,
 	.priv_auto_alloc_size = sizeof(struct rk3036_clk_priv),
-	.platdata_auto_alloc_size = sizeof(struct rk3036_clk_plat),
 	.ops		= &rk3036_clk_ops,
 	.bind		= rk3036_clk_bind,
 	.probe		= rk3036_clk_probe,
diff --git a/drivers/clk/clk_rk3288.c b/drivers/clk/clk_rk3288.c
index e763a1c8e91f..6deb80f9c950 100644
--- a/drivers/clk/clk_rk3288.c
+++ b/drivers/clk/clk_rk3288.c
@@ -5,7 +5,7 @@ 
  */
 
 #include <common.h>
-#include <clk.h>
+#include <clk_uclass.h>
 #include <dm.h>
 #include <errno.h>
 #include <syscon.h>
@@ -21,10 +21,6 @@ 
 
 DECLARE_GLOBAL_DATA_PTR;
 
-struct rk3288_clk_plat {
-	enum rk_clk_id clk_id;
-};
-
 struct rk3288_clk_priv {
 	struct rk3288_grf *grf;
 	struct rk3288_cru *cru;
@@ -135,34 +131,18 @@  static const struct pll_div apll_init_cfg = PLL_DIVISORS(APLL_HZ, 1, 1);
 static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2);
 static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 2);
 
-int rkclk_get_clk(enum rk_clk_id clk_id, struct udevice **devp)
-{
-	struct udevice *dev;
-
-	for (uclass_find_first_device(UCLASS_CLK, &dev);
-	     dev;
-	     uclass_find_next_device(&dev)) {
-		struct rk3288_clk_plat *plat = dev_get_platdata(dev);
-
-		if (plat->clk_id == clk_id) {
-			*devp = dev;
-			return device_probe(dev);
-		}
-	}
-
-	return -ENODEV;
-}
-
 void *rockchip_get_cru(void)
 {
 	struct rk3288_clk_priv *priv;
 	struct udevice *dev;
 	int ret;
 
-	ret = rkclk_get_clk(CLK_GENERAL, &dev);
+	ret = uclass_get_device(UCLASS_CLK, 0, &dev);
 	if (ret)
 		return ERR_PTR(ret);
+
 	priv = dev_get_priv(dev);
+
 	return priv->cru;
 }
 
@@ -528,32 +508,6 @@  static uint32_t rkclk_pll_get_rate(struct rk3288_cru *cru,
 	}
 }
 
-static ulong rk3288_clk_get_rate(struct udevice *dev)
-{
-	struct rk3288_clk_plat *plat = dev_get_platdata(dev);
-	struct rk3288_clk_priv *priv = dev_get_priv(dev);
-
-	debug("%s\n", dev->name);
-	return rkclk_pll_get_rate(priv->cru, plat->clk_id);
-}
-
-static ulong rk3288_clk_set_rate(struct udevice *dev, ulong rate)
-{
-	struct rk3288_clk_plat *plat = dev_get_platdata(dev);
-	struct rk3288_clk_priv *priv = dev_get_priv(dev);
-
-	debug("%s\n", dev->name);
-	switch (plat->clk_id) {
-	case CLK_DDR:
-		rkclk_configure_ddr(priv->cru, priv->grf, rate);
-		break;
-	default:
-		return -ENOENT;
-	}
-
-	return 0;
-}
-
 static ulong rockchip_mmc_get_clk(struct rk3288_cru *cru, uint gclk_rate,
 				  int periph)
 {
@@ -699,27 +653,25 @@  static ulong rockchip_spi_set_clk(struct rk3288_cru *cru, uint gclk_rate,
 	return rockchip_spi_get_clk(cru, gclk_rate, periph);
 }
 
-static ulong rk3288_get_periph_rate(struct udevice *dev, int periph)
+static ulong rk3288_clk_get_rate(struct clk *clk)
 {
-	struct rk3288_clk_priv *priv = dev_get_priv(dev);
-	struct udevice *gclk;
+	struct rk3288_clk_priv *priv = dev_get_priv(clk->dev);
 	ulong new_rate, gclk_rate;
-	int ret;
 
-	ret = rkclk_get_clk(CLK_GENERAL, &gclk);
-	if (ret)
-		return ret;
-	gclk_rate = clk_get_rate(gclk);
-	switch (periph) {
+	gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL);
+	switch (clk->id) {
+	case 0 ... 63:
+		new_rate = rkclk_pll_get_rate(priv->cru, clk->id);
+		break;
 	case HCLK_EMMC:
 	case HCLK_SDMMC:
 	case HCLK_SDIO0:
-		new_rate = rockchip_mmc_get_clk(priv->cru, gclk_rate, periph);
+		new_rate = rockchip_mmc_get_clk(priv->cru, gclk_rate, clk->id);
 		break;
 	case SCLK_SPI0:
 	case SCLK_SPI1:
 	case SCLK_SPI2:
-		new_rate = rockchip_spi_get_clk(priv->cru, gclk_rate, periph);
+		new_rate = rockchip_spi_get_clk(priv->cru, gclk_rate, clk->id);
 		break;
 	case PCLK_I2C0:
 	case PCLK_I2C1:
@@ -735,33 +687,31 @@  static ulong rk3288_get_periph_rate(struct udevice *dev, int periph)
 	return new_rate;
 }
 
-static ulong rk3288_set_periph_rate(struct udevice *dev, int periph, ulong rate)
+static ulong rk3288_clk_set_rate(struct clk *clk, ulong rate)
 {
-	struct rk3288_clk_priv *priv = dev_get_priv(dev);
+	struct rk3288_clk_priv *priv = dev_get_priv(clk->dev);
 	struct rk3288_cru *cru = priv->cru;
-	struct udevice *gclk;
 	ulong new_rate, gclk_rate;
-	int ret;
 
-	ret = rkclk_get_clk(CLK_GENERAL, &gclk);
-	if (ret)
-		return ret;
-	gclk_rate = clk_get_rate(gclk);
-	switch (periph) {
+	gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL);
+	switch (clk->id) {
+	case CLK_DDR:
+		new_rate = rkclk_configure_ddr(priv->cru, priv->grf, rate);
+		break;
 	case HCLK_EMMC:
 	case HCLK_SDMMC:
 	case HCLK_SDIO0:
-		new_rate = rockchip_mmc_set_clk(cru, gclk_rate, periph, rate);
+		new_rate = rockchip_mmc_set_clk(cru, gclk_rate, clk->id, rate);
 		break;
 	case SCLK_SPI0:
 	case SCLK_SPI1:
 	case SCLK_SPI2:
-		new_rate = rockchip_spi_set_clk(cru, gclk_rate, periph, rate);
+		new_rate = rockchip_spi_set_clk(cru, gclk_rate, clk->id, rate);
 		break;
 #ifndef CONFIG_SPL_BUILD
 	case DCLK_VOP0:
 	case DCLK_VOP1:
-		new_rate = rockchip_vop_set_clk(cru, priv->grf, periph, rate);
+		new_rate = rockchip_vop_set_clk(cru, priv->grf, clk->id, rate);
 		break;
 	case SCLK_EDP_24M:
 		/* clk_edp_24M source: 24M */
@@ -781,7 +731,7 @@  static ulong rk3288_set_periph_rate(struct udevice *dev, int periph, ulong rate)
 		div = CPLL_HZ / rate;
 		assert((div - 1 < 64) && (div * rate == CPLL_HZ));
 
-		switch (periph) {
+		switch (clk->id) {
 		case ACLK_VOP0:
 			rk_clrsetreg(&cru->cru_clksel_con[31],
 				     3 << 6 | 0x1f << 0,
@@ -817,22 +767,12 @@  static ulong rk3288_set_periph_rate(struct udevice *dev, int periph, ulong rate)
 static struct clk_ops rk3288_clk_ops = {
 	.get_rate	= rk3288_clk_get_rate,
 	.set_rate	= rk3288_clk_set_rate,
-	.set_periph_rate = rk3288_set_periph_rate,
-	.get_periph_rate = rk3288_get_periph_rate,
 };
 
 static int rk3288_clk_probe(struct udevice *dev)
 {
-	struct rk3288_clk_plat *plat = dev_get_platdata(dev);
 	struct rk3288_clk_priv *priv = dev_get_priv(dev);
 
-	if (plat->clk_id != CLK_OSC) {
-		struct rk3288_clk_priv *parent_priv = dev_get_priv(dev->parent);
-
-		priv->cru = parent_priv->cru;
-		priv->grf = parent_priv->grf;
-		return 0;
-	}
 	priv->cru = (struct rk3288_cru *)dev_get_addr(dev);
 	priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
 #ifdef CONFIG_SPL_BUILD
@@ -842,39 +782,9 @@  static int rk3288_clk_probe(struct udevice *dev)
 	return 0;
 }
 
-static const char *const clk_name[CLK_COUNT] = {
-	"osc",
-	"apll",
-	"dpll",
-	"cpll",
-	"gpll",
-	"npll",
-};
-
 static int rk3288_clk_bind(struct udevice *dev)
 {
-	struct rk3288_clk_plat *plat = dev_get_platdata(dev);
-	int pll, ret;
-
-	/* We only need to set up the root clock */
-	if (dev->of_offset == -1) {
-		plat->clk_id = CLK_OSC;
-		return 0;
-	}
-
-	/* Create devices for P main clocks */
-	for (pll = 1; pll < CLK_COUNT; pll++) {
-		struct udevice *child;
-		struct rk3288_clk_plat *cplat;
-
-		debug("%s %s\n", __func__, clk_name[pll]);
-		ret = device_bind_driver(dev, "clk_rk3288", clk_name[pll],
-					 &child);
-		if (ret)
-			return ret;
-		cplat = dev_get_platdata(child);
-		cplat->clk_id = pll;
-	}
+	int ret;
 
 	/* The reset driver does not have a device node, so bind it here */
 	ret = device_bind_driver(gd->dm_root, "rk3288_sysreset", "reset", &dev);
@@ -894,7 +804,6 @@  U_BOOT_DRIVER(clk_rk3288) = {
 	.id		= UCLASS_CLK,
 	.of_match	= rk3288_clk_ids,
 	.priv_auto_alloc_size = sizeof(struct rk3288_clk_priv),
-	.platdata_auto_alloc_size = sizeof(struct rk3288_clk_plat),
 	.ops		= &rk3288_clk_ops,
 	.bind		= rk3288_clk_bind,
 	.probe		= rk3288_clk_probe,
diff --git a/drivers/clk/clk_sandbox.c b/drivers/clk/clk_sandbox.c
index 367130f8b76b..52261020d7d4 100644
--- a/drivers/clk/clk_sandbox.c
+++ b/drivers/clk/clk_sandbox.c
@@ -5,61 +5,63 @@ 
  */
 
 #include <common.h>
-#include <clk.h>
+#include <clk_uclass.h>
 #include <dm.h>
 #include <errno.h>
-#include <asm/test.h>
+#include <asm/clk.h>
 
 struct sandbox_clk_priv {
-	ulong rate;
-	ulong periph_rate[PERIPH_ID_COUNT];
+	ulong rate[SANDBOX_CLK_ID_COUNT];
+	bool enabled[SANDBOX_CLK_ID_COUNT];
 };
 
-static ulong sandbox_clk_get_rate(struct udevice *dev)
+static ulong sandbox_clk_get_rate(struct clk *clk)
 {
-	struct sandbox_clk_priv *priv = dev_get_priv(dev);
+	struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
+
+	if (clk->id < 0 || clk->id >= SANDBOX_CLK_ID_COUNT)
+		return -EINVAL;
 
-	return priv->rate;
+	return priv->rate[clk->id];
 }
 
-static ulong sandbox_clk_set_rate(struct udevice *dev, ulong rate)
+static ulong sandbox_clk_set_rate(struct clk *clk, ulong rate)
 {
-	struct sandbox_clk_priv *priv = dev_get_priv(dev);
+	struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
+	ulong old_rate;
+
+	if (clk->id < 0 || clk->id >= SANDBOX_CLK_ID_COUNT)
+		return -EINVAL;
 
 	if (!rate)
 		return -EINVAL;
-	priv->rate = rate;
-	return 0;
-}
 
-static ulong sandbox_get_periph_rate(struct udevice *dev, int periph)
-{
-	struct sandbox_clk_priv *priv = dev_get_priv(dev);
+	old_rate = priv->rate[clk->id];
+	priv->rate[clk->id] = rate;
 
-	if (periph < PERIPH_ID_FIRST || periph >= PERIPH_ID_COUNT)
-		return -EINVAL;
-	return priv->periph_rate[periph];
+	return old_rate;
 }
 
-static ulong sandbox_set_periph_rate(struct udevice *dev, int periph,
-				     ulong rate)
+static int sandbox_clk_enable(struct clk *clk)
 {
-	struct sandbox_clk_priv *priv = dev_get_priv(dev);
-	ulong old_rate;
+	struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
 
-	if (periph < PERIPH_ID_FIRST || periph >= PERIPH_ID_COUNT)
+	if (clk->id < 0 || clk->id >= SANDBOX_CLK_ID_COUNT)
 		return -EINVAL;
-	old_rate = priv->periph_rate[periph];
-	priv->periph_rate[periph] = rate;
 
-	return old_rate;
+	priv->enabled[clk->id] = true;
+
+	return 0;
 }
 
-static int sandbox_clk_probe(struct udevice *dev)
+static int sandbox_clk_disable(struct clk *clk)
 {
-	struct sandbox_clk_priv *priv = dev_get_priv(dev);
+	struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
+
+	if (clk->id < 0 || clk->id >= SANDBOX_CLK_ID_COUNT)
+		return -EINVAL;
 
-	priv->rate = SANDBOX_CLK_RATE;
+	priv->enabled[clk->id] = false;
 
 	return 0;
 }
@@ -67,8 +69,8 @@  static int sandbox_clk_probe(struct udevice *dev)
 static struct clk_ops sandbox_clk_ops = {
 	.get_rate	= sandbox_clk_get_rate,
 	.set_rate	= sandbox_clk_set_rate,
-	.get_periph_rate = sandbox_get_periph_rate,
-	.set_periph_rate = sandbox_set_periph_rate,
+	.enable		= sandbox_clk_enable,
+	.disable	= sandbox_clk_disable,
 };
 
 static const struct udevice_id sandbox_clk_ids[] = {
@@ -82,5 +84,24 @@  U_BOOT_DRIVER(clk_sandbox) = {
 	.of_match	= sandbox_clk_ids,
 	.ops		= &sandbox_clk_ops,
 	.priv_auto_alloc_size = sizeof(struct sandbox_clk_priv),
-	.probe		= sandbox_clk_probe,
 };
+
+ulong sandbox_clk_query_rate(struct udevice *dev, int id)
+{
+	struct sandbox_clk_priv *priv = dev_get_priv(dev);
+
+	if (id < 0 || id >= SANDBOX_CLK_ID_COUNT)
+		return -EINVAL;
+
+	return priv->rate[id];
+}
+
+int sandbox_clk_query_enable(struct udevice *dev, int id)
+{
+	struct sandbox_clk_priv *priv = dev_get_priv(dev);
+
+	if (id < 0 || id >= SANDBOX_CLK_ID_COUNT)
+		return -EINVAL;
+
+	return priv->enabled[id];
+}
diff --git a/drivers/clk/clk_sandbox_test.c b/drivers/clk/clk_sandbox_test.c
new file mode 100644
index 000000000000..7b7720c2f657
--- /dev/null
+++ b/drivers/clk/clk_sandbox_test.c
@@ -0,0 +1,101 @@ 
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <clk_client.h>
+#include <asm/clk.h>
+
+struct sandbox_clk_test {
+	struct clk clks[SANDBOX_CLK_TEST_ID_COUNT];
+};
+
+static const char * const sandbox_clk_test_names[] = {
+	[SANDBOX_CLK_TEST_ID_FIXED] = "fixed",
+	[SANDBOX_CLK_TEST_ID_SPI] = "spi",
+	[SANDBOX_CLK_TEST_ID_I2C] = "i2c",
+};
+
+int sandbox_clk_test_get(struct udevice *dev)
+{
+	struct sandbox_clk_test *sbct = dev_get_priv(dev);
+	int i, ret;
+
+	for (i = 0; i < SANDBOX_CLK_TEST_ID_COUNT; i++) {
+		ret = clk_get_by_name(dev, sandbox_clk_test_names[i],
+				      &sbct->clks[i]);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+ulong sandbox_clk_test_get_rate(struct udevice *dev, int id)
+{
+	struct sandbox_clk_test *sbct = dev_get_priv(dev);
+
+	if (id < 0 || id >= SANDBOX_CLK_TEST_ID_COUNT)
+		return -EINVAL;
+
+	return clk_get_rate(&sbct->clks[id]);
+}
+
+ulong sandbox_clk_test_set_rate(struct udevice *dev, int id, ulong rate)
+{
+	struct sandbox_clk_test *sbct = dev_get_priv(dev);
+
+	if (id < 0 || id >= SANDBOX_CLK_TEST_ID_COUNT)
+		return -EINVAL;
+
+	return clk_set_rate(&sbct->clks[id], rate);
+}
+
+int sandbox_clk_test_enable(struct udevice *dev, int id)
+{
+	struct sandbox_clk_test *sbct = dev_get_priv(dev);
+
+	if (id < 0 || id >= SANDBOX_CLK_TEST_ID_COUNT)
+		return -EINVAL;
+
+	return clk_enable(&sbct->clks[id]);
+}
+
+int sandbox_clk_test_disable(struct udevice *dev, int id)
+{
+	struct sandbox_clk_test *sbct = dev_get_priv(dev);
+
+	if (id < 0 || id >= SANDBOX_CLK_TEST_ID_COUNT)
+		return -EINVAL;
+
+	return clk_disable(&sbct->clks[id]);
+}
+
+int sandbox_clk_test_free(struct udevice *dev)
+{
+	struct sandbox_clk_test *sbct = dev_get_priv(dev);
+	int i, ret;
+
+	for (i = 0; i < SANDBOX_CLK_TEST_ID_COUNT; i++) {
+		ret = clk_free(&sbct->clks[i]);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static const struct udevice_id sandbox_clk_test_ids[] = {
+	{ .compatible = "sandbox,clk-test" },
+	{ }
+};
+
+U_BOOT_DRIVER(sandbox_clk_test) = {
+	.name = "sandbox_clk_test",
+	.id = UCLASS_MISC,
+	.of_match = sandbox_clk_test_ids,
+	.priv_auto_alloc_size = sizeof(struct sandbox_clk_test),
+};
diff --git a/drivers/clk/uniphier/clk-uniphier-core.c b/drivers/clk/uniphier/clk-uniphier-core.c
index 25c163b395dd..b42265b4f1a1 100644
--- a/drivers/clk/uniphier/clk-uniphier-core.c
+++ b/drivers/clk/uniphier/clk-uniphier-core.c
@@ -9,14 +9,14 @@ 
 #include <linux/bitops.h>
 #include <linux/io.h>
 #include <linux/sizes.h>
-#include <clk.h>
+#include <clk_uclass.h>
 #include <dm/device.h>
 
 #include "clk-uniphier.h"
 
-static int uniphier_clk_enable(struct udevice *dev, int index)
+static int uniphier_clk_enable(struct clk *clk)
 {
-	struct uniphier_clk_priv *priv = dev_get_priv(dev);
+	struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
 	struct uniphier_clk_gate_data *gate = priv->socdata->gate;
 	unsigned int nr_gate = priv->socdata->nr_gate;
 	void __iomem *reg;
@@ -24,7 +24,7 @@  static int uniphier_clk_enable(struct udevice *dev, int index)
 	int i;
 
 	for (i = 0; i < nr_gate; i++) {
-		if (gate[i].index != index)
+		if (gate[i].index != clk->id)
 			continue;
 
 		reg = priv->base + gate[i].reg;
@@ -41,9 +41,9 @@  static int uniphier_clk_enable(struct udevice *dev, int index)
 	return 0;
 }
 
-static ulong uniphier_clk_get_rate(struct udevice *dev, int index)
+static ulong uniphier_clk_get_rate(struct clk *clk)
 {
-	struct uniphier_clk_priv *priv = dev_get_priv(dev);
+	struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
 	struct uniphier_clk_rate_data *rdata = priv->socdata->rate;
 	unsigned int nr_rdata = priv->socdata->nr_rate;
 	void __iomem *reg;
@@ -52,7 +52,7 @@  static ulong uniphier_clk_get_rate(struct udevice *dev, int index)
 	int i;
 
 	for (i = 0; i < nr_rdata; i++) {
-		if (rdata[i].index != index)
+		if (rdata[i].index != clk->id)
 			continue;
 
 		if (rdata[i].reg == UNIPHIER_CLK_RATE_IS_FIXED)
@@ -75,9 +75,9 @@  static ulong uniphier_clk_get_rate(struct udevice *dev, int index)
 	return matched_rate;
 }
 
-static ulong uniphier_clk_set_rate(struct udevice *dev, int index, ulong rate)
+static ulong uniphier_clk_set_rate(struct clk *clk, ulong rate)
 {
-	struct uniphier_clk_priv *priv = dev_get_priv(dev);
+	struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
 	struct uniphier_clk_rate_data *rdata = priv->socdata->rate;
 	unsigned int nr_rdata = priv->socdata->nr_rate;
 	void __iomem *reg;
@@ -87,7 +87,7 @@  static ulong uniphier_clk_set_rate(struct udevice *dev, int index, ulong rate)
 
 	/* first, decide the best match rate */
 	for (i = 0; i < nr_rdata; i++) {
-		if (rdata[i].index != index)
+		if (rdata[i].index != clk->id)
 			continue;
 
 		if (rdata[i].reg == UNIPHIER_CLK_RATE_IS_FIXED)
@@ -105,7 +105,7 @@  static ulong uniphier_clk_set_rate(struct udevice *dev, int index, ulong rate)
 
 	/* second, really set registers */
 	for (i = 0; i < nr_rdata; i++) {
-		if (rdata[i].index != index || rdata[i].rate != best_rate)
+		if (rdata[i].index != clk->id || rdata[i].rate != best_rate)
 			continue;
 
 		reg = priv->base + rdata[i].reg;
@@ -124,8 +124,8 @@  static ulong uniphier_clk_set_rate(struct udevice *dev, int index, ulong rate)
 
 const struct clk_ops uniphier_clk_ops = {
 	.enable = uniphier_clk_enable,
-	.get_periph_rate = uniphier_clk_get_rate,
-	.set_periph_rate = uniphier_clk_set_rate,
+	.get_rate = uniphier_clk_get_rate,
+	.set_rate = uniphier_clk_set_rate,
 };
 
 int uniphier_clk_probe(struct udevice *dev)
diff --git a/drivers/clk/uniphier/clk-uniphier-mio.c b/drivers/clk/uniphier/clk-uniphier-mio.c
index a2b0e80a3394..7003e378be73 100644
--- a/drivers/clk/uniphier/clk-uniphier-mio.c
+++ b/drivers/clk/uniphier/clk-uniphier-mio.c
@@ -4,7 +4,6 @@ 
  * SPDX-License-Identifier:	GPL-2.0+
  */
 
-#include <clk.h>
 #include <dm/device.h>
 
 #include "clk-uniphier.h"
diff --git a/drivers/gpio/rk_gpio.c b/drivers/gpio/rk_gpio.c
index 40e87bd1996a..9d583af64739 100644
--- a/drivers/gpio/rk_gpio.c
+++ b/drivers/gpio/rk_gpio.c
@@ -8,7 +8,6 @@ 
  */
 
 #include <common.h>
-#include <clk.h>
 #include <dm.h>
 #include <syscon.h>
 #include <asm/errno.h>
diff --git a/drivers/i2c/rk_i2c.c b/drivers/i2c/rk_i2c.c
index 3fceade61ec7..edf98fa966d2 100644
--- a/drivers/i2c/rk_i2c.c
+++ b/drivers/i2c/rk_i2c.c
@@ -8,7 +8,7 @@ 
  */
 
 #include <common.h>
-#include <clk.h>
+#include <clk_client.h>
 #include <dm.h>
 #include <errno.h>
 #include <i2c.h>
@@ -29,10 +29,9 @@  DECLARE_GLOBAL_DATA_PTR;
 #define RK_I2C_FIFO_SIZE	32
 
 struct rk_i2c {
-	struct udevice *clk;
+	struct clk clk;
 	struct i2c_regs *regs;
 	unsigned int speed;
-	int clk_id;
 };
 
 static inline void rk_i2c_get_div(int div, int *divh, int *divl)
@@ -55,7 +54,7 @@  static void rk_i2c_set_clk(struct rk_i2c *i2c, uint32_t scl_rate)
 	int div, divl, divh;
 
 	/* First get i2c rate from pclk */
-	i2c_rate = clk_get_periph_rate(i2c->clk, i2c->clk_id);
+	i2c_rate = clk_get_rate(&i2c->clk);
 
 	div = DIV_ROUND_UP(i2c_rate, scl_rate * 8) - 2;
 	divh = 0;
@@ -362,7 +361,6 @@  static int rockchip_i2c_ofdata_to_platdata(struct udevice *bus)
 		      bus->name, ret);
 		return ret;
 	}
-	priv->clk_id = ret;
 
 	return 0;
 }
diff --git a/drivers/mmc/msm_sdhci.c b/drivers/mmc/msm_sdhci.c
index 1e2a29b825f3..6715dd604dfb 100644
--- a/drivers/mmc/msm_sdhci.c
+++ b/drivers/mmc/msm_sdhci.c
@@ -9,7 +9,7 @@ 
  */
 
 #include <common.h>
-#include <clk.h>
+#include <clk_client.h>
 #include <dm.h>
 #include <sdhci.h>
 #include <wait_bit.h>
@@ -49,7 +49,8 @@  static int msm_sdc_clk_init(struct udevice *dev)
 					"clock-frequency", 400000);
 	uint clkd[2]; /* clk_id and clk_no */
 	int clk_offset;
-	struct udevice *clk;
+	struct udevice *clk_dev;
+	struct clk clk;
 	int ret;
 
 	ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "clock", clkd,
@@ -61,11 +62,17 @@  static int msm_sdc_clk_init(struct udevice *dev)
 	if (clk_offset < 0)
 		return clk_offset;
 
-	ret = uclass_get_device_by_of_offset(UCLASS_CLK, clk_offset, &clk);
+	ret = uclass_get_device_by_of_offset(UCLASS_CLK, clk_offset, &clk_dev);
 	if (ret)
 		return ret;
 
-	ret = clk_set_periph_rate(clk, clkd[1], clk_rate);
+	clk.id = clkd[1];
+	ret = clk_request(clk_dev, &clk);
+	if (ret < 0)
+		return ret;
+
+	ret = clk_set_rate(&clk, clk_rate);
+	clk_free(&clk);
 	if (ret < 0)
 		return ret;
 
diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c
index cb9e1048d035..d38aeaadf46e 100644
--- a/drivers/mmc/rockchip_dw_mmc.c
+++ b/drivers/mmc/rockchip_dw_mmc.c
@@ -5,7 +5,7 @@ 
  */
 
 #include <common.h>
-#include <clk.h>
+#include <clk_client.h>
 #include <dm.h>
 #include <dwmmc.h>
 #include <errno.h>
@@ -19,8 +19,7 @@ 
 DECLARE_GLOBAL_DATA_PTR;
 
 struct rockchip_dwmmc_priv {
-	struct udevice *clk;
-	int periph;
+	struct clk clk;
 	struct dwmci_host host;
 };
 
@@ -30,7 +29,7 @@  static uint rockchip_dwmmc_get_mmc_clk(struct dwmci_host *host, uint freq)
 	struct rockchip_dwmmc_priv *priv = dev_get_priv(dev);
 	int ret;
 
-	ret = clk_set_periph_rate(priv->clk, priv->periph, freq);
+	ret = clk_set_rate(&priv->clk, freq);
 	if (ret < 0) {
 		debug("%s: err=%d\n", __func__, ret);
 		return ret;
@@ -73,7 +72,6 @@  static int rockchip_dwmmc_probe(struct udevice *dev)
 	ret = clk_get_by_index(dev, 0, &priv->clk);
 	if (ret < 0)
 		return ret;
-	priv->periph = ret;
 
 	if (fdtdec_get_int_array(gd->fdt_blob, dev->of_offset,
 				 "clock-freq-min-max", minmax, 2))
diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c
index 81a80cdbc2ca..7aa45965de48 100644
--- a/drivers/mmc/uniphier-sd.c
+++ b/drivers/mmc/uniphier-sd.c
@@ -5,7 +5,7 @@ 
  */
 
 #include <common.h>
-#include <clk.h>
+#include <clk_client.h>
 #include <fdtdec.h>
 #include <mapmem.h>
 #include <mmc.h>
@@ -651,8 +651,7 @@  int uniphier_sd_probe(struct udevice *dev)
 	struct uniphier_sd_priv *priv = dev_get_priv(dev);
 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
 	fdt_addr_t base;
-	struct udevice *clk_dev;
-	int clk_id;
+	struct clk clk;
 	int ret;
 
 	priv->dev = dev;
@@ -665,20 +664,22 @@  int uniphier_sd_probe(struct udevice *dev)
 	if (!priv->regbase)
 		return -ENOMEM;
 
-	clk_id = clk_get_by_index(dev, 0, &clk_dev);
-	if (clk_id < 0) {
+	ret = clk_get_by_index(dev, 0, &clk);
+	if (ret < 0) {
 		dev_err(dev, "failed to get host clock\n");
-		return clk_id;
+		return ret;
 	}
 
 	/* set to max rate */
-	priv->mclk = clk_set_periph_rate(clk_dev, clk_id, ULONG_MAX);
+	priv->mclk = clk_set_rate(&clk, ULONG_MAX);
 	if (IS_ERR_VALUE(priv->mclk)) {
 		dev_err(dev, "failed to set rate for host clock\n");
+		clk_free(&clk);
 		return priv->mclk;
 	}
 
-	ret = clk_enable(clk_dev, clk_id);
+	ret = clk_enable(&clk);
+	clk_free(&clk);
 	if (ret) {
 		dev_err(dev, "failed to enable host clock\n");
 		return ret;
diff --git a/drivers/serial/serial_msm.c b/drivers/serial/serial_msm.c
index 80fb89ea8b05..cbb00d7f689a 100644
--- a/drivers/serial/serial_msm.c
+++ b/drivers/serial/serial_msm.c
@@ -10,7 +10,7 @@ 
  */
 
 #include <common.h>
-#include <clk.h>
+#include <clk_client.h>
 #include <dm.h>
 #include <errno.h>
 #include <serial.h>
@@ -150,7 +150,8 @@  static int msm_uart_clk_init(struct udevice *dev)
 					"clock-frequency", 115200);
 	uint clkd[2]; /* clk_id and clk_no */
 	int clk_offset;
-	struct udevice *clk;
+	struct udevice *clk_dev;
+	struct clk clk;
 	int ret;
 
 	ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "clock", clkd,
@@ -162,11 +163,17 @@  static int msm_uart_clk_init(struct udevice *dev)
 	if (clk_offset < 0)
 		return clk_offset;
 
-	ret = uclass_get_device_by_of_offset(UCLASS_CLK, clk_offset, &clk);
+	ret = uclass_get_device_by_of_offset(UCLASS_CLK, clk_offset, &clk_dev);
 	if (ret)
 		return ret;
 
-	ret = clk_set_periph_rate(clk, clkd[1], clk_rate);
+	clk.id = clkd[1];
+	ret = clk_request(clk_dev, &clk);
+	if (ret < 0)
+		return ret;
+
+	ret = clk_set_rate(&clk, clk_rate);
+	clk_free(&clk);
 	if (ret < 0)
 		return ret;
 
diff --git a/drivers/serial/serial_pic32.c b/drivers/serial/serial_pic32.c
index af9fbbf65544..0e90f9cfb753 100644
--- a/drivers/serial/serial_pic32.c
+++ b/drivers/serial/serial_pic32.c
@@ -5,7 +5,7 @@ 
  *
  */
 #include <common.h>
-#include <clk.h>
+#include <clk_client.h>
 #include <dm.h>
 #include <serial.h>
 #include <wait_bit.h>
@@ -135,7 +135,7 @@  static int pic32_uart_getc(struct udevice *dev)
 static int pic32_uart_probe(struct udevice *dev)
 {
 	struct pic32_uart_priv *priv = dev_get_priv(dev);
-	struct udevice *clkdev;
+	struct clk clk;
 	fdt_addr_t addr;
 	fdt_size_t size;
 	int ret;
@@ -148,10 +148,11 @@  static int pic32_uart_probe(struct udevice *dev)
 	priv->base = ioremap(addr, size);
 
 	/* get clock rate */
-	ret = clk_get_by_index(dev, 0, &clkdev);
+	ret = clk_get_by_index(dev, 0, &clk);
 	if (ret < 0)
 		return ret;
-	priv->uartclk = clk_get_periph_rate(clkdev, ret);
+	priv->uartclk = clk_get_rate(&clk);
+	clk_free(&clk);
 
 	/* initialize serial */
 	return pic32_serial_init(priv->base, priv->uartclk, CONFIG_BAUDRATE);
diff --git a/drivers/spi/rk_spi.c b/drivers/spi/rk_spi.c
index 9eff423acd12..617487ffdb5c 100644
--- a/drivers/spi/rk_spi.c
+++ b/drivers/spi/rk_spi.c
@@ -10,7 +10,7 @@ 
  */
 
 #include <common.h>
-#include <clk.h>
+#include <clk_client.h>
 #include <dm.h>
 #include <errno.h>
 #include <spi.h>
@@ -35,8 +35,7 @@  struct rockchip_spi_platdata {
 
 struct rockchip_spi_priv {
 	struct rockchip_spi *regs;
-	struct udevice *clk;
-	int clk_id;
+	struct clk clk;
 	unsigned int max_freq;
 	unsigned int mode;
 	ulong last_transaction_us;	/* Time of last transaction end */
@@ -144,7 +143,6 @@  static int rockchip_spi_ofdata_to_platdata(struct udevice *bus)
 		      bus->name, ret);
 		return ret;
 	}
-	priv->clk_id = ret;
 
 	plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
 					 50000000);
@@ -175,7 +173,7 @@  static int rockchip_spi_probe(struct udevice *bus)
 	 * Use 99 MHz as our clock since it divides nicely into 594 MHz which
 	 * is the assumed speed for CLK_GENERAL.
 	 */
-	ret = clk_set_periph_rate(priv->clk, priv->clk_id, 99000000);
+	ret = clk_set_rate(&priv->clk, 99000000);
 	if (ret < 0) {
 		debug("%s: Failed to set clock: %d\n", __func__, ret);
 		return ret;
diff --git a/drivers/usb/host/ehci-generic.c b/drivers/usb/host/ehci-generic.c
index 4444988e36fc..a2ae917f996b 100644
--- a/drivers/usb/host/ehci-generic.c
+++ b/drivers/usb/host/ehci-generic.c
@@ -5,7 +5,7 @@ 
  */
 
 #include <common.h>
-#include <clk.h>
+#include <clk_client.h>
 #include <asm/io.h>
 #include <dm.h>
 #include "ehci.h"
@@ -26,15 +26,15 @@  static int ehci_usb_probe(struct udevice *dev)
 	int i;
 
 	for (i = 0; ; i++) {
-		struct udevice *clk_dev;
-		int clk_id;
+		struct clk *clk;
+		int ret;
 
-		clk_id = clk_get_by_index(dev, i, &clk_dev);
-		if (clk_id < 0)
+		ret = clk_get_by_index(dev, i, &clk);
+		if (ret < 0)
 			break;
-		if (clk_enable(clk_dev, clk_id))
-			printf("failed to enable clock (dev=%s, id=%d)\n",
-			       clk_dev->name, clk_id);
+		if (clk_enable(&clk))
+			printf("failed to enable clock %d\n", i);
+		clk_free(&clk);
 	}
 
 	hccr = map_physmem(dev_get_addr(dev), 0x100, MAP_NOCACHE);
diff --git a/drivers/video/rockchip/rk_edp.c b/drivers/video/rockchip/rk_edp.c
index 124ddf684b51..2cf531399b83 100644
--- a/drivers/video/rockchip/rk_edp.c
+++ b/drivers/video/rockchip/rk_edp.c
@@ -6,7 +6,7 @@ 
  */
 
 #include <common.h>
-#include <clk.h>
+#include <clk_client.h>
 #include <display.h>
 #include <dm.h>
 #include <edid.h>
@@ -1009,8 +1009,7 @@  int rk_edp_probe(struct udevice *dev)
 	struct display_plat *uc_plat = dev_get_uclass_platdata(dev);
 	struct rk_edp_priv *priv = dev_get_priv(dev);
 	struct rk3288_edp *regs = priv->regs;
-	struct udevice *clk;
-	int periph;
+	struct clk clk;
 	int ret;
 
 	ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev, "rockchip,panel",
@@ -1026,8 +1025,8 @@  int rk_edp_probe(struct udevice *dev)
 
 	ret = clk_get_by_index(dev, 1, &clk);
 	if (ret >= 0) {
-		periph = ret;
-		ret = clk_set_periph_rate(clk, periph, 0);
+		ret = clk_set_rate(&clk, 0);
+		clk_free(&clk);
 	}
 	if (ret) {
 		debug("%s: Failed to set EDP clock: ret=%d\n", __func__, ret);
@@ -1036,8 +1035,8 @@  int rk_edp_probe(struct udevice *dev)
 
 	ret = clk_get_by_index(uc_plat->src_dev, 0, &clk);
 	if (ret >= 0) {
-		periph = ret;
-		ret = clk_set_periph_rate(clk, periph, 192000000);
+		ret = clk_set_rate(&clk, 192000000);
+		clk_free(&clk);
 	}
 	if (ret < 0) {
 		debug("%s: Failed to set clock in source device '%s': ret=%d\n",
diff --git a/drivers/video/rockchip/rk_hdmi.c b/drivers/video/rockchip/rk_hdmi.c
index 5fcb61ac2a3e..92535d0dd31d 100644
--- a/drivers/video/rockchip/rk_hdmi.c
+++ b/drivers/video/rockchip/rk_hdmi.c
@@ -6,7 +6,7 @@ 
  */
 
 #include <common.h>
-#include <clk.h>
+#include <clk_client.h>
 #include <display.h>
 #include <dm.h>
 #include <edid.h>
@@ -859,15 +859,15 @@  static int rk_hdmi_probe(struct udevice *dev)
 {
 	struct display_plat *uc_plat = dev_get_uclass_platdata(dev);
 	struct rk_hdmi_priv *priv = dev_get_priv(dev);
-	struct udevice *reg, *clk;
-	int periph;
+	struct udevice *reg;
+	struct clk clk;
 	int ret;
 	int vop_id = uc_plat->source_id;
 
 	ret = clk_get_by_index(dev, 0, &clk);
 	if (ret >= 0) {
-		periph = ret;
-		ret = clk_set_periph_rate(clk, periph, 0);
+		ret = clk_set_rate(&clk, 0);
+		clk_free(&clk);
 	}
 	if (ret) {
 		debug("%s: Failed to set EDP clock: ret=%d\n", __func__, ret);
@@ -880,8 +880,8 @@  static int rk_hdmi_probe(struct udevice *dev)
 	 */
 	ret = clk_get_by_index(uc_plat->src_dev, 0, &clk);
 	if (ret >= 0) {
-		periph = ret;
-		ret = clk_set_periph_rate(clk, periph, 384000000);
+		ret = clk_set_rate(&clk, 384000000);
+		clk_free(&clk);
 	}
 	if (ret < 0) {
 		debug("%s: Failed to set clock in source device '%s': ret=%d\n",
diff --git a/drivers/video/rockchip/rk_lvds.c b/drivers/video/rockchip/rk_lvds.c
index dc10b866c966..fcbb4d63d25f 100644
--- a/drivers/video/rockchip/rk_lvds.c
+++ b/drivers/video/rockchip/rk_lvds.c
@@ -5,7 +5,6 @@ 
  */
 
 #include <common.h>
-#include <clk.h>
 #include <display.h>
 #include <dm.h>
 #include <edid.h>
diff --git a/drivers/video/rockchip/rk_vop.c b/drivers/video/rockchip/rk_vop.c
index a54af172ec06..9ba7a1134e65 100644
--- a/drivers/video/rockchip/rk_vop.c
+++ b/drivers/video/rockchip/rk_vop.c
@@ -6,7 +6,7 @@ 
  */
 
 #include <common.h>
-#include <clk.h>
+#include <clk_client.h>
 #include <display.h>
 #include <dm.h>
 #include <edid.h>
@@ -195,7 +195,8 @@  int rk_display_init(struct udevice *dev, ulong fbbase,
 	struct udevice *disp;
 	int ret, remote, i, offset;
 	struct display_plat *disp_uc_plat;
-	struct udevice *clk;
+	struct udevice *dev_clk;
+	struct clk clk;
 
 	vop_id = fdtdec_get_int(blob, ep_node, "reg", -1);
 	debug("vop_id=%d\n", vop_id);
@@ -237,11 +238,13 @@  int rk_display_init(struct udevice *dev, ulong fbbase,
 		return ret;
 	}
 
-	ret = rkclk_get_clk(CLK_NEW, &clk);
+	ret = uclass_get_device(UCLASS_CLK, 0, &dev_clk);
 	if (!ret) {
-		ret = clk_set_periph_rate(clk, DCLK_VOP0 + remote_vop_id,
-					  timing.pixelclock.typ);
+		clk.id = DCLK_VOP0 + remote_vop_id;
+		ret = clk_request(dev_clk, &clk);
 	}
+	if (!ret)
+		ret = clk_set_rate(&clk, timing.pixelclock.typ);
 	if (ret) {
 		debug("%s: Failed to set pixel clock: ret=%d\n", __func__, ret);
 		return ret;
diff --git a/include/clk.h b/include/clk.h
deleted file mode 100644
index ca20c3dd27c1..000000000000
--- a/include/clk.h
+++ /dev/null
@@ -1,132 +0,0 @@ 
-/*
- * Copyright (c) 2015 Google, Inc
- * Written by Simon Glass <sjg@chromium.org>
- *
- * SPDX-License-Identifier:	GPL-2.0+
- */
-
-#ifndef _CLK_H_
-#define _CLK_H_
-
-#include <errno.h>
-#include <linux/types.h>
-
-struct udevice;
-
-int soc_clk_dump(void);
-
-struct clk_ops {
-	/**
-	 * get_rate() - Get current clock rate
-	 *
-	 * @dev:	Device to check (UCLASS_CLK)
-	 * @return clock rate in Hz, or -ve error code
-	 */
-	ulong (*get_rate)(struct udevice *dev);
-
-	/**
-	 * set_rate() - Set current clock rate
-	 *
-	 * @dev:	Device to adjust
-	 * @rate:	New clock rate in Hz
-	 * @return new rate, or -ve error code
-	 */
-	ulong (*set_rate)(struct udevice *dev, ulong rate);
-
-	/**
-	 * enable() - Enable the clock for a peripheral
-	 *
-	 * @dev:	clock provider
-	 * @periph:	Peripheral ID to enable
-	 * @return zero on success, or -ve error code
-	 */
-	int (*enable)(struct udevice *dev, int periph);
-
-	/**
-	 * get_periph_rate() - Get clock rate for a peripheral
-	 *
-	 * @dev:	Device to check (UCLASS_CLK)
-	 * @periph:	Peripheral ID to check
-	 * @return clock rate in Hz, or -ve error code
-	 */
-	ulong (*get_periph_rate)(struct udevice *dev, int periph);
-
-	/**
-	 * set_periph_rate() - Set current clock rate for a peripheral
-	 *
-	 * @dev:	Device to update (UCLASS_CLK)
-	 * @periph:	Peripheral ID to update
-	 * @return new clock rate in Hz, or -ve error code
-	 */
-	ulong (*set_periph_rate)(struct udevice *dev, int periph, ulong rate);
-};
-
-#define clk_get_ops(dev)	((struct clk_ops *)(dev)->driver->ops)
-
-/**
- * clk_get_rate() - Get current clock rate
- *
- * @dev:	Device to check (UCLASS_CLK)
- * @return clock rate in Hz, or -ve error code
- */
-ulong clk_get_rate(struct udevice *dev);
-
-/**
- * clk_set_rate() - Set current clock rate
- *
- * @dev:	Device to adjust
- * @rate:	New clock rate in Hz
- * @return new rate, or -ve error code
- */
-ulong clk_set_rate(struct udevice *dev, ulong rate);
-
-/**
- * clk_enable() - Enable the clock for a peripheral
- *
- * @dev:	clock provider
- * @periph:	Peripheral ID to enable
- * @return zero on success, or -ve error code
- */
-int clk_enable(struct udevice *dev, int periph);
-
-/**
- * clk_get_periph_rate() - Get current clock rate for a peripheral
- *
- * @dev:	Device to check (UCLASS_CLK)
- * @return clock rate in Hz, -ve error code
- */
-ulong clk_get_periph_rate(struct udevice *dev, int periph);
-
-/**
- * clk_set_periph_rate() - Set current clock rate for a peripheral
- *
- * @dev:	Device to update (UCLASS_CLK)
- * @periph:	Peripheral ID to update
- * @return new clock rate in Hz, or -ve error code
- */
-ulong clk_set_periph_rate(struct udevice *dev, int periph, ulong rate);
-
-#if CONFIG_IS_ENABLED(OF_CONTROL)
-/**
- * clk_get_by_index() - look up a clock referenced by a device
- *
- * Parse a device's 'clocks' list, returning information on the indexed clock,
- * ensuring that it is activated.
- *
- * @dev:	Device containing the clock reference
- * @index:	Clock index to return (0 = first)
- * @clk_devp:	Returns clock device
- * @return:	Peripheral ID for the device to control. This is the first
- *		argument after the clock node phandle. If there is no arguemnt,
- *		returns 0. Return -ve error code on any error
- */
-int clk_get_by_index(struct udevice *dev, int index, struct udevice **clk_devp);
-#else
-static inline int clk_get_by_index(struct udevice *dev, int index,
-				   struct udevice **clk_devp)
-{
-	return -ENOSYS;
-}
-#endif
-
-#endif /* _CLK_H_ */
diff --git a/include/clk_client.h b/include/clk_client.h
new file mode 100644
index 000000000000..6f2038fb4e4d
--- /dev/null
+++ b/include/clk_client.h
@@ -0,0 +1,174 @@ 
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _CLK_CLIENT_H
+#define _CLK_CLIENT_H
+
+#include <linux/types.h>
+
+/**
+ * A clock is a hardware signal that oscillates autonomously at a specific
+ * frequency and duty cycle. Most hardware modules require one or more clock
+ * signal to drive their operation. Clock signals are typically generated
+ * externally to the HW module consuming them, by an entity this API calls a
+ * clock provider. This API provides a standard means for drivers to enable and
+ * disable clocks, and to set the rate at which they oscillate.
+ *
+ * A driver that implements UCLASS_CLOCK is a clock provider. A provider will
+ * often implement multiple separate clocks, since the hardware it manages
+ * often has this capability. clock_uclass.h describes the interface which
+ * clock providers must implement.
+ *
+ * Clock consumers/clients are the HW modules driven by the clock signals. This
+ * header file describes the API used by drivers for those HW modules.
+ */
+
+struct udevice;
+
+/**
+ * struct clk - A handle to (allowing control of) a single clock.
+ *
+ * Clients provide storage for clock handles. The content of the structure is
+ * managed solely by the clock API and clock drivers. A clock struct is
+ * initialized by "get"ing the clock struct. The clock struct is passed to all
+ * other clock APIs to identify which clock signal to operate upon.
+ *
+ * @dev: The device which implements the clock signal.
+ * @id: The clock signal ID within the provider.
+ *
+ * Currently, the clock API assumes that a single integer ID is enough to
+ * identify and configure any clock signal for any clock provider. If this
+ * assumption becomes invalid in the future, the struct could be expanded to
+ * either (a) add more fields to allow clock providers to store additional
+ * information, or (b) replace the id field with an opaque pointer, which the
+ * provider would dynamically allocated during its .of_xlate op, and process
+ * during is .request op. This may require the addition of an extra op to clean
+ * up the allocation.
+ */
+struct clk {
+	struct udevice *dev;
+	/*
+	 * Written by of_xlate. We assume a single id is enough for now. In the
+	 * future, we might add more fields here.
+	 */
+	unsigned long id;
+};
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+/**
+ * clock_get_by_index - Get/request a clock by integer index.
+ *
+ * This looks up and requests a clock. The index is relative to the client
+ * device; each device is assumed to have n clocks associated with it somehow,
+ * and this function finds and requests one of them. The mapping of client
+ * device clock indices to provider clocks may be via device-tree properties,
+ * board-provided mapping tables, or some other mechanism.
+ *
+ * @dev:	The client device.
+ * @index:	The index of the clock to request, within the client's list of
+ *		clocks.
+ * @clock	A pointer to a clock struct to initialize.
+ * @return 0 if OK, or a negative error code.
+ */
+int clk_get_by_index(struct udevice *dev, int index, struct clk *clk);
+
+/**
+ * clock_get_by_name - Get/request a clock by name.
+ *
+ * This looks up and requests a clock. The name is relative to the client
+ * device; each device is assumed to have n clocks associated with it somehow,
+ * and this function finds and requests one of them. The mapping of client
+ * device clock names to provider clocks may be via device-tree properties,
+ * board-provided mapping tables, or some other mechanism.
+ *
+ * @dev:	The client device.
+ * @name:	The name of the clock to request, within the client's list of
+ *		clocks.
+ * @clock:	A pointer to a clock struct to initialize.
+ * @return 0 if OK, or a negative error code.
+ */
+int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk);
+#else
+static inline int clk_get_by_index(struct udevice *dev, int index,
+				   struct clk *clk)
+{
+	return -ENOSYS;
+}
+
+static int clk_get_by_name(struct udevice *dev, const char *name,
+			   struct clk *clk)
+{
+	return -ENOSYS;
+}
+#endif
+
+/**
+ * clk_request - Request a clock by provider-specific ID.
+ *
+ * This requests a clock using a provider-specific ID. Generally, this function
+ * should not be used, since clk_get_by_index/name() provide an interface that
+ * better separates clients from intimate knowledge of clock providers.
+ * However, this function may be useful in core SoC-specific code.
+ *
+ * @dev:	The clock provider device.
+ * @clock:	A pointer to a clock struct to initialize. The caller must
+ *		have already initialized any field in this struct which the
+ *		clock provider uses to identify the clock.
+ * @return 0 if OK, or a negative error code.
+ */
+int clk_request(struct udevice *dev, struct clk *clk);
+
+/**
+ * clock_free - Free a previously requested clock.
+ *
+ * @clock:	A clock struct that was previously successfully requested by
+ *		clk_request/get_by_*().
+ * @return 0 if OK, or a negative error code.
+ */
+int clk_free(struct clk *clk);
+
+/**
+ * clk_get_rate() - Get current clock rate.
+ *
+ * @clk:	A clock struct that was previously successfully requested by
+ *		clk_request/get_by_*().
+ * @return clock rate in Hz, or -ve error code.
+ */
+ulong clk_get_rate(struct clk *clk);
+
+/**
+ * clk_set_rate() - Set current clock rate.
+ *
+ * @clk:	A clock struct that was previously successfully requested by
+ *		clk_request/get_by_*().
+ * @rate:	New clock rate in Hz.
+ * @return new rate, or -ve error code.
+ */
+ulong clk_set_rate(struct clk *clk, ulong rate);
+
+/**
+ * clk_enable() - Enable (turn on) a clock.
+ *
+ * @clk:	A clock struct that was previously successfully requested by
+ *		clk_request/get_by_*().
+ * @return zero on success, or -ve error code.
+ */
+int clk_enable(struct clk *clk);
+
+/**
+ * clk_disable() - Disable (turn off) a clock.
+ *
+ * @clk:	A clock struct that was previously successfully requested by
+ *		clk_request/get_by_*().
+ * @return zero on success, or -ve error code.
+ */
+int clk_disable(struct clk *clk);
+
+int soc_clk_dump(void);
+
+#endif
diff --git a/include/clk_uclass.h b/include/clk_uclass.h
new file mode 100644
index 000000000000..74d69aadfbdc
--- /dev/null
+++ b/include/clk_uclass.h
@@ -0,0 +1,95 @@ 
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _CLK_UCLASS_H
+#define _CLK_UCLASS_H
+
+/* See clk_client.h for background documentation. */
+
+#include <clk_client.h>
+#include <fdtdec.h>
+
+/**
+ * struct clk_ops - The functions that a clock driver must implement.
+ */
+struct clk_ops {
+	/**
+	 * of_xlate - Translate a client's device-tree (OF) clock specifier.
+	 *
+	 * The clock core calls this function as the first step in implementing
+	 * a client's clk_get_by_*() call.
+	 *
+	 * If this function pointer is set to NULL, the clock core will use a
+	 * default implementation, which assumes #clock-cells = <1>, and that
+	 * the DT cell contains a simple integer clock ID.
+	 *
+	 * At present, the clock API solely supports device-tree. If this
+	 * changes, other xxx_xlate() functions may be added to support those
+	 * other mechanisms.
+	 *
+	 * @clock:	The clock struct to hold the translation result.
+	 * @args:	The clock specifier values from device tree.
+	 * @return 0 if OK, or a negative error code.
+	 */
+	int (*of_xlate)(struct clk *clock,
+			struct fdtdec_phandle_args *args);
+	/**
+	 * request - Request a translated clock.
+	 *
+	 * The clock core calls this function as the second step in
+	 * implementing a client's clk_get_by_*() call, following a successful
+	 * xxx_xlate() call, or as the only step in implementing a client's
+	 * clk_request() call.
+	 *
+	 * @clock:	The clock struct to request; this has been fille in by
+	 *		a previoux xxx_xlate() function call, or by the caller
+	 *		of clk_request().
+	 * @return 0 if OK, or a negative error code.
+	 */
+	int (*request)(struct clk *clock);
+	/**
+	 * free - Free a previously requested clock.
+	 *
+	 * This is the implementation of the client clk_free() API.
+	 *
+	 * @clock:	The clock to free.
+	 * @return 0 if OK, or a negative error code.
+	 */
+	int (*free)(struct clk *clock);
+	/**
+	 * get_rate() - Get current clock rate.
+	 *
+	 * @clk:	The clock to query.
+	 * @return clock rate in Hz, or -ve error code
+	 */
+	ulong (*get_rate)(struct clk *clk);
+	/**
+	 * set_rate() - Set current clock rate.
+	 *
+	 * @clk:	The clock to manipulate.
+	 * @rate:	New clock rate in Hz.
+	 * @return new rate, or -ve error code.
+	 */
+	ulong (*set_rate)(struct clk *clk, ulong rate);
+	/**
+	 * enable() - Enable a clock.
+	 *
+	 * @clk:	The clock to manipulate.
+	 * @return zero on success, or -ve error code.
+	 */
+	int (*enable)(struct clk *clk);
+	/**
+	 * disable() - Disable a clock.
+	 *
+	 * @clk:	The clock to manipulate.
+	 * @return zero on success, or -ve error code.
+	 */
+	int (*disable)(struct clk *clk);
+};
+
+#endif
diff --git a/test/dm/clk.c b/test/dm/clk.c
index 9ff6d9510343..712a1e674a55 100644
--- a/test/dm/clk.c
+++ b/test/dm/clk.c
@@ -5,55 +5,99 @@ 
  */
 
 #include <common.h>
-#include <clk.h>
 #include <dm.h>
-#include <asm/test.h>
+#include <asm/clk.h>
 #include <dm/test.h>
 #include <linux/err.h>
 #include <test/ut.h>
 
-/* Test that we can find and adjust clocks */
-static int dm_test_clk_base(struct unit_test_state *uts)
+static int dm_test_clk(struct unit_test_state *uts)
 {
-	struct udevice *clk;
+	struct udevice *dev_fixed, *dev_clk, *dev_test;
 	ulong rate;
 
-	ut_assertok(uclass_get_device(UCLASS_CLK, 0, &clk));
-	rate = clk_get_rate(clk);
-	ut_asserteq(SANDBOX_CLK_RATE, rate);
-	ut_asserteq(-EINVAL, clk_set_rate(clk, 0));
-	ut_assertok(clk_set_rate(clk, rate * 2));
-	ut_asserteq(SANDBOX_CLK_RATE * 2, clk_get_rate(clk));
+	ut_assertok(uclass_get_device_by_name(UCLASS_CLK, "clk-fixed",
+					      &dev_fixed));
 
-	return 0;
-}
-DM_TEST(dm_test_clk_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+	ut_assertok(uclass_get_device_by_name(UCLASS_CLK, "clk-sbox",
+					      &dev_clk));
+	ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_SPI));
+	ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_I2C));
+	ut_asserteq(0, sandbox_clk_query_rate(dev_clk, SANDBOX_CLK_ID_SPI));
+	ut_asserteq(0, sandbox_clk_query_rate(dev_clk, SANDBOX_CLK_ID_I2C));
 
-/* Test that peripheral clocks work as expected */
-static int dm_test_clk_periph(struct unit_test_state *uts)
-{
-	struct udevice *clk;
-	ulong rate;
+	ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "clk-test",
+					      &dev_test));
+	ut_assertok(sandbox_clk_test_get(dev_test));
 
-	ut_assertok(uclass_get_device(UCLASS_CLK, 0, &clk));
-	rate = clk_set_periph_rate(clk, PERIPH_ID_COUNT, 123);
-	ut_asserteq(-EINVAL, rate);
-	ut_asserteq(1, IS_ERR_VALUE(rate));
+	ut_asserteq(1234,
+		    sandbox_clk_test_get_rate(dev_test,
+					      SANDBOX_CLK_TEST_ID_FIXED));
+	ut_asserteq(0, sandbox_clk_test_get_rate(dev_test,
+						 SANDBOX_CLK_TEST_ID_SPI));
+	ut_asserteq(0, sandbox_clk_test_get_rate(dev_test,
+						 SANDBOX_CLK_TEST_ID_I2C));
 
-	rate = clk_set_periph_rate(clk, PERIPH_ID_SPI, 123);
-	ut_asserteq(0, rate);
-	ut_asserteq(123, clk_get_periph_rate(clk, PERIPH_ID_SPI));
+	rate = sandbox_clk_test_set_rate(dev_test, SANDBOX_CLK_TEST_ID_FIXED,
+					 12345);
+	ut_assert(IS_ERR_VALUE(rate));
+	rate = sandbox_clk_test_get_rate(dev_test, SANDBOX_CLK_TEST_ID_FIXED);
+	ut_asserteq(1234, rate);
 
-	rate = clk_set_periph_rate(clk, PERIPH_ID_SPI, 1234);
-	ut_asserteq(123, rate);
+	ut_asserteq(0, sandbox_clk_test_set_rate(dev_test,
+						 SANDBOX_CLK_TEST_ID_SPI,
+						 1000));
+	ut_asserteq(0, sandbox_clk_test_set_rate(dev_test,
+						 SANDBOX_CLK_TEST_ID_I2C,
+						 2000));
 
-	rate = clk_set_periph_rate(clk, PERIPH_ID_I2C, 567);
+	ut_asserteq(1000, sandbox_clk_test_get_rate(dev_test,
+						    SANDBOX_CLK_TEST_ID_SPI));
+	ut_asserteq(2000, sandbox_clk_test_get_rate(dev_test,
+						    SANDBOX_CLK_TEST_ID_I2C));
 
-	rate = clk_set_periph_rate(clk, PERIPH_ID_SPI, 1234);
-	ut_asserteq(1234, rate);
+	ut_asserteq(1000, sandbox_clk_test_set_rate(dev_test,
+						    SANDBOX_CLK_TEST_ID_SPI,
+						    10000));
+	ut_asserteq(2000, sandbox_clk_test_set_rate(dev_test,
+						    SANDBOX_CLK_TEST_ID_I2C,
+						    20000));
+
+	rate = sandbox_clk_test_set_rate(dev_test, SANDBOX_CLK_TEST_ID_SPI, 0);
+	ut_assert(IS_ERR_VALUE(rate));
+	rate = sandbox_clk_test_set_rate(dev_test, SANDBOX_CLK_TEST_ID_I2C, 0);
+	ut_assert(IS_ERR_VALUE(rate));
+
+	ut_asserteq(10000, sandbox_clk_test_get_rate(dev_test,
+						     SANDBOX_CLK_TEST_ID_SPI));
+	ut_asserteq(20000, sandbox_clk_test_get_rate(dev_test,
+						     SANDBOX_CLK_TEST_ID_I2C));
+
+	ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_SPI));
+	ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_I2C));
+	ut_asserteq(10000, sandbox_clk_query_rate(dev_clk, SANDBOX_CLK_ID_SPI));
+	ut_asserteq(20000, sandbox_clk_query_rate(dev_clk, SANDBOX_CLK_ID_I2C));
+
+	ut_assertok(sandbox_clk_test_enable(dev_test, SANDBOX_CLK_TEST_ID_SPI));
+	ut_asserteq(1, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_SPI));
+	ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_I2C));
+
+	ut_assertok(sandbox_clk_test_enable(dev_test, SANDBOX_CLK_TEST_ID_I2C));
+	ut_asserteq(1, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_SPI));
+	ut_asserteq(1, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_I2C));
+
+	ut_assertok(sandbox_clk_test_disable(dev_test,
+					     SANDBOX_CLK_TEST_ID_SPI));
+	ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_SPI));
+	ut_asserteq(1, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_I2C));
+
+	ut_assertok(sandbox_clk_test_disable(dev_test,
+					     SANDBOX_CLK_TEST_ID_I2C));
+	ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_SPI));
+	ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_I2C));
 
-	ut_asserteq(567, clk_get_periph_rate(clk, PERIPH_ID_I2C));
+	ut_assertok(sandbox_clk_test_free(dev_test));
 
 	return 0;
 }
-DM_TEST(dm_test_clk_periph, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+DM_TEST(dm_test_clk, DM_TESTF_SCAN_FDT);