2014-06-10 01:33:36

by Chao Xie

[permalink] [raw]
Subject: [PATCH 00/12] clk: mmp: clock device tree support

From: Chao Xie <[email protected]>

The patch set focuses at support device tree for clock.

The first part of the patches
clk: mmp: add prefix "mmp" for structures defined for clk-frac
clk: mmp: add spin lock for clk-frac
clk: mmp: add init callback for clk-frac
clk: mmp: move definiton of mmp_clk_frac to clk.h
It enhances the clk-frac.

The second part of the patches
clk: mmp: add clock type mix
clk: mmp: add mmp private gate clock
clk: mmp: add clock type composite for mix
It add three new types of clocks.

The third part of the patches
clk: mmp: add clock type master
clk: mmp: add spin lock automatic detection from device tree
clk: mmp: add device tree support for composite type clock
clk: mmp: add device tree support for clocks.
It add the device tree support. The whole clock tree is not
defined in .c file, but be parsed from the device tree file.

The final part of the patches
arm: mmp: support clock device tree for mmp platforms
Change the mmp platform to use device tree to parse the clocks.

Chao Xie (12):
clk: mmp: add prefix "mmp" for structures defined for clk-frac
clk: mmp: add spin lock for clk-frac
clk: mmp: add init callback for clk-frac
clk: mmp: move definiton of mmp_clk_frac to clk.h
clk: mmp: add clock type mix
clk: mmp: add mmp private gate clock
clk: mmp: add clock type composite for mix
clk: mmp: add clock type master
clk: mmp: add spin lock automatic detection from device tree
clk: mmp: add device tree support for composite type clock
clk: mmp: add device tree support for clocks.
arm: mmp: support clock device tree for mmp platforms

.../devicetree/bindings/clock/mmp/clk-composite | 58 ++
.../devicetree/bindings/clock/mmp/clk-div | 28 +
.../devicetree/bindings/clock/mmp/clk-factor | 28 +
.../devicetree/bindings/clock/mmp/clk-gate | 41 ++
.../devicetree/bindings/clock/mmp/clk-master | 47 ++
.../devicetree/bindings/clock/mmp/clk-mix | 38 ++
.../devicetree/bindings/clock/mmp/clk-mux | 20 +
Documentation/devicetree/bindings/clock/mmp/lock | 44 ++
arch/arm/boot/dts/mmp2-clock.dtsi | 575 +++++++++++++++++
arch/arm/boot/dts/mmp2.dtsi | 11 +
arch/arm/boot/dts/pxa168-clock.dtsi | 443 +++++++++++++
arch/arm/boot/dts/pxa168.dtsi | 10 +
arch/arm/boot/dts/pxa910-clock.dtsi | 388 ++++++++++++
arch/arm/boot/dts/pxa910.dtsi | 10 +
arch/arm/mach-mmp/Kconfig | 7 +-
arch/arm/mach-mmp/Makefile | 2 +-
arch/arm/mach-mmp/common.h | 1 +
arch/arm/mach-mmp/mmp-dt.c | 57 +-
arch/arm/mach-mmp/mmp2-dt.c | 50 --
drivers/clk/mmp/Makefile | 7 +-
drivers/clk/mmp/clk-frac.c | 74 ++-
drivers/clk/mmp/clk-gate.c | 133 ++++
drivers/clk/mmp/clk-master-node.c | 195 ++++++
drivers/clk/mmp/clk-mix-composite.c | 195 ++++++
drivers/clk/mmp/clk-mix.c | 419 +++++++++++++
drivers/clk/mmp/clk-mmp2.c | 6 +-
drivers/clk/mmp/clk-of-composite.c | 253 ++++++++
drivers/clk/mmp/clk-of.c | 689 +++++++++++++++++++++
drivers/clk/mmp/clk-pxa168.c | 6 +-
drivers/clk/mmp/clk-pxa910.c | 6 +-
drivers/clk/mmp/clk.h | 164 ++++-
drivers/clk/mmp/lock.c | 159 +++++
32 files changed, 4035 insertions(+), 129 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/mmp/clk-composite
create mode 100644 Documentation/devicetree/bindings/clock/mmp/clk-div
create mode 100644 Documentation/devicetree/bindings/clock/mmp/clk-factor
create mode 100644 Documentation/devicetree/bindings/clock/mmp/clk-gate
create mode 100644 Documentation/devicetree/bindings/clock/mmp/clk-master
create mode 100644 Documentation/devicetree/bindings/clock/mmp/clk-mix
create mode 100644 Documentation/devicetree/bindings/clock/mmp/clk-mux
create mode 100644 Documentation/devicetree/bindings/clock/mmp/lock
create mode 100644 arch/arm/boot/dts/mmp2-clock.dtsi
create mode 100644 arch/arm/boot/dts/pxa168-clock.dtsi
create mode 100644 arch/arm/boot/dts/pxa910-clock.dtsi
delete mode 100644 arch/arm/mach-mmp/mmp2-dt.c
create mode 100644 drivers/clk/mmp/clk-gate.c
create mode 100644 drivers/clk/mmp/clk-master-node.c
create mode 100644 drivers/clk/mmp/clk-mix-composite.c
create mode 100644 drivers/clk/mmp/clk-mix.c
create mode 100644 drivers/clk/mmp/clk-of-composite.c
create mode 100644 drivers/clk/mmp/clk-of.c
create mode 100644 drivers/clk/mmp/lock.c

--
1.8.3.2


2014-06-10 01:28:13

by Chao Xie

[permalink] [raw]
Subject: [PATCH 03/12] clk: mmp: add init callback for clk-frac

From: Chao Xie <[email protected]>

For the clk-frac, if it has table, we need to make
sure that the initial clock rate is one item of the
table.
If it is not, we use the first item in the table by default.

Signed-off-by: Chao Xie <[email protected]>
---
drivers/clk/mmp/clk-frac.c | 40 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)

diff --git a/drivers/clk/mmp/clk-frac.c b/drivers/clk/mmp/clk-frac.c
index e29d006..1876d2c 100644
--- a/drivers/clk/mmp/clk-frac.c
+++ b/drivers/clk/mmp/clk-frac.c
@@ -118,10 +118,50 @@ static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate,
return 0;
}

+void clk_factor_init(struct clk_hw *hw)
+{
+ struct mmp_clk_factor *factor = to_clk_factor(hw);
+ struct mmp_clk_factor_masks *masks = factor->masks;
+ u32 val, num, den;
+ int i;
+ unsigned long flags = 0;
+
+ if (factor->lock)
+ spin_lock_irqsave(factor->lock, flags);
+
+ val = readl(factor->base);
+
+ /* calculate numerator */
+ num = (val >> masks->num_shift) & masks->num_mask;
+
+ /* calculate denominator */
+ den = (val >> masks->den_shift) & masks->den_mask;
+
+ for (i = 0; i < factor->ftbl_cnt; i++)
+ if (den == factor->ftbl[i].den && num == factor->ftbl[i].num)
+ break;
+
+ if (i >= factor->ftbl_cnt) {
+ val &= ~(masks->num_mask << masks->num_shift);
+ val |= (factor->ftbl[0].num & masks->num_mask) <<
+ masks->num_shift;
+
+ val &= ~(masks->den_mask << masks->den_shift);
+ val |= (factor->ftbl[0].den & masks->den_mask) <<
+ masks->den_shift;
+
+ writel(val, factor->base);
+ }
+
+ if (factor->lock)
+ spin_unlock_irqrestore(factor->lock, flags);
+}
+
static struct clk_ops clk_factor_ops = {
.recalc_rate = clk_factor_recalc_rate,
.round_rate = clk_factor_round_rate,
.set_rate = clk_factor_set_rate,
+ .init = clk_factor_init,
};

struct clk *mmp_clk_register_factor(const char *name, const char *parent_name,
--
1.8.3.2

2014-06-10 01:28:21

by Chao Xie

[permalink] [raw]
Subject: [PATCH 07/12] clk: mmp: add clock type composite for mix

From: Chao Xie <[email protected]>

The general composite clock supports div/mux/gate.
marvell SOCes have many clocks that need change
div and mux together. So it need the composite
clock that supports mix/gate.

Signed-off-by: Chao Xie <[email protected]>
---
drivers/clk/mmp/Makefile | 3 +-
drivers/clk/mmp/clk-mix-composite.c | 195 ++++++++++++++++++++++++++++++++++++
drivers/clk/mmp/clk.h | 20 ++++
3 files changed, 217 insertions(+), 1 deletion(-)
create mode 100644 drivers/clk/mmp/clk-mix-composite.c

diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile
index 2855f7b..2cd7d94 100644
--- a/drivers/clk/mmp/Makefile
+++ b/drivers/clk/mmp/Makefile
@@ -2,7 +2,8 @@
# Makefile for mmp specific clk
#

-obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o clk-gate.o
+obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o clk-gate.o \
+ clk-mix-composite.o

obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o
diff --git a/drivers/clk/mmp/clk-mix-composite.c b/drivers/clk/mmp/clk-mix-composite.c
new file mode 100644
index 0000000..79d5286
--- /dev/null
+++ b/drivers/clk/mmp/clk-mix-composite.c
@@ -0,0 +1,195 @@
+/*
+ * mmp mix(div and mux) clock operation source file
+ *
+ * Copyright (C) 2014 Marvell
+ * Chao Xie <[email protected]>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+#include "clk.h"
+
+#define to_clk_composite(_hw) container_of(_hw, struct mmp_clk_composite, hw)
+
+static u8 mmp_clk_composite_get_parent(struct clk_hw *hw)
+{
+ struct mmp_clk_composite *composite = to_clk_composite(hw);
+ const struct clk_ops *mix_ops = composite->mix_ops;
+ struct clk_hw *mix_hw = composite->mix_hw;
+
+ mix_hw->clk = hw->clk;
+
+ return mix_ops->get_parent(mix_hw);
+}
+
+static int mmp_clk_composite_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct mmp_clk_composite *composite = to_clk_composite(hw);
+ const struct clk_ops *mix_ops = composite->mix_ops;
+ struct clk_hw *mix_hw = composite->mix_hw;
+
+ mix_hw->clk = hw->clk;
+
+ return mix_ops->set_parent(mix_hw, index);
+}
+
+static int mmp_clk_composite_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct mmp_clk_composite *composite = to_clk_composite(hw);
+ const struct clk_ops *mix_ops = composite->mix_ops;
+ struct clk_hw *mix_hw = composite->mix_hw;
+
+ mix_hw->clk = hw->clk;
+
+ return mix_ops->set_rate(mix_hw, rate, parent_rate);
+}
+
+static unsigned long mmp_clk_composite_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct mmp_clk_composite *composite = to_clk_composite(hw);
+ const struct clk_ops *mix_ops = composite->mix_ops;
+ struct clk_hw *mix_hw = composite->mix_hw;
+
+ mix_hw->clk = hw->clk;
+
+ return mix_ops->recalc_rate(mix_hw, parent_rate);
+}
+
+static long mmp_clk_composite_determine_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long *best_parent_rate,
+ struct clk **best_parent_p)
+{
+ struct mmp_clk_composite *composite = to_clk_composite(hw);
+ const struct clk_ops *mix_ops = composite->mix_ops;
+ struct clk_hw *mix_hw = composite->mix_hw;
+
+ mix_hw->clk = hw->clk;
+
+ return mix_ops->determine_rate(mix_hw, rate, best_parent_rate,
+ best_parent_p);
+}
+
+static int mmp_clk_composite_set_rate_and_parent(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long parent_rate, u8 index)
+
+{
+ struct mmp_clk_composite *composite = to_clk_composite(hw);
+ const struct clk_ops *mix_ops = composite->mix_ops;
+ struct clk_hw *mix_hw = composite->mix_hw;
+
+ mix_hw->clk = hw->clk;
+
+ return mix_ops->set_rate_and_parent(mix_hw, rate, parent_rate, index);
+}
+
+static int mmp_clk_composite_is_enabled(struct clk_hw *hw)
+{
+ struct mmp_clk_composite *composite = to_clk_composite(hw);
+ const struct clk_ops *gate_ops = composite->gate_ops;
+ struct clk_hw *gate_hw = composite->gate_hw;
+
+ gate_hw->clk = hw->clk;
+
+ return gate_ops->is_enabled(gate_hw);
+}
+
+static int mmp_clk_composite_enable(struct clk_hw *hw)
+{
+ struct mmp_clk_composite *composite = to_clk_composite(hw);
+ const struct clk_ops *gate_ops = composite->gate_ops;
+ struct clk_hw *gate_hw = composite->gate_hw;
+
+ gate_hw->clk = hw->clk;
+
+ return gate_ops->enable(gate_hw);
+}
+
+static void mmp_clk_composite_disable(struct clk_hw *hw)
+{
+ struct mmp_clk_composite *composite = to_clk_composite(hw);
+ const struct clk_ops *gate_ops = composite->gate_ops;
+ struct clk_hw *gate_hw = composite->gate_hw;
+
+ gate_hw->clk = hw->clk;
+
+ gate_ops->disable(gate_hw);
+}
+
+static void mmp_clk_composite_init(struct clk_hw *hw)
+{
+ struct mmp_clk_composite *composite = to_clk_composite(hw);
+ const struct clk_ops *gate_ops = composite->gate_ops;
+ struct clk_hw *gate_hw = composite->gate_hw;
+ const struct clk_ops *mix_ops = composite->mix_ops;
+ struct clk_hw *mix_hw = composite->mix_hw;
+
+ mix_hw->clk = hw->clk;
+ gate_hw->clk = hw->clk;
+
+ if (mix_ops->init)
+ mix_ops->init(mix_hw);
+ if (gate_ops->init)
+ gate_ops->init(gate_hw);
+}
+
+static struct clk_ops mmp_clk_composite_ops = {
+ .enable = mmp_clk_composite_enable,
+ .disable = mmp_clk_composite_disable,
+ .is_enabled = mmp_clk_composite_is_enabled,
+ .determine_rate = mmp_clk_composite_determine_rate,
+ .set_rate_and_parent = mmp_clk_composite_set_rate_and_parent,
+ .set_rate = mmp_clk_composite_set_rate,
+ .recalc_rate = mmp_clk_composite_recalc_rate,
+ .get_parent = mmp_clk_composite_get_parent,
+ .set_parent = mmp_clk_composite_set_parent,
+ .init = mmp_clk_composite_init,
+};
+
+struct clk *mmp_clk_register_composite(struct device *dev, const char *name,
+ const char **parent_names, int num_parents,
+ struct clk_hw *mix_hw, const struct clk_ops *mix_ops,
+ struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
+ unsigned long flags)
+{
+ struct clk *clk;
+ struct clk_init_data init;
+ struct mmp_clk_composite *composite;
+
+ if (!mix_hw || !gate_hw)
+ return ERR_PTR(-EINVAL);
+
+ composite = kzalloc(sizeof(*composite), GFP_KERNEL);
+ if (!composite) {
+ pr_err("%s: could not allocate mmp composite clk\n", __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ init.name = name;
+ init.flags = flags;
+ init.parent_names = parent_names;
+ init.num_parents = num_parents;
+ init.ops = &mmp_clk_composite_ops;
+
+ composite->mix_hw = mix_hw;
+ composite->mix_ops = mix_ops;
+ composite->gate_hw = gate_hw;
+ composite->gate_ops = gate_ops;
+ composite->hw.init = &init;
+
+ clk = clk_register(dev, &composite->hw);
+ if (IS_ERR(clk))
+ kfree(composite);
+
+ return clk;
+}
diff --git a/drivers/clk/mmp/clk.h b/drivers/clk/mmp/clk.h
index 9096f0a..9827a4f 100644
--- a/drivers/clk/mmp/clk.h
+++ b/drivers/clk/mmp/clk.h
@@ -120,6 +120,26 @@ extern struct clk *mmp_clk_register_gate(struct device *dev, const char *name,
spinlock_t *lock);


+/* Clock type "composite" for mix clock */
+struct mmp_clk_composite {
+ struct clk_hw hw;
+ struct clk_ops ops;
+
+ struct clk_hw *mix_hw;
+ struct clk_hw *gate_hw;
+
+ const struct clk_ops *mix_ops;
+ const struct clk_ops *gate_ops;
+};
+
+extern struct clk *mmp_clk_register_composite(struct device *dev,
+ const char *name,
+ const char **parent_names, int num_parents,
+ struct clk_hw *mix_hw, const struct clk_ops *mix_ops,
+ struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
+ unsigned long flags);
+
+
extern struct clk *mmp_clk_register_pll2(const char *name,
const char *parent_name, unsigned long flags);
extern struct clk *mmp_clk_register_apbc(const char *name,
--
1.8.3.2

2014-06-10 01:28:27

by Chao Xie

[permalink] [raw]
Subject: [PATCH 12/12] arm: mmp: support clock device tree for mmp platforms

From: Chao Xie <[email protected]>

The platforms including pxa168/pxa910/mmp2.

After add clock device tree support. There is no need
to maintain mmp2-dt.c because it is same as mmp-dt.c now.
The file will be removed.

Compiling test for pxa168 because of lacking of platform.
The platform is too old.

Functonality test for pxa910 and mmp2.

Signed-off-by: Chao Xie <[email protected]>
---
arch/arm/boot/dts/mmp2-clock.dtsi | 575 ++++++++++++++++++++++++++++++++++++
arch/arm/boot/dts/mmp2.dtsi | 11 +
arch/arm/boot/dts/pxa168-clock.dtsi | 443 +++++++++++++++++++++++++++
arch/arm/boot/dts/pxa168.dtsi | 10 +
arch/arm/boot/dts/pxa910-clock.dtsi | 388 ++++++++++++++++++++++++
arch/arm/boot/dts/pxa910.dtsi | 10 +
arch/arm/mach-mmp/Kconfig | 7 +-
arch/arm/mach-mmp/Makefile | 2 +-
arch/arm/mach-mmp/common.h | 1 +
arch/arm/mach-mmp/mmp-dt.c | 57 ++--
arch/arm/mach-mmp/mmp2-dt.c | 50 ----
11 files changed, 1462 insertions(+), 92 deletions(-)
create mode 100644 arch/arm/boot/dts/mmp2-clock.dtsi
create mode 100644 arch/arm/boot/dts/pxa168-clock.dtsi
create mode 100644 arch/arm/boot/dts/pxa910-clock.dtsi
delete mode 100644 arch/arm/mach-mmp/mmp2-dt.c

diff --git a/arch/arm/boot/dts/mmp2-clock.dtsi b/arch/arm/boot/dts/mmp2-clock.dtsi
new file mode 100644
index 0000000..89f2279
--- /dev/null
+++ b/arch/arm/boot/dts/mmp2-clock.dtsi
@@ -0,0 +1,575 @@
+&soc_clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ fixed_clocks: fixed_clocks {
+ compatible = "marvell,mmp-clk-master";
+ clk32: clk32 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ };
+ vctcxo: vctcxo {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <26000000>;
+ };
+ vctcxo_2: vctcxo_2 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&vctcxo>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ vctcxo_4: vctcxo_4 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&vctcxo_2>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ usb_pll: usb_pll {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <480000000>;
+ };
+ pll1: pll1 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <624000000>;
+ };
+ pll1_2: pll1_2 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ pll1_4: pll1_4 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_2>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ pll1_8: pll1_8 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_4>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ pll1_16: pll1_16 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_8>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ pll1_20: pll1_20 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_4>;
+ clock-div = <5>;
+ clock-mult = <1>;
+ };
+ pll1_3: pll1_3 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1>;
+ clock-div = <3>;
+ clock-mult = <1>;
+ };
+ pll1_6: pll1_6 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_3>;
+ clock-div = <3>;
+ clock-mult = <1>;
+ };
+ pll1_12: pll1_12 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_6>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ pll2: pll2 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <960000000>;
+ };
+ pll2_2: pll2_2 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll2>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ pll2_4: pll2_4 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll2_2>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ pll2_8: pll2_8 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll2_4>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ pll2_16: pll2_16 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll2_8>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ pll2_20: pll2_20 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll2_4>;
+ clock-div = <5>;
+ clock-mult = <1>;
+ };
+ pll2_3: pll2_3 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll2>;
+ clock-div = <3>;
+ clock-mult = <1>;
+ };
+ pll2_6: pll2_6 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll2_3>;
+ clock-div = <3>;
+ clock-mult = <1>;
+ };
+ pll2_12: pll2_12 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll2_6>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ };
+ mpmu_clocks: mpmu_clocks {
+ compatible = "marvell,mmp-clk-master";
+ reg = <0xd4050000 0x1000>;
+ uart_pll: uart_pll {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-factor";
+ clocks = <&pll1_4>;
+ marvell,reg-offset = <0 0x14>;
+ marvell,mmp-clk-factor-factor = <2>;
+ marvell,mmp-clk-factor-bits-den = <13 0>;
+ marvell,mmp-clk-factor-bits-num = <13 16>;
+ marvell,mmp-clk-factor-table = <14634 2165>,
+ <3521 689>,
+ <9679 5728>,
+ <15859 9451>;
+ };
+ };
+ apbc_clocks: apbc_clocks {
+ compatible = "marvell,mmp-clk-master";
+ reg = <0xd4015000 0x1000>;
+ twsi0_clock: twsi0_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&vctcxo>;
+ marvell,reg-offset = <0 0x4>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ twsi1_clock: twsi1_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&vctcxo>;
+ marvell,reg-offset = <0 0x8>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ twsi2_clock: twsi2_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&vctcxo>;
+ marvell,reg-offset = <0 0xc>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ twsi3_clock: twsi3_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&vctcxo>;
+ marvell,reg-offset = <0 0x10>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ twsi4_clock: twsi4_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&vctcxo>;
+ marvell,reg-offset = <0 0x7c>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ twsi5_clock: twsi5_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&vctcxo>;
+ marvell,reg-offset = <0 0x80>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ gpio_clock: gpio_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&vctcxo>;
+ marvell,reg-offset = <0 0x38>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ kpc_clock: kpc_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&clk32>;
+ marvell,reg-offset = <0 0x18>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ marvell,mmp-clk-gate-need-delay;
+ };
+ rtc_clock: rtc_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&clk32>;
+ marvell,reg-offset = <0 0x0>;
+ marvell,mmp-clk-mask = <0x87 0x83 0x4>;
+ marvell,mmp-clk-gate-need-delay;
+ };
+ pwm0_clock: pwm0_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&vctcxo>;
+ marvell,reg-offset = <0 0x3c>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ pwm1_clock: pwm1_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&vctcxo>;
+ marvell,reg-offset = <0 0x40>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ pwm2_clock: pwm2_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&vctcxo>;
+ marvell,reg-offset = <0 0x44>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ pwm3_clock: pwm3_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&vctcxo>;
+ marvell,reg-offset = <0 0x48>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ uart0_clock: uart0_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ uart0_mux: uart0_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&uart_pll &vctcxo>;
+ marvell,reg-offset = <0 0x2c>;
+ marvell,mmp-clk-bits-mux = <1 4>;
+ };
+ uart0_gate: uart0_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x2c>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x0>;
+ };
+ };
+ uart1_clock: uart1_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ uart1_mux: uart1_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&uart_pll &vctcxo>;
+ marvell,reg-offset = <0 0x30>;
+ marvell,mmp-clk-bits-mux = <1 4>;
+ };
+ uart1_gate: uart1_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x30>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x0>;
+ };
+ };
+ uart2_clock: uart2_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ uart2_mux: uart2_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&uart_pll &vctcxo>;
+ marvell,reg-offset = <0 0x34>;
+ marvell,mmp-clk-bits-mux = <1 4>;
+ };
+ uart2_gate: uart2_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x34>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x0>;
+ };
+ };
+ uart3_clock: uart3_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ uart3_mux: uart3_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&uart_pll &vctcxo>;
+ marvell,reg-offset = <0 0x88>;
+ marvell,mmp-clk-bits-mux = <1 4>;
+ };
+ uart3_gate: uart3_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x88>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x0>;
+ };
+ };
+
+ ssp0_clock: ssp0_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ ssp0_mux: ssp0_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&vctcxo_4 &vctcxo_2 &vctcxo &pll1_16>;
+ marvell,reg-offset = <0 0x50>;
+ marvell,mmp-clk-bits-mux = <3 4>;
+ };
+ ssp0_gate: ssp0_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x50>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ };
+ ssp1_clock: ssp1_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ ssp1_mux: ssp1_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&vctcxo_4 &vctcxo_2 &vctcxo &pll1_16>;
+ marvell,reg-offset = <0 0x54>;
+ marvell,mmp-clk-bits-mux = <3 4>;
+ };
+ ssp1_gate: ssp1_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x54>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ };
+ ssp2_clock: ssp2_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ ssp2_mux: ssp2_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&vctcxo_4 &vctcxo_2 &vctcxo &pll1_16>;
+ marvell,reg-offset = <0 0x58>;
+ marvell,mmp-clk-bits-mux = <3 4>;
+ };
+ ssp2_gate: ssp2_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x58>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ };
+ ssp3_clock: ssp3_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ ssp3_mux: ssp3_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&vctcxo_4 &vctcxo_2 &vctcxo &pll1_16>;
+ marvell,reg-offset = <0 0x5c>;
+ marvell,mmp-clk-bits-mux = <3 4>;
+ };
+ ssp3_gate: ssp3_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x5c>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ };
+ };
+ apmu_clocks: apmu_clocks {
+ compatible = "marvell,mmp-clk-master";
+ reg = <0xd4282800 0x1000>;
+ sdh_mix: sdh_mix {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mix";
+ clocks = <&pll1_4 &pll2 &usb_pll &pll1>;
+ marvell,reg-offset = <0 0x54>;
+ marvell,mmp-clk-bits-mux = <2 8>;
+ marvell,mmp-clk-bits-div = <4 10>;
+ marvell,mmp-clk-div-one-based;
+ };
+ sdh0_clock: sdh0_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&sdh_mix>;
+ marvell,reg-offset = <0 0x54>;
+ marvell,mmp-clk-mask = <0x1b 0x1b 0x0>;
+ };
+ sdh1_clock: sdh1_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&sdh_mix>;
+ marvell,reg-offset = <0 0x58>;
+ marvell,mmp-clk-mask = <0x1b 0x1b 0x0>;
+ };
+ sdh2_clock: sdh2_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&sdh_mix>;
+ marvell,reg-offset = <0 0xe8>;
+ marvell,mmp-clk-mask = <0x1b 0x1b 0x0>;
+ };
+ sdh3_clock: sdh3_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&sdh_mix>;
+ marvell,reg-offset = <0 0xec>;
+ marvell,mmp-clk-mask = <0x1b 0x1b 0x0>;
+ };
+ usb_clock: usb_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x5c>;
+ marvell,mmp-clk-mask = <0x9 0x9 0x0>;
+ };
+ disp0_mux: disp0_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ marvell,reg-offset = <0 0x4c>;
+ clocks = <&pll1 &pll1_16 &pll2 &vctcxo>;
+ marvell,mmp-clk-bits-mux = <2 6>;
+ };
+ disp0_clock: disp0_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ disp0_div: disp0_div {
+ compatible = "marvell,mmp-clk-div";
+ marvell,reg-offset = <0 0x4c>;
+ clocks = <&disp0_mux>;
+ marvell,mmp-clk-bits-div = <4 8>;
+ marvell,mmp-clk-div-one-based;
+ };
+ disp0_gate: disp0_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x4c>;
+ marvell,mmp-clk-mask = <0x1b 0x1b 0x0>;
+ };
+ };
+ disp1_clock: disp1_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ disp1_mix: disp1_mix {
+ compatible = "marvell,mmp-clk-mix";
+ marvell,reg-offset = <0 0x110>;
+ clocks = <&pll1 &pll1_16 &pll2 &vctcxo>;
+ marvell,mmp-clk-bits-mux = <2 6>;
+ marvell,mmp-clk-bits-div = <4 8>;
+ marvell,mmp-clk-div-one-based;
+ };
+ disp1_gate: disp1_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x110>;
+ marvell,mmp-clk-mask = <0x1b 0x1b 0x0>;
+ };
+ };
+ ccic_arbiter: ccic_arbiter {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&vctcxo>;
+ marvell,reg-offset = <0 0x50>;
+ marvell,mmp-clk-mask = <0x1800 0x1800 0x0>;
+ };
+ ccic0_mix: ccic0_mix {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&pll1_2 &pll1_16 &vctcxo>;
+ marvell,reg-offset = <0 0x50>;
+ marvell,mmp-clk-bits-mux = <2 6>;
+ marvell,mmp-clk-bits-div = <4 17>;
+ marvell,mmp-clk-div-one-based;
+ };
+ ccic0_clock: ccic0_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&ccic0_mix>;
+ marvell,reg-offset = <0 0x50>;
+ marvell,mmp-clk-mask = <0x1b 0x1b 0x0>;
+ };
+ ccic0_phy_clock: ccic0_phy_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&ccic0_mix>;
+ marvell,reg-offset = <0 0x50>;
+ marvell,mmp-clk-mask = <0x24 0x24 0x0>;
+ };
+ ccic0_sphy_clock: ccic0_sphy_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ ccic0_sphy_div: ccic0_sphy_div {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-div";
+ clocks = <&ccic0_mix>;
+ marvell,reg-offset = <0 0x50>;
+ marvell,mmp-clk-bits-div = <5 10>;
+ };
+ ccic0_sphy_gate: ccic0_sphy_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x50>;
+ marvell,mmp-clk-mask = <0x300 0x300 0x0>;
+ };
+ };
+ ccic1_mix: ccic1_mix {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&pll1_2 &pll1_16 &vctcxo>;
+ marvell,reg-offset = <0 0xf4>;
+ marvell,mmp-clk-bits-mux = <2 6>;
+ marvell,mmp-clk-bits-div = <4 16>;
+ marvell,mmp-clk-div-one-based;
+ };
+ ccic1_clock: ccic1_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&ccic1_mix>;
+ marvell,reg-offset = <0 0xf4>;
+ marvell,mmp-clk-mask = <0x1b 0x1b 0x0>;
+ };
+ ccic1_phy_clock: ccic1_phy_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&ccic1_mix>;
+ marvell,reg-offset = <0 0xf4>;
+ marvell,mmp-clk-mask = <0x24 0x24 0x0>;
+ };
+ ccic1_sphy_clock: ccic1_sphy_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ ccic1_sphy_div: ccic1_sphy_div {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-div";
+ clocks = <&ccic1_mix>;
+ marvell,reg-offset = <0 0xf4>;
+ marvell,mmp-clk-bits-div = <5 10>;
+ };
+ ccic1_sphy_gate: ccic1_sphy_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0xf4>;
+ marvell,mmp-clk-mask = <0x300 0x300 0x0>;
+ };
+ };
+
+ };
+};
diff --git a/arch/arm/boot/dts/mmp2.dtsi b/arch/arm/boot/dts/mmp2.dtsi
index 4e8b08c..66bc8db 100644
--- a/arch/arm/boot/dts/mmp2.dtsi
+++ b/arch/arm/boot/dts/mmp2.dtsi
@@ -135,6 +135,7 @@
compatible = "mrvl,mmp-uart";
reg = <0xd4030000 0x1000>;
interrupts = <27>;
+ clocks = <&uart0_clock>;
status = "disabled";
};

@@ -142,6 +143,7 @@
compatible = "mrvl,mmp-uart";
reg = <0xd4017000 0x1000>;
interrupts = <28>;
+ clocks = <&uart1_clock>;
status = "disabled";
};

@@ -149,6 +151,7 @@
compatible = "mrvl,mmp-uart";
reg = <0xd4018000 0x1000>;
interrupts = <24>;
+ clocks = <&uart2_clock>;
status = "disabled";
};

@@ -156,6 +159,7 @@
compatible = "mrvl,mmp-uart";
reg = <0xd4016000 0x1000>;
interrupts = <46>;
+ clocks = <&uart3_clock>;
status = "disabled";
};

@@ -164,6 +168,7 @@
#address-cells = <1>;
#size-cells = <1>;
reg = <0xd4019000 0x1000>;
+ clocks = <&gpio_clock>;
gpio-controller;
#gpio-cells = <2>;
interrupts = <49>;
@@ -201,6 +206,7 @@
compatible = "mrvl,mmp-twsi";
reg = <0xd4011000 0x1000>;
interrupts = <7>;
+ clocks = <&twsi0_clock>;
#address-cells = <1>;
#size-cells = <0>;
mrvl,i2c-fast-mode;
@@ -211,6 +217,7 @@
compatible = "mrvl,mmp-twsi";
reg = <0xd4025000 0x1000>;
interrupts = <58>;
+ clocks = <&twsi1_clock>;
status = "disabled";
};

@@ -220,8 +227,12 @@
interrupts = <1 0>;
interrupt-names = "rtc 1Hz", "rtc alarm";
interrupt-parent = <&intcmux5>;
+ clocks = <&rtc_clock>;
status = "disabled";
};
};
+ soc_clocks: clocks{
+ };
};
};
+/include/ "mmp2-clock.dtsi"
diff --git a/arch/arm/boot/dts/pxa168-clock.dtsi b/arch/arm/boot/dts/pxa168-clock.dtsi
new file mode 100644
index 0000000..8bd331e
--- /dev/null
+++ b/arch/arm/boot/dts/pxa168-clock.dtsi
@@ -0,0 +1,443 @@
+&soc_clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ fixed_clocks: fixed_clocks {
+ compatible = "marvell,mmp-clk-master";
+ clk32: clk32 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ };
+ vctcxo: vctcxo {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <26000000>;
+ };
+ pll1: pll1 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <624000000>;
+ };
+ pll1_2: pll1_2 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ pll1_4: pll1_4 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_2>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ pll1_8: pll1_8 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_4>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ pll1_16: pll1_16 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_8>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ pll1_6: pll1_6 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_2>;
+ clock-div = <3>;
+ clock-mult = <1>;
+ };
+ pll1_12: pll1_12 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_6>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ pll1_24: pll1_24 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_12>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ pll1_48: pll1_48 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_24>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ pll1_96: pll1_96 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_48>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ pll1_13: pll1_13 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1>;
+ clock-div = <13>;
+ clock-mult = <1>;
+ };
+ pll1_13_1_5: pll1_13_1_5 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_13>;
+ clock-div = <3>;
+ clock-mult = <2>;
+ };
+ pll1_2_1_5: pll1_2_1_5 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1>;
+ clock-div = <3>;
+ clock-mult = <2>;
+ };
+ pll1_3_16: pll1_3_16 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1>;
+ clock-div = <16>;
+ clock-mult = <3>;
+ };
+ };
+ mpmu_clocks: mpmu_clocks {
+ compatible = "marvell,mmp-clk-master";
+ reg = <0xd4050000 0x1000>;
+ uart_pll: uart_pll {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-factor";
+ clocks = <&pll1_4>;
+ marvell,reg-offset = <0 0x14>;
+ marvell,mmp-clk-factor-factor = <2>;
+ marvell,mmp-clk-factor-bits-den = <13 0>;
+ marvell,mmp-clk-factor-bits-num = <13 16>;
+ marvell,mmp-clk-factor-table = <8125 1536>;
+ };
+ };
+ apbc_clocks: apbc_clocks {
+ compatible = "marvell,mmp-clk-master";
+ reg = <0xd4015000 0x1000>;
+ twsi0_clock: twsi0_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&pll1_13_1_5>;
+ marvell,reg-offset = <0 0x2c>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ twsi1_clock: twsi1_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&pll1_13_1_5>;
+ marvell,reg-offset = <0 0x6c>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ gpio_clock: gpio_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&vctcxo>;
+ marvell,reg-offset = <0 0x8>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ kpc_clock: kpc_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&clk32>;
+ marvell,reg-offset = <0 0x30>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ marvell,mmp-clk-gate-need-delay;
+ };
+ rtc_clock: rtc_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&clk32>;
+ marvell,reg-offset = <0 0x28>;
+ marvell,mmp-clk-mask = <0x87 0x83 0x4>;
+ marvell,mmp-clk-gate-need-delay;
+ };
+ pwm0_clock: pwm0_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&pll1_48>;
+ marvell,reg-offset = <0 0xc>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ pwm1_clock: pwm1_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&pll1_48>;
+ marvell,reg-offset = <0 0x10>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ pwm2_clock: pwm2_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&pll1_48>;
+ marvell,reg-offset = <0 0x14>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ pwm3_clock: pwm3_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&pll1_48>;
+ marvell,reg-offset = <0 0x18>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ uart0_clock: uart0_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ uart0_mux: uart0_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&pll1_3_16 &uart_pll>;
+ marvell,reg-offset = <0 0x0>;
+ marvell,mmp-clk-bits-mux = <1 4>;
+ };
+ uart0_gate: uart0_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x0>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x0>;
+ };
+ };
+ uart1_clock: uart1_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ uart1_mux: uart1_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&pll1_3_16 &uart_pll>;
+ marvell,reg-offset = <0 0x4>;
+ marvell,mmp-clk-bits-mux = <1 4>;
+ };
+ uart1_gate: uart1_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x4>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x0>;
+ };
+ };
+ uart2_clock: uart2_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ uart2_mux: uart2_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&pll1_3_16 &uart_pll>;
+ marvell,reg-offset = <0 0x70>;
+ marvell,mmp-clk-bits-mux = <1 4>;
+ };
+ uart2_gate: uart2_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x4>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x0>;
+ };
+ };
+ ssp0_clock: ssp0_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ ssp0_mux: ssp0_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&pll1_96 &pll1_48 &pll1_24 &pll1_12>;
+ marvell,reg-offset = <0 0x81c>;
+ marvell,mmp-clk-bits-mux = <3 4>;
+ };
+ ssp0_gate: ssp0_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x81c>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ };
+ ssp1_clock: ssp1_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ ssp1_mux: ssp1_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&pll1_96 &pll1_48 &pll1_24 &pll1_12>;
+ marvell,reg-offset = <0 0x820>;
+ marvell,mmp-clk-bits-mux = <3 4>;
+ };
+ ssp1_gate: ssp1_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x820>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ };
+ ssp2_clock: ssp2_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ ssp2_mux: ssp2_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&pll1_96 &pll1_48 &pll1_24 &pll1_12>;
+ marvell,reg-offset = <0 0x84c>;
+ marvell,mmp-clk-bits-mux = <3 4>;
+ };
+ ssp2_gate: ssp2_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x84c>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ };
+ ssp3_clock: ssp3_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ ssp3_mux: ssp3_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&pll1_96 &pll1_48 &pll1_24 &pll1_12>;
+ marvell,reg-offset = <0 0x858>;
+ marvell,mmp-clk-bits-mux = <3 4>;
+ };
+ ssp3_gate: ssp3_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x858>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ };
+ ssp4_clock: ssp4_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ ssp4_mux: ssp4_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&pll1_96 &pll1_48 &pll1_24 &pll1_12>;
+ marvell,reg-offset = <0 0x85c>;
+ marvell,mmp-clk-bits-mux = <3 4>;
+ };
+ ssp4_gate: ssp4_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x85c>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ };
+ };
+ apmu_clocks: apmu_clocks {
+ compatible = "marvell,mmp-clk-master";
+ reg = <0xd4282800 0x1000>;
+ dfc_clock: dfc_clock {
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&pll1_4>;
+ marvell,reg-offset = <0 0x60>;
+ marvell,mmp-clk-mask = <0x19b 0x19b 0x0>;
+ };
+ sdh0_clock: sdh0_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ sdh0_mux: sdh0_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&pll1_12 &pll1_13>;
+ marvell,reg-offset = <0 0x54>;
+ marvell,mmp-clk-bits-mux = <1 6>;
+ };
+ sdh0_gate: sdh0_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x54>;
+ marvell,mmp-clk-mask = <0x1b 0x1b 0x0>;
+ };
+ };
+ sdh1_clock: sdh1_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ sdh1_mux: sdh1_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&pll1_12 &pll1_13>;
+ marvell,reg-offset = <0 0x58>;
+ marvell,mmp-clk-bits-mux = <1 6>;
+ };
+ sdh1_gate: sdh1_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x58>;
+ marvell,mmp-clk-mask = <0x1b 0x1b 0x0>;
+ };
+ };
+ usb_clock: usb_clock {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x5c>;
+ marvell,mmp-clk-mask = <0x9 0x9 0x0>;
+ };
+ sph_clock: sph_clock {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x5c>;
+ marvell,mmp-clk-mask = <0x12 0x12 0x0>;
+ };
+ disp0_clock: disp0_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ disp0_mux: disp0_mux {
+ compatible = "marvell,mmp-clk-mux";
+ marvell,reg-offset = <0 0x4c>;
+ clocks = <&pll1_2 &pll1_12>;
+ marvell,mmp-clk-bits-mux = <1 6>;
+ };
+ disp0_gate: disp0_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x4c>;
+ marvell,mmp-clk-mask = <0x1b 0x1b 0x0>;
+ };
+ };
+ disp0_h_clock: disp0_h_clock {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x4c>;
+ marvell,mmp-clk-mask = <0x24 0x24 0x0>;
+ };
+ ccic0_mux: ccic0_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&pll1_2 &pll1_12>;
+ marvell,reg-offset = <0 0x50>;
+ marvell,mmp-clk-bits-mux = <1 6>;
+ };
+ ccic0_clock: ccic0_clock {
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&ccic0_mux>;
+ marvell,reg-offset = <0 0x50>;
+ marvell,mmp-clk-mask = <0x1b 0x1b 0x0>;
+ };
+ ccic0_phy_clock: ccic0_phy_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-composite";
+ ccic0_phy_mux: ccic0_phy_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&pll1_2 &pll1_12>;
+ marvell,reg-offset = <0 0x50>;
+ marvell,mmp-clk-bits-mux = <1 7>;
+ };
+ ccic0_phy_gate: ccic0_phy_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x50>;
+ marvell,mmp-clk-mask = <0x24 0x24 0x0>;
+ };
+ };
+ ccic0_sphy_clock: ccic0_sphy_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-composite";
+ ccic0_sphy_div: ccic0_sphy_div {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-div";
+ clocks = <&ccic0_mux>;
+ marvell,reg-offset = <0 0x50>;
+ marvell,mmp-clk-bits-div = <5 10>;
+ };
+ ccic0_sphy_gate: ccic0_sphy_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x50>;
+ marvell,mmp-clk-mask = <0x300 0x300 0x0>;
+ };
+ };
+
+ };
+};
diff --git a/arch/arm/boot/dts/pxa168.dtsi b/arch/arm/boot/dts/pxa168.dtsi
index 975dad2..d16aa1b 100644
--- a/arch/arm/boot/dts/pxa168.dtsi
+++ b/arch/arm/boot/dts/pxa168.dtsi
@@ -59,6 +59,7 @@
compatible = "mrvl,mmp-uart";
reg = <0xd4017000 0x1000>;
interrupts = <27>;
+ clocks = <&uart0_clock>;
status = "disabled";
};

@@ -66,6 +67,7 @@
compatible = "mrvl,mmp-uart";
reg = <0xd4018000 0x1000>;
interrupts = <28>;
+ clocks = <&uart1_clock>;
status = "disabled";
};

@@ -73,6 +75,7 @@
compatible = "mrvl,mmp-uart";
reg = <0xd4026000 0x1000>;
interrupts = <29>;
+ clocks = <&uart2_clock>;
status = "disabled";
};

@@ -81,6 +84,7 @@
#address-cells = <1>;
#size-cells = <1>;
reg = <0xd4019000 0x1000>;
+ clocks = <&gpio_clock>;
gpio-controller;
#gpio-cells = <2>;
interrupts = <49>;
@@ -110,6 +114,7 @@
compatible = "mrvl,mmp-twsi";
reg = <0xd4011000 0x1000>;
interrupts = <7>;
+ clocks = <&twsi0_clock>;
mrvl,i2c-fast-mode;
status = "disabled";
};
@@ -118,6 +123,7 @@
compatible = "mrvl,mmp-twsi";
reg = <0xd4025000 0x1000>;
interrupts = <58>;
+ clocks = <&twsi1_clock>;
status = "disabled";
};

@@ -126,8 +132,12 @@
reg = <0xd4010000 0x1000>;
interrupts = <5 6>;
interrupt-names = "rtc 1Hz", "rtc alarm";
+ clocks = <&rtc_clock>;
status = "disabled";
};
};
+ soc_clocks: clocks{
+ };
};
};
+/include/ "pxa168-clock.dtsi"
diff --git a/arch/arm/boot/dts/pxa910-clock.dtsi b/arch/arm/boot/dts/pxa910-clock.dtsi
new file mode 100644
index 0000000..e9c58e2
--- /dev/null
+++ b/arch/arm/boot/dts/pxa910-clock.dtsi
@@ -0,0 +1,388 @@
+&soc_clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ fixed_clocks: fixed_clocks {
+ compatible = "marvell,mmp-clk-master";
+ clk32: clk32 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ };
+ vctcxo: vctcxo {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <26000000>;
+ };
+ pll1: pll1 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <624000000>;
+ };
+ pll1_2: pll1_2 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ pll1_4: pll1_4 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_2>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ pll1_8: pll1_8 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_4>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ pll1_16: pll1_16 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_8>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ pll1_6: pll1_6 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_2>;
+ clock-div = <3>;
+ clock-mult = <1>;
+ };
+ pll1_12: pll1_12 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_6>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ pll1_24: pll1_24 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_12>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ pll1_48: pll1_48 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_24>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ pll1_96: pll1_96 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_48>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+ pll1_13: pll1_13 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1>;
+ clock-div = <13>;
+ clock-mult = <1>;
+ };
+ pll1_13_1_5: pll1_13_1_5 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1_13>;
+ clock-div = <3>;
+ clock-mult = <2>;
+ };
+ pll1_2_1_5: pll1_2_1_5 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1>;
+ clock-div = <3>;
+ clock-mult = <2>;
+ };
+ pll1_3_16: pll1_3_16 {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&pll1>;
+ clock-div = <16>;
+ clock-mult = <3>;
+ };
+ };
+ mpmu_clocks: mpmu_clocks {
+ compatible = "marvell,mmp-clk-master";
+ reg = <0xd4050000 0x1000>;
+ uart_pll: uart_pll {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-factor";
+ clocks = <&pll1_4>;
+ marvell,reg-offset = <0 0x14>;
+ marvell,mmp-clk-factor-factor = <2>;
+ marvell,mmp-clk-factor-bits-den = <13 0>;
+ marvell,mmp-clk-factor-bits-num = <13 16>;
+ marvell,mmp-clk-factor-table = <8125 1536>;
+ };
+ };
+ apbc_clocks: apbc_clocks {
+ compatible = "marvell,mmp-clk-master";
+ reg = <0xd4015000 0x1000>;
+ twsi0_clock: twsi0_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&pll1_13_1_5>;
+ marvell,reg-offset = <0 0x2c>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ gpio_clock: gpio_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&vctcxo>;
+ marvell,reg-offset = <0 0x8>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ kpc_clock: kpc_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&clk32>;
+ marvell,reg-offset = <0 0x30>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ marvell,mmp-clk-gate-need-delay;
+ };
+ rtc_clock: rtc_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&clk32>;
+ marvell,reg-offset = <0 0x28>;
+ marvell,mmp-clk-mask = <0x87 0x83 0x4>;
+ marvell,mmp-clk-gate-need-delay;
+ };
+ pwm0_clock: pwm0_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&pll1_48>;
+ marvell,reg-offset = <0 0xc>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ pwm1_clock: pwm1_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&pll1_48>;
+ marvell,reg-offset = <0 0x10>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ pwm2_clock: pwm2_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&pll1_48>;
+ marvell,reg-offset = <0 0x14>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ pwm3_clock: pwm3_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&pll1_48>;
+ marvell,reg-offset = <0 0x18>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ uart0_clock: uart0_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ uart0_mux: uart0_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&pll1_3_16 &uart_pll>;
+ marvell,reg-offset = <0 0x0>;
+ marvell,mmp-clk-bits-mux = <1 4>;
+ };
+ uart0_gate: uart0_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x0>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x0>;
+ };
+ };
+ uart1_clock: uart1_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ uart1_mux: uart1_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&pll1_3_16 &uart_pll>;
+ marvell,reg-offset = <0 0x4>;
+ marvell,mmp-clk-bits-mux = <1 4>;
+ };
+ uart1_gate: uart1_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x4>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x0>;
+ };
+ };
+ ssp0_clock: ssp0_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ ssp0_mux: ssp0_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&pll1_96 &pll1_48 &pll1_24 &pll1_12>;
+ marvell,reg-offset = <0 0x81c>;
+ marvell,mmp-clk-bits-mux = <3 4>;
+ };
+ ssp0_gate: ssp0_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x81c>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ };
+ ssp1_clock: ssp1_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ ssp1_mux: ssp1_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&pll1_96 &pll1_48 &pll1_24 &pll1_12>;
+ marvell,reg-offset = <0 0x820>;
+ marvell,mmp-clk-bits-mux = <3 4>;
+ };
+ ssp1_gate: ssp1_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x820>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ };
+ };
+ apbcp_clock: apbcp_clock {
+ compatible = "marvell,mmp-clk-master";
+ reg = <0xd403b000 0x1000>;
+ uart2_clock: uart2_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ uart2_mux: uart2_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&pll1_3_16 &uart_pll>;
+ marvell,reg-offset = <0 0x70>;
+ marvell,mmp-clk-bits-mux = <1 4>;
+ };
+ uart2_gate: uart2_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x4>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x0>;
+ };
+ };
+ twsi1_clock: twsi1_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&pll1_13_1_5>;
+ marvell,reg-offset = <0 0x28>;
+ marvell,mmp-clk-mask = <0x7 0x3 0x4>;
+ };
+ };
+ apmu_clocks: apmu_clocks {
+ compatible = "marvell,mmp-clk-master";
+ reg = <0xd4282800 0x1000>;
+ sdh0_clock: sdh0_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ sdh0_mux: sdh0_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&pll1_12 &pll1_13>;
+ marvell,reg-offset = <0 0x54>;
+ marvell,mmp-clk-bits-mux = <1 6>;
+ };
+ sdh0_gate: sdh0_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x54>;
+ marvell,mmp-clk-mask = <0x1b 0x1b 0x0>;
+ };
+ };
+ sdh1_clock: sdh1_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ sdh1_mux: sdh1_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&pll1_12 &pll1_13>;
+ marvell,reg-offset = <0 0x58>;
+ marvell,mmp-clk-bits-mux = <1 6>;
+ };
+ sdh1_gate: sdh1_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x58>;
+ marvell,mmp-clk-mask = <0x1b 0x1b 0x0>;
+ };
+ };
+ usb_clock: usb_clock {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x5c>;
+ marvell,mmp-clk-mask = <0x9 0x9 0x0>;
+ };
+ sph_clock: sph_clock {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x5c>;
+ marvell,mmp-clk-mask = <0x12 0x12 0x0>;
+ };
+ disp0_clock: disp0_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ disp0_mux: disp0_mux {
+ compatible = "marvell,mmp-clk-mux";
+ marvell,reg-offset = <0 0x4c>;
+ clocks = <&pll1_2 &pll1_12>;
+ marvell,mmp-clk-bits-mux = <1 6>;
+ };
+ disp0_gate: disp0_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x4c>;
+ marvell,mmp-clk-mask = <0x1b 0x1b 0x0>;
+ };
+ };
+ ccic0_mux: ccic0_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&pll1_2 &pll1_12>;
+ marvell,reg-offset = <0 0x50>;
+ marvell,mmp-clk-bits-mux = <1 6>;
+ };
+ ccic0_clock: ccic0_clock {
+ compatible = "marvell,mmp-clk-gate";
+ clocks = <&ccic0_mux>;
+ marvell,reg-offset = <0 0x50>;
+ marvell,mmp-clk-mask = <0x1b 0x1b 0x0>;
+ };
+ ccic0_phy_clock: ccic0_phy_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ ccic0_phy_mux: ccic0_phy_mux {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-mux";
+ clocks = <&pll1_2 &pll1_12>;
+ marvell,reg-offset = <0 0x50>;
+ marvell,mmp-clk-bits-mux = <1 7>;
+ };
+ ccic0_phy_gate: ccic0_phy_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x50>;
+ marvell,mmp-clk-mask = <0x24 0x24 0x0>;
+ };
+ };
+ ccic0_sphy_clock: ccic0_sphy_clock {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-general-composite";
+ ccic0_sphy_div: ccic0_sphy_div {
+ #clock-cells = <0>;
+ compatible = "marvell,mmp-clk-div";
+ clocks = <&ccic0_mux>;
+ marvell,reg-offset = <0 0x50>;
+ marvell,mmp-clk-bits-div = <5 10>;
+ };
+ ccic0_sphy_gate: ccic0_sphy_gate {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x50>;
+ marvell,mmp-clk-mask = <0x300 0x300 0x0>;
+ };
+ };
+
+ };
+};
diff --git a/arch/arm/boot/dts/pxa910.dtsi b/arch/arm/boot/dts/pxa910.dtsi
index 0247c62..cc06c5d 100644
--- a/arch/arm/boot/dts/pxa910.dtsi
+++ b/arch/arm/boot/dts/pxa910.dtsi
@@ -71,6 +71,7 @@
compatible = "mrvl,mmp-uart";
reg = <0xd4017000 0x1000>;
interrupts = <27>;
+ clocks = <&uart0_clock>;
status = "disabled";
};

@@ -78,6 +79,7 @@
compatible = "mrvl,mmp-uart";
reg = <0xd4018000 0x1000>;
interrupts = <28>;
+ clocks = <&uart1_clock>;
status = "disabled";
};

@@ -85,6 +87,7 @@
compatible = "mrvl,mmp-uart";
reg = <0xd4036000 0x1000>;
interrupts = <59>;
+ clocks = <&uart2_clock>;
status = "disabled";
};

@@ -93,6 +96,7 @@
#address-cells = <1>;
#size-cells = <1>;
reg = <0xd4019000 0x1000>;
+ clocks = <&gpio_clock>;
gpio-controller;
#gpio-cells = <2>;
interrupts = <49>;
@@ -124,6 +128,7 @@
#size-cells = <0>;
reg = <0xd4011000 0x1000>;
interrupts = <7>;
+ clocks = <&twsi0_clock>;
mrvl,i2c-fast-mode;
status = "disabled";
};
@@ -134,6 +139,7 @@
#size-cells = <0>;
reg = <0xd4037000 0x1000>;
interrupts = <54>;
+ clocks = <&twsi1_clock>;
status = "disabled";
};

@@ -142,8 +148,12 @@
reg = <0xd4010000 0x1000>;
interrupts = <5 6>;
interrupt-names = "rtc 1Hz", "rtc alarm";
+ clocks = <&rtc_clock>;
status = "disabled";
};
};
+ soc_clocks: clocks{
+ };
};
};
+/include/ "pxa910-clock.dtsi"
diff --git a/arch/arm/mach-mmp/Kconfig b/arch/arm/mach-mmp/Kconfig
index ebdba87..ce15826 100644
--- a/arch/arm/mach-mmp/Kconfig
+++ b/arch/arm/mach-mmp/Kconfig
@@ -86,8 +86,8 @@ config MACH_GPLUGD

config MACH_MMP_DT
bool "Support MMP (ARMv5) platforms from device tree"
- select CPU_PXA168
- select CPU_PXA910
+ select COMMON_CLK
+ select CPU_MOHAWK
select USE_OF
select PINCTRL
select PINCTRL_SINGLE
@@ -99,7 +99,8 @@ config MACH_MMP_DT
config MACH_MMP2_DT
bool "Support MMP2 (ARMv7) platforms from device tree"
depends on !CPU_MOHAWK
- select CPU_MMP2
+ select COMMON_CLK
+ select CPU_PJ4
select USE_OF
select PINCTRL
select PINCTRL_SINGLE
diff --git a/arch/arm/mach-mmp/Makefile b/arch/arm/mach-mmp/Makefile
index 98f0f63..ab54ff3 100644
--- a/arch/arm/mach-mmp/Makefile
+++ b/arch/arm/mach-mmp/Makefile
@@ -31,6 +31,6 @@ obj-$(CONFIG_MACH_BROWNSTONE) += brownstone.o
obj-$(CONFIG_MACH_FLINT) += flint.o
obj-$(CONFIG_MACH_MARVELL_JASPER) += jasper.o
obj-$(CONFIG_MACH_MMP_DT) += mmp-dt.o
-obj-$(CONFIG_MACH_MMP2_DT) += mmp2-dt.o
+obj-$(CONFIG_MACH_MMP2_DT) += mmp-dt.o
obj-$(CONFIG_MACH_TETON_BGA) += teton_bga.o
obj-$(CONFIG_MACH_GPLUGD) += gplugd.o
diff --git a/arch/arm/mach-mmp/common.h b/arch/arm/mach-mmp/common.h
index cf445ba..9dcf19c 100644
--- a/arch/arm/mach-mmp/common.h
+++ b/arch/arm/mach-mmp/common.h
@@ -8,3 +8,4 @@ extern void mmp_restart(enum reboot_mode, const char *);
extern void __init pxa168_clk_init(void);
extern void __init pxa910_clk_init(void);
extern void __init mmp2_clk_init(void);
+extern void mmp_clk_of_init(void);
diff --git a/arch/arm/mach-mmp/mmp-dt.c b/arch/arm/mach-mmp/mmp-dt.c
index cca529c..714735e 100644
--- a/arch/arm/mach-mmp/mmp-dt.c
+++ b/arch/arm/mach-mmp/mmp-dt.c
@@ -13,61 +13,42 @@
#include <linux/of_platform.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
+#include <asm/hardware/cache-tauros2.h>

#include "common.h"

extern void __init mmp_dt_init_timer(void);

-static const struct of_dev_auxdata pxa168_auxdata_lookup[] __initconst = {
- OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4017000, "pxa2xx-uart.0", NULL),
- OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4018000, "pxa2xx-uart.1", NULL),
- OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4026000, "pxa2xx-uart.2", NULL),
- OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4011000, "pxa2xx-i2c.0", NULL),
- OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4025000, "pxa2xx-i2c.1", NULL),
- OF_DEV_AUXDATA("marvell,mmp-gpio", 0xd4019000, "mmp-gpio", NULL),
- OF_DEV_AUXDATA("mrvl,mmp-rtc", 0xd4010000, "sa1100-rtc", NULL),
- {}
-};
-
-static const struct of_dev_auxdata pxa910_auxdata_lookup[] __initconst = {
- OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4017000, "pxa2xx-uart.0", NULL),
- OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4018000, "pxa2xx-uart.1", NULL),
- OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4036000, "pxa2xx-uart.2", NULL),
- OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4011000, "pxa2xx-i2c.0", NULL),
- OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4037000, "pxa2xx-i2c.1", NULL),
- OF_DEV_AUXDATA("marvell,mmp-gpio", 0xd4019000, "mmp-gpio", NULL),
- OF_DEV_AUXDATA("mrvl,mmp-rtc", 0xd4010000, "sa1100-rtc", NULL),
- {}
-};
-
-static void __init pxa168_dt_init(void)
-{
- of_platform_populate(NULL, of_default_bus_match_table,
- pxa168_auxdata_lookup, NULL);
-}
-
-static void __init pxa910_dt_init(void)
-{
- of_platform_populate(NULL, of_default_bus_match_table,
- pxa910_auxdata_lookup, NULL);
-}
-
static const char *mmp_dt_board_compat[] __initdata = {
"mrvl,pxa168-aspenite",
"mrvl,pxa910-dkb",
+ "mrvl,mmp2-brownstone",
NULL,
};

+void __init mmp_init_timer(void)
+{
+#ifdef CONFIG_CACHE_TAUROS2
+ tauros2_init(0);
+#endif
+ mmp_clk_of_init();
+ mmp_dt_init_timer();
+}
+
DT_MACHINE_START(PXA168_DT, "Marvell PXA168 (Device Tree Support)")
.map_io = mmp_map_io,
- .init_time = mmp_dt_init_timer,
- .init_machine = pxa168_dt_init,
+ .init_time = mmp_init_timer,
.dt_compat = mmp_dt_board_compat,
MACHINE_END

DT_MACHINE_START(PXA910_DT, "Marvell PXA910 (Device Tree Support)")
.map_io = mmp_map_io,
- .init_time = mmp_dt_init_timer,
- .init_machine = pxa910_dt_init,
+ .init_time = mmp_init_timer,
+ .dt_compat = mmp_dt_board_compat,
+MACHINE_END
+
+DT_MACHINE_START(MMP2_DT, "Marvell MMP2 (Device Tree Support)")
+ .map_io = mmp_map_io,
+ .init_time = mmp_init_timer,
.dt_compat = mmp_dt_board_compat,
MACHINE_END
diff --git a/arch/arm/mach-mmp/mmp2-dt.c b/arch/arm/mach-mmp/mmp2-dt.c
deleted file mode 100644
index 023cb45..0000000
--- a/arch/arm/mach-mmp/mmp2-dt.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * linux/arch/arm/mach-mmp/mmp2-dt.c
- *
- * Copyright (C) 2012 Marvell Technology Group Ltd.
- * Author: Haojian Zhuang <[email protected]>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * publishhed by the Free Software Foundation.
- */
-
-#include <linux/io.h>
-#include <linux/irqchip.h>
-#include <linux/of_platform.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/time.h>
-
-#include "common.h"
-
-extern void __init mmp_dt_init_timer(void);
-
-static const struct of_dev_auxdata mmp2_auxdata_lookup[] __initconst = {
- OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4030000, "pxa2xx-uart.0", NULL),
- OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4017000, "pxa2xx-uart.1", NULL),
- OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4018000, "pxa2xx-uart.2", NULL),
- OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4016000, "pxa2xx-uart.3", NULL),
- OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4011000, "pxa2xx-i2c.0", NULL),
- OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4025000, "pxa2xx-i2c.1", NULL),
- OF_DEV_AUXDATA("marvell,mmp-gpio", 0xd4019000, "mmp2-gpio", NULL),
- OF_DEV_AUXDATA("mrvl,mmp-rtc", 0xd4010000, "sa1100-rtc", NULL),
- {}
-};
-
-static void __init mmp2_dt_init(void)
-{
- of_platform_populate(NULL, of_default_bus_match_table,
- mmp2_auxdata_lookup, NULL);
-}
-
-static const char *mmp2_dt_board_compat[] __initdata = {
- "mrvl,mmp2-brownstone",
- NULL,
-};
-
-DT_MACHINE_START(MMP2_DT, "Marvell MMP2 (Device Tree Support)")
- .map_io = mmp_map_io,
- .init_time = mmp_dt_init_timer,
- .init_machine = mmp2_dt_init,
- .dt_compat = mmp2_dt_board_compat,
-MACHINE_END
--
1.8.3.2

2014-06-10 01:28:35

by Chao Xie

[permalink] [raw]
Subject: [PATCH 11/12] clk: mmp: add device tree support for clocks.

From: Chao Xie <[email protected]>

For MMP series SOC, it will use some types of clock.
Add the device tree support for these kind of clocks.
It includes mux/div/mix/gate/factor clock.

Signed-off-by: Chao Xie <[email protected]>

Conflicts:
drivers/clk/mmp/Makefile
---
.../devicetree/bindings/clock/mmp/clk-div | 28 +
.../devicetree/bindings/clock/mmp/clk-factor | 28 +
.../devicetree/bindings/clock/mmp/clk-gate | 41 ++
.../devicetree/bindings/clock/mmp/clk-mix | 38 ++
.../devicetree/bindings/clock/mmp/clk-mux | 20 +
drivers/clk/mmp/Makefile | 2 +-
drivers/clk/mmp/clk-of.c | 689 +++++++++++++++++++++
7 files changed, 845 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/clock/mmp/clk-div
create mode 100644 Documentation/devicetree/bindings/clock/mmp/clk-factor
create mode 100644 Documentation/devicetree/bindings/clock/mmp/clk-gate
create mode 100644 Documentation/devicetree/bindings/clock/mmp/clk-mix
create mode 100644 Documentation/devicetree/bindings/clock/mmp/clk-mux
create mode 100644 drivers/clk/mmp/clk-of.c

diff --git a/Documentation/devicetree/bindings/clock/mmp/clk-div b/Documentation/devicetree/bindings/clock/mmp/clk-div
new file mode 100644
index 0000000..62eb7d5
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/mmp/clk-div
@@ -0,0 +1,28 @@
+Binding for div type clock
+
+The div clock is defined as common clock.
+
+
+Required properties
+- compatible : It should be "marvell,mmp-clk-div".
+- clocks : The parents of the clock.
+- marvell,mmp-clk-bits-div : The width and shift of divider bits.
+
+Optional properties:
+- marvell,mmp-clk-div-power-of-two : The value of divider is a power of two.
+- marvell,mmp-clk-div-one-based : The value of divider starts from 1.
+- marvell,mmp-clk-div-table : The value of divider is not continous, and need
+ a table to record it.
+
+
+Examples
+apmu_clk {
+ compatible = "marvell,mmp-clk-master";
+ reg = <0xd4282800 0x1000>;
+ dsi_phy_slow_div: dsi_phy_slow_div {
+ compatible = "marvell,mmp-clk-div";
+ marvell,reg-offset = <0 0x44>;
+ clocks = <&vctcxo>;
+ marvell,mmp-clk-bits-div = <5 6>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/clock/mmp/clk-factor b/Documentation/devicetree/bindings/clock/mmp/clk-factor
new file mode 100644
index 0000000..9e1816c
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/mmp/clk-factor
@@ -0,0 +1,28 @@
+Binding for Marvell MMP series factor clock
+
+The factor clock is calculated by
+ Fout = (Fin * (den / num)) / factor;
+
+Required properties
+- compatible : It should be "marvell,mmp-clk-factor";
+- clock: The parent of the clock.
+- marvell,mmp-clk-factor-factor : The "factor" of the clock.
+- marvell,mmp-clk-factor-bits-num : The width and shift of bits for "num".
+- marvell,mmp-clk-factor-bits-den : The width and shift of bits for "dev".
+- marvell,mmp-clk-factor-table : The table of (num, den) for the clock.
+
+Examples
+mpmu_clocks: mpmu_clocks {
+ compatible = "marvell,mmp-clk-master";
+ reg = <0xd4050000 0x1000>;
+ uart_pll: uart_pll {
+ compatible = "marvell,mmp-clk-factor";
+ clocks = <&pll1_4>;
+ marvell,reg-offset = <0 0x14>;
+ marvell,mmp-clk-factor-factor = <2>;
+ marvell,mmp-clk-factor-bits-den = <13 0>;
+ marvell,mmp-clk-factor-bits-num = <13 16>;
+ marvell,mmp-clk-factor-table = <8125 1536>;
+ };
+};
++
diff --git a/Documentation/devicetree/bindings/clock/mmp/clk-gate b/Documentation/devicetree/bindings/clock/mmp/clk-gate
new file mode 100644
index 0000000..5da6c63
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/mmp/clk-gate
@@ -0,0 +1,41 @@
+Binding for Marvell MMP series gate clock and common gate clock
+
+There two type of gate clock used by Marvell MMP series SOC.
+The common gate clock and the gate clock defined for MMP series SOC.
+
+For common gate clock
+
+Required properties
+- compatible : It should be "marvell,mmp-clk-general-gate";
+- clock : The parent of the clock.
+- marvell,mmp-clk-bit-gate : The offset of the bit control the gate.
+
+Examples
+apmu_clocks: apmu_clocks {
+ compatible = "marvell,mmp-clk-master";
+ reg = <0xd4282800 0x1000>;
+ pll1_416_gate: pll1_416_gate {
+ compatible = "marvell,mmp-clk-general-gate";
+ clocks = <&pll1_416m>;
+ marvell,reg-offset = <0 0x40>;
+ marvell,mmp-clk-bit-gate = <27>;
+ };
+};
+
+For MMP series gate clock
+
+Required properties
+- compatible : It should be "marvell,mmp-clk-gate";
+- clock : The parent of the clock.
+- marvell,mmp-clk-mask : The (mask, val_enable, val_disable) for the clock.
+
+Examples
+apmu_clocks: apmu_clocks {
+ compatible = "marvell,mmp-clk-master";
+ reg = <0xd4282800 0x1000>;
+ usb_clock: usb_clock {
+ compatible = "marvell,mmp-clk-gate";
+ marvell,reg-offset = <0 0x5c>;
+ marvell,mmp-clk-mask = <0x9 0x9 0x1>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/clock/mmp/clk-mix b/Documentation/devicetree/bindings/clock/mmp/clk-mix
new file mode 100644
index 0000000..8cf9b38
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/mmp/clk-mix
@@ -0,0 +1,38 @@
+Binding for Marvell MMP series mix clock
+
+The mix clock is a combination of mux and div clock. It need to
+change the bits of mux and div together.
+
+
+Required properties
+- compatible : It should be "marvell,mmp-clk-mix".
+- clocks : The parents of the clock.
+- marvell,mmp-clk-bits-div : The width and shift of divider bits.
+- marvell,mmp-clk-bits-mux : The width and shift of divider bits.
+- marvell,mmp-clk-bit-fc : The offset of the frequency change bit.
+- marvell,mmp-clk-mix-table : The array of (rate, parent_index). The rate
+ means the clock's rate, and parent_index means
+ the suggested parent index from user.
+
+Optional properties:
+- marvell,mmp-clk-div-power-of-two : The value of divider is a power of two.
+- marvell,mmp-clk-div-one-based : The value of divider starts from 1.
+- marvell,mmp-clk-div-table : The value of divider is not continous, and need
+ a table to record it.
+
+
+Exampels
+
+apmu_clk {
+ compatible = "marvell,mmp-clk-master";
+ reg = <0xd4282800 0x1000>;
+ lcd_clk {
+ compatible = "marvell,mmp-clk-mix";
+ clocks = <&pll1_416m &pll1_624 &pll2 &pll2p>;
+ marvell,reg-offset = <0 0x4c>;
+ marvell,mmp-clk-bits-mux = <2 17>;
+ marvell,mmp-clk-bits-div = <3 19>;
+ marvell,mmp-clk-bit-fc = <22>;
+ };
+};
+
diff --git a/Documentation/devicetree/bindings/clock/mmp/clk-mux b/Documentation/devicetree/bindings/clock/mmp/clk-mux
new file mode 100644
index 0000000..f5bb4dd
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/mmp/clk-mux
@@ -0,0 +1,20 @@
+Binding for mux type clock
+
+The mux clock is defined as common clock.
+
+Required properties
+- compatible : It should be "marvell,mmp-clk-mux".
+- clocks : The parents of the clock.
+- marvell,mmp-clk-bits-mux : The width and shift of mux bits.
+
+Examples
+apmu_clk {
+ compatible = "marvell,mmp-clk-master";
+ reg = <0xd4282800 0x1000>;
+ dsi_phy_esc_mux: dsi_phy_esc_mux {
+ compatible = "marvell,mmp-clk-mux";
+ marvell,reg-offset = <0 0x44>;
+ clocks = <&pll1_12 &pll1_13 &vctcxo &pll1_8>;
+ marvell,mmp-clk-bits-mux = <2 0>;
+ };
+};
diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile
index 84dce78..e29c6f1 100644
--- a/drivers/clk/mmp/Makefile
+++ b/drivers/clk/mmp/Makefile
@@ -6,7 +6,7 @@ obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o clk-gate.o \
clk-mix-composite.o

ifneq ($(CONFIG_OF),)
-obj-y += clk-master-node.o lock.o clk-of-composite.o
+obj-y += clk-master-node.o lock.o clk-of-composite.o clk-of.o
endif

obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
diff --git a/drivers/clk/mmp/clk-of.c b/drivers/clk/mmp/clk-of.c
new file mode 100644
index 0000000..2bba7ee
--- /dev/null
+++ b/drivers/clk/mmp/clk-of.c
@@ -0,0 +1,689 @@
+/*
+ * mmp mix(div and mux) clock operation source file
+ *
+ * Copyright (C) 2014 Marvell
+ * Chao Xie <[email protected]>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/of.h>
+
+#include "clk.h"
+
+static int of_mmp_clk_get_flags(struct device_node *np,
+ unsigned long *flags)
+{
+ *flags = 0;
+
+ return 0;
+}
+
+static int of_mmp_clk_get_bits(struct device_node *np, const char *name,
+ u8 *width, u8 *shift)
+{
+ int ret;
+ u32 tmp[2];
+
+ ret = of_property_read_u32_array(np, name, tmp, 2);
+ if (ret) {
+ pr_err("%s:%s failed to read bits %s\n",
+ __func__, np->name, name);
+ return -EINVAL;
+ }
+
+ *width = tmp[0];
+ *shift = tmp[1];
+
+ return 0;
+}
+
+static int of_mmp_clk_div_dt_parse(struct device_node *np, u8 *shift,
+ u8 *width,
+ struct clk_div_table **ptable,
+ u8 *div_flags)
+{
+ int i, ret;
+ const __be32 *prop;
+ unsigned int proplen;
+ struct clk_div_table *table;
+ unsigned int size;
+
+ ret = of_mmp_clk_get_bits(np, "marvell,mmp-clk-bits-div",
+ width, shift);
+ if (ret)
+ return ret;
+
+ *div_flags = 0;
+ if (of_property_read_bool(np, "marvell,mmp-clk-div-power-of-two"))
+ *div_flags |= CLK_DIVIDER_POWER_OF_TWO;
+ else if (of_property_read_bool(np, "marvell,mmp-clk-div-one-based"))
+ *div_flags |= CLK_DIVIDER_ONE_BASED;
+
+ if (ptable)
+ *ptable = NULL;
+
+ prop = of_get_property(np, "marvell,mmp-clk-div-table", &proplen);
+ if (prop) {
+ if (!ptable)
+ return -EINVAL;
+
+ size = proplen / sizeof(u32);
+ if ((proplen % sizeof(u32)) || size % 2) {
+ pr_err("%s:%s marvell,mmp-clk-mix-table wrong value\n",
+ __func__, np->name);
+ return -EINVAL;
+ }
+ table = kzalloc(sizeof(*table) * (size / 2 + 1), GFP_KERNEL);
+ if (!table) {
+ pr_err("%s:%s failed to allocate table\n",
+ __func__, np->name);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < size; i += 2) {
+ table[i / 2].val = be32_to_cpup(prop + i);
+ table[i / 2].div = be32_to_cpup(prop + i + 1);
+ }
+ /* For safe. */
+ table[i / 2].val = 0;
+ table[i / 2].div = 0;
+
+ *ptable = table;
+ }
+
+ return 0;
+}
+
+static int of_mmp_clk_mux_dt_parse(struct device_node *np, u8 *shift,
+ u8 *width, u8 *mux_flags)
+{
+ int ret;
+
+ ret = of_mmp_clk_get_bits(np, "marvell,mmp-clk-bits-mux",
+ width, shift);
+ if (ret)
+ return ret;
+
+ *mux_flags = 0;
+
+ return 0;
+}
+
+static int of_mmp_clk_general_gate_dt_parse(struct device_node *np,
+ u8 *bit_idx, u8 *gate_flags)
+{
+ int ret;
+ u32 tmp;
+
+ ret = of_property_read_u32(np, "marvell,mmp-clk-bit-gate", &tmp);
+ if (ret) {
+ pr_err("%s:%s can not find marvell,mmp-clk-bit-gate\n",
+ __func__, np->name);
+ return -EINVAL;
+ }
+ *bit_idx = tmp;
+
+ *gate_flags = 0;
+
+ return 0;
+}
+
+static int of_mmp_clk_gate_dt_parse(struct device_node *np,
+ u32 *mask, u32 *val_enable, u32 *val_disable,
+ unsigned int *gate_flags)
+{
+ int ret;
+ u32 tmp[3];
+
+ ret = of_property_read_u32_array(np, "marvell,mmp-clk-mask", tmp, 3);
+ if (ret) {
+ pr_err("%s:%s can not find marvell,mmp-clk-mask\n",
+ __func__, np->name);
+ return -EINVAL;
+ }
+ *mask = tmp[0];
+ *val_enable = tmp[1];
+ *val_disable = tmp[2];
+
+ *gate_flags = 0;
+ if (of_property_read_bool(np, "marvell,mmp-clk-gate-need-delay"))
+ *gate_flags |= MMP_CLK_GATE_NEED_DELAY;
+
+ return 0;
+}
+
+
+static int of_mmp_clk_mix_dt_parse(struct device_node *np,
+ struct mmp_clk_mix_config *config,
+ spinlock_t **plock)
+{
+ struct mmp_clk_mix_reg_info *ri;
+ struct mmp_clk_mix_clk_table *table;
+ int i, ret, size;
+ u32 tmp;
+ spinlock_t *lock;
+ void __iomem *reg;
+ unsigned int reg_phys;
+ const __be32 *prop;
+ unsigned int proplen;
+
+ ri = &config->reg_info;
+ ret = of_mmp_clk_div_dt_parse(np, &ri->shift_div, &ri->width_div,
+ NULL, &config->div_flags);
+ if (ret)
+ return ret;
+
+ ret = of_mmp_clk_mux_dt_parse(np, &ri->shift_mux, &ri->width_mux,
+ &config->mux_flags);
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u32(np, "marvell,mmp-clk-bit-fc", &tmp);
+ if (ret)
+ ri->bit_fc = (u8)-1;
+ else
+ ri->bit_fc = tmp;
+
+ reg = of_mmp_clk_get_reg(np, 0, &reg_phys);
+ if (!reg)
+ return -EINVAL;
+ ri->reg_clk_ctrl = reg;
+
+ lock = of_mmp_clk_get_spinlock(np, reg_phys);
+ if (!lock)
+ return -EINVAL;
+
+ *plock = lock;
+ reg = of_mmp_clk_get_reg(np, 1, &reg_phys);
+ if (reg)
+ ri->reg_clk_sel = reg;
+
+ prop = of_get_property(np, "marvell,mmp-clk-mix-table", &proplen);
+ if (prop) {
+ size = proplen / sizeof(u32);
+ if ((proplen % sizeof(u32)) || size % 2) {
+ pr_err("%s:%s marvell,mmp-clk-mix-table wrong value\n",
+ __func__, np->name);
+ return -EINVAL;
+ }
+ table = kzalloc(sizeof(*table) * (size / 2), GFP_KERNEL);
+ if (!table) {
+ pr_err("%s:%s failed to allocate table\n",
+ __func__, np->name);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < size; i += 2) {
+ table[i / 2].rate = be32_to_cpup(prop + i);
+ table[i / 2].parent_index = be32_to_cpup(prop + i + 1);
+ }
+ config->table = table;
+ config->table_size = size / 2;
+ } else {
+ config->table = NULL;
+ config->table_size = 0;
+ }
+
+ return 0;
+}
+
+static int of_mmp_clk_factor_dt_parse(struct device_node *np,
+ struct mmp_clk_factor_masks **pmasks,
+ struct mmp_clk_factor_tbl **pftbl,
+ unsigned int *pftbl_cnt)
+{
+ struct mmp_clk_factor_masks *masks;
+ struct mmp_clk_factor_tbl *table;
+ u8 width, shift;
+ int i, ret, size;
+ u32 tmp;
+ const __be32 *prop;
+ unsigned int proplen;
+
+ masks = kzalloc(sizeof(*masks), GFP_KERNEL);
+ if (!masks) {
+ pr_err("%s:%s failed to allocate factor masks\n",
+ __func__, np->name);
+ return -ENOMEM;
+ }
+
+ ret = of_property_read_u32(np, "marvell,mmp-clk-factor-factor", &tmp);
+ if (ret) {
+ pr_err("%s:%s can not find marvell,mmp-clk-factor-num\n",
+ __func__, np->name);
+ return -EINVAL;
+ }
+ masks->factor = tmp;
+
+ ret = of_mmp_clk_get_bits(np, "marvell,mmp-clk-factor-bits-num",
+ &width, &shift);
+ if (ret)
+ return ret;
+ masks->num_mask = BIT(width) - 1;
+ masks->num_shift = shift;
+
+ ret = of_mmp_clk_get_bits(np, "marvell,mmp-clk-factor-bits-den",
+ &width, &shift);
+ if (ret)
+ return ret;
+ masks->den_mask = BIT(width) - 1;
+ masks->den_shift = shift;
+ *pmasks = masks;
+
+ prop = of_get_property(np, "marvell,mmp-clk-factor-table", &proplen);
+ if (!prop) {
+ pr_err("%s:%s failed to get marvell,mmp-clk-factor-table\n",
+ __func__, np->name);
+ return -EINVAL;
+ }
+
+ size = proplen / sizeof(u32);
+ if ((proplen % sizeof(u32)) || size % 2) {
+ pr_err("%s:%s marvell,mmp-clk-factor-table wrong value\n",
+ __func__, np->name);
+ return -EINVAL;
+ }
+ table = kzalloc(sizeof(*table) * (size / 2), GFP_KERNEL);
+ if (!table) {
+ pr_err("%s:%s failed to allocate table\n",
+ __func__, np->name);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < size; i += 2) {
+ table[i / 2].num = be32_to_cpup(prop + i);
+ table[i / 2].den = be32_to_cpup(prop + i + 1);
+ }
+ *pftbl = table;
+ *pftbl_cnt = size / 2;
+
+ return 0;
+}
+
+static void of_mmp_clk_mix_setup(struct device_node *np)
+{
+ struct mmp_clk_mix *mix;
+ struct mmp_clk_mix_config config;
+ struct clk *clk;
+ spinlock_t *lock;
+ unsigned int num_parents;
+ const char **parent_names;
+ int i, ret;
+
+ ret = of_mmp_clk_mix_dt_parse(np, &config, &lock);
+ if (ret)
+ return;
+
+ if (of_mmp_clk_is_composite(np)) {
+ mix = kzalloc(sizeof(*mix), GFP_KERNEL);
+ if (!mix) {
+ pr_err("%s:%s failed to allocate clk\n",
+ __func__, np->name);
+ return;
+ }
+ memcpy(&mix->reg_info, &config.reg_info,
+ sizeof(config.reg_info));
+ mix->div_flags = config.div_flags;
+ mix->mux_flags = config.mux_flags;
+ mix->lock = lock;
+ if (config.table) {
+ mix->table = config.table;
+ mix->table_size = config.table_size;
+ }
+
+ of_mmp_clk_composite_add_member(np, &mix->hw, &mmp_clk_mix_ops,
+ MMP_CLK_COMPOSITE_TYPE_MUXMIX);
+ } else {
+ num_parents = of_clk_get_parent_count(np);
+ parent_names = kcalloc(num_parents, sizeof(char *),
+ GFP_KERNEL);
+ if (!parent_names) {
+ pr_err("%s:%s failed to allocate parent_names\n",
+ __func__, np->name);
+ return;
+ }
+ for (i = 0; i < num_parents; i++)
+ parent_names[i] = of_clk_get_parent_name(np, i);
+
+ clk = mmp_clk_register_mix(NULL, np->name, num_parents,
+ parent_names, 0, &config, lock);
+
+ if (IS_ERR(clk)) {
+ kfree(parent_names);
+
+ pr_err("%s:%s failed to register clk\n",
+ __func__, np->name);
+ return;
+ }
+
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ }
+}
+CLK_OF_DECLARE(mmp_clk_mix, "marvell,mmp-clk-mix",
+ of_mmp_clk_mix_setup);
+
+static void of_mmp_clk_div_setup(struct device_node *np)
+{
+ struct clk_divider *div;
+ void __iomem *reg;
+ u8 width, shift, div_flags;
+ struct clk_div_table *table;
+ unsigned long flags;
+ const char *parent_name;
+ struct clk *clk;
+ unsigned int reg_phys;
+ spinlock_t *lock;
+ int ret;
+
+ reg = of_mmp_clk_get_reg(np, 0, &reg_phys);
+ if (!reg)
+ return;
+
+ ret = of_mmp_clk_div_dt_parse(np, &shift, &width, &table, &div_flags);
+ if (ret)
+ return;
+
+ ret = of_mmp_clk_get_flags(np, &flags);
+ if (ret)
+ return;
+
+ lock = of_mmp_clk_get_spinlock(np, reg_phys);
+ if (!lock)
+ return;
+
+ if (of_mmp_clk_is_composite(np)) {
+ div = kzalloc(sizeof(*div), GFP_KERNEL);
+ if (!div) {
+ pr_err("%s:%s failed to allocate clk\n",
+ __func__, np->name);
+ return;
+ }
+ div->shift = shift;
+ div->width = width;
+ div->table = table;
+ div->flags = div_flags;
+ div->lock = lock;
+ div->reg = reg;
+
+ of_mmp_clk_composite_add_member(np, &div->hw, &clk_divider_ops,
+ MMP_CLK_COMPOSITE_TYPE_DIV);
+ } else {
+ parent_name = of_clk_get_parent_name(np, 0);
+
+ if (!table)
+ clk = clk_register_divider(NULL, np->name, parent_name,
+ flags, reg, shift, width, div_flags,
+ lock);
+ else
+ clk = clk_register_divider_table(NULL, np->name,
+ parent_name, flags, reg, shift, width,
+ div_flags, table, lock);
+ if (IS_ERR(clk)) {
+ pr_err("%s:%s failed to register clk\n",
+ __func__, np->name);
+ return;
+ }
+
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ }
+}
+CLK_OF_DECLARE(mmp_clk_div, "marvell,mmp-clk-div",
+ of_mmp_clk_div_setup);
+
+static void of_mmp_clk_mux_setup(struct device_node *np)
+{
+ struct clk_mux *mux;
+ void __iomem *reg;
+ u8 width, shift, mux_flags;
+ unsigned long flags;
+ spinlock_t *lock;
+ unsigned int num_parents;
+ const char **parent_names;
+ struct clk *clk;
+ unsigned int reg_phys;
+ int i, ret;
+
+ reg = of_mmp_clk_get_reg(np, 0, &reg_phys);
+ if (!reg)
+ return;
+
+ ret = of_mmp_clk_mux_dt_parse(np, &shift, &width, &mux_flags);
+ if (ret)
+ return;
+
+ ret = of_mmp_clk_get_flags(np, &flags);
+ if (ret)
+ return;
+
+ lock = of_mmp_clk_get_spinlock(np, reg_phys);
+ if (!lock)
+ return;
+
+ if (of_mmp_clk_is_composite(np)) {
+ mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+ if (!mux) {
+ pr_err("%s:%s failed to allocate clk\n",
+ __func__, np->name);
+ return;
+ }
+
+ mux->reg = reg;
+ mux->mask = BIT(width) - 1;
+ mux->shift = shift;
+ mux->lock = lock;
+ mux->flags = mux_flags;
+ of_mmp_clk_composite_add_member(np, &mux->hw, &clk_mux_ops,
+ MMP_CLK_COMPOSITE_TYPE_MUXMIX);
+ } else {
+ num_parents = of_clk_get_parent_count(np);
+ parent_names = kcalloc(num_parents, sizeof(char *),
+ GFP_KERNEL);
+ if (!parent_names) {
+ pr_err("%s:%s failed to allocate parent_names\n",
+ __func__, np->name);
+ return;
+ }
+ for (i = 0; i < num_parents; i++)
+ parent_names[i] = of_clk_get_parent_name(np, i);
+
+ clk = clk_register_mux(NULL, np->name, parent_names,
+ num_parents, flags,
+ reg, shift, width, mux_flags, lock);
+ if (IS_ERR(clk)) {
+ pr_err("%s:%s failed to register clk\n",
+ __func__, np->name);
+ return;
+ }
+
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ }
+}
+CLK_OF_DECLARE(mmp_clk_mux, "marvell,mmp-clk-mux",
+ of_mmp_clk_mux_setup);
+
+static void of_mmp_clk_general_gate_setup(struct device_node *np)
+{
+ struct clk_gate *gate;
+ void __iomem *reg;
+ u8 bit_idx, gate_flags;
+ unsigned long flags;
+ spinlock_t *lock;
+ const char *parent_name;
+ struct clk *clk;
+ unsigned int reg_phys;
+ int ret;
+
+ reg = of_mmp_clk_get_reg(np, 0, &reg_phys);
+ if (!reg)
+ return;
+
+ ret = of_mmp_clk_general_gate_dt_parse(np, &bit_idx, &gate_flags);
+ if (ret)
+ return;
+
+ ret = of_mmp_clk_get_flags(np, &flags);
+ if (ret)
+ return;
+
+ lock = of_mmp_clk_get_spinlock(np, reg_phys);
+ if (!lock)
+ return;
+
+ if (of_mmp_clk_is_composite(np)) {
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate) {
+ pr_err("%s:%s failed to allocate clk\n",
+ __func__, np->name);
+ return;
+ }
+ gate->bit_idx = bit_idx;
+ gate->flags = gate_flags;
+ gate->reg = reg;
+ gate->lock = lock;
+ of_mmp_clk_composite_add_member(np, &gate->hw, &clk_gate_ops,
+ MMP_CLK_COMPOSITE_TYPE_GATE);
+ } else {
+ parent_name = of_clk_get_parent_name(np, 0);
+
+ clk = clk_register_gate(NULL, np->name, parent_name, flags,
+ reg, bit_idx, gate_flags, lock);
+ if (IS_ERR(clk)) {
+ pr_err("%s:%s failed to register clk\n",
+ __func__, np->name);
+ return;
+ }
+
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ }
+}
+CLK_OF_DECLARE(mmp_clk_general_gate, "marvell,mmp-clk-general-gate",
+ of_mmp_clk_general_gate_setup);
+
+static void of_mmp_clk_gate_setup(struct device_node *np)
+{
+ struct mmp_clk_gate *gate;
+ void __iomem *reg;
+ u32 mask, val_enable, val_disable;
+ unsigned int gate_flags;
+ unsigned long flags;
+ spinlock_t *lock;
+ const char *parent_name;
+ struct clk *clk;
+ unsigned int reg_phys;
+ int ret;
+
+ reg = of_mmp_clk_get_reg(np, 0, &reg_phys);
+ if (!reg)
+ return;
+
+ ret = of_mmp_clk_gate_dt_parse(np, &mask, &val_enable, &val_disable,
+ &gate_flags);
+ if (ret)
+ return;
+
+ ret = of_mmp_clk_get_flags(np, &flags);
+ if (ret)
+ return;
+
+ lock = of_mmp_clk_get_spinlock(np, reg_phys);
+ if (!lock)
+ return;
+
+ if (of_mmp_clk_is_composite(np)) {
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate) {
+ pr_err("%s:%s failed to allocate clk\n",
+ __func__, np->name);
+ return;
+ }
+
+ gate->flags = gate_flags;
+ gate->mask = mask;
+ gate->val_enable = val_enable;
+ gate->val_disable = val_disable;
+ gate->reg = reg;
+ gate->lock = lock;
+ of_mmp_clk_composite_add_member(np, &gate->hw,
+ &mmp_clk_gate_ops,
+ MMP_CLK_COMPOSITE_TYPE_GATE);
+ } else {
+ parent_name = of_clk_get_parent_name(np, 0);
+
+ clk = mmp_clk_register_gate(NULL, np->name, parent_name, flags,
+ reg, mask, val_enable, val_disable,
+ gate_flags, lock);
+ if (IS_ERR(clk)) {
+ pr_err("%s:%s failed to register clk\n",
+ __func__, np->name);
+ return;
+ }
+
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ }
+}
+CLK_OF_DECLARE(mmp_clk_gate, "marvell,mmp-clk-gate",
+ of_mmp_clk_gate_setup);
+
+static void of_mmp_clk_factor_setup(struct device_node *np)
+{
+ void __iomem *reg;
+ struct mmp_clk_factor_masks *masks;
+ struct mmp_clk_factor_tbl *table;
+ unsigned int table_size;
+ unsigned long flags;
+ spinlock_t *lock;
+ const char *parent_name;
+ struct clk *clk;
+ unsigned int reg_phys;
+ int ret;
+
+ reg = of_mmp_clk_get_reg(np, 0, &reg_phys);
+ if (!reg)
+ return;
+
+ ret = of_mmp_clk_factor_dt_parse(np, &masks, &table, &table_size);
+ if (ret)
+ return;
+
+ ret = of_mmp_clk_get_flags(np, &flags);
+ if (ret)
+ return;
+
+ lock = of_mmp_clk_get_spinlock(np, reg_phys);
+ if (!lock)
+ return;
+
+ parent_name = of_clk_get_parent_name(np, 0);
+
+ clk = mmp_clk_register_factor(np->name, parent_name, flags,
+ reg, masks, table, table_size,
+ lock);
+ if (IS_ERR(clk)) {
+ pr_err("%s:%s failed to register clk\n", __func__, np->name);
+ return;
+ }
+
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+
+}
+CLK_OF_DECLARE(mmp_clk_factor,
+ "marvell,mmp-clk-factor",
+ of_mmp_clk_factor_setup);
+
+void mmp_clk_of_init(void)
+{
+ struct device_node *next;
+
+ next = NULL;
+ do {
+ next = of_mmp_clk_master_init(next);
+ } while (next);
+}
--
1.8.3.2

2014-06-10 01:28:19

by Chao Xie

[permalink] [raw]
Subject: [PATCH 09/12] clk: mmp: add spin lock automatic detection from device tree

From: Chao Xie <[email protected]>

For Marvell MMP series SOC, many clocks share same register.
In the operations of these clock, a spin lock is needed to avoid
confilicts.
When parse the clock from the device tree and register the clock,
we do not know whether it share the register with others.
So a common API is provided to get the spin lock for the clock based
on device tree support.
The general idea is record the node (clock device node, regsiter),
and before register a new clock, search the node list based on
register. If a node is found, return the shared spin lock, or create
a new.

Signed-off-by: Chao Xie <[email protected]>

Conflicts:
drivers/clk/mmp/Makefile
---
Documentation/devicetree/bindings/clock/mmp/lock | 44 +++++++
drivers/clk/mmp/Makefile | 2 +-
drivers/clk/mmp/clk.h | 5 +
drivers/clk/mmp/lock.c | 159 +++++++++++++++++++++++
4 files changed, 209 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/clock/mmp/lock
create mode 100644 drivers/clk/mmp/lock.c

diff --git a/Documentation/devicetree/bindings/clock/mmp/lock b/Documentation/devicetree/bindings/clock/mmp/lock
new file mode 100644
index 0000000..7e7b5bc
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/mmp/lock
@@ -0,0 +1,44 @@
+Binding of spin lock support for Marvell MMP series clock
+
+Because some clocks share same register, spinlock need to be used to avoid
+conflicts.
+
+The spin lock sharing detection is based on regsiter address, and it is
+automatically. To support some clocks, the spin lock is not based on
+register address, some properies are provided.
+The properites are used as part of clock's properties in clock device tree
+files.
+
+Optional properties:
+marvell,mmp-clk-spinlock-new : Skip the automatic detection based on
+ register address. Direclty create a new
+ spin lock.
+marvell,mmp-clk-spinlock : It is handle. It points to the clock that share
+ same spin lock.
+
+Examples:
+
+Assume that clk1, clk2, clk3 share same spin lock.
+
+apmu_clk {
+ compatible = "marvell,mmp-clk-master";
+ ...
+
+ clk1 {
+ ...
+ marvell,mmp-clk-spinlock-new;
+ ...
+ };
+
+ clk2 {
+ ...
+ mmp-clk-spinlock = <&clk1>;
+ ...
+ };
+
+ clk3 {
+ ...
+ mmp-clk-spinlock = <&clk1>;
+ ...
+ };
+};
diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile
index 518931e..e8810b6 100644
--- a/drivers/clk/mmp/Makefile
+++ b/drivers/clk/mmp/Makefile
@@ -6,7 +6,7 @@ obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o clk-gate.o \
clk-mix-composite.o

ifneq ($(CONFIG_OF),)
-obj-y += clk-master-node.o
+obj-y += clk-master-node.o lock.o
endif

obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
diff --git a/drivers/clk/mmp/clk.h b/drivers/clk/mmp/clk.h
index 6d8c3b3..e06a228 100644
--- a/drivers/clk/mmp/clk.h
+++ b/drivers/clk/mmp/clk.h
@@ -147,6 +147,11 @@ extern void __iomem *of_mmp_clk_get_reg(struct device_node *np,
struct device_node *of_mmp_clk_master_init(struct device_node *from);


+/* spin lock sharing support. */
+extern spinlock_t *of_mmp_clk_get_spinlock(struct device_node *np,
+ unsigned int reg_base);
+
+
extern struct clk *mmp_clk_register_pll2(const char *name,
const char *parent_name, unsigned long flags);
extern struct clk *mmp_clk_register_apbc(const char *name,
diff --git a/drivers/clk/mmp/lock.c b/drivers/clk/mmp/lock.c
new file mode 100644
index 0000000..e2e246c
--- /dev/null
+++ b/drivers/clk/mmp/lock.c
@@ -0,0 +1,159 @@
+/*
+ * mmp mix(div and mux) clock operation source file
+ *
+ * Copyright (C) 2014 Marvell
+ * Chao Xie <[email protected]>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/of.h>
+
+struct mmp_clk_spinlock_node {
+ struct device_node *share;
+ struct list_head node;
+};
+
+struct mmp_clk_spinlock {
+ spinlock_t lock;
+ struct device_node *owner;
+ unsigned int reg_base;
+ struct list_head share_list;
+ struct list_head node;
+};
+
+static LIST_HEAD(lock_list);
+
+static DEFINE_MUTEX(lock_mutex);
+
+static struct mmp_clk_spinlock_node *create_lock_node(struct device_node *np)
+{
+ struct mmp_clk_spinlock_node *node;
+
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node) {
+ pr_err("%s:%s failed to allocate spinlock node.\n",
+ __func__, np->name);
+ return NULL;
+ }
+
+ node->share = np;
+
+ return node;
+}
+
+static struct mmp_clk_spinlock *create_lock(struct device_node *np,
+ unsigned int reg_base)
+{
+ struct mmp_clk_spinlock *lock;
+
+ lock = kzalloc(sizeof(*lock), GFP_KERNEL);
+ if (!lock) {
+ pr_err("%s:%s failed to allocate spinlock.\n",
+ __func__, np->name);
+ return NULL;
+ }
+
+ lock->owner = np;
+ lock->reg_base = reg_base;
+ INIT_LIST_HEAD(&lock->node);
+ INIT_LIST_HEAD(&lock->share_list);
+ spin_lock_init(&lock->lock);
+
+ return lock;
+}
+
+static struct mmp_clk_spinlock *find_lock_by_np(struct device_node *np)
+{
+ struct mmp_clk_spinlock *lock;
+
+ list_for_each_entry(lock, &lock_list, node) {
+ if (lock->owner == np)
+ return lock;
+ }
+
+ return NULL;
+}
+
+static struct mmp_clk_spinlock *find_lock_by_reg_base(unsigned int reg_base)
+{
+ struct mmp_clk_spinlock *lock;
+
+ list_for_each_entry(lock, &lock_list, node) {
+ if (lock->reg_base == reg_base)
+ return lock;
+ }
+
+ return NULL;
+}
+
+spinlock_t *of_mmp_clk_get_spinlock(struct device_node *np,
+ unsigned int reg_base)
+{
+ struct mmp_clk_spinlock *lock;
+ struct mmp_clk_spinlock_node *node;
+ struct device_node *owner;
+
+ if (of_property_read_bool(np, "marvell,mmp-clk-spinlock-new")) {
+
+ mutex_lock(&lock_mutex);
+
+ lock = find_lock_by_np(np);
+ if (!lock) {
+ lock = create_lock(np, reg_base);
+ if (lock)
+ list_add(&lock->node, &lock_list);
+ }
+
+ mutex_unlock(&lock_mutex);
+
+ return &lock->lock;
+ }
+
+ if (of_find_property(np, "marvell,mmp-clk-spinlock", NULL)) {
+
+ mutex_lock(&lock_mutex);
+
+ owner = of_parse_phandle(np, "marvell,mmp-clk-spinlock", 0);
+ lock = find_lock_by_np(owner);
+ } else {
+
+ mutex_lock(&lock_mutex);
+
+ lock = find_lock_by_reg_base(reg_base);
+ }
+
+ if (!lock) {
+ lock = create_lock(np, reg_base);
+ if (lock)
+ list_add(&lock->node, &lock_list);
+ }
+
+ if (!lock) {
+ mutex_unlock(&lock_mutex);
+ pr_err("%s:%s failed to get spinlock\n", __func__, np->name);
+ return NULL;
+ }
+
+ node = create_lock_node(np);
+ if (!node) {
+ mutex_unlock(&lock_mutex);
+ pr_err("%s:%s failed to create spinlock node\n",
+ __func__, np->name);
+ return NULL;
+ }
+ node->share = np;
+ list_add(&node->node, &lock->share_list);
+
+ mutex_unlock(&lock_mutex);
+
+ return &lock->lock;
+}
+
--
1.8.3.2

2014-06-10 01:28:18

by Chao Xie

[permalink] [raw]
Subject: [PATCH 08/12] clk: mmp: add clock type master

From: Chao Xie <[email protected]>

To support device tree for clock, we need pass the register
base and range to the clock.
There are many clock share same range of registers.
For example, clk1 has register as 0xd4210010 while clk2
has 0xd42100c0. If we map the register seperately. There
will waste some space. If there are many clocks like that,
the waste will be huge.
clock type "master node" will map the register for all clocks
that listed as its child in DT file. Each clock will invoke
the APIs provided by "master node" to get its register base.
The following is a exmaple of master clock usage in DT file

apmu_clocks {
compatible = "marvell,mmp-clk-master";
reg = <0xd4210000 0x1000>;

ck1 {
marvell,reg-offset = <0 0x10>;
};

clk2 {
marvell,reg-offset = <0 0xc0>;
};
}

Signed-off-by: Chao Xie <[email protected]>
---
.../devicetree/bindings/clock/mmp/clk-master | 47 +++++
drivers/clk/mmp/Makefile | 4 +
drivers/clk/mmp/clk-master-node.c | 195 +++++++++++++++++++++
drivers/clk/mmp/clk.h | 7 +
4 files changed, 253 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/mmp/clk-master
create mode 100644 drivers/clk/mmp/clk-master-node.c

diff --git a/Documentation/devicetree/bindings/clock/mmp/clk-master b/Documentation/devicetree/bindings/clock/mmp/clk-master
new file mode 100644
index 0000000..b6acde1
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/mmp/clk-master
@@ -0,0 +1,47 @@
+Binding for Marvell MMP series master clock.
+
+The MMP related device tree support for clock based on the clock type not clock
+controller. So specific SOC, user need define the DT file for the clock such as
+pxa910-clock.dtsi.
+
+Almost all types of clock will need parameter as "register", and it will map the
+"register" before access it. If every clock map the "register" seperately, there
+will be a lot of waste.
+
+A master clock is defined for this kind of situation. It will be responsible for
+map the registers for all clocks that lists as its children in DT file.
+
+Required properties
+- compatible : It should be "marvell,mmp-clk-master".
+
+
+Optional properties:
+- reg : The register start and range the master clock covered.
+
+Optional properties for child node:
+- marvell,reg-offset : It is a two-values item - <register_index regiser_offset>.
+ Master node will map the registers for all its children. So
+ for the child it need to pass the information about register
+ index and offset. "register_index" indicates which register space
+ it from because master clock can have mutiple register space in
+ "reg". "register_offset" indicates the offset in the register
+ space.
+
+Examples
+There are two clocks, clk1 has register at 0xd4210010, and clk2 has register at
+0xd42100c0.
+
+apmu_clk {
+ compatible = "marvell,mmp-clk-master";
+ reg = <0xd4210000 0x1000>;
+
+ clk1 {
+ ...
+ marvell,reg-offset = <0 0x10>;
+ };
+
+ clk2 {
+ ...
+ marvell,reg-offset = <0 0xc0>;
+ };
+};
diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile
index 2cd7d94..518931e 100644
--- a/drivers/clk/mmp/Makefile
+++ b/drivers/clk/mmp/Makefile
@@ -5,6 +5,10 @@
obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o clk-gate.o \
clk-mix-composite.o

+ifneq ($(CONFIG_OF),)
+obj-y += clk-master-node.o
+endif
+
obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o
obj-$(CONFIG_CPU_MMP2) += clk-mmp2.o
diff --git a/drivers/clk/mmp/clk-master-node.c b/drivers/clk/mmp/clk-master-node.c
new file mode 100644
index 0000000..584f72f
--- /dev/null
+++ b/drivers/clk/mmp/clk-master-node.c
@@ -0,0 +1,195 @@
+/*
+ * mmp master clock source file
+ *
+ * Copyright (C) 2014 Marvell
+ * Chao Xie <[email protected]>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/ioport.h>
+
+#include "clk.h"
+
+#define MAX_REG 8
+
+struct mmp_clk_master_node {
+ unsigned int reg_base[MAX_REG];
+ void __iomem *reg[MAX_REG];
+ struct device_node *np;
+ struct list_head node;
+};
+
+static LIST_HEAD(master_list);
+static DEFINE_MUTEX(master_mutex);
+
+static void mmp_clk_master_setup(struct device_node *np)
+{
+ struct mmp_clk_master_node *node;
+ struct resource res;
+ int i, ret;
+
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node) {
+ pr_err("%s:%s failed to allocate master node.\n",
+ __func__, np->name);
+ return;
+ }
+
+ for (i = 0; i < MAX_REG; i++) {
+ ret = of_address_to_resource(np, i, &res);
+ if (ret)
+ break;
+ node->reg_base[i] = res.start;
+ node->reg[i] = ioremap(res.start, resource_size(&res));
+ if (!node->reg[i]) {
+ pr_err("%s:%s failed to map register.\n",
+ __func__, np->name);
+ goto error;
+ }
+ }
+
+ node->np = np;
+ INIT_LIST_HEAD(&node->node);
+
+ mutex_lock(&master_mutex);
+
+ list_add(&node->node, &master_list);
+
+ mutex_unlock(&master_mutex);
+
+ return;
+error:
+ for (i--; i >= 0; i--)
+ iounmap(node->reg[i]);
+
+ kfree(node);
+}
+
+struct of_device_id mmp_clk_master_of_id[] = {
+ {
+ .compatible = "marvell,mmp-clk-master",
+ .data = mmp_clk_master_setup,
+ },
+ { },
+};
+
+static struct mmp_clk_master_node *get_master_node(struct device_node *child)
+{
+ struct device_node *master;
+ struct mmp_clk_master_node *node;
+
+ /* Find the master device node */
+ master = child;
+ do {
+ master = of_get_next_parent(master);
+ } while (!of_match_node(mmp_clk_master_of_id, master));
+
+ mutex_lock(&master_mutex);
+
+ list_for_each_entry(node, &master_list, node) {
+ if (node->np == master) {
+ mutex_unlock(&master_mutex);
+ return node;
+ }
+ }
+
+ mutex_unlock(&master_mutex);
+
+ return NULL;
+}
+
+static void __iomem *get_child_reg(struct device_node *child,
+ unsigned int reg_index,
+ unsigned int *reg_base)
+{
+ struct mmp_clk_master_node *node;
+
+ if (reg_index >= MAX_REG) {
+ pr_err("%s:%s reg_index too big.\n", __func__, child->name);
+ return NULL;
+ }
+
+ node = get_master_node(child);
+ if (!node) {
+ pr_err("%s:%s failed to get master node\n",
+ __func__, child->name);
+ return NULL;
+ }
+
+ *reg_base = node->reg_base[reg_index];
+
+ return node->reg[reg_index];
+}
+
+void __iomem *of_mmp_clk_get_reg(struct device_node *np,
+ unsigned int index,
+ unsigned int *reg_phys)
+{
+ const __be32 *prop;
+ unsigned int proplen, size;
+ u32 reg_index, reg_offset;
+ unsigned int reg_base;
+ void __iomem *reg;
+
+ prop = of_get_property(np, "marvell,reg-offset", &proplen);
+ if (!prop) {
+ pr_err("%s:%s can not find marvell,reg-offset\n",
+ __func__, np->name);
+ return NULL;
+ }
+
+ size = proplen / sizeof(u32);
+
+ if ((proplen % sizeof(u32)) || (size <= (index * 2))) {
+ pr_err("%s:%s prop len is not correct\n",
+ __func__, np->name);
+ return NULL;
+ }
+
+ reg_index = be32_to_cpup(prop + index * 2);
+ reg_offset = be32_to_cpup(prop + index * 2 + 1);
+ reg = get_child_reg(np, reg_index, &reg_base);
+ if (!reg) {
+ pr_err("%s:%s failed to get reg\n",
+ __func__, np->name);
+ return NULL;
+ }
+
+ *reg_phys = reg_base + reg_offset;
+
+ return reg + reg_offset;
+}
+
+struct device_node *of_mmp_clk_master_init(struct device_node *from)
+{
+ struct device_node *parent, *child;
+ const struct of_device_id *match;
+ of_clk_init_cb_t clk_init_cb;
+
+ parent = from;
+ parent = of_find_matching_node_and_match(from, mmp_clk_master_of_id,
+ &match);
+ if (parent) {
+ clk_init_cb = (of_clk_init_cb_t)match->data;
+ clk_init_cb(parent);
+ for_each_child_of_node(parent, child) {
+ match = of_match_node(&__clk_of_table, child);
+ if (!match)
+ continue;
+ clk_init_cb = (of_clk_init_cb_t)match->data;
+ clk_init_cb(child);
+ }
+ }
+
+ return parent;
+}
diff --git a/drivers/clk/mmp/clk.h b/drivers/clk/mmp/clk.h
index 9827a4f..6d8c3b3 100644
--- a/drivers/clk/mmp/clk.h
+++ b/drivers/clk/mmp/clk.h
@@ -140,6 +140,13 @@ extern struct clk *mmp_clk_register_composite(struct device *dev,
unsigned long flags);


+/* Master clock exported APIs and data. */
+extern void __iomem *of_mmp_clk_get_reg(struct device_node *np,
+ unsigned int reg_index,
+ unsigned int *reg_phys);
+struct device_node *of_mmp_clk_master_init(struct device_node *from);
+
+
extern struct clk *mmp_clk_register_pll2(const char *name,
const char *parent_name, unsigned long flags);
extern struct clk *mmp_clk_register_apbc(const char *name,
--
1.8.3.2

2014-06-10 01:29:32

by Chao Xie

[permalink] [raw]
Subject: [PATCH 05/12] clk: mmp: add clock type mix

From: Chao Xie <[email protected]>

The clock type mix is a kind of clock combines "div" and "mux".
This kind of clock can not allow to change div first then
mux or change mux first or div.
The reason is
1. Some clock has frequency change bit. Each time want to change
the frequency, there are some operations based on this bit, and
these operations are time-cost.
Seperating div and mux change will make the process longer, and
waste more time.
2. Seperting the div and mux may generate middle clock that the
peripharals do not support. It may make the peripharals hang.

There are three kinds of this type of clock in all SOCes.
1. The clock has bit to trigger the frequency change.
2. Same as #1, but the operations for the bit is different
3. Do not have frequency change bit.

So this type of clock has implemented the callbacks
->determine_rate
->set_rate_and_parent
These callbacks can help to change the div and mux together.

Signed-off-by: Chao Xie <[email protected]>
---
drivers/clk/mmp/Makefile | 2 +-
drivers/clk/mmp/clk-mix.c | 419 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/clk/mmp/clk.h | 62 +++++++
3 files changed, 482 insertions(+), 1 deletion(-)
create mode 100644 drivers/clk/mmp/clk-mix.c

diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile
index 392d780..8bfee860 100644
--- a/drivers/clk/mmp/Makefile
+++ b/drivers/clk/mmp/Makefile
@@ -2,7 +2,7 @@
# Makefile for mmp specific clk
#

-obj-y += clk-apbc.o clk-apmu.o clk-frac.o
+obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o

obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o
diff --git a/drivers/clk/mmp/clk-mix.c b/drivers/clk/mmp/clk-mix.c
new file mode 100644
index 0000000..d2f6406
--- /dev/null
+++ b/drivers/clk/mmp/clk-mix.c
@@ -0,0 +1,419 @@
+/*
+ * mmp mix(div and mux) clock operation source file
+ *
+ * Copyright (C) 2014 Marvell
+ * Chao Xie <[email protected]>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+#include "clk.h"
+
+/*
+ * The mix clock is a clock combined mux and div type clock.
+ * Because the div field and mux field need to be set at same
+ * time, we can not divide it into 2 types of clock
+ */
+
+#define to_clk_mix(hw) container_of(hw, struct mmp_clk_mix, hw)
+
+static unsigned int _get_div(struct mmp_clk_mix *mix, unsigned int val)
+{
+ if (mix->div_flags & CLK_DIVIDER_ONE_BASED)
+ return val;
+ if (mix->div_flags & CLK_DIVIDER_POWER_OF_TWO)
+ return 1 << val;
+ return val + 1;
+}
+
+static unsigned int _get_val(struct mmp_clk_mix *mix, unsigned int div)
+{
+ if (mix->div_flags & CLK_DIVIDER_ONE_BASED)
+ return div;
+ if (mix->div_flags & CLK_DIVIDER_POWER_OF_TWO)
+ return __ffs(div);
+ return div - 1;
+}
+
+static void _filter_clk_table(struct mmp_clk_mix *mix,
+ struct mmp_clk_mix_clk_table *table,
+ unsigned int table_size)
+{
+ int i;
+ struct mmp_clk_mix_clk_table *item;
+ struct clk *parent, *clk;
+ unsigned long parent_rate;
+
+ clk = mix->hw.clk;
+
+ for (i = 0; i < table_size; i++) {
+ item = &table[i];
+ parent = clk_get_parent_by_index(clk, item->parent_index);
+ parent_rate = __clk_get_rate(parent);
+ if (parent_rate % item->rate) {
+ item->valid = 0;
+ } else {
+ item->divisor = parent_rate / item->rate;
+ item->valid = 1;
+ }
+ }
+}
+
+static int _set_rate(struct mmp_clk_mix *mix, u32 mux_val, u32 div_val,
+ unsigned int change_mux, unsigned int change_div)
+{
+ struct mmp_clk_mix_reg_info *ri = &mix->reg_info;
+ u8 width, shift;
+ u32 mux_div, fc_req;
+ int ret, timeout = 50;
+ unsigned long flags = 0;
+
+ if (!change_mux && !change_div)
+ return -EINVAL;
+
+ if (mix->lock)
+ spin_lock_irqsave(mix->lock, flags);
+
+ if (mix->type == MMP_CLK_MIX_TYPE_V1
+ || mix->type == MMP_CLK_MIX_TYPE_V2)
+ mux_div = readl(ri->reg_clk_ctrl);
+ else
+ mux_div = readl(ri->reg_clk_sel);
+
+ if (change_div) {
+ width = ri->width_div;
+ shift = ri->shift_div;
+ mux_div &= ~MMP_CLK_BITS_MASK(width, shift);
+ mux_div |= MMP_CLK_BITS_SET_VAL(div_val, width, shift);
+ }
+
+ if (change_mux) {
+ width = ri->width_mux;
+ shift = ri->shift_mux;
+ mux_div &= ~MMP_CLK_BITS_MASK(width, shift);
+ mux_div |= MMP_CLK_BITS_SET_VAL(mux_val, width, shift);
+ }
+
+ if (mix->type == MMP_CLK_MIX_TYPE_V1) {
+ writel(mux_div, ri->reg_clk_ctrl);
+ } else if (mix->type == MMP_CLK_MIX_TYPE_V2) {
+ writel(mux_div, ri->reg_clk_ctrl);
+
+ do {
+ fc_req = readl(ri->reg_clk_ctrl);
+ timeout--;
+ if (fc_req & (1 << ri->bit_fc))
+ break;
+ } while (timeout);
+
+ if (timeout == 0) {
+ pr_err("%s:%s cannot do frequency change\n",
+ __func__, __clk_get_name(mix->hw.clk));
+ ret = -EBUSY;
+ goto error;
+ }
+ } else {
+ fc_req = readl(ri->reg_clk_ctrl);
+ fc_req |= 1 << ri->bit_fc;
+ writel(fc_req, ri->reg_clk_ctrl);
+ writel(mux_div, ri->reg_clk_sel);
+ fc_req &= ~(1 << ri->bit_fc);
+ }
+
+ ret = 0;
+error:
+ if (mix->lock)
+ spin_unlock_irqrestore(mix->lock, flags);
+
+ return ret;
+}
+
+static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *best_parent_rate,
+ struct clk **best_parent_clk)
+{
+ struct mmp_clk_mix *mix = to_clk_mix(hw);
+ struct mmp_clk_mix_clk_table *item;
+ struct clk *parent, *parent_best, *mix_clk;
+ unsigned long parent_rate, mix_rate, mix_rate_best, parent_rate_best;
+ unsigned long gap, gap_best;
+ u32 div_val_max;
+ unsigned int div;
+ int i, j;
+
+ mix_clk = hw->clk;
+
+ parent = NULL;
+ mix_rate_best = 0;
+ parent_rate_best = 0;
+ gap_best = rate;
+ parent_best = NULL;
+
+ if (mix->table) {
+ for (i = 0; i < mix->table_size; i++) {
+ item = &mix->table[i];
+ if (item->valid == 0)
+ continue;
+ parent = clk_get_parent_by_index(mix_clk,
+ item->parent_index);
+ parent_rate = __clk_get_rate(parent);
+ mix_rate = parent_rate / item->divisor;
+ gap = abs(mix_rate - rate);
+ if (parent_best == NULL || gap < gap_best) {
+ parent_best = parent;
+ parent_rate_best = parent_rate;
+ mix_rate_best = mix_rate;
+ gap_best = gap;
+ if (gap_best == 0)
+ goto found;
+ }
+ }
+ } else {
+ for (i = 0; i < __clk_get_num_parents(mix_clk); i++) {
+ parent = clk_get_parent_by_index(mix_clk, i);
+ parent_rate = __clk_get_rate(parent);
+ div_val_max = (1 << mix->reg_info.width_div) - 1;
+ for (j = 0; j < div_val_max; j++) {
+ div = _get_div(mix, j);
+ mix_rate = parent_rate / div;
+ gap = abs(mix_rate - rate);
+ if (parent_best == NULL || gap < gap_best) {
+ parent_best = parent;
+ parent_rate_best = parent_rate;
+ mix_rate_best = mix_rate;
+ gap_best = gap;
+ if (gap_best == 0)
+ goto found;
+ }
+ }
+ }
+ }
+
+found:
+ *best_parent_rate = parent_rate_best;
+ *best_parent_clk = parent_best;
+
+ return mix_rate_best;
+}
+
+static int mmp_clk_mix_set_rate_and_parent(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long parent_rate,
+ u8 index)
+{
+ struct mmp_clk_mix *mix = to_clk_mix(hw);
+ unsigned int div;
+ u32 div_val, mux_val;
+
+ div = parent_rate / rate;
+ div_val = _get_val(mix, div);
+ mux_val = index;
+
+ return _set_rate(mix, mux_val, div_val, 1, 1);
+}
+
+static u8 mmp_clk_mix_get_parent(struct clk_hw *hw)
+{
+ struct mmp_clk_mix *mix = to_clk_mix(hw);
+ struct mmp_clk_mix_reg_info *ri = &mix->reg_info;
+ unsigned long flags = 0;
+ u32 mux_div = 0;
+ u8 width, shift;
+
+ if (mix->lock)
+ spin_lock_irqsave(mix->lock, flags);
+
+ if (mix->type == MMP_CLK_MIX_TYPE_V1
+ || mix->type == MMP_CLK_MIX_TYPE_V2)
+ mux_div = readl(ri->reg_clk_ctrl);
+ else
+ mux_div = readl(ri->reg_clk_sel);
+
+ if (mix->lock)
+ spin_unlock_irqrestore(mix->lock, flags);
+
+ width = mix->reg_info.width_mux;
+ shift = mix->reg_info.shift_mux;
+
+ return MMP_CLK_BITS_GET_VAL(mux_div, width, shift);
+}
+
+static unsigned long mmp_clk_mix_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct mmp_clk_mix *mix = to_clk_mix(hw);
+ struct mmp_clk_mix_reg_info *ri = &mix->reg_info;
+ unsigned long flags = 0;
+ u32 mux_div = 0;
+ u8 width, shift;
+ unsigned int div;
+
+ if (mix->lock)
+ spin_lock_irqsave(mix->lock, flags);
+
+ if (mix->type == MMP_CLK_MIX_TYPE_V1
+ || mix->type == MMP_CLK_MIX_TYPE_V2)
+ mux_div = readl(ri->reg_clk_ctrl);
+ else
+ mux_div = readl(ri->reg_clk_sel);
+
+ if (mix->lock)
+ spin_unlock_irqrestore(mix->lock, flags);
+
+ width = mix->reg_info.width_div;
+ shift = mix->reg_info.shift_div;
+
+ div = _get_div(mix, MMP_CLK_BITS_GET_VAL(mux_div, width, shift));
+
+ return parent_rate / div;
+}
+
+static int mmp_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct mmp_clk_mix *mix = to_clk_mix(hw);
+ struct mmp_clk_mix_clk_table *item;
+ int i;
+
+ if (mix->table) {
+ for (i = 0; i < mix->table_size; i++) {
+ item = &mix->table[i];
+ if (item->valid == 0)
+ continue;
+ if (item->parent_index == index)
+ break;
+ }
+ if (i < mix->table_size)
+ return _set_rate(mix, index,
+ _get_val(mix, item->divisor), 1, 1);
+ else
+ return -EINVAL;
+ } else
+ return _set_rate(mix, index, 0, 1, 0);
+}
+
+static int mmp_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long best_parent_rate)
+{
+ struct mmp_clk_mix *mix = to_clk_mix(hw);
+ struct mmp_clk_mix_clk_table *item;
+ unsigned long parent_rate;
+ unsigned int best_divisor;
+ struct clk *mix_clk, *parent;
+ int i;
+
+ best_divisor = best_parent_rate / rate;
+
+ mix_clk = hw->clk;
+ if (mix->table) {
+ for (i = 0; i < mix->table_size; i++) {
+ item = &mix->table[i];
+ if (item->valid == 0)
+ continue;
+ parent = clk_get_parent_by_index(mix_clk,
+ item->parent_index);
+ parent_rate = __clk_get_rate(parent);
+ if (parent_rate == best_parent_rate
+ && item->divisor == best_divisor)
+ break;
+ }
+ if (i < mix->table_size)
+ return _set_rate(mix, item->parent_index,
+ item->divisor, 1, 1);
+ else
+ return -EINVAL;
+ } else {
+ for (i = 0; i < __clk_get_num_parents(mix_clk); i++) {
+ parent = clk_get_parent_by_index(mix_clk, i);
+ parent_rate = __clk_get_rate(parent);
+ if (parent_rate == best_parent_rate)
+ break;
+ }
+ if (i < mix->table_size)
+ return _set_rate(mix, i, best_divisor, 1, 1);
+ else
+ return -EINVAL;
+ }
+}
+
+static void mmp_clk_mix_init(struct clk_hw *hw)
+{
+ struct mmp_clk_mix *mix = to_clk_mix(hw);
+
+ if (mix->table)
+ _filter_clk_table(mix, mix->table, mix->table_size);
+}
+
+const struct clk_ops mmp_clk_mix_ops = {
+ .determine_rate = mmp_clk_mix_determine_rate,
+ .set_rate_and_parent = mmp_clk_mix_set_rate_and_parent,
+ .set_rate = mmp_clk_set_rate,
+ .set_parent = mmp_clk_set_parent,
+ .get_parent = mmp_clk_mix_get_parent,
+ .recalc_rate = mmp_clk_mix_recalc_rate,
+ .init = mmp_clk_mix_init,
+};
+
+struct clk *mmp_clk_register_mix(struct device *dev,
+ const char *name,
+ u8 num_parents,
+ const char **parent_names,
+ unsigned long flags,
+ struct mmp_clk_mix_config *config,
+ spinlock_t *lock)
+{
+ struct mmp_clk_mix *mix;
+ struct clk *clk;
+ struct clk_init_data init;
+ size_t table_bytes;
+
+ if (config->table)
+ table_bytes = sizeof(config->table) * config->table_size;
+ else
+ table_bytes = 0;
+
+ mix = kzalloc(sizeof(*mix) + table_bytes, GFP_KERNEL);
+ if (!mix) {
+ pr_err("%s:%s: could not allocate mmp mix clk\n",
+ __func__, name);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ init.name = name;
+ init.flags = flags;
+ init.parent_names = parent_names;
+ init.num_parents = num_parents;
+ init.ops = &mmp_clk_mix_ops;
+
+ memcpy(&mix->reg_info, &config->reg_info, sizeof(config->reg_info));
+ if (config->table) {
+ mix->table = (struct mmp_clk_mix_clk_table *)(mix + 1);
+ memcpy(mix->table, config->table, table_bytes);
+ mix->table_size = config->table_size;
+ }
+ mix->div_flags = config->div_flags;
+ mix->mux_flags = config->mux_flags;
+ mix->lock = lock;
+ mix->hw.init = &init;
+
+ if (config->reg_info.bit_fc >= 32)
+ mix->type = MMP_CLK_MIX_TYPE_V1;
+ else if (config->reg_info.reg_clk_sel)
+ mix->type = MMP_CLK_MIX_TYPE_V3;
+ else
+ mix->type = MMP_CLK_MIX_TYPE_V2;
+ clk = clk_register(dev, &mix->hw);
+
+ if (IS_ERR(clk)) {
+ kfree(mix->table);
+ kfree(mix);
+ }
+
+ return clk;
+}
diff --git a/drivers/clk/mmp/clk.h b/drivers/clk/mmp/clk.h
index d267639..426616b 100644
--- a/drivers/clk/mmp/clk.h
+++ b/drivers/clk/mmp/clk.h
@@ -37,6 +37,68 @@ extern struct clk *mmp_clk_register_factor(const char *name,
struct mmp_clk_factor_tbl *ftbl, unsigned int ftbl_cnt,
spinlock_t *lock);

+/* Clock type "mix" */
+#define MMP_CLK_BITS_MASK(width, shift) \
+ (((1 << (width)) - 1) << (shift))
+#define MMP_CLK_BITS_GET_VAL(data, width, shift) \
+ ((data & MMP_CLK_BITS_MASK(width, shift)) >> (shift))
+#define MMP_CLK_BITS_SET_VAL(val, width, shift) \
+ (((val) << (shift)) & MMP_CLK_BITS_MASK(width, shift))
+
+enum {
+ MMP_CLK_MIX_TYPE_V1,
+ MMP_CLK_MIX_TYPE_V2,
+ MMP_CLK_MIX_TYPE_V3,
+};
+
+/* The register layout */
+struct mmp_clk_mix_reg_info {
+ void __iomem *reg_clk_ctrl;
+ void __iomem *reg_clk_sel;
+ u8 width_div;
+ u8 shift_div;
+ u8 width_mux;
+ u8 shift_mux;
+ u8 bit_fc;
+};
+
+/* The suggested clock table from user. */
+struct mmp_clk_mix_clk_table {
+ unsigned long rate;
+ u8 parent_index;
+ unsigned int divisor;
+ unsigned int valid;
+};
+
+struct mmp_clk_mix_config {
+ struct mmp_clk_mix_reg_info reg_info;
+ struct mmp_clk_mix_clk_table *table;
+ unsigned int table_size;
+ u8 div_flags;
+ u8 mux_flags;
+};
+
+struct mmp_clk_mix {
+ struct clk_hw hw;
+ struct mmp_clk_mix_reg_info reg_info;
+ struct mmp_clk_mix_clk_table *table;
+ unsigned int table_size;
+ u8 div_flags;
+ u8 mux_flags;
+ unsigned int type;
+ spinlock_t *lock;
+};
+
+extern const struct clk_ops mmp_clk_mix_ops;
+extern struct clk *mmp_clk_register_mix(struct device *dev,
+ const char *name,
+ u8 num_parents,
+ const char **parent_names,
+ unsigned long flags,
+ struct mmp_clk_mix_config *config,
+ spinlock_t *lock);
+
+
extern struct clk *mmp_clk_register_pll2(const char *name,
const char *parent_name, unsigned long flags);
extern struct clk *mmp_clk_register_apbc(const char *name,
--
1.8.3.2

2014-06-10 01:29:50

by Chao Xie

[permalink] [raw]
Subject: [PATCH 10/12] clk: mmp: add device tree support for composite type clock

From: Chao Xie <[email protected]>

To parse composite clock from device tree file, there are some
rules.
The clock to be composited will be the child of the composite
clock in device tree file.
It can support the composition of (mux,div,gate) clock defined
as common clock and (mix,gate) defined only for MMP series.

Signed-off-by: Chao Xie <[email protected]>

Conflicts:
drivers/clk/mmp/Makefile
---
.../devicetree/bindings/clock/mmp/clk-composite | 58 +++++
drivers/clk/mmp/Makefile | 2 +-
drivers/clk/mmp/clk-of-composite.c | 253 +++++++++++++++++++++
drivers/clk/mmp/clk.h | 14 ++
4 files changed, 326 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/clock/mmp/clk-composite
create mode 100644 drivers/clk/mmp/clk-of-composite.c

diff --git a/Documentation/devicetree/bindings/clock/mmp/clk-composite b/Documentation/devicetree/bindings/clock/mmp/clk-composite
new file mode 100644
index 0000000..224968c
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/mmp/clk-composite
@@ -0,0 +1,58 @@
+Binding for Marvell MMP series composite clock
+
+The common clock defines a general composite clock with div/mux/gate.
+Because MMP series has clock need combines the div/mux together, so
+there is a new type of clock "mix". The "mix" clock can also be
+composited with gate clock. In fact, many mix clocks and gate clocks
+share same registers.
+
+In the device tree file, the clock to be composited should be child
+of the composite clock.
+
+Required properties
+- compatible : It should be "marvell,mmp-clk-composite" for (mix, gate)
+ composition, or "marvell,mmp-clk-general-composite" for
+ (mux, div, gate) composition.
+
+
+Examples
+1. There are three clocks mux1, div1, gate1.
+
+apmu_clk {
+ compatible = "marvell,mmp-clk-master";
+ reg = <0xde210000 0x1000>;
+
+ general_composite_clk {
+ compatible = "marvell,mmp-clk-general-composite";
+
+ mux1 {
+ ...
+ };
+ div1 {
+ ...
+ };
+ gate1 {
+ ...
+ };
+ };
+};
+
+2. There are two clocks mix1, gate2
+
+apmu_clk {
+ compatible = "marvell,mmp-clk-master";
+ reg = <0xde210000 0x1000>;
+
+ composite_clk {
+ compatible = "marvell,mmp-clk-composite";
+
+ mix1 {
+ ...
+ };
+ gate2 {
+ ...
+ };
+ };
+};
+
+
diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile
index e8810b6..84dce78 100644
--- a/drivers/clk/mmp/Makefile
+++ b/drivers/clk/mmp/Makefile
@@ -6,7 +6,7 @@ obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o clk-gate.o \
clk-mix-composite.o

ifneq ($(CONFIG_OF),)
-obj-y += clk-master-node.o lock.o
+obj-y += clk-master-node.o lock.o clk-of-composite.o
endif

obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
diff --git a/drivers/clk/mmp/clk-of-composite.c b/drivers/clk/mmp/clk-of-composite.c
new file mode 100644
index 0000000..403ebe2
--- /dev/null
+++ b/drivers/clk/mmp/clk-of-composite.c
@@ -0,0 +1,253 @@
+/*
+ * mmp mix(div and mux) clock operation source file
+ *
+ * Copyright (C) 2014 Marvell
+ * Chao Xie <[email protected]>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/of.h>
+
+#include "clk.h"
+
+struct mmp_clk_composite_member {
+ struct device_node *np;
+ struct clk_hw *hw;
+ const struct clk_ops *ops;
+ int num_parents;
+ const char **parent_names;
+};
+
+struct mmp_clk_composite_node {
+ struct device_node *np;
+ struct mmp_clk_composite_member *members[MMP_CLK_COMPOSITE_TYPE_MAX];
+ struct list_head node;
+};
+
+static LIST_HEAD(composite_list);
+static DEFINE_MUTEX(composite_mutex);
+
+int of_mmp_clk_composite_add_member(struct device_node *np, struct clk_hw *hw,
+ const struct clk_ops *ops, int type)
+{
+ struct device_node *parent_np;
+ struct mmp_clk_composite_node *node;
+ struct mmp_clk_composite_member *member;
+ unsigned int found = 0;
+ size_t size;
+ int i, ret;
+
+ mutex_lock(&composite_mutex);
+
+ parent_np = of_get_next_parent(np);
+
+ list_for_each_entry(node, &composite_list, node) {
+ if (node->np == parent_np) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ pr_err("%s:%s can not find member %s\n",
+ __func__, parent_np->name, np->name);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ if (node->members[type]) {
+ pr_err("%s:%s already has type %d,when add member %s\n",
+ __func__, parent_np->name, type, np->name);
+ ret = -EBUSY;
+ goto out;
+ }
+
+ member = kzalloc(sizeof(*member), GFP_KERNEL);
+ if (!member) {
+ pr_err("%s:%s failed to allocate member.\n",
+ __func__, parent_np->name);
+ ret = -ENOMEM;
+ goto out;
+ }
+ member->np = np;
+ member->hw = hw;
+ member->ops = ops;
+
+ ret = of_clk_get_parent_count(np);
+ if (ret >= 1) {
+ member->num_parents = ret;
+ size = sizeof(*member->parent_names) * member->num_parents;
+ member->parent_names = kzalloc(size, GFP_KERNEL);
+ if (!member->parent_names) {
+ pr_err("%s:%s failed to allocate parent_names.\n",
+ __func__, parent_np->name);
+ ret = -ENOMEM;
+ goto member_free;
+ }
+ for (i = 0; i < member->num_parents; i++)
+ member->parent_names[i] =
+ of_clk_get_parent_name(np, i);
+ } else {
+ member->num_parents = 0;
+ member->parent_names = NULL;
+ }
+
+ node->members[type] = member;
+
+ ret = 0;
+ goto out;
+
+member_free:
+ kfree(member);
+out:
+ mutex_unlock(&composite_mutex);
+
+ return ret;
+}
+
+static void of_mmp_clk_composite_setup(struct device_node *np)
+{
+ struct mmp_clk_composite_node *node;
+ struct mmp_clk_composite_member *mix, *gate;
+ struct device_node *child;
+ struct clk *clk;
+ const struct of_device_id *match;
+ of_clk_init_cb_t clk_init_cb;
+
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node) {
+ pr_err("%s:%s failed to allocate node\n", __func__, np->name);
+ return;
+ }
+
+ INIT_LIST_HEAD(&node->node);
+ node->np = np;
+
+ mutex_lock(&composite_mutex);
+ list_add(&node->node, &composite_list);
+ mutex_unlock(&composite_mutex);
+
+ for_each_child_of_node(np, child) {
+ match = of_match_node(&__clk_of_table, child);
+ clk_init_cb = (of_clk_init_cb_t)match->data;
+ clk_init_cb(child);
+ }
+
+ mix = node->members[MMP_CLK_COMPOSITE_TYPE_MUXMIX];
+ gate = node->members[MMP_CLK_COMPOSITE_TYPE_GATE];
+ if (!mix || !gate) {
+ pr_err("%s:%s failed to parse members.\n", __func__, np->name);
+ goto error;
+ }
+
+ clk = mmp_clk_register_composite(NULL, np->name,
+ mix->parent_names, mix->num_parents,
+ mix->hw, mix->ops,
+ gate->hw, gate->ops, 0);
+ if (!IS_ERR(clk))
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+
+ return;
+
+error:
+ mutex_lock(&composite_mutex);
+ list_del(&node->node);
+ mutex_unlock(&composite_mutex);
+ kfree(node);
+}
+
+static void of_mmp_clk_general_composite_setup(struct device_node *np)
+{
+ struct mmp_clk_composite_node *node;
+ struct mmp_clk_composite_member *mux, *gate, *div;
+ struct device_node *child;
+ struct clk *clk;
+ const char **parent_names;
+ int num_parents;
+ const struct of_device_id *match;
+ of_clk_init_cb_t clk_init_cb;
+
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node) {
+ pr_err("%s:%s failed to allocate node\n", __func__, np->name);
+ return;
+ }
+
+ INIT_LIST_HEAD(&node->node);
+ node->np = np;
+
+ mutex_lock(&composite_mutex);
+ list_add(&node->node, &composite_list);
+ mutex_unlock(&composite_mutex);
+
+ for_each_child_of_node(np, child) {
+ match = of_match_node(&__clk_of_table, child);
+ clk_init_cb = (of_clk_init_cb_t)match->data;
+ clk_init_cb(child);
+ }
+
+ mux = node->members[MMP_CLK_COMPOSITE_TYPE_MUXMIX];
+ gate = node->members[MMP_CLK_COMPOSITE_TYPE_GATE];
+ div = node->members[MMP_CLK_COMPOSITE_TYPE_DIV];
+
+ if ((!mux && !div) || (!mux && !gate) || (!gate && !div)) {
+ pr_err("%s:%s failed to parse members.\n", __func__, np->name);
+ goto error;
+ }
+
+ if (mux) {
+ parent_names = mux->parent_names;
+ num_parents = mux->num_parents;
+ } else {
+ parent_names = div->parent_names;
+ num_parents = div->num_parents;
+ }
+
+ clk = clk_register_composite(NULL, np->name,
+ parent_names, num_parents,
+ mux ? mux->hw : NULL, mux ? mux->ops : NULL,
+ div ? div->hw : NULL, div ? div->ops : NULL,
+ gate ? gate->hw : NULL,
+ gate ? gate->ops : NULL, 0);
+ if (!IS_ERR(clk))
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+
+ return;
+
+error:
+ mutex_lock(&composite_mutex);
+ list_del(&node->node);
+ mutex_unlock(&composite_mutex);
+ kfree(node);
+}
+
+CLK_OF_DECLARE(mmp_clk_composite, "marvell,mmp-clk-composite",
+ of_mmp_clk_composite_setup);
+CLK_OF_DECLARE(mmp_clk_general_composite, "marvell,mmp-clk-general-composite",
+ of_mmp_clk_general_composite_setup);
+
+int of_mmp_clk_is_composite(struct device_node *np)
+{
+ struct device_node *parent_np;
+ struct mmp_clk_composite_node *node;
+
+ parent_np = of_get_next_parent(np);
+ mutex_lock(&composite_mutex);
+ list_for_each_entry(node, &composite_list, node) {
+ if (node->np == parent_np) {
+ mutex_unlock(&composite_mutex);
+ return 1;
+ }
+ }
+ mutex_unlock(&composite_mutex);
+
+ return 0;
+}
diff --git a/drivers/clk/mmp/clk.h b/drivers/clk/mmp/clk.h
index e06a228..66d0fd4 100644
--- a/drivers/clk/mmp/clk.h
+++ b/drivers/clk/mmp/clk.h
@@ -152,6 +152,20 @@ extern spinlock_t *of_mmp_clk_get_spinlock(struct device_node *np,
unsigned int reg_base);


+/* DT support for composiste type clock. */
+enum {
+ MMP_CLK_COMPOSITE_TYPE_MUXMIX,
+ MMP_CLK_COMPOSITE_TYPE_DIV,
+ MMP_CLK_COMPOSITE_TYPE_GATE,
+ MMP_CLK_COMPOSITE_TYPE_MAX,
+};
+
+extern int of_mmp_clk_composite_add_member(struct device_node *np,
+ struct clk_hw *hw,
+ const struct clk_ops *ops, int type);
+extern int of_mmp_clk_is_composite(struct device_node *np);
+
+
extern struct clk *mmp_clk_register_pll2(const char *name,
const char *parent_name, unsigned long flags);
extern struct clk *mmp_clk_register_apbc(const char *name,
--
1.8.3.2

2014-06-10 01:28:11

by Chao Xie

[permalink] [raw]
Subject: [PATCH 04/12] clk: mmp: move definiton of mmp_clk_frac to clk.h

From: Chao Xie <[email protected]>

Move the definition of structure of mmp_clk_frac to
clk.h.
So device tree support can use this structure.

Signed-off-by: Chao Xie <[email protected]>
---
drivers/clk/mmp/clk-frac.c | 8 --------
drivers/clk/mmp/clk.h | 32 ++++++++++++++++++++++----------
2 files changed, 22 insertions(+), 18 deletions(-)

diff --git a/drivers/clk/mmp/clk-frac.c b/drivers/clk/mmp/clk-frac.c
index 1876d2c..eeba52c 100644
--- a/drivers/clk/mmp/clk-frac.c
+++ b/drivers/clk/mmp/clk-frac.c
@@ -23,14 +23,6 @@
*/

#define to_clk_factor(hw) container_of(hw, struct mmp_clk_factor, hw)
-struct mmp_clk_factor {
- struct clk_hw hw;
- void __iomem *base;
- struct mmp_clk_factor_masks *masks;
- struct mmp_clk_factor_tbl *ftbl;
- unsigned int ftbl_cnt;
- spinlock_t *lock;
-};

static long clk_factor_round_rate(struct clk_hw *hw, unsigned long drate,
unsigned long *prate)
diff --git a/drivers/clk/mmp/clk.h b/drivers/clk/mmp/clk.h
index b71b717..d267639 100644
--- a/drivers/clk/mmp/clk.h
+++ b/drivers/clk/mmp/clk.h
@@ -7,12 +7,14 @@
#define APBC_NO_BUS_CTRL BIT(0)
#define APBC_POWER_CTRL BIT(1)

+
+/* Clock type "factor" */
struct mmp_clk_factor_masks {
- unsigned int factor;
- unsigned int num_mask;
- unsigned int den_mask;
- unsigned int num_shift;
- unsigned int den_shift;
+ unsigned int factor;
+ unsigned int num_mask;
+ unsigned int den_mask;
+ unsigned int num_shift;
+ unsigned int den_shift;
};

struct mmp_clk_factor_tbl {
@@ -20,6 +22,21 @@ struct mmp_clk_factor_tbl {
unsigned int den;
};

+struct mmp_clk_factor {
+ struct clk_hw hw;
+ void __iomem *base;
+ struct mmp_clk_factor_masks *masks;
+ struct mmp_clk_factor_tbl *ftbl;
+ unsigned int ftbl_cnt;
+ spinlock_t *lock;
+};
+
+extern struct clk *mmp_clk_register_factor(const char *name,
+ const char *parent_name, unsigned long flags,
+ void __iomem *base, struct mmp_clk_factor_masks *masks,
+ struct mmp_clk_factor_tbl *ftbl, unsigned int ftbl_cnt,
+ spinlock_t *lock);
+
extern struct clk *mmp_clk_register_pll2(const char *name,
const char *parent_name, unsigned long flags);
extern struct clk *mmp_clk_register_apbc(const char *name,
@@ -28,9 +45,4 @@ extern struct clk *mmp_clk_register_apbc(const char *name,
extern struct clk *mmp_clk_register_apmu(const char *name,
const char *parent_name, void __iomem *base, u32 enable_mask,
spinlock_t *lock);
-extern struct clk *mmp_clk_register_factor(const char *name,
- const char *parent_name, unsigned long flags,
- void __iomem *base, struct mmp_clk_factor_masks *masks,
- struct mmp_clk_factor_tbl *ftbl, unsigned int ftbl_cnt,
- spinlock_t *lock);
#endif
--
1.8.3.2

2014-06-10 01:30:54

by Chao Xie

[permalink] [raw]
Subject: [PATCH 06/12] clk: mmp: add mmp private gate clock

From: Chao Xie <[email protected]>

Some SOCes have this kind of the gate clock
1. There are some bits to control the gate not only one bit.
2. Some clocks has operations of "out of reset" and "enable".
To enable clock, we need do "out of reset" and "enable".
To disable clock, we may not need "set to reset". It depends
on the SOCes' design.
3. It is not always that "1" is to enable while "0" is to disable
when write register.

So we have to define the "mask", "enable_val", "disable_val" for
this kind of gate clock.

Signed-off-by: Chao Xie <[email protected]>
---
drivers/clk/mmp/Makefile | 2 +-
drivers/clk/mmp/clk-gate.c | 133 +++++++++++++++++++++++++++++++++++++++++++++
drivers/clk/mmp/clk.h | 21 +++++++
3 files changed, 155 insertions(+), 1 deletion(-)
create mode 100644 drivers/clk/mmp/clk-gate.c

diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile
index 8bfee860..2855f7b 100644
--- a/drivers/clk/mmp/Makefile
+++ b/drivers/clk/mmp/Makefile
@@ -2,7 +2,7 @@
# Makefile for mmp specific clk
#

-obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o
+obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o clk-gate.o

obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o
diff --git a/drivers/clk/mmp/clk-gate.c b/drivers/clk/mmp/clk-gate.c
new file mode 100644
index 0000000..adbd9d6
--- /dev/null
+++ b/drivers/clk/mmp/clk-gate.c
@@ -0,0 +1,133 @@
+/*
+ * mmp gate clock operation source file
+ *
+ * Copyright (C) 2014 Marvell
+ * Chao Xie <[email protected]>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+
+#include "clk.h"
+
+/*
+ * Some clocks will have mutiple bits to enable the clocks, and
+ * the bits to disable the clock is not same as enabling bits.
+ */
+
+#define to_clk_mmp_gate(hw) container_of(hw, struct mmp_clk_gate, hw)
+
+static int mmp_clk_gate_enable(struct clk_hw *hw)
+{
+ struct mmp_clk_gate *gate = to_clk_mmp_gate(hw);
+ struct clk *clk = hw->clk;
+ unsigned long flags = 0;
+ unsigned long rate;
+ u32 tmp;
+
+ if (gate->lock)
+ spin_lock_irqsave(gate->lock, flags);
+
+ tmp = readl(gate->reg);
+ tmp &= ~gate->mask;
+ tmp |= gate->val_enable;
+ writel(tmp, gate->reg);
+
+ if (gate->lock)
+ spin_unlock_irqrestore(gate->lock, flags);
+
+ if (gate->flags & MMP_CLK_GATE_NEED_DELAY) {
+ rate = __clk_get_rate(clk);
+ /* Need delay 2 cycles. */
+ udelay(2000000/rate);
+ }
+
+ return 0;
+}
+
+static void mmp_clk_gate_disable(struct clk_hw *hw)
+{
+ struct mmp_clk_gate *gate = to_clk_mmp_gate(hw);
+ unsigned long flags = 0;
+ u32 tmp;
+
+ if (gate->lock)
+ spin_lock_irqsave(gate->lock, flags);
+
+ tmp = readl(gate->reg);
+ tmp &= ~gate->mask;
+ tmp |= gate->val_disable;
+ writel(tmp, gate->reg);
+
+ if (gate->lock)
+ spin_unlock_irqrestore(gate->lock, flags);
+}
+
+static int mmp_clk_gate_is_enabled(struct clk_hw *hw)
+{
+ struct mmp_clk_gate *gate = to_clk_mmp_gate(hw);
+ unsigned long flags = 0;
+ u32 tmp;
+
+ if (gate->lock)
+ spin_lock_irqsave(gate->lock, flags);
+
+ tmp = readl(gate->reg);
+
+ if (gate->lock)
+ spin_unlock_irqrestore(gate->lock, flags);
+
+ return (tmp & gate->mask) == gate->val_enable;
+}
+
+const struct clk_ops mmp_clk_gate_ops = {
+ .enable = mmp_clk_gate_enable,
+ .disable = mmp_clk_gate_disable,
+ .is_enabled = mmp_clk_gate_is_enabled,
+};
+
+struct clk *mmp_clk_register_gate(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ void __iomem *reg, u32 mask, u32 val_enable, u32 val_disable,
+ unsigned int gate_flags, spinlock_t *lock)
+{
+ struct mmp_clk_gate *gate;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ /* allocate the gate */
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate) {
+ pr_err("%s:%s could not allocate gate clk\n", __func__, name);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ init.name = name;
+ init.ops = &mmp_clk_gate_ops;
+ init.flags = flags | CLK_IS_BASIC;
+ init.parent_names = (parent_name ? &parent_name : NULL);
+ init.num_parents = (parent_name ? 1 : 0);
+
+ /* struct clk_gate assignments */
+ gate->reg = reg;
+ gate->mask = mask;
+ gate->val_enable = val_enable;
+ gate->val_disable = val_disable;
+ gate->flags = gate_flags;
+ gate->lock = lock;
+ gate->hw.init = &init;
+
+ clk = clk_register(dev, &gate->hw);
+
+ if (IS_ERR(clk))
+ kfree(gate);
+
+ return clk;
+}
diff --git a/drivers/clk/mmp/clk.h b/drivers/clk/mmp/clk.h
index 426616b..9096f0a 100644
--- a/drivers/clk/mmp/clk.h
+++ b/drivers/clk/mmp/clk.h
@@ -99,6 +99,27 @@ extern struct clk *mmp_clk_register_mix(struct device *dev,
spinlock_t *lock);


+/* Clock type "gate". MMP private gate */
+#define MMP_CLK_GATE_NEED_DELAY BIT(0)
+
+struct mmp_clk_gate {
+ struct clk_hw hw;
+ void __iomem *reg;
+ u32 mask;
+ u32 val_enable;
+ u32 val_disable;
+ unsigned int flags;
+ spinlock_t *lock;
+};
+
+extern const struct clk_ops mmp_clk_gate_ops;
+extern struct clk *mmp_clk_register_gate(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ void __iomem *reg, u32 mask, u32 val_enable,
+ u32 val_disable, unsigned int gate_flags,
+ spinlock_t *lock);
+
+
extern struct clk *mmp_clk_register_pll2(const char *name,
const char *parent_name, unsigned long flags);
extern struct clk *mmp_clk_register_apbc(const char *name,
--
1.8.3.2

2014-06-10 01:33:37

by Chao Xie

[permalink] [raw]
Subject: [PATCH 01/12] clk: mmp: add prefix "mmp" for structures defined for clk-frac

From: Chao Xie <[email protected]>

The structures defined for clk-frac will be used out side
of clk-frac.c.
To avoid conflicts, add prefix "mmp" for these structures'
name.

Signed-off-by: Chao Xie <[email protected]>
---
drivers/clk/mmp/clk-frac.c | 23 ++++++++++++-----------
drivers/clk/mmp/clk-mmp2.c | 4 ++--
drivers/clk/mmp/clk-pxa168.c | 4 ++--
drivers/clk/mmp/clk-pxa910.c | 4 ++--
drivers/clk/mmp/clk.h | 8 ++++----
5 files changed, 22 insertions(+), 21 deletions(-)

diff --git a/drivers/clk/mmp/clk-frac.c b/drivers/clk/mmp/clk-frac.c
index 23a56f5..3fbc9ca 100644
--- a/drivers/clk/mmp/clk-frac.c
+++ b/drivers/clk/mmp/clk-frac.c
@@ -22,19 +22,19 @@
* numerator/denominator = Fin / (Fout * factor)
*/

-#define to_clk_factor(hw) container_of(hw, struct clk_factor, hw)
-struct clk_factor {
+#define to_clk_factor(hw) container_of(hw, struct mmp_clk_factor, hw)
+struct mmp_clk_factor {
struct clk_hw hw;
void __iomem *base;
- struct clk_factor_masks *masks;
- struct clk_factor_tbl *ftbl;
+ struct mmp_clk_factor_masks *masks;
+ struct mmp_clk_factor_tbl *ftbl;
unsigned int ftbl_cnt;
};

static long clk_factor_round_rate(struct clk_hw *hw, unsigned long drate,
unsigned long *prate)
{
- struct clk_factor *factor = to_clk_factor(hw);
+ struct mmp_clk_factor *factor = to_clk_factor(hw);
unsigned long rate = 0, prev_rate;
int i;

@@ -58,8 +58,8 @@ static long clk_factor_round_rate(struct clk_hw *hw, unsigned long drate,
static unsigned long clk_factor_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
- struct clk_factor *factor = to_clk_factor(hw);
- struct clk_factor_masks *masks = factor->masks;
+ struct mmp_clk_factor *factor = to_clk_factor(hw);
+ struct mmp_clk_factor_masks *masks = factor->masks;
unsigned int val, num, den;

val = readl_relaxed(factor->base);
@@ -81,8 +81,8 @@ static unsigned long clk_factor_recalc_rate(struct clk_hw *hw,
static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate,
unsigned long prate)
{
- struct clk_factor *factor = to_clk_factor(hw);
- struct clk_factor_masks *masks = factor->masks;
+ struct mmp_clk_factor *factor = to_clk_factor(hw);
+ struct mmp_clk_factor_masks *masks = factor->masks;
int i;
unsigned long val;
unsigned long prev_rate, rate = 0;
@@ -118,10 +118,11 @@ static struct clk_ops clk_factor_ops = {

struct clk *mmp_clk_register_factor(const char *name, const char *parent_name,
unsigned long flags, void __iomem *base,
- struct clk_factor_masks *masks, struct clk_factor_tbl *ftbl,
+ struct mmp_clk_factor_masks *masks,
+ struct mmp_clk_factor_tbl *ftbl,
unsigned int ftbl_cnt)
{
- struct clk_factor *factor;
+ struct mmp_clk_factor *factor;
struct clk_init_data init;
struct clk *clk;

diff --git a/drivers/clk/mmp/clk-mmp2.c b/drivers/clk/mmp/clk-mmp2.c
index b2721ca..7083f12 100644
--- a/drivers/clk/mmp/clk-mmp2.c
+++ b/drivers/clk/mmp/clk-mmp2.c
@@ -54,7 +54,7 @@

static DEFINE_SPINLOCK(clk_lock);

-static struct clk_factor_masks uart_factor_masks = {
+static struct mmp_clk_factor_masks uart_factor_masks = {
.factor = 2,
.num_mask = 0x1fff,
.den_mask = 0x1fff,
@@ -62,7 +62,7 @@ static struct clk_factor_masks uart_factor_masks = {
.den_shift = 0,
};

-static struct clk_factor_tbl uart_factor_tbl[] = {
+static struct mmp_clk_factor_tbl uart_factor_tbl[] = {
{.num = 14634, .den = 2165}, /*14.745MHZ */
{.num = 3521, .den = 689}, /*19.23MHZ */
{.num = 9679, .den = 5728}, /*58.9824MHZ */
diff --git a/drivers/clk/mmp/clk-pxa168.c b/drivers/clk/mmp/clk-pxa168.c
index 014396b..75266ac 100644
--- a/drivers/clk/mmp/clk-pxa168.c
+++ b/drivers/clk/mmp/clk-pxa168.c
@@ -47,7 +47,7 @@

static DEFINE_SPINLOCK(clk_lock);

-static struct clk_factor_masks uart_factor_masks = {
+static struct mmp_clk_factor_masks uart_factor_masks = {
.factor = 2,
.num_mask = 0x1fff,
.den_mask = 0x1fff,
@@ -55,7 +55,7 @@ static struct clk_factor_masks uart_factor_masks = {
.den_shift = 0,
};

-static struct clk_factor_tbl uart_factor_tbl[] = {
+static struct mmp_clk_factor_tbl uart_factor_tbl[] = {
{.num = 8125, .den = 1536}, /*14.745MHZ */
};

diff --git a/drivers/clk/mmp/clk-pxa910.c b/drivers/clk/mmp/clk-pxa910.c
index 9efc6a4..f817999 100644
--- a/drivers/clk/mmp/clk-pxa910.c
+++ b/drivers/clk/mmp/clk-pxa910.c
@@ -45,7 +45,7 @@

static DEFINE_SPINLOCK(clk_lock);

-static struct clk_factor_masks uart_factor_masks = {
+static struct mmp_clk_factor_masks uart_factor_masks = {
.factor = 2,
.num_mask = 0x1fff,
.den_mask = 0x1fff,
@@ -53,7 +53,7 @@ static struct clk_factor_masks uart_factor_masks = {
.den_shift = 0,
};

-static struct clk_factor_tbl uart_factor_tbl[] = {
+static struct mmp_clk_factor_tbl uart_factor_tbl[] = {
{.num = 8125, .den = 1536}, /*14.745MHZ */
};

diff --git a/drivers/clk/mmp/clk.h b/drivers/clk/mmp/clk.h
index ab86dd4..3fe92be 100644
--- a/drivers/clk/mmp/clk.h
+++ b/drivers/clk/mmp/clk.h
@@ -7,7 +7,7 @@
#define APBC_NO_BUS_CTRL BIT(0)
#define APBC_POWER_CTRL BIT(1)

-struct clk_factor_masks {
+struct mmp_clk_factor_masks {
unsigned int factor;
unsigned int num_mask;
unsigned int den_mask;
@@ -15,7 +15,7 @@ struct clk_factor_masks {
unsigned int den_shift;
};

-struct clk_factor_tbl {
+struct mmp_clk_factor_tbl {
unsigned int num;
unsigned int den;
};
@@ -30,6 +30,6 @@ extern struct clk *mmp_clk_register_apmu(const char *name,
spinlock_t *lock);
extern struct clk *mmp_clk_register_factor(const char *name,
const char *parent_name, unsigned long flags,
- void __iomem *base, struct clk_factor_masks *masks,
- struct clk_factor_tbl *ftbl, unsigned int ftbl_cnt);
+ void __iomem *base, struct mmp_clk_factor_masks *masks,
+ struct mmp_clk_factor_tbl *ftbl, unsigned int ftbl_cnt);
#endif
--
1.8.3.2

2014-06-10 01:34:06

by Chao Xie

[permalink] [raw]
Subject: [PATCH 02/12] clk: mmp: add spin lock for clk-frac

From: Chao Xie <[email protected]>

The register used by clk-frac may be shared with
other clocks.
So it needs to use spin lock to protect the register
access.

Signed-off-by: Chao Xie <[email protected]>
---
drivers/clk/mmp/clk-frac.c | 11 ++++++++++-
drivers/clk/mmp/clk-mmp2.c | 2 +-
drivers/clk/mmp/clk-pxa168.c | 2 +-
drivers/clk/mmp/clk-pxa910.c | 2 +-
drivers/clk/mmp/clk.h | 3 ++-
5 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/drivers/clk/mmp/clk-frac.c b/drivers/clk/mmp/clk-frac.c
index 3fbc9ca..e29d006 100644
--- a/drivers/clk/mmp/clk-frac.c
+++ b/drivers/clk/mmp/clk-frac.c
@@ -29,6 +29,7 @@ struct mmp_clk_factor {
struct mmp_clk_factor_masks *masks;
struct mmp_clk_factor_tbl *ftbl;
unsigned int ftbl_cnt;
+ spinlock_t *lock;
};

static long clk_factor_round_rate(struct clk_hw *hw, unsigned long drate,
@@ -86,6 +87,7 @@ static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate,
int i;
unsigned long val;
unsigned long prev_rate, rate = 0;
+ unsigned long flags = 0;

for (i = 0; i < factor->ftbl_cnt; i++) {
prev_rate = rate;
@@ -97,6 +99,9 @@ static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate,
if (i > 0)
i--;

+ if (factor->lock)
+ spin_lock_irqsave(factor->lock, flags);
+
val = readl_relaxed(factor->base);

val &= ~(masks->num_mask << masks->num_shift);
@@ -107,6 +112,9 @@ static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate,

writel_relaxed(val, factor->base);

+ if (factor->lock)
+ spin_unlock_irqrestore(factor->lock, flags);
+
return 0;
}

@@ -120,7 +128,7 @@ struct clk *mmp_clk_register_factor(const char *name, const char *parent_name,
unsigned long flags, void __iomem *base,
struct mmp_clk_factor_masks *masks,
struct mmp_clk_factor_tbl *ftbl,
- unsigned int ftbl_cnt)
+ unsigned int ftbl_cnt, spinlock_t *lock)
{
struct mmp_clk_factor *factor;
struct clk_init_data init;
@@ -143,6 +151,7 @@ struct clk *mmp_clk_register_factor(const char *name, const char *parent_name,
factor->ftbl = ftbl;
factor->ftbl_cnt = ftbl_cnt;
factor->hw.init = &init;
+ factor->lock = lock;

init.name = name;
init.ops = &clk_factor_ops;
diff --git a/drivers/clk/mmp/clk-mmp2.c b/drivers/clk/mmp/clk-mmp2.c
index 7083f12..5c90a42 100644
--- a/drivers/clk/mmp/clk-mmp2.c
+++ b/drivers/clk/mmp/clk-mmp2.c
@@ -191,7 +191,7 @@ void __init mmp2_clk_init(void)
clk = mmp_clk_register_factor("uart_pll", "pll1_4", 0,
mpmu_base + MPMU_UART_PLL,
&uart_factor_masks, uart_factor_tbl,
- ARRAY_SIZE(uart_factor_tbl));
+ ARRAY_SIZE(uart_factor_tbl), &clk_lock);
clk_set_rate(clk, 14745600);
clk_register_clkdev(clk, "uart_pll", NULL);

diff --git a/drivers/clk/mmp/clk-pxa168.c b/drivers/clk/mmp/clk-pxa168.c
index 75266ac..93e967c 100644
--- a/drivers/clk/mmp/clk-pxa168.c
+++ b/drivers/clk/mmp/clk-pxa168.c
@@ -158,7 +158,7 @@ void __init pxa168_clk_init(void)
uart_pll = mmp_clk_register_factor("uart_pll", "pll1_4", 0,
mpmu_base + MPMU_UART_PLL,
&uart_factor_masks, uart_factor_tbl,
- ARRAY_SIZE(uart_factor_tbl));
+ ARRAY_SIZE(uart_factor_tbl), &clk_lock);
clk_set_rate(uart_pll, 14745600);
clk_register_clkdev(uart_pll, "uart_pll", NULL);

diff --git a/drivers/clk/mmp/clk-pxa910.c b/drivers/clk/mmp/clk-pxa910.c
index f817999..993abcd 100644
--- a/drivers/clk/mmp/clk-pxa910.c
+++ b/drivers/clk/mmp/clk-pxa910.c
@@ -163,7 +163,7 @@ void __init pxa910_clk_init(void)
uart_pll = mmp_clk_register_factor("uart_pll", "pll1_4", 0,
mpmu_base + MPMU_UART_PLL,
&uart_factor_masks, uart_factor_tbl,
- ARRAY_SIZE(uart_factor_tbl));
+ ARRAY_SIZE(uart_factor_tbl), &clk_lock);
clk_set_rate(uart_pll, 14745600);
clk_register_clkdev(uart_pll, "uart_pll", NULL);

diff --git a/drivers/clk/mmp/clk.h b/drivers/clk/mmp/clk.h
index 3fe92be..b71b717 100644
--- a/drivers/clk/mmp/clk.h
+++ b/drivers/clk/mmp/clk.h
@@ -31,5 +31,6 @@ extern struct clk *mmp_clk_register_apmu(const char *name,
extern struct clk *mmp_clk_register_factor(const char *name,
const char *parent_name, unsigned long flags,
void __iomem *base, struct mmp_clk_factor_masks *masks,
- struct mmp_clk_factor_tbl *ftbl, unsigned int ftbl_cnt);
+ struct mmp_clk_factor_tbl *ftbl, unsigned int ftbl_cnt,
+ spinlock_t *lock);
#endif
--
1.8.3.2