[v2] clk: uniphier: add clock drivers for UniPhier SoCs
diff mbox

Message ID 1451298003-28841-1-git-send-email-yamada.masahiro@socionext.com
State New, archived
Headers show

Commit Message

Masahiro Yamada Dec. 28, 2015, 10:20 a.m. UTC
This is the initial commit for the UniPhier clock drivers, including
support for PH1-sLD3, PH1-LD4, PH1-Pro4, PH1-sLD8, PH1-Pro5, and
ProXstream2/PH1-LD6b.

To improve the code maintainability, the driver consists of common
functions (clk-uniphier-core.c) and clock data arrays needed to
support each SoC.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---

Changes in v2:
  - split emmc_hw_reset
  - make SD clock rate-controllable
  - add CLK_SET_RATE_PARENT flag to mux, gate, fixed-factor clocks

 MAINTAINERS                              |   1 +
 drivers/clk/Kconfig                      |   1 +
 drivers/clk/Makefile                     |   1 +
 drivers/clk/uniphier/Kconfig             |  35 ++++
 drivers/clk/uniphier/Makefile            |  10 +
 drivers/clk/uniphier/clk-ph1-ld4.c       | 117 ++++++++++++
 drivers/clk/uniphier/clk-ph1-pro4.c      | 117 ++++++++++++
 drivers/clk/uniphier/clk-ph1-pro5.c      | 107 +++++++++++
 drivers/clk/uniphier/clk-ph1-sld3.c      | 117 ++++++++++++
 drivers/clk/uniphier/clk-ph1-sld8.c      | 107 +++++++++++
 drivers/clk/uniphier/clk-proxstream2.c   |  88 +++++++++
 drivers/clk/uniphier/clk-uniphier-core.c | 151 +++++++++++++++
 drivers/clk/uniphier/clk-uniphier-mio.c  | 315 +++++++++++++++++++++++++++++++
 drivers/clk/uniphier/clk-uniphier-peri.c | 175 +++++++++++++++++
 drivers/clk/uniphier/clk-uniphier.h      |  68 +++++++
 15 files changed, 1410 insertions(+)
 create mode 100644 drivers/clk/uniphier/Kconfig
 create mode 100644 drivers/clk/uniphier/Makefile
 create mode 100644 drivers/clk/uniphier/clk-ph1-ld4.c
 create mode 100644 drivers/clk/uniphier/clk-ph1-pro4.c
 create mode 100644 drivers/clk/uniphier/clk-ph1-pro5.c
 create mode 100644 drivers/clk/uniphier/clk-ph1-sld3.c
 create mode 100644 drivers/clk/uniphier/clk-ph1-sld8.c
 create mode 100644 drivers/clk/uniphier/clk-proxstream2.c
 create mode 100644 drivers/clk/uniphier/clk-uniphier-core.c
 create mode 100644 drivers/clk/uniphier/clk-uniphier-mio.c
 create mode 100644 drivers/clk/uniphier/clk-uniphier-peri.c
 create mode 100644 drivers/clk/uniphier/clk-uniphier.h

Comments

Stephen Boyd Feb. 26, 2016, 12:07 a.m. UTC | #1
On 12/28, Masahiro Yamada wrote:
> This is the initial commit for the UniPhier clock drivers, including
> support for PH1-sLD3, PH1-LD4, PH1-Pro4, PH1-sLD8, PH1-Pro5, and
> ProXstream2/PH1-LD6b.
> 
> To improve the code maintainability, the driver consists of common
> functions (clk-uniphier-core.c) and clock data arrays needed to
> support each SoC.
> 
> Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
> ---

Where's the DT binding? Also, can these clks be registered from a
platform device driver instead of from 
> 
> diff --git a/drivers/clk/uniphier/Kconfig b/drivers/clk/uniphier/Kconfig
> new file mode 100644
> index 0000000..7606f27
> --- /dev/null
> +++ b/drivers/clk/uniphier/Kconfig
> @@ -0,0 +1,35 @@
> +menuconfig CLK_UNIPHIER
> +	bool "Clock drivers for UniPhier SoCs"
> +	depends on ARCH_UNIPHIER

Can we have COMPILE_TEST here?

> +	depends on OF
> +	default y

And then default ARCH_UNIPHIER instead.

> +	help
> +	  Supports clock drivers for UniPhier SoCs.
> +
> +if CLK_UNIPHIER
> +
> +config CLK_UNIPHIER_PH1_SLD3
> +	bool "Clock driver for UniPhier PH1-sLD3 SoC"
> +	default y

These would all become default ARCH_UNIPHIER as well.
> +
> +config CLK_UNIPHIER_PH1_LD4
> +	bool "Clock driver for UniPhier PH1-LD4 SoC"
> +	default y
> +
> +config CLK_UNIPHIER_PH1_PRO4
> +	bool "Clock driver for UniPhier PH1-Pro4 SoC"
> +	default y
> +
> +config CLK_UNIPHIER_PH1_SLD8
> +	bool "Clock driver for UniPhier PH1-sLD8 SoC"
> +	default y
> +
> +config CLK_UNIPHIER_PH1_PRO5
> +	bool "Clock driver for UniPhier PH1-Pro5 SoC"
> +	default y
> +
> +config CLK_UNIPHIER_PROXSTREAM2
> +	bool "Clock driver for UniPhier ProXstream2/PH1-LD6b SoC"
> +	default y
> +
> +endif
> diff --git a/drivers/clk/uniphier/clk-uniphier-core.c b/drivers/clk/uniphier/clk-uniphier-core.c

Maybe this patch can be split between core code and SoC specific
data? That way we can focus on the core code without wading
through all the random clk data arrays.

> new file mode 100644
> index 0000000..8680101
> --- /dev/null
> +++ b/drivers/clk/uniphier/clk-uniphier-core.c
> @@ -0,0 +1,151 @@
> +/*
> + * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
> + *
> + * 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.
> + */
> +
> +#define pr_fmt(fmt)		"uniphier-clk: " fmt
> +
> +#include <linux/clk-provider.h>
> +#include <linux/log2.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/slab.h>
> +
> +#include "clk-uniphier.h"
> +
> +static void __init uniphier_clk_update_parent_name(struct device_node *np,
> +						   const char **parent_name)
> +{
> +	const char *new_name;
> +	int index;
> +
> +	if (!parent_name || !*parent_name)
> +		return;
> +
> +	if (strncmp(*parent_name, UNIPHIER_CLK_EXT, strlen(UNIPHIER_CLK_EXT)))
> +		return;
> +
> +	index = of_property_match_string(np, "clock-names",
> +				*parent_name + strlen(UNIPHIER_CLK_EXT));

If possible please don't use clock-names to set up clock
hierarchy.

> +	new_name = of_clk_get_parent_name(np, index);
> +	if (new_name)
> +		*parent_name = new_name;
> +}
> +
> +static struct clk * __init uniphier_clk_register(struct device_node *np,
> +						 void __iomem *regbase,
> +					  struct uniphier_clk_init_data *idata)
> +{
> +	int i;
> +
> +	switch (idata->type) {
> +	case UNIPHIER_CLK_TYPE_FIXED_FACTOR:
> +		uniphier_clk_update_parent_name(np,
> +					&idata->data.factor.parent_name);
> +		return clk_register_fixed_factor(NULL, idata->name,
> +						 idata->data.factor.parent_name,
> +						 CLK_SET_RATE_PARENT,
> +						 idata->data.factor.mult,
> +						 idata->data.factor.div);
> +	case UNIPHIER_CLK_TYPE_FIXED_RATE:
> +		return clk_register_fixed_rate(NULL, idata->name, NULL,
> +					       CLK_IS_ROOT,
> +					       idata->data.rate.fixed_rate);
> +	case UNIPHIER_CLK_TYPE_GATE:
> +		uniphier_clk_update_parent_name(np,
> +						&idata->data.gate.parent_name);
> +		return clk_register_gate(NULL, idata->name,
> +					 idata->data.gate.parent_name,
> +					 idata->data.gate.parent_name ?
> +					 CLK_SET_RATE_PARENT : CLK_IS_ROOT,
> +					 regbase + idata->data.gate.reg,
> +					 idata->data.gate.bit_idx, 0, NULL);
> +	case UNIPHIER_CLK_TYPE_MUX:
> +		for (i = 0; i < idata->data.mux.num_parents; i++)
> +			uniphier_clk_update_parent_name(np,
> +					&idata->data.mux.parent_names[i]);
> +		return clk_register_mux(NULL, idata->name,
> +					idata->data.mux.parent_names,
> +					idata->data.mux.num_parents,
> +					CLK_SET_RATE_PARENT,
> +					regbase + idata->data.mux.reg,
> +					idata->data.mux.shift,
> +					ilog2(idata->data.mux.num_parents),
> +					0, NULL);
> +	default:
> +		WARN(1, "unsupported clock type\n");
> +		return ERR_PTR(-EINVAL);
> +	}
> +}
> +
> +int __init uniphier_clk_init(struct device_node *np,
> +			     struct uniphier_clk_init_data *idata)
> +{
> +	struct clk_onecell_data *clk_data;
> +	struct uniphier_clk_init_data *p;
> +	void __iomem *regbase;
> +	int max_index = 0;
> +	int ret;
> +
> +	regbase = of_iomap(np, 0);

If not a platform device, use of_io_request_and_map()?

> +	if (!regbase)
> +		return -ENOMEM;
> +
> +	for (p = idata; p->name; p++)
> +		max_index = max(max_index, p->output_index);
> +
> +	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
> +	if (!clk_data)
> +		return -ENOMEM;
> +
> +	clk_data->clk_num = max_index + 1;
> +	clk_data->clks = kcalloc(clk_data->clk_num, sizeof(struct clk *),
> +				 GFP_KERNEL);
> diff --git a/drivers/clk/uniphier/clk-uniphier.h b/drivers/clk/uniphier/clk-uniphier.h
> new file mode 100644
> index 0000000..05277b6
> --- /dev/null
> +++ b/drivers/clk/uniphier/clk-uniphier.h
> @@ -0,0 +1,68 @@
> +/*
> + * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
> + *
> + * 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.
> + */
> +
> +#ifndef __CLK_UNIPHIER_H__
> +#define __CLK_UNIPHIER_H__
> +
> +#include <linux/kernel.h>

What's this include for?

> +
> +#define UNIPHIER_CLK_EXT	"[EXT]"
> +
> +enum uniphier_clk_type {
> +	UNIPHIER_CLK_TYPE_FIXED_FACTOR,
> +	UNIPHIER_CLK_TYPE_FIXED_RATE,
> +	UNIPHIER_CLK_TYPE_GATE,
> +	UNIPHIER_CLK_TYPE_MUX,
> +};
> +
> +struct uniphier_clk_fixed_factor_data {
> +	const char *parent_name;
> +	unsigned int mult;
> +	unsigned int div;
> +};
> +
> +struct uniphier_clk_fixed_rate_data {
> +	unsigned long fixed_rate;
> +};
> +
> +struct uniphier_clk_gate_data {
> +	const char *parent_name;
> +	unsigned int reg;
> +	u8 bit_idx;
> +};
> +
> +struct uniphier_clk_mux_data {
> +	const char *parent_names[4];
> +	u8 num_parents;
> +	unsigned int reg;
> +	u8 shift;
> +};
> +
> +struct uniphier_clk_init_data {
> +	const char *name;
> +	enum uniphier_clk_type type;
> +	int output_index;
> +	union {
> +		struct uniphier_clk_fixed_factor_data factor;
> +		struct uniphier_clk_fixed_rate_data rate;
> +		struct uniphier_clk_gate_data gate;
> +		struct uniphier_clk_mux_data mux;
> +	} data;
> +	struct clk *clk;

Probably need to forward declare this struct.

> +};
> +
> +int uniphier_clk_init(struct device_node *np,

Same for device_node.

> +		      struct uniphier_clk_init_data *idata);
> +
> +#endif /* __CLK_UNIPHIER_H__ */
> -- 
> 1.9.1
>
Masahiro Yamada May 2, 2016, 3:59 p.m. UTC | #2
Hi Stephen,

I am back after long silence.

2016-02-26 9:07 GMT+09:00 Stephen Boyd <sboyd@codeaurora.org>:
> On 12/28, Masahiro Yamada wrote:
>> This is the initial commit for the UniPhier clock drivers, including
>> support for PH1-sLD3, PH1-LD4, PH1-Pro4, PH1-sLD8, PH1-Pro5, and
>> ProXstream2/PH1-LD6b.
>>
>> To improve the code maintainability, the driver consists of common
>> functions (clk-uniphier-core.c) and clock data arrays needed to
>> support each SoC.
>>
>> Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
>> ---
>
> Where's the DT binding? Also, can these clks be registered from a
> platform device driver instead of from
>>
>> diff --git a/drivers/clk/uniphier/Kconfig b/drivers/clk/uniphier/Kconfig
>> new file mode 100644
>> index 0000000..7606f27
>> --- /dev/null
>> +++ b/drivers/clk/uniphier/Kconfig
>> @@ -0,0 +1,35 @@
>> +menuconfig CLK_UNIPHIER
>> +     bool "Clock drivers for UniPhier SoCs"
>> +     depends on ARCH_UNIPHIER
>
> Can we have COMPILE_TEST here?

OK.
But if you recommend to drop "depends on ARCH_UNIPHIER",
COMPILE_TEST is not necessary.


>> +     depends on OF
>> +     default y
>
> And then default ARCH_UNIPHIER instead.



The problem is that CLK_UNIPHIER is not enabled along with
ARCH_UNIPHIER in "make menuconfig".

If we use "depends on ARCH_UNIPHIER"
and we enable ARCH_UNIPHIER from "make menuconfig",
CLK_UNIPHIER is automatically enabled as well.

Is the latter more like what we expect?




>> +endif
>> diff --git a/drivers/clk/uniphier/clk-uniphier-core.c b/drivers/clk/uniphier/clk-uniphier-core.c
>
> Maybe this patch can be split between core code and SoC specific
> data? That way we can focus on the core code without wading
> through all the random clk data arrays.

OK.  will do so.



>> +static void __init uniphier_clk_update_parent_name(struct device_node *np,
>> +                                                const char **parent_name)
>> +{
>> +     const char *new_name;
>> +     int index;
>> +
>> +     if (!parent_name || !*parent_name)
>> +             return;
>> +
>> +     if (strncmp(*parent_name, UNIPHIER_CLK_EXT, strlen(UNIPHIER_CLK_EXT)))
>> +             return;
>> +
>> +     index = of_property_match_string(np, "clock-names",
>> +                             *parent_name + strlen(UNIPHIER_CLK_EXT));
>
> If possible please don't use clock-names to set up clock
> hierarchy.

So, what shall I do instead?

I am not comfortable with hard-coding the parents' names
for clock-cascading.

Maybe, can we support clk registration
with clk_hw of parents, not names of parents?

For example, by adding  "struct clk_hw **parents"
to struct clk_init_data.



>> +int __init uniphier_clk_init(struct device_node *np,
>> +                          struct uniphier_clk_init_data *idata)
>> +{
>> +     struct clk_onecell_data *clk_data;
>> +     struct uniphier_clk_init_data *p;
>> +     void __iomem *regbase;
>> +     int max_index = 0;
>> +     int ret;
>> +
>> +     regbase = of_iomap(np, 0);
>
> If not a platform device, use of_io_request_and_map()?


I am planning to change all of them into platform drivers in the next version.



>> +#ifndef __CLK_UNIPHIER_H__
>> +#define __CLK_UNIPHIER_H__
>> +
>> +#include <linux/kernel.h>
>
> What's this include for?

Probably my mistake.  Will remove.


>> +
>> +#define UNIPHIER_CLK_EXT     "[EXT]"
>> +
>> +enum uniphier_clk_type {
>> +     UNIPHIER_CLK_TYPE_FIXED_FACTOR,
>> +     UNIPHIER_CLK_TYPE_FIXED_RATE,
>> +     UNIPHIER_CLK_TYPE_GATE,
>> +     UNIPHIER_CLK_TYPE_MUX,
>> +};
>> +
>> +struct uniphier_clk_fixed_factor_data {
>> +     const char *parent_name;
>> +     unsigned int mult;
>> +     unsigned int div;
>> +};
>> +
>> +struct uniphier_clk_fixed_rate_data {
>> +     unsigned long fixed_rate;
>> +};
>> +
>> +struct uniphier_clk_gate_data {
>> +     const char *parent_name;
>> +     unsigned int reg;
>> +     u8 bit_idx;
>> +};
>> +
>> +struct uniphier_clk_mux_data {
>> +     const char *parent_names[4];
>> +     u8 num_parents;
>> +     unsigned int reg;
>> +     u8 shift;
>> +};
>> +
>> +struct uniphier_clk_init_data {
>> +     const char *name;
>> +     enum uniphier_clk_type type;
>> +     int output_index;
>> +     union {
>> +             struct uniphier_clk_fixed_factor_data factor;
>> +             struct uniphier_clk_fixed_rate_data rate;
>> +             struct uniphier_clk_gate_data gate;
>> +             struct uniphier_clk_mux_data mux;
>> +     } data;
>> +     struct clk *clk;
>
> Probably need to forward declare this struct.


OK, thanks.

>> +};
>> +
>> +int uniphier_clk_init(struct device_node *np,
>
> Same for device_node.
Stephen Boyd May 3, 2016, 12:33 a.m. UTC | #3
On 05/03, Masahiro Yamada wrote:
> 
> 2016-02-26 9:07 GMT+09:00 Stephen Boyd <sboyd@codeaurora.org>:
> > On 12/28, Masahiro Yamada wrote:
> >>
> >> diff --git a/drivers/clk/uniphier/Kconfig b/drivers/clk/uniphier/Kconfig
> >> new file mode 100644
> >> index 0000000..7606f27
> >> --- /dev/null
> >> +++ b/drivers/clk/uniphier/Kconfig
> >> @@ -0,0 +1,35 @@
> >> +menuconfig CLK_UNIPHIER
> >> +     bool "Clock drivers for UniPhier SoCs"
> >> +     depends on ARCH_UNIPHIER
> >
> > Can we have COMPILE_TEST here?
> 
> OK.
> But if you recommend to drop "depends on ARCH_UNIPHIER",
> COMPILE_TEST is not necessary.

Right, I wasn't recommending removing the depends on
ARCH_UNIPHIER. Sorry if that wasn't clear.

> 
> 
> >> +     depends on OF
> >> +     default y
> >
> > And then default ARCH_UNIPHIER instead.
> 
> 
> 
> The problem is that CLK_UNIPHIER is not enabled along with
> ARCH_UNIPHIER in "make menuconfig".
> 
> If we use "depends on ARCH_UNIPHIER"
> and we enable ARCH_UNIPHIER from "make menuconfig",
> CLK_UNIPHIER is automatically enabled as well.
> 
> Is the latter more like what we expect?

I'm thinking

	menuconfig CLK_UNIPHIER
		bool "Clock drivers for UniPhier SoCs"
		depends on ARCH_UNIPHIER || COMPILE_TEST
		depends on OF
		default ARCH_UNIPHIER

That way we can build it even if we're not the arch, and it's
defaulted to be built if we have the arch enabled, but it isn't
defaulted to be built if that arch isn't enabled and compile test
is enabled.

> 
> >
> > If possible please don't use clock-names to set up clock
> > hierarchy.
> 
> So, what shall I do instead?
> 
> I am not comfortable with hard-coding the parents' names
> for clock-cascading.
> 
> Maybe, can we support clk registration
> with clk_hw of parents, not names of parents?
> 
> For example, by adding  "struct clk_hw **parents"
> to struct clk_init_data.
> 

Sounds like it isn't possible to avoid clock-names DT property
then. Not a big deal.

We've been trying to figure out some way to register clks without
requiring strings, but so far nothing has really happened. The
clk_hw approach would work, except for the case where some of the
provider's clks rely on another provider's clks that also rely on
the first provider (sort of a spiral of dependencies). In that
case we want to break the provider level loop by letting clks say
something besides clk_hw pointers are parents.

Strings work well here because we have support for clock-names
and string based parent-child descriptions already, but maybe
we'd be better off having some way to say that this clk we're
registering uses provider X's 24th output as its second parent.
It would be good if we avoided tying it to any DT construct
though, because DT isn't the only way clks are registered and
provided to the system.

This is all because we know that forcing driver authors to come
up with globally unique names for clks just doesn't work when it
comes to things like the same clk controller IP instantiated
twice in the hardware and thus the same driver matches both
device instances.

Patch
diff mbox

diff --git a/MAINTAINERS b/MAINTAINERS
index fc08493..6c10e9b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1644,6 +1644,7 @@  F:	arch/arm/mach-uniphier/
 F:	arch/arm/mm/cache-uniphier.c
 F:	arch/arm64/boot/dts/socionext/
 F:	drivers/bus/uniphier-system-bus.c
+F:	drivers/clk/uniphier/
 F:	drivers/i2c/busses/i2c-uniphier*
 F:	drivers/pinctrl/uniphier/
 F:	drivers/tty/serial/8250/8250_uniphier.c
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index c3e3a02..7580323 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -191,6 +191,7 @@  config COMMON_CLK_CDCE706
 source "drivers/clk/bcm/Kconfig"
 source "drivers/clk/hisilicon/Kconfig"
 source "drivers/clk/qcom/Kconfig"
+source "drivers/clk/uniphier/Kconfig"
 
 endmenu
 
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 820714c..ab9d1bd 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -76,6 +76,7 @@  obj-$(CONFIG_ARCH_STI)			+= st/
 obj-$(CONFIG_ARCH_SUNXI)		+= sunxi/
 obj-$(CONFIG_ARCH_TEGRA)		+= tegra/
 obj-$(CONFIG_ARCH_OMAP2PLUS)		+= ti/
+obj-$(CONFIG_CLK_UNIPHIER)		+= uniphier/
 obj-$(CONFIG_ARCH_U8500)		+= ux500/
 obj-$(CONFIG_COMMON_CLK_VERSATILE)	+= versatile/
 obj-$(CONFIG_X86)			+= x86/
diff --git a/drivers/clk/uniphier/Kconfig b/drivers/clk/uniphier/Kconfig
new file mode 100644
index 0000000..7606f27
--- /dev/null
+++ b/drivers/clk/uniphier/Kconfig
@@ -0,0 +1,35 @@ 
+menuconfig CLK_UNIPHIER
+	bool "Clock drivers for UniPhier SoCs"
+	depends on ARCH_UNIPHIER
+	depends on OF
+	default y
+	help
+	  Supports clock drivers for UniPhier SoCs.
+
+if CLK_UNIPHIER
+
+config CLK_UNIPHIER_PH1_SLD3
+	bool "Clock driver for UniPhier PH1-sLD3 SoC"
+	default y
+
+config CLK_UNIPHIER_PH1_LD4
+	bool "Clock driver for UniPhier PH1-LD4 SoC"
+	default y
+
+config CLK_UNIPHIER_PH1_PRO4
+	bool "Clock driver for UniPhier PH1-Pro4 SoC"
+	default y
+
+config CLK_UNIPHIER_PH1_SLD8
+	bool "Clock driver for UniPhier PH1-sLD8 SoC"
+	default y
+
+config CLK_UNIPHIER_PH1_PRO5
+	bool "Clock driver for UniPhier PH1-Pro5 SoC"
+	default y
+
+config CLK_UNIPHIER_PROXSTREAM2
+	bool "Clock driver for UniPhier ProXstream2/PH1-LD6b SoC"
+	default y
+
+endif
diff --git a/drivers/clk/uniphier/Makefile b/drivers/clk/uniphier/Makefile
new file mode 100644
index 0000000..3be1a17
--- /dev/null
+++ b/drivers/clk/uniphier/Makefile
@@ -0,0 +1,10 @@ 
+obj-y += clk-uniphier-core.o
+obj-y += clk-uniphier-peri.o
+obj-y += clk-uniphier-mio.o
+
+obj-$(CONFIG_CLK_UNIPHIER_PH1_SLD3)	+= clk-ph1-sld3.o
+obj-$(CONFIG_CLK_UNIPHIER_PH1_LD4)	+= clk-ph1-ld4.o
+obj-$(CONFIG_CLK_UNIPHIER_PH1_PRO4)	+= clk-ph1-pro4.o
+obj-$(CONFIG_CLK_UNIPHIER_PH1_SLD8)	+= clk-ph1-sld8.o
+obj-$(CONFIG_CLK_UNIPHIER_PH1_PRO5)	+= clk-ph1-pro5.o
+obj-$(CONFIG_CLK_UNIPHIER_PROXSTREAM2)	+= clk-proxstream2.o
diff --git a/drivers/clk/uniphier/clk-ph1-ld4.c b/drivers/clk/uniphier/clk-ph1-ld4.c
new file mode 100644
index 0000000..48d342f
--- /dev/null
+++ b/drivers/clk/uniphier/clk-ph1-ld4.c
@@ -0,0 +1,117 @@ 
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * 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.
+ */
+
+#include <linux/clk-provider.h>
+
+#include "clk-uniphier.h"
+
+static struct uniphier_clk_init_data ph1_ld4_clk_idata[] __initdata = {
+	{
+		.name = "spll",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = -1,
+		.data.factor = {
+			.parent_name = UNIPHIER_CLK_EXT "ref",
+			.mult = 65,
+			.div = 1,
+		},
+	},
+	{
+		.name = "upll",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = -1,
+		.data.factor = {
+			.parent_name = UNIPHIER_CLK_EXT "ref",
+			.mult = 288000,
+			.div = 24576,
+		},
+	},
+	{
+		.name = "a2pll",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = -1,
+		.data.factor = {
+			.parent_name = UNIPHIER_CLK_EXT "ref",
+			.mult = 24,
+			.div = 1,
+		},
+	},
+	{
+		.name = "uart",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = 3,
+		.data.factor = {
+			.parent_name = "a2pll",
+			.mult = 1,
+			.div = 16,
+		},
+	},
+	{
+		.name = "i2c",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = 4,
+		.data.factor = {
+			.parent_name = "spll",
+			.mult = 1,
+			.div = 16,
+		},
+	},
+	{
+		.name = "arm-scu",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = 7,
+		.data.factor = {
+			.parent_name = "spll",
+			.mult = 1,
+			.div = 32,
+		},
+	},
+	{
+		.name = "stdmac-clken",
+		.type = UNIPHIER_CLK_TYPE_GATE,
+		.output_index = -1,
+		.data.gate = {
+			.parent_name = NULL,
+			.reg = 0x2104,
+			.bit_idx = 10,
+		},
+	},
+	{
+		.name = "stdmac",
+		.type = UNIPHIER_CLK_TYPE_GATE,
+		.output_index = 10,
+		.data.gate = {
+			.parent_name = "stdmac-clken",
+			.reg = 0x2000,
+			.bit_idx = 10,
+		},
+	},
+	{
+		.name = "ehci",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = 18,
+		.data.factor = {
+			.parent_name = "upll",
+			.mult = 1,
+			.div = 12,
+		},
+	},
+	{ /* sentinel */ }
+};
+
+static void __init ph1_ld4_clk_init(struct device_node *np)
+{
+	uniphier_clk_init(np, ph1_ld4_clk_idata);
+}
+CLK_OF_DECLARE(ph1_ld4_clk, "socionext,ph1-ld4-sysctrl", ph1_ld4_clk_init);
diff --git a/drivers/clk/uniphier/clk-ph1-pro4.c b/drivers/clk/uniphier/clk-ph1-pro4.c
new file mode 100644
index 0000000..052813a
--- /dev/null
+++ b/drivers/clk/uniphier/clk-ph1-pro4.c
@@ -0,0 +1,117 @@ 
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * 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.
+ */
+
+#include <linux/clk-provider.h>
+
+#include "clk-uniphier.h"
+
+static struct uniphier_clk_init_data ph1_pro4_clk_idata[] __initdata = {
+	{
+		.name = "spll",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = -1,
+		.data.factor = {
+			.parent_name = UNIPHIER_CLK_EXT "ref",
+			.mult = 64,
+			.div = 1,
+		},
+	},
+	{
+		.name = "upll",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = -1,
+		.data.factor = {
+			.parent_name = UNIPHIER_CLK_EXT "ref",
+			.mult = 288,
+			.div = 25,
+		},
+	},
+	{
+		.name = "a2pll",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = -1,
+		.data.factor = {
+			.parent_name = "upll",
+			.mult = 256,
+			.div = 125,
+		},
+	},
+	{
+		.name = "uart",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = 3,
+		.data.factor = {
+			.parent_name = "a2pll",
+			.mult = 1,
+			.div = 8,
+		},
+	},
+	{
+		.name = "fi2c",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = 4,
+		.data.factor = {
+			.parent_name = "spll",
+			.mult = 1,
+			.div = 32,
+		},
+	},
+	{
+		.name = "arm-scu",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = 7,
+		.data.factor = {
+			.parent_name = "spll",
+			.mult = 1,
+			.div = 32,
+		},
+	},
+	{
+		.name = "stdmac-clken",
+		.type = UNIPHIER_CLK_TYPE_GATE,
+		.output_index = -1,
+		.data.gate = {
+			.parent_name = UNIPHIER_CLK_EXT "ref",
+			.reg = 0x2104,
+			.bit_idx = 10,
+		},
+	},
+	{
+		.name = "stdmac",
+		.type = UNIPHIER_CLK_TYPE_GATE,
+		.output_index = 10,
+		.data.gate = {
+			.parent_name = "stdmac-clken",
+			.reg = 0x2000,
+			.bit_idx = 10,
+		},
+	},
+	{
+		.name = "ehci",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = 18,
+		.data.factor = {
+			.parent_name = "upll",
+			.mult = 1,
+			.div = 12,
+		},
+	},
+	{ /* sentinel */ }
+};
+
+static void __init ph1_pro4_clk_init(struct device_node *np)
+{
+	uniphier_clk_init(np, ph1_pro4_clk_idata);
+}
+CLK_OF_DECLARE(ph1_pro4_clk, "socionext,ph1-pro4-sysctrl", ph1_pro4_clk_init);
diff --git a/drivers/clk/uniphier/clk-ph1-pro5.c b/drivers/clk/uniphier/clk-ph1-pro5.c
new file mode 100644
index 0000000..9f782d9
--- /dev/null
+++ b/drivers/clk/uniphier/clk-ph1-pro5.c
@@ -0,0 +1,107 @@ 
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * 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.
+ */
+
+#include <linux/clk-provider.h>
+
+#include "clk-uniphier.h"
+
+static struct uniphier_clk_init_data ph1_pro5_clk_idata[] __initdata = {
+	{
+		.name = "spll",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = -1,
+		.data.factor = {
+			.parent_name = UNIPHIER_CLK_EXT "ref",
+			.mult = 120,
+			.div = 1,
+		},
+	},
+	{
+		.name = "dapll1",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = -1,
+		.data.factor = {
+			.parent_name = UNIPHIER_CLK_EXT "ref",
+			.mult = 128,
+			.div = 125,
+		},
+	},
+	{
+		.name = "dapll2",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = -1,
+		.data.factor = {
+			.parent_name = "upll",
+			.mult = 144,
+			.div = 5,
+		},
+	},
+	{
+		.name = "uart",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = 3,
+		.data.factor = {
+			.parent_name = "dapll2",
+			.mult = 1,
+			.div = 8,
+		},
+	},
+	{
+		.name = "fi2c",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = 4,
+		.data.factor = {
+			.parent_name = "spll",
+			.mult = 1,
+			.div = 48,
+		},
+	},
+	{
+		.name = "arm-scu",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = 7,
+		.data.factor = {
+			.parent_name = "spll",
+			.mult = 1,
+			.div = 48,
+		},
+	},
+	{
+		.name = "stdmac-clken",
+		.type = UNIPHIER_CLK_TYPE_GATE,
+		.output_index = -1,
+		.data.gate = {
+			.parent_name = NULL,
+			.reg = 0x2104,
+			.bit_idx = 10,
+		},
+	},
+	{
+		.name = "stdmac",
+		.type = UNIPHIER_CLK_TYPE_GATE,
+		.output_index = 10,
+		.data.gate = {
+			.parent_name = "stdmac-clken",
+			.reg = 0x2000,
+			.bit_idx = 10,
+		},
+	},
+	{ /* sentinel */ }
+};
+
+static void __init ph1_pro5_clk_init(struct device_node *np)
+{
+	uniphier_clk_init(np, ph1_pro5_clk_idata);
+}
+CLK_OF_DECLARE(ph1_pro5_clk, "socionext,ph1-pro5-sysctrl", ph1_pro5_clk_init);
diff --git a/drivers/clk/uniphier/clk-ph1-sld3.c b/drivers/clk/uniphier/clk-ph1-sld3.c
new file mode 100644
index 0000000..7249a81
--- /dev/null
+++ b/drivers/clk/uniphier/clk-ph1-sld3.c
@@ -0,0 +1,117 @@ 
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * 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.
+ */
+
+#include <linux/clk-provider.h>
+
+#include "clk-uniphier.h"
+
+static struct uniphier_clk_init_data ph1_sld3_clk_idata[] __initdata = {
+	{
+		.name = "spll",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = -1,
+		.data.factor = {
+			.parent_name = UNIPHIER_CLK_EXT "ref",
+			.mult = 65,
+			.div = 1,
+		},
+	},
+	{
+		.name = "upll",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = -1,
+		.data.factor = {
+			.parent_name = UNIPHIER_CLK_EXT "ref",
+			.mult = 288000,
+			.div = 24576,
+		},
+	},
+	{
+		.name = "a2pll",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = -1,
+		.data.factor = {
+			.parent_name = UNIPHIER_CLK_EXT "ref",
+			.mult = 24,
+			.div = 1,
+		},
+	},
+	{
+		.name = "uart",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = 3,
+		.data.factor = {
+			.parent_name = "a2pll",
+			.mult = 1,
+			.div = 16,
+		},
+	},
+	{
+		.name = "i2c",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = 4,
+		.data.factor = {
+			.parent_name = "spll",
+			.mult = 1,
+			.div = 16,
+		},
+	},
+	{
+		.name = "arm-scu",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = 7,
+		.data.factor = {
+			.parent_name = "spll",
+			.mult = 1,
+			.div = 32,
+		},
+	},
+	{
+		.name = "stdmac-clken",
+		.type = UNIPHIER_CLK_TYPE_GATE,
+		.output_index = -1,
+		.data.gate = {
+			.parent_name = UNIPHIER_CLK_EXT "ref",
+			.reg = 0x2104,
+			.bit_idx = 10,
+		},
+	},
+	{
+		.name = "stdmac",
+		.type = UNIPHIER_CLK_TYPE_GATE,
+		.output_index = 10,
+		.data.gate = {
+			.parent_name = "stdmac-clken",
+			.reg = 0x2000,
+			.bit_idx = 10,
+		},
+	},
+	{
+		.name = "ehci",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = 18,
+		.data.factor = {
+			.parent_name = "upll",
+			.mult = 1,
+			.div = 12,
+		},
+	},
+	{ /* sentinel */ }
+};
+
+static void __init ph1_sld3_clk_init(struct device_node *np)
+{
+	uniphier_clk_init(np, ph1_sld3_clk_idata);
+}
+CLK_OF_DECLARE(ph1_sld3_clk, "socionext,ph1-sld3-sysctrl", ph1_sld3_clk_init);
diff --git a/drivers/clk/uniphier/clk-ph1-sld8.c b/drivers/clk/uniphier/clk-ph1-sld8.c
new file mode 100644
index 0000000..bfebd38
--- /dev/null
+++ b/drivers/clk/uniphier/clk-ph1-sld8.c
@@ -0,0 +1,107 @@ 
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * 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.
+ */
+
+#include <linux/clk-provider.h>
+
+#include "clk-uniphier.h"
+
+static struct uniphier_clk_init_data ph1_sld8_clk_idata[] __initdata = {
+	{
+		.name = "spll",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = -1,
+		.data.factor = {
+			.parent_name = UNIPHIER_CLK_EXT "ref",
+			.mult = 64,
+			.div = 1,
+		},
+	},
+	{
+		.name = "upll",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = -1,
+		.data.factor = {
+			.parent_name = UNIPHIER_CLK_EXT "ref",
+			.mult = 288,
+			.div = 25,
+		},
+	},
+	{
+		.name = "uart",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = 3,
+		.data.factor = {
+			.parent_name = "spll",
+			.mult = 1,
+			.div = 20,
+		},
+	},
+	{
+		.name = "i2c",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = 4,
+		.data.factor = {
+			.parent_name = "spll",
+			.mult = 1,
+			.div = 16,
+		},
+	},
+	{
+		.name = "arm-scu",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = 7,
+		.data.factor = {
+			.parent_name = "spll",
+			.mult = 1,
+			.div = 32,
+		},
+	},
+	{
+		.name = "stdmac-clken",
+		.type = UNIPHIER_CLK_TYPE_GATE,
+		.output_index = -1,
+		.data.gate = {
+			.parent_name = NULL,
+			.reg = 0x2104,
+			.bit_idx = 10,
+		},
+	},
+	{
+		.name = "stdmac",
+		.type = UNIPHIER_CLK_TYPE_GATE,
+		.output_index = 10,
+		.data.gate = {
+			.parent_name = "stdmac-clken",
+			.reg = 0x2000,
+			.bit_idx = 10,
+		},
+	},
+	{
+		.name = "ehci",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = 18,
+		.data.factor = {
+			.parent_name = "upll",
+			.mult = 1,
+			.div = 12,
+		},
+	},
+	{ /* sentinel */ }
+};
+
+static void __init ph1_sld8_clk_init(struct device_node *np)
+{
+	uniphier_clk_init(np, ph1_sld8_clk_idata);
+}
+CLK_OF_DECLARE(ph1_sld8_clk, "socionext,ph1-sld8-sysctrl", ph1_sld8_clk_init);
diff --git a/drivers/clk/uniphier/clk-proxstream2.c b/drivers/clk/uniphier/clk-proxstream2.c
new file mode 100644
index 0000000..b3ffedc
--- /dev/null
+++ b/drivers/clk/uniphier/clk-proxstream2.c
@@ -0,0 +1,88 @@ 
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * 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.
+ */
+
+#include <linux/clk-provider.h>
+
+#include "clk-uniphier.h"
+
+static struct uniphier_clk_init_data proxstream2_clk_idata[] __initdata = {
+	{
+		.name = "spll",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = -1,
+		.data.factor = {
+			.parent_name = UNIPHIER_CLK_EXT "ref",
+			.mult = 96,
+			.div = 1,
+		},
+	},
+	{
+		.name = "uart",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = 3,
+		.data.factor = {
+			.parent_name = "spll",
+			.mult = 1,
+			.div = 27,
+		},
+	},
+	{
+		.name = "fi2c",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = 4,
+		.data.factor = {
+			.parent_name = "spll",
+			.mult = 1,
+			.div = 48,
+		},
+	},
+	{
+		.name = "arm-scu",
+		.type = UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+		.output_index = 7,
+		.data.factor = {
+			.parent_name = "spll",
+			.mult = 1,
+			.div = 48,
+		},
+	},
+	{
+		.name = "stdmac-clken",
+		.type = UNIPHIER_CLK_TYPE_GATE,
+		.output_index = -1,
+		.data.gate = {
+			.parent_name = NULL,
+			.reg = 0x2104,
+			.bit_idx = 10,
+		},
+	},
+	{
+		.name = "stdmac",
+		.type = UNIPHIER_CLK_TYPE_GATE,
+		.output_index = 10,
+		.data.gate = {
+			.parent_name = "stdmac-clken",
+			.reg = 0x2000,
+			.bit_idx = 10,
+		},
+	},
+	{ /* sentinel */ }
+};
+
+static void __init proxstream2_clk_init(struct device_node *np)
+{
+	uniphier_clk_init(np, proxstream2_clk_idata);
+}
+CLK_OF_DECLARE(proxstream2_clk, "socionext,proxstream2-sysctrl",
+	       proxstream2_clk_init);
diff --git a/drivers/clk/uniphier/clk-uniphier-core.c b/drivers/clk/uniphier/clk-uniphier-core.c
new file mode 100644
index 0000000..8680101
--- /dev/null
+++ b/drivers/clk/uniphier/clk-uniphier-core.c
@@ -0,0 +1,151 @@ 
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt)		"uniphier-clk: " fmt
+
+#include <linux/clk-provider.h>
+#include <linux/log2.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+
+#include "clk-uniphier.h"
+
+static void __init uniphier_clk_update_parent_name(struct device_node *np,
+						   const char **parent_name)
+{
+	const char *new_name;
+	int index;
+
+	if (!parent_name || !*parent_name)
+		return;
+
+	if (strncmp(*parent_name, UNIPHIER_CLK_EXT, strlen(UNIPHIER_CLK_EXT)))
+		return;
+
+	index = of_property_match_string(np, "clock-names",
+				*parent_name + strlen(UNIPHIER_CLK_EXT));
+	new_name = of_clk_get_parent_name(np, index);
+	if (new_name)
+		*parent_name = new_name;
+}
+
+static struct clk * __init uniphier_clk_register(struct device_node *np,
+						 void __iomem *regbase,
+					  struct uniphier_clk_init_data *idata)
+{
+	int i;
+
+	switch (idata->type) {
+	case UNIPHIER_CLK_TYPE_FIXED_FACTOR:
+		uniphier_clk_update_parent_name(np,
+					&idata->data.factor.parent_name);
+		return clk_register_fixed_factor(NULL, idata->name,
+						 idata->data.factor.parent_name,
+						 CLK_SET_RATE_PARENT,
+						 idata->data.factor.mult,
+						 idata->data.factor.div);
+	case UNIPHIER_CLK_TYPE_FIXED_RATE:
+		return clk_register_fixed_rate(NULL, idata->name, NULL,
+					       CLK_IS_ROOT,
+					       idata->data.rate.fixed_rate);
+	case UNIPHIER_CLK_TYPE_GATE:
+		uniphier_clk_update_parent_name(np,
+						&idata->data.gate.parent_name);
+		return clk_register_gate(NULL, idata->name,
+					 idata->data.gate.parent_name,
+					 idata->data.gate.parent_name ?
+					 CLK_SET_RATE_PARENT : CLK_IS_ROOT,
+					 regbase + idata->data.gate.reg,
+					 idata->data.gate.bit_idx, 0, NULL);
+	case UNIPHIER_CLK_TYPE_MUX:
+		for (i = 0; i < idata->data.mux.num_parents; i++)
+			uniphier_clk_update_parent_name(np,
+					&idata->data.mux.parent_names[i]);
+		return clk_register_mux(NULL, idata->name,
+					idata->data.mux.parent_names,
+					idata->data.mux.num_parents,
+					CLK_SET_RATE_PARENT,
+					regbase + idata->data.mux.reg,
+					idata->data.mux.shift,
+					ilog2(idata->data.mux.num_parents),
+					0, NULL);
+	default:
+		WARN(1, "unsupported clock type\n");
+		return ERR_PTR(-EINVAL);
+	}
+}
+
+int __init uniphier_clk_init(struct device_node *np,
+			     struct uniphier_clk_init_data *idata)
+{
+	struct clk_onecell_data *clk_data;
+	struct uniphier_clk_init_data *p;
+	void __iomem *regbase;
+	int max_index = 0;
+	int ret;
+
+	regbase = of_iomap(np, 0);
+	if (!regbase)
+		return -ENOMEM;
+
+	for (p = idata; p->name; p++)
+		max_index = max(max_index, p->output_index);
+
+	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
+	if (!clk_data)
+		return -ENOMEM;
+
+	clk_data->clk_num = max_index + 1;
+	clk_data->clks = kcalloc(clk_data->clk_num, sizeof(struct clk *),
+				 GFP_KERNEL);
+	if (!clk_data->clks) {
+		ret = -ENOMEM;
+		goto free_clk_data;
+	}
+
+	for (p = idata; p->name; p++) {
+		pr_debug("register %s (%s[%d])\n", p->name, np->name,
+			 p->output_index);
+		p->clk = uniphier_clk_register(np, regbase, p);
+		if (IS_ERR(p->clk)) {
+			pr_err("failed to register %s\n", p->name);
+			ret = PTR_ERR(p->clk);
+			goto unregister;
+		}
+
+		if (p->output_index >= 0)
+			clk_data->clks[p->output_index] = p->clk;
+	}
+
+	ret = of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
+	if (ret)
+		goto unregister;
+
+	return ret;
+unregister:
+	for (p--; p >= idata; p--) {
+		pr_debug("unregister %s (%s[%d])\n", p->name, np->name,
+			 p->output_index);
+		clk_unregister(p->clk);
+		p->clk = NULL;
+	}
+	kfree(clk_data->clks);
+free_clk_data:
+	kfree(clk_data);
+
+	pr_err("%s: init failed with error %d\n", np->full_name, ret);
+
+	return ret;
+}
diff --git a/drivers/clk/uniphier/clk-uniphier-mio.c b/drivers/clk/uniphier/clk-uniphier-mio.c
new file mode 100644
index 0000000..ad6491b
--- /dev/null
+++ b/drivers/clk/uniphier/clk-uniphier-mio.c
@@ -0,0 +1,315 @@ 
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * 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.
+ */
+
+#include <linux/clk-provider.h>
+
+#include "clk-uniphier.h"
+
+#define UNIPHIER_MIO_CLK_SD_FIXED					\
+	{								\
+		.name = "sd-44m",					\
+		.type = UNIPHIER_CLK_TYPE_FIXED_RATE,			\
+		.output_index = -1,					\
+		.data.rate = {						\
+			.fixed_rate = 44444444,				\
+		},							\
+	},								\
+	{								\
+		.name = "sd-33m",					\
+		.type = UNIPHIER_CLK_TYPE_FIXED_RATE,			\
+		.output_index = -1,					\
+		.data.rate = {						\
+			.fixed_rate = 33333333,				\
+		},							\
+	},								\
+	{								\
+		.name = "sd-50m",					\
+		.type = UNIPHIER_CLK_TYPE_FIXED_RATE,			\
+		.output_index = -1,					\
+		.data.rate = {						\
+			.fixed_rate = 50000000,				\
+		},							\
+	},								\
+	{								\
+		.name = "sd-67m",					\
+		.type = UNIPHIER_CLK_TYPE_FIXED_RATE,			\
+		.output_index = -1,					\
+		.data.rate = {						\
+			.fixed_rate = 66666666,				\
+		},							\
+	},								\
+	{								\
+		.name = "sd-100m",					\
+		.type = UNIPHIER_CLK_TYPE_FIXED_RATE,			\
+		.output_index = -1,					\
+		.data.rate = {						\
+			.fixed_rate = 100000000,			\
+		},							\
+	},								\
+	{								\
+		.name = "sd-40m",					\
+		.type = UNIPHIER_CLK_TYPE_FIXED_RATE,			\
+		.output_index = -1,					\
+		.data.rate = {						\
+			.fixed_rate = 40000000,				\
+		},							\
+	},								\
+	{								\
+		.name = "sd-25m",					\
+		.type = UNIPHIER_CLK_TYPE_FIXED_RATE,			\
+		.output_index = -1,					\
+		.data.rate = {						\
+			.fixed_rate = 25000000,				\
+		},							\
+	},								\
+	{								\
+		.name = "sd-22m",					\
+		.type = UNIPHIER_CLK_TYPE_FIXED_RATE,			\
+		.output_index = -1,					\
+		.data.rate = {						\
+			.fixed_rate = 22222222,				\
+		},							\
+	}
+
+
+#define UNIPHIER_MIO_CLK_SD(ch, index)					\
+	{								\
+		.name = "sd" #ch "-clksel0",				\
+		.type = UNIPHIER_CLK_TYPE_MUX,				\
+		.output_index = -1,					\
+		.data.mux = {						\
+			.parent_names = {				\
+				"sd-44m",				\
+				"sd-33m",				\
+				"sd-50m",				\
+				"sd-67m",				\
+			},						\
+			.num_parents = 4,				\
+			.reg = 0x30 + 0x200 * ch,			\
+			.shift = 16,					\
+		},							\
+	},								\
+	{								\
+		.name = "sd" #ch "-clksel1",				\
+		.type = UNIPHIER_CLK_TYPE_MUX,				\
+		.output_index = -1,					\
+		.data.mux = {						\
+			.parent_names = {				\
+				"sd-100m",				\
+				"sd-40m",				\
+				"sd-25m",				\
+				"sd-22m",				\
+			},						\
+			.num_parents = 4,				\
+			.reg = 0x30 + 0x200 * ch,			\
+			.shift = 8,					\
+		},							\
+	},								\
+	{								\
+		.name = "sd" #ch "-clkmode",				\
+		.type = UNIPHIER_CLK_TYPE_MUX,				\
+		.output_index = -1,					\
+		.data.mux = {						\
+			.parent_names = {				\
+				"sd" #ch "-clksel0",			\
+				"sd" #ch "-clksel1",			\
+			},						\
+			.num_parents = 2,				\
+			.reg = 0x30 + 0x200 * ch,			\
+			.shift = 12,					\
+		},							\
+	},								\
+	{								\
+		.name = "sd" #ch "-clken",				\
+		.type = UNIPHIER_CLK_TYPE_GATE,				\
+		.output_index = -1,					\
+		.data.gate = {						\
+			.parent_name = "sd" #ch "-clkmode",		\
+			.reg = 0x20 + 0x200 * ch,			\
+			.bit_idx = 8,					\
+		},							\
+	},								\
+	{								\
+		.name = "sd" #ch "-bridge-reset",			\
+		.type = UNIPHIER_CLK_TYPE_GATE,				\
+		.output_index = -1,					\
+		.data.gate = {						\
+			.parent_name = "sd" #ch "-clken",		\
+			.reg = 0x110 + 0x200 * ch,			\
+			.bit_idx = 26,					\
+		},							\
+	},								\
+	{								\
+		.name = "sd" #ch,					\
+		.type = UNIPHIER_CLK_TYPE_GATE,				\
+		.output_index = (index),				\
+		.data.gate = {						\
+			.parent_name = "sd" #ch "-bridge-reset",	\
+			.reg = 0x110 + 0x200 * ch,			\
+			.bit_idx = 0,					\
+		},							\
+	}
+
+#define UNIPHIER_MIO_CLK_SD_HW_RESET(ch, index)				\
+	{								\
+		.name = "sd" #ch "-hw-reset",				\
+		.type = UNIPHIER_CLK_TYPE_GATE,				\
+		.output_index = (index),				\
+		.data.gate = {						\
+			.parent_name = NULL,				\
+			.reg = 0x80 + 0x200 * ch,			\
+			.bit_idx = 0,					\
+		},							\
+	}
+
+#define UNIPHIER_MIO_CLK_EHCI(ch, index)				\
+	{								\
+		.name = "ehci" #ch "-phy-clken",			\
+		.type = UNIPHIER_CLK_TYPE_GATE,				\
+		.output_index = -1,					\
+		.data.gate = {						\
+			.parent_name = UNIPHIER_CLK_EXT "ehci",		\
+			.reg = 0x20 + 0x200 * ch,			\
+			.bit_idx = 29,					\
+		},							\
+	},								\
+	{								\
+		.name = "ehci" #ch "-link-clken",			\
+		.type = UNIPHIER_CLK_TYPE_GATE,				\
+		.output_index = -1,					\
+		.data.gate = {						\
+			.parent_name = "ehci" #ch "-phy-clken",		\
+			.reg = 0x20 + 0x200 * ch,			\
+			.bit_idx = 28,					\
+		},							\
+	},								\
+	{								\
+		.name = "ehci" #ch "-bridge-reset",			\
+		.type = UNIPHIER_CLK_TYPE_GATE,				\
+		.output_index = -1,					\
+		.data.gate = {						\
+			.parent_name = "ehci" #ch "-link-clken",	\
+			.reg = 0x110 + 0x200 * ch,			\
+			.bit_idx = 24,					\
+		},							\
+	},								\
+	{								\
+		.name = "ehci" #ch,					\
+		.type = UNIPHIER_CLK_TYPE_GATE,				\
+		.output_index = (index),				\
+		.data.gate = {						\
+			.parent_name = "ehci" #ch "-bridge-reset",	\
+			.reg = 0x114 + 0x200 * ch,			\
+			.bit_idx = 0,					\
+		},							\
+	}
+
+#define UNIPHIER_MIO_CLK_DMAC(index)					\
+	{								\
+		.name = "miodmac-clken",				\
+		.type = UNIPHIER_CLK_TYPE_GATE,				\
+		.output_index = -1,					\
+		.data.gate = {						\
+			.parent_name = UNIPHIER_CLK_EXT "stdmac",	\
+			.reg = 0x20,					\
+			.bit_idx = 25,					\
+		},							\
+	},								\
+	{								\
+		.name = "miodmac",					\
+		.type = UNIPHIER_CLK_TYPE_GATE,				\
+		.output_index = (index),				\
+		.data.gate = {						\
+			.parent_name = "miodmac-clken",			\
+			.reg = 0x110,					\
+			.bit_idx = 17,					\
+		},							\
+	}
+
+static struct uniphier_clk_init_data ph1_sld3_mio_clk_idata[] __initdata = {
+	UNIPHIER_MIO_CLK_SD_FIXED,
+	UNIPHIER_MIO_CLK_SD(0, 0),
+	UNIPHIER_MIO_CLK_SD(1, 1),
+	UNIPHIER_MIO_CLK_SD_HW_RESET(0, 3),
+	UNIPHIER_MIO_CLK_EHCI(0, 4),
+	UNIPHIER_MIO_CLK_EHCI(1, 5),
+	UNIPHIER_MIO_CLK_EHCI(2, 6),
+	UNIPHIER_MIO_CLK_EHCI(3, 7),
+	UNIPHIER_MIO_CLK_DMAC(8),
+	{ /* sentinel */ }
+};
+
+static struct uniphier_clk_init_data ph1_ld4_mio_clk_idata[] __initdata = {
+	UNIPHIER_MIO_CLK_SD_FIXED,
+	UNIPHIER_MIO_CLK_SD(0, 0),
+	UNIPHIER_MIO_CLK_SD(1, 1),
+	UNIPHIER_MIO_CLK_SD_HW_RESET(1, 3),
+	UNIPHIER_MIO_CLK_EHCI(0, 4),
+	UNIPHIER_MIO_CLK_EHCI(1, 5),
+	UNIPHIER_MIO_CLK_EHCI(2, 6),
+	UNIPHIER_MIO_CLK_DMAC(8),
+	{ /* sentinel */ }
+};
+
+static struct uniphier_clk_init_data ph1_pro4_mio_clk_idata[] __initdata = {
+	UNIPHIER_MIO_CLK_SD_FIXED,
+	UNIPHIER_MIO_CLK_SD(0, 0),
+	UNIPHIER_MIO_CLK_SD(1, 1),
+	UNIPHIER_MIO_CLK_SD(2, 2),
+	UNIPHIER_MIO_CLK_SD_HW_RESET(1, 3),
+	UNIPHIER_MIO_CLK_EHCI(0, 4),
+	UNIPHIER_MIO_CLK_EHCI(1, 5),
+	UNIPHIER_MIO_CLK_DMAC(8),
+	{ /* sentinel */ }
+};
+
+static struct uniphier_clk_init_data ph1_pro5_mio_clk_idata[] __initdata = {
+	UNIPHIER_MIO_CLK_SD_FIXED,
+	UNIPHIER_MIO_CLK_SD(0, 0),
+	UNIPHIER_MIO_CLK_SD(1, 1),
+	UNIPHIER_MIO_CLK_SD_HW_RESET(1, 3),
+	{ /* sentinel */ }
+};
+
+static void __init ph1_sld3_mio_clk_init(struct device_node *np)
+{
+	uniphier_clk_init(np, ph1_sld3_mio_clk_idata);
+}
+CLK_OF_DECLARE(ph1_sld3_mio_clk, "socionext,ph1-sld3-mioctrl",
+	       ph1_sld3_mio_clk_init);
+
+static void __init ph1_ld4_mio_clk_init(struct device_node *np)
+{
+	uniphier_clk_init(np, ph1_ld4_mio_clk_idata);
+}
+CLK_OF_DECLARE(ph1_ld4_mio_clk, "socionext,ph1-ld4-mioctrl",
+	       ph1_ld4_mio_clk_init);
+CLK_OF_DECLARE(ph1_sld8_mio_clk, "socionext,ph1-sld8-mioctrl",
+	       ph1_ld4_mio_clk_init);
+
+static void __init ph1_pro4_mio_clk_init(struct device_node *np)
+{
+	uniphier_clk_init(np, ph1_pro4_mio_clk_idata);
+}
+CLK_OF_DECLARE(ph1_pro4_mio_clk, "socionext,ph1-pro4-mioctrl",
+	       ph1_pro4_mio_clk_init);
+
+static void __init ph1_pro5_mio_clk_init(struct device_node *np)
+{
+	uniphier_clk_init(np, ph1_pro5_mio_clk_idata);
+}
+CLK_OF_DECLARE(ph1_pro5_mio_clk, "socionext,ph1-pro5-mioctrl",
+	       ph1_pro5_mio_clk_init);
+CLK_OF_DECLARE(proxstream2_mio_clk, "socionext,proxstream2-mioctrl",
+	       ph1_pro5_mio_clk_init);
diff --git a/drivers/clk/uniphier/clk-uniphier-peri.c b/drivers/clk/uniphier/clk-uniphier-peri.c
new file mode 100644
index 0000000..adaae8e
--- /dev/null
+++ b/drivers/clk/uniphier/clk-uniphier-peri.c
@@ -0,0 +1,175 @@ 
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * 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.
+ */
+
+#include <linux/clk-provider.h>
+
+#include "clk-uniphier.h"
+
+#define UNIPHIER_PERI_CLK_UART(ch, index)			\
+	{							\
+		.name = "uart" #ch "-clken",			\
+		.type = UNIPHIER_CLK_TYPE_GATE,			\
+		.output_index = -1,				\
+		.data.gate = {					\
+			.parent_name = UNIPHIER_CLK_EXT "uart",	\
+			.reg = 0x24,				\
+			.bit_idx = 19 + ch,			\
+		},						\
+	},							\
+	{							\
+		.name = "uart" #ch,				\
+		.type = UNIPHIER_CLK_TYPE_GATE,			\
+		.output_index = (index),			\
+		.data.gate = {					\
+			.parent_name = "uart" #ch "-clken",	\
+			.reg = 0x114,				\
+			.bit_idx = 19 + ch,			\
+		},						\
+	}
+
+#define UNIPHIER_PERI_CLK_I2C_COMMON				\
+	{							\
+		.name = "i2c-clken",				\
+		.type = UNIPHIER_CLK_TYPE_GATE,			\
+		.output_index = -1,				\
+		.data.gate = {					\
+			.parent_name = UNIPHIER_CLK_EXT "i2c",	\
+			.reg = 0x20,				\
+			.bit_idx = 1,				\
+		},						\
+	},							\
+	{							\
+		.name = "i2c-reset",				\
+		.type = UNIPHIER_CLK_TYPE_GATE,			\
+		.output_index = -1,				\
+		.data.gate = {					\
+			.parent_name = "i2c-clken",		\
+			.reg = 0x110,				\
+			.bit_idx = 1,				\
+		},						\
+	}
+
+
+#define UNIPHIER_PERI_CLK_I2C(ch, index)			\
+	{							\
+		.name = "i2c" #ch "-clken",			\
+		.type = UNIPHIER_CLK_TYPE_GATE,			\
+		.output_index = -1,				\
+		.data.gate = {					\
+			.parent_name = "i2c-reset",		\
+			.reg = 0x24,				\
+			.bit_idx = 5 + ch,			\
+		},						\
+	},							\
+	{							\
+		.name = "i2c" #ch,				\
+		.type = UNIPHIER_CLK_TYPE_GATE,			\
+		.output_index = (index),			\
+		.data.gate = {					\
+			.parent_name = "i2c" #ch "-clken",	\
+			.reg = 0x114,				\
+			.bit_idx = 5 + ch,			\
+		},						\
+	}
+
+#define UNIPHIER_PERI_CLK_FI2C(ch, index)			\
+	{							\
+		.name = "fi2c" #ch "-clken",			\
+		.type = UNIPHIER_CLK_TYPE_GATE,			\
+		.output_index = -1,				\
+		.data.gate = {					\
+			.parent_name = UNIPHIER_CLK_EXT "fi2c",	\
+			.reg = 0x24,				\
+			.bit_idx = 24 + ch,			\
+		},						\
+	},							\
+	{							\
+		.name = "fi2c" #ch,				\
+		.type = UNIPHIER_CLK_TYPE_GATE,			\
+		.output_index = index,				\
+		.data.gate = {					\
+			.parent_name = "fi2c" #ch "-clken",	\
+			.reg = 0x114,				\
+			.bit_idx = 24 + ch,			\
+		},						\
+	}
+
+static struct uniphier_clk_init_data ph1_ld4_peri_clk_idata[] __initdata = {
+	UNIPHIER_PERI_CLK_UART(0, 0),
+	UNIPHIER_PERI_CLK_UART(1, 1),
+	UNIPHIER_PERI_CLK_UART(2, 2),
+	UNIPHIER_PERI_CLK_UART(3, 3),
+	UNIPHIER_PERI_CLK_I2C_COMMON,
+	UNIPHIER_PERI_CLK_I2C(0, 4),
+	UNIPHIER_PERI_CLK_I2C(1, 5),
+	UNIPHIER_PERI_CLK_I2C(2, 6),
+	UNIPHIER_PERI_CLK_I2C(3, 7),
+	UNIPHIER_PERI_CLK_I2C(4, 8),
+	{ /* sentinel */ }
+};
+
+static struct uniphier_clk_init_data ph1_pro4_peri_clk_idata[] __initdata = {
+	UNIPHIER_PERI_CLK_UART(0, 0),
+	UNIPHIER_PERI_CLK_UART(1, 1),
+	UNIPHIER_PERI_CLK_UART(2, 2),
+	UNIPHIER_PERI_CLK_UART(3, 3),
+	UNIPHIER_PERI_CLK_FI2C(0, 4),
+	UNIPHIER_PERI_CLK_FI2C(1, 5),
+	UNIPHIER_PERI_CLK_FI2C(2, 6),
+	UNIPHIER_PERI_CLK_FI2C(3, 7),
+	/* no I2C ch4 */
+	UNIPHIER_PERI_CLK_FI2C(5, 9),
+	UNIPHIER_PERI_CLK_FI2C(6, 10),
+	{ /* sentinel */ }
+};
+
+static struct uniphier_clk_init_data ph1_pro5_peri_clk_idata[] __initdata = {
+	UNIPHIER_PERI_CLK_UART(0, 0),
+	UNIPHIER_PERI_CLK_UART(1, 1),
+	UNIPHIER_PERI_CLK_UART(2, 2),
+	UNIPHIER_PERI_CLK_UART(3, 3),
+	UNIPHIER_PERI_CLK_FI2C(0, 4),
+	UNIPHIER_PERI_CLK_FI2C(1, 5),
+	UNIPHIER_PERI_CLK_FI2C(2, 6),
+	UNIPHIER_PERI_CLK_FI2C(3, 7),
+	UNIPHIER_PERI_CLK_FI2C(4, 8),
+	UNIPHIER_PERI_CLK_FI2C(5, 9),
+	UNIPHIER_PERI_CLK_FI2C(6, 10),
+	{ /* sentinel */ }
+};
+
+static void __init ph1_ld4_peri_clk_init(struct device_node *np)
+{
+	uniphier_clk_init(np, ph1_ld4_peri_clk_idata);
+}
+CLK_OF_DECLARE(ph1_ld4_peri_clk, "socionext,ph1-ld4-perictrl",
+	       ph1_ld4_peri_clk_init);
+CLK_OF_DECLARE(ph1_sld8_peri_clk, "socionext,ph1-sld8-perictrl",
+	       ph1_ld4_peri_clk_init);
+
+static void __init ph1_pro4_peri_clk_init(struct device_node *np)
+{
+	uniphier_clk_init(np, ph1_pro4_peri_clk_idata);
+}
+CLK_OF_DECLARE(ph1_pro4_peri_clk, "socionext,ph1-pro4-perictrl",
+	       ph1_pro4_peri_clk_init);
+
+static void __init ph1_pro5_peri_clk_init(struct device_node *np)
+{
+	uniphier_clk_init(np, ph1_pro5_peri_clk_idata);
+}
+CLK_OF_DECLARE(ph1_pro5_peri_clk, "socionext,ph1-pro5-perictrl",
+	       ph1_pro5_peri_clk_init);
+CLK_OF_DECLARE(proxstream2_peri_clk, "socionext,proxstream2-perictrl",
+	       ph1_pro5_peri_clk_init);
diff --git a/drivers/clk/uniphier/clk-uniphier.h b/drivers/clk/uniphier/clk-uniphier.h
new file mode 100644
index 0000000..05277b6
--- /dev/null
+++ b/drivers/clk/uniphier/clk-uniphier.h
@@ -0,0 +1,68 @@ 
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * 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.
+ */
+
+#ifndef __CLK_UNIPHIER_H__
+#define __CLK_UNIPHIER_H__
+
+#include <linux/kernel.h>
+
+#define UNIPHIER_CLK_EXT	"[EXT]"
+
+enum uniphier_clk_type {
+	UNIPHIER_CLK_TYPE_FIXED_FACTOR,
+	UNIPHIER_CLK_TYPE_FIXED_RATE,
+	UNIPHIER_CLK_TYPE_GATE,
+	UNIPHIER_CLK_TYPE_MUX,
+};
+
+struct uniphier_clk_fixed_factor_data {
+	const char *parent_name;
+	unsigned int mult;
+	unsigned int div;
+};
+
+struct uniphier_clk_fixed_rate_data {
+	unsigned long fixed_rate;
+};
+
+struct uniphier_clk_gate_data {
+	const char *parent_name;
+	unsigned int reg;
+	u8 bit_idx;
+};
+
+struct uniphier_clk_mux_data {
+	const char *parent_names[4];
+	u8 num_parents;
+	unsigned int reg;
+	u8 shift;
+};
+
+struct uniphier_clk_init_data {
+	const char *name;
+	enum uniphier_clk_type type;
+	int output_index;
+	union {
+		struct uniphier_clk_fixed_factor_data factor;
+		struct uniphier_clk_fixed_rate_data rate;
+		struct uniphier_clk_gate_data gate;
+		struct uniphier_clk_mux_data mux;
+	} data;
+	struct clk *clk;
+};
+
+int uniphier_clk_init(struct device_node *np,
+		      struct uniphier_clk_init_data *idata);
+
+#endif /* __CLK_UNIPHIER_H__ */