All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 00/10] update irqchip, clocksource, clk for mmp
@ 2013-06-04  4:12 Haojian Zhuang
  2013-06-04  4:12 ` [PATCH v4 01/10] irqchip: move mmp irq driver Haojian Zhuang
                   ` (10 more replies)
  0 siblings, 11 replies; 13+ messages in thread
From: Haojian Zhuang @ 2013-06-04  4:12 UTC (permalink / raw)
  To: linux-arm-kernel

Changelog:
v4:
1. Remove .init_irq in mmp & mmp2 DT machine descriptor.
2. Use an argument to replace TIMER_PHYS_BASE. Now transfer virtual
address directly.
3. Merge 10th & 11th patches together. Remove the redundant changes
on drivers/clocksource/Kconfig & drivers/clocksource/Makefile.

v3:
1. Don't use include/linux/irqchip/mmp.h since we don't need to
move <mach/irqs.h> to <include/linux/irqchip/mmp.h>.
2. Move timer-mmp driver into clocksource directory & support
clocksource.
3. Support clksrc in mmp & parse all clock from DTS.

v2:
1. Avoid to include <mach/irqs.h>. Move the head file into
? ?include/linux/irqchip directory.
2. Avoid to include <mach/pm-pxa910.h> & <mach/pm-mmp2.h>.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v4 01/10] irqchip: move mmp irq driver
  2013-06-04  4:12 [PATCH v4 00/10] update irqchip, clocksource, clk for mmp Haojian Zhuang
@ 2013-06-04  4:12 ` Haojian Zhuang
  2013-06-04  4:12 ` [PATCH v4 02/10] irqchip: mmp: support irqchip Haojian Zhuang
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Haojian Zhuang @ 2013-06-04  4:12 UTC (permalink / raw)
  To: linux-arm-kernel

Move irq-mmp driver from mach-mmp directory into irqchip directory.

Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
 arch/arm/mach-mmp/Makefile                           | 2 +-
 arch/arm/mach-mmp/common.h                           | 1 -
 arch/arm/mach-mmp/include/mach/pxa168.h              | 1 +
 arch/arm/mach-mmp/include/mach/pxa910.h              | 1 +
 arch/arm/mach-mmp/pxa910.c                           | 1 +
 drivers/irqchip/Makefile                             | 1 +
 arch/arm/mach-mmp/irq.c => drivers/irqchip/irq-mmp.c | 2 --
 7 files changed, 5 insertions(+), 4 deletions(-)
 rename arch/arm/mach-mmp/irq.c => drivers/irqchip/irq-mmp.c (99%)

diff --git a/arch/arm/mach-mmp/Makefile b/arch/arm/mach-mmp/Makefile
index 095c155..9b702a1 100644
--- a/arch/arm/mach-mmp/Makefile
+++ b/arch/arm/mach-mmp/Makefile
@@ -2,7 +2,7 @@
 # Makefile for Marvell's PXA168 processors line
 #
 
-obj-y				+= common.o devices.o time.o irq.o
+obj-y				+= common.o devices.o time.o
 
 # SoC support
 obj-$(CONFIG_CPU_PXA168)	+= pxa168.o
diff --git a/arch/arm/mach-mmp/common.h b/arch/arm/mach-mmp/common.h
index 0bdc50b..9c1c9be 100644
--- a/arch/arm/mach-mmp/common.h
+++ b/arch/arm/mach-mmp/common.h
@@ -2,7 +2,6 @@
 
 extern void timer_init(int irq);
 
-extern void __init icu_init_irq(void);
 extern void __init mmp_map_io(void);
 extern void mmp_restart(char, const char *);
 extern void __init pxa168_clk_init(void);
diff --git a/arch/arm/mach-mmp/include/mach/pxa168.h b/arch/arm/mach-mmp/include/mach/pxa168.h
index 7ed1df2..e01dc2a 100644
--- a/arch/arm/mach-mmp/include/mach/pxa168.h
+++ b/arch/arm/mach-mmp/include/mach/pxa168.h
@@ -2,6 +2,7 @@
 #define __ASM_MACH_PXA168_H
 
 extern void pxa168_timer_init(void);
+extern void __init icu_init_irq(void);
 extern void __init pxa168_init_irq(void);
 extern void pxa168_restart(char, const char *);
 extern void pxa168_clear_keypad_wakeup(void);
diff --git a/arch/arm/mach-mmp/include/mach/pxa910.h b/arch/arm/mach-mmp/include/mach/pxa910.h
index b914afa..9225320 100644
--- a/arch/arm/mach-mmp/include/mach/pxa910.h
+++ b/arch/arm/mach-mmp/include/mach/pxa910.h
@@ -2,6 +2,7 @@
 #define __ASM_MACH_PXA910_H
 
 extern void pxa910_timer_init(void);
+extern void __init icu_init_irq(void);
 extern void __init pxa910_init_irq(void);
 
 #include <linux/i2c.h>
diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c
index ce6393a..a586742 100644
--- a/arch/arm/mach-mmp/pxa910.c
+++ b/arch/arm/mach-mmp/pxa910.c
@@ -23,6 +23,7 @@
 #include <mach/dma.h>
 #include <mach/mfp.h>
 #include <mach/devices.h>
+#include <mach/pxa910.h>
 
 #include "common.h"
 
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index cda4cb5..542d47e 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_ARCH_MXS)			+= irq-mxs.o
 obj-$(CONFIG_ARCH_S3C24XX)		+= irq-s3c24xx.o
 obj-$(CONFIG_METAG)			+= irq-metag-ext.o
 obj-$(CONFIG_METAG_PERFCOUNTER_IRQS)	+= irq-metag.o
+obj-$(CONFIG_ARCH_MMP)			+= irq-mmp.o
 obj-$(CONFIG_ARCH_SUNXI)		+= irq-sun4i.o
 obj-$(CONFIG_ARCH_SPEAR3XX)		+= spear-shirq.o
 obj-$(CONFIG_ARM_GIC)			+= irq-gic.o
diff --git a/arch/arm/mach-mmp/irq.c b/drivers/irqchip/irq-mmp.c
similarity index 99%
rename from arch/arm/mach-mmp/irq.c
rename to drivers/irqchip/irq-mmp.c
index 3c71246..dab6def 100644
--- a/arch/arm/mach-mmp/irq.c
+++ b/drivers/irqchip/irq-mmp.c
@@ -30,8 +30,6 @@
 #include <mach/pm-pxa910.h>
 #endif
 
-#include "common.h"
-
 #define MAX_ICU_NR		16
 
 struct icu_chip_data {
-- 
1.8.1.2

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v4 02/10] irqchip: mmp: support irqchip
  2013-06-04  4:12 [PATCH v4 00/10] update irqchip, clocksource, clk for mmp Haojian Zhuang
  2013-06-04  4:12 ` [PATCH v4 01/10] irqchip: move mmp irq driver Haojian Zhuang
@ 2013-06-04  4:12 ` Haojian Zhuang
  2013-06-04  4:12 ` [PATCH v4 03/10] irqchip: mmp: support MULTI_IRQ_HANDLER Haojian Zhuang
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Haojian Zhuang @ 2013-06-04  4:12 UTC (permalink / raw)
  To: linux-arm-kernel

Support IRQCHIP on irq-mmp driver.

Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
 arch/arm/mach-mmp/mmp-dt.c  |   8 +-
 arch/arm/mach-mmp/mmp2-dt.c |   8 +-
 drivers/irqchip/irq-mmp.c   | 238 +++++++++++++++++++++++---------------------
 3 files changed, 126 insertions(+), 128 deletions(-)

diff --git a/arch/arm/mach-mmp/mmp-dt.c b/arch/arm/mach-mmp/mmp-dt.c
index b37915d..cca529c 100644
--- a/arch/arm/mach-mmp/mmp-dt.c
+++ b/arch/arm/mach-mmp/mmp-dt.c
@@ -9,17 +9,13 @@
  *  publishhed by the Free Software Foundation.
  */
 
-#include <linux/irq.h>
-#include <linux/irqdomain.h>
-#include <linux/of_irq.h>
+#include <linux/irqchip.h>
 #include <linux/of_platform.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
-#include <mach/irqs.h>
 
 #include "common.h"
 
-extern void __init mmp_dt_irq_init(void);
 extern void __init mmp_dt_init_timer(void);
 
 static const struct of_dev_auxdata pxa168_auxdata_lookup[] __initconst = {
@@ -64,7 +60,6 @@ static const char *mmp_dt_board_compat[] __initdata = {
 
 DT_MACHINE_START(PXA168_DT, "Marvell PXA168 (Device Tree Support)")
 	.map_io		= mmp_map_io,
-	.init_irq	= mmp_dt_irq_init,
 	.init_time	= mmp_dt_init_timer,
 	.init_machine	= pxa168_dt_init,
 	.dt_compat	= mmp_dt_board_compat,
@@ -72,7 +67,6 @@ MACHINE_END
 
 DT_MACHINE_START(PXA910_DT, "Marvell PXA910 (Device Tree Support)")
 	.map_io		= mmp_map_io,
-	.init_irq	= mmp_dt_irq_init,
 	.init_time	= mmp_dt_init_timer,
 	.init_machine	= pxa910_dt_init,
 	.dt_compat	= mmp_dt_board_compat,
diff --git a/arch/arm/mach-mmp/mmp2-dt.c b/arch/arm/mach-mmp/mmp2-dt.c
index 4ac2567..023cb45 100644
--- a/arch/arm/mach-mmp/mmp2-dt.c
+++ b/arch/arm/mach-mmp/mmp2-dt.c
@@ -10,18 +10,13 @@
  */
 
 #include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/irqdomain.h>
-#include <linux/of_irq.h>
+#include <linux/irqchip.h>
 #include <linux/of_platform.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
-#include <mach/irqs.h>
-#include <mach/regs-apbc.h>
 
 #include "common.h"
 
-extern void __init mmp_dt_irq_init(void);
 extern void __init mmp_dt_init_timer(void);
 
 static const struct of_dev_auxdata mmp2_auxdata_lookup[] __initconst = {
@@ -49,7 +44,6 @@ static const char *mmp2_dt_board_compat[] __initdata = {
 
 DT_MACHINE_START(MMP2_DT, "Marvell MMP2 (Device Tree Support)")
 	.map_io		= mmp_map_io,
-	.init_irq	= mmp_dt_irq_init,
 	.init_time	= mmp_dt_init_timer,
 	.init_machine	= mmp2_dt_init,
 	.dt_compat	= mmp2_dt_board_compat,
diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c
index dab6def..275709b 100644
--- a/drivers/irqchip/irq-mmp.c
+++ b/drivers/irqchip/irq-mmp.c
@@ -30,6 +30,8 @@
 #include <mach/pm-pxa910.h>
 #endif
 
+#include "irqchip.h"
+
 #define MAX_ICU_NR		16
 
 struct icu_chip_data {
@@ -324,138 +326,146 @@ void __init mmp2_init_icu(void)
 }
 
 #ifdef CONFIG_OF
-static const struct of_device_id intc_ids[] __initconst = {
-	{ .compatible = "mrvl,mmp-intc", .data = &mmp_conf },
-	{ .compatible = "mrvl,mmp2-intc", .data = &mmp2_conf },
-	{}
-};
-
-static const struct of_device_id mmp_mux_irq_match[] __initconst = {
-	{ .compatible = "mrvl,mmp2-mux-intc" },
-	{}
-};
-
-int __init mmp2_mux_init(struct device_node *parent)
+static int __init mmp_init_bases(struct device_node *node)
 {
-	struct device_node *node;
-	const struct of_device_id *of_id;
-	struct resource res;
-	int i, irq_base, ret, irq;
-	u32 nr_irqs, mfp_irq;
+	int ret, nr_irqs, irq, i = 0;
 
-	node = parent;
-	max_icu_nr = 1;
-	for (i = 1; i < MAX_ICU_NR; i++) {
-		node = of_find_matching_node(node, mmp_mux_irq_match);
-		if (!node)
-			break;
-		of_id = of_match_node(&mmp_mux_irq_match[0], node);
-		ret = of_property_read_u32(node, "mrvl,intc-nr-irqs",
-					   &nr_irqs);
-		if (ret) {
-			pr_err("Not found mrvl,intc-nr-irqs property\n");
-			ret = -EINVAL;
-			goto err;
-		}
-		ret = of_address_to_resource(node, 0, &res);
-		if (ret < 0) {
-			pr_err("Not found reg property\n");
-			ret = -EINVAL;
-			goto err;
-		}
-		icu_data[i].reg_status = mmp_icu_base + res.start;
-		ret = of_address_to_resource(node, 1, &res);
-		if (ret < 0) {
-			pr_err("Not found reg property\n");
-			ret = -EINVAL;
-			goto err;
-		}
-		icu_data[i].reg_mask = mmp_icu_base + res.start;
-		icu_data[i].cascade_irq = irq_of_parse_and_map(node, 0);
-		if (!icu_data[i].cascade_irq) {
-			ret = -EINVAL;
-			goto err;
-		}
+	ret = of_property_read_u32(node, "mrvl,intc-nr-irqs", &nr_irqs);
+	if (ret) {
+		pr_err("Not found mrvl,intc-nr-irqs property\n");
+		return ret;
+	}
 
-		irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
-		if (irq_base < 0) {
-			pr_err("Failed to allocate IRQ numbers for mux intc\n");
-			ret = irq_base;
+	mmp_icu_base = of_iomap(node, 0);
+	if (!mmp_icu_base) {
+		pr_err("Failed to get interrupt controller register\n");
+		return -ENOMEM;
+	}
+
+	icu_data[0].virq_base = 0;
+	icu_data[0].domain = irq_domain_add_linear(node, nr_irqs,
+						   &mmp_irq_domain_ops,
+						   &icu_data[0]);
+	for (irq = 0; irq < nr_irqs; irq++) {
+		ret = irq_create_mapping(icu_data[0].domain, irq);
+		if (!ret) {
+			pr_err("Failed to mapping hwirq\n");
 			goto err;
 		}
-		if (!of_property_read_u32(node, "mrvl,clr-mfp-irq",
-					  &mfp_irq)) {
-			icu_data[i].clr_mfp_irq_base = irq_base;
-			icu_data[i].clr_mfp_hwirq = mfp_irq;
-		}
-		irq_set_chained_handler(icu_data[i].cascade_irq,
-					icu_mux_irq_demux);
-		icu_data[i].nr_irqs = nr_irqs;
-		icu_data[i].virq_base = irq_base;
-		icu_data[i].domain = irq_domain_add_legacy(node, nr_irqs,
-							   irq_base, 0,
-							   &mmp_irq_domain_ops,
-							   &icu_data[i]);
-		for (irq = irq_base; irq < irq_base + nr_irqs; irq++)
-			icu_mask_irq(irq_get_irq_data(irq));
+		if (!irq)
+			icu_data[0].virq_base = ret;
 	}
-	max_icu_nr = i;
+	icu_data[0].nr_irqs = nr_irqs;
 	return 0;
 err:
-	of_node_put(node);
-	max_icu_nr = i;
-	return ret;
+	if (icu_data[0].virq_base) {
+		for (i = 0; i < irq; i++)
+			irq_dispose_mapping(icu_data[0].virq_base + i);
+	}
+	irq_domain_remove(icu_data[0].domain);
+	iounmap(mmp_icu_base);
+	return -EINVAL;
 }
 
-void __init mmp_dt_irq_init(void)
+static int __init mmp_of_init(struct device_node *node,
+			      struct device_node *parent)
 {
-	struct device_node *node;
-	const struct of_device_id *of_id;
-	struct mmp_intc_conf *conf;
-	int nr_irqs, irq_base, ret, irq;
-
-	node = of_find_matching_node(NULL, intc_ids);
-	if (!node) {
-		pr_err("Failed to find interrupt controller in arch-mmp\n");
-		return;
-	}
-	of_id = of_match_node(intc_ids, node);
-	conf = of_id->data;
+	int ret;
 
-	ret = of_property_read_u32(node, "mrvl,intc-nr-irqs", &nr_irqs);
+	ret = mmp_init_bases(node);
+	if (ret < 0)
+		return ret;
+
+	icu_data[0].conf_enable = mmp_conf.conf_enable;
+	icu_data[0].conf_disable = mmp_conf.conf_disable;
+	icu_data[0].conf_mask = mmp_conf.conf_mask;
+	irq_set_default_host(icu_data[0].domain);
+	max_icu_nr = 1;
+	return 0;
+}
+IRQCHIP_DECLARE(mmp_intc, "mrvl,mmp-intc", mmp_of_init);
+
+static int __init mmp2_of_init(struct device_node *node,
+			       struct device_node *parent)
+{
+	int ret;
+
+	ret = mmp_init_bases(node);
+	if (ret < 0)
+		return ret;
+
+	icu_data[0].conf_enable = mmp2_conf.conf_enable;
+	icu_data[0].conf_disable = mmp2_conf.conf_disable;
+	icu_data[0].conf_mask = mmp2_conf.conf_mask;
+	irq_set_default_host(icu_data[0].domain);
+	max_icu_nr = 1;
+	return 0;
+}
+IRQCHIP_DECLARE(mmp2_intc, "mrvl,mmp2-intc", mmp2_of_init);
+
+static int __init mmp2_mux_of_init(struct device_node *node,
+				   struct device_node *parent)
+{
+	struct resource res;
+	int i, ret, irq, j = 0;
+	u32 nr_irqs, mfp_irq;
+
+	if (!parent)
+		return -ENODEV;
+
+	i = max_icu_nr;
+	ret = of_property_read_u32(node, "mrvl,intc-nr-irqs",
+				   &nr_irqs);
 	if (ret) {
 		pr_err("Not found mrvl,intc-nr-irqs property\n");
-		return;
+		return -EINVAL;
 	}
-
-	mmp_icu_base = of_iomap(node, 0);
-	if (!mmp_icu_base) {
-		pr_err("Failed to get interrupt controller register\n");
-		return;
+	ret = of_address_to_resource(node, 0, &res);
+	if (ret < 0) {
+		pr_err("Not found reg property\n");
+		return -EINVAL;
 	}
-
-	irq_base = irq_alloc_descs(-1, 0, nr_irqs - NR_IRQS_LEGACY, 0);
-	if (irq_base < 0) {
-		pr_err("Failed to allocate IRQ numbers\n");
-		goto err;
-	} else if (irq_base != NR_IRQS_LEGACY) {
-		pr_err("ICU's irqbase should be started from 0\n");
-		goto err;
+	icu_data[i].reg_status = mmp_icu_base + res.start;
+	ret = of_address_to_resource(node, 1, &res);
+	if (ret < 0) {
+		pr_err("Not found reg property\n");
+		return -EINVAL;
 	}
-	icu_data[0].conf_enable = conf->conf_enable;
-	icu_data[0].conf_disable = conf->conf_disable;
-	icu_data[0].conf_mask = conf->conf_mask;
-	icu_data[0].nr_irqs = nr_irqs;
-	icu_data[0].virq_base = 0;
-	icu_data[0].domain = irq_domain_add_legacy(node, nr_irqs, 0, 0,
+	icu_data[i].reg_mask = mmp_icu_base + res.start;
+	icu_data[i].cascade_irq = irq_of_parse_and_map(node, 0);
+	if (!icu_data[i].cascade_irq)
+		return -EINVAL;
+
+	icu_data[i].virq_base = 0;
+	icu_data[i].domain = irq_domain_add_linear(node, nr_irqs,
 						   &mmp_irq_domain_ops,
-						   &icu_data[0]);
-	irq_set_default_host(icu_data[0].domain);
-	for (irq = 0; irq < nr_irqs; irq++)
-		icu_mask_irq(irq_get_irq_data(irq));
-	mmp2_mux_init(node);
-	return;
+						   &icu_data[i]);
+	for (irq = 0; irq < nr_irqs; irq++) {
+		ret = irq_create_mapping(icu_data[i].domain, irq);
+		if (!ret) {
+			pr_err("Failed to mapping hwirq\n");
+			goto err;
+		}
+		if (!irq)
+			icu_data[i].virq_base = ret;
+	}
+	icu_data[i].nr_irqs = nr_irqs;
+	if (!of_property_read_u32(node, "mrvl,clr-mfp-irq",
+				  &mfp_irq)) {
+		icu_data[i].clr_mfp_irq_base = icu_data[i].virq_base;
+		icu_data[i].clr_mfp_hwirq = mfp_irq;
+	}
+	irq_set_chained_handler(icu_data[i].cascade_irq,
+				icu_mux_irq_demux);
+	max_icu_nr++;
+	return 0;
 err:
-	iounmap(mmp_icu_base);
+	if (icu_data[i].virq_base) {
+		for (j = 0; j < irq; j++)
+			irq_dispose_mapping(icu_data[i].virq_base + j);
+	}
+	irq_domain_remove(icu_data[i].domain);
+	return -EINVAL;
 }
+IRQCHIP_DECLARE(mmp2_mux_intc, "mrvl,mmp2-mux-intc", mmp2_mux_of_init);
 #endif
-- 
1.8.1.2

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v4 03/10] irqchip: mmp: support MULTI_IRQ_HANDLER
  2013-06-04  4:12 [PATCH v4 00/10] update irqchip, clocksource, clk for mmp Haojian Zhuang
  2013-06-04  4:12 ` [PATCH v4 01/10] irqchip: move mmp irq driver Haojian Zhuang
  2013-06-04  4:12 ` [PATCH v4 02/10] irqchip: mmp: support irqchip Haojian Zhuang
@ 2013-06-04  4:12 ` Haojian Zhuang
  2013-06-04  4:12 ` [PATCH v4 04/10] ARM: mmp: avoid to include head file in mach-mmp Haojian Zhuang
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Haojian Zhuang @ 2013-06-04  4:12 UTC (permalink / raw)
  To: linux-arm-kernel

Support CONFIG_MULTI_IRQ_HANDLER in ARCH_MMP. So remove entry-macro.S.

Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
 arch/arm/Kconfig                             |  1 +
 arch/arm/mach-mmp/include/mach/entry-macro.S | 26 -----------------
 drivers/irqchip/irq-mmp.c                    | 42 +++++++++++++++++++++++++++-
 3 files changed, 42 insertions(+), 27 deletions(-)
 delete mode 100644 arch/arm/mach-mmp/include/mach/entry-macro.S

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index d423d58..d6ba351 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -549,6 +549,7 @@ config ARCH_MMP
 	select GENERIC_CLOCKEVENTS
 	select GPIO_PXA
 	select IRQ_DOMAIN
+	select MULTI_IRQ_HANDLER
 	select NEED_MACH_GPIO_H
 	select PINCTRL
 	select PLAT_PXA
diff --git a/arch/arm/mach-mmp/include/mach/entry-macro.S b/arch/arm/mach-mmp/include/mach/entry-macro.S
deleted file mode 100644
index bd152e2..0000000
--- a/arch/arm/mach-mmp/include/mach/entry-macro.S
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * linux/arch/arm/mach-mmp/include/mach/entry-macro.S
- *
- * 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
- * published by the Free Software Foundation.
- */
-
-#include <asm/irq.h>
-#include <mach/regs-icu.h>
-
-	.macro	get_irqnr_preamble, base, tmp
-	mrc	p15, 0, \tmp, c0, c0, 0		@ CPUID
-	and	\tmp, \tmp, #0xff00
-	cmp	\tmp, #0x5800
-	ldr	\base, =mmp_icu_base
-	ldr	\base, [\base, #0]
-	addne	\base, \base, #0x10c		@ PJ1 AP INT SEL register
-	addeq	\base, \base, #0x104		@ PJ4 IRQ SEL register
-	.endm
-
-	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
-	ldr	\tmp, [\base, #0]
-	and	\irqnr, \tmp, #0x3f
-	tst	\tmp, #(1 << 6)
-	.endm
diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c
index 275709b..84d51ff 100644
--- a/drivers/irqchip/irq-mmp.c
+++ b/drivers/irqchip/irq-mmp.c
@@ -21,6 +21,9 @@
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 
+#include <asm/exception.h>
+#include <asm/mach/irq.h>
+
 #include <mach/irqs.h>
 
 #ifdef CONFIG_CPU_MMP2
@@ -34,6 +37,13 @@
 
 #define MAX_ICU_NR		16
 
+#define PJ1_INT_SEL		0x10c
+#define PJ4_INT_SEL		0x104
+
+/* bit fields in PJ1_INT_SEL and PJ4_INT_SEL */
+#define SEL_INT_PENDING		(1 << 6)
+#define SEL_INT_NUM_MASK	0x3f
+
 struct icu_chip_data {
 	int			nr_irqs;
 	unsigned int		virq_base;
@@ -54,7 +64,7 @@ struct mmp_intc_conf {
 	unsigned int	conf_mask;
 };
 
-void __iomem *mmp_icu_base;
+static void __iomem *mmp_icu_base;
 static struct icu_chip_data icu_data[MAX_ICU_NR];
 static int max_icu_nr;
 
@@ -193,6 +203,32 @@ static struct mmp_intc_conf mmp2_conf = {
 	.conf_mask	= 0x7f,
 };
 
+static asmlinkage void __exception_irq_entry
+mmp_handle_irq(struct pt_regs *regs)
+{
+	int irq, hwirq;
+
+	hwirq = readl_relaxed(mmp_icu_base + PJ1_INT_SEL);
+	if (!(hwirq & SEL_INT_PENDING))
+		return;
+	hwirq &= SEL_INT_NUM_MASK;
+	irq = irq_find_mapping(icu_data[0].domain, hwirq);
+	handle_IRQ(irq, regs);
+}
+
+static asmlinkage void __exception_irq_entry
+mmp2_handle_irq(struct pt_regs *regs)
+{
+	int irq, hwirq;
+
+	hwirq = readl_relaxed(mmp_icu_base + PJ4_INT_SEL);
+	if (!(hwirq & SEL_INT_PENDING))
+		return;
+	hwirq &= SEL_INT_NUM_MASK;
+	irq = irq_find_mapping(icu_data[0].domain, hwirq);
+	handle_IRQ(irq, regs);
+}
+
 /* MMP (ARMv5) */
 void __init icu_init_irq(void)
 {
@@ -214,6 +250,7 @@ void __init icu_init_irq(void)
 		set_irq_flags(irq, IRQF_VALID);
 	}
 	irq_set_default_host(icu_data[0].domain);
+	set_handle_irq(mmp_handle_irq);
 #ifdef CONFIG_CPU_PXA910
 	icu_irq_chip.irq_set_wake = pxa910_set_wake;
 #endif
@@ -320,6 +357,7 @@ void __init mmp2_init_icu(void)
 		set_irq_flags(irq, IRQF_VALID);
 	}
 	irq_set_default_host(icu_data[0].domain);
+	set_handle_irq(mmp2_handle_irq);
 #ifdef CONFIG_CPU_MMP2
 	icu_irq_chip.irq_set_wake = mmp2_set_wake;
 #endif
@@ -380,6 +418,7 @@ static int __init mmp_of_init(struct device_node *node,
 	icu_data[0].conf_disable = mmp_conf.conf_disable;
 	icu_data[0].conf_mask = mmp_conf.conf_mask;
 	irq_set_default_host(icu_data[0].domain);
+	set_handle_irq(mmp_handle_irq);
 	max_icu_nr = 1;
 	return 0;
 }
@@ -398,6 +437,7 @@ static int __init mmp2_of_init(struct device_node *node,
 	icu_data[0].conf_disable = mmp2_conf.conf_disable;
 	icu_data[0].conf_mask = mmp2_conf.conf_mask;
 	irq_set_default_host(icu_data[0].domain);
+	set_handle_irq(mmp2_handle_irq);
 	max_icu_nr = 1;
 	return 0;
 }
-- 
1.8.1.2

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v4 04/10] ARM: mmp: avoid to include head file in mach-mmp
  2013-06-04  4:12 [PATCH v4 00/10] update irqchip, clocksource, clk for mmp Haojian Zhuang
                   ` (2 preceding siblings ...)
  2013-06-04  4:12 ` [PATCH v4 03/10] irqchip: mmp: support MULTI_IRQ_HANDLER Haojian Zhuang
@ 2013-06-04  4:12 ` Haojian Zhuang
  2013-06-04  4:12 ` [PATCH v4 05/10] irqchip: mmp: avoid to include irqs head file Haojian Zhuang
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Haojian Zhuang @ 2013-06-04  4:12 UTC (permalink / raw)
  To: linux-arm-kernel

pxa910_set_wake() & mmp2_set_wake() are both declared in head files
of arch/arm/mach-mmp/include/mach directory. If we include these
head files in irq-mmp driver, it blocks the multiplatform build.
So adjust the code.

Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
 arch/arm/mach-mmp/mmp2.c    |  4 ++++
 arch/arm/mach-mmp/pxa910.c  |  4 ++++
 drivers/irqchip/irq-mmp.c   | 15 +--------------
 include/linux/irqchip/mmp.h |  6 ++++++
 4 files changed, 15 insertions(+), 14 deletions(-)
 create mode 100644 include/linux/irqchip/mmp.h

diff --git a/arch/arm/mach-mmp/mmp2.c b/arch/arm/mach-mmp/mmp2.c
index c7592f1..09fbe7d 100644
--- a/arch/arm/mach-mmp/mmp2.c
+++ b/arch/arm/mach-mmp/mmp2.c
@@ -13,6 +13,8 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqchip/mmp.h>
 #include <linux/platform_device.h>
 
 #include <asm/hardware/cache-tauros2.h>
@@ -26,6 +28,7 @@
 #include <mach/mfp.h>
 #include <mach/devices.h>
 #include <mach/mmp2.h>
+#include <mach/pm-mmp2.h>
 
 #include "common.h"
 
@@ -94,6 +97,7 @@ void mmp2_clear_pmic_int(void)
 void __init mmp2_init_irq(void)
 {
 	mmp2_init_icu();
+	icu_irq_chip.irq_set_wake = mmp2_set_wake;
 }
 
 static int __init mmp2_init(void)
diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c
index a586742..96e125b 100644
--- a/arch/arm/mach-mmp/pxa910.c
+++ b/arch/arm/mach-mmp/pxa910.c
@@ -12,6 +12,8 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqchip/mmp.h>
 #include <linux/platform_device.h>
 
 #include <asm/hardware/cache-tauros2.h>
@@ -23,6 +25,7 @@
 #include <mach/dma.h>
 #include <mach/mfp.h>
 #include <mach/devices.h>
+#include <mach/pm-pxa910.h>
 #include <mach/pxa910.h>
 
 #include "common.h"
@@ -80,6 +83,7 @@ static struct mfp_addr_map pxa910_mfp_addr_map[] __initdata =
 void __init pxa910_init_irq(void)
 {
 	icu_init_irq();
+	icu_irq_chip.irq_set_wake = pxa910_set_wake;
 }
 
 static int __init pxa910_init(void)
diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c
index 84d51ff..1f81432 100644
--- a/drivers/irqchip/irq-mmp.c
+++ b/drivers/irqchip/irq-mmp.c
@@ -26,13 +26,6 @@
 
 #include <mach/irqs.h>
 
-#ifdef CONFIG_CPU_MMP2
-#include <mach/pm-mmp2.h>
-#endif
-#ifdef CONFIG_CPU_PXA910
-#include <mach/pm-pxa910.h>
-#endif
-
 #include "irqchip.h"
 
 #define MAX_ICU_NR		16
@@ -132,7 +125,7 @@ static void icu_unmask_irq(struct irq_data *d)
 	}
 }
 
-static struct irq_chip icu_irq_chip = {
+struct irq_chip icu_irq_chip = {
 	.name		= "icu_irq",
 	.irq_mask	= icu_mask_irq,
 	.irq_mask_ack	= icu_mask_ack_irq,
@@ -251,9 +244,6 @@ void __init icu_init_irq(void)
 	}
 	irq_set_default_host(icu_data[0].domain);
 	set_handle_irq(mmp_handle_irq);
-#ifdef CONFIG_CPU_PXA910
-	icu_irq_chip.irq_set_wake = pxa910_set_wake;
-#endif
 }
 
 /* MMP2 (ARMv7) */
@@ -358,9 +348,6 @@ void __init mmp2_init_icu(void)
 	}
 	irq_set_default_host(icu_data[0].domain);
 	set_handle_irq(mmp2_handle_irq);
-#ifdef CONFIG_CPU_MMP2
-	icu_irq_chip.irq_set_wake = mmp2_set_wake;
-#endif
 }
 
 #ifdef CONFIG_OF
diff --git a/include/linux/irqchip/mmp.h b/include/linux/irqchip/mmp.h
new file mode 100644
index 0000000..c78a892
--- /dev/null
+++ b/include/linux/irqchip/mmp.h
@@ -0,0 +1,6 @@
+#ifndef	__IRQCHIP_MMP_H
+#define	__IRQCHIP_MMP_H
+
+extern struct irq_chip icu_irq_chip;
+
+#endif	/* __IRQCHIP_MMP_H */
-- 
1.8.1.2

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v4 05/10] irqchip: mmp: avoid to include irqs head file
  2013-06-04  4:12 [PATCH v4 00/10] update irqchip, clocksource, clk for mmp Haojian Zhuang
                   ` (3 preceding siblings ...)
  2013-06-04  4:12 ` [PATCH v4 04/10] ARM: mmp: avoid to include head file in mach-mmp Haojian Zhuang
@ 2013-06-04  4:12 ` Haojian Zhuang
  2013-06-04  4:12 ` [PATCH v4 06/10] clocksource: mmp: move mmp timer driver Haojian Zhuang
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Haojian Zhuang @ 2013-06-04  4:12 UTC (permalink / raw)
  To: linux-arm-kernel

Since <mach/irqs.h> in irq-mmp.c blocks the multiplatform build,
remove it instead.

Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
 drivers/irqchip/irq-mmp.c | 45 +++++++++++++++++++++------------------------
 1 file changed, 21 insertions(+), 24 deletions(-)

diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c
index 1f81432..2cb7cd0 100644
--- a/drivers/irqchip/irq-mmp.c
+++ b/drivers/irqchip/irq-mmp.c
@@ -24,8 +24,6 @@
 #include <asm/exception.h>
 #include <asm/mach/irq.h>
 
-#include <mach/irqs.h>
-
 #include "irqchip.h"
 
 #define MAX_ICU_NR		16
@@ -249,7 +247,7 @@ void __init icu_init_irq(void)
 /* MMP2 (ARMv7) */
 void __init mmp2_init_icu(void)
 {
-	int irq;
+	int irq, end;
 
 	max_icu_nr = 8;
 	mmp_icu_base = ioremap(0xd4282000, 0x1000);
@@ -263,11 +261,12 @@ void __init mmp2_init_icu(void)
 						   &icu_data[0]);
 	icu_data[1].reg_status = mmp_icu_base + 0x150;
 	icu_data[1].reg_mask = mmp_icu_base + 0x168;
-	icu_data[1].clr_mfp_irq_base = IRQ_MMP2_PMIC_BASE;
-	icu_data[1].clr_mfp_hwirq = IRQ_MMP2_PMIC - IRQ_MMP2_PMIC_BASE;
+	icu_data[1].clr_mfp_irq_base = icu_data[0].virq_base +
+				icu_data[0].nr_irqs;
+	icu_data[1].clr_mfp_hwirq = 1;		/* offset to IRQ_MMP2_PMIC_BASE */
 	icu_data[1].nr_irqs = 2;
 	icu_data[1].cascade_irq = 4;
-	icu_data[1].virq_base = IRQ_MMP2_PMIC_BASE;
+	icu_data[1].virq_base = icu_data[0].virq_base + icu_data[0].nr_irqs;
 	icu_data[1].domain = irq_domain_add_legacy(NULL, icu_data[1].nr_irqs,
 						   icu_data[1].virq_base, 0,
 						   &irq_domain_simple_ops,
@@ -276,7 +275,7 @@ void __init mmp2_init_icu(void)
 	icu_data[2].reg_mask = mmp_icu_base + 0x16c;
 	icu_data[2].nr_irqs = 2;
 	icu_data[2].cascade_irq = 5;
-	icu_data[2].virq_base = IRQ_MMP2_RTC_BASE;
+	icu_data[2].virq_base = icu_data[1].virq_base + icu_data[1].nr_irqs;
 	icu_data[2].domain = irq_domain_add_legacy(NULL, icu_data[2].nr_irqs,
 						   icu_data[2].virq_base, 0,
 						   &irq_domain_simple_ops,
@@ -285,7 +284,7 @@ void __init mmp2_init_icu(void)
 	icu_data[3].reg_mask = mmp_icu_base + 0x17c;
 	icu_data[3].nr_irqs = 3;
 	icu_data[3].cascade_irq = 9;
-	icu_data[3].virq_base = IRQ_MMP2_KEYPAD_BASE;
+	icu_data[3].virq_base = icu_data[2].virq_base + icu_data[2].nr_irqs;
 	icu_data[3].domain = irq_domain_add_legacy(NULL, icu_data[3].nr_irqs,
 						   icu_data[3].virq_base, 0,
 						   &irq_domain_simple_ops,
@@ -294,7 +293,7 @@ void __init mmp2_init_icu(void)
 	icu_data[4].reg_mask = mmp_icu_base + 0x170;
 	icu_data[4].nr_irqs = 5;
 	icu_data[4].cascade_irq = 17;
-	icu_data[4].virq_base = IRQ_MMP2_TWSI_BASE;
+	icu_data[4].virq_base = icu_data[3].virq_base + icu_data[3].nr_irqs;
 	icu_data[4].domain = irq_domain_add_legacy(NULL, icu_data[4].nr_irqs,
 						   icu_data[4].virq_base, 0,
 						   &irq_domain_simple_ops,
@@ -303,7 +302,7 @@ void __init mmp2_init_icu(void)
 	icu_data[5].reg_mask = mmp_icu_base + 0x174;
 	icu_data[5].nr_irqs = 15;
 	icu_data[5].cascade_irq = 35;
-	icu_data[5].virq_base = IRQ_MMP2_MISC_BASE;
+	icu_data[5].virq_base = icu_data[4].virq_base + icu_data[4].nr_irqs;
 	icu_data[5].domain = irq_domain_add_legacy(NULL, icu_data[5].nr_irqs,
 						   icu_data[5].virq_base, 0,
 						   &irq_domain_simple_ops,
@@ -312,7 +311,7 @@ void __init mmp2_init_icu(void)
 	icu_data[6].reg_mask = mmp_icu_base + 0x178;
 	icu_data[6].nr_irqs = 2;
 	icu_data[6].cascade_irq = 51;
-	icu_data[6].virq_base = IRQ_MMP2_MIPI_HSI1_BASE;
+	icu_data[6].virq_base = icu_data[5].virq_base + icu_data[5].nr_irqs;
 	icu_data[6].domain = irq_domain_add_legacy(NULL, icu_data[6].nr_irqs,
 						   icu_data[6].virq_base, 0,
 						   &irq_domain_simple_ops,
@@ -321,28 +320,26 @@ void __init mmp2_init_icu(void)
 	icu_data[7].reg_mask = mmp_icu_base + 0x184;
 	icu_data[7].nr_irqs = 2;
 	icu_data[7].cascade_irq = 55;
-	icu_data[7].virq_base = IRQ_MMP2_MIPI_HSI0_BASE;
+	icu_data[7].virq_base = icu_data[6].virq_base + icu_data[6].nr_irqs;
 	icu_data[7].domain = irq_domain_add_legacy(NULL, icu_data[7].nr_irqs,
 						   icu_data[7].virq_base, 0,
 						   &irq_domain_simple_ops,
 						   &icu_data[7]);
-	for (irq = 0; irq < IRQ_MMP2_MUX_END; irq++) {
+	end = icu_data[7].virq_base + icu_data[7].nr_irqs;
+	for (irq = 0; irq < end; irq++) {
 		icu_mask_irq(irq_get_irq_data(irq));
-		switch (irq) {
-		case IRQ_MMP2_PMIC_MUX:
-		case IRQ_MMP2_RTC_MUX:
-		case IRQ_MMP2_KEYPAD_MUX:
-		case IRQ_MMP2_TWSI_MUX:
-		case IRQ_MMP2_MISC_MUX:
-		case IRQ_MMP2_MIPI_HSI1_MUX:
-		case IRQ_MMP2_MIPI_HSI0_MUX:
+		if (irq == icu_data[1].cascade_irq ||
+		    irq == icu_data[2].cascade_irq ||
+		    irq == icu_data[3].cascade_irq ||
+		    irq == icu_data[4].cascade_irq ||
+		    irq == icu_data[5].cascade_irq ||
+		    irq == icu_data[6].cascade_irq ||
+		    irq == icu_data[7].cascade_irq) {
 			irq_set_chip(irq, &icu_irq_chip);
 			irq_set_chained_handler(irq, icu_mux_irq_demux);
-			break;
-		default:
+		} else {
 			irq_set_chip_and_handler(irq, &icu_irq_chip,
 						 handle_level_irq);
-			break;
 		}
 		set_irq_flags(irq, IRQF_VALID);
 	}
-- 
1.8.1.2

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v4 06/10] clocksource: mmp: move mmp timer driver
  2013-06-04  4:12 [PATCH v4 00/10] update irqchip, clocksource, clk for mmp Haojian Zhuang
                   ` (4 preceding siblings ...)
  2013-06-04  4:12 ` [PATCH v4 05/10] irqchip: mmp: avoid to include irqs head file Haojian Zhuang
@ 2013-06-04  4:12 ` Haojian Zhuang
  2013-06-04  4:12 ` [PATCH v4 07/10] ARM: mmp: move timer registers into driver Haojian Zhuang
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Haojian Zhuang @ 2013-06-04  4:12 UTC (permalink / raw)
  To: linux-arm-kernel

Move timer-mmp driver from mach-mmp to clocksource directory.

Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
 arch/arm/mach-mmp/Makefile                                  | 2 +-
 drivers/clocksource/Makefile                                | 1 +
 arch/arm/mach-mmp/time.c => drivers/clocksource/timer-mmp.c | 2 --
 3 files changed, 2 insertions(+), 3 deletions(-)
 rename arch/arm/mach-mmp/time.c => drivers/clocksource/timer-mmp.c (99%)

diff --git a/arch/arm/mach-mmp/Makefile b/arch/arm/mach-mmp/Makefile
index 9b702a1..5d4ccc6 100644
--- a/arch/arm/mach-mmp/Makefile
+++ b/arch/arm/mach-mmp/Makefile
@@ -2,7 +2,7 @@
 # Makefile for Marvell's PXA168 processors line
 #
 
-obj-y				+= common.o devices.o time.o
+obj-y				+= common.o devices.o
 
 # SoC support
 obj-$(CONFIG_CPU_PXA168)	+= pxa168.o
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 8d979c7..f6aa3b6 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_CLKSRC_DBX500_PRCMU)	+= clksrc-dbx500-prcmu.o
 obj-$(CONFIG_ARMADA_370_XP_TIMER)	+= time-armada-370-xp.o
 obj-$(CONFIG_ARCH_BCM2835)	+= bcm2835_timer.o
 obj-$(CONFIG_ARCH_MARCO)	+= timer-marco.o
+obj-$(CONFIG_ARCH_MMP)		+= timer-mmp.o
 obj-$(CONFIG_ARCH_MXS)		+= mxs_timer.o
 obj-$(CONFIG_ARCH_PRIMA2)	+= timer-prima2.o
 obj-$(CONFIG_SUN4I_TIMER)	+= sun4i_timer.o
diff --git a/arch/arm/mach-mmp/time.c b/drivers/clocksource/timer-mmp.c
similarity index 99%
rename from arch/arm/mach-mmp/time.c
rename to drivers/clocksource/timer-mmp.c
index 86a18b3..553e3de 100644
--- a/arch/arm/mach-mmp/time.c
+++ b/drivers/clocksource/timer-mmp.c
@@ -37,8 +37,6 @@
 #include <mach/cputype.h>
 #include <asm/mach/time.h>
 
-#include "clock.h"
-
 #define TIMERS_VIRT_BASE	TIMERS1_VIRT_BASE
 
 #define MAX_DELTA		(0xfffffffe)
-- 
1.8.1.2

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v4 07/10] ARM: mmp: move timer registers into driver
  2013-06-04  4:12 [PATCH v4 00/10] update irqchip, clocksource, clk for mmp Haojian Zhuang
                   ` (5 preceding siblings ...)
  2013-06-04  4:12 ` [PATCH v4 06/10] clocksource: mmp: move mmp timer driver Haojian Zhuang
@ 2013-06-04  4:12 ` Haojian Zhuang
  2013-06-04  4:12 ` [PATCH v4 08/10] ARM: pxa: init dma debugfs in late level Haojian Zhuang
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Haojian Zhuang @ 2013-06-04  4:12 UTC (permalink / raw)
  To: linux-arm-kernel

Move the definition of timer registers into timer-mmp driver.
And map timer registers in driver.

Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
 arch/arm/mach-mmp/common.h                   |  2 +-
 arch/arm/mach-mmp/include/mach/addr-map.h    |  3 ++
 arch/arm/mach-mmp/include/mach/regs-timers.h | 44 ----------------------------
 arch/arm/mach-mmp/mmp2.c                     |  2 +-
 arch/arm/mach-mmp/pxa168.c                   |  2 +-
 arch/arm/mach-mmp/pxa910.c                   |  2 +-
 drivers/clocksource/timer-mmp.c              | 37 ++++++++++++++++++-----
 7 files changed, 37 insertions(+), 55 deletions(-)
 delete mode 100644 arch/arm/mach-mmp/include/mach/regs-timers.h

diff --git a/arch/arm/mach-mmp/common.h b/arch/arm/mach-mmp/common.h
index 9c1c9be..2fc9390 100644
--- a/arch/arm/mach-mmp/common.h
+++ b/arch/arm/mach-mmp/common.h
@@ -1,6 +1,6 @@
 #define ARRAY_AND_SIZE(x)	(x), ARRAY_SIZE(x)
 
-extern void timer_init(int irq);
+extern void timer_init(void __iomem *base, int irq);
 
 extern void __init mmp_map_io(void);
 extern void mmp_restart(char, const char *);
diff --git a/arch/arm/mach-mmp/include/mach/addr-map.h b/arch/arm/mach-mmp/include/mach/addr-map.h
index f88a44c..169c280 100644
--- a/arch/arm/mach-mmp/include/mach/addr-map.h
+++ b/arch/arm/mach-mmp/include/mach/addr-map.h
@@ -43,4 +43,7 @@
 #define CIU_VIRT_BASE		(AXI_VIRT_BASE + 0x82c00)
 #define CIU_REG(x)		(CIU_VIRT_BASE + (x))
 
+#define TIMER1_VIRT_BASE	(APB_VIRT_BASE + 0x14000)
+#define TIMER2_VIRT_BASE	(APB_VIRT_BASE + 0x16000)
+
 #endif /* __ASM_MACH_ADDR_MAP_H */
diff --git a/arch/arm/mach-mmp/include/mach/regs-timers.h b/arch/arm/mach-mmp/include/mach/regs-timers.h
deleted file mode 100644
index 45589fe..0000000
--- a/arch/arm/mach-mmp/include/mach/regs-timers.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * linux/arch/arm/mach-mmp/include/mach/regs-timers.h
- *
- *   Timers Module
- *
- * 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
- * published by the Free Software Foundation.
- */
-
-#ifndef __ASM_MACH_REGS_TIMERS_H
-#define __ASM_MACH_REGS_TIMERS_H
-
-#include <mach/addr-map.h>
-
-#define TIMERS1_VIRT_BASE	(APB_VIRT_BASE + 0x14000)
-#define TIMERS2_VIRT_BASE	(APB_VIRT_BASE + 0x16000)
-
-#define TMR_CCR		(0x0000)
-#define TMR_TN_MM(n, m)	(0x0004 + ((n) << 3) + (((n) + (m)) << 2))
-#define TMR_CR(n)	(0x0028 + ((n) << 2))
-#define TMR_SR(n)	(0x0034 + ((n) << 2))
-#define TMR_IER(n)	(0x0040 + ((n) << 2))
-#define TMR_PLVR(n)	(0x004c + ((n) << 2))
-#define TMR_PLCR(n)	(0x0058 + ((n) << 2))
-#define TMR_WMER	(0x0064)
-#define TMR_WMR		(0x0068)
-#define TMR_WVR		(0x006c)
-#define TMR_WSR		(0x0070)
-#define TMR_ICR(n)	(0x0074 + ((n) << 2))
-#define TMR_WICR	(0x0080)
-#define TMR_CER		(0x0084)
-#define TMR_CMR		(0x0088)
-#define TMR_ILR(n)	(0x008c + ((n) << 2))
-#define TMR_WCR		(0x0098)
-#define TMR_WFAR	(0x009c)
-#define TMR_WSAR	(0x00A0)
-#define TMR_CVWR(n)	(0x00A4 + ((n) << 2))
-
-#define TMR_CCR_CS_0(x)	(((x) & 0x3) << 0)
-#define TMR_CCR_CS_1(x)	(((x) & 0x7) << 2)
-#define TMR_CCR_CS_2(x)	(((x) & 0x3) << 5)
-
-#endif /* __ASM_MACH_REGS_TIMERS_H */
diff --git a/arch/arm/mach-mmp/mmp2.c b/arch/arm/mach-mmp/mmp2.c
index 09fbe7d..f26ea9d 100644
--- a/arch/arm/mach-mmp/mmp2.c
+++ b/arch/arm/mach-mmp/mmp2.c
@@ -131,7 +131,7 @@ void __init mmp2_timer_init(void)
 	clk_rst = APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(1);
 	__raw_writel(clk_rst, APBC_TIMERS);
 
-	timer_init(IRQ_MMP2_TIMER1);
+	timer_init(TIMER1_VIRT_BASE, IRQ_MMP2_TIMER1);
 }
 
 /* on-chip devices */
diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c
index a30dcf3..2bdec91 100644
--- a/arch/arm/mach-mmp/pxa168.c
+++ b/arch/arm/mach-mmp/pxa168.c
@@ -78,7 +78,7 @@ void __init pxa168_timer_init(void)
 	/* 3.25MHz, bus/functional clock enabled, release reset */
 	__raw_writel(TIMER_CLK_RST, APBC_TIMERS);
 
-	timer_init(IRQ_PXA168_TIMER1);
+	timer_init(TIMER1_VIRT_BASE, IRQ_PXA168_TIMER1);
 }
 
 void pxa168_clear_keypad_wakeup(void)
diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c
index 96e125b..df379c2 100644
--- a/arch/arm/mach-mmp/pxa910.c
+++ b/arch/arm/mach-mmp/pxa910.c
@@ -112,7 +112,7 @@ void __init pxa910_timer_init(void)
 	__raw_writel(APBC_APBCLK | APBC_RST, APBC_TIMERS);
 	__raw_writel(TIMER_CLK_RST, APBC_TIMERS);
 
-	timer_init(IRQ_PXA910_AP1_TIMER1);
+	timer_init(TIMER1_VIRT_BASE, IRQ_PXA910_AP1_TIMER1);
 }
 
 /* on-chip devices */
diff --git a/drivers/clocksource/timer-mmp.c b/drivers/clocksource/timer-mmp.c
index 553e3de..bfd0997 100644
--- a/drivers/clocksource/timer-mmp.c
+++ b/drivers/clocksource/timer-mmp.c
@@ -30,19 +30,39 @@
 #include <linux/of_irq.h>
 
 #include <asm/sched_clock.h>
-#include <mach/addr-map.h>
-#include <mach/regs-timers.h>
-#include <mach/regs-apbc.h>
 #include <mach/irqs.h>
 #include <mach/cputype.h>
 #include <asm/mach/time.h>
 
-#define TIMERS_VIRT_BASE	TIMERS1_VIRT_BASE
+#define TMR_CCR		(0x0000)
+#define TMR_TN_MM(n, m)	(0x0004 + ((n) << 3) + (((n) + (m)) << 2))
+#define TMR_CR(n)	(0x0028 + ((n) << 2))
+#define TMR_SR(n)	(0x0034 + ((n) << 2))
+#define TMR_IER(n)	(0x0040 + ((n) << 2))
+#define TMR_PLVR(n)	(0x004c + ((n) << 2))
+#define TMR_PLCR(n)	(0x0058 + ((n) << 2))
+#define TMR_WMER	(0x0064)
+#define TMR_WMR		(0x0068)
+#define TMR_WVR		(0x006c)
+#define TMR_WSR		(0x0070)
+#define TMR_ICR(n)	(0x0074 + ((n) << 2))
+#define TMR_WICR	(0x0080)
+#define TMR_CER		(0x0084)
+#define TMR_CMR		(0x0088)
+#define TMR_ILR(n)	(0x008c + ((n) << 2))
+#define TMR_WCR		(0x0098)
+#define TMR_WFAR	(0x009c)
+#define TMR_WSAR	(0x00A0)
+#define TMR_CVWR(n)	(0x00A4 + ((n) << 2))
+
+#define TMR_CCR_CS_0(x)	(((x) & 0x3) << 0)
+#define TMR_CCR_CS_1(x)	(((x) & 0x7) << 2)
+#define TMR_CCR_CS_2(x)	(((x) & 0x3) << 5)
 
 #define MAX_DELTA		(0xfffffffe)
 #define MIN_DELTA		(16)
 
-static void __iomem *mmp_timer_base = TIMERS_VIRT_BASE;
+static void __iomem *mmp_timer_base;
 
 /*
  * FIXME: the timer needs some delay to stablize the counter capture
@@ -189,8 +209,11 @@ static struct irqaction timer_irq = {
 	.dev_id		= &ckevt,
 };
 
-void __init timer_init(int irq)
+void __init timer_init(void __iomem *base, int irq)
 {
+	BUG_ON(!base);
+	mmp_timer_base = base;
+
 	timer_config();
 
 	setup_sched_clock(mmp_read_sched_clock, 32, CLOCK_TICK_RATE);
@@ -231,7 +254,7 @@ void __init mmp_dt_init_timer(void)
 		ret = -ENOMEM;
 		goto out;
 	}
-	timer_init(irq);
+	timer_init(mmp_timer_base, irq);
 	return;
 out:
 	pr_err("Failed to get timer from device tree with error:%d\n", ret);
-- 
1.8.1.2

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v4 08/10] ARM: pxa: init dma debugfs in late level
  2013-06-04  4:12 [PATCH v4 00/10] update irqchip, clocksource, clk for mmp Haojian Zhuang
                   ` (6 preceding siblings ...)
  2013-06-04  4:12 ` [PATCH v4 07/10] ARM: mmp: move timer registers into driver Haojian Zhuang
@ 2013-06-04  4:12 ` Haojian Zhuang
  2013-06-04  4:12 ` [PATCH v4 09/10] clk: mmp: parse clock from dts Haojian Zhuang
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Haojian Zhuang @ 2013-06-04  4:12 UTC (permalink / raw)
  To: linux-arm-kernel

Remove pxa_init_dma() from core_initcall level since it's unncecssary
for DT mode. But dma debugfs is also included in pxa_init_dma().
So only initiliaze dma debugfs in late_initcall level.

Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
 arch/arm/mach-mmp/mmp2.c   |  2 +-
 arch/arm/mach-mmp/pxa168.c |  2 +-
 arch/arm/mach-mmp/pxa910.c |  2 +-
 arch/arm/plat-pxa/dma.c    | 30 ++++++++++++++++++++----------
 4 files changed, 23 insertions(+), 13 deletions(-)

diff --git a/arch/arm/mach-mmp/mmp2.c b/arch/arm/mach-mmp/mmp2.c
index f26ea9d..a0abfd7 100644
--- a/arch/arm/mach-mmp/mmp2.c
+++ b/arch/arm/mach-mmp/mmp2.c
@@ -114,7 +114,6 @@ static int __init mmp2_init(void)
 
 	return 0;
 }
-postcore_initcall(mmp2_init);
 
 #define APBC_TIMERS	APBC_REG(0x024)
 
@@ -122,6 +121,7 @@ void __init mmp2_timer_init(void)
 {
 	unsigned long clk_rst;
 
+	mmp2_init();
 	__raw_writel(APBC_APBCLK | APBC_RST, APBC_TIMERS);
 
 	/*
diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c
index 2bdec91..345a493 100644
--- a/arch/arm/mach-mmp/pxa168.c
+++ b/arch/arm/mach-mmp/pxa168.c
@@ -61,7 +61,6 @@ static int __init pxa168_init(void)
 
 	return 0;
 }
-postcore_initcall(pxa168_init);
 
 /* system timer - clock enabled, 3.25MHz */
 #define TIMER_CLK_RST	(APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(3))
@@ -69,6 +68,7 @@ postcore_initcall(pxa168_init);
 
 void __init pxa168_timer_init(void)
 {
+	pxa168_init();
 	/* this is early, we have to initialize the CCU registers by
 	 * ourselves instead of using clk_* API. Clock rate is defined
 	 * by APBC_TIMERS_CLK_RST (3.25MHz) and enabled free-running
diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c
index df379c2..1a84800 100644
--- a/arch/arm/mach-mmp/pxa910.c
+++ b/arch/arm/mach-mmp/pxa910.c
@@ -100,7 +100,6 @@ static int __init pxa910_init(void)
 
 	return 0;
 }
-postcore_initcall(pxa910_init);
 
 /* system timer - clock enabled, 3.25MHz */
 #define TIMER_CLK_RST	(APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(3))
@@ -108,6 +107,7 @@ postcore_initcall(pxa910_init);
 
 void __init pxa910_timer_init(void)
 {
+	pxa910_init();
 	/* reset and configure */
 	__raw_writel(APBC_APBCLK | APBC_RST, APBC_TIMERS);
 	__raw_writel(TIMER_CLK_RST, APBC_TIMERS);
diff --git a/arch/arm/plat-pxa/dma.c b/arch/arm/plat-pxa/dma.c
index 79ef102..6c5472b 100644
--- a/arch/arm/plat-pxa/dma.c
+++ b/arch/arm/plat-pxa/dma.c
@@ -228,36 +228,46 @@ err_state:
 	return NULL;
 }
 
-static void pxa_dma_init_debugfs(void)
+static int __init pxa_dma_init_debugfs(void)
 {
-	int i;
+	int i, ret;
 	struct dentry *chandir;
 
 	dbgfs_root = debugfs_create_dir(DMA_DEBUG_NAME, NULL);
-	if (IS_ERR(dbgfs_root) || !dbgfs_root)
+	if (IS_ERR(dbgfs_root) || !dbgfs_root) {
+		ret = -EINVAL;
 		goto err_root;
+	}
 
 	dbgfs_state = debugfs_create_file("state", 0400, dbgfs_root, NULL,
 					  &dbg_fops_state);
-	if (!dbgfs_state)
+	if (!dbgfs_state) {
+		ret = -EINVAL;
 		goto err_state;
+	}
 
 	dbgfs_chan = kmalloc(sizeof(*dbgfs_state) * num_dma_channels,
 			     GFP_KERNEL);
-	if (!dbgfs_chan)
+	if (!dbgfs_chan) {
+		ret = -ENOMEM;
 		goto err_alloc;
+	}
 
 	chandir = debugfs_create_dir("channels", dbgfs_root);
-	if (!chandir)
+	if (!chandir) {
+		ret = -EINVAL;
 		goto err_chandir;
+	}
 
 	for (i = 0; i < num_dma_channels; i++) {
 		dbgfs_chan[i] = pxa_dma_dbg_alloc_chan(i, chandir);
-		if (!dbgfs_chan[i])
+		if (!dbgfs_chan[i]) {
+			ret = -EINVAL;
 			goto err_chans;
+		}
 	}
 
-	return;
+	return 0;
 err_chans:
 err_chandir:
 	kfree(dbgfs_chan);
@@ -266,7 +276,9 @@ err_state:
 	debugfs_remove_recursive(dbgfs_root);
 err_root:
 	pr_err("pxa_dma: debugfs is not available\n");
+	return ret;
 }
+late_initcall(pxa_dma_init_debugfs);
 
 static void __exit pxa_dma_cleanup_debugfs(void)
 {
@@ -385,7 +397,5 @@ int __init pxa_init_dma(int irq, int num_ch)
 	}
 	num_dma_channels = num_ch;
 
-	pxa_dma_init_debugfs();
-
 	return 0;
 }
-- 
1.8.1.2

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v4 09/10] clk: mmp: parse clock from dts
  2013-06-04  4:12 [PATCH v4 00/10] update irqchip, clocksource, clk for mmp Haojian Zhuang
                   ` (7 preceding siblings ...)
  2013-06-04  4:12 ` [PATCH v4 08/10] ARM: pxa: init dma debugfs in late level Haojian Zhuang
@ 2013-06-04  4:12 ` Haojian Zhuang
  2013-06-11 20:20   ` Mike Turquette
  2013-06-04  4:12 ` [PATCH v4 10/10] ARM: mmp: avoid to use cpu_is_xxx in timer Haojian Zhuang
  2013-06-04 15:27 ` [PATCH v5 09/10] clk: mmp: parse clock from dts Haojian Zhuang
  10 siblings, 1 reply; 13+ messages in thread
From: Haojian Zhuang @ 2013-06-04  4:12 UTC (permalink / raw)
  To: linux-arm-kernel

Parse clock information from DTS file for mach-mmp.

Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
 arch/arm/boot/dts/pxa168-aspenite.dts |   3 +
 arch/arm/boot/dts/pxa168-clk.dtsi     | 304 ++++++++++++++++++
 arch/arm/boot/dts/pxa168.dtsi         |  10 +
 arch/arm/boot/dts/pxa910-clk.dtsi     | 569 ++++++++++++++++++++++++++++++++++
 arch/arm/boot/dts/pxa910-dkb.dts      |  11 +
 arch/arm/boot/dts/pxa910.dtsi         |  12 +-
 arch/arm/mach-mmp/mmp-dt.c            |   2 +
 drivers/clk/mmp/Makefile              |   2 +-
 drivers/clk/mmp/clk-mmp.c             | 363 ++++++++++++++++++++++
 9 files changed, 1274 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm/boot/dts/pxa168-clk.dtsi
 create mode 100644 arch/arm/boot/dts/pxa910-clk.dtsi
 create mode 100644 drivers/clk/mmp/clk-mmp.c

diff --git a/arch/arm/boot/dts/pxa168-aspenite.dts b/arch/arm/boot/dts/pxa168-aspenite.dts
index e762fac..2597e98 100644
--- a/arch/arm/boot/dts/pxa168-aspenite.dts
+++ b/arch/arm/boot/dts/pxa168-aspenite.dts
@@ -24,6 +24,9 @@
 
 	soc {
 		apb at d4000000 {
+			timer0: timer at d4014000 {
+				status = "okay";
+			};
 			uart1: uart at d4017000 {
 				status = "okay";
 			};
diff --git a/arch/arm/boot/dts/pxa168-clk.dtsi b/arch/arm/boot/dts/pxa168-clk.dtsi
new file mode 100644
index 0000000..f9c298df
--- /dev/null
+++ b/arch/arm/boot/dts/pxa168-clk.dtsi
@@ -0,0 +1,304 @@
+/*
+ *  Copyright (C) 2013
+ *  Author: Haojian Zhuang <haojian.zhuang@gmail.com>
+ *
+ *  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/ "skeleton.dtsi"
+
+/ {
+	soc {
+		apb at d4000000 {	/* APB */
+			compatible = "mrvl,apb-bus", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0xd4000000 0x00200000>;
+			ranges;
+
+			mpmu: clocks at 50000 {
+				compatible = "marvell,mmp-mpmu";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				reg = <0xd4050000 0x1100>;
+
+				osc_32k: osc32khz {
+					compatible = "fixed-clock";
+					#clock-cells = <0>;
+					clock-frequency = <32768>;
+					clock-output-names = "osc32khz";
+				};
+				osc_26m: osc26mhz {
+					compatible = "fixed-clock";
+					#clock-cells = <0>;
+					clock-frequency = <26000000>;
+					clock-output-names = "osc26mhz";
+				};
+				pll1_312m: refclk312mhz {
+					compatible = "marvell,mmp-fixed-clkrate";
+					#clock-cells = <0>;
+					clocks = <&osc_26m>;
+					clock-frequency = <312000000>;
+					clock-output-names = "refclk312mhz";
+				};
+				refclk156m: refclk156mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&pll1_312m>;
+					clock-output-names = "refclk156mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 2>;
+				};
+				refclk118m: refclk117mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&refclk156m>;
+					/* 117.9648MHz */
+					clock-output-names = "refclk118mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <6144 8125>;
+				};
+				refclk104m: refclk104mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&pll1_312m>;
+					clock-output-names = "refclk104mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 3>;
+				};
+				refclk59m: refclk59mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&refclk118m>;
+					clock-names = "baud_58.98mhz";
+					/* 58.9824MHz */
+					clock-output-names = "refclk59mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 2>;
+				};
+				refclk15m: refclk15mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&refclk156m>;
+					clock-names = "baud_14.86mhz";
+					/* 14.857MHz */
+					clock-output-names = "refclk15mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <2 21>;
+				};
+			};
+
+			apbc: clocks at 15000 {
+				compatible = "marvell,mmp-apbc";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				#clock-cells = <0>;
+				reg = <0xd4015000 0x100>;
+
+				apbc_twsi1_clk: apbc_twsi1_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&refclk32m>;
+					clock-names = "apbc_twsi1_clk";
+					/* register value of each item */
+					marvell,mmp-clk-sel = <0>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x2c 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_twsi2_clk: apbc_twsi2_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&refclk32m>;
+					clock-names = "apbc_twsi2_clk";
+					/* register value of each item */
+					marvell,mmp-clk-sel = <0>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x6c 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_rtc_clk: apbc_rtc_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&osc_32k>;
+					clock-names = "apbc_rtc_clk";
+					marvell,mmp-clk-sel = <0>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x28 0x70>;
+					marvell,mmp-apbc-power-ctl;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_gpio_clk: apbc_gpio_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&refclk26m>;
+					clock-names = "apbc_gpio_clk";
+					marvell,mmp-clk-sel = <0>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x8 0x0>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_uart1_mux: apbc_uart1_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk59m &refclk15m>;
+					clock-output-names = "apbc_uart1_mux";
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x0 0x70>;
+					/* register value of each item */
+					marvell,mmp-clk-sel = <0 0x10>;
+				};
+				apbc_uart1_clk: apbc_uart1_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_uart1_mux>;
+					clock-names = "apbc_uart1_clk";
+					marvell,mmp-clk-reg = <0x0 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_uart2_mux: apbc_uart2_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk59m &refclk15m>;
+					clock-output-names = "apbc_uart2_mux";
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x4 0x70>;
+					/* register value of each item */
+					marvell,mmp-clk-sel = <0 0x10>;
+				};
+				apbc_uart2_clk: apbc_uart2_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_uart2_mux>;
+					clock-names = "apbc_uart2_clk";
+					marvell,mmp-clk-reg = <0x4 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_uart3_mux: apbc_uart3_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk59m &refclk15m>;
+					clock-output-names = "apbc_uart3_mux";
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x70 0x70>;
+					/* register value of each item */
+					marvell,mmp-clk-sel = <0 0x10>;
+				};
+				apbc_uart3_clk: apbc_uart3_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_uart3_mux>;
+					clock-names = "apbc_uart3_clk";
+					marvell,mmp-clk-reg = <0x70 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_pwm1_mux: apbc_pwm1_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk13m &osc_32k>;
+					clock-output-names = "apbc_pwm1_mux";
+					marvell,mmp-clk-sel = <0 0x10>;
+					marvell,mmp-clk-reg = <0xc 0x70>;
+				};
+				apbc_pwm1_clk: apbc_pwm1_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_pwm1_mux>;
+					clock-names = "apbc_pwm1_clk";
+					marvell,mmp-clk-reg = <0xc 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_pwm2_mux: apbc_pwm2_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk13m &osc_32k>;
+					clock-output-names = "apbc_pwm2_mux";
+					marvell,mmp-clk-sel = <0 0x10>;
+					marvell,mmp-clk-reg = <0x10 0x70>;
+				};
+				apbc_pwm2_clk: apbc_pwm2_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_pwm2_mux>;
+					clock-names = "apbc_pwm2_clk";
+					marvell,mmp-clk-reg = <0x10 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_pwm3_mux: apbc_pwm3_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk13m &osc_32k>;
+					clock-output-names = "apbc_pwm3_mux";
+					marvell,mmp-clk-sel = <0 0x10>;
+					marvell,mmp-clk-reg = <0x14 0x70>;
+				};
+				apbc_pwm3_clk: apbc_pwm3_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_pwm3_mux>;
+					clock-names = "apbc_pwm3_clk";
+					marvell,mmp-clk-reg = <0x14 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_pwm4_mux: apbc_pwm4_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk13m &osc_32k>;
+					clock-output-names = "apbc_pwm4_mux";
+					marvell,mmp-clk-sel = <0 0x10>;
+					marvell,mmp-clk-reg = <0x18 0x70>;
+				};
+				apbc_pwm4_clk: apbc_pwm4_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_pwm4_mux>;
+					clock-names = "apbc_pwm4_clk";
+					marvell,mmp-clk-reg = <0x18 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_kpc_mux: apbc_kpc_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&osc_32k &refclk16k &refclk26m>;
+					clock-output-names = "apbc_kpc_mux";
+					marvell,mmp-clk-sel = <0 0x10 0x20>;
+					marvell,mmp-clk-reg = <0x30 0x70>;
+				};
+				apbc_kpc_clk: apbc_kpc_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_kpc_mux>;
+					clock-names = "apbc_kpc_clk";
+					marvell,mmp-clk-reg = <0x30 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_timer0_mux: apbc_timer0_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk13m &osc_32k &refclk7m &refclk3m>;
+					clock-output-names = "apbc_timer0_mux";
+					marvell,mmp-clk-sel = <0 0x10 0x20 0x30>;
+					marvell,mmp-clk-reg = <0x34 0x70>;
+				};
+				apbc_timer0_clk: apbc_timer0_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&timer0_mux>;
+					clock-names = "apbc_timer0_clk";
+					marvell,mmp-clk-reg = <0x34 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+			};
+			timer0_mux: timer0_mux {
+				compatible = "marvell,mmp-clkmux";
+				#clock-cells = <0>;
+				clocks = <&apbc_timer0_mux &osc_32k>;
+				clock-output-names = "timer0_mux";
+				marvell,mmp-clk-sel = <0 0x2>;
+				marvell,mmp-clk-reg = <0x14000 0x1c>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/pxa168.dtsi b/arch/arm/boot/dts/pxa168.dtsi
index 975dad2..250bf2c 100644
--- a/arch/arm/boot/dts/pxa168.dtsi
+++ b/arch/arm/boot/dts/pxa168.dtsi
@@ -8,6 +8,7 @@
  */
 
 /include/ "skeleton.dtsi"
+/include/ "pxa910-clk.dtsi"
 
 / {
 	aliases {
@@ -53,12 +54,15 @@
 				compatible = "mrvl,mmp-timer";
 				reg = <0xd4014000 0x100>;
 				interrupts = <13>;
+				clocks = <&apbc_timer0_clk>;
+				status = "disabled";
 			};
 
 			uart1: uart at d4017000 {
 				compatible = "mrvl,mmp-uart";
 				reg = <0xd4017000 0x1000>;
 				interrupts = <27>;
+				clocks = <&apbc_uart1_clk>;
 				status = "disabled";
 			};
 
@@ -66,6 +70,7 @@
 				compatible = "mrvl,mmp-uart";
 				reg = <0xd4018000 0x1000>;
 				interrupts = <28>;
+				clocks = <&apbc_uart2_clk>;
 				status = "disabled";
 			};
 
@@ -73,6 +78,7 @@
 				compatible = "mrvl,mmp-uart";
 				reg = <0xd4026000 0x1000>;
 				interrupts = <29>;
+				clocks = <&apbc_uart3_clk>;
 				status = "disabled";
 			};
 
@@ -87,6 +93,7 @@
 				interrupt-names = "gpio_mux";
 				interrupt-controller;
 				#interrupt-cells = <1>;
+				clocks = <&apbc_gpio_clk>;
 				ranges;
 
 				gcb0: gpio at d4019000 {
@@ -111,6 +118,7 @@
 				reg = <0xd4011000 0x1000>;
 				interrupts = <7>;
 				mrvl,i2c-fast-mode;
+				clocks = <&apbc_twsi1_clk>;
 				status = "disabled";
 			};
 
@@ -118,6 +126,7 @@
 				compatible = "mrvl,mmp-twsi";
 				reg = <0xd4025000 0x1000>;
 				interrupts = <58>;
+				clocks = <&apbc_twsi2_clk>;
 				status = "disabled";
 			};
 
@@ -126,6 +135,7 @@
 				reg = <0xd4010000 0x1000>;
 				interrupts = <5 6>;
 				interrupt-names = "rtc 1Hz", "rtc alarm";
+				clocks = <&apbc_rtc_clk>;
 				status = "disabled";
 			};
 		};
diff --git a/arch/arm/boot/dts/pxa910-clk.dtsi b/arch/arm/boot/dts/pxa910-clk.dtsi
new file mode 100644
index 0000000..035697f
--- /dev/null
+++ b/arch/arm/boot/dts/pxa910-clk.dtsi
@@ -0,0 +1,569 @@
+/*
+ *  Copyright (C) 2013
+ *  Author: Haojian Zhuang <haojian.zhuang@gmail.com>
+ *
+ *  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/ "skeleton.dtsi"
+
+/ {
+	soc {
+		axi at d4200000 {	/* AXI */
+			compatible = "mrvl,axi-bus", "simple-bus";
+			reg = <0xd4200000 0x00200000>;
+			ranges;
+
+			apmu: clocks at 82800 {
+				compatible = "marvell,mmp-apmu";
+				reg = <0xd4282800 0x100>;
+
+				/*
+				 * Processor clocks: pclk, pdclk, baclk, xpclk
+				 * DDR Controller clocks: dclk
+				 * AXI Fabric clocks: aclk
+				 */
+				pclk_refclk: refclk_pclk {
+					compatible = "marvell,mmp-apmu-clkdiv";
+					#clock-cells = <0>;
+					clocks = <&pj1_refclk>;
+					clock-output-names = "pclk";
+					marvell,mmp-clock-frequency = <104000000 156000000 208000000 312000000 500500000 624000000 806000000 1001000000>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x4 0x7>;
+				};
+				/* pdclk -- DDR Interface clock */
+				pdclk_refclk: refclk_pdclk {
+					compatible = "marvell,mmp-apmu-clkdiv";
+					#clock-cells = <0>;
+					clocks = <&pj1_refclk>;
+					clock-output-names = "pdclk";
+					marvell,mmp-clock-frequency = <78000000 104000000 156000000 201000000 250250000>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x4 0x38>;
+				};
+				/* baclk -- AXI Fabric Bus Interface clock */
+				baclk_refclk: refclk_baclk {
+					compatible = "marvell,mmp-apmu-clkdiv";
+					#clock-cells = <0>;
+					clocks = <&pj1_refclk>;
+					clock-output-names = "baclk";
+					marvell,mmp-clock-frequency = <78000000 104000000 156000000 201000000 250250000>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x4 0x1c0>;
+				};
+				/* xpclk -- L2 interface clock */
+				xpclk_refclk: refclk_xpclk {
+					compatible = "marvell,mmp-apmu-clkdiv";
+					#clock-cells = <0>;
+					clocks = <&pj1_refclk>;
+					clock-output-names = "xpclk";
+					marvell,mmp-clock-frequency = <104000000 156000000 250250000 312000000 403000000 500500000>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x4 0xe00>;
+				};
+				/* dclk -- DDR Controller clock */
+				dclk2x_refclk: refclk_dclk2x {
+					compatible = "marvell,mmp-apmu-clkdiv";
+					#clock-cells = <0>;
+					clocks = <&ddr_refclk>;
+					clock-output-names = "dclk2x";
+					marvell,mmp-clock-frequency = <208000000 312000000 402000000 500500000>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x4 0x7000>;
+				};
+				dclk_refclk: refclk_dclk {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&dclk2x_refclk>;
+					clock-output-names = "dclk";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 2>;
+				};
+				/* aclk -- AXI Fabric clock */
+				aclk_refclk: refclk_aclk {
+					compatible = "marvell,mmp-apmu-clkdiv";
+					#clock-cells = <0>;
+					clocks = <&axi_refclk>;
+					clock-output-names = "aclk";
+					marvell,mmp-clock-frequency = <104000000 156000000>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x4 0x38000>;
+				};
+			};
+		};
+
+		apb at d4000000 {	/* APB */
+			compatible = "mrvl,apb-bus", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0xd4000000 0x00200000>;
+			ranges;
+
+			mpmu: clocks at 50000 {
+				compatible = "marvell,mmp-mpmu";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				reg = <0xd4050000 0x1100>;
+
+				osc_32k: osc32khz {
+					compatible = "fixed-clock";
+					#clock-cells = <0>;
+					clock-frequency = <32768>;
+					clock-output-names = "osc32khz";
+				};
+				osc_26m: osc26mhz {
+					compatible = "fixed-clock";
+					#clock-cells = <0>;
+					clock-frequency = <26000000>;
+					clock-output-names = "osc26mhz";
+				};
+				pll1_312m: refclk312mhz {
+					compatible = "marvell,mmp-fixed-clkrate";
+					#clock-cells = <0>;
+					clocks = <&osc_26m>;
+					clock-frequency = <312000000>;
+					clock-output-names = "refclk312mhz";
+				};
+				pll1_624m: refclk624mhz {
+					compatible = "marvell,mmp-fixed-clkrate";
+					#clock-cells = <0>;
+					clocks = <&osc_26m>;
+					clock-frequency = <624000000>;
+					clock-output-names = "refclk624mhz";
+				};
+				pj1_refclk: refclk_pj1 {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&pll1_312m &pll1_624m &pll2>;
+					clock-output-names = "refclk_pj1";
+					/* register value of each item */
+					marvell,mmp-clk-sel = <0 0x20000000 0x40000000>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x8 0xe0000000>;
+				};
+				ddr_refclk: refclk_ddr {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&pll1_312m &pll1_624m &pll2>;
+					clock-output-names = "refclk_ddr";
+					/* register value of each item */
+					marvell,mmp-clk-sel = <0 0x00800000 0x01000000>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x8 0x01800000>;
+				};
+				axi_refclk: refclk_axi {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&pll1_312m &pll1_624m>;
+					clock-output-names = "refclk_axi";
+					/* register value of each item */
+					marvell,mmp-clk-sel = <0 0x00080000>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x8 0x00080000>;
+				};
+				refclk156m: refclk156mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&pll1_312m>;
+					clock-output-names = "refclk156mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 2>;
+				};
+				refclk118m: refclk117mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&refclk156m>;
+					/* 117.9648MHz */
+					clock-output-names = "refclk118mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <6144 8125>;
+				};
+				refclk104m: refclk104mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&pll1_312m>;
+					clock-output-names = "refclk104mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 3>;
+				};
+				refclk59m: refclk59mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&refclk118m>;
+					clock-names = "baud_58.98mhz";
+					/* 58.9824MHz */
+					clock-output-names = "refclk59mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 2>;
+				};
+				refclk52m: refclk52mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&refclk104m>;
+					clock-output-names = "refclk52mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 2>;
+				};
+				refclk48m: refclk48mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&pll1_624m>;
+					clock-output-names = "refclk48mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 13>;
+				};
+				refclk32m: refclk32mhz@ {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&refclk48m>;
+					clock-output-names = "refclk32mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <2 3>;
+				};
+				refclk26m: refclk26mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&refclk52m>;
+					clock-output-names = "refclk26mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 2>;
+				};
+				refclk15m: refclk15mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&refclk156m>;
+					clock-names = "baud_14.86mhz";
+					/* 14.857MHz */
+					clock-output-names = "refclk15mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <2 21>;
+				};
+				refclk13m: refclk13mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&refclk26m>;
+					clock-output-names = "refclk13mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 2>;
+				};
+				refclk7m: refclk7mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&refclk13m>;
+					clock-output-names = "refclk7mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 2>;
+				};
+				refclk3m: refclk3mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&refclk7m>;
+					clock-output-names = "refclk3mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 2>;
+				};
+				refclk16k: refclk16khz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&osc_32k>;
+					clock-output-names = "refclk16khz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 2>;
+				};
+			};
+
+			apbc: clocks at 15000 {
+				compatible = "marvell,mmp-apbc";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				#clock-cells = <0>;
+				reg = <0xd4015000 0x100>;
+
+				apbc_twsi1_clk: apbc_twsi1_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&refclk32m>;
+					clock-names = "apbc_twsi1_clk";
+					/* register value of each item */
+					marvell,mmp-clk-sel = <0>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x2c 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_rtc_clk: apbc_rtc_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&osc_32k>;
+					clock-names = "apbc_rtc_clk";
+					marvell,mmp-clk-sel = <0>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x28 0x70>;
+					marvell,mmp-apbc-power-ctl;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_gpio_clk: apbc_gpio_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&refclk26m>;
+					clock-names = "apbc_gpio_clk";
+					marvell,mmp-clk-sel = <0>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x8 0x0>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_uart1_mux: apbc_uart1_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk59m &refclk15m>;
+					clock-output-names = "apbc_uart1_mux";
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x0 0x70>;
+					/* register value of each item */
+					marvell,mmp-clk-sel = <0 0x10>;
+				};
+				apbc_uart1_clk: apbc_uart1_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_uart1_mux>;
+					clock-names = "apbc_uart1_clk";
+					marvell,mmp-clk-reg = <0x0 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_uart2_mux: apbc_uart2_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk59m &refclk15m>;
+					clock-output-names = "apbc_uart2_mux";
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x4 0x70>;
+					/* register value of each item */
+					marvell,mmp-clk-sel = <0 0x10>;
+				};
+				apbc_uart2_clk: apbc_uart2_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_uart2_mux>;
+					clock-names = "apbc_uart2_clk";
+					marvell,mmp-clk-reg = <0x4 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_pwm1_mux: apbc_pwm1_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk13m &osc_32k>;
+					clock-output-names = "apbc_pwm1_mux";
+					marvell,mmp-clk-sel = <0 0x10>;
+					marvell,mmp-clk-reg = <0xc 0x70>;
+				};
+				apbc_pwm1_clk: apbc_pwm1_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_pwm1_mux>;
+					clock-names = "apbc_pwm1_clk";
+					marvell,mmp-clk-reg = <0xc 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_pwm2_mux: apbc_pwm2_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk13m &osc_32k>;
+					clock-output-names = "apbc_pwm2_mux";
+					marvell,mmp-clk-sel = <0 0x10>;
+					marvell,mmp-clk-reg = <0x10 0x70>;
+				};
+				apbc_pwm2_clk: apbc_pwm2_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_pwm2_mux>;
+					clock-names = "apbc_pwm2_clk";
+					marvell,mmp-clk-reg = <0x10 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_pwm3_mux: apbc_pwm3_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk13m &osc_32k>;
+					clock-output-names = "apbc_pwm3_mux";
+					marvell,mmp-clk-sel = <0 0x10>;
+					marvell,mmp-clk-reg = <0x14 0x70>;
+				};
+				apbc_pwm3_clk: apbc_pwm3_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_pwm3_mux>;
+					clock-names = "apbc_pwm3_clk";
+					marvell,mmp-clk-reg = <0x14 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_pwm4_mux: apbc_pwm4_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk13m &osc_32k>;
+					clock-output-names = "apbc_pwm4_mux";
+					marvell,mmp-clk-sel = <0 0x10>;
+					marvell,mmp-clk-reg = <0x18 0x70>;
+				};
+				apbc_pwm4_clk: apbc_pwm4_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_pwm4_mux>;
+					clock-names = "apbc_pwm4_clk";
+					marvell,mmp-clk-reg = <0x18 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_ssp1_mux: apbc_ssp1_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk7m &refclk13m &refclk26m &refclk52m>;
+					clock-output-names = "apbc_ssp1_mux";
+					marvell,mmp-clk-sel = <0 0x10 0x20 0x30>;
+					marvell,mmp-clk-reg = <0x1c 0x70>;
+				};
+				apbc_ssp1_clk: apbc_ssp1_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_ssp1_mux>;
+					clock-names = "apbc_ssp1_clk";
+					marvell,mmp-clk-reg = <0x1c 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_ssp2_mux: apbc_ssp2_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk7m &refclk13m &refclk26m &refclk52m>;
+					clock-output-names = "apbc_ssp2_mux";
+					marvell,mmp-clk-sel = <0 0x10 0x20 0x30>;
+					marvell,mmp-clk-reg = <0x20 0x70>;
+				};
+				apbc_ssp2_clk: apbc_ssp2_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_ssp2_mux>;
+					clock-names = "apbc_ssp2_clk";
+					marvell,mmp-clk-reg = <0x20 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_ssp3_mux: apbc_ssp3_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk7m &refclk13m &refclk26m &refclk52m>;
+					clock-output-names = "apbc_ssp3_mux";
+					marvell,mmp-clk-sel = <0 0x10 0x20 0x30>;
+					marvell,mmp-clk-reg = <0x4c 0x70>;
+				};
+				apbc_ssp3_clk: apbc_ssp3_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_ssp3_mux>;
+					clock-names = "apbc_ssp3_clk";
+					marvell,mmp-clk-reg = <0x4c 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_kpc_mux: apbc_kpc_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&osc_32k &refclk16k &refclk26m>;
+					clock-output-names = "apbc_kpc_mux";
+					marvell,mmp-clk-sel = <0 0x10 0x20>;
+					marvell,mmp-clk-reg = <0x30 0x70>;
+				};
+				apbc_kpc_clk: apbc_kpc_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_kpc_mux>;
+					clock-names = "apbc_kpc_clk";
+					marvell,mmp-clk-reg = <0x30 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_timer0_mux: apbc_timer0_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk13m &osc_32k &refclk7m &refclk3m>;
+					clock-output-names = "apbc_timer0_mux";
+					marvell,mmp-clk-sel = <0 0x10 0x20 0x30>;
+					marvell,mmp-clk-reg = <0x34 0x70>;
+				};
+				apbc_timer0_clk: apbc_timer0_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&timer0_mux>;
+					clock-names = "apbc_timer0_clk";
+					marvell,mmp-clk-reg = <0x34 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_timer1_mux: apbc_timer1_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk13m &osc_32k &refclk7m &refclk3m>;
+					clock-output-names = "apbc_timer1_mux";
+					marvell,mmp-clk-sel = <0 0x10 0x20 0x30>;
+					marvell,mmp-clk-reg = <0x44 0x70>;
+				};
+				apbc_timer1_clk: apbc_timer1_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&timer1_mux>;
+					clock-names = "apbc_timer1_clk";
+					marvell,mmp-clk-reg = <0x44 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+			};
+
+			apbcp: clocks at 3b000 {
+				compatible = "marvell,mmp-apbcp";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				reg = <0xd403b000 0x100>;
+
+				apbcp_twsi2_clk: apbcp_twsi2_clk {
+					compatible = "marvell,mmp-apbcp-clock";
+					#clock-cells = <0>;
+					clocks = <&refclk32m>;
+					clock-output-names = "apbcp_twsi2_clk";
+					marvell,mmp-clk-sel = <0>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x28 0x70>;
+				};
+				apbcp_uart3_mux: apbcp_uart3_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk59m &refclk15m>;
+					clock-output-names = "apbcp_uart3_mux";
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x1c 0x70>;
+					/* register value of each item */
+					marvell,mmp-clk-sel = <0 0x10>;
+				};
+				apbcp_uart3_clk: apbcp_uart3_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbcp_uart3_mux>;
+					clock-names = "apbcp_uart3_clk";
+					marvell,mmp-clk-reg = <0x1c 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+			};
+
+			timer0_mux: timer0_mux {
+				compatible = "marvell,mmp-clkmux";
+				#clock-cells = <0>;
+				clocks = <&refclk3m &osc_32k &apbc_timer0_mux>;
+				clock-output-names = "timer0_mux";
+				marvell,mmp-clk-sel = <0 0x1 0x3>;
+				marvell,mmp-clk-reg = <0x14000 0x1c>;
+			};
+
+			timer1_mux: timer1_mux {
+				compatible = "marvell,mmp-clkmux";
+				#clock-cells = <0>;
+				clocks = <&refclk3m &osc_32k &apbc_timer1_mux>;
+				clock-output-names = "timer1_mux";
+				marvell,mmp-clk-sel = <0 0x1 0x3>;
+				marvell,mmp-clk-reg = <0x16000 0x1c>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/pxa910-dkb.dts b/arch/arm/boot/dts/pxa910-dkb.dts
index 595492a..b892ebe 100644
--- a/arch/arm/boot/dts/pxa910-dkb.dts
+++ b/arch/arm/boot/dts/pxa910-dkb.dts
@@ -24,6 +24,17 @@
 
 	soc {
 		apb at d4000000 {
+			pll2: refclk1001mhz {
+				/* Reference clock for internal PLL2 */
+				compatible = "marvell,mmp-fixed-clkrate";
+				#clock-cells = <0>;
+				clocks = <&osc_26m>;
+				clock-frequency = <1001000000>;
+				clock-output-names = "refclk1001mhz";
+			};
+			timer0: timer at d4014000 {
+				status = "okay";
+			};
 			uart1: uart at d4017000 {
 				status = "okay";
 			};
diff --git a/arch/arm/boot/dts/pxa910.dtsi b/arch/arm/boot/dts/pxa910.dtsi
index 0247c62..cd888d3 100644
--- a/arch/arm/boot/dts/pxa910.dtsi
+++ b/arch/arm/boot/dts/pxa910.dtsi
@@ -8,6 +8,7 @@
  */
 
 /include/ "skeleton.dtsi"
+/include/ "pxa910-clk.dtsi"
 
 / {
 	aliases {
@@ -44,7 +45,6 @@
 				reg = <0xd4282000 0x1000>;
 				mrvl,intc-nr-irqs = <64>;
 			};
-
 		};
 
 		apb at d4000000 {	/* APB */
@@ -58,12 +58,15 @@
 				compatible = "mrvl,mmp-timer";
 				reg = <0xd4014000 0x100>;
 				interrupts = <13>;
+				clocks = <&apbc_timer0_clk>;
+				status = "disabled";
 			};
 
 			timer1: timer at d4016000 {
 				compatible = "mrvl,mmp-timer";
 				reg = <0xd4016000 0x100>;
 				interrupts = <29>;
+				clocks = <&apbc_timer1_clk>;
 				status = "disabled";
 			};
 
@@ -71,6 +74,7 @@
 				compatible = "mrvl,mmp-uart";
 				reg = <0xd4017000 0x1000>;
 				interrupts = <27>;
+				clocks = <&apbc_uart1_clk>;
 				status = "disabled";
 			};
 
@@ -78,6 +82,7 @@
 				compatible = "mrvl,mmp-uart";
 				reg = <0xd4018000 0x1000>;
 				interrupts = <28>;
+				clocks = <&apbc_uart2_clk>;
 				status = "disabled";
 			};
 
@@ -85,6 +90,7 @@
 				compatible = "mrvl,mmp-uart";
 				reg = <0xd4036000 0x1000>;
 				interrupts = <59>;
+				clocks = <&apbcp_uart3_clk>;
 				status = "disabled";
 			};
 
@@ -99,6 +105,7 @@
 				interrupt-names = "gpio_mux";
 				interrupt-controller;
 				#interrupt-cells = <1>;
+				clocks = <&apbc_gpio_clk>;
 				ranges;
 
 				gcb0: gpio at d4019000 {
@@ -124,6 +131,7 @@
 				#size-cells = <0>;
 				reg = <0xd4011000 0x1000>;
 				interrupts = <7>;
+				clocks = <&apbc_twsi1_clk>;
 				mrvl,i2c-fast-mode;
 				status = "disabled";
 			};
@@ -134,6 +142,7 @@
 				#size-cells = <0>;
 				reg = <0xd4037000 0x1000>;
 				interrupts = <54>;
+				clocks = <&apbcp_twsi2_clk>;
 				status = "disabled";
 			};
 
@@ -142,6 +151,7 @@
 				reg = <0xd4010000 0x1000>;
 				interrupts = <5 6>;
 				interrupt-names = "rtc 1Hz", "rtc alarm";
+				clocks = <&apbc_rtc_clk>;
 				status = "disabled";
 			};
 		};
diff --git a/arch/arm/mach-mmp/mmp-dt.c b/arch/arm/mach-mmp/mmp-dt.c
index cca529c..f109bf6 100644
--- a/arch/arm/mach-mmp/mmp-dt.c
+++ b/arch/arm/mach-mmp/mmp-dt.c
@@ -9,6 +9,7 @@
  *  publishhed by the Free Software Foundation.
  */
 
+#include <linux/clk-provider.h>
 #include <linux/irqchip.h>
 #include <linux/of_platform.h>
 #include <asm/mach/arch.h>
@@ -48,6 +49,7 @@ static void __init pxa168_dt_init(void)
 
 static void __init pxa910_dt_init(void)
 {
+	of_clk_init(NULL);
 	of_platform_populate(NULL, of_default_bus_match_table,
 			     pxa910_auxdata_lookup, NULL);
 }
diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile
index 392d780..83182e5 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-mmp.o
 
 obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
 obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o
diff --git a/drivers/clk/mmp/clk-mmp.c b/drivers/clk/mmp/clk-mmp.c
new file mode 100644
index 0000000..7ead432
--- /dev/null
+++ b/drivers/clk/mmp/clk-mmp.c
@@ -0,0 +1,363 @@
+/*
+ * Marvell MMP clock driver
+ *
+ * Copyright (c) 2012 Linaro Limited.
+ *
+ * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+
+#include "clk.h"
+
+enum {
+	MMP_MPMU = 0,
+	MMP_APMU,
+	MMP_APBC,
+	MMP_APBCP,
+	MMP_APB,
+	MMP_MAX,
+};
+
+static void __iomem *mmp_clk_base[MMP_MAX];
+
+static DEFINE_SPINLOCK(mmp_clk_lock);
+
+static const struct of_device_id mmp_of_match[] = {
+	{ .compatible = "marvell,mmp-mpmu", .data = (void *)MMP_MPMU, },
+	{ .compatible = "marvell,mmp-apmu", .data = (void *)MMP_APMU, },
+	{ .compatible = "marvell,mmp-apbc", .data = (void *)MMP_APBC, },
+	{ .compatible = "marvell,mmp-apbcp", .data = (void *)MMP_APBCP, },
+	{ .compatible = "mrvl,apb-bus", .data = (void *)MMP_APB, },
+};
+
+void __iomem __init *mmp_init_clocks(struct device_node *np)
+{
+	struct device_node *parent;
+	const struct of_device_id *match;
+	void __iomem *ret = NULL;
+	int i;
+
+	parent = of_get_parent(np);
+	if (!parent)
+		goto out;
+	match = of_match_node(mmp_of_match, parent);
+	if (!match)
+		goto out;
+
+	i = (unsigned int)match->data;
+	switch (i) {
+	case MMP_MPMU:
+	case MMP_APMU:
+	case MMP_APBC:
+	case MMP_APBCP:
+	case MMP_APB:
+		if (!mmp_clk_base[i]) {
+			ret = of_iomap(parent, 0);
+			WARN_ON(!ret);
+			mmp_clk_base[i] = ret;
+		} else {
+			ret = mmp_clk_base[i];
+		}
+		break;
+	default:
+		goto out;
+	}
+out:
+	return ret;
+}
+
+static void __init mmp_fixed_rate_setup(struct device_node *np)
+{
+	struct clk *clk;
+	const char *clk_name, *parent_name;
+	int rate;
+
+	if (of_property_read_u32(np, "clock-frequency", &rate))
+		return;
+
+	if (of_property_read_string(np, "clock-output-names", &clk_name))
+		return;
+
+	/* this node has only one parent */
+	parent_name = of_clk_get_parent_name(np, 0);
+	if (!parent_name)
+		return;
+
+	clk = clk_register_fixed_rate(NULL, clk_name, parent_name, 0, rate);
+	if (IS_ERR(clk))
+		return;
+	of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+CLK_OF_DECLARE(mmp_fixed_rate, "marvell,mmp-fixed-clkrate",
+	       mmp_fixed_rate_setup);
+
+static void __init mmp_fixed_factor_setup(struct device_node *np)
+{
+	struct clk *clk;
+	const char *clk_name, *output_name, *parent_name;
+	u32 data[2];
+
+	if (of_property_read_u32_array(np, "marvell,mmp-fixed-factor",
+				&data[0], 2))
+		return;
+	if (of_property_read_string(np, "clock-output-names", &output_name))
+		return;
+
+	/* this node has only one parent */
+	parent_name = of_clk_get_parent_name(np, 0);
+	if (!parent_name)
+		return;
+
+	clk = clk_register_fixed_factor(NULL, output_name, parent_name, 0,
+			data[0], data[1]);
+	if (IS_ERR(clk))
+		return;
+	if (!of_property_read_string(np, "clock-names", &clk_name))
+		clk_register_clkdev(clk, clk_name, NULL);
+	of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+CLK_OF_DECLARE(mmp_fixed_factor, "marvell,mmp-fixed-clkfactor",
+	       mmp_fixed_factor_setup);
+
+static void __init mmp_apmu_div_setup(struct device_node *np)
+{
+	u32 data[2];
+	u8 shift, width;
+	void __iomem *reg, *base;
+	const char *parent_name, *clk_name;
+	struct clk *clk;
+
+	base = mmp_init_clocks(np);
+	if (!base)
+		return;
+
+	if (of_property_read_u32_array(np, "marvell,mmp-clk-reg", &data[0], 2))
+		return;
+	reg = base + data[0];
+	shift = ffs(data[1]) - 1;
+	width = fls(data[1]) - ffs(data[1]) + 1;
+
+	parent_name = of_clk_get_parent_name(np, 0);
+	if (!parent_name)
+		return;
+	if (of_property_read_string(np, "clock-output-names", &clk_name))
+		return;
+
+	clk = clk_register_divider(NULL, clk_name, parent_name,
+			CLK_SET_RATE_PARENT, reg, shift, width, 0,
+			&mmp_clk_lock);
+	if (IS_ERR(clk))
+		return;
+	of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	return;
+}
+CLK_OF_DECLARE(mmp_div, "mmp-apmu-clkdiv", mmp_apmu_div_setup);
+
+static int __init mmp_parse_mux(struct device_node *np,
+				const char **parent_names,
+				u8 *num_parents,
+				u32 *clk_sel)
+{
+	int i, cnt, ret;
+
+	/* get the count of items in mux */
+	for (i = 0, cnt = 0; ; i++, cnt++) {
+		/* parent's #clock-cells property is always 0 */
+		if (!of_parse_phandle(np, "clocks", i))
+			break;
+	}
+
+	for (i = 0; ; i++) {
+		if (!of_clk_get_parent_name(np, i))
+			break;
+	}
+	*num_parents = i;
+	if (!*num_parents)
+		return -ENOENT;
+
+	clk_sel = kzalloc(sizeof(u32 *) * *num_parents, GFP_KERNEL);
+	if (!clk_sel)
+		return -ENOMEM;
+	ret = of_property_read_u32_array(np, "marvell,mmp-clk-sel", clk_sel, cnt);
+	if (ret)
+		goto err;
+	return 0;
+err:
+	kfree(clk_sel);
+	return ret;
+}
+
+static void __init mmp_mux_setup(struct device_node *np)
+{
+	u32 data[2], *clk_sel, mux_flags = 0;
+	u8 shift, width, num_parents;
+	void __iomem *reg, *base;
+	const char **parent_names;
+	const char *clk_name;
+	struct clk *clk;
+	int i, ret;
+
+	base = mmp_init_clocks(np);
+	if (!base)
+		return;
+	if (of_property_read_string(np, "clock-output-names", &clk_name))
+		return;
+	if (of_property_read_u32_array(np, "marvell,mmp-clk-reg", &data[0], 2))
+		return;
+	ret = mmp_parse_mux(np, parent_names, &num_parents, clk_sel);
+	if (ret)
+		return;
+
+	reg = base + data[0];
+	shift = ffs(data[1]) - 1;
+	width = fls(data[1]) - ffs(data[1]) + 1;
+
+	parent_names = kzalloc(sizeof(char *) * num_parents, GFP_KERNEL);
+	if (!parent_names)
+		return;
+
+	for (i = 0; i < num_parents; i++)
+		parent_names[i] = of_clk_get_parent_name(np, i);
+	clk = clk_register_mux(NULL, clk_name, parent_names, num_parents,
+			       CLK_SET_RATE_PARENT, reg, shift, width,
+			       mux_flags, &mmp_clk_lock);
+	if (IS_ERR(clk)) {
+		kfree(parent_names);
+		return;
+	}
+	of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+CLK_OF_DECLARE(mmp_mux, "marvell,mmp-clkmux", mmp_mux_setup);
+
+#define APBC_NO_BUS_CTRL	BIT(0)
+#define APBC_POWER_CTRL		BIT(1)
+
+static void __init mmp_apbc_setup(struct device_node *np)
+{
+	u32 data[2], delay, apbc_flags, clkdev;
+	void __iomem *reg, *base;
+	const char **parent_names;
+	const char *clk_name = NULL;
+	struct clk *clk;
+
+	base = mmp_init_clocks(np);
+	if (!base)
+		return;
+
+	if (of_property_read_string(np, "clock-names", &clk_name))
+		clkdev = 1;
+	else {
+		of_property_read_string(np, "clock-output-names", &clk_name);
+		clkdev = 0;
+	}
+
+	if (of_property_read_u32_array(np, "marvell,mmp-clk-reg", &data[0], 2))
+		return;
+	/* If marvell,mmp-clk-delay property isn't defined, set delay as 10us */
+	if (of_property_read_u32(np, "marvell,mmp-clk-delay", &delay))
+		delay = 10;
+	if (of_get_property(np, "marvell,mmp-apbc-power-ctl", NULL))
+		apbc_flags |= APBC_POWER_CTRL;
+
+	reg = base + data[0];
+
+	/* only has the fixed parent */
+	parent_names = kzalloc(sizeof(char *), GFP_KERNEL);
+	if (!parent_names)
+		return;
+	parent_names[0] = of_clk_get_parent_name(np, 0);
+
+	clk = mmp_clk_register_apbc(clk_name, parent_names[0],
+				    reg, delay, 0, &mmp_clk_lock);
+	if (IS_ERR(clk)) {
+		kfree(parent_names);
+		return;
+	}
+	if (clkdev)
+		clk_register_clkdev(clk, clk_name, NULL);
+	of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+CLK_OF_DECLARE(mmp_apbc, "marvell,mmp-apbc-clk", mmp_apbc_setup);
+
+static void __init mmp_apbcp_setup(struct device_node *np)
+{
+	int i, cnt;
+	u32 *clk_sel, data[2];
+	u8 num_parents, shift, width;
+	void __iomem *reg, *base;
+	const char **parent_names, *clk_name;
+	struct clk *clk;
+
+	base = mmp_init_clocks(np);
+	if (!base)
+		return;
+
+	if (of_property_read_string(np, "clock-output-names", &clk_name))
+		return;
+	/* get the count of items in mux */
+	for (i = 0, cnt = 0; ; i++, cnt++) {
+		/* parent's #clock-cells property is always 0 */
+		if (!of_parse_phandle(np, "clocks", i))
+			break;
+	}
+
+	for (i = 0; ; i++) {
+		if (!of_clk_get_parent_name(np, i))
+			break;
+	}
+	num_parents = i;
+	if (!num_parents)
+		return;
+
+	if (of_property_read_u32_array(np, "marvell,mmp-clk-reg", &data[0], 2))
+		return;
+	reg = base + data[0];
+	shift = ffs(data[1]) - 1;
+	width = fls(data[1]) - ffs(data[1]) + 1;
+
+	clk_sel = kzalloc(sizeof(u32 *) * num_parents, GFP_KERNEL);
+	if (!clk_sel)
+		return;
+	if (of_property_read_u32_array(np, "marvell,mmp-clk-sel", clk_sel, cnt))
+		goto err_sel;
+	parent_names = kzalloc(sizeof(char *) * num_parents, GFP_KERNEL);
+	if (!parent_names)
+		goto err_sel;
+
+	for (i = 0; i < num_parents; i++)
+		parent_names[i] = of_clk_get_parent_name(np, i);
+	clk = clk_register_mux(NULL, clk_name, parent_names, num_parents, 0,
+				reg, shift, width, 0, &mmp_clk_lock);
+	if (IS_ERR(clk))
+		goto err_mux;
+	of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	return;
+err_mux:
+	kfree(parent_names);
+err_sel:
+	kfree(clk_sel);
+}
+CLK_OF_DECLARE(mmp_apbcp, "mmp-apbcp-clk", mmp_apbcp_setup);
-- 
1.8.1.2

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v4 10/10] ARM: mmp: avoid to use cpu_is_xxx in timer
  2013-06-04  4:12 [PATCH v4 00/10] update irqchip, clocksource, clk for mmp Haojian Zhuang
                   ` (8 preceding siblings ...)
  2013-06-04  4:12 ` [PATCH v4 09/10] clk: mmp: parse clock from dts Haojian Zhuang
@ 2013-06-04  4:12 ` Haojian Zhuang
  2013-06-04 15:27 ` [PATCH v5 09/10] clk: mmp: parse clock from dts Haojian Zhuang
  10 siblings, 0 replies; 13+ messages in thread
From: Haojian Zhuang @ 2013-06-04  4:12 UTC (permalink / raw)
  To: linux-arm-kernel

Avoid to use cpu_is_xxx() in timer-mmp driver, since it blocks the
multiplatform build. Now add mmp2_mode variable for legacy mode.
In DT mode, set the right clock rate in DTS file.

Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
 arch/arm/Kconfig                      |  1 +
 arch/arm/boot/dts/mmp2-brownstone.dts |  4 ++
 arch/arm/boot/dts/pxa168-aspenite.dts |  1 +
 arch/arm/boot/dts/pxa910-dkb.dts      |  1 +
 arch/arm/mach-mmp/common.h            |  2 +-
 arch/arm/mach-mmp/mmp-dt.c            | 14 ++++---
 arch/arm/mach-mmp/mmp2-dt.c           | 12 ++++--
 arch/arm/mach-mmp/mmp2.c              |  2 +-
 arch/arm/mach-mmp/pxa168.c            |  2 +-
 arch/arm/mach-mmp/pxa910.c            |  2 +-
 drivers/clocksource/timer-mmp.c       | 72 +++++++++++++++++++++--------------
 11 files changed, 72 insertions(+), 41 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index d6ba351..324cb62 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -545,6 +545,7 @@ config ARCH_MMP
 	depends on MMU
 	select ARCH_REQUIRE_GPIOLIB
 	select CLKDEV_LOOKUP
+	select CLKSRC_OF if OF
 	select GENERIC_ALLOCATOR
 	select GENERIC_CLOCKEVENTS
 	select GPIO_PXA
diff --git a/arch/arm/boot/dts/mmp2-brownstone.dts b/arch/arm/boot/dts/mmp2-brownstone.dts
index 7f70a39..29c7dc6 100644
--- a/arch/arm/boot/dts/mmp2-brownstone.dts
+++ b/arch/arm/boot/dts/mmp2-brownstone.dts
@@ -24,6 +24,10 @@
 
 	soc {
 		apb at d4000000 {
+			timer0: timer at d4014000 {
+				clock-frequency = <6500000>;
+				status = "okay";
+			};
 			uart3: uart at d4018000 {
 				status = "okay";
 			};
diff --git a/arch/arm/boot/dts/pxa168-aspenite.dts b/arch/arm/boot/dts/pxa168-aspenite.dts
index 2597e98..9b3d6d9 100644
--- a/arch/arm/boot/dts/pxa168-aspenite.dts
+++ b/arch/arm/boot/dts/pxa168-aspenite.dts
@@ -25,6 +25,7 @@
 	soc {
 		apb at d4000000 {
 			timer0: timer at d4014000 {
+				clock-frequency = <3250000>;
 				status = "okay";
 			};
 			uart1: uart at d4017000 {
diff --git a/arch/arm/boot/dts/pxa910-dkb.dts b/arch/arm/boot/dts/pxa910-dkb.dts
index b892ebe..3cd1a85 100644
--- a/arch/arm/boot/dts/pxa910-dkb.dts
+++ b/arch/arm/boot/dts/pxa910-dkb.dts
@@ -33,6 +33,7 @@
 				clock-output-names = "refclk1001mhz";
 			};
 			timer0: timer at d4014000 {
+				clock-frequency = <3250000>;
 				status = "okay";
 			};
 			uart1: uart at d4017000 {
diff --git a/arch/arm/mach-mmp/common.h b/arch/arm/mach-mmp/common.h
index 2fc9390..3784ea9 100644
--- a/arch/arm/mach-mmp/common.h
+++ b/arch/arm/mach-mmp/common.h
@@ -1,6 +1,6 @@
 #define ARRAY_AND_SIZE(x)	(x), ARRAY_SIZE(x)
 
-extern void timer_init(void __iomem *base, int irq);
+extern void timer_init(void __iomem *base, int irq, int mmp2_mode);
 
 extern void __init mmp_map_io(void);
 extern void mmp_restart(char, const char *);
diff --git a/arch/arm/mach-mmp/mmp-dt.c b/arch/arm/mach-mmp/mmp-dt.c
index f109bf6..8d0253b 100644
--- a/arch/arm/mach-mmp/mmp-dt.c
+++ b/arch/arm/mach-mmp/mmp-dt.c
@@ -10,6 +10,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/clocksource.h>
 #include <linux/irqchip.h>
 #include <linux/of_platform.h>
 #include <asm/mach/arch.h>
@@ -17,8 +18,6 @@
 
 #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),
@@ -49,7 +48,6 @@ static void __init pxa168_dt_init(void)
 
 static void __init pxa910_dt_init(void)
 {
-	of_clk_init(NULL);
 	of_platform_populate(NULL, of_default_bus_match_table,
 			     pxa910_auxdata_lookup, NULL);
 }
@@ -60,16 +58,22 @@ static const char *mmp_dt_board_compat[] __initdata = {
 	NULL,
 };
 
+static void __init mmp_init_timer(void)
+{
+	of_clk_init(NULL);
+	clocksource_of_init();
+}
+
 DT_MACHINE_START(PXA168_DT, "Marvell PXA168 (Device Tree Support)")
 	.map_io		= mmp_map_io,
-	.init_time	= mmp_dt_init_timer,
+	.init_time	= mmp_init_timer,
 	.init_machine	= pxa168_dt_init,
 	.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_time	= mmp_init_timer,
 	.init_machine	= pxa910_dt_init,
 	.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
index 023cb45..2229d1d 100644
--- a/arch/arm/mach-mmp/mmp2-dt.c
+++ b/arch/arm/mach-mmp/mmp2-dt.c
@@ -9,6 +9,8 @@
  *  publishhed by the Free Software Foundation.
  */
 
+#include <linux/clk-provider.h>
+#include <linux/clocksource.h>
 #include <linux/io.h>
 #include <linux/irqchip.h>
 #include <linux/of_platform.h>
@@ -17,8 +19,6 @@
 
 #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),
@@ -37,6 +37,12 @@ static void __init mmp2_dt_init(void)
 			     mmp2_auxdata_lookup, NULL);
 }
 
+static void __init mmp2_init_timer(void)
+{
+	of_clk_init(NULL);
+	clocksource_of_init();
+}
+
 static const char *mmp2_dt_board_compat[] __initdata = {
 	"mrvl,mmp2-brownstone",
 	NULL,
@@ -44,7 +50,7 @@ static const char *mmp2_dt_board_compat[] __initdata = {
 
 DT_MACHINE_START(MMP2_DT, "Marvell MMP2 (Device Tree Support)")
 	.map_io		= mmp_map_io,
-	.init_time	= mmp_dt_init_timer,
+	.init_time	= mmp2_init_timer,
 	.init_machine	= mmp2_dt_init,
 	.dt_compat	= mmp2_dt_board_compat,
 MACHINE_END
diff --git a/arch/arm/mach-mmp/mmp2.c b/arch/arm/mach-mmp/mmp2.c
index a0abfd7..d00c0fe 100644
--- a/arch/arm/mach-mmp/mmp2.c
+++ b/arch/arm/mach-mmp/mmp2.c
@@ -131,7 +131,7 @@ void __init mmp2_timer_init(void)
 	clk_rst = APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(1);
 	__raw_writel(clk_rst, APBC_TIMERS);
 
-	timer_init(TIMER1_VIRT_BASE, IRQ_MMP2_TIMER1);
+	timer_init(TIMER1_VIRT_BASE, IRQ_MMP2_TIMER1, 1);
 }
 
 /* on-chip devices */
diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c
index 345a493..f8dfbc6 100644
--- a/arch/arm/mach-mmp/pxa168.c
+++ b/arch/arm/mach-mmp/pxa168.c
@@ -78,7 +78,7 @@ void __init pxa168_timer_init(void)
 	/* 3.25MHz, bus/functional clock enabled, release reset */
 	__raw_writel(TIMER_CLK_RST, APBC_TIMERS);
 
-	timer_init(TIMER1_VIRT_BASE, IRQ_PXA168_TIMER1);
+	timer_init(TIMER1_VIRT_BASE, IRQ_PXA168_TIMER1, 0);
 }
 
 void pxa168_clear_keypad_wakeup(void)
diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c
index 1a84800..0e98bf3 100644
--- a/arch/arm/mach-mmp/pxa910.c
+++ b/arch/arm/mach-mmp/pxa910.c
@@ -112,7 +112,7 @@ void __init pxa910_timer_init(void)
 	__raw_writel(APBC_APBCLK | APBC_RST, APBC_TIMERS);
 	__raw_writel(TIMER_CLK_RST, APBC_TIMERS);
 
-	timer_init(TIMER1_VIRT_BASE, IRQ_PXA910_AP1_TIMER1);
+	timer_init(TIMER1_VIRT_BASE, IRQ_PXA910_AP1_TIMER1, 0);
 }
 
 /* on-chip devices */
diff --git a/drivers/clocksource/timer-mmp.c b/drivers/clocksource/timer-mmp.c
index bfd0997..ca4f10c 100644
--- a/drivers/clocksource/timer-mmp.c
+++ b/drivers/clocksource/timer-mmp.c
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
+#include <linux/clk-provider.h>
 #include <linux/clockchips.h>
 
 #include <linux/io.h>
@@ -30,8 +31,6 @@
 #include <linux/of_irq.h>
 
 #include <asm/sched_clock.h>
-#include <mach/irqs.h>
-#include <mach/cputype.h>
 #include <asm/mach/time.h>
 
 #define TMR_CCR		(0x0000)
@@ -177,16 +176,19 @@ static struct clocksource cksrc = {
 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-static void __init timer_config(void)
+static void __init timer_init_clk(int mmp2_mode)
 {
 	uint32_t ccr = __raw_readl(mmp_timer_base + TMR_CCR);
 
 	__raw_writel(0x0, mmp_timer_base + TMR_CER); /* disable */
 
-	ccr &= (cpu_is_mmp2()) ? (TMR_CCR_CS_0(0) | TMR_CCR_CS_1(0)) :
+	ccr &= mmp2_mode ? (TMR_CCR_CS_0(0) | TMR_CCR_CS_1(0)) :
 		(TMR_CCR_CS_0(3) | TMR_CCR_CS_1(3));
 	__raw_writel(ccr, mmp_timer_base + TMR_CCR);
+}
 
+static void __init timer_config(void)
+{
 	/* set timer 0 to periodic mode, and timer 1 to free-running mode */
 	__raw_writel(0x2, mmp_timer_base + TMR_CMR);
 
@@ -209,11 +211,12 @@ static struct irqaction timer_irq = {
 	.dev_id		= &ckevt,
 };
 
-void __init timer_init(void __iomem *base, int irq)
+void __init timer_init(void __iomem *base, int irq, int mmp2_mode)
 {
 	BUG_ON(!base);
 	mmp_timer_base = base;
 
+	timer_init_clk(mmp2_mode);
 	timer_config();
 
 	setup_sched_clock(mmp_read_sched_clock, 32, CLOCK_TICK_RATE);
@@ -227,36 +230,47 @@ void __init timer_init(void __iomem *base, int irq)
 					MIN_DELTA, MAX_DELTA);
 }
 
-#ifdef CONFIG_OF
-static struct of_device_id mmp_timer_dt_ids[] = {
-	{ .compatible = "mrvl,mmp-timer", },
-	{}
-};
-
-void __init mmp_dt_init_timer(void)
+static void __init mmp_dt_init_timer(struct device_node *np)
 {
-	struct device_node *np;
-	int irq, ret;
-
-	np = of_find_matching_node(NULL, mmp_timer_dt_ids);
-	if (!np) {
-		ret = -ENODEV;
-		goto out;
+	struct clk *clk;
+	int irq;
+	u32 rate = 0;
+
+	if (!of_device_is_available(np))
+		return;
+	if (of_property_read_u32(np, "clock-frequency", &rate)) {
+		pr_err("failed to find clock-frequency property\n");
+		return;
 	}
-
 	irq = irq_of_parse_and_map(np, 0);
-	if (!irq) {
-		ret = -EINVAL;
-		goto out;
+	if (!irq)
+		return;
+	clk = of_clk_get(np, 0);
+	if (IS_ERR(clk)) {
+		pr_err("failed to get timer clock\n");
+		return;
 	}
 	mmp_timer_base = of_iomap(np, 0);
-	if (!mmp_timer_base) {
-		ret = -ENOMEM;
+	if (!mmp_timer_base)
 		goto out;
-	}
-	timer_init(mmp_timer_base, irq);
+
+	__raw_writel(0x0, mmp_timer_base + TMR_CER); /* disable */
+	if (rate)
+		clk_set_rate(clk, rate);
+	clk_prepare_enable(clk);
+	timer_config();
+
+	setup_sched_clock(mmp_read_sched_clock, 32, rate);
+
+	ckevt.cpumask = cpumask_of(0);
+
+	setup_irq(irq, &timer_irq);
+
+	clocksource_register_hz(&cksrc, rate);
+	clockevents_config_and_register(&ckevt, rate,
+					MIN_DELTA, MAX_DELTA);
 	return;
 out:
-	pr_err("Failed to get timer from device tree with error:%d\n", ret);
+	clk_put(clk);
 }
-#endif
+CLOCKSOURCE_OF_DECLARE(mmp_timer, "mrvl,mmp-timer", mmp_dt_init_timer);
-- 
1.8.1.2

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v5 09/10] clk: mmp: parse clock from dts
  2013-06-04  4:12 [PATCH v4 00/10] update irqchip, clocksource, clk for mmp Haojian Zhuang
                   ` (9 preceding siblings ...)
  2013-06-04  4:12 ` [PATCH v4 10/10] ARM: mmp: avoid to use cpu_is_xxx in timer Haojian Zhuang
@ 2013-06-04 15:27 ` Haojian Zhuang
  10 siblings, 0 replies; 13+ messages in thread
From: Haojian Zhuang @ 2013-06-04 15:27 UTC (permalink / raw)
  To: linux-arm-kernel

Parse clock information from DTS file for mach-mmp.

Changelog:
v5:
1. Replace clk_register_mux() by clk_register_mux_table().

Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
 arch/arm/boot/dts/pxa168-aspenite.dts |   3 +
 arch/arm/boot/dts/pxa168-clk.dtsi     | 304 ++++++++++++++++++
 arch/arm/boot/dts/pxa168.dtsi         |  10 +
 arch/arm/boot/dts/pxa910-clk.dtsi     | 569 ++++++++++++++++++++++++++++++++++
 arch/arm/boot/dts/pxa910-dkb.dts      |  11 +
 arch/arm/boot/dts/pxa910.dtsi         |  12 +-
 arch/arm/mach-mmp/mmp-dt.c            |   2 +
 drivers/clk/mmp/Makefile              |   2 +-
 drivers/clk/mmp/clk-mmp.c             | 361 +++++++++++++++++++++
 9 files changed, 1272 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm/boot/dts/pxa168-clk.dtsi
 create mode 100644 arch/arm/boot/dts/pxa910-clk.dtsi
 create mode 100644 drivers/clk/mmp/clk-mmp.c

diff --git a/arch/arm/boot/dts/pxa168-aspenite.dts b/arch/arm/boot/dts/pxa168-aspenite.dts
index e762fac..2597e98 100644
--- a/arch/arm/boot/dts/pxa168-aspenite.dts
+++ b/arch/arm/boot/dts/pxa168-aspenite.dts
@@ -24,6 +24,9 @@
 
 	soc {
 		apb at d4000000 {
+			timer0: timer at d4014000 {
+				status = "okay";
+			};
 			uart1: uart at d4017000 {
 				status = "okay";
 			};
diff --git a/arch/arm/boot/dts/pxa168-clk.dtsi b/arch/arm/boot/dts/pxa168-clk.dtsi
new file mode 100644
index 0000000..f9c298df
--- /dev/null
+++ b/arch/arm/boot/dts/pxa168-clk.dtsi
@@ -0,0 +1,304 @@
+/*
+ *  Copyright (C) 2013
+ *  Author: Haojian Zhuang <haojian.zhuang@gmail.com>
+ *
+ *  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/ "skeleton.dtsi"
+
+/ {
+	soc {
+		apb at d4000000 {	/* APB */
+			compatible = "mrvl,apb-bus", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0xd4000000 0x00200000>;
+			ranges;
+
+			mpmu: clocks at 50000 {
+				compatible = "marvell,mmp-mpmu";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				reg = <0xd4050000 0x1100>;
+
+				osc_32k: osc32khz {
+					compatible = "fixed-clock";
+					#clock-cells = <0>;
+					clock-frequency = <32768>;
+					clock-output-names = "osc32khz";
+				};
+				osc_26m: osc26mhz {
+					compatible = "fixed-clock";
+					#clock-cells = <0>;
+					clock-frequency = <26000000>;
+					clock-output-names = "osc26mhz";
+				};
+				pll1_312m: refclk312mhz {
+					compatible = "marvell,mmp-fixed-clkrate";
+					#clock-cells = <0>;
+					clocks = <&osc_26m>;
+					clock-frequency = <312000000>;
+					clock-output-names = "refclk312mhz";
+				};
+				refclk156m: refclk156mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&pll1_312m>;
+					clock-output-names = "refclk156mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 2>;
+				};
+				refclk118m: refclk117mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&refclk156m>;
+					/* 117.9648MHz */
+					clock-output-names = "refclk118mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <6144 8125>;
+				};
+				refclk104m: refclk104mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&pll1_312m>;
+					clock-output-names = "refclk104mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 3>;
+				};
+				refclk59m: refclk59mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&refclk118m>;
+					clock-names = "baud_58.98mhz";
+					/* 58.9824MHz */
+					clock-output-names = "refclk59mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 2>;
+				};
+				refclk15m: refclk15mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&refclk156m>;
+					clock-names = "baud_14.86mhz";
+					/* 14.857MHz */
+					clock-output-names = "refclk15mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <2 21>;
+				};
+			};
+
+			apbc: clocks at 15000 {
+				compatible = "marvell,mmp-apbc";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				#clock-cells = <0>;
+				reg = <0xd4015000 0x100>;
+
+				apbc_twsi1_clk: apbc_twsi1_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&refclk32m>;
+					clock-names = "apbc_twsi1_clk";
+					/* register value of each item */
+					marvell,mmp-clk-sel = <0>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x2c 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_twsi2_clk: apbc_twsi2_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&refclk32m>;
+					clock-names = "apbc_twsi2_clk";
+					/* register value of each item */
+					marvell,mmp-clk-sel = <0>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x6c 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_rtc_clk: apbc_rtc_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&osc_32k>;
+					clock-names = "apbc_rtc_clk";
+					marvell,mmp-clk-sel = <0>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x28 0x70>;
+					marvell,mmp-apbc-power-ctl;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_gpio_clk: apbc_gpio_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&refclk26m>;
+					clock-names = "apbc_gpio_clk";
+					marvell,mmp-clk-sel = <0>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x8 0x0>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_uart1_mux: apbc_uart1_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk59m &refclk15m>;
+					clock-output-names = "apbc_uart1_mux";
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x0 0x70>;
+					/* register value of each item */
+					marvell,mmp-clk-sel = <0 0x10>;
+				};
+				apbc_uart1_clk: apbc_uart1_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_uart1_mux>;
+					clock-names = "apbc_uart1_clk";
+					marvell,mmp-clk-reg = <0x0 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_uart2_mux: apbc_uart2_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk59m &refclk15m>;
+					clock-output-names = "apbc_uart2_mux";
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x4 0x70>;
+					/* register value of each item */
+					marvell,mmp-clk-sel = <0 0x10>;
+				};
+				apbc_uart2_clk: apbc_uart2_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_uart2_mux>;
+					clock-names = "apbc_uart2_clk";
+					marvell,mmp-clk-reg = <0x4 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_uart3_mux: apbc_uart3_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk59m &refclk15m>;
+					clock-output-names = "apbc_uart3_mux";
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x70 0x70>;
+					/* register value of each item */
+					marvell,mmp-clk-sel = <0 0x10>;
+				};
+				apbc_uart3_clk: apbc_uart3_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_uart3_mux>;
+					clock-names = "apbc_uart3_clk";
+					marvell,mmp-clk-reg = <0x70 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_pwm1_mux: apbc_pwm1_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk13m &osc_32k>;
+					clock-output-names = "apbc_pwm1_mux";
+					marvell,mmp-clk-sel = <0 0x10>;
+					marvell,mmp-clk-reg = <0xc 0x70>;
+				};
+				apbc_pwm1_clk: apbc_pwm1_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_pwm1_mux>;
+					clock-names = "apbc_pwm1_clk";
+					marvell,mmp-clk-reg = <0xc 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_pwm2_mux: apbc_pwm2_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk13m &osc_32k>;
+					clock-output-names = "apbc_pwm2_mux";
+					marvell,mmp-clk-sel = <0 0x10>;
+					marvell,mmp-clk-reg = <0x10 0x70>;
+				};
+				apbc_pwm2_clk: apbc_pwm2_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_pwm2_mux>;
+					clock-names = "apbc_pwm2_clk";
+					marvell,mmp-clk-reg = <0x10 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_pwm3_mux: apbc_pwm3_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk13m &osc_32k>;
+					clock-output-names = "apbc_pwm3_mux";
+					marvell,mmp-clk-sel = <0 0x10>;
+					marvell,mmp-clk-reg = <0x14 0x70>;
+				};
+				apbc_pwm3_clk: apbc_pwm3_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_pwm3_mux>;
+					clock-names = "apbc_pwm3_clk";
+					marvell,mmp-clk-reg = <0x14 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_pwm4_mux: apbc_pwm4_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk13m &osc_32k>;
+					clock-output-names = "apbc_pwm4_mux";
+					marvell,mmp-clk-sel = <0 0x10>;
+					marvell,mmp-clk-reg = <0x18 0x70>;
+				};
+				apbc_pwm4_clk: apbc_pwm4_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_pwm4_mux>;
+					clock-names = "apbc_pwm4_clk";
+					marvell,mmp-clk-reg = <0x18 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_kpc_mux: apbc_kpc_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&osc_32k &refclk16k &refclk26m>;
+					clock-output-names = "apbc_kpc_mux";
+					marvell,mmp-clk-sel = <0 0x10 0x20>;
+					marvell,mmp-clk-reg = <0x30 0x70>;
+				};
+				apbc_kpc_clk: apbc_kpc_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_kpc_mux>;
+					clock-names = "apbc_kpc_clk";
+					marvell,mmp-clk-reg = <0x30 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_timer0_mux: apbc_timer0_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk13m &osc_32k &refclk7m &refclk3m>;
+					clock-output-names = "apbc_timer0_mux";
+					marvell,mmp-clk-sel = <0 0x10 0x20 0x30>;
+					marvell,mmp-clk-reg = <0x34 0x70>;
+				};
+				apbc_timer0_clk: apbc_timer0_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&timer0_mux>;
+					clock-names = "apbc_timer0_clk";
+					marvell,mmp-clk-reg = <0x34 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+			};
+			timer0_mux: timer0_mux {
+				compatible = "marvell,mmp-clkmux";
+				#clock-cells = <0>;
+				clocks = <&apbc_timer0_mux &osc_32k>;
+				clock-output-names = "timer0_mux";
+				marvell,mmp-clk-sel = <0 0x2>;
+				marvell,mmp-clk-reg = <0x14000 0x1c>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/pxa168.dtsi b/arch/arm/boot/dts/pxa168.dtsi
index 975dad2..250bf2c 100644
--- a/arch/arm/boot/dts/pxa168.dtsi
+++ b/arch/arm/boot/dts/pxa168.dtsi
@@ -8,6 +8,7 @@
  */
 
 /include/ "skeleton.dtsi"
+/include/ "pxa910-clk.dtsi"
 
 / {
 	aliases {
@@ -53,12 +54,15 @@
 				compatible = "mrvl,mmp-timer";
 				reg = <0xd4014000 0x100>;
 				interrupts = <13>;
+				clocks = <&apbc_timer0_clk>;
+				status = "disabled";
 			};
 
 			uart1: uart at d4017000 {
 				compatible = "mrvl,mmp-uart";
 				reg = <0xd4017000 0x1000>;
 				interrupts = <27>;
+				clocks = <&apbc_uart1_clk>;
 				status = "disabled";
 			};
 
@@ -66,6 +70,7 @@
 				compatible = "mrvl,mmp-uart";
 				reg = <0xd4018000 0x1000>;
 				interrupts = <28>;
+				clocks = <&apbc_uart2_clk>;
 				status = "disabled";
 			};
 
@@ -73,6 +78,7 @@
 				compatible = "mrvl,mmp-uart";
 				reg = <0xd4026000 0x1000>;
 				interrupts = <29>;
+				clocks = <&apbc_uart3_clk>;
 				status = "disabled";
 			};
 
@@ -87,6 +93,7 @@
 				interrupt-names = "gpio_mux";
 				interrupt-controller;
 				#interrupt-cells = <1>;
+				clocks = <&apbc_gpio_clk>;
 				ranges;
 
 				gcb0: gpio at d4019000 {
@@ -111,6 +118,7 @@
 				reg = <0xd4011000 0x1000>;
 				interrupts = <7>;
 				mrvl,i2c-fast-mode;
+				clocks = <&apbc_twsi1_clk>;
 				status = "disabled";
 			};
 
@@ -118,6 +126,7 @@
 				compatible = "mrvl,mmp-twsi";
 				reg = <0xd4025000 0x1000>;
 				interrupts = <58>;
+				clocks = <&apbc_twsi2_clk>;
 				status = "disabled";
 			};
 
@@ -126,6 +135,7 @@
 				reg = <0xd4010000 0x1000>;
 				interrupts = <5 6>;
 				interrupt-names = "rtc 1Hz", "rtc alarm";
+				clocks = <&apbc_rtc_clk>;
 				status = "disabled";
 			};
 		};
diff --git a/arch/arm/boot/dts/pxa910-clk.dtsi b/arch/arm/boot/dts/pxa910-clk.dtsi
new file mode 100644
index 0000000..035697f
--- /dev/null
+++ b/arch/arm/boot/dts/pxa910-clk.dtsi
@@ -0,0 +1,569 @@
+/*
+ *  Copyright (C) 2013
+ *  Author: Haojian Zhuang <haojian.zhuang@gmail.com>
+ *
+ *  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/ "skeleton.dtsi"
+
+/ {
+	soc {
+		axi at d4200000 {	/* AXI */
+			compatible = "mrvl,axi-bus", "simple-bus";
+			reg = <0xd4200000 0x00200000>;
+			ranges;
+
+			apmu: clocks at 82800 {
+				compatible = "marvell,mmp-apmu";
+				reg = <0xd4282800 0x100>;
+
+				/*
+				 * Processor clocks: pclk, pdclk, baclk, xpclk
+				 * DDR Controller clocks: dclk
+				 * AXI Fabric clocks: aclk
+				 */
+				pclk_refclk: refclk_pclk {
+					compatible = "marvell,mmp-apmu-clkdiv";
+					#clock-cells = <0>;
+					clocks = <&pj1_refclk>;
+					clock-output-names = "pclk";
+					marvell,mmp-clock-frequency = <104000000 156000000 208000000 312000000 500500000 624000000 806000000 1001000000>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x4 0x7>;
+				};
+				/* pdclk -- DDR Interface clock */
+				pdclk_refclk: refclk_pdclk {
+					compatible = "marvell,mmp-apmu-clkdiv";
+					#clock-cells = <0>;
+					clocks = <&pj1_refclk>;
+					clock-output-names = "pdclk";
+					marvell,mmp-clock-frequency = <78000000 104000000 156000000 201000000 250250000>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x4 0x38>;
+				};
+				/* baclk -- AXI Fabric Bus Interface clock */
+				baclk_refclk: refclk_baclk {
+					compatible = "marvell,mmp-apmu-clkdiv";
+					#clock-cells = <0>;
+					clocks = <&pj1_refclk>;
+					clock-output-names = "baclk";
+					marvell,mmp-clock-frequency = <78000000 104000000 156000000 201000000 250250000>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x4 0x1c0>;
+				};
+				/* xpclk -- L2 interface clock */
+				xpclk_refclk: refclk_xpclk {
+					compatible = "marvell,mmp-apmu-clkdiv";
+					#clock-cells = <0>;
+					clocks = <&pj1_refclk>;
+					clock-output-names = "xpclk";
+					marvell,mmp-clock-frequency = <104000000 156000000 250250000 312000000 403000000 500500000>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x4 0xe00>;
+				};
+				/* dclk -- DDR Controller clock */
+				dclk2x_refclk: refclk_dclk2x {
+					compatible = "marvell,mmp-apmu-clkdiv";
+					#clock-cells = <0>;
+					clocks = <&ddr_refclk>;
+					clock-output-names = "dclk2x";
+					marvell,mmp-clock-frequency = <208000000 312000000 402000000 500500000>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x4 0x7000>;
+				};
+				dclk_refclk: refclk_dclk {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&dclk2x_refclk>;
+					clock-output-names = "dclk";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 2>;
+				};
+				/* aclk -- AXI Fabric clock */
+				aclk_refclk: refclk_aclk {
+					compatible = "marvell,mmp-apmu-clkdiv";
+					#clock-cells = <0>;
+					clocks = <&axi_refclk>;
+					clock-output-names = "aclk";
+					marvell,mmp-clock-frequency = <104000000 156000000>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x4 0x38000>;
+				};
+			};
+		};
+
+		apb at d4000000 {	/* APB */
+			compatible = "mrvl,apb-bus", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0xd4000000 0x00200000>;
+			ranges;
+
+			mpmu: clocks at 50000 {
+				compatible = "marvell,mmp-mpmu";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				reg = <0xd4050000 0x1100>;
+
+				osc_32k: osc32khz {
+					compatible = "fixed-clock";
+					#clock-cells = <0>;
+					clock-frequency = <32768>;
+					clock-output-names = "osc32khz";
+				};
+				osc_26m: osc26mhz {
+					compatible = "fixed-clock";
+					#clock-cells = <0>;
+					clock-frequency = <26000000>;
+					clock-output-names = "osc26mhz";
+				};
+				pll1_312m: refclk312mhz {
+					compatible = "marvell,mmp-fixed-clkrate";
+					#clock-cells = <0>;
+					clocks = <&osc_26m>;
+					clock-frequency = <312000000>;
+					clock-output-names = "refclk312mhz";
+				};
+				pll1_624m: refclk624mhz {
+					compatible = "marvell,mmp-fixed-clkrate";
+					#clock-cells = <0>;
+					clocks = <&osc_26m>;
+					clock-frequency = <624000000>;
+					clock-output-names = "refclk624mhz";
+				};
+				pj1_refclk: refclk_pj1 {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&pll1_312m &pll1_624m &pll2>;
+					clock-output-names = "refclk_pj1";
+					/* register value of each item */
+					marvell,mmp-clk-sel = <0 0x20000000 0x40000000>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x8 0xe0000000>;
+				};
+				ddr_refclk: refclk_ddr {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&pll1_312m &pll1_624m &pll2>;
+					clock-output-names = "refclk_ddr";
+					/* register value of each item */
+					marvell,mmp-clk-sel = <0 0x00800000 0x01000000>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x8 0x01800000>;
+				};
+				axi_refclk: refclk_axi {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&pll1_312m &pll1_624m>;
+					clock-output-names = "refclk_axi";
+					/* register value of each item */
+					marvell,mmp-clk-sel = <0 0x00080000>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x8 0x00080000>;
+				};
+				refclk156m: refclk156mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&pll1_312m>;
+					clock-output-names = "refclk156mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 2>;
+				};
+				refclk118m: refclk117mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&refclk156m>;
+					/* 117.9648MHz */
+					clock-output-names = "refclk118mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <6144 8125>;
+				};
+				refclk104m: refclk104mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&pll1_312m>;
+					clock-output-names = "refclk104mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 3>;
+				};
+				refclk59m: refclk59mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&refclk118m>;
+					clock-names = "baud_58.98mhz";
+					/* 58.9824MHz */
+					clock-output-names = "refclk59mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 2>;
+				};
+				refclk52m: refclk52mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&refclk104m>;
+					clock-output-names = "refclk52mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 2>;
+				};
+				refclk48m: refclk48mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&pll1_624m>;
+					clock-output-names = "refclk48mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 13>;
+				};
+				refclk32m: refclk32mhz@ {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&refclk48m>;
+					clock-output-names = "refclk32mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <2 3>;
+				};
+				refclk26m: refclk26mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&refclk52m>;
+					clock-output-names = "refclk26mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 2>;
+				};
+				refclk15m: refclk15mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&refclk156m>;
+					clock-names = "baud_14.86mhz";
+					/* 14.857MHz */
+					clock-output-names = "refclk15mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <2 21>;
+				};
+				refclk13m: refclk13mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&refclk26m>;
+					clock-output-names = "refclk13mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 2>;
+				};
+				refclk7m: refclk7mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&refclk13m>;
+					clock-output-names = "refclk7mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 2>;
+				};
+				refclk3m: refclk3mhz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&refclk7m>;
+					clock-output-names = "refclk3mhz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 2>;
+				};
+				refclk16k: refclk16khz {
+					compatible = "marvell,mmp-fixed-clkfactor";
+					#clock-cells = <0>;
+					clocks = <&osc_32k>;
+					clock-output-names = "refclk16khz";
+					/* multiple & divider */
+					marvell,mmp-fixed-factor = <1 2>;
+				};
+			};
+
+			apbc: clocks at 15000 {
+				compatible = "marvell,mmp-apbc";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				#clock-cells = <0>;
+				reg = <0xd4015000 0x100>;
+
+				apbc_twsi1_clk: apbc_twsi1_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&refclk32m>;
+					clock-names = "apbc_twsi1_clk";
+					/* register value of each item */
+					marvell,mmp-clk-sel = <0>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x2c 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_rtc_clk: apbc_rtc_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&osc_32k>;
+					clock-names = "apbc_rtc_clk";
+					marvell,mmp-clk-sel = <0>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x28 0x70>;
+					marvell,mmp-apbc-power-ctl;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_gpio_clk: apbc_gpio_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&refclk26m>;
+					clock-names = "apbc_gpio_clk";
+					marvell,mmp-clk-sel = <0>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x8 0x0>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_uart1_mux: apbc_uart1_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk59m &refclk15m>;
+					clock-output-names = "apbc_uart1_mux";
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x0 0x70>;
+					/* register value of each item */
+					marvell,mmp-clk-sel = <0 0x10>;
+				};
+				apbc_uart1_clk: apbc_uart1_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_uart1_mux>;
+					clock-names = "apbc_uart1_clk";
+					marvell,mmp-clk-reg = <0x0 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_uart2_mux: apbc_uart2_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk59m &refclk15m>;
+					clock-output-names = "apbc_uart2_mux";
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x4 0x70>;
+					/* register value of each item */
+					marvell,mmp-clk-sel = <0 0x10>;
+				};
+				apbc_uart2_clk: apbc_uart2_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_uart2_mux>;
+					clock-names = "apbc_uart2_clk";
+					marvell,mmp-clk-reg = <0x4 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_pwm1_mux: apbc_pwm1_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk13m &osc_32k>;
+					clock-output-names = "apbc_pwm1_mux";
+					marvell,mmp-clk-sel = <0 0x10>;
+					marvell,mmp-clk-reg = <0xc 0x70>;
+				};
+				apbc_pwm1_clk: apbc_pwm1_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_pwm1_mux>;
+					clock-names = "apbc_pwm1_clk";
+					marvell,mmp-clk-reg = <0xc 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_pwm2_mux: apbc_pwm2_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk13m &osc_32k>;
+					clock-output-names = "apbc_pwm2_mux";
+					marvell,mmp-clk-sel = <0 0x10>;
+					marvell,mmp-clk-reg = <0x10 0x70>;
+				};
+				apbc_pwm2_clk: apbc_pwm2_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_pwm2_mux>;
+					clock-names = "apbc_pwm2_clk";
+					marvell,mmp-clk-reg = <0x10 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_pwm3_mux: apbc_pwm3_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk13m &osc_32k>;
+					clock-output-names = "apbc_pwm3_mux";
+					marvell,mmp-clk-sel = <0 0x10>;
+					marvell,mmp-clk-reg = <0x14 0x70>;
+				};
+				apbc_pwm3_clk: apbc_pwm3_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_pwm3_mux>;
+					clock-names = "apbc_pwm3_clk";
+					marvell,mmp-clk-reg = <0x14 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_pwm4_mux: apbc_pwm4_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk13m &osc_32k>;
+					clock-output-names = "apbc_pwm4_mux";
+					marvell,mmp-clk-sel = <0 0x10>;
+					marvell,mmp-clk-reg = <0x18 0x70>;
+				};
+				apbc_pwm4_clk: apbc_pwm4_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_pwm4_mux>;
+					clock-names = "apbc_pwm4_clk";
+					marvell,mmp-clk-reg = <0x18 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_ssp1_mux: apbc_ssp1_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk7m &refclk13m &refclk26m &refclk52m>;
+					clock-output-names = "apbc_ssp1_mux";
+					marvell,mmp-clk-sel = <0 0x10 0x20 0x30>;
+					marvell,mmp-clk-reg = <0x1c 0x70>;
+				};
+				apbc_ssp1_clk: apbc_ssp1_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_ssp1_mux>;
+					clock-names = "apbc_ssp1_clk";
+					marvell,mmp-clk-reg = <0x1c 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_ssp2_mux: apbc_ssp2_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk7m &refclk13m &refclk26m &refclk52m>;
+					clock-output-names = "apbc_ssp2_mux";
+					marvell,mmp-clk-sel = <0 0x10 0x20 0x30>;
+					marvell,mmp-clk-reg = <0x20 0x70>;
+				};
+				apbc_ssp2_clk: apbc_ssp2_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_ssp2_mux>;
+					clock-names = "apbc_ssp2_clk";
+					marvell,mmp-clk-reg = <0x20 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_ssp3_mux: apbc_ssp3_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk7m &refclk13m &refclk26m &refclk52m>;
+					clock-output-names = "apbc_ssp3_mux";
+					marvell,mmp-clk-sel = <0 0x10 0x20 0x30>;
+					marvell,mmp-clk-reg = <0x4c 0x70>;
+				};
+				apbc_ssp3_clk: apbc_ssp3_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_ssp3_mux>;
+					clock-names = "apbc_ssp3_clk";
+					marvell,mmp-clk-reg = <0x4c 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_kpc_mux: apbc_kpc_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&osc_32k &refclk16k &refclk26m>;
+					clock-output-names = "apbc_kpc_mux";
+					marvell,mmp-clk-sel = <0 0x10 0x20>;
+					marvell,mmp-clk-reg = <0x30 0x70>;
+				};
+				apbc_kpc_clk: apbc_kpc_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbc_kpc_mux>;
+					clock-names = "apbc_kpc_clk";
+					marvell,mmp-clk-reg = <0x30 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_timer0_mux: apbc_timer0_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk13m &osc_32k &refclk7m &refclk3m>;
+					clock-output-names = "apbc_timer0_mux";
+					marvell,mmp-clk-sel = <0 0x10 0x20 0x30>;
+					marvell,mmp-clk-reg = <0x34 0x70>;
+				};
+				apbc_timer0_clk: apbc_timer0_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&timer0_mux>;
+					clock-names = "apbc_timer0_clk";
+					marvell,mmp-clk-reg = <0x34 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+				apbc_timer1_mux: apbc_timer1_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk13m &osc_32k &refclk7m &refclk3m>;
+					clock-output-names = "apbc_timer1_mux";
+					marvell,mmp-clk-sel = <0 0x10 0x20 0x30>;
+					marvell,mmp-clk-reg = <0x44 0x70>;
+				};
+				apbc_timer1_clk: apbc_timer1_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&timer1_mux>;
+					clock-names = "apbc_timer1_clk";
+					marvell,mmp-clk-reg = <0x44 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+			};
+
+			apbcp: clocks at 3b000 {
+				compatible = "marvell,mmp-apbcp";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				reg = <0xd403b000 0x100>;
+
+				apbcp_twsi2_clk: apbcp_twsi2_clk {
+					compatible = "marvell,mmp-apbcp-clock";
+					#clock-cells = <0>;
+					clocks = <&refclk32m>;
+					clock-output-names = "apbcp_twsi2_clk";
+					marvell,mmp-clk-sel = <0>;
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x28 0x70>;
+				};
+				apbcp_uart3_mux: apbcp_uart3_mux {
+					compatible = "marvell,mmp-clkmux";
+					#clock-cells = <0>;
+					clocks = <&refclk59m &refclk15m>;
+					clock-output-names = "apbcp_uart3_mux";
+					/* register offset & mask */
+					marvell,mmp-clk-reg = <0x1c 0x70>;
+					/* register value of each item */
+					marvell,mmp-clk-sel = <0 0x10>;
+				};
+				apbcp_uart3_clk: apbcp_uart3_clk {
+					compatible = "marvell,mmp-apbc-clk";
+					#clock-cells = <0>;
+					clocks = <&apbcp_uart3_mux>;
+					clock-names = "apbcp_uart3_clk";
+					marvell,mmp-clk-reg = <0x1c 0x70>;
+					marvell,mmp-clk-delay = <10>;
+				};
+			};
+
+			timer0_mux: timer0_mux {
+				compatible = "marvell,mmp-clkmux";
+				#clock-cells = <0>;
+				clocks = <&refclk3m &osc_32k &apbc_timer0_mux>;
+				clock-output-names = "timer0_mux";
+				marvell,mmp-clk-sel = <0 0x1 0x3>;
+				marvell,mmp-clk-reg = <0x14000 0x1c>;
+			};
+
+			timer1_mux: timer1_mux {
+				compatible = "marvell,mmp-clkmux";
+				#clock-cells = <0>;
+				clocks = <&refclk3m &osc_32k &apbc_timer1_mux>;
+				clock-output-names = "timer1_mux";
+				marvell,mmp-clk-sel = <0 0x1 0x3>;
+				marvell,mmp-clk-reg = <0x16000 0x1c>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/pxa910-dkb.dts b/arch/arm/boot/dts/pxa910-dkb.dts
index 595492a..b892ebe 100644
--- a/arch/arm/boot/dts/pxa910-dkb.dts
+++ b/arch/arm/boot/dts/pxa910-dkb.dts
@@ -24,6 +24,17 @@
 
 	soc {
 		apb at d4000000 {
+			pll2: refclk1001mhz {
+				/* Reference clock for internal PLL2 */
+				compatible = "marvell,mmp-fixed-clkrate";
+				#clock-cells = <0>;
+				clocks = <&osc_26m>;
+				clock-frequency = <1001000000>;
+				clock-output-names = "refclk1001mhz";
+			};
+			timer0: timer at d4014000 {
+				status = "okay";
+			};
 			uart1: uart at d4017000 {
 				status = "okay";
 			};
diff --git a/arch/arm/boot/dts/pxa910.dtsi b/arch/arm/boot/dts/pxa910.dtsi
index 0247c62..cd888d3 100644
--- a/arch/arm/boot/dts/pxa910.dtsi
+++ b/arch/arm/boot/dts/pxa910.dtsi
@@ -8,6 +8,7 @@
  */
 
 /include/ "skeleton.dtsi"
+/include/ "pxa910-clk.dtsi"
 
 / {
 	aliases {
@@ -44,7 +45,6 @@
 				reg = <0xd4282000 0x1000>;
 				mrvl,intc-nr-irqs = <64>;
 			};
-
 		};
 
 		apb at d4000000 {	/* APB */
@@ -58,12 +58,15 @@
 				compatible = "mrvl,mmp-timer";
 				reg = <0xd4014000 0x100>;
 				interrupts = <13>;
+				clocks = <&apbc_timer0_clk>;
+				status = "disabled";
 			};
 
 			timer1: timer at d4016000 {
 				compatible = "mrvl,mmp-timer";
 				reg = <0xd4016000 0x100>;
 				interrupts = <29>;
+				clocks = <&apbc_timer1_clk>;
 				status = "disabled";
 			};
 
@@ -71,6 +74,7 @@
 				compatible = "mrvl,mmp-uart";
 				reg = <0xd4017000 0x1000>;
 				interrupts = <27>;
+				clocks = <&apbc_uart1_clk>;
 				status = "disabled";
 			};
 
@@ -78,6 +82,7 @@
 				compatible = "mrvl,mmp-uart";
 				reg = <0xd4018000 0x1000>;
 				interrupts = <28>;
+				clocks = <&apbc_uart2_clk>;
 				status = "disabled";
 			};
 
@@ -85,6 +90,7 @@
 				compatible = "mrvl,mmp-uart";
 				reg = <0xd4036000 0x1000>;
 				interrupts = <59>;
+				clocks = <&apbcp_uart3_clk>;
 				status = "disabled";
 			};
 
@@ -99,6 +105,7 @@
 				interrupt-names = "gpio_mux";
 				interrupt-controller;
 				#interrupt-cells = <1>;
+				clocks = <&apbc_gpio_clk>;
 				ranges;
 
 				gcb0: gpio at d4019000 {
@@ -124,6 +131,7 @@
 				#size-cells = <0>;
 				reg = <0xd4011000 0x1000>;
 				interrupts = <7>;
+				clocks = <&apbc_twsi1_clk>;
 				mrvl,i2c-fast-mode;
 				status = "disabled";
 			};
@@ -134,6 +142,7 @@
 				#size-cells = <0>;
 				reg = <0xd4037000 0x1000>;
 				interrupts = <54>;
+				clocks = <&apbcp_twsi2_clk>;
 				status = "disabled";
 			};
 
@@ -142,6 +151,7 @@
 				reg = <0xd4010000 0x1000>;
 				interrupts = <5 6>;
 				interrupt-names = "rtc 1Hz", "rtc alarm";
+				clocks = <&apbc_rtc_clk>;
 				status = "disabled";
 			};
 		};
diff --git a/arch/arm/mach-mmp/mmp-dt.c b/arch/arm/mach-mmp/mmp-dt.c
index cca529c..f109bf6 100644
--- a/arch/arm/mach-mmp/mmp-dt.c
+++ b/arch/arm/mach-mmp/mmp-dt.c
@@ -9,6 +9,7 @@
  *  publishhed by the Free Software Foundation.
  */
 
+#include <linux/clk-provider.h>
 #include <linux/irqchip.h>
 #include <linux/of_platform.h>
 #include <asm/mach/arch.h>
@@ -48,6 +49,7 @@ static void __init pxa168_dt_init(void)
 
 static void __init pxa910_dt_init(void)
 {
+	of_clk_init(NULL);
 	of_platform_populate(NULL, of_default_bus_match_table,
 			     pxa910_auxdata_lookup, NULL);
 }
diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile
index 392d780..83182e5 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-mmp.o
 
 obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
 obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o
diff --git a/drivers/clk/mmp/clk-mmp.c b/drivers/clk/mmp/clk-mmp.c
new file mode 100644
index 0000000..5137e6d
--- /dev/null
+++ b/drivers/clk/mmp/clk-mmp.c
@@ -0,0 +1,361 @@
+/*
+ * Marvell MMP clock driver
+ *
+ * Copyright (c) 2012 Linaro Limited.
+ *
+ * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+
+#include "clk.h"
+
+enum {
+	MMP_MPMU = 0,
+	MMP_APMU,
+	MMP_APBC,
+	MMP_APBCP,
+	MMP_APB,
+	MMP_MAX,
+};
+
+static void __iomem *mmp_clk_base[MMP_MAX];
+
+static DEFINE_SPINLOCK(mmp_clk_lock);
+
+static const struct of_device_id mmp_of_match[] = {
+	{ .compatible = "marvell,mmp-mpmu", .data = (void *)MMP_MPMU, },
+	{ .compatible = "marvell,mmp-apmu", .data = (void *)MMP_APMU, },
+	{ .compatible = "marvell,mmp-apbc", .data = (void *)MMP_APBC, },
+	{ .compatible = "marvell,mmp-apbcp", .data = (void *)MMP_APBCP, },
+	{ .compatible = "mrvl,apb-bus", .data = (void *)MMP_APB, },
+};
+
+void __iomem __init *mmp_init_clocks(struct device_node *np)
+{
+	struct device_node *parent;
+	const struct of_device_id *match;
+	void __iomem *ret = NULL;
+	int i;
+
+	parent = of_get_parent(np);
+	if (!parent)
+		goto out;
+	match = of_match_node(mmp_of_match, parent);
+	if (!match)
+		goto out;
+
+	i = (unsigned int)match->data;
+	switch (i) {
+	case MMP_MPMU:
+	case MMP_APMU:
+	case MMP_APBC:
+	case MMP_APBCP:
+	case MMP_APB:
+		if (!mmp_clk_base[i]) {
+			ret = of_iomap(parent, 0);
+			WARN_ON(!ret);
+			mmp_clk_base[i] = ret;
+		} else {
+			ret = mmp_clk_base[i];
+		}
+		break;
+	default:
+		goto out;
+	}
+out:
+	return ret;
+}
+
+static void __init mmp_fixed_rate_setup(struct device_node *np)
+{
+	struct clk *clk;
+	const char *clk_name, *parent_name;
+	int rate;
+
+	if (of_property_read_u32(np, "clock-frequency", &rate))
+		return;
+
+	if (of_property_read_string(np, "clock-output-names", &clk_name))
+		return;
+
+	/* this node has only one parent */
+	parent_name = of_clk_get_parent_name(np, 0);
+	if (!parent_name)
+		return;
+
+	clk = clk_register_fixed_rate(NULL, clk_name, parent_name, 0, rate);
+	if (IS_ERR(clk))
+		return;
+	of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+CLK_OF_DECLARE(mmp_fixed_rate, "marvell,mmp-fixed-clkrate",
+	       mmp_fixed_rate_setup);
+
+static void __init mmp_fixed_factor_setup(struct device_node *np)
+{
+	struct clk *clk;
+	const char *clk_name, *output_name, *parent_name;
+	u32 data[2];
+
+	if (of_property_read_u32_array(np, "marvell,mmp-fixed-factor",
+				&data[0], 2))
+		return;
+	if (of_property_read_string(np, "clock-output-names", &output_name))
+		return;
+
+	/* this node has only one parent */
+	parent_name = of_clk_get_parent_name(np, 0);
+	if (!parent_name)
+		return;
+
+	clk = clk_register_fixed_factor(NULL, output_name, parent_name, 0,
+			data[0], data[1]);
+	if (IS_ERR(clk))
+		return;
+	if (!of_property_read_string(np, "clock-names", &clk_name))
+		clk_register_clkdev(clk, clk_name, NULL);
+	of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+CLK_OF_DECLARE(mmp_fixed_factor, "marvell,mmp-fixed-clkfactor",
+	       mmp_fixed_factor_setup);
+
+static void __init mmp_apmu_div_setup(struct device_node *np)
+{
+	u32 data[2];
+	u8 shift, width;
+	void __iomem *reg, *base;
+	const char *parent_name, *clk_name;
+	struct clk *clk;
+
+	base = mmp_init_clocks(np);
+	if (!base)
+		return;
+
+	if (of_property_read_u32_array(np, "marvell,mmp-clk-reg", &data[0], 2))
+		return;
+	reg = base + data[0];
+	shift = ffs(data[1]) - 1;
+	width = fls(data[1]) - ffs(data[1]) + 1;
+
+	parent_name = of_clk_get_parent_name(np, 0);
+	if (!parent_name)
+		return;
+	if (of_property_read_string(np, "clock-output-names", &clk_name))
+		return;
+
+	clk = clk_register_divider(NULL, clk_name, parent_name,
+			CLK_SET_RATE_PARENT, reg, shift, width, 0,
+			&mmp_clk_lock);
+	if (IS_ERR(clk))
+		return;
+	of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	return;
+}
+CLK_OF_DECLARE(mmp_div, "mmp-apmu-clkdiv", mmp_apmu_div_setup);
+
+static int __init mmp_parse_mux(struct device_node *np,
+				u8 *num_parents,
+				u32 *clk_sel)
+{
+	int i, cnt, ret;
+
+	/* get the count of items in mux */
+	for (i = 0, cnt = 0; ; i++, cnt++) {
+		/* parent's #clock-cells property is always 0 */
+		if (!of_parse_phandle(np, "clocks", i))
+			break;
+	}
+
+	for (i = 0; i < cnt; i++) {
+		if (!of_clk_get_parent_name(np, i))
+			break;
+	}
+	*num_parents = cnt;
+	clk_sel = kzalloc(sizeof(u32 *) * cnt, GFP_KERNEL);
+	if (!clk_sel)
+		return -ENOMEM;
+	ret = of_property_read_u32_array(np, "marvell,mmp-clk-sel", clk_sel, cnt);
+	if (ret)
+		goto err;
+	return 0;
+err:
+	kfree(clk_sel);
+	return ret;
+}
+
+static void __init mmp_mux_setup(struct device_node *np)
+{
+	u32 data[2], mask, *clk_sel = NULL, mux_flags = 0;
+	u8 shift, num_parents;
+	void __iomem *reg, *base;
+	const char **parent_names;
+	const char *clk_name;
+	struct clk *clk;
+	int i, ret;
+
+	base = mmp_init_clocks(np);
+	if (!base)
+		return;
+	if (of_property_read_string(np, "clock-output-names", &clk_name))
+		return;
+	if (of_property_read_u32_array(np, "marvell,mmp-clk-reg", &data[0], 2))
+		return;
+	ret = mmp_parse_mux(np, &num_parents, clk_sel);
+	if (ret)
+		return;
+
+	reg = base + data[0];
+	shift = ffs(data[1]) - 1;
+	mask = data[1] >> shift;
+
+	parent_names = kzalloc(sizeof(char *) * num_parents, GFP_KERNEL);
+	if (!parent_names)
+		goto err;
+	for (i = 0; i < num_parents; i++)
+		parent_names[i] = of_clk_get_parent_name(np, i);
+	clk = clk_register_mux_table(NULL, clk_name, parent_names, num_parents,
+				     CLK_SET_RATE_PARENT, reg, shift, mask,
+				     mux_flags, clk_sel, &mmp_clk_lock);
+	if (IS_ERR(clk))
+		goto err_clk;
+	of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	return;
+err_clk:
+	kfree(parent_names);
+err:
+	kfree(clk_sel);
+}
+CLK_OF_DECLARE(mmp_mux, "marvell,mmp-clkmux", mmp_mux_setup);
+
+#define APBC_NO_BUS_CTRL	BIT(0)
+#define APBC_POWER_CTRL		BIT(1)
+
+static void __init mmp_apbc_setup(struct device_node *np)
+{
+	u32 data[2], delay, apbc_flags, clkdev;
+	void __iomem *reg, *base;
+	const char **parent_names;
+	const char *clk_name = NULL;
+	struct clk *clk;
+
+	base = mmp_init_clocks(np);
+	if (!base)
+		return;
+
+	if (of_property_read_string(np, "clock-names", &clk_name))
+		clkdev = 1;
+	else {
+		of_property_read_string(np, "clock-output-names", &clk_name);
+		clkdev = 0;
+	}
+
+	if (of_property_read_u32_array(np, "marvell,mmp-clk-reg", &data[0], 2))
+		return;
+	/* If marvell,mmp-clk-delay property isn't defined, set delay as 10us */
+	if (of_property_read_u32(np, "marvell,mmp-clk-delay", &delay))
+		delay = 10;
+	if (of_get_property(np, "marvell,mmp-apbc-power-ctl", NULL))
+		apbc_flags |= APBC_POWER_CTRL;
+
+	reg = base + data[0];
+
+	/* only has the fixed parent */
+	parent_names = kzalloc(sizeof(char *), GFP_KERNEL);
+	if (!parent_names)
+		return;
+	parent_names[0] = of_clk_get_parent_name(np, 0);
+
+	clk = mmp_clk_register_apbc(clk_name, parent_names[0],
+				    reg, delay, 0, &mmp_clk_lock);
+	if (IS_ERR(clk)) {
+		kfree(parent_names);
+		return;
+	}
+	if (clkdev)
+		clk_register_clkdev(clk, clk_name, NULL);
+	of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+CLK_OF_DECLARE(mmp_apbc, "marvell,mmp-apbc-clk", mmp_apbc_setup);
+
+static void __init mmp_apbcp_setup(struct device_node *np)
+{
+	int i, cnt;
+	u32 *clk_sel, data[2];
+	u8 num_parents, shift, width;
+	void __iomem *reg, *base;
+	const char **parent_names, *clk_name;
+	struct clk *clk;
+
+	base = mmp_init_clocks(np);
+	if (!base)
+		return;
+
+	if (of_property_read_string(np, "clock-output-names", &clk_name))
+		return;
+	/* get the count of items in mux */
+	for (i = 0, cnt = 0; ; i++, cnt++) {
+		/* parent's #clock-cells property is always 0 */
+		if (!of_parse_phandle(np, "clocks", i))
+			break;
+	}
+
+	for (i = 0; ; i++) {
+		if (!of_clk_get_parent_name(np, i))
+			break;
+	}
+	num_parents = i;
+	if (!num_parents)
+		return;
+
+	if (of_property_read_u32_array(np, "marvell,mmp-clk-reg", &data[0], 2))
+		return;
+	reg = base + data[0];
+	shift = ffs(data[1]) - 1;
+	width = fls(data[1]) - ffs(data[1]) + 1;
+
+	clk_sel = kzalloc(sizeof(u32 *) * num_parents, GFP_KERNEL);
+	if (!clk_sel)
+		return;
+	if (of_property_read_u32_array(np, "marvell,mmp-clk-sel", clk_sel, cnt))
+		goto err_sel;
+	parent_names = kzalloc(sizeof(char *) * num_parents, GFP_KERNEL);
+	if (!parent_names)
+		goto err_sel;
+
+	for (i = 0; i < num_parents; i++)
+		parent_names[i] = of_clk_get_parent_name(np, i);
+	clk = clk_register_mux(NULL, clk_name, parent_names, num_parents, 0,
+				reg, shift, width, 0, &mmp_clk_lock);
+	if (IS_ERR(clk))
+		goto err_mux;
+	of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	return;
+err_mux:
+	kfree(parent_names);
+err_sel:
+	kfree(clk_sel);
+}
+CLK_OF_DECLARE(mmp_apbcp, "mmp-apbcp-clk", mmp_apbcp_setup);
-- 
1.8.1.2

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v4 09/10] clk: mmp: parse clock from dts
  2013-06-04  4:12 ` [PATCH v4 09/10] clk: mmp: parse clock from dts Haojian Zhuang
@ 2013-06-11 20:20   ` Mike Turquette
  0 siblings, 0 replies; 13+ messages in thread
From: Mike Turquette @ 2013-06-11 20:20 UTC (permalink / raw)
  To: linux-arm-kernel

Quoting Haojian Zhuang (2013-06-03 21:12:51)
> Parse clock information from DTS file for mach-mmp.
> 
> Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
> ---
>  arch/arm/boot/dts/pxa168-aspenite.dts |   3 +
>  arch/arm/boot/dts/pxa168-clk.dtsi     | 304 ++++++++++++++++++
>  arch/arm/boot/dts/pxa168.dtsi         |  10 +
>  arch/arm/boot/dts/pxa910-clk.dtsi     | 569 ++++++++++++++++++++++++++++++++++
>  arch/arm/boot/dts/pxa910-dkb.dts      |  11 +
>  arch/arm/boot/dts/pxa910.dtsi         |  12 +-
>  arch/arm/mach-mmp/mmp-dt.c            |   2 +
>  drivers/clk/mmp/Makefile              |   2 +-
>  drivers/clk/mmp/clk-mmp.c             | 363 ++++++++++++++++++++++

Patch looks mostly good to me.  I prefer to break out the DTS changes
from the clock driver changes into separate patches.

Also I believe that binding definitions are missing from
Documentation/devicetree/bindings/clocks.

Regards,
Mike

>  9 files changed, 1274 insertions(+), 2 deletions(-)
>  create mode 100644 arch/arm/boot/dts/pxa168-clk.dtsi
>  create mode 100644 arch/arm/boot/dts/pxa910-clk.dtsi
>  create mode 100644 drivers/clk/mmp/clk-mmp.c
> 
> diff --git a/arch/arm/boot/dts/pxa168-aspenite.dts b/arch/arm/boot/dts/pxa168-aspenite.dts
> index e762fac..2597e98 100644
> --- a/arch/arm/boot/dts/pxa168-aspenite.dts
> +++ b/arch/arm/boot/dts/pxa168-aspenite.dts
> @@ -24,6 +24,9 @@
>  
>         soc {
>                 apb at d4000000 {
> +                       timer0: timer at d4014000 {
> +                               status = "okay";
> +                       };
>                         uart1: uart at d4017000 {
>                                 status = "okay";
>                         };
> diff --git a/arch/arm/boot/dts/pxa168-clk.dtsi b/arch/arm/boot/dts/pxa168-clk.dtsi
> new file mode 100644
> index 0000000..f9c298df
> --- /dev/null
> +++ b/arch/arm/boot/dts/pxa168-clk.dtsi
> @@ -0,0 +1,304 @@
> +/*
> + *  Copyright (C) 2013
> + *  Author: Haojian Zhuang <haojian.zhuang@gmail.com>
> + *
> + *  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/ "skeleton.dtsi"
> +
> +/ {
> +       soc {
> +               apb at d4000000 {  /* APB */
> +                       compatible = "mrvl,apb-bus", "simple-bus";
> +                       #address-cells = <1>;
> +                       #size-cells = <1>;
> +                       reg = <0xd4000000 0x00200000>;
> +                       ranges;
> +
> +                       mpmu: clocks at 50000 {
> +                               compatible = "marvell,mmp-mpmu";
> +                               #address-cells = <1>;
> +                               #size-cells = <1>;
> +                               reg = <0xd4050000 0x1100>;
> +
> +                               osc_32k: osc32khz {
> +                                       compatible = "fixed-clock";
> +                                       #clock-cells = <0>;
> +                                       clock-frequency = <32768>;
> +                                       clock-output-names = "osc32khz";
> +                               };
> +                               osc_26m: osc26mhz {
> +                                       compatible = "fixed-clock";
> +                                       #clock-cells = <0>;
> +                                       clock-frequency = <26000000>;
> +                                       clock-output-names = "osc26mhz";
> +                               };
> +                               pll1_312m: refclk312mhz {
> +                                       compatible = "marvell,mmp-fixed-clkrate";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&osc_26m>;
> +                                       clock-frequency = <312000000>;
> +                                       clock-output-names = "refclk312mhz";
> +                               };
> +                               refclk156m: refclk156mhz {
> +                                       compatible = "marvell,mmp-fixed-clkfactor";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&pll1_312m>;
> +                                       clock-output-names = "refclk156mhz";
> +                                       /* multiple & divider */
> +                                       marvell,mmp-fixed-factor = <1 2>;
> +                               };
> +                               refclk118m: refclk117mhz {
> +                                       compatible = "marvell,mmp-fixed-clkfactor";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk156m>;
> +                                       /* 117.9648MHz */
> +                                       clock-output-names = "refclk118mhz";
> +                                       /* multiple & divider */
> +                                       marvell,mmp-fixed-factor = <6144 8125>;
> +                               };
> +                               refclk104m: refclk104mhz {
> +                                       compatible = "marvell,mmp-fixed-clkfactor";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&pll1_312m>;
> +                                       clock-output-names = "refclk104mhz";
> +                                       /* multiple & divider */
> +                                       marvell,mmp-fixed-factor = <1 3>;
> +                               };
> +                               refclk59m: refclk59mhz {
> +                                       compatible = "marvell,mmp-fixed-clkfactor";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk118m>;
> +                                       clock-names = "baud_58.98mhz";
> +                                       /* 58.9824MHz */
> +                                       clock-output-names = "refclk59mhz";
> +                                       /* multiple & divider */
> +                                       marvell,mmp-fixed-factor = <1 2>;
> +                               };
> +                               refclk15m: refclk15mhz {
> +                                       compatible = "marvell,mmp-fixed-clkfactor";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk156m>;
> +                                       clock-names = "baud_14.86mhz";
> +                                       /* 14.857MHz */
> +                                       clock-output-names = "refclk15mhz";
> +                                       /* multiple & divider */
> +                                       marvell,mmp-fixed-factor = <2 21>;
> +                               };
> +                       };
> +
> +                       apbc: clocks at 15000 {
> +                               compatible = "marvell,mmp-apbc";
> +                               #address-cells = <1>;
> +                               #size-cells = <1>;
> +                               #clock-cells = <0>;
> +                               reg = <0xd4015000 0x100>;
> +
> +                               apbc_twsi1_clk: apbc_twsi1_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk32m>;
> +                                       clock-names = "apbc_twsi1_clk";
> +                                       /* register value of each item */
> +                                       marvell,mmp-clk-sel = <0>;
> +                                       /* register offset & mask */
> +                                       marvell,mmp-clk-reg = <0x2c 0x70>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_twsi2_clk: apbc_twsi2_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk32m>;
> +                                       clock-names = "apbc_twsi2_clk";
> +                                       /* register value of each item */
> +                                       marvell,mmp-clk-sel = <0>;
> +                                       /* register offset & mask */
> +                                       marvell,mmp-clk-reg = <0x6c 0x70>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_rtc_clk: apbc_rtc_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&osc_32k>;
> +                                       clock-names = "apbc_rtc_clk";
> +                                       marvell,mmp-clk-sel = <0>;
> +                                       /* register offset & mask */
> +                                       marvell,mmp-clk-reg = <0x28 0x70>;
> +                                       marvell,mmp-apbc-power-ctl;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_gpio_clk: apbc_gpio_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk26m>;
> +                                       clock-names = "apbc_gpio_clk";
> +                                       marvell,mmp-clk-sel = <0>;
> +                                       /* register offset & mask */
> +                                       marvell,mmp-clk-reg = <0x8 0x0>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_uart1_mux: apbc_uart1_mux {
> +                                       compatible = "marvell,mmp-clkmux";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk59m &refclk15m>;
> +                                       clock-output-names = "apbc_uart1_mux";
> +                                       /* register offset & mask */
> +                                       marvell,mmp-clk-reg = <0x0 0x70>;
> +                                       /* register value of each item */
> +                                       marvell,mmp-clk-sel = <0 0x10>;
> +                               };
> +                               apbc_uart1_clk: apbc_uart1_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&apbc_uart1_mux>;
> +                                       clock-names = "apbc_uart1_clk";
> +                                       marvell,mmp-clk-reg = <0x0 0x70>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_uart2_mux: apbc_uart2_mux {
> +                                       compatible = "marvell,mmp-clkmux";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk59m &refclk15m>;
> +                                       clock-output-names = "apbc_uart2_mux";
> +                                       /* register offset & mask */
> +                                       marvell,mmp-clk-reg = <0x4 0x70>;
> +                                       /* register value of each item */
> +                                       marvell,mmp-clk-sel = <0 0x10>;
> +                               };
> +                               apbc_uart2_clk: apbc_uart2_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&apbc_uart2_mux>;
> +                                       clock-names = "apbc_uart2_clk";
> +                                       marvell,mmp-clk-reg = <0x4 0x70>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_uart3_mux: apbc_uart3_mux {
> +                                       compatible = "marvell,mmp-clkmux";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk59m &refclk15m>;
> +                                       clock-output-names = "apbc_uart3_mux";
> +                                       /* register offset & mask */
> +                                       marvell,mmp-clk-reg = <0x70 0x70>;
> +                                       /* register value of each item */
> +                                       marvell,mmp-clk-sel = <0 0x10>;
> +                               };
> +                               apbc_uart3_clk: apbc_uart3_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&apbc_uart3_mux>;
> +                                       clock-names = "apbc_uart3_clk";
> +                                       marvell,mmp-clk-reg = <0x70 0x70>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_pwm1_mux: apbc_pwm1_mux {
> +                                       compatible = "marvell,mmp-clkmux";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk13m &osc_32k>;
> +                                       clock-output-names = "apbc_pwm1_mux";
> +                                       marvell,mmp-clk-sel = <0 0x10>;
> +                                       marvell,mmp-clk-reg = <0xc 0x70>;
> +                               };
> +                               apbc_pwm1_clk: apbc_pwm1_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&apbc_pwm1_mux>;
> +                                       clock-names = "apbc_pwm1_clk";
> +                                       marvell,mmp-clk-reg = <0xc 0x70>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_pwm2_mux: apbc_pwm2_mux {
> +                                       compatible = "marvell,mmp-clkmux";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk13m &osc_32k>;
> +                                       clock-output-names = "apbc_pwm2_mux";
> +                                       marvell,mmp-clk-sel = <0 0x10>;
> +                                       marvell,mmp-clk-reg = <0x10 0x70>;
> +                               };
> +                               apbc_pwm2_clk: apbc_pwm2_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&apbc_pwm2_mux>;
> +                                       clock-names = "apbc_pwm2_clk";
> +                                       marvell,mmp-clk-reg = <0x10 0x70>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_pwm3_mux: apbc_pwm3_mux {
> +                                       compatible = "marvell,mmp-clkmux";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk13m &osc_32k>;
> +                                       clock-output-names = "apbc_pwm3_mux";
> +                                       marvell,mmp-clk-sel = <0 0x10>;
> +                                       marvell,mmp-clk-reg = <0x14 0x70>;
> +                               };
> +                               apbc_pwm3_clk: apbc_pwm3_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&apbc_pwm3_mux>;
> +                                       clock-names = "apbc_pwm3_clk";
> +                                       marvell,mmp-clk-reg = <0x14 0x70>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_pwm4_mux: apbc_pwm4_mux {
> +                                       compatible = "marvell,mmp-clkmux";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk13m &osc_32k>;
> +                                       clock-output-names = "apbc_pwm4_mux";
> +                                       marvell,mmp-clk-sel = <0 0x10>;
> +                                       marvell,mmp-clk-reg = <0x18 0x70>;
> +                               };
> +                               apbc_pwm4_clk: apbc_pwm4_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&apbc_pwm4_mux>;
> +                                       clock-names = "apbc_pwm4_clk";
> +                                       marvell,mmp-clk-reg = <0x18 0x70>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_kpc_mux: apbc_kpc_mux {
> +                                       compatible = "marvell,mmp-clkmux";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&osc_32k &refclk16k &refclk26m>;
> +                                       clock-output-names = "apbc_kpc_mux";
> +                                       marvell,mmp-clk-sel = <0 0x10 0x20>;
> +                                       marvell,mmp-clk-reg = <0x30 0x70>;
> +                               };
> +                               apbc_kpc_clk: apbc_kpc_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&apbc_kpc_mux>;
> +                                       clock-names = "apbc_kpc_clk";
> +                                       marvell,mmp-clk-reg = <0x30 0x70>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_timer0_mux: apbc_timer0_mux {
> +                                       compatible = "marvell,mmp-clkmux";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk13m &osc_32k &refclk7m &refclk3m>;
> +                                       clock-output-names = "apbc_timer0_mux";
> +                                       marvell,mmp-clk-sel = <0 0x10 0x20 0x30>;
> +                                       marvell,mmp-clk-reg = <0x34 0x70>;
> +                               };
> +                               apbc_timer0_clk: apbc_timer0_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&timer0_mux>;
> +                                       clock-names = "apbc_timer0_clk";
> +                                       marvell,mmp-clk-reg = <0x34 0x70>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                       };
> +                       timer0_mux: timer0_mux {
> +                               compatible = "marvell,mmp-clkmux";
> +                               #clock-cells = <0>;
> +                               clocks = <&apbc_timer0_mux &osc_32k>;
> +                               clock-output-names = "timer0_mux";
> +                               marvell,mmp-clk-sel = <0 0x2>;
> +                               marvell,mmp-clk-reg = <0x14000 0x1c>;
> +                       };
> +               };
> +       };
> +};
> diff --git a/arch/arm/boot/dts/pxa168.dtsi b/arch/arm/boot/dts/pxa168.dtsi
> index 975dad2..250bf2c 100644
> --- a/arch/arm/boot/dts/pxa168.dtsi
> +++ b/arch/arm/boot/dts/pxa168.dtsi
> @@ -8,6 +8,7 @@
>   */
>  
>  /include/ "skeleton.dtsi"
> +/include/ "pxa910-clk.dtsi"
>  
>  / {
>         aliases {
> @@ -53,12 +54,15 @@
>                                 compatible = "mrvl,mmp-timer";
>                                 reg = <0xd4014000 0x100>;
>                                 interrupts = <13>;
> +                               clocks = <&apbc_timer0_clk>;
> +                               status = "disabled";
>                         };
>  
>                         uart1: uart at d4017000 {
>                                 compatible = "mrvl,mmp-uart";
>                                 reg = <0xd4017000 0x1000>;
>                                 interrupts = <27>;
> +                               clocks = <&apbc_uart1_clk>;
>                                 status = "disabled";
>                         };
>  
> @@ -66,6 +70,7 @@
>                                 compatible = "mrvl,mmp-uart";
>                                 reg = <0xd4018000 0x1000>;
>                                 interrupts = <28>;
> +                               clocks = <&apbc_uart2_clk>;
>                                 status = "disabled";
>                         };
>  
> @@ -73,6 +78,7 @@
>                                 compatible = "mrvl,mmp-uart";
>                                 reg = <0xd4026000 0x1000>;
>                                 interrupts = <29>;
> +                               clocks = <&apbc_uart3_clk>;
>                                 status = "disabled";
>                         };
>  
> @@ -87,6 +93,7 @@
>                                 interrupt-names = "gpio_mux";
>                                 interrupt-controller;
>                                 #interrupt-cells = <1>;
> +                               clocks = <&apbc_gpio_clk>;
>                                 ranges;
>  
>                                 gcb0: gpio at d4019000 {
> @@ -111,6 +118,7 @@
>                                 reg = <0xd4011000 0x1000>;
>                                 interrupts = <7>;
>                                 mrvl,i2c-fast-mode;
> +                               clocks = <&apbc_twsi1_clk>;
>                                 status = "disabled";
>                         };
>  
> @@ -118,6 +126,7 @@
>                                 compatible = "mrvl,mmp-twsi";
>                                 reg = <0xd4025000 0x1000>;
>                                 interrupts = <58>;
> +                               clocks = <&apbc_twsi2_clk>;
>                                 status = "disabled";
>                         };
>  
> @@ -126,6 +135,7 @@
>                                 reg = <0xd4010000 0x1000>;
>                                 interrupts = <5 6>;
>                                 interrupt-names = "rtc 1Hz", "rtc alarm";
> +                               clocks = <&apbc_rtc_clk>;
>                                 status = "disabled";
>                         };
>                 };
> diff --git a/arch/arm/boot/dts/pxa910-clk.dtsi b/arch/arm/boot/dts/pxa910-clk.dtsi
> new file mode 100644
> index 0000000..035697f
> --- /dev/null
> +++ b/arch/arm/boot/dts/pxa910-clk.dtsi
> @@ -0,0 +1,569 @@
> +/*
> + *  Copyright (C) 2013
> + *  Author: Haojian Zhuang <haojian.zhuang@gmail.com>
> + *
> + *  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/ "skeleton.dtsi"
> +
> +/ {
> +       soc {
> +               axi at d4200000 {  /* AXI */
> +                       compatible = "mrvl,axi-bus", "simple-bus";
> +                       reg = <0xd4200000 0x00200000>;
> +                       ranges;
> +
> +                       apmu: clocks at 82800 {
> +                               compatible = "marvell,mmp-apmu";
> +                               reg = <0xd4282800 0x100>;
> +
> +                               /*
> +                                * Processor clocks: pclk, pdclk, baclk, xpclk
> +                                * DDR Controller clocks: dclk
> +                                * AXI Fabric clocks: aclk
> +                                */
> +                               pclk_refclk: refclk_pclk {
> +                                       compatible = "marvell,mmp-apmu-clkdiv";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&pj1_refclk>;
> +                                       clock-output-names = "pclk";
> +                                       marvell,mmp-clock-frequency = <104000000 156000000 208000000 312000000 500500000 624000000 806000000 1001000000>;
> +                                       /* register offset & mask */
> +                                       marvell,mmp-clk-reg = <0x4 0x7>;
> +                               };
> +                               /* pdclk -- DDR Interface clock */
> +                               pdclk_refclk: refclk_pdclk {
> +                                       compatible = "marvell,mmp-apmu-clkdiv";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&pj1_refclk>;
> +                                       clock-output-names = "pdclk";
> +                                       marvell,mmp-clock-frequency = <78000000 104000000 156000000 201000000 250250000>;
> +                                       /* register offset & mask */
> +                                       marvell,mmp-clk-reg = <0x4 0x38>;
> +                               };
> +                               /* baclk -- AXI Fabric Bus Interface clock */
> +                               baclk_refclk: refclk_baclk {
> +                                       compatible = "marvell,mmp-apmu-clkdiv";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&pj1_refclk>;
> +                                       clock-output-names = "baclk";
> +                                       marvell,mmp-clock-frequency = <78000000 104000000 156000000 201000000 250250000>;
> +                                       /* register offset & mask */
> +                                       marvell,mmp-clk-reg = <0x4 0x1c0>;
> +                               };
> +                               /* xpclk -- L2 interface clock */
> +                               xpclk_refclk: refclk_xpclk {
> +                                       compatible = "marvell,mmp-apmu-clkdiv";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&pj1_refclk>;
> +                                       clock-output-names = "xpclk";
> +                                       marvell,mmp-clock-frequency = <104000000 156000000 250250000 312000000 403000000 500500000>;
> +                                       /* register offset & mask */
> +                                       marvell,mmp-clk-reg = <0x4 0xe00>;
> +                               };
> +                               /* dclk -- DDR Controller clock */
> +                               dclk2x_refclk: refclk_dclk2x {
> +                                       compatible = "marvell,mmp-apmu-clkdiv";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&ddr_refclk>;
> +                                       clock-output-names = "dclk2x";
> +                                       marvell,mmp-clock-frequency = <208000000 312000000 402000000 500500000>;
> +                                       /* register offset & mask */
> +                                       marvell,mmp-clk-reg = <0x4 0x7000>;
> +                               };
> +                               dclk_refclk: refclk_dclk {
> +                                       compatible = "marvell,mmp-fixed-clkfactor";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&dclk2x_refclk>;
> +                                       clock-output-names = "dclk";
> +                                       /* multiple & divider */
> +                                       marvell,mmp-fixed-factor = <1 2>;
> +                               };
> +                               /* aclk -- AXI Fabric clock */
> +                               aclk_refclk: refclk_aclk {
> +                                       compatible = "marvell,mmp-apmu-clkdiv";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&axi_refclk>;
> +                                       clock-output-names = "aclk";
> +                                       marvell,mmp-clock-frequency = <104000000 156000000>;
> +                                       /* register offset & mask */
> +                                       marvell,mmp-clk-reg = <0x4 0x38000>;
> +                               };
> +                       };
> +               };
> +
> +               apb at d4000000 {  /* APB */
> +                       compatible = "mrvl,apb-bus", "simple-bus";
> +                       #address-cells = <1>;
> +                       #size-cells = <1>;
> +                       reg = <0xd4000000 0x00200000>;
> +                       ranges;
> +
> +                       mpmu: clocks at 50000 {
> +                               compatible = "marvell,mmp-mpmu";
> +                               #address-cells = <1>;
> +                               #size-cells = <1>;
> +                               reg = <0xd4050000 0x1100>;
> +
> +                               osc_32k: osc32khz {
> +                                       compatible = "fixed-clock";
> +                                       #clock-cells = <0>;
> +                                       clock-frequency = <32768>;
> +                                       clock-output-names = "osc32khz";
> +                               };
> +                               osc_26m: osc26mhz {
> +                                       compatible = "fixed-clock";
> +                                       #clock-cells = <0>;
> +                                       clock-frequency = <26000000>;
> +                                       clock-output-names = "osc26mhz";
> +                               };
> +                               pll1_312m: refclk312mhz {
> +                                       compatible = "marvell,mmp-fixed-clkrate";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&osc_26m>;
> +                                       clock-frequency = <312000000>;
> +                                       clock-output-names = "refclk312mhz";
> +                               };
> +                               pll1_624m: refclk624mhz {
> +                                       compatible = "marvell,mmp-fixed-clkrate";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&osc_26m>;
> +                                       clock-frequency = <624000000>;
> +                                       clock-output-names = "refclk624mhz";
> +                               };
> +                               pj1_refclk: refclk_pj1 {
> +                                       compatible = "marvell,mmp-clkmux";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&pll1_312m &pll1_624m &pll2>;
> +                                       clock-output-names = "refclk_pj1";
> +                                       /* register value of each item */
> +                                       marvell,mmp-clk-sel = <0 0x20000000 0x40000000>;
> +                                       /* register offset & mask */
> +                                       marvell,mmp-clk-reg = <0x8 0xe0000000>;
> +                               };
> +                               ddr_refclk: refclk_ddr {
> +                                       compatible = "marvell,mmp-clkmux";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&pll1_312m &pll1_624m &pll2>;
> +                                       clock-output-names = "refclk_ddr";
> +                                       /* register value of each item */
> +                                       marvell,mmp-clk-sel = <0 0x00800000 0x01000000>;
> +                                       /* register offset & mask */
> +                                       marvell,mmp-clk-reg = <0x8 0x01800000>;
> +                               };
> +                               axi_refclk: refclk_axi {
> +                                       compatible = "marvell,mmp-clkmux";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&pll1_312m &pll1_624m>;
> +                                       clock-output-names = "refclk_axi";
> +                                       /* register value of each item */
> +                                       marvell,mmp-clk-sel = <0 0x00080000>;
> +                                       /* register offset & mask */
> +                                       marvell,mmp-clk-reg = <0x8 0x00080000>;
> +                               };
> +                               refclk156m: refclk156mhz {
> +                                       compatible = "marvell,mmp-fixed-clkfactor";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&pll1_312m>;
> +                                       clock-output-names = "refclk156mhz";
> +                                       /* multiple & divider */
> +                                       marvell,mmp-fixed-factor = <1 2>;
> +                               };
> +                               refclk118m: refclk117mhz {
> +                                       compatible = "marvell,mmp-fixed-clkfactor";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk156m>;
> +                                       /* 117.9648MHz */
> +                                       clock-output-names = "refclk118mhz";
> +                                       /* multiple & divider */
> +                                       marvell,mmp-fixed-factor = <6144 8125>;
> +                               };
> +                               refclk104m: refclk104mhz {
> +                                       compatible = "marvell,mmp-fixed-clkfactor";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&pll1_312m>;
> +                                       clock-output-names = "refclk104mhz";
> +                                       /* multiple & divider */
> +                                       marvell,mmp-fixed-factor = <1 3>;
> +                               };
> +                               refclk59m: refclk59mhz {
> +                                       compatible = "marvell,mmp-fixed-clkfactor";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk118m>;
> +                                       clock-names = "baud_58.98mhz";
> +                                       /* 58.9824MHz */
> +                                       clock-output-names = "refclk59mhz";
> +                                       /* multiple & divider */
> +                                       marvell,mmp-fixed-factor = <1 2>;
> +                               };
> +                               refclk52m: refclk52mhz {
> +                                       compatible = "marvell,mmp-fixed-clkfactor";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk104m>;
> +                                       clock-output-names = "refclk52mhz";
> +                                       /* multiple & divider */
> +                                       marvell,mmp-fixed-factor = <1 2>;
> +                               };
> +                               refclk48m: refclk48mhz {
> +                                       compatible = "marvell,mmp-fixed-clkfactor";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&pll1_624m>;
> +                                       clock-output-names = "refclk48mhz";
> +                                       /* multiple & divider */
> +                                       marvell,mmp-fixed-factor = <1 13>;
> +                               };
> +                               refclk32m: refclk32mhz@ {
> +                                       compatible = "marvell,mmp-fixed-clkfactor";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk48m>;
> +                                       clock-output-names = "refclk32mhz";
> +                                       /* multiple & divider */
> +                                       marvell,mmp-fixed-factor = <2 3>;
> +                               };
> +                               refclk26m: refclk26mhz {
> +                                       compatible = "marvell,mmp-fixed-clkfactor";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk52m>;
> +                                       clock-output-names = "refclk26mhz";
> +                                       /* multiple & divider */
> +                                       marvell,mmp-fixed-factor = <1 2>;
> +                               };
> +                               refclk15m: refclk15mhz {
> +                                       compatible = "marvell,mmp-fixed-clkfactor";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk156m>;
> +                                       clock-names = "baud_14.86mhz";
> +                                       /* 14.857MHz */
> +                                       clock-output-names = "refclk15mhz";
> +                                       /* multiple & divider */
> +                                       marvell,mmp-fixed-factor = <2 21>;
> +                               };
> +                               refclk13m: refclk13mhz {
> +                                       compatible = "marvell,mmp-fixed-clkfactor";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk26m>;
> +                                       clock-output-names = "refclk13mhz";
> +                                       /* multiple & divider */
> +                                       marvell,mmp-fixed-factor = <1 2>;
> +                               };
> +                               refclk7m: refclk7mhz {
> +                                       compatible = "marvell,mmp-fixed-clkfactor";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk13m>;
> +                                       clock-output-names = "refclk7mhz";
> +                                       /* multiple & divider */
> +                                       marvell,mmp-fixed-factor = <1 2>;
> +                               };
> +                               refclk3m: refclk3mhz {
> +                                       compatible = "marvell,mmp-fixed-clkfactor";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk7m>;
> +                                       clock-output-names = "refclk3mhz";
> +                                       /* multiple & divider */
> +                                       marvell,mmp-fixed-factor = <1 2>;
> +                               };
> +                               refclk16k: refclk16khz {
> +                                       compatible = "marvell,mmp-fixed-clkfactor";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&osc_32k>;
> +                                       clock-output-names = "refclk16khz";
> +                                       /* multiple & divider */
> +                                       marvell,mmp-fixed-factor = <1 2>;
> +                               };
> +                       };
> +
> +                       apbc: clocks at 15000 {
> +                               compatible = "marvell,mmp-apbc";
> +                               #address-cells = <1>;
> +                               #size-cells = <1>;
> +                               #clock-cells = <0>;
> +                               reg = <0xd4015000 0x100>;
> +
> +                               apbc_twsi1_clk: apbc_twsi1_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk32m>;
> +                                       clock-names = "apbc_twsi1_clk";
> +                                       /* register value of each item */
> +                                       marvell,mmp-clk-sel = <0>;
> +                                       /* register offset & mask */
> +                                       marvell,mmp-clk-reg = <0x2c 0x70>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_rtc_clk: apbc_rtc_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&osc_32k>;
> +                                       clock-names = "apbc_rtc_clk";
> +                                       marvell,mmp-clk-sel = <0>;
> +                                       /* register offset & mask */
> +                                       marvell,mmp-clk-reg = <0x28 0x70>;
> +                                       marvell,mmp-apbc-power-ctl;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_gpio_clk: apbc_gpio_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk26m>;
> +                                       clock-names = "apbc_gpio_clk";
> +                                       marvell,mmp-clk-sel = <0>;
> +                                       /* register offset & mask */
> +                                       marvell,mmp-clk-reg = <0x8 0x0>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_uart1_mux: apbc_uart1_mux {
> +                                       compatible = "marvell,mmp-clkmux";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk59m &refclk15m>;
> +                                       clock-output-names = "apbc_uart1_mux";
> +                                       /* register offset & mask */
> +                                       marvell,mmp-clk-reg = <0x0 0x70>;
> +                                       /* register value of each item */
> +                                       marvell,mmp-clk-sel = <0 0x10>;
> +                               };
> +                               apbc_uart1_clk: apbc_uart1_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&apbc_uart1_mux>;
> +                                       clock-names = "apbc_uart1_clk";
> +                                       marvell,mmp-clk-reg = <0x0 0x70>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_uart2_mux: apbc_uart2_mux {
> +                                       compatible = "marvell,mmp-clkmux";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk59m &refclk15m>;
> +                                       clock-output-names = "apbc_uart2_mux";
> +                                       /* register offset & mask */
> +                                       marvell,mmp-clk-reg = <0x4 0x70>;
> +                                       /* register value of each item */
> +                                       marvell,mmp-clk-sel = <0 0x10>;
> +                               };
> +                               apbc_uart2_clk: apbc_uart2_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&apbc_uart2_mux>;
> +                                       clock-names = "apbc_uart2_clk";
> +                                       marvell,mmp-clk-reg = <0x4 0x70>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_pwm1_mux: apbc_pwm1_mux {
> +                                       compatible = "marvell,mmp-clkmux";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk13m &osc_32k>;
> +                                       clock-output-names = "apbc_pwm1_mux";
> +                                       marvell,mmp-clk-sel = <0 0x10>;
> +                                       marvell,mmp-clk-reg = <0xc 0x70>;
> +                               };
> +                               apbc_pwm1_clk: apbc_pwm1_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&apbc_pwm1_mux>;
> +                                       clock-names = "apbc_pwm1_clk";
> +                                       marvell,mmp-clk-reg = <0xc 0x70>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_pwm2_mux: apbc_pwm2_mux {
> +                                       compatible = "marvell,mmp-clkmux";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk13m &osc_32k>;
> +                                       clock-output-names = "apbc_pwm2_mux";
> +                                       marvell,mmp-clk-sel = <0 0x10>;
> +                                       marvell,mmp-clk-reg = <0x10 0x70>;
> +                               };
> +                               apbc_pwm2_clk: apbc_pwm2_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&apbc_pwm2_mux>;
> +                                       clock-names = "apbc_pwm2_clk";
> +                                       marvell,mmp-clk-reg = <0x10 0x70>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_pwm3_mux: apbc_pwm3_mux {
> +                                       compatible = "marvell,mmp-clkmux";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk13m &osc_32k>;
> +                                       clock-output-names = "apbc_pwm3_mux";
> +                                       marvell,mmp-clk-sel = <0 0x10>;
> +                                       marvell,mmp-clk-reg = <0x14 0x70>;
> +                               };
> +                               apbc_pwm3_clk: apbc_pwm3_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&apbc_pwm3_mux>;
> +                                       clock-names = "apbc_pwm3_clk";
> +                                       marvell,mmp-clk-reg = <0x14 0x70>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_pwm4_mux: apbc_pwm4_mux {
> +                                       compatible = "marvell,mmp-clkmux";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk13m &osc_32k>;
> +                                       clock-output-names = "apbc_pwm4_mux";
> +                                       marvell,mmp-clk-sel = <0 0x10>;
> +                                       marvell,mmp-clk-reg = <0x18 0x70>;
> +                               };
> +                               apbc_pwm4_clk: apbc_pwm4_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&apbc_pwm4_mux>;
> +                                       clock-names = "apbc_pwm4_clk";
> +                                       marvell,mmp-clk-reg = <0x18 0x70>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_ssp1_mux: apbc_ssp1_mux {
> +                                       compatible = "marvell,mmp-clkmux";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk7m &refclk13m &refclk26m &refclk52m>;
> +                                       clock-output-names = "apbc_ssp1_mux";
> +                                       marvell,mmp-clk-sel = <0 0x10 0x20 0x30>;
> +                                       marvell,mmp-clk-reg = <0x1c 0x70>;
> +                               };
> +                               apbc_ssp1_clk: apbc_ssp1_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&apbc_ssp1_mux>;
> +                                       clock-names = "apbc_ssp1_clk";
> +                                       marvell,mmp-clk-reg = <0x1c 0x70>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_ssp2_mux: apbc_ssp2_mux {
> +                                       compatible = "marvell,mmp-clkmux";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk7m &refclk13m &refclk26m &refclk52m>;
> +                                       clock-output-names = "apbc_ssp2_mux";
> +                                       marvell,mmp-clk-sel = <0 0x10 0x20 0x30>;
> +                                       marvell,mmp-clk-reg = <0x20 0x70>;
> +                               };
> +                               apbc_ssp2_clk: apbc_ssp2_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&apbc_ssp2_mux>;
> +                                       clock-names = "apbc_ssp2_clk";
> +                                       marvell,mmp-clk-reg = <0x20 0x70>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_ssp3_mux: apbc_ssp3_mux {
> +                                       compatible = "marvell,mmp-clkmux";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk7m &refclk13m &refclk26m &refclk52m>;
> +                                       clock-output-names = "apbc_ssp3_mux";
> +                                       marvell,mmp-clk-sel = <0 0x10 0x20 0x30>;
> +                                       marvell,mmp-clk-reg = <0x4c 0x70>;
> +                               };
> +                               apbc_ssp3_clk: apbc_ssp3_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&apbc_ssp3_mux>;
> +                                       clock-names = "apbc_ssp3_clk";
> +                                       marvell,mmp-clk-reg = <0x4c 0x70>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_kpc_mux: apbc_kpc_mux {
> +                                       compatible = "marvell,mmp-clkmux";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&osc_32k &refclk16k &refclk26m>;
> +                                       clock-output-names = "apbc_kpc_mux";
> +                                       marvell,mmp-clk-sel = <0 0x10 0x20>;
> +                                       marvell,mmp-clk-reg = <0x30 0x70>;
> +                               };
> +                               apbc_kpc_clk: apbc_kpc_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&apbc_kpc_mux>;
> +                                       clock-names = "apbc_kpc_clk";
> +                                       marvell,mmp-clk-reg = <0x30 0x70>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_timer0_mux: apbc_timer0_mux {
> +                                       compatible = "marvell,mmp-clkmux";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk13m &osc_32k &refclk7m &refclk3m>;
> +                                       clock-output-names = "apbc_timer0_mux";
> +                                       marvell,mmp-clk-sel = <0 0x10 0x20 0x30>;
> +                                       marvell,mmp-clk-reg = <0x34 0x70>;
> +                               };
> +                               apbc_timer0_clk: apbc_timer0_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&timer0_mux>;
> +                                       clock-names = "apbc_timer0_clk";
> +                                       marvell,mmp-clk-reg = <0x34 0x70>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                               apbc_timer1_mux: apbc_timer1_mux {
> +                                       compatible = "marvell,mmp-clkmux";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk13m &osc_32k &refclk7m &refclk3m>;
> +                                       clock-output-names = "apbc_timer1_mux";
> +                                       marvell,mmp-clk-sel = <0 0x10 0x20 0x30>;
> +                                       marvell,mmp-clk-reg = <0x44 0x70>;
> +                               };
> +                               apbc_timer1_clk: apbc_timer1_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&timer1_mux>;
> +                                       clock-names = "apbc_timer1_clk";
> +                                       marvell,mmp-clk-reg = <0x44 0x70>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                       };
> +
> +                       apbcp: clocks at 3b000 {
> +                               compatible = "marvell,mmp-apbcp";
> +                               #address-cells = <1>;
> +                               #size-cells = <1>;
> +                               reg = <0xd403b000 0x100>;
> +
> +                               apbcp_twsi2_clk: apbcp_twsi2_clk {
> +                                       compatible = "marvell,mmp-apbcp-clock";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk32m>;
> +                                       clock-output-names = "apbcp_twsi2_clk";
> +                                       marvell,mmp-clk-sel = <0>;
> +                                       /* register offset & mask */
> +                                       marvell,mmp-clk-reg = <0x28 0x70>;
> +                               };
> +                               apbcp_uart3_mux: apbcp_uart3_mux {
> +                                       compatible = "marvell,mmp-clkmux";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&refclk59m &refclk15m>;
> +                                       clock-output-names = "apbcp_uart3_mux";
> +                                       /* register offset & mask */
> +                                       marvell,mmp-clk-reg = <0x1c 0x70>;
> +                                       /* register value of each item */
> +                                       marvell,mmp-clk-sel = <0 0x10>;
> +                               };
> +                               apbcp_uart3_clk: apbcp_uart3_clk {
> +                                       compatible = "marvell,mmp-apbc-clk";
> +                                       #clock-cells = <0>;
> +                                       clocks = <&apbcp_uart3_mux>;
> +                                       clock-names = "apbcp_uart3_clk";
> +                                       marvell,mmp-clk-reg = <0x1c 0x70>;
> +                                       marvell,mmp-clk-delay = <10>;
> +                               };
> +                       };
> +
> +                       timer0_mux: timer0_mux {
> +                               compatible = "marvell,mmp-clkmux";
> +                               #clock-cells = <0>;
> +                               clocks = <&refclk3m &osc_32k &apbc_timer0_mux>;
> +                               clock-output-names = "timer0_mux";
> +                               marvell,mmp-clk-sel = <0 0x1 0x3>;
> +                               marvell,mmp-clk-reg = <0x14000 0x1c>;
> +                       };
> +
> +                       timer1_mux: timer1_mux {
> +                               compatible = "marvell,mmp-clkmux";
> +                               #clock-cells = <0>;
> +                               clocks = <&refclk3m &osc_32k &apbc_timer1_mux>;
> +                               clock-output-names = "timer1_mux";
> +                               marvell,mmp-clk-sel = <0 0x1 0x3>;
> +                               marvell,mmp-clk-reg = <0x16000 0x1c>;
> +                       };
> +               };
> +       };
> +};
> diff --git a/arch/arm/boot/dts/pxa910-dkb.dts b/arch/arm/boot/dts/pxa910-dkb.dts
> index 595492a..b892ebe 100644
> --- a/arch/arm/boot/dts/pxa910-dkb.dts
> +++ b/arch/arm/boot/dts/pxa910-dkb.dts
> @@ -24,6 +24,17 @@
>  
>         soc {
>                 apb at d4000000 {
> +                       pll2: refclk1001mhz {
> +                               /* Reference clock for internal PLL2 */
> +                               compatible = "marvell,mmp-fixed-clkrate";
> +                               #clock-cells = <0>;
> +                               clocks = <&osc_26m>;
> +                               clock-frequency = <1001000000>;
> +                               clock-output-names = "refclk1001mhz";
> +                       };
> +                       timer0: timer at d4014000 {
> +                               status = "okay";
> +                       };
>                         uart1: uart at d4017000 {
>                                 status = "okay";
>                         };
> diff --git a/arch/arm/boot/dts/pxa910.dtsi b/arch/arm/boot/dts/pxa910.dtsi
> index 0247c62..cd888d3 100644
> --- a/arch/arm/boot/dts/pxa910.dtsi
> +++ b/arch/arm/boot/dts/pxa910.dtsi
> @@ -8,6 +8,7 @@
>   */
>  
>  /include/ "skeleton.dtsi"
> +/include/ "pxa910-clk.dtsi"
>  
>  / {
>         aliases {
> @@ -44,7 +45,6 @@
>                                 reg = <0xd4282000 0x1000>;
>                                 mrvl,intc-nr-irqs = <64>;
>                         };
> -
>                 };
>  
>                 apb at d4000000 {  /* APB */
> @@ -58,12 +58,15 @@
>                                 compatible = "mrvl,mmp-timer";
>                                 reg = <0xd4014000 0x100>;
>                                 interrupts = <13>;
> +                               clocks = <&apbc_timer0_clk>;
> +                               status = "disabled";
>                         };
>  
>                         timer1: timer at d4016000 {
>                                 compatible = "mrvl,mmp-timer";
>                                 reg = <0xd4016000 0x100>;
>                                 interrupts = <29>;
> +                               clocks = <&apbc_timer1_clk>;
>                                 status = "disabled";
>                         };
>  
> @@ -71,6 +74,7 @@
>                                 compatible = "mrvl,mmp-uart";
>                                 reg = <0xd4017000 0x1000>;
>                                 interrupts = <27>;
> +                               clocks = <&apbc_uart1_clk>;
>                                 status = "disabled";
>                         };
>  
> @@ -78,6 +82,7 @@
>                                 compatible = "mrvl,mmp-uart";
>                                 reg = <0xd4018000 0x1000>;
>                                 interrupts = <28>;
> +                               clocks = <&apbc_uart2_clk>;
>                                 status = "disabled";
>                         };
>  
> @@ -85,6 +90,7 @@
>                                 compatible = "mrvl,mmp-uart";
>                                 reg = <0xd4036000 0x1000>;
>                                 interrupts = <59>;
> +                               clocks = <&apbcp_uart3_clk>;
>                                 status = "disabled";
>                         };
>  
> @@ -99,6 +105,7 @@
>                                 interrupt-names = "gpio_mux";
>                                 interrupt-controller;
>                                 #interrupt-cells = <1>;
> +                               clocks = <&apbc_gpio_clk>;
>                                 ranges;
>  
>                                 gcb0: gpio at d4019000 {
> @@ -124,6 +131,7 @@
>                                 #size-cells = <0>;
>                                 reg = <0xd4011000 0x1000>;
>                                 interrupts = <7>;
> +                               clocks = <&apbc_twsi1_clk>;
>                                 mrvl,i2c-fast-mode;
>                                 status = "disabled";
>                         };
> @@ -134,6 +142,7 @@
>                                 #size-cells = <0>;
>                                 reg = <0xd4037000 0x1000>;
>                                 interrupts = <54>;
> +                               clocks = <&apbcp_twsi2_clk>;
>                                 status = "disabled";
>                         };
>  
> @@ -142,6 +151,7 @@
>                                 reg = <0xd4010000 0x1000>;
>                                 interrupts = <5 6>;
>                                 interrupt-names = "rtc 1Hz", "rtc alarm";
> +                               clocks = <&apbc_rtc_clk>;
>                                 status = "disabled";
>                         };
>                 };
> diff --git a/arch/arm/mach-mmp/mmp-dt.c b/arch/arm/mach-mmp/mmp-dt.c
> index cca529c..f109bf6 100644
> --- a/arch/arm/mach-mmp/mmp-dt.c
> +++ b/arch/arm/mach-mmp/mmp-dt.c
> @@ -9,6 +9,7 @@
>   *  publishhed by the Free Software Foundation.
>   */
>  
> +#include <linux/clk-provider.h>
>  #include <linux/irqchip.h>
>  #include <linux/of_platform.h>
>  #include <asm/mach/arch.h>
> @@ -48,6 +49,7 @@ static void __init pxa168_dt_init(void)
>  
>  static void __init pxa910_dt_init(void)
>  {
> +       of_clk_init(NULL);
>         of_platform_populate(NULL, of_default_bus_match_table,
>                              pxa910_auxdata_lookup, NULL);
>  }
> diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile
> index 392d780..83182e5 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-mmp.o
>  
>  obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
>  obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o
> diff --git a/drivers/clk/mmp/clk-mmp.c b/drivers/clk/mmp/clk-mmp.c
> new file mode 100644
> index 0000000..7ead432
> --- /dev/null
> +++ b/drivers/clk/mmp/clk-mmp.c
> @@ -0,0 +1,363 @@
> +/*
> + * Marvell MMP clock driver
> + *
> + * Copyright (c) 2012 Linaro Limited.
> + *
> + * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/slab.h>
> +
> +#include "clk.h"
> +
> +enum {
> +       MMP_MPMU = 0,
> +       MMP_APMU,
> +       MMP_APBC,
> +       MMP_APBCP,
> +       MMP_APB,
> +       MMP_MAX,
> +};
> +
> +static void __iomem *mmp_clk_base[MMP_MAX];
> +
> +static DEFINE_SPINLOCK(mmp_clk_lock);
> +
> +static const struct of_device_id mmp_of_match[] = {
> +       { .compatible = "marvell,mmp-mpmu", .data = (void *)MMP_MPMU, },
> +       { .compatible = "marvell,mmp-apmu", .data = (void *)MMP_APMU, },
> +       { .compatible = "marvell,mmp-apbc", .data = (void *)MMP_APBC, },
> +       { .compatible = "marvell,mmp-apbcp", .data = (void *)MMP_APBCP, },
> +       { .compatible = "mrvl,apb-bus", .data = (void *)MMP_APB, },
> +};
> +
> +void __iomem __init *mmp_init_clocks(struct device_node *np)
> +{
> +       struct device_node *parent;
> +       const struct of_device_id *match;
> +       void __iomem *ret = NULL;
> +       int i;
> +
> +       parent = of_get_parent(np);
> +       if (!parent)
> +               goto out;
> +       match = of_match_node(mmp_of_match, parent);
> +       if (!match)
> +               goto out;
> +
> +       i = (unsigned int)match->data;
> +       switch (i) {
> +       case MMP_MPMU:
> +       case MMP_APMU:
> +       case MMP_APBC:
> +       case MMP_APBCP:
> +       case MMP_APB:
> +               if (!mmp_clk_base[i]) {
> +                       ret = of_iomap(parent, 0);
> +                       WARN_ON(!ret);
> +                       mmp_clk_base[i] = ret;
> +               } else {
> +                       ret = mmp_clk_base[i];
> +               }
> +               break;
> +       default:
> +               goto out;
> +       }
> +out:
> +       return ret;
> +}
> +
> +static void __init mmp_fixed_rate_setup(struct device_node *np)
> +{
> +       struct clk *clk;
> +       const char *clk_name, *parent_name;
> +       int rate;
> +
> +       if (of_property_read_u32(np, "clock-frequency", &rate))
> +               return;
> +
> +       if (of_property_read_string(np, "clock-output-names", &clk_name))
> +               return;
> +
> +       /* this node has only one parent */
> +       parent_name = of_clk_get_parent_name(np, 0);
> +       if (!parent_name)
> +               return;
> +
> +       clk = clk_register_fixed_rate(NULL, clk_name, parent_name, 0, rate);
> +       if (IS_ERR(clk))
> +               return;
> +       of_clk_add_provider(np, of_clk_src_simple_get, clk);
> +}
> +CLK_OF_DECLARE(mmp_fixed_rate, "marvell,mmp-fixed-clkrate",
> +              mmp_fixed_rate_setup);
> +
> +static void __init mmp_fixed_factor_setup(struct device_node *np)
> +{
> +       struct clk *clk;
> +       const char *clk_name, *output_name, *parent_name;
> +       u32 data[2];
> +
> +       if (of_property_read_u32_array(np, "marvell,mmp-fixed-factor",
> +                               &data[0], 2))
> +               return;
> +       if (of_property_read_string(np, "clock-output-names", &output_name))
> +               return;
> +
> +       /* this node has only one parent */
> +       parent_name = of_clk_get_parent_name(np, 0);
> +       if (!parent_name)
> +               return;
> +
> +       clk = clk_register_fixed_factor(NULL, output_name, parent_name, 0,
> +                       data[0], data[1]);
> +       if (IS_ERR(clk))
> +               return;
> +       if (!of_property_read_string(np, "clock-names", &clk_name))
> +               clk_register_clkdev(clk, clk_name, NULL);
> +       of_clk_add_provider(np, of_clk_src_simple_get, clk);
> +}
> +CLK_OF_DECLARE(mmp_fixed_factor, "marvell,mmp-fixed-clkfactor",
> +              mmp_fixed_factor_setup);
> +
> +static void __init mmp_apmu_div_setup(struct device_node *np)
> +{
> +       u32 data[2];
> +       u8 shift, width;
> +       void __iomem *reg, *base;
> +       const char *parent_name, *clk_name;
> +       struct clk *clk;
> +
> +       base = mmp_init_clocks(np);
> +       if (!base)
> +               return;
> +
> +       if (of_property_read_u32_array(np, "marvell,mmp-clk-reg", &data[0], 2))
> +               return;
> +       reg = base + data[0];
> +       shift = ffs(data[1]) - 1;
> +       width = fls(data[1]) - ffs(data[1]) + 1;
> +
> +       parent_name = of_clk_get_parent_name(np, 0);
> +       if (!parent_name)
> +               return;
> +       if (of_property_read_string(np, "clock-output-names", &clk_name))
> +               return;
> +
> +       clk = clk_register_divider(NULL, clk_name, parent_name,
> +                       CLK_SET_RATE_PARENT, reg, shift, width, 0,
> +                       &mmp_clk_lock);
> +       if (IS_ERR(clk))
> +               return;
> +       of_clk_add_provider(np, of_clk_src_simple_get, clk);
> +       return;
> +}
> +CLK_OF_DECLARE(mmp_div, "mmp-apmu-clkdiv", mmp_apmu_div_setup);
> +
> +static int __init mmp_parse_mux(struct device_node *np,
> +                               const char **parent_names,
> +                               u8 *num_parents,
> +                               u32 *clk_sel)
> +{
> +       int i, cnt, ret;
> +
> +       /* get the count of items in mux */
> +       for (i = 0, cnt = 0; ; i++, cnt++) {
> +               /* parent's #clock-cells property is always 0 */
> +               if (!of_parse_phandle(np, "clocks", i))
> +                       break;
> +       }
> +
> +       for (i = 0; ; i++) {
> +               if (!of_clk_get_parent_name(np, i))
> +                       break;
> +       }
> +       *num_parents = i;
> +       if (!*num_parents)
> +               return -ENOENT;
> +
> +       clk_sel = kzalloc(sizeof(u32 *) * *num_parents, GFP_KERNEL);
> +       if (!clk_sel)
> +               return -ENOMEM;
> +       ret = of_property_read_u32_array(np, "marvell,mmp-clk-sel", clk_sel, cnt);
> +       if (ret)
> +               goto err;
> +       return 0;
> +err:
> +       kfree(clk_sel);
> +       return ret;
> +}
> +
> +static void __init mmp_mux_setup(struct device_node *np)
> +{
> +       u32 data[2], *clk_sel, mux_flags = 0;
> +       u8 shift, width, num_parents;
> +       void __iomem *reg, *base;
> +       const char **parent_names;
> +       const char *clk_name;
> +       struct clk *clk;
> +       int i, ret;
> +
> +       base = mmp_init_clocks(np);
> +       if (!base)
> +               return;
> +       if (of_property_read_string(np, "clock-output-names", &clk_name))
> +               return;
> +       if (of_property_read_u32_array(np, "marvell,mmp-clk-reg", &data[0], 2))
> +               return;
> +       ret = mmp_parse_mux(np, parent_names, &num_parents, clk_sel);
> +       if (ret)
> +               return;
> +
> +       reg = base + data[0];
> +       shift = ffs(data[1]) - 1;
> +       width = fls(data[1]) - ffs(data[1]) + 1;
> +
> +       parent_names = kzalloc(sizeof(char *) * num_parents, GFP_KERNEL);
> +       if (!parent_names)
> +               return;
> +
> +       for (i = 0; i < num_parents; i++)
> +               parent_names[i] = of_clk_get_parent_name(np, i);
> +       clk = clk_register_mux(NULL, clk_name, parent_names, num_parents,
> +                              CLK_SET_RATE_PARENT, reg, shift, width,
> +                              mux_flags, &mmp_clk_lock);
> +       if (IS_ERR(clk)) {
> +               kfree(parent_names);
> +               return;
> +       }
> +       of_clk_add_provider(np, of_clk_src_simple_get, clk);
> +}
> +CLK_OF_DECLARE(mmp_mux, "marvell,mmp-clkmux", mmp_mux_setup);
> +
> +#define APBC_NO_BUS_CTRL       BIT(0)
> +#define APBC_POWER_CTRL                BIT(1)
> +
> +static void __init mmp_apbc_setup(struct device_node *np)
> +{
> +       u32 data[2], delay, apbc_flags, clkdev;
> +       void __iomem *reg, *base;
> +       const char **parent_names;
> +       const char *clk_name = NULL;
> +       struct clk *clk;
> +
> +       base = mmp_init_clocks(np);
> +       if (!base)
> +               return;
> +
> +       if (of_property_read_string(np, "clock-names", &clk_name))
> +               clkdev = 1;
> +       else {
> +               of_property_read_string(np, "clock-output-names", &clk_name);
> +               clkdev = 0;
> +       }
> +
> +       if (of_property_read_u32_array(np, "marvell,mmp-clk-reg", &data[0], 2))
> +               return;
> +       /* If marvell,mmp-clk-delay property isn't defined, set delay as 10us */
> +       if (of_property_read_u32(np, "marvell,mmp-clk-delay", &delay))
> +               delay = 10;
> +       if (of_get_property(np, "marvell,mmp-apbc-power-ctl", NULL))
> +               apbc_flags |= APBC_POWER_CTRL;
> +
> +       reg = base + data[0];
> +
> +       /* only has the fixed parent */
> +       parent_names = kzalloc(sizeof(char *), GFP_KERNEL);
> +       if (!parent_names)
> +               return;
> +       parent_names[0] = of_clk_get_parent_name(np, 0);
> +
> +       clk = mmp_clk_register_apbc(clk_name, parent_names[0],
> +                                   reg, delay, 0, &mmp_clk_lock);
> +       if (IS_ERR(clk)) {
> +               kfree(parent_names);
> +               return;
> +       }
> +       if (clkdev)
> +               clk_register_clkdev(clk, clk_name, NULL);
> +       of_clk_add_provider(np, of_clk_src_simple_get, clk);
> +}
> +CLK_OF_DECLARE(mmp_apbc, "marvell,mmp-apbc-clk", mmp_apbc_setup);
> +
> +static void __init mmp_apbcp_setup(struct device_node *np)
> +{
> +       int i, cnt;
> +       u32 *clk_sel, data[2];
> +       u8 num_parents, shift, width;
> +       void __iomem *reg, *base;
> +       const char **parent_names, *clk_name;
> +       struct clk *clk;
> +
> +       base = mmp_init_clocks(np);
> +       if (!base)
> +               return;
> +
> +       if (of_property_read_string(np, "clock-output-names", &clk_name))
> +               return;
> +       /* get the count of items in mux */
> +       for (i = 0, cnt = 0; ; i++, cnt++) {
> +               /* parent's #clock-cells property is always 0 */
> +               if (!of_parse_phandle(np, "clocks", i))
> +                       break;
> +       }
> +
> +       for (i = 0; ; i++) {
> +               if (!of_clk_get_parent_name(np, i))
> +                       break;
> +       }
> +       num_parents = i;
> +       if (!num_parents)
> +               return;
> +
> +       if (of_property_read_u32_array(np, "marvell,mmp-clk-reg", &data[0], 2))
> +               return;
> +       reg = base + data[0];
> +       shift = ffs(data[1]) - 1;
> +       width = fls(data[1]) - ffs(data[1]) + 1;
> +
> +       clk_sel = kzalloc(sizeof(u32 *) * num_parents, GFP_KERNEL);
> +       if (!clk_sel)
> +               return;
> +       if (of_property_read_u32_array(np, "marvell,mmp-clk-sel", clk_sel, cnt))
> +               goto err_sel;
> +       parent_names = kzalloc(sizeof(char *) * num_parents, GFP_KERNEL);
> +       if (!parent_names)
> +               goto err_sel;
> +
> +       for (i = 0; i < num_parents; i++)
> +               parent_names[i] = of_clk_get_parent_name(np, i);
> +       clk = clk_register_mux(NULL, clk_name, parent_names, num_parents, 0,
> +                               reg, shift, width, 0, &mmp_clk_lock);
> +       if (IS_ERR(clk))
> +               goto err_mux;
> +       of_clk_add_provider(np, of_clk_src_simple_get, clk);
> +       return;
> +err_mux:
> +       kfree(parent_names);
> +err_sel:
> +       kfree(clk_sel);
> +}
> +CLK_OF_DECLARE(mmp_apbcp, "mmp-apbcp-clk", mmp_apbcp_setup);
> -- 
> 1.8.1.2

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2013-06-11 20:20 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-06-04  4:12 [PATCH v4 00/10] update irqchip, clocksource, clk for mmp Haojian Zhuang
2013-06-04  4:12 ` [PATCH v4 01/10] irqchip: move mmp irq driver Haojian Zhuang
2013-06-04  4:12 ` [PATCH v4 02/10] irqchip: mmp: support irqchip Haojian Zhuang
2013-06-04  4:12 ` [PATCH v4 03/10] irqchip: mmp: support MULTI_IRQ_HANDLER Haojian Zhuang
2013-06-04  4:12 ` [PATCH v4 04/10] ARM: mmp: avoid to include head file in mach-mmp Haojian Zhuang
2013-06-04  4:12 ` [PATCH v4 05/10] irqchip: mmp: avoid to include irqs head file Haojian Zhuang
2013-06-04  4:12 ` [PATCH v4 06/10] clocksource: mmp: move mmp timer driver Haojian Zhuang
2013-06-04  4:12 ` [PATCH v4 07/10] ARM: mmp: move timer registers into driver Haojian Zhuang
2013-06-04  4:12 ` [PATCH v4 08/10] ARM: pxa: init dma debugfs in late level Haojian Zhuang
2013-06-04  4:12 ` [PATCH v4 09/10] clk: mmp: parse clock from dts Haojian Zhuang
2013-06-11 20:20   ` Mike Turquette
2013-06-04  4:12 ` [PATCH v4 10/10] ARM: mmp: avoid to use cpu_is_xxx in timer Haojian Zhuang
2013-06-04 15:27 ` [PATCH v5 09/10] clk: mmp: parse clock from dts Haojian Zhuang

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.