diff mbox

[v11,1/2] clk: hisilicon: add common clock support

Message ID 1384306274-27315-2-git-send-email-haojian.zhuang@gmail.com
State Changes Requested
Headers show

Commit Message

Haojian Zhuang Nov. 13, 2013, 1:31 a.m. UTC
Enable common clock driver of Hi3620 SoC. clkgate-seperated driver is
used to support the clock gate that enable/disable/status registers
are seperated.

Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
 .../devicetree/bindings/clock/hi3620-clock.txt     |  19 ++
 drivers/clk/Makefile                               |   1 +
 drivers/clk/hisilicon/Makefile                     |   5 +
 drivers/clk/hisilicon/clk-hi3620.c                 | 242 +++++++++++++++++++++
 drivers/clk/hisilicon/clk.c                        | 171 +++++++++++++++
 drivers/clk/hisilicon/clk.h                        | 103 +++++++++
 drivers/clk/hisilicon/clkgate-seperated.c          | 130 +++++++++++
 include/dt-bindings/clock/hi3620-clock.h           | 152 +++++++++++++
 8 files changed, 823 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/hi3620-clock.txt
 create mode 100644 drivers/clk/hisilicon/Makefile
 create mode 100644 drivers/clk/hisilicon/clk-hi3620.c
 create mode 100644 drivers/clk/hisilicon/clk.c
 create mode 100644 drivers/clk/hisilicon/clk.h
 create mode 100644 drivers/clk/hisilicon/clkgate-seperated.c
 create mode 100644 include/dt-bindings/clock/hi3620-clock.h

Comments

Mark Rutland Nov. 13, 2013, 12:39 p.m. UTC | #1
On Wed, Nov 13, 2013 at 01:31:13AM +0000, Haojian Zhuang wrote:
> Enable common clock driver of Hi3620 SoC. clkgate-seperated driver is
> used to support the clock gate that enable/disable/status registers
> are seperated.

Typo: s/seperated/separated/

That seems to apply throughout the code and comments too.

> 
> Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
> ---
>  .../devicetree/bindings/clock/hi3620-clock.txt     |  19 ++
>  drivers/clk/Makefile                               |   1 +
>  drivers/clk/hisilicon/Makefile                     |   5 +
>  drivers/clk/hisilicon/clk-hi3620.c                 | 242 +++++++++++++++++++++
>  drivers/clk/hisilicon/clk.c                        | 171 +++++++++++++++
>  drivers/clk/hisilicon/clk.h                        | 103 +++++++++
>  drivers/clk/hisilicon/clkgate-seperated.c          | 130 +++++++++++
>  include/dt-bindings/clock/hi3620-clock.h           | 152 +++++++++++++
>  8 files changed, 823 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/hi3620-clock.txt
>  create mode 100644 drivers/clk/hisilicon/Makefile
>  create mode 100644 drivers/clk/hisilicon/clk-hi3620.c
>  create mode 100644 drivers/clk/hisilicon/clk.c
>  create mode 100644 drivers/clk/hisilicon/clk.h
>  create mode 100644 drivers/clk/hisilicon/clkgate-seperated.c
>  create mode 100644 include/dt-bindings/clock/hi3620-clock.h
> 
> diff --git a/Documentation/devicetree/bindings/clock/hi3620-clock.txt b/Documentation/devicetree/bindings/clock/hi3620-clock.txt
> new file mode 100644
> index 0000000..80e134d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/hi3620-clock.txt
> @@ -0,0 +1,19 @@
> +* Hisilicon Hi3620 Clock Controller
> +
> +The Hi3620 clock controller generates and supplies clock to various
> +controllers within the Hi3620 SoC.
> +
> +Required Properties:
> +
> +- comptible: should be one of the following.

s/comptible/compatible/

> +  - "hisilicon,hi3620-clock" - controller compatible with Hi3620 SoC.
> +
> +- reg: physical base address of the controller and length of memory mapped
> +  region.
> +
> +- #clock-cells: should be 1.
> +
> +Each clock is assigned an identifier and client nodes use this identifier
> +to specify the clock which they consume.
> +
> +All these identifier could be found in <dt-bindings/clock/hi3620-clock.h>.

With the typo fixed, the binding looks fine to me.

[...]

> +struct clk *hisi_register_clkgate_sep(struct device *dev, const char *name,
> +                                     const char *parent_name,
> +                                     unsigned long flags,
> +                                     void __iomem *reg, u8 bit_idx,
> +                                     u8 clk_gate_flags, spinlock_t *lock)
> +{
> +       struct clkgate_seperated *sclk;
> +       struct clk *clk;
> +       struct clk_init_data init;
> +
> +       sclk = kzalloc(sizeof(struct clkgate_seperated), GFP_KERNEL);

This could be neater:

sclk = kzalloc(sizeof(*sclk), GFP_KERNEL);

Thanks,
Mark.
Haojian Zhuang Nov. 13, 2013, 1:25 p.m. UTC | #2
On Wed, Nov 13, 2013 at 8:39 PM, Mark Rutland <mark.rutland@arm.com> wrote:
> On Wed, Nov 13, 2013 at 01:31:13AM +0000, Haojian Zhuang wrote:
>> Enable common clock driver of Hi3620 SoC. clkgate-seperated driver is
>> used to support the clock gate that enable/disable/status registers
>> are seperated.
>
> Typo: s/seperated/separated/
>
> That seems to apply throughout the code and comments too.
>
>>
>> Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
>> ---
>>  .../devicetree/bindings/clock/hi3620-clock.txt     |  19 ++
>>  drivers/clk/Makefile                               |   1 +
>>  drivers/clk/hisilicon/Makefile                     |   5 +
>>  drivers/clk/hisilicon/clk-hi3620.c                 | 242 +++++++++++++++++++++
>>  drivers/clk/hisilicon/clk.c                        | 171 +++++++++++++++
>>  drivers/clk/hisilicon/clk.h                        | 103 +++++++++
>>  drivers/clk/hisilicon/clkgate-seperated.c          | 130 +++++++++++
>>  include/dt-bindings/clock/hi3620-clock.h           | 152 +++++++++++++
>>  8 files changed, 823 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/clock/hi3620-clock.txt
>>  create mode 100644 drivers/clk/hisilicon/Makefile
>>  create mode 100644 drivers/clk/hisilicon/clk-hi3620.c
>>  create mode 100644 drivers/clk/hisilicon/clk.c
>>  create mode 100644 drivers/clk/hisilicon/clk.h
>>  create mode 100644 drivers/clk/hisilicon/clkgate-seperated.c
>>  create mode 100644 include/dt-bindings/clock/hi3620-clock.h
>>
>> diff --git a/Documentation/devicetree/bindings/clock/hi3620-clock.txt b/Documentation/devicetree/bindings/clock/hi3620-clock.txt
>> new file mode 100644
>> index 0000000..80e134d
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/clock/hi3620-clock.txt
>> @@ -0,0 +1,19 @@
>> +* Hisilicon Hi3620 Clock Controller
>> +
>> +The Hi3620 clock controller generates and supplies clock to various
>> +controllers within the Hi3620 SoC.
>> +
>> +Required Properties:
>> +
>> +- comptible: should be one of the following.
>
> s/comptible/compatible/
>
>> +  - "hisilicon,hi3620-clock" - controller compatible with Hi3620 SoC.
>> +
>> +- reg: physical base address of the controller and length of memory mapped
>> +  region.
>> +
>> +- #clock-cells: should be 1.
>> +
>> +Each clock is assigned an identifier and client nodes use this identifier
>> +to specify the clock which they consume.
>> +
>> +All these identifier could be found in <dt-bindings/clock/hi3620-clock.h>.
>
> With the typo fixed, the binding looks fine to me.
>
> [...]
>
>> +struct clk *hisi_register_clkgate_sep(struct device *dev, const char *name,
>> +                                     const char *parent_name,
>> +                                     unsigned long flags,
>> +                                     void __iomem *reg, u8 bit_idx,
>> +                                     u8 clk_gate_flags, spinlock_t *lock)
>> +{
>> +       struct clkgate_seperated *sclk;
>> +       struct clk *clk;
>> +       struct clk_init_data init;
>> +
>> +       sclk = kzalloc(sizeof(struct clkgate_seperated), GFP_KERNEL);
>
> This could be neater:
>
> sclk = kzalloc(sizeof(*sclk), GFP_KERNEL);
>
> Thanks,
> Mark.

OK. I'll fix it.

Mike,
I hope this patch could be merged into arm-soc tree. Could you help to
review this patch?

Regards
Haojian
Mike Turquette Nov. 18, 2013, 5:24 a.m. UTC | #3
Quoting Haojian Zhuang (2013-11-12 17:31:13)
> Enable common clock driver of Hi3620 SoC. clkgate-seperated driver is
> used to support the clock gate that enable/disable/status registers
> are seperated.

I've taken this patch in for testing after fixing the spelling of
'seperated'. It looks good to me. Per the discussion at the ARM Summit,
I'll take the clock patch through my tree and the dts patch goes through
the arm-soc tree.

Olof, Arnd Kevin & Grant: are we being strict and splitting the DT
binding description out into a third patch which goes through the DT
maintainers? If so that aspect needs to be culled from this patch,
though I'm happy to take this as-as.

Besides that this patch looks good to me. Thanks Haojian for reworking
it to fit the clock-controller model the discussions at the ARM Summit
and Linaro Connect.

Regards,
Mike

> 
> Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
> ---
>  .../devicetree/bindings/clock/hi3620-clock.txt     |  19 ++
>  drivers/clk/Makefile                               |   1 +
>  drivers/clk/hisilicon/Makefile                     |   5 +
>  drivers/clk/hisilicon/clk-hi3620.c                 | 242 +++++++++++++++++++++
>  drivers/clk/hisilicon/clk.c                        | 171 +++++++++++++++
>  drivers/clk/hisilicon/clk.h                        | 103 +++++++++
>  drivers/clk/hisilicon/clkgate-seperated.c          | 130 +++++++++++
>  include/dt-bindings/clock/hi3620-clock.h           | 152 +++++++++++++
>  8 files changed, 823 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/hi3620-clock.txt
>  create mode 100644 drivers/clk/hisilicon/Makefile
>  create mode 100644 drivers/clk/hisilicon/clk-hi3620.c
>  create mode 100644 drivers/clk/hisilicon/clk.c
>  create mode 100644 drivers/clk/hisilicon/clk.h
>  create mode 100644 drivers/clk/hisilicon/clkgate-seperated.c
>  create mode 100644 include/dt-bindings/clock/hi3620-clock.h
> 
> diff --git a/Documentation/devicetree/bindings/clock/hi3620-clock.txt b/Documentation/devicetree/bindings/clock/hi3620-clock.txt
> new file mode 100644
> index 0000000..80e134d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/hi3620-clock.txt
> @@ -0,0 +1,19 @@
> +* Hisilicon Hi3620 Clock Controller
> +
> +The Hi3620 clock controller generates and supplies clock to various
> +controllers within the Hi3620 SoC.
> +
> +Required Properties:
> +
> +- comptible: should be one of the following.
> +  - "hisilicon,hi3620-clock" - controller compatible with Hi3620 SoC.
> +
> +- reg: physical base address of the controller and length of memory mapped
> +  region.
> +
> +- #clock-cells: should be 1.
> +
> +Each clock is assigned an identifier and client nodes use this identifier
> +to specify the clock which they consume.
> +
> +All these identifier could be found in <dt-bindings/clock/hi3620-clock.h>.
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index 7b11106..e156b53 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -13,6 +13,7 @@ obj-$(CONFIG_COMMON_CLK)      += clk-composite.o
>  obj-$(CONFIG_ARCH_BCM2835)     += clk-bcm2835.o
>  obj-$(CONFIG_ARCH_NOMADIK)     += clk-nomadik.o
>  obj-$(CONFIG_ARCH_HIGHBANK)    += clk-highbank.o
> +obj-$(CONFIG_ARCH_HI3xxx)      += hisilicon/
>  obj-$(CONFIG_ARCH_NSPIRE)      += clk-nspire.o
>  obj-$(CONFIG_ARCH_MXS)         += mxs/
>  obj-$(CONFIG_ARCH_SOCFPGA)     += socfpga/
> diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile
> new file mode 100644
> index 0000000..fad958b
> --- /dev/null
> +++ b/drivers/clk/hisilicon/Makefile
> @@ -0,0 +1,5 @@
> +#
> +# Hisilicon Clock specific Makefile
> +#
> +
> +obj-y  += clk.o clkgate-seperated.o clk-hi3620.o
> diff --git a/drivers/clk/hisilicon/clk-hi3620.c b/drivers/clk/hisilicon/clk-hi3620.c
> new file mode 100644
> index 0000000..b66b074
> --- /dev/null
> +++ b/drivers/clk/hisilicon/clk-hi3620.c
> @@ -0,0 +1,242 @@
> +/*
> + * Hisilicon Hi3620 clock driver
> + *
> + * Copyright (c) 2012-2013 Hisilicon Limited.
> + * Copyright (c) 2012-2013 Linaro Limited.
> + *
> + * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
> + *        Xin Li <li.xin@linaro.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/slab.h>
> +#include <linux/clk.h>
> +
> +#include <dt-bindings/clock/hi3620-clock.h>
> +
> +#include "clk.h"
> +
> +/* clock parent list */
> +static const char *timer0_mux_p[] __initdata = { "osc32k", "timerclk01", };
> +static const char *timer1_mux_p[] __initdata = { "osc32k", "timerclk01", };
> +static const char *timer2_mux_p[] __initdata = { "osc32k", "timerclk23", };
> +static const char *timer3_mux_p[] __initdata = { "osc32k", "timerclk23", };
> +static const char *timer4_mux_p[] __initdata = { "osc32k", "timerclk45", };
> +static const char *timer5_mux_p[] __initdata = { "osc32k", "timerclk45", };
> +static const char *timer6_mux_p[] __initdata = { "osc32k", "timerclk67", };
> +static const char *timer7_mux_p[] __initdata = { "osc32k", "timerclk67", };
> +static const char *timer8_mux_p[] __initdata = { "osc32k", "timerclk89", };
> +static const char *timer9_mux_p[] __initdata = { "osc32k", "timerclk89", };
> +static const char *uart0_mux_p[] __initdata = { "osc26m", "pclk", };
> +static const char *uart1_mux_p[] __initdata = { "osc26m", "pclk", };
> +static const char *uart2_mux_p[] __initdata = { "osc26m", "pclk", };
> +static const char *uart3_mux_p[] __initdata = { "osc26m", "pclk", };
> +static const char *uart4_mux_p[] __initdata = { "osc26m", "pclk", };
> +static const char *spi0_mux_p[] __initdata = { "osc26m", "rclk_cfgaxi", };
> +static const char *spi1_mux_p[] __initdata = { "osc26m", "rclk_cfgaxi", };
> +static const char *spi2_mux_p[] __initdata = { "osc26m", "rclk_cfgaxi", };
> +/* share axi parent */
> +static const char *saxi_mux_p[] __initdata = { "armpll3", "armpll2", };
> +static const char *pwm0_mux_p[] __initdata = { "osc32k", "osc26m", };
> +static const char *pwm1_mux_p[] __initdata = { "osc32k", "osc26m", };
> +static const char *sd_mux_p[] __initdata = { "armpll3", "armpll2", };
> +static const char *mmc1_mux_p[] __initdata = { "armpll3", "armpll2", };
> +static const char *mmc1_mux2_p[] __initdata = { "osc26m", "mmc1_div", };
> +static const char *g2d_mux_p[] __initdata = { "armpll2", "armpll3", };
> +static const char *venc_mux_p[] __initdata = { "armpll2", "armpll3", };
> +static const char *vdec_mux_p[] __initdata = { "armpll2", "armpll3", };
> +static const char *vpp_mux_p[] __initdata = { "armpll2", "armpll3", };
> +static const char *edc0_mux_p[] __initdata = { "armpll2", "armpll3", };
> +static const char *ldi0_mux_p[] __initdata = { "armpll2", "armpll4",
> +                                            "armpll3", "armpll5", };
> +static const char *edc1_mux_p[] __initdata = { "armpll2", "armpll3", };
> +static const char *ldi1_mux_p[] __initdata = { "armpll2", "armpll4",
> +                                            "armpll3", "armpll5", };
> +static const char *rclk_hsic_p[] __initdata = { "armpll3", "armpll2", };
> +static const char *mmc2_mux_p[] __initdata = { "armpll3", "armpll2", };
> +static const char *mmc3_mux_p[] __initdata = { "armpll3", "armpll2", };
> +
> +
> +/* fixed rate clocks */
> +static struct hisi_fixed_rate_clock hi3620_fixed_rate_clks[] __initdata = {
> +       { HI3620_OSC32K,   "osc32k",   NULL, CLK_IS_ROOT, 32768, },
> +       { HI3620_OSC26M,   "osc26m",   NULL, CLK_IS_ROOT, 26000000, },
> +       { HI3620_PCLK,     "pclk",     NULL, CLK_IS_ROOT, 26000000, },
> +       { HI3620_PLL_ARM0, "armpll0",  NULL, CLK_IS_ROOT, 1600000000, },
> +       { HI3620_PLL_ARM1, "armpll1",  NULL, CLK_IS_ROOT, 1600000000, },
> +       { HI3620_PLL_PERI, "armpll2",  NULL, CLK_IS_ROOT, 1440000000, },
> +       { HI3620_PLL_USB,  "armpll3",  NULL, CLK_IS_ROOT, 1440000000, },
> +       { HI3620_PLL_HDMI, "armpll4",  NULL, CLK_IS_ROOT, 1188000000, },
> +       { HI3620_PLL_GPU,  "armpll5",  NULL, CLK_IS_ROOT, 1300000000, },
> +};
> +
> +/* fixed factor clocks */
> +static struct hisi_fixed_factor_clock hi3620_fixed_factor_clks[] __initdata = {
> +       { HI3620_RCLK_TCXO,   "rclk_tcxo",   "osc26m",   1, 4,  0, },
> +       { HI3620_RCLK_CFGAXI, "rclk_cfgaxi", "armpll2",  1, 30, 0, },
> +       { HI3620_RCLK_PICO,   "rclk_pico",   "hsic_div", 1, 40, 0, },
> +};
> +
> +static struct hisi_mux_clock hi3620_mux_clks[] __initdata = {
> +       { HI3620_TIMER0_MUX, "timer0_mux", timer0_mux_p, ARRAY_SIZE(timer0_mux_p), CLK_SET_RATE_PARENT, 0,     15, 2, 0,                   },
> +       { HI3620_TIMER1_MUX, "timer1_mux", timer1_mux_p, ARRAY_SIZE(timer1_mux_p), CLK_SET_RATE_PARENT, 0,     17, 2, 0,                   },
> +       { HI3620_TIMER2_MUX, "timer2_mux", timer2_mux_p, ARRAY_SIZE(timer2_mux_p), CLK_SET_RATE_PARENT, 0,     19, 2, 0,                   },
> +       { HI3620_TIMER3_MUX, "timer3_mux", timer3_mux_p, ARRAY_SIZE(timer3_mux_p), CLK_SET_RATE_PARENT, 0,     21, 2, 0,                   },
> +       { HI3620_TIMER4_MUX, "timer4_mux", timer4_mux_p, ARRAY_SIZE(timer4_mux_p), CLK_SET_RATE_PARENT, 0x18,  0,  2, 0,                   },
> +       { HI3620_TIMER5_MUX, "timer5_mux", timer5_mux_p, ARRAY_SIZE(timer5_mux_p), CLK_SET_RATE_PARENT, 0x18,  2,  2, 0,                   },
> +       { HI3620_TIMER6_MUX, "timer6_mux", timer6_mux_p, ARRAY_SIZE(timer6_mux_p), CLK_SET_RATE_PARENT, 0x18,  4,  2, 0,                   },
> +       { HI3620_TIMER7_MUX, "timer7_mux", timer7_mux_p, ARRAY_SIZE(timer7_mux_p), CLK_SET_RATE_PARENT, 0x18,  6,  2, 0,                   },
> +       { HI3620_TIMER8_MUX, "timer8_mux", timer8_mux_p, ARRAY_SIZE(timer8_mux_p), CLK_SET_RATE_PARENT, 0x18,  8,  2, 0,                   },
> +       { HI3620_TIMER9_MUX, "timer9_mux", timer9_mux_p, ARRAY_SIZE(timer9_mux_p), CLK_SET_RATE_PARENT, 0x18,  10, 2, 0,                   },
> +       { HI3620_UART0_MUX,  "uart0_mux",  uart0_mux_p,  ARRAY_SIZE(uart0_mux_p),  CLK_SET_RATE_PARENT, 0x100, 7,  1, CLK_MUX_HIWORD_MASK, },
> +       { HI3620_UART1_MUX,  "uart1_mux",  uart1_mux_p,  ARRAY_SIZE(uart1_mux_p),  CLK_SET_RATE_PARENT, 0x100, 8,  1, CLK_MUX_HIWORD_MASK, },
> +       { HI3620_UART2_MUX,  "uart2_mux",  uart2_mux_p,  ARRAY_SIZE(uart2_mux_p),  CLK_SET_RATE_PARENT, 0x100, 9,  1, CLK_MUX_HIWORD_MASK, },
> +       { HI3620_UART3_MUX,  "uart3_mux",  uart3_mux_p,  ARRAY_SIZE(uart3_mux_p),  CLK_SET_RATE_PARENT, 0x100, 10, 1, CLK_MUX_HIWORD_MASK, },
> +       { HI3620_UART4_MUX,  "uart4_mux",  uart4_mux_p,  ARRAY_SIZE(uart4_mux_p),  CLK_SET_RATE_PARENT, 0x100, 11, 1, CLK_MUX_HIWORD_MASK, },
> +       { HI3620_SPI0_MUX,   "spi0_mux",   spi0_mux_p,   ARRAY_SIZE(spi0_mux_p),   CLK_SET_RATE_PARENT, 0x100, 12, 1, CLK_MUX_HIWORD_MASK, },
> +       { HI3620_SPI1_MUX,   "spi1_mux",   spi1_mux_p,   ARRAY_SIZE(spi1_mux_p),   CLK_SET_RATE_PARENT, 0x100, 13, 1, CLK_MUX_HIWORD_MASK, },
> +       { HI3620_SPI2_MUX,   "spi2_mux",   spi2_mux_p,   ARRAY_SIZE(spi2_mux_p),   CLK_SET_RATE_PARENT, 0x100, 14, 1, CLK_MUX_HIWORD_MASK, },
> +       { HI3620_SAXI_MUX,   "saxi_mux",   saxi_mux_p,   ARRAY_SIZE(saxi_mux_p),   CLK_SET_RATE_PARENT, 0x100, 15, 1, CLK_MUX_HIWORD_MASK, },
> +       { HI3620_PWM0_MUX,   "pwm0_mux",   pwm0_mux_p,   ARRAY_SIZE(pwm0_mux_p),   CLK_SET_RATE_PARENT, 0x104, 10, 1, CLK_MUX_HIWORD_MASK, },
> +       { HI3620_PWM1_MUX,   "pwm1_mux",   pwm1_mux_p,   ARRAY_SIZE(pwm1_mux_p),   CLK_SET_RATE_PARENT, 0x104, 11, 1, CLK_MUX_HIWORD_MASK, },
> +       { HI3620_SD_MUX,     "sd_mux",     sd_mux_p,     ARRAY_SIZE(sd_mux_p),     CLK_SET_RATE_PARENT, 0x108, 4,  1, CLK_MUX_HIWORD_MASK, },
> +       { HI3620_MMC1_MUX,   "mmc1_mux",   mmc1_mux_p,   ARRAY_SIZE(mmc1_mux_p),   CLK_SET_RATE_PARENT, 0x108, 9,  1, CLK_MUX_HIWORD_MASK, },
> +       { HI3620_MMC1_MUX2,  "mmc1_mux2",  mmc1_mux2_p,  ARRAY_SIZE(mmc1_mux2_p),  CLK_SET_RATE_PARENT, 0x108, 10, 1, CLK_MUX_HIWORD_MASK, },
> +       { HI3620_G2D_MUX,    "g2d_mux",    g2d_mux_p,    ARRAY_SIZE(g2d_mux_p),    CLK_SET_RATE_PARENT, 0x10c, 5,  1, CLK_MUX_HIWORD_MASK, },
> +       { HI3620_VENC_MUX,   "venc_mux",   venc_mux_p,   ARRAY_SIZE(venc_mux_p),   CLK_SET_RATE_PARENT, 0x10c, 11, 1, CLK_MUX_HIWORD_MASK, },
> +       { HI3620_VDEC_MUX,   "vdec_mux",   vdec_mux_p,   ARRAY_SIZE(vdec_mux_p),   CLK_SET_RATE_PARENT, 0x110, 5,  1, CLK_MUX_HIWORD_MASK, },
> +       { HI3620_VPP_MUX,    "vpp_mux",    vpp_mux_p,    ARRAY_SIZE(vpp_mux_p),    CLK_SET_RATE_PARENT, 0x110, 11, 1, CLK_MUX_HIWORD_MASK, },
> +       { HI3620_EDC0_MUX,   "edc0_mux",   edc0_mux_p,   ARRAY_SIZE(edc0_mux_p),   CLK_SET_RATE_PARENT, 0x114, 6,  1, CLK_MUX_HIWORD_MASK, },
> +       { HI3620_LDI0_MUX,   "ldi0_mux",   ldi0_mux_p,   ARRAY_SIZE(ldi0_mux_p),   CLK_SET_RATE_PARENT, 0x114, 13, 2, CLK_MUX_HIWORD_MASK, },
> +       { HI3620_EDC1_MUX,   "edc1_mux",   edc1_mux_p,   ARRAY_SIZE(edc1_mux_p),   CLK_SET_RATE_PARENT, 0x118, 6,  1, CLK_MUX_HIWORD_MASK, },
> +       { HI3620_LDI1_MUX,   "ldi1_mux",   ldi1_mux_p,   ARRAY_SIZE(ldi1_mux_p),   CLK_SET_RATE_PARENT, 0x118, 14, 2, CLK_MUX_HIWORD_MASK, },
> +       { HI3620_RCLK_HSIC,  "rclk_hsic",  rclk_hsic_p,  ARRAY_SIZE(rclk_hsic_p),  CLK_SET_RATE_PARENT, 0x130, 2,  1, CLK_MUX_HIWORD_MASK, },
> +       { HI3620_MMC2_MUX,   "mmc2_mux",   mmc2_mux_p,   ARRAY_SIZE(mmc2_mux_p),   CLK_SET_RATE_PARENT, 0x140, 4,  1, CLK_MUX_HIWORD_MASK, },
> +       { HI3620_MMC3_MUX,   "mmc3_mux",   mmc3_mux_p,   ARRAY_SIZE(mmc3_mux_p),   CLK_SET_RATE_PARENT, 0x140, 9,  1, CLK_MUX_HIWORD_MASK, },
> +};
> +
> +static struct hisi_divider_clock hi3620_div_clks[] __initdata = {
> +       { HI3620_SHAREAXI_DIV, "saxi_div",   "saxi_mux",  0, 0x100, 0, 5, CLK_MUX_HIWORD_MASK, NULL, },
> +       { HI3620_CFGAXI_DIV,   "cfgaxi_div", "saxi_div",  0, 0x100, 5, 2, CLK_MUX_HIWORD_MASK, NULL, },
> +       { HI3620_SD_DIV,       "sd_div",     "sd_mux",    0, 0x108, 0, 4, CLK_MUX_HIWORD_MASK, NULL, },
> +       { HI3620_MMC1_DIV,     "mmc1_div",   "mmc1_mux",  0, 0x108, 5, 4, CLK_MUX_HIWORD_MASK, NULL, },
> +       { HI3620_HSIC_DIV,     "hsic_div",   "rclk_hsic", 0, 0x130, 0, 2, CLK_MUX_HIWORD_MASK, NULL, },
> +       { HI3620_MMC2_DIV,     "mmc2_div",   "mmc2_mux",  0, 0x140, 0, 4, CLK_MUX_HIWORD_MASK, NULL, },
> +       { HI3620_MMC3_DIV,     "mmc3_div",   "mmc3_mux",  0, 0x140, 5, 4, CLK_MUX_HIWORD_MASK, NULL, },
> +};
> +
> +static struct hisi_gate_clock hi3620_seperated_gate_clks[] __initdata = {
> +       { HI3620_TIMERCLK01,   "timerclk01",   "timer_rclk01", 0, 0x20, 0, 0, },
> +       { HI3620_TIMER_RCLK01, "timer_rclk01", "rclk_tcxo",    0, 0x20, 1, 0, },
> +       { HI3620_TIMERCLK23,   "timerclk23",   "timer_rclk23", 0, 0x20, 2, 0, },
> +       { HI3620_TIMER_RCLK23, "timer_rclk23", "rclk_tcxo",    0, 0x20, 3, 0, },
> +       { HI3620_RTCCLK,       "rtcclk",       "pclk",         0, 0x20, 5, 0, },
> +       { HI3620_KPC_CLK,      "kpc_clk",      "pclk",         0, 0x20, 6, 0, },
> +       { HI3620_GPIOCLK0,     "gpioclk0",     "pclk",         0, 0x20, 8, 0, },
> +       { HI3620_GPIOCLK1,     "gpioclk1",     "pclk",         0, 0x20, 9, 0, },
> +       { HI3620_GPIOCLK2,     "gpioclk2",     "pclk",         0, 0x20, 10, 0, },
> +       { HI3620_GPIOCLK3,     "gpioclk3",     "pclk",         0, 0x20, 11, 0, },
> +       { HI3620_GPIOCLK4,     "gpioclk4",     "pclk",         0, 0x20, 12, 0, },
> +       { HI3620_GPIOCLK5,     "gpioclk5",     "pclk",         0, 0x20, 13, 0, },
> +       { HI3620_GPIOCLK6,     "gpioclk6",     "pclk",         0, 0x20, 14, 0, },
> +       { HI3620_GPIOCLK7,     "gpioclk7",     "pclk",         0, 0x20, 15, 0, },
> +       { HI3620_GPIOCLK8,     "gpioclk8",     "pclk",         0, 0x20, 16, 0, },
> +       { HI3620_GPIOCLK9,     "gpioclk9",     "pclk",         0, 0x20, 17, 0, },
> +       { HI3620_GPIOCLK10,    "gpioclk10",    "pclk",         0, 0x20, 18, 0, },
> +       { HI3620_GPIOCLK11,    "gpioclk11",    "pclk",         0, 0x20, 19, 0, },
> +       { HI3620_GPIOCLK12,    "gpioclk12",    "pclk",         0, 0x20, 20, 0, },
> +       { HI3620_GPIOCLK13,    "gpioclk13",    "pclk",         0, 0x20, 21, 0, },
> +       { HI3620_GPIOCLK14,    "gpioclk14",    "pclk",         0, 0x20, 22, 0, },
> +       { HI3620_GPIOCLK15,    "gpioclk15",    "pclk",         0, 0x20, 23, 0, },
> +       { HI3620_GPIOCLK16,    "gpioclk16",    "pclk",         0, 0x20, 24, 0, },
> +       { HI3620_GPIOCLK17,    "gpioclk17",    "pclk",         0, 0x20, 25, 0, },
> +       { HI3620_GPIOCLK18,    "gpioclk18",    "pclk",         0, 0x20, 26, 0, },
> +       { HI3620_GPIOCLK19,    "gpioclk19",    "pclk",         0, 0x20, 27, 0, },
> +       { HI3620_GPIOCLK20,    "gpioclk20",    "pclk",         0, 0x20, 28, 0, },
> +       { HI3620_GPIOCLK21,    "gpioclk21",    "pclk",         0, 0x20, 29, 0, },
> +       { HI3620_DPHY0_CLK,    "dphy0_clk",    "osc26m",       0, 0x30, 15, 0, },
> +       { HI3620_DPHY1_CLK,    "dphy1_clk",    "osc26m",       0, 0x30, 16, 0, },
> +       { HI3620_DPHY2_CLK,    "dphy2_clk",    "osc26m",       0, 0x30, 17, 0, },
> +       { HI3620_USBPHY_CLK,   "usbphy_clk",   "rclk_pico",    0, 0x30, 24, 0, },
> +       { HI3620_ACP_CLK,      "acp_clk",      "rclk_cfgaxi",  0, 0x30, 28, 0, },
> +       { HI3620_TIMERCLK45,   "timerclk45",   "rclk_tcxo",    0, 0x40, 3, 0, },
> +       { HI3620_TIMERCLK67,   "timerclk67",   "rclk_tcxo",    0, 0x40, 4, 0, },
> +       { HI3620_TIMERCLK89,   "timerclk89",   "rclk_tcxo",    0, 0x40, 5, 0, },
> +       { HI3620_PWMCLK0,      "pwmclk0",      "pwm0_mux",     0, 0x40, 7, 0, },
> +       { HI3620_PWMCLK1,      "pwmclk1",      "pwm1_mux",     0, 0x40, 8, 0, },
> +       { HI3620_UARTCLK0,     "uartclk0",     "uart0_mux",    0, 0x40, 16, 0, },
> +       { HI3620_UARTCLK1,     "uartclk1",     "uart1_mux",    0, 0x40, 17, 0, },
> +       { HI3620_UARTCLK2,     "uartclk2",     "uart2_mux",    0, 0x40, 18, 0, },
> +       { HI3620_UARTCLK3,     "uartclk3",     "uart3_mux",    0, 0x40, 19, 0, },
> +       { HI3620_UARTCLK4,     "uartclk4",     "uart4_mux",    0, 0x40, 20, 0, },
> +       { HI3620_SPICLK0,      "spiclk0",      "spi0_mux",     0, 0x40, 21, 0, },
> +       { HI3620_SPICLK1,      "spiclk1",      "spi1_mux",     0, 0x40, 22, 0, },
> +       { HI3620_SPICLK2,      "spiclk2",      "spi2_mux",     0, 0x40, 23, 0, },
> +       { HI3620_I2CCLK0,      "i2cclk0",      "pclk",         0, 0x40, 24, 0, },
> +       { HI3620_I2CCLK1,      "i2cclk1",      "pclk",         0, 0x40, 25, 0, },
> +       { HI3620_SCI_CLK,      "sci_clk",      "osc26m",       0, 0x40, 26, 0, },
> +       { HI3620_I2CCLK2,      "i2cclk2",      "pclk",         0, 0x40, 28, 0, },
> +       { HI3620_I2CCLK3,      "i2cclk3",      "pclk",         0, 0x40, 29, 0, },
> +       { HI3620_DDRC_PER_CLK, "ddrc_per_clk", "rclk_cfgaxi",  0, 0x50, 9, 0, },
> +       { HI3620_DMAC_CLK,     "dmac_clk",     "rclk_cfgaxi",  0, 0x50, 10, 0, },
> +       { HI3620_USB2DVC_CLK,  "usb2dvc_clk",  "rclk_cfgaxi",  0, 0x50, 17, 0, },
> +       { HI3620_SD_CLK,       "sd_clk",       "sd_div",       0, 0x50, 20, 0, },
> +       { HI3620_MMC_CLK1,     "mmc_clk1",     "mmc1_mux2",    0, 0x50, 21, 0, },
> +       { HI3620_MMC_CLK2,     "mmc_clk2",     "mmc2_div",     0, 0x50, 22, 0, },
> +       { HI3620_MMC_CLK3,     "mmc_clk3",     "mmc3_div",     0, 0x50, 23, 0, },
> +       { HI3620_MCU_CLK,      "mcu_clk",      "acp_clk",      0, 0x50, 24, 0, },
> +};
> +
> +static void __init hi3620_clk_init(struct device_node *np)
> +{
> +       void __iomem *base;
> +
> +       if (np) {
> +               base = of_iomap(np, 0);
> +               if (!base) {
> +                       pr_err("failed to map Hi3620 clock registers\n");
> +                       return;
> +               }
> +       } else {
> +               pr_err("failed to find Hi3620 clock node in DTS\n");
> +               return;
> +       }
> +
> +       hisi_clk_init(np, HI3620_NR_CLKS);
> +
> +       hisi_clk_register_fixed_rate(hi3620_fixed_rate_clks,
> +                                    ARRAY_SIZE(hi3620_fixed_rate_clks),
> +                                    base);
> +       hisi_clk_register_fixed_factor(hi3620_fixed_factor_clks,
> +                                      ARRAY_SIZE(hi3620_fixed_factor_clks),
> +                                      base);
> +       hisi_clk_register_mux(hi3620_mux_clks, ARRAY_SIZE(hi3620_mux_clks),
> +                             base);
> +       hisi_clk_register_divider(hi3620_div_clks, ARRAY_SIZE(hi3620_div_clks),
> +                                 base);
> +       hisi_clk_register_gate_sep(hi3620_seperated_gate_clks,
> +                                  ARRAY_SIZE(hi3620_seperated_gate_clks),
> +                                  base);
> +}
> +CLK_OF_DECLARE(hi3620_clk, "hisilicon,hi3620-clock", hi3620_clk_init);
> diff --git a/drivers/clk/hisilicon/clk.c b/drivers/clk/hisilicon/clk.c
> new file mode 100644
> index 0000000..a3a7152
> --- /dev/null
> +++ b/drivers/clk/hisilicon/clk.c
> @@ -0,0 +1,171 @@
> +/*
> + * Hisilicon clock driver
> + *
> + * Copyright (c) 2012-2013 Hisilicon Limited.
> + * Copyright (c) 2012-2013 Linaro Limited.
> + *
> + * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
> + *        Xin Li <li.xin@linaro.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/slab.h>
> +#include <linux/clk.h>
> +
> +#include "clk.h"
> +
> +static DEFINE_SPINLOCK(hisi_clk_lock);
> +static struct clk **clk_table;
> +static struct clk_onecell_data clk_data;
> +
> +void __init hisi_clk_init(struct device_node *np, int nr_clks)
> +{
> +       clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
> +       if (!clk_table) {
> +               pr_err("%s: could not allocate clock lookup table\n", __func__);
> +               return;
> +       }
> +       clk_data.clks = clk_table;
> +       clk_data.clk_num = nr_clks;
> +       of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
> +}
> +
> +void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *clks,
> +                                        int nums, void __iomem *base)
> +{
> +       struct clk *clk;
> +       int i;
> +
> +       for (i = 0; i < nums; i++) {
> +               clk = clk_register_fixed_rate(NULL, clks[i].name,
> +                                             clks[i].parent_name,
> +                                             clks[i].flags,
> +                                             clks[i].fixed_rate);
> +               if (IS_ERR(clk)) {
> +                       pr_err("%s: failed to register clock %s\n",
> +                              __func__, clks[i].name);
> +                       continue;
> +               }
> +       }
> +}
> +
> +void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *clks,
> +                                          int nums, void __iomem *base)
> +{
> +       struct clk *clk;
> +       int i;
> +
> +       for (i = 0; i < nums; i++) {
> +               clk = clk_register_fixed_factor(NULL, clks[i].name,
> +                                               clks[i].parent_name,
> +                                               clks[i].flags, clks[i].mult,
> +                                               clks[i].div);
> +               if (IS_ERR(clk)) {
> +                       pr_err("%s: failed to register clock %s\n",
> +                              __func__, clks[i].name);
> +                       continue;
> +               }
> +       }
> +}
> +
> +void __init hisi_clk_register_mux(struct hisi_mux_clock *clks,
> +                                 int nums, void __iomem *base)
> +{
> +       struct clk *clk;
> +       int i;
> +
> +       for (i = 0; i < nums; i++) {
> +               clk = clk_register_mux(NULL, clks[i].name, clks[i].parent_names,
> +                                      clks[i].num_parents, clks[i].flags,
> +                                      base + clks[i].offset, clks[i].shift,
> +                                      clks[i].width, clks[i].mux_flags,
> +                                      &hisi_clk_lock);
> +               if (IS_ERR(clk)) {
> +                       pr_err("%s: failed to register clock %s\n",
> +                              __func__, clks[i].name);
> +                       continue;
> +               }
> +
> +               if (clks[i].alias)
> +                       clk_register_clkdev(clk, clks[i].alias, NULL);
> +
> +               clk_table[clks[i].id] = clk;
> +       }
> +}
> +
> +void __init hisi_clk_register_divider(struct hisi_divider_clock *clks,
> +                                     int nums, void __iomem *base)
> +{
> +       struct clk *clk;
> +       int i;
> +
> +       for (i = 0; i < nums; i++) {
> +               clk = clk_register_divider_table(NULL, clks[i].name,
> +                                                clks[i].parent_name,
> +                                                clks[i].flags,
> +                                                base + clks[i].offset,
> +                                                clks[i].shift, clks[i].width,
> +                                                clks[i].div_flags,
> +                                                clks[i].table,
> +                                                &hisi_clk_lock);
> +               if (IS_ERR(clk)) {
> +                       pr_err("%s: failed to register clock %s\n",
> +                              __func__, clks[i].name);
> +                       continue;
> +               }
> +
> +               if (clks[i].alias)
> +                       clk_register_clkdev(clk, clks[i].alias, NULL);
> +
> +               clk_table[clks[i].id] = clk;
> +       }
> +}
> +
> +void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks,
> +                                      int nums, void __iomem *base)
> +{
> +       struct clk *clk;
> +       int i;
> +
> +       for (i = 0; i < nums; i++) {
> +               clk = hisi_register_clkgate_sep(NULL, clks[i].name,
> +                                               clks[i].parent_name,
> +                                               clks[i].flags,
> +                                               base + clks[i].offset,
> +                                               clks[i].bit_idx,
> +                                               clks[i].gate_flags,
> +                                               &hisi_clk_lock);
> +               if (IS_ERR(clk)) {
> +                       pr_err("%s: failed to register clock %s\n",
> +                              __func__, clks[i].name);
> +                       continue;
> +               }
> +
> +               if (clks[i].alias)
> +                       clk_register_clkdev(clk, clks[i].alias, NULL);
> +
> +               clk_table[clks[i].id] = clk;
> +       }
> +}
> diff --git a/drivers/clk/hisilicon/clk.h b/drivers/clk/hisilicon/clk.h
> new file mode 100644
> index 0000000..4a6beeb
> --- /dev/null
> +++ b/drivers/clk/hisilicon/clk.h
> @@ -0,0 +1,103 @@
> +/*
> + * Hisilicon Hi3620 clock gate driver
> + *
> + * Copyright (c) 2012-2013 Hisilicon Limited.
> + * Copyright (c) 2012-2013 Linaro Limited.
> + *
> + * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
> + *        Xin Li <li.xin@linaro.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + */
> +
> +#ifndef        __HISI_CLK_H
> +#define        __HISI_CLK_H
> +
> +#include <linux/clk-provider.h>
> +#include <linux/io.h>
> +#include <linux/spinlock.h>
> +
> +struct hisi_fixed_rate_clock {
> +       unsigned int            id;
> +       char                    *name;
> +       const char              *parent_name;
> +       unsigned long           flags;
> +       unsigned long           fixed_rate;
> +};
> +
> +struct hisi_fixed_factor_clock {
> +       unsigned int            id;
> +       char                    *name;
> +       const char              *parent_name;
> +       unsigned long           mult;
> +       unsigned long           div;
> +       unsigned long           flags;
> +};
> +
> +struct hisi_mux_clock {
> +       unsigned int            id;
> +       const char              *name;
> +       const char              **parent_names;
> +       u8                      num_parents;
> +       unsigned long           flags;
> +       unsigned long           offset;
> +       u8                      shift;
> +       u8                      width;
> +       u8                      mux_flags;
> +       const char              *alias;
> +};
> +
> +struct hisi_divider_clock {
> +       unsigned int            id;
> +       const char              *name;
> +       const char              *parent_name;
> +       unsigned long           flags;
> +       unsigned long           offset;
> +       u8                      shift;
> +       u8                      width;
> +       u8                      div_flags;
> +       struct clk_div_table    *table;
> +       const char              *alias;
> +};
> +
> +struct hisi_gate_clock {
> +       unsigned int            id;
> +       const char              *name;
> +       const char              *parent_name;
> +       unsigned long           flags;
> +       unsigned long           offset;
> +       u8                      bit_idx;
> +       u8                      gate_flags;
> +       const char              *alias;
> +};
> +
> +struct clk *hisi_register_clkgate_sep(struct device *, const char *,
> +                               const char *, unsigned long,
> +                               void __iomem *, u8,
> +                               u8, spinlock_t *);
> +
> +void __init hisi_clk_init(struct device_node *, int);
> +void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *,
> +                                       int, void __iomem *);
> +void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *,
> +                                       int, void __iomem *);
> +void __init hisi_clk_register_mux(struct hisi_mux_clock *, int,
> +                               void __iomem *);
> +void __init hisi_clk_register_divider(struct hisi_divider_clock *,
> +                               int, void __iomem *);
> +void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *,
> +                                       int, void __iomem *);
> +#endif /* __HISI_CLK_H */
> diff --git a/drivers/clk/hisilicon/clkgate-seperated.c b/drivers/clk/hisilicon/clkgate-seperated.c
> new file mode 100644
> index 0000000..cddc6d3
> --- /dev/null
> +++ b/drivers/clk/hisilicon/clkgate-seperated.c
> @@ -0,0 +1,130 @@
> +/*
> + * Hisilicon clock seperated gate driver
> + *
> + * Copyright (c) 2012-2013 Hisilicon Limited.
> + * Copyright (c) 2012-2013 Linaro Limited.
> + *
> + * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
> + *        Xin Li <li.xin@linaro.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/io.h>
> +#include <linux/slab.h>
> +#include <linux/clk.h>
> +
> +#include "clk.h"
> +
> +/* clock seperated gate register offset */
> +#define CLKGATE_SEPERATED_ENABLE               0x0
> +#define CLKGATE_SEPERATED_DISABLE              0x4
> +#define CLKGATE_SEPERATED_STATUS               0x8
> +
> +struct clkgate_seperated {
> +       struct clk_hw   hw;
> +       void __iomem    *enable;        /* enable register */
> +       u8              bit_idx;        /* bits in enable/disable register */
> +       u8              flags;
> +       spinlock_t      *lock;
> +};
> +
> +static int clkgate_seperated_enable(struct clk_hw *hw)
> +{
> +       struct clkgate_seperated *sclk;
> +       unsigned long flags = 0;
> +       u32 reg;
> +
> +       sclk = container_of(hw, struct clkgate_seperated, hw);
> +       if (sclk->lock)
> +               spin_lock_irqsave(sclk->lock, flags);
> +       reg = BIT(sclk->bit_idx);
> +       writel_relaxed(reg, sclk->enable);
> +       readl_relaxed(sclk->enable + CLKGATE_SEPERATED_STATUS);
> +       if (sclk->lock)
> +               spin_unlock_irqrestore(sclk->lock, flags);
> +       return 0;
> +}
> +
> +static void clkgate_seperated_disable(struct clk_hw *hw)
> +{
> +       struct clkgate_seperated *sclk;
> +       unsigned long flags = 0;
> +       u32 reg;
> +
> +       sclk = container_of(hw, struct clkgate_seperated, hw);
> +       if (sclk->lock)
> +               spin_lock_irqsave(sclk->lock, flags);
> +       reg = BIT(sclk->bit_idx);
> +       writel_relaxed(reg, sclk->enable + CLKGATE_SEPERATED_DISABLE);
> +       readl_relaxed(sclk->enable + CLKGATE_SEPERATED_STATUS);
> +       if (sclk->lock)
> +               spin_unlock_irqrestore(sclk->lock, flags);
> +}
> +
> +static int clkgate_seperated_is_enabled(struct clk_hw *hw)
> +{
> +       struct clkgate_seperated *sclk;
> +       u32 reg;
> +
> +       sclk = container_of(hw, struct clkgate_seperated, hw);
> +       reg = readl_relaxed(sclk->enable + CLKGATE_SEPERATED_STATUS);
> +       reg &= BIT(sclk->bit_idx);
> +
> +       return reg ? 1 : 0;
> +}
> +
> +static struct clk_ops clkgate_seperated_ops = {
> +       .enable         = clkgate_seperated_enable,
> +       .disable        = clkgate_seperated_disable,
> +       .is_enabled     = clkgate_seperated_is_enabled,
> +};
> +
> +struct clk *hisi_register_clkgate_sep(struct device *dev, const char *name,
> +                                     const char *parent_name,
> +                                     unsigned long flags,
> +                                     void __iomem *reg, u8 bit_idx,
> +                                     u8 clk_gate_flags, spinlock_t *lock)
> +{
> +       struct clkgate_seperated *sclk;
> +       struct clk *clk;
> +       struct clk_init_data init;
> +
> +       sclk = kzalloc(sizeof(struct clkgate_seperated), GFP_KERNEL);
> +       if (!sclk) {
> +               pr_err("%s: fail to allocate seperated gated clk\n", __func__);
> +               return ERR_PTR(-ENOMEM);
> +       }
> +
> +       init.name = name;
> +       init.ops = &clkgate_seperated_ops;
> +       init.flags = flags | CLK_IS_BASIC;
> +       init.parent_names = (parent_name ? &parent_name : NULL);
> +       init.num_parents = (parent_name ? 1 : 0);
> +
> +       sclk->enable = reg + CLKGATE_SEPERATED_ENABLE;
> +       sclk->bit_idx = bit_idx;
> +       sclk->flags = clk_gate_flags;
> +       sclk->hw.init = &init;
> +
> +       clk = clk_register(dev, &sclk->hw);
> +       if (IS_ERR(clk))
> +               kfree(sclk);
> +       return clk;
> +}
> diff --git a/include/dt-bindings/clock/hi3620-clock.h b/include/dt-bindings/clock/hi3620-clock.h
> new file mode 100644
> index 0000000..6eaa6a4
> --- /dev/null
> +++ b/include/dt-bindings/clock/hi3620-clock.h
> @@ -0,0 +1,152 @@
> +/*
> + * Copyright (c) 2012-2013 Hisilicon Limited.
> + * Copyright (c) 2012-2013 Linaro Limited.
> + *
> + * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
> + *        Xin Li <li.xin@linaro.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + */
> +
> +#ifndef __DTS_HI3620_CLOCK_H
> +#define __DTS_HI3620_CLOCK_H
> +
> +#define HI3620_NONE_CLOCK      0
> +
> +/* fixed rate & fixed factor clocks */
> +#define HI3620_OSC32K          1
> +#define HI3620_OSC26M          2
> +#define HI3620_PCLK            3
> +#define HI3620_PLL_ARM0                4
> +#define HI3620_PLL_ARM1                5
> +#define HI3620_PLL_PERI                6
> +#define HI3620_PLL_USB         7
> +#define HI3620_PLL_HDMI                8
> +#define HI3620_PLL_GPU         9
> +#define HI3620_RCLK_TCXO       10
> +#define HI3620_RCLK_CFGAXI     11
> +#define HI3620_RCLK_PICO       12
> +
> +/* mux clocks */
> +#define HI3620_TIMER0_MUX      32
> +#define HI3620_TIMER1_MUX      33
> +#define HI3620_TIMER2_MUX      34
> +#define HI3620_TIMER3_MUX      35
> +#define HI3620_TIMER4_MUX      36
> +#define HI3620_TIMER5_MUX      37
> +#define HI3620_TIMER6_MUX      38
> +#define HI3620_TIMER7_MUX      39
> +#define HI3620_TIMER8_MUX      40
> +#define HI3620_TIMER9_MUX      41
> +#define HI3620_UART0_MUX       42
> +#define HI3620_UART1_MUX       43
> +#define HI3620_UART2_MUX       44
> +#define HI3620_UART3_MUX       45
> +#define HI3620_UART4_MUX       46
> +#define HI3620_SPI0_MUX                47
> +#define HI3620_SPI1_MUX                48
> +#define HI3620_SPI2_MUX                49
> +#define HI3620_SAXI_MUX                50
> +#define HI3620_PWM0_MUX                51
> +#define HI3620_PWM1_MUX                52
> +#define HI3620_SD_MUX          53
> +#define HI3620_MMC1_MUX                54
> +#define HI3620_MMC1_MUX2       55
> +#define HI3620_G2D_MUX         56
> +#define HI3620_VENC_MUX                57
> +#define HI3620_VDEC_MUX                58
> +#define HI3620_VPP_MUX         59
> +#define HI3620_EDC0_MUX                60
> +#define HI3620_LDI0_MUX                61
> +#define HI3620_EDC1_MUX                62
> +#define HI3620_LDI1_MUX                63
> +#define HI3620_RCLK_HSIC       64
> +#define HI3620_MMC2_MUX                65
> +#define HI3620_MMC3_MUX                66
> +
> +/* divider clocks */
> +#define HI3620_SHAREAXI_DIV    128
> +#define HI3620_CFGAXI_DIV      129
> +#define HI3620_SD_DIV          130
> +#define HI3620_MMC1_DIV                131
> +#define HI3620_HSIC_DIV                132
> +#define HI3620_MMC2_DIV                133
> +#define HI3620_MMC3_DIV                134
> +
> +/* gate clocks */
> +#define HI3620_TIMERCLK01      160
> +#define HI3620_TIMER_RCLK01    161
> +#define HI3620_TIMERCLK23      162
> +#define HI3620_TIMER_RCLK23    163
> +#define HI3620_TIMERCLK45      164
> +#define HI3620_TIMERCLK67      165
> +#define HI3620_TIMERCLK89      166
> +#define HI3620_RTCCLK          167
> +#define HI3620_KPC_CLK         168
> +#define HI3620_GPIOCLK0                169
> +#define HI3620_GPIOCLK1                170
> +#define HI3620_GPIOCLK2                171
> +#define HI3620_GPIOCLK3                172
> +#define HI3620_GPIOCLK4                173
> +#define HI3620_GPIOCLK5                174
> +#define HI3620_GPIOCLK6                175
> +#define HI3620_GPIOCLK7                176
> +#define HI3620_GPIOCLK8                177
> +#define HI3620_GPIOCLK9                178
> +#define HI3620_GPIOCLK10       179
> +#define HI3620_GPIOCLK11       180
> +#define HI3620_GPIOCLK12       181
> +#define HI3620_GPIOCLK13       182
> +#define HI3620_GPIOCLK14       183
> +#define HI3620_GPIOCLK15       184
> +#define HI3620_GPIOCLK16       185
> +#define HI3620_GPIOCLK17       186
> +#define HI3620_GPIOCLK18       187
> +#define HI3620_GPIOCLK19       188
> +#define HI3620_GPIOCLK20       189
> +#define HI3620_GPIOCLK21       190
> +#define HI3620_DPHY0_CLK       191
> +#define HI3620_DPHY1_CLK       192
> +#define HI3620_DPHY2_CLK       193
> +#define HI3620_USBPHY_CLK      194
> +#define HI3620_ACP_CLK         195
> +#define HI3620_PWMCLK0         196
> +#define HI3620_PWMCLK1         197
> +#define HI3620_UARTCLK0                198
> +#define HI3620_UARTCLK1                199
> +#define HI3620_UARTCLK2                200
> +#define HI3620_UARTCLK3                201
> +#define HI3620_UARTCLK4                202
> +#define HI3620_SPICLK0         203
> +#define HI3620_SPICLK1         204
> +#define HI3620_SPICLK2         205
> +#define HI3620_I2CCLK0         206
> +#define HI3620_I2CCLK1         207
> +#define HI3620_I2CCLK2         208
> +#define HI3620_I2CCLK3         209
> +#define HI3620_SCI_CLK         210
> +#define HI3620_DDRC_PER_CLK    211
> +#define HI3620_DMAC_CLK                212
> +#define HI3620_USB2DVC_CLK     213
> +#define HI3620_SD_CLK          214
> +#define HI3620_MMC_CLK1                215
> +#define HI3620_MMC_CLK2                216
> +#define HI3620_MMC_CLK3                217
> +#define HI3620_MCU_CLK         218
> +
> +#define HI3620_NR_CLKS         219
> +
> +#endif /* __DTS_HI3620_CLOCK_H */
> -- 
> 1.8.3.2
Mike Turquette Nov. 27, 2013, 7:46 p.m. UTC | #4
Quoting Mike Turquette (2013-11-17 21:24:30)
> Quoting Haojian Zhuang (2013-11-12 17:31:13)
> > Enable common clock driver of Hi3620 SoC. clkgate-seperated driver is
> > used to support the clock gate that enable/disable/status registers
> > are seperated.
> 
> I've taken this patch in for testing after fixing the spelling of
> 'seperated'. It looks good to me. Per the discussion at the ARM Summit,
> I'll take the clock patch through my tree and the dts patch goes through
> the arm-soc tree.

Can you fix the spelling issues pointed out by Mark and myself, as well
as the kzalloc issue? After that I'll take in patch #1.

Patch #2 doesn't apply for me without first applying your hisilicon-init
tag first, and it should go through the arm-soc tree first.

Regards,
Mike

> 
> Olof, Arnd Kevin & Grant: are we being strict and splitting the DT
> binding description out into a third patch which goes through the DT
> maintainers? If so that aspect needs to be culled from this patch,
> though I'm happy to take this as-as.
> 
> Besides that this patch looks good to me. Thanks Haojian for reworking
> it to fit the clock-controller model the discussions at the ARM Summit
> and Linaro Connect.
> 
> Regards,
> Mike
> 
> > 
> > Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
> > ---
> >  .../devicetree/bindings/clock/hi3620-clock.txt     |  19 ++
> >  drivers/clk/Makefile                               |   1 +
> >  drivers/clk/hisilicon/Makefile                     |   5 +
> >  drivers/clk/hisilicon/clk-hi3620.c                 | 242 +++++++++++++++++++++
> >  drivers/clk/hisilicon/clk.c                        | 171 +++++++++++++++
> >  drivers/clk/hisilicon/clk.h                        | 103 +++++++++
> >  drivers/clk/hisilicon/clkgate-seperated.c          | 130 +++++++++++
> >  include/dt-bindings/clock/hi3620-clock.h           | 152 +++++++++++++
> >  8 files changed, 823 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/clock/hi3620-clock.txt
> >  create mode 100644 drivers/clk/hisilicon/Makefile
> >  create mode 100644 drivers/clk/hisilicon/clk-hi3620.c
> >  create mode 100644 drivers/clk/hisilicon/clk.c
> >  create mode 100644 drivers/clk/hisilicon/clk.h
> >  create mode 100644 drivers/clk/hisilicon/clkgate-seperated.c
> >  create mode 100644 include/dt-bindings/clock/hi3620-clock.h
> > 
> > diff --git a/Documentation/devicetree/bindings/clock/hi3620-clock.txt b/Documentation/devicetree/bindings/clock/hi3620-clock.txt
> > new file mode 100644
> > index 0000000..80e134d
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/clock/hi3620-clock.txt
> > @@ -0,0 +1,19 @@
> > +* Hisilicon Hi3620 Clock Controller
> > +
> > +The Hi3620 clock controller generates and supplies clock to various
> > +controllers within the Hi3620 SoC.
> > +
> > +Required Properties:
> > +
> > +- comptible: should be one of the following.
> > +  - "hisilicon,hi3620-clock" - controller compatible with Hi3620 SoC.
> > +
> > +- reg: physical base address of the controller and length of memory mapped
> > +  region.
> > +
> > +- #clock-cells: should be 1.
> > +
> > +Each clock is assigned an identifier and client nodes use this identifier
> > +to specify the clock which they consume.
> > +
> > +All these identifier could be found in <dt-bindings/clock/hi3620-clock.h>.
> > diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> > index 7b11106..e156b53 100644
> > --- a/drivers/clk/Makefile
> > +++ b/drivers/clk/Makefile
> > @@ -13,6 +13,7 @@ obj-$(CONFIG_COMMON_CLK)      += clk-composite.o
> >  obj-$(CONFIG_ARCH_BCM2835)     += clk-bcm2835.o
> >  obj-$(CONFIG_ARCH_NOMADIK)     += clk-nomadik.o
> >  obj-$(CONFIG_ARCH_HIGHBANK)    += clk-highbank.o
> > +obj-$(CONFIG_ARCH_HI3xxx)      += hisilicon/
> >  obj-$(CONFIG_ARCH_NSPIRE)      += clk-nspire.o
> >  obj-$(CONFIG_ARCH_MXS)         += mxs/
> >  obj-$(CONFIG_ARCH_SOCFPGA)     += socfpga/
> > diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile
> > new file mode 100644
> > index 0000000..fad958b
> > --- /dev/null
> > +++ b/drivers/clk/hisilicon/Makefile
> > @@ -0,0 +1,5 @@
> > +#
> > +# Hisilicon Clock specific Makefile
> > +#
> > +
> > +obj-y  += clk.o clkgate-seperated.o clk-hi3620.o
> > diff --git a/drivers/clk/hisilicon/clk-hi3620.c b/drivers/clk/hisilicon/clk-hi3620.c
> > new file mode 100644
> > index 0000000..b66b074
> > --- /dev/null
> > +++ b/drivers/clk/hisilicon/clk-hi3620.c
> > @@ -0,0 +1,242 @@
> > +/*
> > + * Hisilicon Hi3620 clock driver
> > + *
> > + * Copyright (c) 2012-2013 Hisilicon Limited.
> > + * Copyright (c) 2012-2013 Linaro Limited.
> > + *
> > + * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
> > + *        Xin Li <li.xin@linaro.org>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License along
> > + * with this program; if not, write to the Free Software Foundation, Inc.,
> > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> > + *
> > + */
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/clk-provider.h>
> > +#include <linux/clkdev.h>
> > +#include <linux/io.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +#include <linux/of_device.h>
> > +#include <linux/slab.h>
> > +#include <linux/clk.h>
> > +
> > +#include <dt-bindings/clock/hi3620-clock.h>
> > +
> > +#include "clk.h"
> > +
> > +/* clock parent list */
> > +static const char *timer0_mux_p[] __initdata = { "osc32k", "timerclk01", };
> > +static const char *timer1_mux_p[] __initdata = { "osc32k", "timerclk01", };
> > +static const char *timer2_mux_p[] __initdata = { "osc32k", "timerclk23", };
> > +static const char *timer3_mux_p[] __initdata = { "osc32k", "timerclk23", };
> > +static const char *timer4_mux_p[] __initdata = { "osc32k", "timerclk45", };
> > +static const char *timer5_mux_p[] __initdata = { "osc32k", "timerclk45", };
> > +static const char *timer6_mux_p[] __initdata = { "osc32k", "timerclk67", };
> > +static const char *timer7_mux_p[] __initdata = { "osc32k", "timerclk67", };
> > +static const char *timer8_mux_p[] __initdata = { "osc32k", "timerclk89", };
> > +static const char *timer9_mux_p[] __initdata = { "osc32k", "timerclk89", };
> > +static const char *uart0_mux_p[] __initdata = { "osc26m", "pclk", };
> > +static const char *uart1_mux_p[] __initdata = { "osc26m", "pclk", };
> > +static const char *uart2_mux_p[] __initdata = { "osc26m", "pclk", };
> > +static const char *uart3_mux_p[] __initdata = { "osc26m", "pclk", };
> > +static const char *uart4_mux_p[] __initdata = { "osc26m", "pclk", };
> > +static const char *spi0_mux_p[] __initdata = { "osc26m", "rclk_cfgaxi", };
> > +static const char *spi1_mux_p[] __initdata = { "osc26m", "rclk_cfgaxi", };
> > +static const char *spi2_mux_p[] __initdata = { "osc26m", "rclk_cfgaxi", };
> > +/* share axi parent */
> > +static const char *saxi_mux_p[] __initdata = { "armpll3", "armpll2", };
> > +static const char *pwm0_mux_p[] __initdata = { "osc32k", "osc26m", };
> > +static const char *pwm1_mux_p[] __initdata = { "osc32k", "osc26m", };
> > +static const char *sd_mux_p[] __initdata = { "armpll3", "armpll2", };
> > +static const char *mmc1_mux_p[] __initdata = { "armpll3", "armpll2", };
> > +static const char *mmc1_mux2_p[] __initdata = { "osc26m", "mmc1_div", };
> > +static const char *g2d_mux_p[] __initdata = { "armpll2", "armpll3", };
> > +static const char *venc_mux_p[] __initdata = { "armpll2", "armpll3", };
> > +static const char *vdec_mux_p[] __initdata = { "armpll2", "armpll3", };
> > +static const char *vpp_mux_p[] __initdata = { "armpll2", "armpll3", };
> > +static const char *edc0_mux_p[] __initdata = { "armpll2", "armpll3", };
> > +static const char *ldi0_mux_p[] __initdata = { "armpll2", "armpll4",
> > +                                            "armpll3", "armpll5", };
> > +static const char *edc1_mux_p[] __initdata = { "armpll2", "armpll3", };
> > +static const char *ldi1_mux_p[] __initdata = { "armpll2", "armpll4",
> > +                                            "armpll3", "armpll5", };
> > +static const char *rclk_hsic_p[] __initdata = { "armpll3", "armpll2", };
> > +static const char *mmc2_mux_p[] __initdata = { "armpll3", "armpll2", };
> > +static const char *mmc3_mux_p[] __initdata = { "armpll3", "armpll2", };
> > +
> > +
> > +/* fixed rate clocks */
> > +static struct hisi_fixed_rate_clock hi3620_fixed_rate_clks[] __initdata = {
> > +       { HI3620_OSC32K,   "osc32k",   NULL, CLK_IS_ROOT, 32768, },
> > +       { HI3620_OSC26M,   "osc26m",   NULL, CLK_IS_ROOT, 26000000, },
> > +       { HI3620_PCLK,     "pclk",     NULL, CLK_IS_ROOT, 26000000, },
> > +       { HI3620_PLL_ARM0, "armpll0",  NULL, CLK_IS_ROOT, 1600000000, },
> > +       { HI3620_PLL_ARM1, "armpll1",  NULL, CLK_IS_ROOT, 1600000000, },
> > +       { HI3620_PLL_PERI, "armpll2",  NULL, CLK_IS_ROOT, 1440000000, },
> > +       { HI3620_PLL_USB,  "armpll3",  NULL, CLK_IS_ROOT, 1440000000, },
> > +       { HI3620_PLL_HDMI, "armpll4",  NULL, CLK_IS_ROOT, 1188000000, },
> > +       { HI3620_PLL_GPU,  "armpll5",  NULL, CLK_IS_ROOT, 1300000000, },
> > +};
> > +
> > +/* fixed factor clocks */
> > +static struct hisi_fixed_factor_clock hi3620_fixed_factor_clks[] __initdata = {
> > +       { HI3620_RCLK_TCXO,   "rclk_tcxo",   "osc26m",   1, 4,  0, },
> > +       { HI3620_RCLK_CFGAXI, "rclk_cfgaxi", "armpll2",  1, 30, 0, },
> > +       { HI3620_RCLK_PICO,   "rclk_pico",   "hsic_div", 1, 40, 0, },
> > +};
> > +
> > +static struct hisi_mux_clock hi3620_mux_clks[] __initdata = {
> > +       { HI3620_TIMER0_MUX, "timer0_mux", timer0_mux_p, ARRAY_SIZE(timer0_mux_p), CLK_SET_RATE_PARENT, 0,     15, 2, 0,                   },
> > +       { HI3620_TIMER1_MUX, "timer1_mux", timer1_mux_p, ARRAY_SIZE(timer1_mux_p), CLK_SET_RATE_PARENT, 0,     17, 2, 0,                   },
> > +       { HI3620_TIMER2_MUX, "timer2_mux", timer2_mux_p, ARRAY_SIZE(timer2_mux_p), CLK_SET_RATE_PARENT, 0,     19, 2, 0,                   },
> > +       { HI3620_TIMER3_MUX, "timer3_mux", timer3_mux_p, ARRAY_SIZE(timer3_mux_p), CLK_SET_RATE_PARENT, 0,     21, 2, 0,                   },
> > +       { HI3620_TIMER4_MUX, "timer4_mux", timer4_mux_p, ARRAY_SIZE(timer4_mux_p), CLK_SET_RATE_PARENT, 0x18,  0,  2, 0,                   },
> > +       { HI3620_TIMER5_MUX, "timer5_mux", timer5_mux_p, ARRAY_SIZE(timer5_mux_p), CLK_SET_RATE_PARENT, 0x18,  2,  2, 0,                   },
> > +       { HI3620_TIMER6_MUX, "timer6_mux", timer6_mux_p, ARRAY_SIZE(timer6_mux_p), CLK_SET_RATE_PARENT, 0x18,  4,  2, 0,                   },
> > +       { HI3620_TIMER7_MUX, "timer7_mux", timer7_mux_p, ARRAY_SIZE(timer7_mux_p), CLK_SET_RATE_PARENT, 0x18,  6,  2, 0,                   },
> > +       { HI3620_TIMER8_MUX, "timer8_mux", timer8_mux_p, ARRAY_SIZE(timer8_mux_p), CLK_SET_RATE_PARENT, 0x18,  8,  2, 0,                   },
> > +       { HI3620_TIMER9_MUX, "timer9_mux", timer9_mux_p, ARRAY_SIZE(timer9_mux_p), CLK_SET_RATE_PARENT, 0x18,  10, 2, 0,                   },
> > +       { HI3620_UART0_MUX,  "uart0_mux",  uart0_mux_p,  ARRAY_SIZE(uart0_mux_p),  CLK_SET_RATE_PARENT, 0x100, 7,  1, CLK_MUX_HIWORD_MASK, },
> > +       { HI3620_UART1_MUX,  "uart1_mux",  uart1_mux_p,  ARRAY_SIZE(uart1_mux_p),  CLK_SET_RATE_PARENT, 0x100, 8,  1, CLK_MUX_HIWORD_MASK, },
> > +       { HI3620_UART2_MUX,  "uart2_mux",  uart2_mux_p,  ARRAY_SIZE(uart2_mux_p),  CLK_SET_RATE_PARENT, 0x100, 9,  1, CLK_MUX_HIWORD_MASK, },
> > +       { HI3620_UART3_MUX,  "uart3_mux",  uart3_mux_p,  ARRAY_SIZE(uart3_mux_p),  CLK_SET_RATE_PARENT, 0x100, 10, 1, CLK_MUX_HIWORD_MASK, },
> > +       { HI3620_UART4_MUX,  "uart4_mux",  uart4_mux_p,  ARRAY_SIZE(uart4_mux_p),  CLK_SET_RATE_PARENT, 0x100, 11, 1, CLK_MUX_HIWORD_MASK, },
> > +       { HI3620_SPI0_MUX,   "spi0_mux",   spi0_mux_p,   ARRAY_SIZE(spi0_mux_p),   CLK_SET_RATE_PARENT, 0x100, 12, 1, CLK_MUX_HIWORD_MASK, },
> > +       { HI3620_SPI1_MUX,   "spi1_mux",   spi1_mux_p,   ARRAY_SIZE(spi1_mux_p),   CLK_SET_RATE_PARENT, 0x100, 13, 1, CLK_MUX_HIWORD_MASK, },
> > +       { HI3620_SPI2_MUX,   "spi2_mux",   spi2_mux_p,   ARRAY_SIZE(spi2_mux_p),   CLK_SET_RATE_PARENT, 0x100, 14, 1, CLK_MUX_HIWORD_MASK, },
> > +       { HI3620_SAXI_MUX,   "saxi_mux",   saxi_mux_p,   ARRAY_SIZE(saxi_mux_p),   CLK_SET_RATE_PARENT, 0x100, 15, 1, CLK_MUX_HIWORD_MASK, },
> > +       { HI3620_PWM0_MUX,   "pwm0_mux",   pwm0_mux_p,   ARRAY_SIZE(pwm0_mux_p),   CLK_SET_RATE_PARENT, 0x104, 10, 1, CLK_MUX_HIWORD_MASK, },
> > +       { HI3620_PWM1_MUX,   "pwm1_mux",   pwm1_mux_p,   ARRAY_SIZE(pwm1_mux_p),   CLK_SET_RATE_PARENT, 0x104, 11, 1, CLK_MUX_HIWORD_MASK, },
> > +       { HI3620_SD_MUX,     "sd_mux",     sd_mux_p,     ARRAY_SIZE(sd_mux_p),     CLK_SET_RATE_PARENT, 0x108, 4,  1, CLK_MUX_HIWORD_MASK, },
> > +       { HI3620_MMC1_MUX,   "mmc1_mux",   mmc1_mux_p,   ARRAY_SIZE(mmc1_mux_p),   CLK_SET_RATE_PARENT, 0x108, 9,  1, CLK_MUX_HIWORD_MASK, },
> > +       { HI3620_MMC1_MUX2,  "mmc1_mux2",  mmc1_mux2_p,  ARRAY_SIZE(mmc1_mux2_p),  CLK_SET_RATE_PARENT, 0x108, 10, 1, CLK_MUX_HIWORD_MASK, },
> > +       { HI3620_G2D_MUX,    "g2d_mux",    g2d_mux_p,    ARRAY_SIZE(g2d_mux_p),    CLK_SET_RATE_PARENT, 0x10c, 5,  1, CLK_MUX_HIWORD_MASK, },
> > +       { HI3620_VENC_MUX,   "venc_mux",   venc_mux_p,   ARRAY_SIZE(venc_mux_p),   CLK_SET_RATE_PARENT, 0x10c, 11, 1, CLK_MUX_HIWORD_MASK, },
> > +       { HI3620_VDEC_MUX,   "vdec_mux",   vdec_mux_p,   ARRAY_SIZE(vdec_mux_p),   CLK_SET_RATE_PARENT, 0x110, 5,  1, CLK_MUX_HIWORD_MASK, },
> > +       { HI3620_VPP_MUX,    "vpp_mux",    vpp_mux_p,    ARRAY_SIZE(vpp_mux_p),    CLK_SET_RATE_PARENT, 0x110, 11, 1, CLK_MUX_HIWORD_MASK, },
> > +       { HI3620_EDC0_MUX,   "edc0_mux",   edc0_mux_p,   ARRAY_SIZE(edc0_mux_p),   CLK_SET_RATE_PARENT, 0x114, 6,  1, CLK_MUX_HIWORD_MASK, },
> > +       { HI3620_LDI0_MUX,   "ldi0_mux",   ldi0_mux_p,   ARRAY_SIZE(ldi0_mux_p),   CLK_SET_RATE_PARENT, 0x114, 13, 2, CLK_MUX_HIWORD_MASK, },
> > +       { HI3620_EDC1_MUX,   "edc1_mux",   edc1_mux_p,   ARRAY_SIZE(edc1_mux_p),   CLK_SET_RATE_PARENT, 0x118, 6,  1, CLK_MUX_HIWORD_MASK, },
> > +       { HI3620_LDI1_MUX,   "ldi1_mux",   ldi1_mux_p,   ARRAY_SIZE(ldi1_mux_p),   CLK_SET_RATE_PARENT, 0x118, 14, 2, CLK_MUX_HIWORD_MASK, },
> > +       { HI3620_RCLK_HSIC,  "rclk_hsic",  rclk_hsic_p,  ARRAY_SIZE(rclk_hsic_p),  CLK_SET_RATE_PARENT, 0x130, 2,  1, CLK_MUX_HIWORD_MASK, },
> > +       { HI3620_MMC2_MUX,   "mmc2_mux",   mmc2_mux_p,   ARRAY_SIZE(mmc2_mux_p),   CLK_SET_RATE_PARENT, 0x140, 4,  1, CLK_MUX_HIWORD_MASK, },
> > +       { HI3620_MMC3_MUX,   "mmc3_mux",   mmc3_mux_p,   ARRAY_SIZE(mmc3_mux_p),   CLK_SET_RATE_PARENT, 0x140, 9,  1, CLK_MUX_HIWORD_MASK, },
> > +};
> > +
> > +static struct hisi_divider_clock hi3620_div_clks[] __initdata = {
> > +       { HI3620_SHAREAXI_DIV, "saxi_div",   "saxi_mux",  0, 0x100, 0, 5, CLK_MUX_HIWORD_MASK, NULL, },
> > +       { HI3620_CFGAXI_DIV,   "cfgaxi_div", "saxi_div",  0, 0x100, 5, 2, CLK_MUX_HIWORD_MASK, NULL, },
> > +       { HI3620_SD_DIV,       "sd_div",     "sd_mux",    0, 0x108, 0, 4, CLK_MUX_HIWORD_MASK, NULL, },
> > +       { HI3620_MMC1_DIV,     "mmc1_div",   "mmc1_mux",  0, 0x108, 5, 4, CLK_MUX_HIWORD_MASK, NULL, },
> > +       { HI3620_HSIC_DIV,     "hsic_div",   "rclk_hsic", 0, 0x130, 0, 2, CLK_MUX_HIWORD_MASK, NULL, },
> > +       { HI3620_MMC2_DIV,     "mmc2_div",   "mmc2_mux",  0, 0x140, 0, 4, CLK_MUX_HIWORD_MASK, NULL, },
> > +       { HI3620_MMC3_DIV,     "mmc3_div",   "mmc3_mux",  0, 0x140, 5, 4, CLK_MUX_HIWORD_MASK, NULL, },
> > +};
> > +
> > +static struct hisi_gate_clock hi3620_seperated_gate_clks[] __initdata = {
> > +       { HI3620_TIMERCLK01,   "timerclk01",   "timer_rclk01", 0, 0x20, 0, 0, },
> > +       { HI3620_TIMER_RCLK01, "timer_rclk01", "rclk_tcxo",    0, 0x20, 1, 0, },
> > +       { HI3620_TIMERCLK23,   "timerclk23",   "timer_rclk23", 0, 0x20, 2, 0, },
> > +       { HI3620_TIMER_RCLK23, "timer_rclk23", "rclk_tcxo",    0, 0x20, 3, 0, },
> > +       { HI3620_RTCCLK,       "rtcclk",       "pclk",         0, 0x20, 5, 0, },
> > +       { HI3620_KPC_CLK,      "kpc_clk",      "pclk",         0, 0x20, 6, 0, },
> > +       { HI3620_GPIOCLK0,     "gpioclk0",     "pclk",         0, 0x20, 8, 0, },
> > +       { HI3620_GPIOCLK1,     "gpioclk1",     "pclk",         0, 0x20, 9, 0, },
> > +       { HI3620_GPIOCLK2,     "gpioclk2",     "pclk",         0, 0x20, 10, 0, },
> > +       { HI3620_GPIOCLK3,     "gpioclk3",     "pclk",         0, 0x20, 11, 0, },
> > +       { HI3620_GPIOCLK4,     "gpioclk4",     "pclk",         0, 0x20, 12, 0, },
> > +       { HI3620_GPIOCLK5,     "gpioclk5",     "pclk",         0, 0x20, 13, 0, },
> > +       { HI3620_GPIOCLK6,     "gpioclk6",     "pclk",         0, 0x20, 14, 0, },
> > +       { HI3620_GPIOCLK7,     "gpioclk7",     "pclk",         0, 0x20, 15, 0, },
> > +       { HI3620_GPIOCLK8,     "gpioclk8",     "pclk",         0, 0x20, 16, 0, },
> > +       { HI3620_GPIOCLK9,     "gpioclk9",     "pclk",         0, 0x20, 17, 0, },
> > +       { HI3620_GPIOCLK10,    "gpioclk10",    "pclk",         0, 0x20, 18, 0, },
> > +       { HI3620_GPIOCLK11,    "gpioclk11",    "pclk",         0, 0x20, 19, 0, },
> > +       { HI3620_GPIOCLK12,    "gpioclk12",    "pclk",         0, 0x20, 20, 0, },
> > +       { HI3620_GPIOCLK13,    "gpioclk13",    "pclk",         0, 0x20, 21, 0, },
> > +       { HI3620_GPIOCLK14,    "gpioclk14",    "pclk",         0, 0x20, 22, 0, },
> > +       { HI3620_GPIOCLK15,    "gpioclk15",    "pclk",         0, 0x20, 23, 0, },
> > +       { HI3620_GPIOCLK16,    "gpioclk16",    "pclk",         0, 0x20, 24, 0, },
> > +       { HI3620_GPIOCLK17,    "gpioclk17",    "pclk",         0, 0x20, 25, 0, },
> > +       { HI3620_GPIOCLK18,    "gpioclk18",    "pclk",         0, 0x20, 26, 0, },
> > +       { HI3620_GPIOCLK19,    "gpioclk19",    "pclk",         0, 0x20, 27, 0, },
> > +       { HI3620_GPIOCLK20,    "gpioclk20",    "pclk",         0, 0x20, 28, 0, },
> > +       { HI3620_GPIOCLK21,    "gpioclk21",    "pclk",         0, 0x20, 29, 0, },
> > +       { HI3620_DPHY0_CLK,    "dphy0_clk",    "osc26m",       0, 0x30, 15, 0, },
> > +       { HI3620_DPHY1_CLK,    "dphy1_clk",    "osc26m",       0, 0x30, 16, 0, },
> > +       { HI3620_DPHY2_CLK,    "dphy2_clk",    "osc26m",       0, 0x30, 17, 0, },
> > +       { HI3620_USBPHY_CLK,   "usbphy_clk",   "rclk_pico",    0, 0x30, 24, 0, },
> > +       { HI3620_ACP_CLK,      "acp_clk",      "rclk_cfgaxi",  0, 0x30, 28, 0, },
> > +       { HI3620_TIMERCLK45,   "timerclk45",   "rclk_tcxo",    0, 0x40, 3, 0, },
> > +       { HI3620_TIMERCLK67,   "timerclk67",   "rclk_tcxo",    0, 0x40, 4, 0, },
> > +       { HI3620_TIMERCLK89,   "timerclk89",   "rclk_tcxo",    0, 0x40, 5, 0, },
> > +       { HI3620_PWMCLK0,      "pwmclk0",      "pwm0_mux",     0, 0x40, 7, 0, },
> > +       { HI3620_PWMCLK1,      "pwmclk1",      "pwm1_mux",     0, 0x40, 8, 0, },
> > +       { HI3620_UARTCLK0,     "uartclk0",     "uart0_mux",    0, 0x40, 16, 0, },
> > +       { HI3620_UARTCLK1,     "uartclk1",     "uart1_mux",    0, 0x40, 17, 0, },
> > +       { HI3620_UARTCLK2,     "uartclk2",     "uart2_mux",    0, 0x40, 18, 0, },
> > +       { HI3620_UARTCLK3,     "uartclk3",     "uart3_mux",    0, 0x40, 19, 0, },
> > +       { HI3620_UARTCLK4,     "uartclk4",     "uart4_mux",    0, 0x40, 20, 0, },
> > +       { HI3620_SPICLK0,      "spiclk0",      "spi0_mux",     0, 0x40, 21, 0, },
> > +       { HI3620_SPICLK1,      "spiclk1",      "spi1_mux",     0, 0x40, 22, 0, },
> > +       { HI3620_SPICLK2,      "spiclk2",      "spi2_mux",     0, 0x40, 23, 0, },
> > +       { HI3620_I2CCLK0,      "i2cclk0",      "pclk",         0, 0x40, 24, 0, },
> > +       { HI3620_I2CCLK1,      "i2cclk1",      "pclk",         0, 0x40, 25, 0, },
> > +       { HI3620_SCI_CLK,      "sci_clk",      "osc26m",       0, 0x40, 26, 0, },
> > +       { HI3620_I2CCLK2,      "i2cclk2",      "pclk",         0, 0x40, 28, 0, },
> > +       { HI3620_I2CCLK3,      "i2cclk3",      "pclk",         0, 0x40, 29, 0, },
> > +       { HI3620_DDRC_PER_CLK, "ddrc_per_clk", "rclk_cfgaxi",  0, 0x50, 9, 0, },
> > +       { HI3620_DMAC_CLK,     "dmac_clk",     "rclk_cfgaxi",  0, 0x50, 10, 0, },
> > +       { HI3620_USB2DVC_CLK,  "usb2dvc_clk",  "rclk_cfgaxi",  0, 0x50, 17, 0, },
> > +       { HI3620_SD_CLK,       "sd_clk",       "sd_div",       0, 0x50, 20, 0, },
> > +       { HI3620_MMC_CLK1,     "mmc_clk1",     "mmc1_mux2",    0, 0x50, 21, 0, },
> > +       { HI3620_MMC_CLK2,     "mmc_clk2",     "mmc2_div",     0, 0x50, 22, 0, },
> > +       { HI3620_MMC_CLK3,     "mmc_clk3",     "mmc3_div",     0, 0x50, 23, 0, },
> > +       { HI3620_MCU_CLK,      "mcu_clk",      "acp_clk",      0, 0x50, 24, 0, },
> > +};
> > +
> > +static void __init hi3620_clk_init(struct device_node *np)
> > +{
> > +       void __iomem *base;
> > +
> > +       if (np) {
> > +               base = of_iomap(np, 0);
> > +               if (!base) {
> > +                       pr_err("failed to map Hi3620 clock registers\n");
> > +                       return;
> > +               }
> > +       } else {
> > +               pr_err("failed to find Hi3620 clock node in DTS\n");
> > +               return;
> > +       }
> > +
> > +       hisi_clk_init(np, HI3620_NR_CLKS);
> > +
> > +       hisi_clk_register_fixed_rate(hi3620_fixed_rate_clks,
> > +                                    ARRAY_SIZE(hi3620_fixed_rate_clks),
> > +                                    base);
> > +       hisi_clk_register_fixed_factor(hi3620_fixed_factor_clks,
> > +                                      ARRAY_SIZE(hi3620_fixed_factor_clks),
> > +                                      base);
> > +       hisi_clk_register_mux(hi3620_mux_clks, ARRAY_SIZE(hi3620_mux_clks),
> > +                             base);
> > +       hisi_clk_register_divider(hi3620_div_clks, ARRAY_SIZE(hi3620_div_clks),
> > +                                 base);
> > +       hisi_clk_register_gate_sep(hi3620_seperated_gate_clks,
> > +                                  ARRAY_SIZE(hi3620_seperated_gate_clks),
> > +                                  base);
> > +}
> > +CLK_OF_DECLARE(hi3620_clk, "hisilicon,hi3620-clock", hi3620_clk_init);
> > diff --git a/drivers/clk/hisilicon/clk.c b/drivers/clk/hisilicon/clk.c
> > new file mode 100644
> > index 0000000..a3a7152
> > --- /dev/null
> > +++ b/drivers/clk/hisilicon/clk.c
> > @@ -0,0 +1,171 @@
> > +/*
> > + * Hisilicon clock driver
> > + *
> > + * Copyright (c) 2012-2013 Hisilicon Limited.
> > + * Copyright (c) 2012-2013 Linaro Limited.
> > + *
> > + * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
> > + *        Xin Li <li.xin@linaro.org>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License along
> > + * with this program; if not, write to the Free Software Foundation, Inc.,
> > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> > + *
> > + */
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/clk-provider.h>
> > +#include <linux/clkdev.h>
> > +#include <linux/delay.h>
> > +#include <linux/io.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +#include <linux/of_device.h>
> > +#include <linux/slab.h>
> > +#include <linux/clk.h>
> > +
> > +#include "clk.h"
> > +
> > +static DEFINE_SPINLOCK(hisi_clk_lock);
> > +static struct clk **clk_table;
> > +static struct clk_onecell_data clk_data;
> > +
> > +void __init hisi_clk_init(struct device_node *np, int nr_clks)
> > +{
> > +       clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
> > +       if (!clk_table) {
> > +               pr_err("%s: could not allocate clock lookup table\n", __func__);
> > +               return;
> > +       }
> > +       clk_data.clks = clk_table;
> > +       clk_data.clk_num = nr_clks;
> > +       of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
> > +}
> > +
> > +void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *clks,
> > +                                        int nums, void __iomem *base)
> > +{
> > +       struct clk *clk;
> > +       int i;
> > +
> > +       for (i = 0; i < nums; i++) {
> > +               clk = clk_register_fixed_rate(NULL, clks[i].name,
> > +                                             clks[i].parent_name,
> > +                                             clks[i].flags,
> > +                                             clks[i].fixed_rate);
> > +               if (IS_ERR(clk)) {
> > +                       pr_err("%s: failed to register clock %s\n",
> > +                              __func__, clks[i].name);
> > +                       continue;
> > +               }
> > +       }
> > +}
> > +
> > +void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *clks,
> > +                                          int nums, void __iomem *base)
> > +{
> > +       struct clk *clk;
> > +       int i;
> > +
> > +       for (i = 0; i < nums; i++) {
> > +               clk = clk_register_fixed_factor(NULL, clks[i].name,
> > +                                               clks[i].parent_name,
> > +                                               clks[i].flags, clks[i].mult,
> > +                                               clks[i].div);
> > +               if (IS_ERR(clk)) {
> > +                       pr_err("%s: failed to register clock %s\n",
> > +                              __func__, clks[i].name);
> > +                       continue;
> > +               }
> > +       }
> > +}
> > +
> > +void __init hisi_clk_register_mux(struct hisi_mux_clock *clks,
> > +                                 int nums, void __iomem *base)
> > +{
> > +       struct clk *clk;
> > +       int i;
> > +
> > +       for (i = 0; i < nums; i++) {
> > +               clk = clk_register_mux(NULL, clks[i].name, clks[i].parent_names,
> > +                                      clks[i].num_parents, clks[i].flags,
> > +                                      base + clks[i].offset, clks[i].shift,
> > +                                      clks[i].width, clks[i].mux_flags,
> > +                                      &hisi_clk_lock);
> > +               if (IS_ERR(clk)) {
> > +                       pr_err("%s: failed to register clock %s\n",
> > +                              __func__, clks[i].name);
> > +                       continue;
> > +               }
> > +
> > +               if (clks[i].alias)
> > +                       clk_register_clkdev(clk, clks[i].alias, NULL);
> > +
> > +               clk_table[clks[i].id] = clk;
> > +       }
> > +}
> > +
> > +void __init hisi_clk_register_divider(struct hisi_divider_clock *clks,
> > +                                     int nums, void __iomem *base)
> > +{
> > +       struct clk *clk;
> > +       int i;
> > +
> > +       for (i = 0; i < nums; i++) {
> > +               clk = clk_register_divider_table(NULL, clks[i].name,
> > +                                                clks[i].parent_name,
> > +                                                clks[i].flags,
> > +                                                base + clks[i].offset,
> > +                                                clks[i].shift, clks[i].width,
> > +                                                clks[i].div_flags,
> > +                                                clks[i].table,
> > +                                                &hisi_clk_lock);
> > +               if (IS_ERR(clk)) {
> > +                       pr_err("%s: failed to register clock %s\n",
> > +                              __func__, clks[i].name);
> > +                       continue;
> > +               }
> > +
> > +               if (clks[i].alias)
> > +                       clk_register_clkdev(clk, clks[i].alias, NULL);
> > +
> > +               clk_table[clks[i].id] = clk;
> > +       }
> > +}
> > +
> > +void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks,
> > +                                      int nums, void __iomem *base)
> > +{
> > +       struct clk *clk;
> > +       int i;
> > +
> > +       for (i = 0; i < nums; i++) {
> > +               clk = hisi_register_clkgate_sep(NULL, clks[i].name,
> > +                                               clks[i].parent_name,
> > +                                               clks[i].flags,
> > +                                               base + clks[i].offset,
> > +                                               clks[i].bit_idx,
> > +                                               clks[i].gate_flags,
> > +                                               &hisi_clk_lock);
> > +               if (IS_ERR(clk)) {
> > +                       pr_err("%s: failed to register clock %s\n",
> > +                              __func__, clks[i].name);
> > +                       continue;
> > +               }
> > +
> > +               if (clks[i].alias)
> > +                       clk_register_clkdev(clk, clks[i].alias, NULL);
> > +
> > +               clk_table[clks[i].id] = clk;
> > +       }
> > +}
> > diff --git a/drivers/clk/hisilicon/clk.h b/drivers/clk/hisilicon/clk.h
> > new file mode 100644
> > index 0000000..4a6beeb
> > --- /dev/null
> > +++ b/drivers/clk/hisilicon/clk.h
> > @@ -0,0 +1,103 @@
> > +/*
> > + * Hisilicon Hi3620 clock gate driver
> > + *
> > + * Copyright (c) 2012-2013 Hisilicon Limited.
> > + * Copyright (c) 2012-2013 Linaro Limited.
> > + *
> > + * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
> > + *        Xin Li <li.xin@linaro.org>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License along
> > + * with this program; if not, write to the Free Software Foundation, Inc.,
> > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> > + *
> > + */
> > +
> > +#ifndef        __HISI_CLK_H
> > +#define        __HISI_CLK_H
> > +
> > +#include <linux/clk-provider.h>
> > +#include <linux/io.h>
> > +#include <linux/spinlock.h>
> > +
> > +struct hisi_fixed_rate_clock {
> > +       unsigned int            id;
> > +       char                    *name;
> > +       const char              *parent_name;
> > +       unsigned long           flags;
> > +       unsigned long           fixed_rate;
> > +};
> > +
> > +struct hisi_fixed_factor_clock {
> > +       unsigned int            id;
> > +       char                    *name;
> > +       const char              *parent_name;
> > +       unsigned long           mult;
> > +       unsigned long           div;
> > +       unsigned long           flags;
> > +};
> > +
> > +struct hisi_mux_clock {
> > +       unsigned int            id;
> > +       const char              *name;
> > +       const char              **parent_names;
> > +       u8                      num_parents;
> > +       unsigned long           flags;
> > +       unsigned long           offset;
> > +       u8                      shift;
> > +       u8                      width;
> > +       u8                      mux_flags;
> > +       const char              *alias;
> > +};
> > +
> > +struct hisi_divider_clock {
> > +       unsigned int            id;
> > +       const char              *name;
> > +       const char              *parent_name;
> > +       unsigned long           flags;
> > +       unsigned long           offset;
> > +       u8                      shift;
> > +       u8                      width;
> > +       u8                      div_flags;
> > +       struct clk_div_table    *table;
> > +       const char              *alias;
> > +};
> > +
> > +struct hisi_gate_clock {
> > +       unsigned int            id;
> > +       const char              *name;
> > +       const char              *parent_name;
> > +       unsigned long           flags;
> > +       unsigned long           offset;
> > +       u8                      bit_idx;
> > +       u8                      gate_flags;
> > +       const char              *alias;
> > +};
> > +
> > +struct clk *hisi_register_clkgate_sep(struct device *, const char *,
> > +                               const char *, unsigned long,
> > +                               void __iomem *, u8,
> > +                               u8, spinlock_t *);
> > +
> > +void __init hisi_clk_init(struct device_node *, int);
> > +void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *,
> > +                                       int, void __iomem *);
> > +void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *,
> > +                                       int, void __iomem *);
> > +void __init hisi_clk_register_mux(struct hisi_mux_clock *, int,
> > +                               void __iomem *);
> > +void __init hisi_clk_register_divider(struct hisi_divider_clock *,
> > +                               int, void __iomem *);
> > +void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *,
> > +                                       int, void __iomem *);
> > +#endif /* __HISI_CLK_H */
> > diff --git a/drivers/clk/hisilicon/clkgate-seperated.c b/drivers/clk/hisilicon/clkgate-seperated.c
> > new file mode 100644
> > index 0000000..cddc6d3
> > --- /dev/null
> > +++ b/drivers/clk/hisilicon/clkgate-seperated.c
> > @@ -0,0 +1,130 @@
> > +/*
> > + * Hisilicon clock seperated gate driver
> > + *
> > + * Copyright (c) 2012-2013 Hisilicon Limited.
> > + * Copyright (c) 2012-2013 Linaro Limited.
> > + *
> > + * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
> > + *        Xin Li <li.xin@linaro.org>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License along
> > + * with this program; if not, write to the Free Software Foundation, Inc.,
> > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> > + *
> > + */
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/clk-provider.h>
> > +#include <linux/clkdev.h>
> > +#include <linux/io.h>
> > +#include <linux/slab.h>
> > +#include <linux/clk.h>
> > +
> > +#include "clk.h"
> > +
> > +/* clock seperated gate register offset */
> > +#define CLKGATE_SEPERATED_ENABLE               0x0
> > +#define CLKGATE_SEPERATED_DISABLE              0x4
> > +#define CLKGATE_SEPERATED_STATUS               0x8
> > +
> > +struct clkgate_seperated {
> > +       struct clk_hw   hw;
> > +       void __iomem    *enable;        /* enable register */
> > +       u8              bit_idx;        /* bits in enable/disable register */
> > +       u8              flags;
> > +       spinlock_t      *lock;
> > +};
> > +
> > +static int clkgate_seperated_enable(struct clk_hw *hw)
> > +{
> > +       struct clkgate_seperated *sclk;
> > +       unsigned long flags = 0;
> > +       u32 reg;
> > +
> > +       sclk = container_of(hw, struct clkgate_seperated, hw);
> > +       if (sclk->lock)
> > +               spin_lock_irqsave(sclk->lock, flags);
> > +       reg = BIT(sclk->bit_idx);
> > +       writel_relaxed(reg, sclk->enable);
> > +       readl_relaxed(sclk->enable + CLKGATE_SEPERATED_STATUS);
> > +       if (sclk->lock)
> > +               spin_unlock_irqrestore(sclk->lock, flags);
> > +       return 0;
> > +}
> > +
> > +static void clkgate_seperated_disable(struct clk_hw *hw)
> > +{
> > +       struct clkgate_seperated *sclk;
> > +       unsigned long flags = 0;
> > +       u32 reg;
> > +
> > +       sclk = container_of(hw, struct clkgate_seperated, hw);
> > +       if (sclk->lock)
> > +               spin_lock_irqsave(sclk->lock, flags);
> > +       reg = BIT(sclk->bit_idx);
> > +       writel_relaxed(reg, sclk->enable + CLKGATE_SEPERATED_DISABLE);
> > +       readl_relaxed(sclk->enable + CLKGATE_SEPERATED_STATUS);
> > +       if (sclk->lock)
> > +               spin_unlock_irqrestore(sclk->lock, flags);
> > +}
> > +
> > +static int clkgate_seperated_is_enabled(struct clk_hw *hw)
> > +{
> > +       struct clkgate_seperated *sclk;
> > +       u32 reg;
> > +
> > +       sclk = container_of(hw, struct clkgate_seperated, hw);
> > +       reg = readl_relaxed(sclk->enable + CLKGATE_SEPERATED_STATUS);
> > +       reg &= BIT(sclk->bit_idx);
> > +
> > +       return reg ? 1 : 0;
> > +}
> > +
> > +static struct clk_ops clkgate_seperated_ops = {
> > +       .enable         = clkgate_seperated_enable,
> > +       .disable        = clkgate_seperated_disable,
> > +       .is_enabled     = clkgate_seperated_is_enabled,
> > +};
> > +
> > +struct clk *hisi_register_clkgate_sep(struct device *dev, const char *name,
> > +                                     const char *parent_name,
> > +                                     unsigned long flags,
> > +                                     void __iomem *reg, u8 bit_idx,
> > +                                     u8 clk_gate_flags, spinlock_t *lock)
> > +{
> > +       struct clkgate_seperated *sclk;
> > +       struct clk *clk;
> > +       struct clk_init_data init;
> > +
> > +       sclk = kzalloc(sizeof(struct clkgate_seperated), GFP_KERNEL);
> > +       if (!sclk) {
> > +               pr_err("%s: fail to allocate seperated gated clk\n", __func__);
> > +               return ERR_PTR(-ENOMEM);
> > +       }
> > +
> > +       init.name = name;
> > +       init.ops = &clkgate_seperated_ops;
> > +       init.flags = flags | CLK_IS_BASIC;
> > +       init.parent_names = (parent_name ? &parent_name : NULL);
> > +       init.num_parents = (parent_name ? 1 : 0);
> > +
> > +       sclk->enable = reg + CLKGATE_SEPERATED_ENABLE;
> > +       sclk->bit_idx = bit_idx;
> > +       sclk->flags = clk_gate_flags;
> > +       sclk->hw.init = &init;
> > +
> > +       clk = clk_register(dev, &sclk->hw);
> > +       if (IS_ERR(clk))
> > +               kfree(sclk);
> > +       return clk;
> > +}
> > diff --git a/include/dt-bindings/clock/hi3620-clock.h b/include/dt-bindings/clock/hi3620-clock.h
> > new file mode 100644
> > index 0000000..6eaa6a4
> > --- /dev/null
> > +++ b/include/dt-bindings/clock/hi3620-clock.h
> > @@ -0,0 +1,152 @@
> > +/*
> > + * Copyright (c) 2012-2013 Hisilicon Limited.
> > + * Copyright (c) 2012-2013 Linaro Limited.
> > + *
> > + * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
> > + *        Xin Li <li.xin@linaro.org>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License along
> > + * with this program; if not, write to the Free Software Foundation, Inc.,
> > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> > + *
> > + */
> > +
> > +#ifndef __DTS_HI3620_CLOCK_H
> > +#define __DTS_HI3620_CLOCK_H
> > +
> > +#define HI3620_NONE_CLOCK      0
> > +
> > +/* fixed rate & fixed factor clocks */
> > +#define HI3620_OSC32K          1
> > +#define HI3620_OSC26M          2
> > +#define HI3620_PCLK            3
> > +#define HI3620_PLL_ARM0                4
> > +#define HI3620_PLL_ARM1                5
> > +#define HI3620_PLL_PERI                6
> > +#define HI3620_PLL_USB         7
> > +#define HI3620_PLL_HDMI                8
> > +#define HI3620_PLL_GPU         9
> > +#define HI3620_RCLK_TCXO       10
> > +#define HI3620_RCLK_CFGAXI     11
> > +#define HI3620_RCLK_PICO       12
> > +
> > +/* mux clocks */
> > +#define HI3620_TIMER0_MUX      32
> > +#define HI3620_TIMER1_MUX      33
> > +#define HI3620_TIMER2_MUX      34
> > +#define HI3620_TIMER3_MUX      35
> > +#define HI3620_TIMER4_MUX      36
> > +#define HI3620_TIMER5_MUX      37
> > +#define HI3620_TIMER6_MUX      38
> > +#define HI3620_TIMER7_MUX      39
> > +#define HI3620_TIMER8_MUX      40
> > +#define HI3620_TIMER9_MUX      41
> > +#define HI3620_UART0_MUX       42
> > +#define HI3620_UART1_MUX       43
> > +#define HI3620_UART2_MUX       44
> > +#define HI3620_UART3_MUX       45
> > +#define HI3620_UART4_MUX       46
> > +#define HI3620_SPI0_MUX                47
> > +#define HI3620_SPI1_MUX                48
> > +#define HI3620_SPI2_MUX                49
> > +#define HI3620_SAXI_MUX                50
> > +#define HI3620_PWM0_MUX                51
> > +#define HI3620_PWM1_MUX                52
> > +#define HI3620_SD_MUX          53
> > +#define HI3620_MMC1_MUX                54
> > +#define HI3620_MMC1_MUX2       55
> > +#define HI3620_G2D_MUX         56
> > +#define HI3620_VENC_MUX                57
> > +#define HI3620_VDEC_MUX                58
> > +#define HI3620_VPP_MUX         59
> > +#define HI3620_EDC0_MUX                60
> > +#define HI3620_LDI0_MUX                61
> > +#define HI3620_EDC1_MUX                62
> > +#define HI3620_LDI1_MUX                63
> > +#define HI3620_RCLK_HSIC       64
> > +#define HI3620_MMC2_MUX                65
> > +#define HI3620_MMC3_MUX                66
> > +
> > +/* divider clocks */
> > +#define HI3620_SHAREAXI_DIV    128
> > +#define HI3620_CFGAXI_DIV      129
> > +#define HI3620_SD_DIV          130
> > +#define HI3620_MMC1_DIV                131
> > +#define HI3620_HSIC_DIV                132
> > +#define HI3620_MMC2_DIV                133
> > +#define HI3620_MMC3_DIV                134
> > +
> > +/* gate clocks */
> > +#define HI3620_TIMERCLK01      160
> > +#define HI3620_TIMER_RCLK01    161
> > +#define HI3620_TIMERCLK23      162
> > +#define HI3620_TIMER_RCLK23    163
> > +#define HI3620_TIMERCLK45      164
> > +#define HI3620_TIMERCLK67      165
> > +#define HI3620_TIMERCLK89      166
> > +#define HI3620_RTCCLK          167
> > +#define HI3620_KPC_CLK         168
> > +#define HI3620_GPIOCLK0                169
> > +#define HI3620_GPIOCLK1                170
> > +#define HI3620_GPIOCLK2                171
> > +#define HI3620_GPIOCLK3                172
> > +#define HI3620_GPIOCLK4                173
> > +#define HI3620_GPIOCLK5                174
> > +#define HI3620_GPIOCLK6                175
> > +#define HI3620_GPIOCLK7                176
> > +#define HI3620_GPIOCLK8                177
> > +#define HI3620_GPIOCLK9                178
> > +#define HI3620_GPIOCLK10       179
> > +#define HI3620_GPIOCLK11       180
> > +#define HI3620_GPIOCLK12       181
> > +#define HI3620_GPIOCLK13       182
> > +#define HI3620_GPIOCLK14       183
> > +#define HI3620_GPIOCLK15       184
> > +#define HI3620_GPIOCLK16       185
> > +#define HI3620_GPIOCLK17       186
> > +#define HI3620_GPIOCLK18       187
> > +#define HI3620_GPIOCLK19       188
> > +#define HI3620_GPIOCLK20       189
> > +#define HI3620_GPIOCLK21       190
> > +#define HI3620_DPHY0_CLK       191
> > +#define HI3620_DPHY1_CLK       192
> > +#define HI3620_DPHY2_CLK       193
> > +#define HI3620_USBPHY_CLK      194
> > +#define HI3620_ACP_CLK         195
> > +#define HI3620_PWMCLK0         196
> > +#define HI3620_PWMCLK1         197
> > +#define HI3620_UARTCLK0                198
> > +#define HI3620_UARTCLK1                199
> > +#define HI3620_UARTCLK2                200
> > +#define HI3620_UARTCLK3                201
> > +#define HI3620_UARTCLK4                202
> > +#define HI3620_SPICLK0         203
> > +#define HI3620_SPICLK1         204
> > +#define HI3620_SPICLK2         205
> > +#define HI3620_I2CCLK0         206
> > +#define HI3620_I2CCLK1         207
> > +#define HI3620_I2CCLK2         208
> > +#define HI3620_I2CCLK3         209
> > +#define HI3620_SCI_CLK         210
> > +#define HI3620_DDRC_PER_CLK    211
> > +#define HI3620_DMAC_CLK                212
> > +#define HI3620_USB2DVC_CLK     213
> > +#define HI3620_SD_CLK          214
> > +#define HI3620_MMC_CLK1                215
> > +#define HI3620_MMC_CLK2                216
> > +#define HI3620_MMC_CLK3                217
> > +#define HI3620_MCU_CLK         218
> > +
> > +#define HI3620_NR_CLKS         219
> > +
> > +#endif /* __DTS_HI3620_CLOCK_H */
> > -- 
> > 1.8.3.2
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/clock/hi3620-clock.txt b/Documentation/devicetree/bindings/clock/hi3620-clock.txt
new file mode 100644
index 0000000..80e134d
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/hi3620-clock.txt
@@ -0,0 +1,19 @@ 
+* Hisilicon Hi3620 Clock Controller
+
+The Hi3620 clock controller generates and supplies clock to various
+controllers within the Hi3620 SoC.
+
+Required Properties:
+
+- comptible: should be one of the following.
+  - "hisilicon,hi3620-clock" - controller compatible with Hi3620 SoC.
+
+- reg: physical base address of the controller and length of memory mapped
+  region.
+
+- #clock-cells: should be 1.
+
+Each clock is assigned an identifier and client nodes use this identifier
+to specify the clock which they consume.
+
+All these identifier could be found in <dt-bindings/clock/hi3620-clock.h>.
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 7b11106..e156b53 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -13,6 +13,7 @@  obj-$(CONFIG_COMMON_CLK)	+= clk-composite.o
 obj-$(CONFIG_ARCH_BCM2835)	+= clk-bcm2835.o
 obj-$(CONFIG_ARCH_NOMADIK)	+= clk-nomadik.o
 obj-$(CONFIG_ARCH_HIGHBANK)	+= clk-highbank.o
+obj-$(CONFIG_ARCH_HI3xxx)	+= hisilicon/
 obj-$(CONFIG_ARCH_NSPIRE)	+= clk-nspire.o
 obj-$(CONFIG_ARCH_MXS)		+= mxs/
 obj-$(CONFIG_ARCH_SOCFPGA)	+= socfpga/
diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile
new file mode 100644
index 0000000..fad958b
--- /dev/null
+++ b/drivers/clk/hisilicon/Makefile
@@ -0,0 +1,5 @@ 
+#
+# Hisilicon Clock specific Makefile
+#
+
+obj-y	+= clk.o clkgate-seperated.o clk-hi3620.o
diff --git a/drivers/clk/hisilicon/clk-hi3620.c b/drivers/clk/hisilicon/clk-hi3620.c
new file mode 100644
index 0000000..b66b074
--- /dev/null
+++ b/drivers/clk/hisilicon/clk-hi3620.c
@@ -0,0 +1,242 @@ 
+/*
+ * Hisilicon Hi3620 clock driver
+ *
+ * Copyright (c) 2012-2013 Hisilicon Limited.
+ * Copyright (c) 2012-2013 Linaro Limited.
+ *
+ * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
+ *	   Xin Li <li.xin@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+
+#include <dt-bindings/clock/hi3620-clock.h>
+
+#include "clk.h"
+
+/* clock parent list */
+static const char *timer0_mux_p[] __initdata = { "osc32k", "timerclk01", };
+static const char *timer1_mux_p[] __initdata = { "osc32k", "timerclk01", };
+static const char *timer2_mux_p[] __initdata = { "osc32k", "timerclk23", };
+static const char *timer3_mux_p[] __initdata = { "osc32k", "timerclk23", };
+static const char *timer4_mux_p[] __initdata = { "osc32k", "timerclk45", };
+static const char *timer5_mux_p[] __initdata = { "osc32k", "timerclk45", };
+static const char *timer6_mux_p[] __initdata = { "osc32k", "timerclk67", };
+static const char *timer7_mux_p[] __initdata = { "osc32k", "timerclk67", };
+static const char *timer8_mux_p[] __initdata = { "osc32k", "timerclk89", };
+static const char *timer9_mux_p[] __initdata = { "osc32k", "timerclk89", };
+static const char *uart0_mux_p[] __initdata = { "osc26m", "pclk", };
+static const char *uart1_mux_p[] __initdata = { "osc26m", "pclk", };
+static const char *uart2_mux_p[] __initdata = { "osc26m", "pclk", };
+static const char *uart3_mux_p[] __initdata = { "osc26m", "pclk", };
+static const char *uart4_mux_p[] __initdata = { "osc26m", "pclk", };
+static const char *spi0_mux_p[] __initdata = { "osc26m", "rclk_cfgaxi", };
+static const char *spi1_mux_p[] __initdata = { "osc26m", "rclk_cfgaxi", };
+static const char *spi2_mux_p[] __initdata = { "osc26m", "rclk_cfgaxi", };
+/* share axi parent */
+static const char *saxi_mux_p[] __initdata = { "armpll3", "armpll2", };
+static const char *pwm0_mux_p[] __initdata = { "osc32k", "osc26m", };
+static const char *pwm1_mux_p[] __initdata = { "osc32k", "osc26m", };
+static const char *sd_mux_p[] __initdata = { "armpll3", "armpll2", };
+static const char *mmc1_mux_p[] __initdata = { "armpll3", "armpll2", };
+static const char *mmc1_mux2_p[] __initdata = { "osc26m", "mmc1_div", };
+static const char *g2d_mux_p[] __initdata = { "armpll2", "armpll3", };
+static const char *venc_mux_p[] __initdata = { "armpll2", "armpll3", };
+static const char *vdec_mux_p[] __initdata = { "armpll2", "armpll3", };
+static const char *vpp_mux_p[] __initdata = { "armpll2", "armpll3", };
+static const char *edc0_mux_p[] __initdata = { "armpll2", "armpll3", };
+static const char *ldi0_mux_p[] __initdata = { "armpll2", "armpll4",
+					     "armpll3", "armpll5", };
+static const char *edc1_mux_p[] __initdata = { "armpll2", "armpll3", };
+static const char *ldi1_mux_p[] __initdata = { "armpll2", "armpll4",
+					     "armpll3", "armpll5", };
+static const char *rclk_hsic_p[] __initdata = { "armpll3", "armpll2", };
+static const char *mmc2_mux_p[] __initdata = { "armpll3", "armpll2", };
+static const char *mmc3_mux_p[] __initdata = { "armpll3", "armpll2", };
+
+
+/* fixed rate clocks */
+static struct hisi_fixed_rate_clock hi3620_fixed_rate_clks[] __initdata = {
+	{ HI3620_OSC32K,   "osc32k",   NULL, CLK_IS_ROOT, 32768, },
+	{ HI3620_OSC26M,   "osc26m",   NULL, CLK_IS_ROOT, 26000000, },
+	{ HI3620_PCLK,     "pclk",     NULL, CLK_IS_ROOT, 26000000, },
+	{ HI3620_PLL_ARM0, "armpll0",  NULL, CLK_IS_ROOT, 1600000000, },
+	{ HI3620_PLL_ARM1, "armpll1",  NULL, CLK_IS_ROOT, 1600000000, },
+	{ HI3620_PLL_PERI, "armpll2",  NULL, CLK_IS_ROOT, 1440000000, },
+	{ HI3620_PLL_USB,  "armpll3",  NULL, CLK_IS_ROOT, 1440000000, },
+	{ HI3620_PLL_HDMI, "armpll4",  NULL, CLK_IS_ROOT, 1188000000, },
+	{ HI3620_PLL_GPU,  "armpll5",  NULL, CLK_IS_ROOT, 1300000000, },
+};
+
+/* fixed factor clocks */
+static struct hisi_fixed_factor_clock hi3620_fixed_factor_clks[] __initdata = {
+	{ HI3620_RCLK_TCXO,   "rclk_tcxo",   "osc26m",   1, 4,  0, },
+	{ HI3620_RCLK_CFGAXI, "rclk_cfgaxi", "armpll2",  1, 30, 0, },
+	{ HI3620_RCLK_PICO,   "rclk_pico",   "hsic_div", 1, 40, 0, },
+};
+
+static struct hisi_mux_clock hi3620_mux_clks[] __initdata = {
+	{ HI3620_TIMER0_MUX, "timer0_mux", timer0_mux_p, ARRAY_SIZE(timer0_mux_p), CLK_SET_RATE_PARENT, 0,     15, 2, 0,                   },
+	{ HI3620_TIMER1_MUX, "timer1_mux", timer1_mux_p, ARRAY_SIZE(timer1_mux_p), CLK_SET_RATE_PARENT, 0,     17, 2, 0,                   },
+	{ HI3620_TIMER2_MUX, "timer2_mux", timer2_mux_p, ARRAY_SIZE(timer2_mux_p), CLK_SET_RATE_PARENT, 0,     19, 2, 0,                   },
+	{ HI3620_TIMER3_MUX, "timer3_mux", timer3_mux_p, ARRAY_SIZE(timer3_mux_p), CLK_SET_RATE_PARENT, 0,     21, 2, 0,                   },
+	{ HI3620_TIMER4_MUX, "timer4_mux", timer4_mux_p, ARRAY_SIZE(timer4_mux_p), CLK_SET_RATE_PARENT, 0x18,  0,  2, 0,                   },
+	{ HI3620_TIMER5_MUX, "timer5_mux", timer5_mux_p, ARRAY_SIZE(timer5_mux_p), CLK_SET_RATE_PARENT, 0x18,  2,  2, 0,                   },
+	{ HI3620_TIMER6_MUX, "timer6_mux", timer6_mux_p, ARRAY_SIZE(timer6_mux_p), CLK_SET_RATE_PARENT, 0x18,  4,  2, 0,                   },
+	{ HI3620_TIMER7_MUX, "timer7_mux", timer7_mux_p, ARRAY_SIZE(timer7_mux_p), CLK_SET_RATE_PARENT, 0x18,  6,  2, 0,                   },
+	{ HI3620_TIMER8_MUX, "timer8_mux", timer8_mux_p, ARRAY_SIZE(timer8_mux_p), CLK_SET_RATE_PARENT, 0x18,  8,  2, 0,                   },
+	{ HI3620_TIMER9_MUX, "timer9_mux", timer9_mux_p, ARRAY_SIZE(timer9_mux_p), CLK_SET_RATE_PARENT, 0x18,  10, 2, 0,                   },
+	{ HI3620_UART0_MUX,  "uart0_mux",  uart0_mux_p,  ARRAY_SIZE(uart0_mux_p),  CLK_SET_RATE_PARENT, 0x100, 7,  1, CLK_MUX_HIWORD_MASK, },
+	{ HI3620_UART1_MUX,  "uart1_mux",  uart1_mux_p,  ARRAY_SIZE(uart1_mux_p),  CLK_SET_RATE_PARENT, 0x100, 8,  1, CLK_MUX_HIWORD_MASK, },
+	{ HI3620_UART2_MUX,  "uart2_mux",  uart2_mux_p,  ARRAY_SIZE(uart2_mux_p),  CLK_SET_RATE_PARENT, 0x100, 9,  1, CLK_MUX_HIWORD_MASK, },
+	{ HI3620_UART3_MUX,  "uart3_mux",  uart3_mux_p,  ARRAY_SIZE(uart3_mux_p),  CLK_SET_RATE_PARENT, 0x100, 10, 1, CLK_MUX_HIWORD_MASK, },
+	{ HI3620_UART4_MUX,  "uart4_mux",  uart4_mux_p,  ARRAY_SIZE(uart4_mux_p),  CLK_SET_RATE_PARENT, 0x100, 11, 1, CLK_MUX_HIWORD_MASK, },
+	{ HI3620_SPI0_MUX,   "spi0_mux",   spi0_mux_p,   ARRAY_SIZE(spi0_mux_p),   CLK_SET_RATE_PARENT, 0x100, 12, 1, CLK_MUX_HIWORD_MASK, },
+	{ HI3620_SPI1_MUX,   "spi1_mux",   spi1_mux_p,   ARRAY_SIZE(spi1_mux_p),   CLK_SET_RATE_PARENT, 0x100, 13, 1, CLK_MUX_HIWORD_MASK, },
+	{ HI3620_SPI2_MUX,   "spi2_mux",   spi2_mux_p,   ARRAY_SIZE(spi2_mux_p),   CLK_SET_RATE_PARENT, 0x100, 14, 1, CLK_MUX_HIWORD_MASK, },
+	{ HI3620_SAXI_MUX,   "saxi_mux",   saxi_mux_p,   ARRAY_SIZE(saxi_mux_p),   CLK_SET_RATE_PARENT, 0x100, 15, 1, CLK_MUX_HIWORD_MASK, },
+	{ HI3620_PWM0_MUX,   "pwm0_mux",   pwm0_mux_p,   ARRAY_SIZE(pwm0_mux_p),   CLK_SET_RATE_PARENT, 0x104, 10, 1, CLK_MUX_HIWORD_MASK, },
+	{ HI3620_PWM1_MUX,   "pwm1_mux",   pwm1_mux_p,   ARRAY_SIZE(pwm1_mux_p),   CLK_SET_RATE_PARENT, 0x104, 11, 1, CLK_MUX_HIWORD_MASK, },
+	{ HI3620_SD_MUX,     "sd_mux",     sd_mux_p,     ARRAY_SIZE(sd_mux_p),     CLK_SET_RATE_PARENT, 0x108, 4,  1, CLK_MUX_HIWORD_MASK, },
+	{ HI3620_MMC1_MUX,   "mmc1_mux",   mmc1_mux_p,   ARRAY_SIZE(mmc1_mux_p),   CLK_SET_RATE_PARENT, 0x108, 9,  1, CLK_MUX_HIWORD_MASK, },
+	{ HI3620_MMC1_MUX2,  "mmc1_mux2",  mmc1_mux2_p,  ARRAY_SIZE(mmc1_mux2_p),  CLK_SET_RATE_PARENT, 0x108, 10, 1, CLK_MUX_HIWORD_MASK, },
+	{ HI3620_G2D_MUX,    "g2d_mux",    g2d_mux_p,    ARRAY_SIZE(g2d_mux_p),    CLK_SET_RATE_PARENT, 0x10c, 5,  1, CLK_MUX_HIWORD_MASK, },
+	{ HI3620_VENC_MUX,   "venc_mux",   venc_mux_p,   ARRAY_SIZE(venc_mux_p),   CLK_SET_RATE_PARENT, 0x10c, 11, 1, CLK_MUX_HIWORD_MASK, },
+	{ HI3620_VDEC_MUX,   "vdec_mux",   vdec_mux_p,   ARRAY_SIZE(vdec_mux_p),   CLK_SET_RATE_PARENT, 0x110, 5,  1, CLK_MUX_HIWORD_MASK, },
+	{ HI3620_VPP_MUX,    "vpp_mux",    vpp_mux_p,    ARRAY_SIZE(vpp_mux_p),    CLK_SET_RATE_PARENT, 0x110, 11, 1, CLK_MUX_HIWORD_MASK, },
+	{ HI3620_EDC0_MUX,   "edc0_mux",   edc0_mux_p,   ARRAY_SIZE(edc0_mux_p),   CLK_SET_RATE_PARENT, 0x114, 6,  1, CLK_MUX_HIWORD_MASK, },
+	{ HI3620_LDI0_MUX,   "ldi0_mux",   ldi0_mux_p,   ARRAY_SIZE(ldi0_mux_p),   CLK_SET_RATE_PARENT, 0x114, 13, 2, CLK_MUX_HIWORD_MASK, },
+	{ HI3620_EDC1_MUX,   "edc1_mux",   edc1_mux_p,   ARRAY_SIZE(edc1_mux_p),   CLK_SET_RATE_PARENT, 0x118, 6,  1, CLK_MUX_HIWORD_MASK, },
+	{ HI3620_LDI1_MUX,   "ldi1_mux",   ldi1_mux_p,   ARRAY_SIZE(ldi1_mux_p),   CLK_SET_RATE_PARENT, 0x118, 14, 2, CLK_MUX_HIWORD_MASK, },
+	{ HI3620_RCLK_HSIC,  "rclk_hsic",  rclk_hsic_p,  ARRAY_SIZE(rclk_hsic_p),  CLK_SET_RATE_PARENT, 0x130, 2,  1, CLK_MUX_HIWORD_MASK, },
+	{ HI3620_MMC2_MUX,   "mmc2_mux",   mmc2_mux_p,   ARRAY_SIZE(mmc2_mux_p),   CLK_SET_RATE_PARENT, 0x140, 4,  1, CLK_MUX_HIWORD_MASK, },
+	{ HI3620_MMC3_MUX,   "mmc3_mux",   mmc3_mux_p,   ARRAY_SIZE(mmc3_mux_p),   CLK_SET_RATE_PARENT, 0x140, 9,  1, CLK_MUX_HIWORD_MASK, },
+};
+
+static struct hisi_divider_clock hi3620_div_clks[] __initdata = {
+	{ HI3620_SHAREAXI_DIV, "saxi_div",   "saxi_mux",  0, 0x100, 0, 5, CLK_MUX_HIWORD_MASK, NULL, },
+	{ HI3620_CFGAXI_DIV,   "cfgaxi_div", "saxi_div",  0, 0x100, 5, 2, CLK_MUX_HIWORD_MASK, NULL, },
+	{ HI3620_SD_DIV,       "sd_div",     "sd_mux",	  0, 0x108, 0, 4, CLK_MUX_HIWORD_MASK, NULL, },
+	{ HI3620_MMC1_DIV,     "mmc1_div",   "mmc1_mux",  0, 0x108, 5, 4, CLK_MUX_HIWORD_MASK, NULL, },
+	{ HI3620_HSIC_DIV,     "hsic_div",   "rclk_hsic", 0, 0x130, 0, 2, CLK_MUX_HIWORD_MASK, NULL, },
+	{ HI3620_MMC2_DIV,     "mmc2_div",   "mmc2_mux",  0, 0x140, 0, 4, CLK_MUX_HIWORD_MASK, NULL, },
+	{ HI3620_MMC3_DIV,     "mmc3_div",   "mmc3_mux",  0, 0x140, 5, 4, CLK_MUX_HIWORD_MASK, NULL, },
+};
+
+static struct hisi_gate_clock hi3620_seperated_gate_clks[] __initdata = {
+	{ HI3620_TIMERCLK01,   "timerclk01",   "timer_rclk01", 0, 0x20, 0, 0, },
+	{ HI3620_TIMER_RCLK01, "timer_rclk01", "rclk_tcxo",    0, 0x20, 1, 0, },
+	{ HI3620_TIMERCLK23,   "timerclk23",   "timer_rclk23", 0, 0x20, 2, 0, },
+	{ HI3620_TIMER_RCLK23, "timer_rclk23", "rclk_tcxo",    0, 0x20, 3, 0, },
+	{ HI3620_RTCCLK,       "rtcclk",       "pclk",         0, 0x20, 5, 0, },
+	{ HI3620_KPC_CLK,      "kpc_clk",      "pclk",         0, 0x20, 6, 0, },
+	{ HI3620_GPIOCLK0,     "gpioclk0",     "pclk",         0, 0x20, 8, 0, },
+	{ HI3620_GPIOCLK1,     "gpioclk1",     "pclk",         0, 0x20, 9, 0, },
+	{ HI3620_GPIOCLK2,     "gpioclk2",     "pclk",         0, 0x20, 10, 0, },
+	{ HI3620_GPIOCLK3,     "gpioclk3",     "pclk",         0, 0x20, 11, 0, },
+	{ HI3620_GPIOCLK4,     "gpioclk4",     "pclk",         0, 0x20, 12, 0, },
+	{ HI3620_GPIOCLK5,     "gpioclk5",     "pclk",         0, 0x20, 13, 0, },
+	{ HI3620_GPIOCLK6,     "gpioclk6",     "pclk",         0, 0x20, 14, 0, },
+	{ HI3620_GPIOCLK7,     "gpioclk7",     "pclk",         0, 0x20, 15, 0, },
+	{ HI3620_GPIOCLK8,     "gpioclk8",     "pclk",         0, 0x20, 16, 0, },
+	{ HI3620_GPIOCLK9,     "gpioclk9",     "pclk",         0, 0x20, 17, 0, },
+	{ HI3620_GPIOCLK10,    "gpioclk10",    "pclk",         0, 0x20, 18, 0, },
+	{ HI3620_GPIOCLK11,    "gpioclk11",    "pclk",         0, 0x20, 19, 0, },
+	{ HI3620_GPIOCLK12,    "gpioclk12",    "pclk",         0, 0x20, 20, 0, },
+	{ HI3620_GPIOCLK13,    "gpioclk13",    "pclk",         0, 0x20, 21, 0, },
+	{ HI3620_GPIOCLK14,    "gpioclk14",    "pclk",         0, 0x20, 22, 0, },
+	{ HI3620_GPIOCLK15,    "gpioclk15",    "pclk",         0, 0x20, 23, 0, },
+	{ HI3620_GPIOCLK16,    "gpioclk16",    "pclk",         0, 0x20, 24, 0, },
+	{ HI3620_GPIOCLK17,    "gpioclk17",    "pclk",         0, 0x20, 25, 0, },
+	{ HI3620_GPIOCLK18,    "gpioclk18",    "pclk",         0, 0x20, 26, 0, },
+	{ HI3620_GPIOCLK19,    "gpioclk19",    "pclk",         0, 0x20, 27, 0, },
+	{ HI3620_GPIOCLK20,    "gpioclk20",    "pclk",         0, 0x20, 28, 0, },
+	{ HI3620_GPIOCLK21,    "gpioclk21",    "pclk",         0, 0x20, 29, 0, },
+	{ HI3620_DPHY0_CLK,    "dphy0_clk",    "osc26m",       0, 0x30, 15, 0, },
+	{ HI3620_DPHY1_CLK,    "dphy1_clk",    "osc26m",       0, 0x30, 16, 0, },
+	{ HI3620_DPHY2_CLK,    "dphy2_clk",    "osc26m",       0, 0x30, 17, 0, },
+	{ HI3620_USBPHY_CLK,   "usbphy_clk",   "rclk_pico",    0, 0x30, 24, 0, },
+	{ HI3620_ACP_CLK,      "acp_clk",      "rclk_cfgaxi",  0, 0x30, 28, 0, },
+	{ HI3620_TIMERCLK45,   "timerclk45",   "rclk_tcxo",    0, 0x40, 3, 0, },
+	{ HI3620_TIMERCLK67,   "timerclk67",   "rclk_tcxo",    0, 0x40, 4, 0, },
+	{ HI3620_TIMERCLK89,   "timerclk89",   "rclk_tcxo",    0, 0x40, 5, 0, },
+	{ HI3620_PWMCLK0,      "pwmclk0",      "pwm0_mux",     0, 0x40, 7, 0, },
+	{ HI3620_PWMCLK1,      "pwmclk1",      "pwm1_mux",     0, 0x40, 8, 0, },
+	{ HI3620_UARTCLK0,     "uartclk0",     "uart0_mux",    0, 0x40, 16, 0, },
+	{ HI3620_UARTCLK1,     "uartclk1",     "uart1_mux",    0, 0x40, 17, 0, },
+	{ HI3620_UARTCLK2,     "uartclk2",     "uart2_mux",    0, 0x40, 18, 0, },
+	{ HI3620_UARTCLK3,     "uartclk3",     "uart3_mux",    0, 0x40, 19, 0, },
+	{ HI3620_UARTCLK4,     "uartclk4",     "uart4_mux",    0, 0x40, 20, 0, },
+	{ HI3620_SPICLK0,      "spiclk0",      "spi0_mux",     0, 0x40, 21, 0, },
+	{ HI3620_SPICLK1,      "spiclk1",      "spi1_mux",     0, 0x40, 22, 0, },
+	{ HI3620_SPICLK2,      "spiclk2",      "spi2_mux",     0, 0x40, 23, 0, },
+	{ HI3620_I2CCLK0,      "i2cclk0",      "pclk",         0, 0x40, 24, 0, },
+	{ HI3620_I2CCLK1,      "i2cclk1",      "pclk",         0, 0x40, 25, 0, },
+	{ HI3620_SCI_CLK,      "sci_clk",      "osc26m",       0, 0x40, 26, 0, },
+	{ HI3620_I2CCLK2,      "i2cclk2",      "pclk",         0, 0x40, 28, 0, },
+	{ HI3620_I2CCLK3,      "i2cclk3",      "pclk",         0, 0x40, 29, 0, },
+	{ HI3620_DDRC_PER_CLK, "ddrc_per_clk", "rclk_cfgaxi",  0, 0x50, 9, 0, },
+	{ HI3620_DMAC_CLK,     "dmac_clk",     "rclk_cfgaxi",  0, 0x50, 10, 0, },
+	{ HI3620_USB2DVC_CLK,  "usb2dvc_clk",  "rclk_cfgaxi",  0, 0x50, 17, 0, },
+	{ HI3620_SD_CLK,       "sd_clk",       "sd_div",       0, 0x50, 20, 0, },
+	{ HI3620_MMC_CLK1,     "mmc_clk1",     "mmc1_mux2",    0, 0x50, 21, 0, },
+	{ HI3620_MMC_CLK2,     "mmc_clk2",     "mmc2_div",     0, 0x50, 22, 0, },
+	{ HI3620_MMC_CLK3,     "mmc_clk3",     "mmc3_div",     0, 0x50, 23, 0, },
+	{ HI3620_MCU_CLK,      "mcu_clk",      "acp_clk",      0, 0x50, 24, 0, },
+};
+
+static void __init hi3620_clk_init(struct device_node *np)
+{
+	void __iomem *base;
+
+	if (np) {
+		base = of_iomap(np, 0);
+		if (!base) {
+			pr_err("failed to map Hi3620 clock registers\n");
+			return;
+		}
+	} else {
+		pr_err("failed to find Hi3620 clock node in DTS\n");
+		return;
+	}
+
+	hisi_clk_init(np, HI3620_NR_CLKS);
+
+	hisi_clk_register_fixed_rate(hi3620_fixed_rate_clks,
+				     ARRAY_SIZE(hi3620_fixed_rate_clks),
+				     base);
+	hisi_clk_register_fixed_factor(hi3620_fixed_factor_clks,
+				       ARRAY_SIZE(hi3620_fixed_factor_clks),
+				       base);
+	hisi_clk_register_mux(hi3620_mux_clks, ARRAY_SIZE(hi3620_mux_clks),
+			      base);
+	hisi_clk_register_divider(hi3620_div_clks, ARRAY_SIZE(hi3620_div_clks),
+				  base);
+	hisi_clk_register_gate_sep(hi3620_seperated_gate_clks,
+				   ARRAY_SIZE(hi3620_seperated_gate_clks),
+				   base);
+}
+CLK_OF_DECLARE(hi3620_clk, "hisilicon,hi3620-clock", hi3620_clk_init);
diff --git a/drivers/clk/hisilicon/clk.c b/drivers/clk/hisilicon/clk.c
new file mode 100644
index 0000000..a3a7152
--- /dev/null
+++ b/drivers/clk/hisilicon/clk.c
@@ -0,0 +1,171 @@ 
+/*
+ * Hisilicon clock driver
+ *
+ * Copyright (c) 2012-2013 Hisilicon Limited.
+ * Copyright (c) 2012-2013 Linaro Limited.
+ *
+ * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
+ *	   Xin Li <li.xin@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+
+#include "clk.h"
+
+static DEFINE_SPINLOCK(hisi_clk_lock);
+static struct clk **clk_table;
+static struct clk_onecell_data clk_data;
+
+void __init hisi_clk_init(struct device_node *np, int nr_clks)
+{
+	clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
+	if (!clk_table) {
+		pr_err("%s: could not allocate clock lookup table\n", __func__);
+		return;
+	}
+	clk_data.clks = clk_table;
+	clk_data.clk_num = nr_clks;
+	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+}
+
+void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *clks,
+					 int nums, void __iomem *base)
+{
+	struct clk *clk;
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		clk = clk_register_fixed_rate(NULL, clks[i].name,
+					      clks[i].parent_name,
+					      clks[i].flags,
+					      clks[i].fixed_rate);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n",
+			       __func__, clks[i].name);
+			continue;
+		}
+	}
+}
+
+void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *clks,
+					   int nums, void __iomem *base)
+{
+	struct clk *clk;
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		clk = clk_register_fixed_factor(NULL, clks[i].name,
+						clks[i].parent_name,
+						clks[i].flags, clks[i].mult,
+						clks[i].div);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n",
+			       __func__, clks[i].name);
+			continue;
+		}
+	}
+}
+
+void __init hisi_clk_register_mux(struct hisi_mux_clock *clks,
+				  int nums, void __iomem *base)
+{
+	struct clk *clk;
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		clk = clk_register_mux(NULL, clks[i].name, clks[i].parent_names,
+				       clks[i].num_parents, clks[i].flags,
+				       base + clks[i].offset, clks[i].shift,
+				       clks[i].width, clks[i].mux_flags,
+				       &hisi_clk_lock);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n",
+			       __func__, clks[i].name);
+			continue;
+		}
+
+		if (clks[i].alias)
+			clk_register_clkdev(clk, clks[i].alias, NULL);
+
+		clk_table[clks[i].id] = clk;
+	}
+}
+
+void __init hisi_clk_register_divider(struct hisi_divider_clock *clks,
+				      int nums, void __iomem *base)
+{
+	struct clk *clk;
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		clk = clk_register_divider_table(NULL, clks[i].name,
+						 clks[i].parent_name,
+						 clks[i].flags,
+						 base + clks[i].offset,
+						 clks[i].shift, clks[i].width,
+						 clks[i].div_flags,
+						 clks[i].table,
+						 &hisi_clk_lock);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n",
+			       __func__, clks[i].name);
+			continue;
+		}
+
+		if (clks[i].alias)
+			clk_register_clkdev(clk, clks[i].alias, NULL);
+
+		clk_table[clks[i].id] = clk;
+	}
+}
+
+void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks,
+				       int nums, void __iomem *base)
+{
+	struct clk *clk;
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		clk = hisi_register_clkgate_sep(NULL, clks[i].name,
+						clks[i].parent_name,
+						clks[i].flags,
+						base + clks[i].offset,
+						clks[i].bit_idx,
+						clks[i].gate_flags,
+						&hisi_clk_lock);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n",
+			       __func__, clks[i].name);
+			continue;
+		}
+
+		if (clks[i].alias)
+			clk_register_clkdev(clk, clks[i].alias, NULL);
+
+		clk_table[clks[i].id] = clk;
+	}
+}
diff --git a/drivers/clk/hisilicon/clk.h b/drivers/clk/hisilicon/clk.h
new file mode 100644
index 0000000..4a6beeb
--- /dev/null
+++ b/drivers/clk/hisilicon/clk.h
@@ -0,0 +1,103 @@ 
+/*
+ * Hisilicon Hi3620 clock gate driver
+ *
+ * Copyright (c) 2012-2013 Hisilicon Limited.
+ * Copyright (c) 2012-2013 Linaro Limited.
+ *
+ * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
+ *	   Xin Li <li.xin@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef	__HISI_CLK_H
+#define	__HISI_CLK_H
+
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+
+struct hisi_fixed_rate_clock {
+	unsigned int		id;
+	char			*name;
+	const char		*parent_name;
+	unsigned long		flags;
+	unsigned long		fixed_rate;
+};
+
+struct hisi_fixed_factor_clock {
+	unsigned int		id;
+	char			*name;
+	const char		*parent_name;
+	unsigned long		mult;
+	unsigned long		div;
+	unsigned long		flags;
+};
+
+struct hisi_mux_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		**parent_names;
+	u8			num_parents;
+	unsigned long		flags;
+	unsigned long		offset;
+	u8			shift;
+	u8			width;
+	u8			mux_flags;
+	const char		*alias;
+};
+
+struct hisi_divider_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		*parent_name;
+	unsigned long		flags;
+	unsigned long		offset;
+	u8			shift;
+	u8			width;
+	u8			div_flags;
+	struct clk_div_table	*table;
+	const char		*alias;
+};
+
+struct hisi_gate_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		*parent_name;
+	unsigned long		flags;
+	unsigned long		offset;
+	u8			bit_idx;
+	u8			gate_flags;
+	const char		*alias;
+};
+
+struct clk *hisi_register_clkgate_sep(struct device *, const char *,
+				const char *, unsigned long,
+				void __iomem *, u8,
+				u8, spinlock_t *);
+
+void __init hisi_clk_init(struct device_node *, int);
+void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *,
+					int, void __iomem *);
+void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *,
+					int, void __iomem *);
+void __init hisi_clk_register_mux(struct hisi_mux_clock *, int,
+				void __iomem *);
+void __init hisi_clk_register_divider(struct hisi_divider_clock *,
+				int, void __iomem *);
+void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *,
+					int, void __iomem *);
+#endif	/* __HISI_CLK_H */
diff --git a/drivers/clk/hisilicon/clkgate-seperated.c b/drivers/clk/hisilicon/clkgate-seperated.c
new file mode 100644
index 0000000..cddc6d3
--- /dev/null
+++ b/drivers/clk/hisilicon/clkgate-seperated.c
@@ -0,0 +1,130 @@ 
+/*
+ * Hisilicon clock seperated gate driver
+ *
+ * Copyright (c) 2012-2013 Hisilicon Limited.
+ * Copyright (c) 2012-2013 Linaro Limited.
+ *
+ * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
+ *	   Xin Li <li.xin@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+
+#include "clk.h"
+
+/* clock seperated gate register offset */
+#define CLKGATE_SEPERATED_ENABLE		0x0
+#define CLKGATE_SEPERATED_DISABLE		0x4
+#define CLKGATE_SEPERATED_STATUS		0x8
+
+struct clkgate_seperated {
+	struct clk_hw	hw;
+	void __iomem	*enable;	/* enable register */
+	u8		bit_idx;	/* bits in enable/disable register */
+	u8		flags;
+	spinlock_t	*lock;
+};
+
+static int clkgate_seperated_enable(struct clk_hw *hw)
+{
+	struct clkgate_seperated *sclk;
+	unsigned long flags = 0;
+	u32 reg;
+
+	sclk = container_of(hw, struct clkgate_seperated, hw);
+	if (sclk->lock)
+		spin_lock_irqsave(sclk->lock, flags);
+	reg = BIT(sclk->bit_idx);
+	writel_relaxed(reg, sclk->enable);
+	readl_relaxed(sclk->enable + CLKGATE_SEPERATED_STATUS);
+	if (sclk->lock)
+		spin_unlock_irqrestore(sclk->lock, flags);
+	return 0;
+}
+
+static void clkgate_seperated_disable(struct clk_hw *hw)
+{
+	struct clkgate_seperated *sclk;
+	unsigned long flags = 0;
+	u32 reg;
+
+	sclk = container_of(hw, struct clkgate_seperated, hw);
+	if (sclk->lock)
+		spin_lock_irqsave(sclk->lock, flags);
+	reg = BIT(sclk->bit_idx);
+	writel_relaxed(reg, sclk->enable + CLKGATE_SEPERATED_DISABLE);
+	readl_relaxed(sclk->enable + CLKGATE_SEPERATED_STATUS);
+	if (sclk->lock)
+		spin_unlock_irqrestore(sclk->lock, flags);
+}
+
+static int clkgate_seperated_is_enabled(struct clk_hw *hw)
+{
+	struct clkgate_seperated *sclk;
+	u32 reg;
+
+	sclk = container_of(hw, struct clkgate_seperated, hw);
+	reg = readl_relaxed(sclk->enable + CLKGATE_SEPERATED_STATUS);
+	reg &= BIT(sclk->bit_idx);
+
+	return reg ? 1 : 0;
+}
+
+static struct clk_ops clkgate_seperated_ops = {
+	.enable		= clkgate_seperated_enable,
+	.disable	= clkgate_seperated_disable,
+	.is_enabled	= clkgate_seperated_is_enabled,
+};
+
+struct clk *hisi_register_clkgate_sep(struct device *dev, const char *name,
+				      const char *parent_name,
+				      unsigned long flags,
+				      void __iomem *reg, u8 bit_idx,
+				      u8 clk_gate_flags, spinlock_t *lock)
+{
+	struct clkgate_seperated *sclk;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	sclk = kzalloc(sizeof(struct clkgate_seperated), GFP_KERNEL);
+	if (!sclk) {
+		pr_err("%s: fail to allocate seperated gated clk\n", __func__);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	init.name = name;
+	init.ops = &clkgate_seperated_ops;
+	init.flags = flags | CLK_IS_BASIC;
+	init.parent_names = (parent_name ? &parent_name : NULL);
+	init.num_parents = (parent_name ? 1 : 0);
+
+	sclk->enable = reg + CLKGATE_SEPERATED_ENABLE;
+	sclk->bit_idx = bit_idx;
+	sclk->flags = clk_gate_flags;
+	sclk->hw.init = &init;
+
+	clk = clk_register(dev, &sclk->hw);
+	if (IS_ERR(clk))
+		kfree(sclk);
+	return clk;
+}
diff --git a/include/dt-bindings/clock/hi3620-clock.h b/include/dt-bindings/clock/hi3620-clock.h
new file mode 100644
index 0000000..6eaa6a4
--- /dev/null
+++ b/include/dt-bindings/clock/hi3620-clock.h
@@ -0,0 +1,152 @@ 
+/*
+ * Copyright (c) 2012-2013 Hisilicon Limited.
+ * Copyright (c) 2012-2013 Linaro Limited.
+ *
+ * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
+ *	   Xin Li <li.xin@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef __DTS_HI3620_CLOCK_H
+#define __DTS_HI3620_CLOCK_H
+
+#define HI3620_NONE_CLOCK	0
+
+/* fixed rate & fixed factor clocks */
+#define HI3620_OSC32K		1
+#define HI3620_OSC26M		2
+#define HI3620_PCLK		3
+#define HI3620_PLL_ARM0		4
+#define HI3620_PLL_ARM1		5
+#define HI3620_PLL_PERI		6
+#define HI3620_PLL_USB		7
+#define HI3620_PLL_HDMI		8
+#define HI3620_PLL_GPU		9
+#define HI3620_RCLK_TCXO	10
+#define HI3620_RCLK_CFGAXI	11
+#define HI3620_RCLK_PICO	12
+
+/* mux clocks */
+#define HI3620_TIMER0_MUX	32
+#define HI3620_TIMER1_MUX	33
+#define HI3620_TIMER2_MUX	34
+#define HI3620_TIMER3_MUX	35
+#define HI3620_TIMER4_MUX	36
+#define HI3620_TIMER5_MUX	37
+#define HI3620_TIMER6_MUX	38
+#define HI3620_TIMER7_MUX	39
+#define HI3620_TIMER8_MUX	40
+#define HI3620_TIMER9_MUX	41
+#define HI3620_UART0_MUX	42
+#define HI3620_UART1_MUX	43
+#define HI3620_UART2_MUX	44
+#define HI3620_UART3_MUX	45
+#define HI3620_UART4_MUX	46
+#define HI3620_SPI0_MUX		47
+#define HI3620_SPI1_MUX		48
+#define HI3620_SPI2_MUX		49
+#define HI3620_SAXI_MUX		50
+#define HI3620_PWM0_MUX		51
+#define HI3620_PWM1_MUX		52
+#define HI3620_SD_MUX		53
+#define HI3620_MMC1_MUX		54
+#define HI3620_MMC1_MUX2	55
+#define HI3620_G2D_MUX		56
+#define HI3620_VENC_MUX		57
+#define HI3620_VDEC_MUX		58
+#define HI3620_VPP_MUX		59
+#define HI3620_EDC0_MUX		60
+#define HI3620_LDI0_MUX		61
+#define HI3620_EDC1_MUX		62
+#define HI3620_LDI1_MUX		63
+#define HI3620_RCLK_HSIC	64
+#define HI3620_MMC2_MUX		65
+#define HI3620_MMC3_MUX		66
+
+/* divider clocks */
+#define HI3620_SHAREAXI_DIV	128
+#define HI3620_CFGAXI_DIV	129
+#define HI3620_SD_DIV		130
+#define HI3620_MMC1_DIV		131
+#define HI3620_HSIC_DIV		132
+#define HI3620_MMC2_DIV		133
+#define HI3620_MMC3_DIV		134
+
+/* gate clocks */
+#define HI3620_TIMERCLK01	160
+#define HI3620_TIMER_RCLK01	161
+#define HI3620_TIMERCLK23	162
+#define HI3620_TIMER_RCLK23	163
+#define HI3620_TIMERCLK45	164
+#define HI3620_TIMERCLK67	165
+#define HI3620_TIMERCLK89	166
+#define HI3620_RTCCLK		167
+#define HI3620_KPC_CLK		168
+#define HI3620_GPIOCLK0		169
+#define HI3620_GPIOCLK1		170
+#define HI3620_GPIOCLK2		171
+#define HI3620_GPIOCLK3		172
+#define HI3620_GPIOCLK4		173
+#define HI3620_GPIOCLK5		174
+#define HI3620_GPIOCLK6		175
+#define HI3620_GPIOCLK7		176
+#define HI3620_GPIOCLK8		177
+#define HI3620_GPIOCLK9		178
+#define HI3620_GPIOCLK10	179
+#define HI3620_GPIOCLK11	180
+#define HI3620_GPIOCLK12	181
+#define HI3620_GPIOCLK13	182
+#define HI3620_GPIOCLK14	183
+#define HI3620_GPIOCLK15	184
+#define HI3620_GPIOCLK16	185
+#define HI3620_GPIOCLK17	186
+#define HI3620_GPIOCLK18	187
+#define HI3620_GPIOCLK19	188
+#define HI3620_GPIOCLK20	189
+#define HI3620_GPIOCLK21	190
+#define HI3620_DPHY0_CLK	191
+#define HI3620_DPHY1_CLK	192
+#define HI3620_DPHY2_CLK	193
+#define HI3620_USBPHY_CLK	194
+#define HI3620_ACP_CLK		195
+#define HI3620_PWMCLK0		196
+#define HI3620_PWMCLK1		197
+#define HI3620_UARTCLK0		198
+#define HI3620_UARTCLK1		199
+#define HI3620_UARTCLK2		200
+#define HI3620_UARTCLK3		201
+#define HI3620_UARTCLK4		202
+#define HI3620_SPICLK0		203
+#define HI3620_SPICLK1		204
+#define HI3620_SPICLK2		205
+#define HI3620_I2CCLK0		206
+#define HI3620_I2CCLK1		207
+#define HI3620_I2CCLK2		208
+#define HI3620_I2CCLK3		209
+#define HI3620_SCI_CLK		210
+#define HI3620_DDRC_PER_CLK	211
+#define HI3620_DMAC_CLK		212
+#define HI3620_USB2DVC_CLK	213
+#define HI3620_SD_CLK		214
+#define HI3620_MMC_CLK1		215
+#define HI3620_MMC_CLK2		216
+#define HI3620_MMC_CLK3		217
+#define HI3620_MCU_CLK		218
+
+#define HI3620_NR_CLKS		219
+
+#endif	/* __DTS_HI3620_CLOCK_H */