All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] ARM: mmp: remove SPARSE_IRQ for mmp
@ 2011-07-08 10:20 ` Haojian Zhuang
  0 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-08 10:20 UTC (permalink / raw)
  To: grant.likely, linux-arm-kernel, devicetree-discuss,
	haojian.zhuang, nico, samuel.ortiz, broonie
  Cc: Haojian Zhuang

Avoid to use SPARSE_IRQ for mmp. There will be irq domain translation between
DT irq specifier and the Linux irq number.

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 arch/arm/Kconfig |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 17507b8..48748fb 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -545,7 +545,6 @@ config ARCH_MMP
 	select HAVE_SCHED_CLOCK
 	select TICK_ONESHOT
 	select PLAT_PXA
-	select SPARSE_IRQ
 	help
 	  Support for Marvell's PXA168/PXA910(MMP) and MMP2 processor line.
 
-- 
1.5.6.5

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

* [PATCH] ARM: mmp: remove SPARSE_IRQ for mmp
@ 2011-07-08 10:20 ` Haojian Zhuang
  0 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-08 10:20 UTC (permalink / raw)
  To: linux-arm-kernel

Avoid to use SPARSE_IRQ for mmp. There will be irq domain translation between
DT irq specifier and the Linux irq number.

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 arch/arm/Kconfig |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 17507b8..48748fb 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -545,7 +545,6 @@ config ARCH_MMP
 	select HAVE_SCHED_CLOCK
 	select TICK_ONESHOT
 	select PLAT_PXA
-	select SPARSE_IRQ
 	help
 	  Support for Marvell's PXA168/PXA910(MMP) and MMP2 processor line.
 
-- 
1.5.6.5

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

* [PATCH] ARM: mmp: remove builtin gpio driver support
  2011-07-08 10:20 ` Haojian Zhuang
@ 2011-07-08 10:20   ` Haojian Zhuang
  -1 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-08 10:20 UTC (permalink / raw)
  To: grant.likely, linux-arm-kernel, devicetree-discuss,
	haojian.zhuang, nico, samuel.ortiz, broonie
  Cc: Haojian Zhuang

Remove builtin gpio driver support form mmp.

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 arch/arm/mach-mmp/include/mach/gpio.h |   27 +++------------------------
 arch/arm/mach-mmp/mmp2.c              |   17 -----------------
 arch/arm/mach-mmp/pxa168.c            |   17 -----------------
 arch/arm/mach-mmp/pxa910.c            |   17 -----------------
 arch/arm/plat-pxa/Makefile            |    2 ++
 5 files changed, 5 insertions(+), 75 deletions(-)

diff --git a/arch/arm/mach-mmp/include/mach/gpio.h b/arch/arm/mach-mmp/include/mach/gpio.h
index 7bfb827..829f165 100644
--- a/arch/arm/mach-mmp/include/mach/gpio.h
+++ b/arch/arm/mach-mmp/include/mach/gpio.h
@@ -1,36 +1,15 @@
 #ifndef __ASM_MACH_GPIO_H
 #define __ASM_MACH_GPIO_H
 
-#include <mach/addr-map.h>
-#include <mach/irqs.h>
 #include <asm-generic/gpio.h>
 
-#define GPIO_REGS_VIRT	(APB_VIRT_BASE + 0x19000)
-
-#define BANK_OFF(n)	(((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2))
-#define GPIO_REG(x)	(*((volatile u32 *)(GPIO_REGS_VIRT + (x))))
-
-#define NR_BUILTIN_GPIO		IRQ_GPIO_NUM
-
 #define gpio_to_bank(gpio)	((gpio) >> 5)
-#define gpio_to_irq(gpio)	(IRQ_GPIO_START + (gpio))
-#define irq_to_gpio(irq)	((irq) - IRQ_GPIO_START)
+#define bank_to_gpio(nr)	(nr << 5)
+#define GPIO_bit(gpio)		(1 << ((gpio) & 0x1f))
 
+#define gpio_to_irq(nr)		__gpio_to_irq(nr)
 
 #define __gpio_is_inverted(gpio)	(0)
 #define __gpio_is_occupied(gpio)	(0)
 
-/* NOTE: these macros are defined here to make optimization of
- * gpio_{get,set}_value() to work when 'gpio' is a constant.
- * Usage of these macros otherwise is no longer recommended,
- * use generic GPIO API whenever possible.
- */
-#define GPIO_bit(gpio)	(1 << ((gpio) & 0x1f))
-
-#define GPLR(x)		GPIO_REG(BANK_OFF(gpio_to_bank(x)) + 0x00)
-#define GPDR(x)		GPIO_REG(BANK_OFF(gpio_to_bank(x)) + 0x0c)
-#define GPSR(x)		GPIO_REG(BANK_OFF(gpio_to_bank(x)) + 0x18)
-#define GPCR(x)		GPIO_REG(BANK_OFF(gpio_to_bank(x)) + 0x24)
-
-#include <plat/gpio.h>
 #endif /* __ASM_MACH_GPIO_H */
diff --git a/arch/arm/mach-mmp/mmp2.c b/arch/arm/mach-mmp/mmp2.c
index 8e6c3ac..d3f9b3b 100644
--- a/arch/arm/mach-mmp/mmp2.c
+++ b/arch/arm/mach-mmp/mmp2.c
@@ -34,8 +34,6 @@
 
 #define MFPR_VIRT_BASE	(APB_VIRT_BASE + 0x1e000)
 
-#define APMASK(i)	(GPIO_REGS_VIRT + BANK_OFF(i) + 0x9c)
-
 static struct mfp_addr_map mmp2_addr_map[] __initdata = {
 
 	MFP_ADDR_X(GPIO0, GPIO58, 0x54),
@@ -95,24 +93,9 @@ void mmp2_clear_pmic_int(void)
 	__raw_writel(data, mfpr_pmic);
 }
 
-static void __init mmp2_init_gpio(void)
-{
-	int i;
-
-	/* enable GPIO clock */
-	__raw_writel(APBC_APBCLK | APBC_FNCLK, APBC_MMP2_GPIO);
-
-	/* unmask GPIO edge detection for all 6 banks -- APMASKx */
-	for (i = 0; i < 6; i++)
-		__raw_writel(0xffffffff, APMASK(i));
-
-	pxa_init_gpio(IRQ_MMP2_GPIO, 0, 167, NULL);
-}
-
 void __init mmp2_init_irq(void)
 {
 	mmp2_init_icu();
-	mmp2_init_gpio();
 }
 
 static void sdhc_clk_enable(struct clk *clk)
diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c
index 72b4e76..4f41ea2 100644
--- a/arch/arm/mach-mmp/pxa168.c
+++ b/arch/arm/mach-mmp/pxa168.c
@@ -41,26 +41,9 @@ static struct mfp_addr_map pxa168_mfp_addr_map[] __initdata =
 	MFP_ADDR_END,
 };
 
-#define APMASK(i)	(GPIO_REGS_VIRT + BANK_OFF(i) + 0x09c)
-
-static void __init pxa168_init_gpio(void)
-{
-	int i;
-
-	/* enable GPIO clock */
-	__raw_writel(APBC_APBCLK | APBC_FNCLK, APBC_PXA168_GPIO);
-
-	/* unmask GPIO edge detection for all 4 banks - APMASKx */
-	for (i = 0; i < 4; i++)
-		__raw_writel(0xffffffff, APMASK(i));
-
-	pxa_init_gpio(IRQ_PXA168_GPIOX, 0, 127, NULL);
-}
-
 void __init pxa168_init_irq(void)
 {
 	icu_init_irq();
-	pxa168_init_gpio();
 }
 
 /* APB peripheral clocks */
diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c
index 8f92ccd..e71a45a 100644
--- a/arch/arm/mach-mmp/pxa910.c
+++ b/arch/arm/mach-mmp/pxa910.c
@@ -78,26 +78,9 @@ static struct mfp_addr_map pxa910_mfp_addr_map[] __initdata =
 	MFP_ADDR_END,
 };
 
-#define APMASK(i)	(GPIO_REGS_VIRT + BANK_OFF(i) + 0x09c)
-
-static void __init pxa910_init_gpio(void)
-{
-	int i;
-
-	/* enable GPIO clock */
-	__raw_writel(APBC_APBCLK | APBC_FNCLK, APBC_PXA910_GPIO);
-
-	/* unmask GPIO edge detection for all 4 banks - APMASKx */
-	for (i = 0; i < 4; i++)
-		__raw_writel(0xffffffff, APMASK(i));
-
-	pxa_init_gpio(IRQ_PXA910_AP_GPIO, 0, 127, NULL);
-}
-
 void __init pxa910_init_irq(void)
 {
 	icu_init_irq();
-	pxa910_init_gpio();
 }
 
 /* APB peripheral clocks */
diff --git a/arch/arm/plat-pxa/Makefile b/arch/arm/plat-pxa/Makefile
index 3aca5ba..8e432b1 100644
--- a/arch/arm/plat-pxa/Makefile
+++ b/arch/arm/plat-pxa/Makefile
@@ -4,7 +4,9 @@
 
 obj-y	:= dma.o
 
+ifeq ($(CONFIG_OF),)
 obj-$(CONFIG_GENERIC_GPIO)	+= gpio.o
+endif
 obj-$(CONFIG_PXA3xx)		+= mfp.o
 obj-$(CONFIG_PXA95x)		+= mfp.o
 obj-$(CONFIG_ARCH_MMP)		+= mfp.o
-- 
1.5.6.5

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

* [PATCH] ARM: mmp: remove builtin gpio driver support
@ 2011-07-08 10:20   ` Haojian Zhuang
  0 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-08 10:20 UTC (permalink / raw)
  To: linux-arm-kernel

Remove builtin gpio driver support form mmp.

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 arch/arm/mach-mmp/include/mach/gpio.h |   27 +++------------------------
 arch/arm/mach-mmp/mmp2.c              |   17 -----------------
 arch/arm/mach-mmp/pxa168.c            |   17 -----------------
 arch/arm/mach-mmp/pxa910.c            |   17 -----------------
 arch/arm/plat-pxa/Makefile            |    2 ++
 5 files changed, 5 insertions(+), 75 deletions(-)

diff --git a/arch/arm/mach-mmp/include/mach/gpio.h b/arch/arm/mach-mmp/include/mach/gpio.h
index 7bfb827..829f165 100644
--- a/arch/arm/mach-mmp/include/mach/gpio.h
+++ b/arch/arm/mach-mmp/include/mach/gpio.h
@@ -1,36 +1,15 @@
 #ifndef __ASM_MACH_GPIO_H
 #define __ASM_MACH_GPIO_H
 
-#include <mach/addr-map.h>
-#include <mach/irqs.h>
 #include <asm-generic/gpio.h>
 
-#define GPIO_REGS_VIRT	(APB_VIRT_BASE + 0x19000)
-
-#define BANK_OFF(n)	(((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2))
-#define GPIO_REG(x)	(*((volatile u32 *)(GPIO_REGS_VIRT + (x))))
-
-#define NR_BUILTIN_GPIO		IRQ_GPIO_NUM
-
 #define gpio_to_bank(gpio)	((gpio) >> 5)
-#define gpio_to_irq(gpio)	(IRQ_GPIO_START + (gpio))
-#define irq_to_gpio(irq)	((irq) - IRQ_GPIO_START)
+#define bank_to_gpio(nr)	(nr << 5)
+#define GPIO_bit(gpio)		(1 << ((gpio) & 0x1f))
 
+#define gpio_to_irq(nr)		__gpio_to_irq(nr)
 
 #define __gpio_is_inverted(gpio)	(0)
 #define __gpio_is_occupied(gpio)	(0)
 
-/* NOTE: these macros are defined here to make optimization of
- * gpio_{get,set}_value() to work when 'gpio' is a constant.
- * Usage of these macros otherwise is no longer recommended,
- * use generic GPIO API whenever possible.
- */
-#define GPIO_bit(gpio)	(1 << ((gpio) & 0x1f))
-
-#define GPLR(x)		GPIO_REG(BANK_OFF(gpio_to_bank(x)) + 0x00)
-#define GPDR(x)		GPIO_REG(BANK_OFF(gpio_to_bank(x)) + 0x0c)
-#define GPSR(x)		GPIO_REG(BANK_OFF(gpio_to_bank(x)) + 0x18)
-#define GPCR(x)		GPIO_REG(BANK_OFF(gpio_to_bank(x)) + 0x24)
-
-#include <plat/gpio.h>
 #endif /* __ASM_MACH_GPIO_H */
diff --git a/arch/arm/mach-mmp/mmp2.c b/arch/arm/mach-mmp/mmp2.c
index 8e6c3ac..d3f9b3b 100644
--- a/arch/arm/mach-mmp/mmp2.c
+++ b/arch/arm/mach-mmp/mmp2.c
@@ -34,8 +34,6 @@
 
 #define MFPR_VIRT_BASE	(APB_VIRT_BASE + 0x1e000)
 
-#define APMASK(i)	(GPIO_REGS_VIRT + BANK_OFF(i) + 0x9c)
-
 static struct mfp_addr_map mmp2_addr_map[] __initdata = {
 
 	MFP_ADDR_X(GPIO0, GPIO58, 0x54),
@@ -95,24 +93,9 @@ void mmp2_clear_pmic_int(void)
 	__raw_writel(data, mfpr_pmic);
 }
 
-static void __init mmp2_init_gpio(void)
-{
-	int i;
-
-	/* enable GPIO clock */
-	__raw_writel(APBC_APBCLK | APBC_FNCLK, APBC_MMP2_GPIO);
-
-	/* unmask GPIO edge detection for all 6 banks -- APMASKx */
-	for (i = 0; i < 6; i++)
-		__raw_writel(0xffffffff, APMASK(i));
-
-	pxa_init_gpio(IRQ_MMP2_GPIO, 0, 167, NULL);
-}
-
 void __init mmp2_init_irq(void)
 {
 	mmp2_init_icu();
-	mmp2_init_gpio();
 }
 
 static void sdhc_clk_enable(struct clk *clk)
diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c
index 72b4e76..4f41ea2 100644
--- a/arch/arm/mach-mmp/pxa168.c
+++ b/arch/arm/mach-mmp/pxa168.c
@@ -41,26 +41,9 @@ static struct mfp_addr_map pxa168_mfp_addr_map[] __initdata =
 	MFP_ADDR_END,
 };
 
-#define APMASK(i)	(GPIO_REGS_VIRT + BANK_OFF(i) + 0x09c)
-
-static void __init pxa168_init_gpio(void)
-{
-	int i;
-
-	/* enable GPIO clock */
-	__raw_writel(APBC_APBCLK | APBC_FNCLK, APBC_PXA168_GPIO);
-
-	/* unmask GPIO edge detection for all 4 banks - APMASKx */
-	for (i = 0; i < 4; i++)
-		__raw_writel(0xffffffff, APMASK(i));
-
-	pxa_init_gpio(IRQ_PXA168_GPIOX, 0, 127, NULL);
-}
-
 void __init pxa168_init_irq(void)
 {
 	icu_init_irq();
-	pxa168_init_gpio();
 }
 
 /* APB peripheral clocks */
diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c
index 8f92ccd..e71a45a 100644
--- a/arch/arm/mach-mmp/pxa910.c
+++ b/arch/arm/mach-mmp/pxa910.c
@@ -78,26 +78,9 @@ static struct mfp_addr_map pxa910_mfp_addr_map[] __initdata =
 	MFP_ADDR_END,
 };
 
-#define APMASK(i)	(GPIO_REGS_VIRT + BANK_OFF(i) + 0x09c)
-
-static void __init pxa910_init_gpio(void)
-{
-	int i;
-
-	/* enable GPIO clock */
-	__raw_writel(APBC_APBCLK | APBC_FNCLK, APBC_PXA910_GPIO);
-
-	/* unmask GPIO edge detection for all 4 banks - APMASKx */
-	for (i = 0; i < 4; i++)
-		__raw_writel(0xffffffff, APMASK(i));
-
-	pxa_init_gpio(IRQ_PXA910_AP_GPIO, 0, 127, NULL);
-}
-
 void __init pxa910_init_irq(void)
 {
 	icu_init_irq();
-	pxa910_init_gpio();
 }
 
 /* APB peripheral clocks */
diff --git a/arch/arm/plat-pxa/Makefile b/arch/arm/plat-pxa/Makefile
index 3aca5ba..8e432b1 100644
--- a/arch/arm/plat-pxa/Makefile
+++ b/arch/arm/plat-pxa/Makefile
@@ -4,7 +4,9 @@
 
 obj-y	:= dma.o
 
+ifeq ($(CONFIG_OF),)
 obj-$(CONFIG_GENERIC_GPIO)	+= gpio.o
+endif
 obj-$(CONFIG_PXA3xx)		+= mfp.o
 obj-$(CONFIG_PXA95x)		+= mfp.o
 obj-$(CONFIG_ARCH_MMP)		+= mfp.o
-- 
1.5.6.5

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

* [PATCH] ARM: mmp: parse irq from DT
  2011-07-08 10:20   ` Haojian Zhuang
@ 2011-07-08 10:20     ` Haojian Zhuang
  -1 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-08 10:20 UTC (permalink / raw)
  To: grant.likely, linux-arm-kernel, devicetree-discuss,
	haojian.zhuang, nico, samuel.ortiz, broonie
  Cc: Haojian Zhuang

Parse irq sepcifier from DT and translate it to Linux irq number.

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 arch/arm/mach-mmp/Makefile |    2 +
 arch/arm/mach-mmp/common.h |    1 +
 arch/arm/mach-mmp/intc.c   |  245 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 248 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-mmp/intc.c

diff --git a/arch/arm/mach-mmp/Makefile b/arch/arm/mach-mmp/Makefile
index 5c68382..e7862ea 100644
--- a/arch/arm/mach-mmp/Makefile
+++ b/arch/arm/mach-mmp/Makefile
@@ -4,6 +4,8 @@
 
 obj-y				+= common.o clock.o devices.o time.o
 
+obj-$(CONFIG_OF_IRQ)		+= intc.o
+
 # SoC support
 obj-$(CONFIG_CPU_PXA168)	+= pxa168.o irq-pxa168.o
 obj-$(CONFIG_CPU_PXA910)	+= pxa910.o irq-pxa168.o
diff --git a/arch/arm/mach-mmp/common.h b/arch/arm/mach-mmp/common.h
index ec8d65d..1c563c2 100644
--- a/arch/arm/mach-mmp/common.h
+++ b/arch/arm/mach-mmp/common.h
@@ -6,3 +6,4 @@ extern void timer_init(int irq);
 
 extern void __init icu_init_irq(void);
 extern void __init mmp_map_io(void);
+extern void __init mmp_init_intc(void);
diff --git a/arch/arm/mach-mmp/intc.c b/arch/arm/mach-mmp/intc.c
new file mode 100644
index 0000000..48ad84b
--- /dev/null
+++ b/arch/arm/mach-mmp/intc.c
@@ -0,0 +1,245 @@
+/*
+ *  linux/arch/arm/mach-mmp/intc.c
+ *
+ *  Generic IRQ handling
+ *
+ *  Author:	Haojian Zhuang <haojian.zhuang@marvell.com>
+ *  Copyright:	Marvell International Ltd. 2011
+ *
+ *  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 <linux/errno.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+
+struct mmp_intc_info {
+	unsigned int		mask;
+	unsigned int		phy_base;
+	void __iomem		*virt_base;
+	void __iomem		*mux_status;
+	void __iomem		*mux_mask;
+	void __iomem		*mfp_edge;
+	unsigned int		mfp_edge_index;	/* index in irq domain */
+	unsigned int		irq_base;
+};
+
+static void mux_irq_unmask(struct irq_data *d)
+{
+	struct mmp_intc_info *info = irq_data_get_irq_chip_data(d);
+	unsigned int data, irq_offs;
+
+	irq_offs = d->irq - info->irq_base;
+	if (info->mfp_edge && (info->mfp_edge_index == irq_offs)) {
+		data = __raw_readl(info->mfp_edge);
+		__raw_writel(data | (1 << 6), info->mfp_edge);
+		__raw_writel(data, info->mfp_edge);
+	}
+	data = __raw_readl(info->mux_mask) & ~(1 << (d->irq - info->irq_base));
+	__raw_writel(data, info->mux_mask);
+}
+
+static void mux_irq_mask(struct irq_data *d)
+{
+	struct mmp_intc_info *info = irq_data_get_irq_chip_data(d);
+	unsigned int data;
+
+	data = __raw_readl(info->mux_mask) | (1 << (d->irq - info->irq_base));
+	__raw_writel(data, info->mux_mask);
+}
+
+static struct irq_chip mux_irq_chip = {
+	.name		= "mmp mux intc",
+	.irq_unmask	= mux_irq_unmask,
+	.irq_mask	= mux_irq_mask,
+	.irq_ack	= mux_irq_mask,
+};
+
+static void mmp_irq_demux_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct mmp_intc_info *info = irq_get_handler_data(irq);
+	unsigned long status, mask, n;
+
+	mask = __raw_readl(info->mux_mask);
+	while (1) {
+		status = __raw_readl(info->mux_status) & ~mask;
+		if (status == 0)
+			break;
+		n = find_first_bit(&status, BITS_PER_LONG);
+		while (n < BITS_PER_LONG) {
+			generic_handle_irq(info->irq_base + n);
+			n = find_next_bit(&status, BITS_PER_LONG, n + 1);
+		}
+	}
+}
+
+static void mux_init_intc(struct mmp_intc_info *mmp_info)
+{
+	struct device_node *np;
+	struct mmp_intc_info *mux_info;
+	const __be32 *nr, *status, *edge;
+	unsigned int addr = 0, offs = 0;
+	int cascade, irq_nr, i;
+
+	if (mmp_info->virt_base == NULL)
+		goto out;
+
+	for (np = NULL; (np = of_find_all_nodes(np)) != NULL;) {
+		if (!of_device_is_compatible(np, "mrvl,mux-intc"))
+			continue;
+		if (of_get_property(np, "interrupt-controller", NULL) == NULL)
+			continue;
+		nr = of_get_property(np, "sub-interrupts", NULL);
+		if (nr == NULL) {
+			printk(KERN_WARNING "sub-interrupts property "
+				"is missed\n");
+			continue;
+		}
+		irq_nr = be32_to_cpu(*nr);
+		status = of_get_property(np, "status-mask", NULL);
+		if (status == NULL) {
+			printk(KERN_WARNING "status-mask property is missed\n");
+			continue;
+		}
+		edge = of_get_property(np, "mfp-edge-interrupt", NULL);
+
+		mux_info = kzalloc(sizeof(struct mmp_intc_info), GFP_KERNEL);
+		if (mux_info == NULL)
+			goto out;
+		mux_info->virt_base = mmp_info->virt_base;
+		mux_info->mux_status = be32_to_cpu(*status++)
+					+ mux_info->virt_base;
+		mux_info->mux_mask = be32_to_cpu(*status)
+					+ mux_info->virt_base;
+		if (edge) {
+			addr = be32_to_cpu(*edge) & PAGE_MASK;
+			offs = be32_to_cpu(*edge) - addr;
+			mux_info->mfp_edge = ioremap(addr, PAGE_SIZE) + offs;
+			mux_info->mfp_edge_index = be32_to_cpu(*++edge);
+		}
+
+		/* allocate new irq */
+		cascade = irq_of_parse_and_map(np, 0);
+		mux_info->irq_base = irq_alloc_descs(-1, 0, irq_nr, 0);
+		irq_domain_add_simple(np, mux_info->irq_base);
+
+		i = mux_info->irq_base;
+		for (; i < mux_info->irq_base + irq_nr; i++) {
+			irq_set_chip_data(i, mux_info);
+			mux_irq_mask(irq_get_irq_data(i));
+			irq_set_chip_and_handler(i, &mux_irq_chip,
+					handle_level_irq);
+			set_irq_flags(i, IRQF_VALID);
+		}
+
+		irq_set_handler_data(cascade, mux_info);
+		irq_set_chained_handler(cascade, mmp_irq_demux_handler);
+	}
+out:
+	return;
+}
+
+static void mmp_irq_unmask(struct irq_data *d)
+{
+	struct mmp_intc_info *info = irq_data_get_irq_chip_data(d);
+
+	/* ICU_INT_CONF */
+	__raw_writel(info->mask, info->virt_base + (d->irq << 2));
+}
+
+static void mmp_irq_mask(struct irq_data *d)
+{
+	struct mmp_intc_info *info = irq_data_get_irq_chip_data(d);
+
+	__raw_writel(0, info->virt_base + (d->irq << 2));
+}
+
+static struct irq_chip mmp_irq_chip = {
+	.name		= "mmp-intc",
+	.irq_unmask	= mmp_irq_unmask,
+	.irq_mask	= mmp_irq_mask,
+	.irq_ack	= mmp_irq_mask,
+};
+
+void __init mmp_init_intc(void)
+{
+	struct mmp_intc_info *info;
+	struct device_node *np;
+	const __be32 *enable_mask, *base, *cell, *nr;
+	int i, irq_nr, phy_base;
+
+	np = of_find_compatible_node(NULL, NULL, "mrvl,mmp-intc");
+
+	BUG_ON(!np);
+
+	of_node_get(np);
+	if (of_get_property(np, "interrupt-controller", NULL) == NULL)
+		goto out;
+	cell = of_get_property(np, "#interrupt-cells", NULL);
+	if (cell == NULL) {
+		printk(KERN_ERR "mmp-intc: Device node %s missing "
+			"interrupt-cells property\n", np->full_name);
+		goto out;
+	}
+	if (be32_to_cpu(*cell) != 1) {
+		printk(KERN_ERR "mmp-intc: interrupt-cells property is "
+			"incorrect:%d\n", be32_to_cpu(*cell));
+		goto out;
+	}
+
+	nr = of_get_property(np, "sub-interrupts", NULL);
+	if (nr == NULL) {
+		printk(KERN_ERR "mmp-intc: interrupts property is missed\n");
+		goto out;
+	}
+	irq_nr = be32_to_cpu(*nr);
+
+	base = of_get_property(np, "reg", NULL);
+	if (base == NULL) {
+		printk(KERN_ERR "intc: Device node %s missing reg property\n",
+			np->full_name);
+		goto out;
+	}
+	phy_base = of_translate_address(np, base);
+
+	info = kzalloc(sizeof(struct mmp_intc_info), GFP_KERNEL);
+	if (info == NULL)
+		goto out;
+
+	enable_mask = of_get_property(np, "enable_mask", NULL);
+	if (enable_mask == NULL) {
+		printk(KERN_ERR "interrupt controller: Device node %s "
+			"missing interrupt property\n", np->full_name);
+		goto out_mem;
+	}
+	info->mask = be32_to_cpu(*enable_mask);
+
+	/* phy_base: 0, phy_size:64 */
+	info->phy_base = phy_base;
+	info->virt_base = ioremap(info->phy_base, PAGE_SIZE);
+
+	/* allocate new irq */
+	info->irq_base = irq_alloc_descs(-1, 0, irq_nr, 0);
+	irq_domain_add_simple(np, 0);
+
+	for (i = info->irq_base; i < info->irq_base + irq_nr; i++) {
+		irq_set_chip_data(i, info);
+		mmp_irq_mask(irq_get_irq_data(i));
+		irq_set_chip_and_handler(i, &mmp_irq_chip, handle_level_irq);
+		set_irq_flags(i, IRQF_VALID);
+	}
+	mux_init_intc(info);
+	of_node_put(np);
+	return;
+out_mem:
+	kfree(info);
+out:
+	of_node_put(np);
+	return;
+}
-- 
1.5.6.5

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

* [PATCH] ARM: mmp: parse irq from DT
@ 2011-07-08 10:20     ` Haojian Zhuang
  0 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-08 10:20 UTC (permalink / raw)
  To: linux-arm-kernel

Parse irq sepcifier from DT and translate it to Linux irq number.

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 arch/arm/mach-mmp/Makefile |    2 +
 arch/arm/mach-mmp/common.h |    1 +
 arch/arm/mach-mmp/intc.c   |  245 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 248 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-mmp/intc.c

diff --git a/arch/arm/mach-mmp/Makefile b/arch/arm/mach-mmp/Makefile
index 5c68382..e7862ea 100644
--- a/arch/arm/mach-mmp/Makefile
+++ b/arch/arm/mach-mmp/Makefile
@@ -4,6 +4,8 @@
 
 obj-y				+= common.o clock.o devices.o time.o
 
+obj-$(CONFIG_OF_IRQ)		+= intc.o
+
 # SoC support
 obj-$(CONFIG_CPU_PXA168)	+= pxa168.o irq-pxa168.o
 obj-$(CONFIG_CPU_PXA910)	+= pxa910.o irq-pxa168.o
diff --git a/arch/arm/mach-mmp/common.h b/arch/arm/mach-mmp/common.h
index ec8d65d..1c563c2 100644
--- a/arch/arm/mach-mmp/common.h
+++ b/arch/arm/mach-mmp/common.h
@@ -6,3 +6,4 @@ extern void timer_init(int irq);
 
 extern void __init icu_init_irq(void);
 extern void __init mmp_map_io(void);
+extern void __init mmp_init_intc(void);
diff --git a/arch/arm/mach-mmp/intc.c b/arch/arm/mach-mmp/intc.c
new file mode 100644
index 0000000..48ad84b
--- /dev/null
+++ b/arch/arm/mach-mmp/intc.c
@@ -0,0 +1,245 @@
+/*
+ *  linux/arch/arm/mach-mmp/intc.c
+ *
+ *  Generic IRQ handling
+ *
+ *  Author:	Haojian Zhuang <haojian.zhuang@marvell.com>
+ *  Copyright:	Marvell International Ltd. 2011
+ *
+ *  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 <linux/errno.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+
+struct mmp_intc_info {
+	unsigned int		mask;
+	unsigned int		phy_base;
+	void __iomem		*virt_base;
+	void __iomem		*mux_status;
+	void __iomem		*mux_mask;
+	void __iomem		*mfp_edge;
+	unsigned int		mfp_edge_index;	/* index in irq domain */
+	unsigned int		irq_base;
+};
+
+static void mux_irq_unmask(struct irq_data *d)
+{
+	struct mmp_intc_info *info = irq_data_get_irq_chip_data(d);
+	unsigned int data, irq_offs;
+
+	irq_offs = d->irq - info->irq_base;
+	if (info->mfp_edge && (info->mfp_edge_index == irq_offs)) {
+		data = __raw_readl(info->mfp_edge);
+		__raw_writel(data | (1 << 6), info->mfp_edge);
+		__raw_writel(data, info->mfp_edge);
+	}
+	data = __raw_readl(info->mux_mask) & ~(1 << (d->irq - info->irq_base));
+	__raw_writel(data, info->mux_mask);
+}
+
+static void mux_irq_mask(struct irq_data *d)
+{
+	struct mmp_intc_info *info = irq_data_get_irq_chip_data(d);
+	unsigned int data;
+
+	data = __raw_readl(info->mux_mask) | (1 << (d->irq - info->irq_base));
+	__raw_writel(data, info->mux_mask);
+}
+
+static struct irq_chip mux_irq_chip = {
+	.name		= "mmp mux intc",
+	.irq_unmask	= mux_irq_unmask,
+	.irq_mask	= mux_irq_mask,
+	.irq_ack	= mux_irq_mask,
+};
+
+static void mmp_irq_demux_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct mmp_intc_info *info = irq_get_handler_data(irq);
+	unsigned long status, mask, n;
+
+	mask = __raw_readl(info->mux_mask);
+	while (1) {
+		status = __raw_readl(info->mux_status) & ~mask;
+		if (status == 0)
+			break;
+		n = find_first_bit(&status, BITS_PER_LONG);
+		while (n < BITS_PER_LONG) {
+			generic_handle_irq(info->irq_base + n);
+			n = find_next_bit(&status, BITS_PER_LONG, n + 1);
+		}
+	}
+}
+
+static void mux_init_intc(struct mmp_intc_info *mmp_info)
+{
+	struct device_node *np;
+	struct mmp_intc_info *mux_info;
+	const __be32 *nr, *status, *edge;
+	unsigned int addr = 0, offs = 0;
+	int cascade, irq_nr, i;
+
+	if (mmp_info->virt_base == NULL)
+		goto out;
+
+	for (np = NULL; (np = of_find_all_nodes(np)) != NULL;) {
+		if (!of_device_is_compatible(np, "mrvl,mux-intc"))
+			continue;
+		if (of_get_property(np, "interrupt-controller", NULL) == NULL)
+			continue;
+		nr = of_get_property(np, "sub-interrupts", NULL);
+		if (nr == NULL) {
+			printk(KERN_WARNING "sub-interrupts property "
+				"is missed\n");
+			continue;
+		}
+		irq_nr = be32_to_cpu(*nr);
+		status = of_get_property(np, "status-mask", NULL);
+		if (status == NULL) {
+			printk(KERN_WARNING "status-mask property is missed\n");
+			continue;
+		}
+		edge = of_get_property(np, "mfp-edge-interrupt", NULL);
+
+		mux_info = kzalloc(sizeof(struct mmp_intc_info), GFP_KERNEL);
+		if (mux_info == NULL)
+			goto out;
+		mux_info->virt_base = mmp_info->virt_base;
+		mux_info->mux_status = be32_to_cpu(*status++)
+					+ mux_info->virt_base;
+		mux_info->mux_mask = be32_to_cpu(*status)
+					+ mux_info->virt_base;
+		if (edge) {
+			addr = be32_to_cpu(*edge) & PAGE_MASK;
+			offs = be32_to_cpu(*edge) - addr;
+			mux_info->mfp_edge = ioremap(addr, PAGE_SIZE) + offs;
+			mux_info->mfp_edge_index = be32_to_cpu(*++edge);
+		}
+
+		/* allocate new irq */
+		cascade = irq_of_parse_and_map(np, 0);
+		mux_info->irq_base = irq_alloc_descs(-1, 0, irq_nr, 0);
+		irq_domain_add_simple(np, mux_info->irq_base);
+
+		i = mux_info->irq_base;
+		for (; i < mux_info->irq_base + irq_nr; i++) {
+			irq_set_chip_data(i, mux_info);
+			mux_irq_mask(irq_get_irq_data(i));
+			irq_set_chip_and_handler(i, &mux_irq_chip,
+					handle_level_irq);
+			set_irq_flags(i, IRQF_VALID);
+		}
+
+		irq_set_handler_data(cascade, mux_info);
+		irq_set_chained_handler(cascade, mmp_irq_demux_handler);
+	}
+out:
+	return;
+}
+
+static void mmp_irq_unmask(struct irq_data *d)
+{
+	struct mmp_intc_info *info = irq_data_get_irq_chip_data(d);
+
+	/* ICU_INT_CONF */
+	__raw_writel(info->mask, info->virt_base + (d->irq << 2));
+}
+
+static void mmp_irq_mask(struct irq_data *d)
+{
+	struct mmp_intc_info *info = irq_data_get_irq_chip_data(d);
+
+	__raw_writel(0, info->virt_base + (d->irq << 2));
+}
+
+static struct irq_chip mmp_irq_chip = {
+	.name		= "mmp-intc",
+	.irq_unmask	= mmp_irq_unmask,
+	.irq_mask	= mmp_irq_mask,
+	.irq_ack	= mmp_irq_mask,
+};
+
+void __init mmp_init_intc(void)
+{
+	struct mmp_intc_info *info;
+	struct device_node *np;
+	const __be32 *enable_mask, *base, *cell, *nr;
+	int i, irq_nr, phy_base;
+
+	np = of_find_compatible_node(NULL, NULL, "mrvl,mmp-intc");
+
+	BUG_ON(!np);
+
+	of_node_get(np);
+	if (of_get_property(np, "interrupt-controller", NULL) == NULL)
+		goto out;
+	cell = of_get_property(np, "#interrupt-cells", NULL);
+	if (cell == NULL) {
+		printk(KERN_ERR "mmp-intc: Device node %s missing "
+			"interrupt-cells property\n", np->full_name);
+		goto out;
+	}
+	if (be32_to_cpu(*cell) != 1) {
+		printk(KERN_ERR "mmp-intc: interrupt-cells property is "
+			"incorrect:%d\n", be32_to_cpu(*cell));
+		goto out;
+	}
+
+	nr = of_get_property(np, "sub-interrupts", NULL);
+	if (nr == NULL) {
+		printk(KERN_ERR "mmp-intc: interrupts property is missed\n");
+		goto out;
+	}
+	irq_nr = be32_to_cpu(*nr);
+
+	base = of_get_property(np, "reg", NULL);
+	if (base == NULL) {
+		printk(KERN_ERR "intc: Device node %s missing reg property\n",
+			np->full_name);
+		goto out;
+	}
+	phy_base = of_translate_address(np, base);
+
+	info = kzalloc(sizeof(struct mmp_intc_info), GFP_KERNEL);
+	if (info == NULL)
+		goto out;
+
+	enable_mask = of_get_property(np, "enable_mask", NULL);
+	if (enable_mask == NULL) {
+		printk(KERN_ERR "interrupt controller: Device node %s "
+			"missing interrupt property\n", np->full_name);
+		goto out_mem;
+	}
+	info->mask = be32_to_cpu(*enable_mask);
+
+	/* phy_base: 0, phy_size:64 */
+	info->phy_base = phy_base;
+	info->virt_base = ioremap(info->phy_base, PAGE_SIZE);
+
+	/* allocate new irq */
+	info->irq_base = irq_alloc_descs(-1, 0, irq_nr, 0);
+	irq_domain_add_simple(np, 0);
+
+	for (i = info->irq_base; i < info->irq_base + irq_nr; i++) {
+		irq_set_chip_data(i, info);
+		mmp_irq_mask(irq_get_irq_data(i));
+		irq_set_chip_and_handler(i, &mmp_irq_chip, handle_level_irq);
+		set_irq_flags(i, IRQF_VALID);
+	}
+	mux_init_intc(info);
+	of_node_put(np);
+	return;
+out_mem:
+	kfree(info);
+out:
+	of_node_put(np);
+	return;
+}
-- 
1.5.6.5

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

* [PATCH] ARM: mmp: support OF by default
  2011-07-08 10:20     ` Haojian Zhuang
@ 2011-07-08 10:20       ` Haojian Zhuang
  -1 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-08 10:20 UTC (permalink / raw)
  To: grant.likely, linux-arm-kernel, devicetree-discuss,
	haojian.zhuang, nico, samuel.ortiz, broonie
  Cc: Haojian Zhuang

Support open firmware by default.

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 arch/arm/Kconfig |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 48748fb..7b083a0 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -545,6 +545,7 @@ config ARCH_MMP
 	select HAVE_SCHED_CLOCK
 	select TICK_ONESHOT
 	select PLAT_PXA
+	select USE_OF
 	help
 	  Support for Marvell's PXA168/PXA910(MMP) and MMP2 processor line.
 
-- 
1.5.6.5

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

* [PATCH] ARM: mmp: support OF by default
@ 2011-07-08 10:20       ` Haojian Zhuang
  0 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-08 10:20 UTC (permalink / raw)
  To: linux-arm-kernel

Support open firmware by default.

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 arch/arm/Kconfig |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 48748fb..7b083a0 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -545,6 +545,7 @@ config ARCH_MMP
 	select HAVE_SCHED_CLOCK
 	select TICK_ONESHOT
 	select PLAT_PXA
+	select USE_OF
 	help
 	  Support for Marvell's PXA168/PXA910(MMP) and MMP2 processor line.
 
-- 
1.5.6.5

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

* [PATCH] tty: serial: support device tree in pxa
  2011-07-08 10:20       ` Haojian Zhuang
@ 2011-07-08 10:20         ` Haojian Zhuang
  -1 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-08 10:20 UTC (permalink / raw)
  To: grant.likely, linux-arm-kernel, devicetree-discuss,
	haojian.zhuang, nico, samuel.ortiz, broonie
  Cc: Haojian Zhuang

Support both normal platform driver and device tree driver in serial pxa.

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 drivers/tty/serial/Kconfig     |    4 +-
 drivers/tty/serial/of_serial.c |   12 +++++
 drivers/tty/serial/pxa.c       |   91 ++++++++++++++++++++++++++++++++++------
 include/linux/serial_pxa.h     |   17 +++++++
 4 files changed, 110 insertions(+), 14 deletions(-)
 create mode 100644 include/linux/serial_pxa.h

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 636144c..3f75e0d 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -663,6 +663,8 @@ config SERIAL_MPSC_CONSOLE
 config SERIAL_PXA
 	bool "PXA serial port support"
 	depends on ARCH_PXA || ARCH_MMP
+	select SERIAL_OF_PLATFORM
+	select SERIAL_CORE_CONSOLE
 	select SERIAL_CORE
 	help
 	  If you have a machine based on an Intel XScale PXA2xx CPU you
@@ -1340,7 +1342,7 @@ config SERIAL_NETX_CONSOLE
 config SERIAL_OF_PLATFORM
 	tristate "Serial port on Open Firmware platform bus"
 	depends on OF
-	depends on SERIAL_8250 || SERIAL_OF_PLATFORM_NWPSERIAL
+	depends on SERIAL_8250 || SERIAL_OF_PLATFORM_NWPSERIAL || SERIAL_PXA
 	help
 	  If you have a PowerPC based system that has serial ports
 	  on a platform specific bus, you should enable this option.
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
index e65f1e8..383bff3 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/of_serial.c
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/serial_core.h>
 #include <linux/serial_8250.h>
+#include <linux/serial_pxa.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
@@ -126,6 +127,11 @@ static int __devinit of_platform_serial_probe(struct platform_device *ofdev)
 		ret = nwpserial_register_port(&port);
 		break;
 #endif
+#ifdef CONFIG_SERIAL_PXA
+	case PORT_PXA:
+		ret = serial_pxa_register_port(&port);
+		break;
+#endif
 	default:
 		/* need to add code for these */
 	case PORT_UNKNOWN:
@@ -163,6 +169,11 @@ static int of_platform_serial_remove(struct platform_device *ofdev)
 		nwpserial_unregister_port(info->line);
 		break;
 #endif
+#ifdef CONFIG_SERIAL_PXA
+	case PORT_PXA:
+		serial_pxa_unregister_port(info->line);
+		break;
+#endif
 	default:
 		/* need to add code for these */
 		break;
@@ -186,6 +197,7 @@ static struct of_device_id __devinitdata of_platform_serial_table[] = {
 	{ .compatible = "ibm,qpace-nwp-serial",
 		.data = (void *)PORT_NWPSERIAL, },
 #endif
+	{ .compatible = "pxa,serial", .data = (void *)PORT_PXA, },
 	{ .type = "serial",         .data = (void *)PORT_UNKNOWN, },
 	{ /* end of list */ },
 };
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index 4302e6e..fb80fb3 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -36,10 +36,12 @@
 #include <linux/circ_buf.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/serial_core.h>
+#include <linux/serial_pxa.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/slab.h>
@@ -51,9 +53,14 @@ struct uart_pxa_port {
 	unsigned char           mcr;
 	unsigned int            lsr_break_flag;
 	struct clk		*clk;
-	char			*name;
+	char			name[32];
+	int			id;
 };
 
+#define PXA_SERIAL_NR		4
+
+static DEFINE_MUTEX(serial_pxa_mutex);
+
 static inline unsigned int serial_in(struct uart_pxa_port *up, int offset)
 {
 	offset <<= 2;
@@ -346,8 +353,6 @@ static int serial_pxa_startup(struct uart_port *port)
 	else
 		up->mcr = 0;
 
-	up->port.uartclk = clk_get_rate(up->clk);
-
 	/*
 	 * Allocate the IRQ
 	 */
@@ -593,7 +598,7 @@ serial_pxa_type(struct uart_port *port)
 	return up->name;
 }
 
-static struct uart_pxa_port *serial_pxa_ports[4];
+static struct uart_pxa_port serial_pxa_ports[PXA_SERIAL_NR];
 static struct uart_driver serial_pxa_reg;
 
 #ifdef CONFIG_SERIAL_PXA_CONSOLE
@@ -645,7 +650,7 @@ static void serial_pxa_console_putchar(struct uart_port *port, int ch)
 static void
 serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
 {
-	struct uart_pxa_port *up = serial_pxa_ports[co->index];
+	struct uart_pxa_port *up = &serial_pxa_ports[co->index];
 	unsigned int ier;
 
 	clk_enable(up->clk);
@@ -679,7 +684,7 @@ serial_pxa_console_setup(struct console *co, char *options)
 
 	if (co->index == -1 || co->index >= serial_pxa_reg.nr)
 		co->index = 0;
-	up = serial_pxa_ports[co->index];
+	up = &serial_pxa_ports[co->index];
 	if (!up)
 		return -ENODEV;
 
@@ -761,6 +766,68 @@ static const struct dev_pm_ops serial_pxa_pm_ops = {
 };
 #endif
 
+static int serial_pxa_port_size(struct uart_pxa_port *sport)
+{
+	return 8 << sport->port.regshift;
+}
+
+int serial_pxa_register_port(struct uart_port *port)
+{
+	struct uart_pxa_port *sport = NULL;
+	char name[32];
+	int i, ret;
+
+	mutex_lock(&serial_pxa_mutex);
+	for (i = 0; i < PXA_SERIAL_NR; i++) {
+		if (serial_pxa_ports[i].id == 0) {
+			sport = &serial_pxa_ports[i];
+			sprintf(sport->name, "UART%d", i);
+			sport->id = i + 1;
+			break;
+		}
+	}
+	sprintf(name, "pxa2xx-uart.%d", i);
+	sport->clk = clk_get_sys(name, NULL);
+	if (IS_ERR(sport->clk)) {
+		ret = PTR_ERR(sport->clk);
+		goto out;
+	}
+	memcpy(&sport->port, port, sizeof(struct uart_port));
+	sport->port.line = i;
+	sport->port.fifosize = 64;
+	sport->port.ops = &serial_pxa_pops;
+
+	sport->port.membase = ioremap(sport->port.mapbase,
+				serial_pxa_port_size(sport));
+	if (!sport->port.membase) {
+		ret = -ENOMEM;
+		goto out_membase;
+	}
+
+	uart_add_one_port(&serial_pxa_reg, &sport->port);
+	mutex_unlock(&serial_pxa_mutex);
+
+	return sport->port.line;
+
+out_membase:
+	clk_put(sport->clk);
+out:
+	mutex_unlock(&serial_pxa_mutex);
+	return ret;
+}
+EXPORT_SYMBOL(serial_pxa_register_port);
+
+void serial_pxa_unregister_port(int line)
+{
+	struct uart_pxa_port *sport = &serial_pxa_ports[line];
+
+	mutex_lock(&serial_pxa_mutex);
+	uart_remove_one_port(&serial_pxa_reg, &sport->port);
+	sport->port.type = PORT_UNKNOWN;
+	clk_put(sport->clk);
+	mutex_unlock(&serial_pxa_mutex);
+}
+
 static int serial_pxa_probe(struct platform_device *dev)
 {
 	struct uart_pxa_port *sport;
@@ -794,12 +861,12 @@ static int serial_pxa_probe(struct platform_device *dev)
 	sport->port.uartclk = clk_get_rate(sport->clk);
 
 	switch (dev->id) {
-	case 0: sport->name = "FFUART"; break;
-	case 1: sport->name = "BTUART"; break;
-	case 2: sport->name = "STUART"; break;
-	case 3: sport->name = "HWUART"; break;
+	case 0: strcpy(sport->name, "FFUART"); break;
+	case 1: strcpy(sport->name, "BTUART"); break;
+	case 2: strcpy(sport->name, "STUART"); break;
+	case 3: strcpy(sport->name, "HWUART"); break;
 	default:
-		sport->name = "???";
+		strcpy(sport->name, "???");
 		break;
 	}
 
@@ -809,8 +876,6 @@ static int serial_pxa_probe(struct platform_device *dev)
 		goto err_clk;
 	}
 
-	serial_pxa_ports[dev->id] = sport;
-
 	uart_add_one_port(&serial_pxa_reg, &sport->port);
 	platform_set_drvdata(dev, sport);
 
diff --git a/include/linux/serial_pxa.h b/include/linux/serial_pxa.h
new file mode 100644
index 0000000..565e510
--- /dev/null
+++ b/include/linux/serial_pxa.h
@@ -0,0 +1,17 @@
+/*
+ *  linux/include/linux/serial_8250.h
+ *
+ *  Marvell Semiconductor Inc.
+ *  Copyright (C) 2011
+ *
+ * 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.
+ */
+#ifndef _LINUX_SERIAL_PXA_H
+#define _LINUX_SERIAL_PXA_H
+
+extern int serial_pxa_register_port(struct uart_port *);
+extern void serial_pxa_unregister_port(int);
+#endif
-- 
1.5.6.5

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

* [PATCH] tty: serial: support device tree in pxa
@ 2011-07-08 10:20         ` Haojian Zhuang
  0 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-08 10:20 UTC (permalink / raw)
  To: linux-arm-kernel

Support both normal platform driver and device tree driver in serial pxa.

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 drivers/tty/serial/Kconfig     |    4 +-
 drivers/tty/serial/of_serial.c |   12 +++++
 drivers/tty/serial/pxa.c       |   91 ++++++++++++++++++++++++++++++++++------
 include/linux/serial_pxa.h     |   17 +++++++
 4 files changed, 110 insertions(+), 14 deletions(-)
 create mode 100644 include/linux/serial_pxa.h

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 636144c..3f75e0d 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -663,6 +663,8 @@ config SERIAL_MPSC_CONSOLE
 config SERIAL_PXA
 	bool "PXA serial port support"
 	depends on ARCH_PXA || ARCH_MMP
+	select SERIAL_OF_PLATFORM
+	select SERIAL_CORE_CONSOLE
 	select SERIAL_CORE
 	help
 	  If you have a machine based on an Intel XScale PXA2xx CPU you
@@ -1340,7 +1342,7 @@ config SERIAL_NETX_CONSOLE
 config SERIAL_OF_PLATFORM
 	tristate "Serial port on Open Firmware platform bus"
 	depends on OF
-	depends on SERIAL_8250 || SERIAL_OF_PLATFORM_NWPSERIAL
+	depends on SERIAL_8250 || SERIAL_OF_PLATFORM_NWPSERIAL || SERIAL_PXA
 	help
 	  If you have a PowerPC based system that has serial ports
 	  on a platform specific bus, you should enable this option.
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
index e65f1e8..383bff3 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/of_serial.c
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/serial_core.h>
 #include <linux/serial_8250.h>
+#include <linux/serial_pxa.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
@@ -126,6 +127,11 @@ static int __devinit of_platform_serial_probe(struct platform_device *ofdev)
 		ret = nwpserial_register_port(&port);
 		break;
 #endif
+#ifdef CONFIG_SERIAL_PXA
+	case PORT_PXA:
+		ret = serial_pxa_register_port(&port);
+		break;
+#endif
 	default:
 		/* need to add code for these */
 	case PORT_UNKNOWN:
@@ -163,6 +169,11 @@ static int of_platform_serial_remove(struct platform_device *ofdev)
 		nwpserial_unregister_port(info->line);
 		break;
 #endif
+#ifdef CONFIG_SERIAL_PXA
+	case PORT_PXA:
+		serial_pxa_unregister_port(info->line);
+		break;
+#endif
 	default:
 		/* need to add code for these */
 		break;
@@ -186,6 +197,7 @@ static struct of_device_id __devinitdata of_platform_serial_table[] = {
 	{ .compatible = "ibm,qpace-nwp-serial",
 		.data = (void *)PORT_NWPSERIAL, },
 #endif
+	{ .compatible = "pxa,serial", .data = (void *)PORT_PXA, },
 	{ .type = "serial",         .data = (void *)PORT_UNKNOWN, },
 	{ /* end of list */ },
 };
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index 4302e6e..fb80fb3 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -36,10 +36,12 @@
 #include <linux/circ_buf.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/serial_core.h>
+#include <linux/serial_pxa.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/slab.h>
@@ -51,9 +53,14 @@ struct uart_pxa_port {
 	unsigned char           mcr;
 	unsigned int            lsr_break_flag;
 	struct clk		*clk;
-	char			*name;
+	char			name[32];
+	int			id;
 };
 
+#define PXA_SERIAL_NR		4
+
+static DEFINE_MUTEX(serial_pxa_mutex);
+
 static inline unsigned int serial_in(struct uart_pxa_port *up, int offset)
 {
 	offset <<= 2;
@@ -346,8 +353,6 @@ static int serial_pxa_startup(struct uart_port *port)
 	else
 		up->mcr = 0;
 
-	up->port.uartclk = clk_get_rate(up->clk);
-
 	/*
 	 * Allocate the IRQ
 	 */
@@ -593,7 +598,7 @@ serial_pxa_type(struct uart_port *port)
 	return up->name;
 }
 
-static struct uart_pxa_port *serial_pxa_ports[4];
+static struct uart_pxa_port serial_pxa_ports[PXA_SERIAL_NR];
 static struct uart_driver serial_pxa_reg;
 
 #ifdef CONFIG_SERIAL_PXA_CONSOLE
@@ -645,7 +650,7 @@ static void serial_pxa_console_putchar(struct uart_port *port, int ch)
 static void
 serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
 {
-	struct uart_pxa_port *up = serial_pxa_ports[co->index];
+	struct uart_pxa_port *up = &serial_pxa_ports[co->index];
 	unsigned int ier;
 
 	clk_enable(up->clk);
@@ -679,7 +684,7 @@ serial_pxa_console_setup(struct console *co, char *options)
 
 	if (co->index == -1 || co->index >= serial_pxa_reg.nr)
 		co->index = 0;
-	up = serial_pxa_ports[co->index];
+	up = &serial_pxa_ports[co->index];
 	if (!up)
 		return -ENODEV;
 
@@ -761,6 +766,68 @@ static const struct dev_pm_ops serial_pxa_pm_ops = {
 };
 #endif
 
+static int serial_pxa_port_size(struct uart_pxa_port *sport)
+{
+	return 8 << sport->port.regshift;
+}
+
+int serial_pxa_register_port(struct uart_port *port)
+{
+	struct uart_pxa_port *sport = NULL;
+	char name[32];
+	int i, ret;
+
+	mutex_lock(&serial_pxa_mutex);
+	for (i = 0; i < PXA_SERIAL_NR; i++) {
+		if (serial_pxa_ports[i].id == 0) {
+			sport = &serial_pxa_ports[i];
+			sprintf(sport->name, "UART%d", i);
+			sport->id = i + 1;
+			break;
+		}
+	}
+	sprintf(name, "pxa2xx-uart.%d", i);
+	sport->clk = clk_get_sys(name, NULL);
+	if (IS_ERR(sport->clk)) {
+		ret = PTR_ERR(sport->clk);
+		goto out;
+	}
+	memcpy(&sport->port, port, sizeof(struct uart_port));
+	sport->port.line = i;
+	sport->port.fifosize = 64;
+	sport->port.ops = &serial_pxa_pops;
+
+	sport->port.membase = ioremap(sport->port.mapbase,
+				serial_pxa_port_size(sport));
+	if (!sport->port.membase) {
+		ret = -ENOMEM;
+		goto out_membase;
+	}
+
+	uart_add_one_port(&serial_pxa_reg, &sport->port);
+	mutex_unlock(&serial_pxa_mutex);
+
+	return sport->port.line;
+
+out_membase:
+	clk_put(sport->clk);
+out:
+	mutex_unlock(&serial_pxa_mutex);
+	return ret;
+}
+EXPORT_SYMBOL(serial_pxa_register_port);
+
+void serial_pxa_unregister_port(int line)
+{
+	struct uart_pxa_port *sport = &serial_pxa_ports[line];
+
+	mutex_lock(&serial_pxa_mutex);
+	uart_remove_one_port(&serial_pxa_reg, &sport->port);
+	sport->port.type = PORT_UNKNOWN;
+	clk_put(sport->clk);
+	mutex_unlock(&serial_pxa_mutex);
+}
+
 static int serial_pxa_probe(struct platform_device *dev)
 {
 	struct uart_pxa_port *sport;
@@ -794,12 +861,12 @@ static int serial_pxa_probe(struct platform_device *dev)
 	sport->port.uartclk = clk_get_rate(sport->clk);
 
 	switch (dev->id) {
-	case 0: sport->name = "FFUART"; break;
-	case 1: sport->name = "BTUART"; break;
-	case 2: sport->name = "STUART"; break;
-	case 3: sport->name = "HWUART"; break;
+	case 0: strcpy(sport->name, "FFUART"); break;
+	case 1: strcpy(sport->name, "BTUART"); break;
+	case 2: strcpy(sport->name, "STUART"); break;
+	case 3: strcpy(sport->name, "HWUART"); break;
 	default:
-		sport->name = "???";
+		strcpy(sport->name, "???");
 		break;
 	}
 
@@ -809,8 +876,6 @@ static int serial_pxa_probe(struct platform_device *dev)
 		goto err_clk;
 	}
 
-	serial_pxa_ports[dev->id] = sport;
-
 	uart_add_one_port(&serial_pxa_reg, &sport->port);
 	platform_set_drvdata(dev, sport);
 
diff --git a/include/linux/serial_pxa.h b/include/linux/serial_pxa.h
new file mode 100644
index 0000000..565e510
--- /dev/null
+++ b/include/linux/serial_pxa.h
@@ -0,0 +1,17 @@
+/*
+ *  linux/include/linux/serial_8250.h
+ *
+ *  Marvell Semiconductor Inc.
+ *  Copyright (C) 2011
+ *
+ * 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.
+ */
+#ifndef _LINUX_SERIAL_PXA_H
+#define _LINUX_SERIAL_PXA_H
+
+extern int serial_pxa_register_port(struct uart_port *);
+extern void serial_pxa_unregister_port(int);
+#endif
-- 
1.5.6.5

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

* [PATCH] tty: serial: check ops before registering console
  2011-07-08 10:20         ` Haojian Zhuang
@ 2011-07-08 10:20           ` Haojian Zhuang
  -1 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-08 10:20 UTC (permalink / raw)
  To: grant.likely, linux-arm-kernel, devicetree-discuss,
	haojian.zhuang, nico, samuel.ortiz, broonie
  Cc: Haojian Zhuang

Console should be only registered after port->ops assigned. If uart console
doesn't match the current uart, port->ops keeps NULL.

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 drivers/tty/serial/pxa.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index fb80fb3..b117fab 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -685,7 +685,7 @@ serial_pxa_console_setup(struct console *co, char *options)
 	if (co->index == -1 || co->index >= serial_pxa_reg.nr)
 		co->index = 0;
 	up = &serial_pxa_ports[co->index];
-	if (!up)
+	if (!up || !up->port.ops)
 		return -ENODEV;
 
 	if (options)
-- 
1.5.6.5

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

* [PATCH] tty: serial: check ops before registering console
@ 2011-07-08 10:20           ` Haojian Zhuang
  0 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-08 10:20 UTC (permalink / raw)
  To: linux-arm-kernel

Console should be only registered after port->ops assigned. If uart console
doesn't match the current uart, port->ops keeps NULL.

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 drivers/tty/serial/pxa.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index fb80fb3..b117fab 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -685,7 +685,7 @@ serial_pxa_console_setup(struct console *co, char *options)
 	if (co->index == -1 || co->index >= serial_pxa_reg.nr)
 		co->index = 0;
 	up = &serial_pxa_ports[co->index];
-	if (!up)
+	if (!up || !up->port.ops)
 		return -ENODEV;
 
 	if (options)
-- 
1.5.6.5

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

* [PATCH] i2c: pxa: create dynamic platform device from device tree
  2011-07-08 10:20           ` Haojian Zhuang
@ 2011-07-08 10:20             ` Haojian Zhuang
  -1 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-08 10:20 UTC (permalink / raw)
  To: grant.likely, linux-arm-kernel, devicetree-discuss,
	haojian.zhuang, nico, samuel.ortiz, broonie
  Cc: Haojian Zhuang

Create two probe function to support both current platform device and created
dynamic platform device from device tree. After moving to device tree,
original implementation of platform device will be removed.

Use property to present polling mode and frequency mode.

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 drivers/i2c/busses/i2c-pxa.c |  163 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 163 insertions(+), 0 deletions(-)

diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index d603646..7a6d774 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -29,6 +29,7 @@
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/i2c-pxa.h>
+#include <linux/of_device.h>
 #include <linux/of_i2c.h>
 #include <linux/platform_device.h>
 #include <linux/err.h>
@@ -1044,6 +1045,162 @@ static const struct i2c_algorithm i2c_pxa_pio_algorithm = {
 	.functionality	= i2c_pxa_functionality,
 };
 
+static const struct of_device_id pxa_i2c_of_match[] = {
+	{ .compatible = "pxa2xx-i2c",	.data = (void *)REGS_PXA2XX, },
+	{ .compatible = "pxa3xx-pwri2c", .data = (void *)REGS_PXA3XX, },
+	{ .compatible = "ce4100-i2c",	.data = (void *)REGS_CE4100, },
+	{},
+};
+
+#ifdef CONFIG_OF
+static int i2c_pxa_of_probe(struct platform_device *of_dev)
+{
+	struct device_node *np = of_dev->dev.of_node;
+	const struct of_device_id *match;
+	struct i2c_pxa_platform_data *plat = NULL;
+	struct pxa_i2c *i2c;
+	struct resource *res;
+	const __be32 *p;
+	int i2c_type, irq, data, ret;
+	int id = 0, poll = 0, fast = 0;
+
+	match = of_match_device(pxa_i2c_of_match, &of_dev->dev);
+	if (match == NULL)
+		return -ENODEV;
+	i2c_type = (int)match->data;
+
+	p = of_get_property(np, "cell-index", &data);
+	if (p)
+		id = be32_to_cpu(*p);
+
+	p = of_get_property(np, "i2c-polling", &data);
+	if (p)
+		poll = be32_to_cpu(*p);
+
+	p = of_get_property(np, "i2c-frequency", &data);
+	if (p && !strncmp((char *)p, "fast", data))
+		fast = 1;
+
+	res = platform_get_resource(of_dev, IORESOURCE_MEM, 0);
+	irq = platform_get_irq(of_dev, 0);
+	if (res == NULL || irq < 0)
+		return -ENODEV;
+
+	if (!request_mem_region(res->start, resource_size(res), res->name))
+		return -ENOMEM;
+
+	i2c = kzalloc(sizeof(struct pxa_i2c), GFP_KERNEL);
+	if (!i2c) {
+		ret = -ENOMEM;
+		goto emalloc;
+	}
+
+	i2c->adap.owner   = THIS_MODULE;
+	i2c->adap.retries = 5;
+
+	spin_lock_init(&i2c->lock);
+	init_waitqueue_head(&i2c->wait);
+
+	/*
+	 * adap.nr comes from cell-index in dts file
+	 */
+	i2c->adap.nr = id;
+	snprintf(i2c->adap.name, sizeof(i2c->adap.name), "pxa2xx-i2c.%u",
+		 i2c->adap.nr);
+
+	i2c->clk = clk_get_sys(i2c->adap.name, NULL);
+	if (IS_ERR(i2c->clk)) {
+		ret = PTR_ERR(i2c->clk);
+		goto eclk;
+	}
+
+	i2c->reg_base = ioremap(res->start, resource_size(res));
+	if (!i2c->reg_base) {
+		ret = -EIO;
+		goto eremap;
+	}
+
+	i2c->reg_ibmr = i2c->reg_base + pxa_reg_layout[i2c_type].ibmr;
+	i2c->reg_idbr = i2c->reg_base + pxa_reg_layout[i2c_type].idbr;
+	i2c->reg_icr = i2c->reg_base + pxa_reg_layout[i2c_type].icr;
+	i2c->reg_isr = i2c->reg_base + pxa_reg_layout[i2c_type].isr;
+	if (i2c_type != REGS_CE4100)
+		i2c->reg_isar = i2c->reg_base + pxa_reg_layout[i2c_type].isar;
+
+	i2c->iobase = res->start;
+	i2c->iosize = resource_size(res);
+
+	i2c->irq = irq;
+	i2c->use_pio = poll;
+	i2c->fast_mode = fast;
+
+	i2c->slave_addr = I2C_PXA_SLAVE_ADDR;
+
+#ifdef CONFIG_I2C_PXA_SLAVE
+	if (plat) {
+		i2c->slave_addr = plat->slave_addr;
+		i2c->slave = plat->slave;
+	}
+#endif
+
+	clk_enable(i2c->clk);
+
+	if (plat)
+		i2c->adap.class = plat->class;
+
+	if (i2c->use_pio) {
+		i2c->adap.algo = &i2c_pxa_pio_algorithm;
+	} else {
+		i2c->adap.algo = &i2c_pxa_algorithm;
+		ret = request_irq(irq, i2c_pxa_handler, IRQF_SHARED,
+				  i2c->adap.name, i2c);
+		if (ret)
+			goto ereqirq;
+	}
+
+	i2c_pxa_reset(i2c);
+
+	i2c->adap.algo_data = i2c;
+	i2c->adap.dev.parent = &of_dev->dev;
+	i2c->adap.dev.of_node = of_dev->dev.of_node;
+
+	if (i2c_type == REGS_CE4100)
+		ret = i2c_add_adapter(&i2c->adap);
+	else
+		ret = i2c_add_numbered_adapter(&i2c->adap);
+	if (ret < 0) {
+		printk(KERN_INFO "I2C: Failed to add bus\n");
+		goto eadapt;
+	}
+	of_i2c_register_devices(&i2c->adap);
+
+	platform_set_drvdata(of_dev, i2c);
+
+#ifdef CONFIG_I2C_PXA_SLAVE
+	printk(KERN_INFO "I2C: %s: PXA I2C adapter, slave address %d\n",
+	       dev_name(&i2c->adap.dev), i2c->slave_addr);
+#else
+	printk(KERN_INFO "I2C: %s: PXA I2C adapter\n",
+	       dev_name(&i2c->adap.dev));
+#endif
+	return 0;
+
+eadapt:
+	if (!i2c->use_pio)
+		free_irq(irq, i2c);
+ereqirq:
+	clk_disable(i2c->clk);
+	iounmap(i2c->reg_base);
+eremap:
+	clk_put(i2c->clk);
+eclk:
+	kfree(i2c);
+emalloc:
+	release_mem_region(res->start, resource_size(res));
+	return ret;
+}
+#else
+
 static int i2c_pxa_probe(struct platform_device *dev)
 {
 	struct pxa_i2c *i2c;
@@ -1174,6 +1331,7 @@ emalloc:
 	release_mem_region(res->start, resource_size(res));
 	return ret;
 }
+#endif
 
 static int __exit i2c_pxa_remove(struct platform_device *dev)
 {
@@ -1228,12 +1386,17 @@ static const struct dev_pm_ops i2c_pxa_dev_pm_ops = {
 #endif
 
 static struct platform_driver i2c_pxa_driver = {
+#ifdef CONFIG_OF
+	.probe		= i2c_pxa_of_probe,
+#else
 	.probe		= i2c_pxa_probe,
+#endif
 	.remove		= __exit_p(i2c_pxa_remove),
 	.driver		= {
 		.name	= "pxa2xx-i2c",
 		.owner	= THIS_MODULE,
 		.pm	= I2C_PXA_DEV_PM_OPS,
+		.of_match_table	= pxa_i2c_of_match,
 	},
 	.id_table	= i2c_pxa_id_table,
 };
-- 
1.5.6.5

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

* [PATCH] i2c: pxa: create dynamic platform device from device tree
@ 2011-07-08 10:20             ` Haojian Zhuang
  0 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-08 10:20 UTC (permalink / raw)
  To: linux-arm-kernel

Create two probe function to support both current platform device and created
dynamic platform device from device tree. After moving to device tree,
original implementation of platform device will be removed.

Use property to present polling mode and frequency mode.

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 drivers/i2c/busses/i2c-pxa.c |  163 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 163 insertions(+), 0 deletions(-)

diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index d603646..7a6d774 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -29,6 +29,7 @@
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/i2c-pxa.h>
+#include <linux/of_device.h>
 #include <linux/of_i2c.h>
 #include <linux/platform_device.h>
 #include <linux/err.h>
@@ -1044,6 +1045,162 @@ static const struct i2c_algorithm i2c_pxa_pio_algorithm = {
 	.functionality	= i2c_pxa_functionality,
 };
 
+static const struct of_device_id pxa_i2c_of_match[] = {
+	{ .compatible = "pxa2xx-i2c",	.data = (void *)REGS_PXA2XX, },
+	{ .compatible = "pxa3xx-pwri2c", .data = (void *)REGS_PXA3XX, },
+	{ .compatible = "ce4100-i2c",	.data = (void *)REGS_CE4100, },
+	{},
+};
+
+#ifdef CONFIG_OF
+static int i2c_pxa_of_probe(struct platform_device *of_dev)
+{
+	struct device_node *np = of_dev->dev.of_node;
+	const struct of_device_id *match;
+	struct i2c_pxa_platform_data *plat = NULL;
+	struct pxa_i2c *i2c;
+	struct resource *res;
+	const __be32 *p;
+	int i2c_type, irq, data, ret;
+	int id = 0, poll = 0, fast = 0;
+
+	match = of_match_device(pxa_i2c_of_match, &of_dev->dev);
+	if (match == NULL)
+		return -ENODEV;
+	i2c_type = (int)match->data;
+
+	p = of_get_property(np, "cell-index", &data);
+	if (p)
+		id = be32_to_cpu(*p);
+
+	p = of_get_property(np, "i2c-polling", &data);
+	if (p)
+		poll = be32_to_cpu(*p);
+
+	p = of_get_property(np, "i2c-frequency", &data);
+	if (p && !strncmp((char *)p, "fast", data))
+		fast = 1;
+
+	res = platform_get_resource(of_dev, IORESOURCE_MEM, 0);
+	irq = platform_get_irq(of_dev, 0);
+	if (res == NULL || irq < 0)
+		return -ENODEV;
+
+	if (!request_mem_region(res->start, resource_size(res), res->name))
+		return -ENOMEM;
+
+	i2c = kzalloc(sizeof(struct pxa_i2c), GFP_KERNEL);
+	if (!i2c) {
+		ret = -ENOMEM;
+		goto emalloc;
+	}
+
+	i2c->adap.owner   = THIS_MODULE;
+	i2c->adap.retries = 5;
+
+	spin_lock_init(&i2c->lock);
+	init_waitqueue_head(&i2c->wait);
+
+	/*
+	 * adap.nr comes from cell-index in dts file
+	 */
+	i2c->adap.nr = id;
+	snprintf(i2c->adap.name, sizeof(i2c->adap.name), "pxa2xx-i2c.%u",
+		 i2c->adap.nr);
+
+	i2c->clk = clk_get_sys(i2c->adap.name, NULL);
+	if (IS_ERR(i2c->clk)) {
+		ret = PTR_ERR(i2c->clk);
+		goto eclk;
+	}
+
+	i2c->reg_base = ioremap(res->start, resource_size(res));
+	if (!i2c->reg_base) {
+		ret = -EIO;
+		goto eremap;
+	}
+
+	i2c->reg_ibmr = i2c->reg_base + pxa_reg_layout[i2c_type].ibmr;
+	i2c->reg_idbr = i2c->reg_base + pxa_reg_layout[i2c_type].idbr;
+	i2c->reg_icr = i2c->reg_base + pxa_reg_layout[i2c_type].icr;
+	i2c->reg_isr = i2c->reg_base + pxa_reg_layout[i2c_type].isr;
+	if (i2c_type != REGS_CE4100)
+		i2c->reg_isar = i2c->reg_base + pxa_reg_layout[i2c_type].isar;
+
+	i2c->iobase = res->start;
+	i2c->iosize = resource_size(res);
+
+	i2c->irq = irq;
+	i2c->use_pio = poll;
+	i2c->fast_mode = fast;
+
+	i2c->slave_addr = I2C_PXA_SLAVE_ADDR;
+
+#ifdef CONFIG_I2C_PXA_SLAVE
+	if (plat) {
+		i2c->slave_addr = plat->slave_addr;
+		i2c->slave = plat->slave;
+	}
+#endif
+
+	clk_enable(i2c->clk);
+
+	if (plat)
+		i2c->adap.class = plat->class;
+
+	if (i2c->use_pio) {
+		i2c->adap.algo = &i2c_pxa_pio_algorithm;
+	} else {
+		i2c->adap.algo = &i2c_pxa_algorithm;
+		ret = request_irq(irq, i2c_pxa_handler, IRQF_SHARED,
+				  i2c->adap.name, i2c);
+		if (ret)
+			goto ereqirq;
+	}
+
+	i2c_pxa_reset(i2c);
+
+	i2c->adap.algo_data = i2c;
+	i2c->adap.dev.parent = &of_dev->dev;
+	i2c->adap.dev.of_node = of_dev->dev.of_node;
+
+	if (i2c_type == REGS_CE4100)
+		ret = i2c_add_adapter(&i2c->adap);
+	else
+		ret = i2c_add_numbered_adapter(&i2c->adap);
+	if (ret < 0) {
+		printk(KERN_INFO "I2C: Failed to add bus\n");
+		goto eadapt;
+	}
+	of_i2c_register_devices(&i2c->adap);
+
+	platform_set_drvdata(of_dev, i2c);
+
+#ifdef CONFIG_I2C_PXA_SLAVE
+	printk(KERN_INFO "I2C: %s: PXA I2C adapter, slave address %d\n",
+	       dev_name(&i2c->adap.dev), i2c->slave_addr);
+#else
+	printk(KERN_INFO "I2C: %s: PXA I2C adapter\n",
+	       dev_name(&i2c->adap.dev));
+#endif
+	return 0;
+
+eadapt:
+	if (!i2c->use_pio)
+		free_irq(irq, i2c);
+ereqirq:
+	clk_disable(i2c->clk);
+	iounmap(i2c->reg_base);
+eremap:
+	clk_put(i2c->clk);
+eclk:
+	kfree(i2c);
+emalloc:
+	release_mem_region(res->start, resource_size(res));
+	return ret;
+}
+#else
+
 static int i2c_pxa_probe(struct platform_device *dev)
 {
 	struct pxa_i2c *i2c;
@@ -1174,6 +1331,7 @@ emalloc:
 	release_mem_region(res->start, resource_size(res));
 	return ret;
 }
+#endif
 
 static int __exit i2c_pxa_remove(struct platform_device *dev)
 {
@@ -1228,12 +1386,17 @@ static const struct dev_pm_ops i2c_pxa_dev_pm_ops = {
 #endif
 
 static struct platform_driver i2c_pxa_driver = {
+#ifdef CONFIG_OF
+	.probe		= i2c_pxa_of_probe,
+#else
 	.probe		= i2c_pxa_probe,
+#endif
 	.remove		= __exit_p(i2c_pxa_remove),
 	.driver		= {
 		.name	= "pxa2xx-i2c",
 		.owner	= THIS_MODULE,
 		.pm	= I2C_PXA_DEV_PM_OPS,
+		.of_match_table	= pxa_i2c_of_match,
 	},
 	.id_table	= i2c_pxa_id_table,
 };
-- 
1.5.6.5

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

* [PATCH] of: add devicetree API for regulator
  2011-07-08 10:20             ` Haojian Zhuang
@ 2011-07-08 10:20               ` Haojian Zhuang
  -1 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-08 10:20 UTC (permalink / raw)
  To: grant.likely, linux-arm-kernel, devicetree-discuss,
	haojian.zhuang, nico, samuel.ortiz, broonie
  Cc: Haojian Zhuang

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 drivers/of/Kconfig           |    4 +
 drivers/of/Makefile          |    1 +
 drivers/of/of_regulator.c    |  166 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/of_regulator.h |   34 +++++++++
 4 files changed, 205 insertions(+), 0 deletions(-)
 create mode 100644 drivers/of/of_regulator.c
 create mode 100644 include/linux/of_regulator.h

diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index d06a637..edb6601 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -75,4 +75,8 @@ config OF_PCI
 	help
 	  OpenFirmware PCI bus accessors
 
+config OF_REGULATOR
+	def_tristate REGULATOR
+	depends on REGULATOR
+
 endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index f7861ed..83ca06f 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_OF_NET)	+= of_net.o
 obj-$(CONFIG_OF_SPI)	+= of_spi.o
 obj-$(CONFIG_OF_MDIO)	+= of_mdio.o
 obj-$(CONFIG_OF_PCI)	+= of_pci.o
+obj-$(CONFIG_OF_REGULATOR)	+= of_regulator.o
diff --git a/drivers/of/of_regulator.c b/drivers/of/of_regulator.c
new file mode 100644
index 0000000..d523302
--- /dev/null
+++ b/drivers/of/of_regulator.c
@@ -0,0 +1,166 @@
+/*
+ * OF helpers for the Regulator API
+ *
+ * Copyright (c) 2011 Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/regulator/machine.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/suspend.h>
+
+static int of_regulator_init_constraints(struct device_node *of_dev,
+				struct regulation_constraints *constraints)
+{
+	const __be32 *p;
+	const char *cp;
+	const char *ops[] = {"voltage", "current", "mode", "status",
+				"drms"};
+	int i, size, len = 0, tmp = 0;
+
+	memset(constraints, 0, sizeof(struct regulation_constraints));
+
+	p = of_get_property(of_dev, "voltages", &size);
+	if (p && size / sizeof(int) == 2) {
+		constraints->min_uV = be32_to_cpu(*p++);
+		constraints->max_uV = be32_to_cpu(*p);
+	}
+	p = of_get_property(of_dev, "currents", &size);
+	if (p && size / sizeof(int) == 2) {
+		constraints->min_uA = be32_to_cpu(*p++);
+		constraints->max_uA = be32_to_cpu(*p);
+	}
+	p = of_get_property(of_dev, "modes-mask", NULL);
+	if (p)
+		constraints->valid_modes_mask = be32_to_cpu(*p);
+	cp = of_get_property(of_dev, "ops-mask", &size);
+	tmp = 0;
+	if (cp && size > 0) {
+		i = 0;
+		do {
+			len = strlen(ops[i]);
+			if (!strncmp(cp, ops[i], len)) {
+				constraints->valid_ops_mask |= 1 << i;
+				/* need to handle '\0' */
+				cp += len + 1;
+				size = size - len - 1;
+				i = 0;
+			} else
+				i++;
+		} while (i < ARRAY_SIZE(ops));
+		if (size > 0)
+			printk(KERN_WARNING "Invalid string:%s\n", cp);
+	}
+	p = of_get_property(of_dev, "input-uV", NULL);
+	if (p)
+		constraints->input_uV = be32_to_cpu(*p);
+	p = of_get_property(of_dev, "state-pm-disk", &size);
+	if (p && size / sizeof(int) == 3) {
+		constraints->state_disk.uV = be32_to_cpu(*p++);
+		constraints->state_disk.mode = be32_to_cpu(*p++);
+		tmp = be32_to_cpu(*p);
+		constraints->state_disk.enabled = (tmp) ? 1 : 0;
+		constraints->state_disk.disabled = (tmp) ? 0 : 1;
+	}
+	p = of_get_property(of_dev, "state-pm-mem", &size);
+	if (p && size / sizeof(int) == 3) {
+		constraints->state_mem.uV = be32_to_cpu(*p++);
+		constraints->state_mem.mode = be32_to_cpu(*p++);
+		tmp = be32_to_cpu(*p);
+		constraints->state_mem.enabled = (tmp) ? 1 : 0;
+		constraints->state_mem.disabled = (tmp) ? 0 : 1;
+	}
+	p = of_get_property(of_dev, "state-pm-standby", &size);
+	if (p && size / sizeof(int) == 3) {
+		constraints->state_standby.uV = be32_to_cpu(*p++);
+		constraints->state_standby.mode = be32_to_cpu(*p++);
+		tmp = be32_to_cpu(*p);
+		constraints->state_standby.enabled = (tmp) ? 1 : 0;
+		constraints->state_standby.disabled = (tmp) ? 0 : 1;
+	}
+	cp = of_get_property(of_dev, "initial-state", &size);
+	if (cp) {
+		if (!strncmp(cp, "pm-suspend-on", size))
+			constraints->initial_state = PM_SUSPEND_ON;
+		if (!strncmp(cp, "pm-suspend-mem", size))
+			constraints->initial_state = PM_SUSPEND_MEM;
+		if (!strncmp(cp, "pm-suspend-standby", size))
+			constraints->initial_state = PM_SUSPEND_STANDBY;
+	}
+	p = of_get_property(of_dev, "initial_mode", NULL);
+	if (p)
+		constraints->initial_mode = be32_to_cpu(*p);
+	p = of_get_property(of_dev, "always-on", NULL);
+	if (p)
+		constraints->always_on = 1;
+	p = of_get_property(of_dev, "boot-on", NULL);
+	if (p)
+		constraints->boot_on = 1;
+	p = of_get_property(of_dev, "apply-uV", NULL);
+	if (p)
+		constraints->apply_uV = 1;
+	return 0;
+}
+
+int of_regulator_init_data(struct device_node *of_dev,
+			struct regulator_init_data *data)
+{
+	struct regulator_consumer_supply *supply;
+	const char *p, *str;
+	int ret, i, size, calc_size, len, count = 0;
+
+	if (of_dev == NULL || data == NULL)
+		return -EINVAL;
+
+	p = of_get_property(of_dev, "device_type", &size);
+	if (p == NULL || strncmp(p, "regulator", size))
+		return -EINVAL;
+
+	ret = of_regulator_init_constraints(of_dev, &data->constraints);
+	if (ret)
+		return ret;
+	p = of_get_property(of_dev, "supply-name", &size);
+	str = p;
+	calc_size = size;
+	while (str && calc_size > 0) {
+		len = strlen(str);
+		if (len == 0)
+			break;
+		calc_size = calc_size - len - 1;
+		str += len + 1;
+		count++;
+	}
+	if (count == 0)
+		return -EINVAL;
+
+	supply = kzalloc(sizeof(struct regulator_consumer_supply) * count,
+		GFP_KERNEL);
+	if (supply == NULL)
+		return -EINVAL;
+	str = p;
+	calc_size = size;
+	i = 0;
+	while (str && calc_size > 0 && i < count) {
+		len = strlen(str);
+		if (len == 0)
+			break;
+		supply[i++].supply = str;
+		calc_size = calc_size - len - 1;
+		str += len + 1;
+	}
+	data->consumer_supplies = supply;
+	data->num_consumer_supplies = count;
+	return 0;
+}
+
+void of_regulator_deinit_data(struct regulator_init_data *data)
+{
+	if (data && data->consumer_supplies)
+		kfree(data->consumer_supplies);
+}
diff --git a/include/linux/of_regulator.h b/include/linux/of_regulator.h
new file mode 100644
index 0000000..0155bd8
--- /dev/null
+++ b/include/linux/of_regulator.h
@@ -0,0 +1,34 @@
+/*
+ * Generic Regulator API implementation
+ *
+ * Copyright (c) 2011 Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __LINUX_OF_REGULATOR_H
+#define __LINUX_OF_REGULATOR_H
+
+#if defined(CONFIG_OF_REGULATOR) || defined(CONFIG_OF_REGULATOR_MODULE)
+#include <linux/regulator/machine.h>
+
+extern int of_regulator_init_data(struct device_node *of_node,
+				struct regulator_init_data *data);
+extern void of_regulator_deinit_data(struct regulator_init_data *data);
+
+#else
+static inline int of_regulator_init_data(struct device_node *of_node,
+				struct regulator_init_data *data)
+{
+	return 0;
+}
+
+static inline void of_regulator_deinit_data(struct regulator_init_data *data)
+{
+}
+#endif	/* CONFIG_OF_REGULATOR */
+
+#endif	/* __LINUX_OF_REGULATOR_H */
-- 
1.5.6.5

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

* [PATCH] of: add devicetree API for regulator
@ 2011-07-08 10:20               ` Haojian Zhuang
  0 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-08 10:20 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 drivers/of/Kconfig           |    4 +
 drivers/of/Makefile          |    1 +
 drivers/of/of_regulator.c    |  166 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/of_regulator.h |   34 +++++++++
 4 files changed, 205 insertions(+), 0 deletions(-)
 create mode 100644 drivers/of/of_regulator.c
 create mode 100644 include/linux/of_regulator.h

diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index d06a637..edb6601 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -75,4 +75,8 @@ config OF_PCI
 	help
 	  OpenFirmware PCI bus accessors
 
+config OF_REGULATOR
+	def_tristate REGULATOR
+	depends on REGULATOR
+
 endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index f7861ed..83ca06f 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_OF_NET)	+= of_net.o
 obj-$(CONFIG_OF_SPI)	+= of_spi.o
 obj-$(CONFIG_OF_MDIO)	+= of_mdio.o
 obj-$(CONFIG_OF_PCI)	+= of_pci.o
+obj-$(CONFIG_OF_REGULATOR)	+= of_regulator.o
diff --git a/drivers/of/of_regulator.c b/drivers/of/of_regulator.c
new file mode 100644
index 0000000..d523302
--- /dev/null
+++ b/drivers/of/of_regulator.c
@@ -0,0 +1,166 @@
+/*
+ * OF helpers for the Regulator API
+ *
+ * Copyright (c) 2011 Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/regulator/machine.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/suspend.h>
+
+static int of_regulator_init_constraints(struct device_node *of_dev,
+				struct regulation_constraints *constraints)
+{
+	const __be32 *p;
+	const char *cp;
+	const char *ops[] = {"voltage", "current", "mode", "status",
+				"drms"};
+	int i, size, len = 0, tmp = 0;
+
+	memset(constraints, 0, sizeof(struct regulation_constraints));
+
+	p = of_get_property(of_dev, "voltages", &size);
+	if (p && size / sizeof(int) == 2) {
+		constraints->min_uV = be32_to_cpu(*p++);
+		constraints->max_uV = be32_to_cpu(*p);
+	}
+	p = of_get_property(of_dev, "currents", &size);
+	if (p && size / sizeof(int) == 2) {
+		constraints->min_uA = be32_to_cpu(*p++);
+		constraints->max_uA = be32_to_cpu(*p);
+	}
+	p = of_get_property(of_dev, "modes-mask", NULL);
+	if (p)
+		constraints->valid_modes_mask = be32_to_cpu(*p);
+	cp = of_get_property(of_dev, "ops-mask", &size);
+	tmp = 0;
+	if (cp && size > 0) {
+		i = 0;
+		do {
+			len = strlen(ops[i]);
+			if (!strncmp(cp, ops[i], len)) {
+				constraints->valid_ops_mask |= 1 << i;
+				/* need to handle '\0' */
+				cp += len + 1;
+				size = size - len - 1;
+				i = 0;
+			} else
+				i++;
+		} while (i < ARRAY_SIZE(ops));
+		if (size > 0)
+			printk(KERN_WARNING "Invalid string:%s\n", cp);
+	}
+	p = of_get_property(of_dev, "input-uV", NULL);
+	if (p)
+		constraints->input_uV = be32_to_cpu(*p);
+	p = of_get_property(of_dev, "state-pm-disk", &size);
+	if (p && size / sizeof(int) == 3) {
+		constraints->state_disk.uV = be32_to_cpu(*p++);
+		constraints->state_disk.mode = be32_to_cpu(*p++);
+		tmp = be32_to_cpu(*p);
+		constraints->state_disk.enabled = (tmp) ? 1 : 0;
+		constraints->state_disk.disabled = (tmp) ? 0 : 1;
+	}
+	p = of_get_property(of_dev, "state-pm-mem", &size);
+	if (p && size / sizeof(int) == 3) {
+		constraints->state_mem.uV = be32_to_cpu(*p++);
+		constraints->state_mem.mode = be32_to_cpu(*p++);
+		tmp = be32_to_cpu(*p);
+		constraints->state_mem.enabled = (tmp) ? 1 : 0;
+		constraints->state_mem.disabled = (tmp) ? 0 : 1;
+	}
+	p = of_get_property(of_dev, "state-pm-standby", &size);
+	if (p && size / sizeof(int) == 3) {
+		constraints->state_standby.uV = be32_to_cpu(*p++);
+		constraints->state_standby.mode = be32_to_cpu(*p++);
+		tmp = be32_to_cpu(*p);
+		constraints->state_standby.enabled = (tmp) ? 1 : 0;
+		constraints->state_standby.disabled = (tmp) ? 0 : 1;
+	}
+	cp = of_get_property(of_dev, "initial-state", &size);
+	if (cp) {
+		if (!strncmp(cp, "pm-suspend-on", size))
+			constraints->initial_state = PM_SUSPEND_ON;
+		if (!strncmp(cp, "pm-suspend-mem", size))
+			constraints->initial_state = PM_SUSPEND_MEM;
+		if (!strncmp(cp, "pm-suspend-standby", size))
+			constraints->initial_state = PM_SUSPEND_STANDBY;
+	}
+	p = of_get_property(of_dev, "initial_mode", NULL);
+	if (p)
+		constraints->initial_mode = be32_to_cpu(*p);
+	p = of_get_property(of_dev, "always-on", NULL);
+	if (p)
+		constraints->always_on = 1;
+	p = of_get_property(of_dev, "boot-on", NULL);
+	if (p)
+		constraints->boot_on = 1;
+	p = of_get_property(of_dev, "apply-uV", NULL);
+	if (p)
+		constraints->apply_uV = 1;
+	return 0;
+}
+
+int of_regulator_init_data(struct device_node *of_dev,
+			struct regulator_init_data *data)
+{
+	struct regulator_consumer_supply *supply;
+	const char *p, *str;
+	int ret, i, size, calc_size, len, count = 0;
+
+	if (of_dev == NULL || data == NULL)
+		return -EINVAL;
+
+	p = of_get_property(of_dev, "device_type", &size);
+	if (p == NULL || strncmp(p, "regulator", size))
+		return -EINVAL;
+
+	ret = of_regulator_init_constraints(of_dev, &data->constraints);
+	if (ret)
+		return ret;
+	p = of_get_property(of_dev, "supply-name", &size);
+	str = p;
+	calc_size = size;
+	while (str && calc_size > 0) {
+		len = strlen(str);
+		if (len == 0)
+			break;
+		calc_size = calc_size - len - 1;
+		str += len + 1;
+		count++;
+	}
+	if (count == 0)
+		return -EINVAL;
+
+	supply = kzalloc(sizeof(struct regulator_consumer_supply) * count,
+		GFP_KERNEL);
+	if (supply == NULL)
+		return -EINVAL;
+	str = p;
+	calc_size = size;
+	i = 0;
+	while (str && calc_size > 0 && i < count) {
+		len = strlen(str);
+		if (len == 0)
+			break;
+		supply[i++].supply = str;
+		calc_size = calc_size - len - 1;
+		str += len + 1;
+	}
+	data->consumer_supplies = supply;
+	data->num_consumer_supplies = count;
+	return 0;
+}
+
+void of_regulator_deinit_data(struct regulator_init_data *data)
+{
+	if (data && data->consumer_supplies)
+		kfree(data->consumer_supplies);
+}
diff --git a/include/linux/of_regulator.h b/include/linux/of_regulator.h
new file mode 100644
index 0000000..0155bd8
--- /dev/null
+++ b/include/linux/of_regulator.h
@@ -0,0 +1,34 @@
+/*
+ * Generic Regulator API implementation
+ *
+ * Copyright (c) 2011 Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __LINUX_OF_REGULATOR_H
+#define __LINUX_OF_REGULATOR_H
+
+#if defined(CONFIG_OF_REGULATOR) || defined(CONFIG_OF_REGULATOR_MODULE)
+#include <linux/regulator/machine.h>
+
+extern int of_regulator_init_data(struct device_node *of_node,
+				struct regulator_init_data *data);
+extern void of_regulator_deinit_data(struct regulator_init_data *data);
+
+#else
+static inline int of_regulator_init_data(struct device_node *of_node,
+				struct regulator_init_data *data)
+{
+	return 0;
+}
+
+static inline void of_regulator_deinit_data(struct regulator_init_data *data)
+{
+}
+#endif	/* CONFIG_OF_REGULATOR */
+
+#endif	/* __LINUX_OF_REGULATOR_H */
-- 
1.5.6.5

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

* [PATCH] regulator: convert devicetree to platform data on max8649
  2011-07-08 10:20               ` Haojian Zhuang
@ 2011-07-08 10:20                 ` Haojian Zhuang
  -1 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-08 10:20 UTC (permalink / raw)
  To: grant.likely, linux-arm-kernel, devicetree-discuss,
	haojian.zhuang, nico, samuel.ortiz, broonie
  Cc: Haojian Zhuang

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 drivers/regulator/max8649.c |   70 +++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 70 insertions(+), 0 deletions(-)

diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c
index 30eb9e5..4316a37 100644
--- a/drivers/regulator/max8649.c
+++ b/drivers/regulator/max8649.c
@@ -15,6 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/slab.h>
+#include <linux/of_regulator.h>
 #include <linux/regulator/max8649.h>
 
 #define MAX8649_DCDC_VMIN	750000		/* uV */
@@ -275,6 +276,69 @@ static struct regulator_desc dcdc_desc = {
 	.owner		= THIS_MODULE,
 };
 
+#ifdef CONFIG_OF_REGULATOR
+static struct max8649_platform_data __devinit
+*max8649_get_alt_pdata(struct i2c_client *client)
+{
+	struct device_node *np = client->dev.of_node;
+	struct max8649_platform_data *pdata;
+	const __be32 *mode, *extclk, *ramp;
+	int ret = 0;
+
+	if (np == NULL)
+		goto out;
+
+	mode = of_get_property(np, "max8649-mode", NULL);
+	if (mode == NULL) {
+		dev_err(&client->dev, "mode property is missed\n");
+		goto out;
+	}
+	extclk = of_get_property(np, "ext-clock-frequency", NULL);
+	if (extclk == NULL)
+		dev_dbg(&client->dev, "ext-clock-frequency is not set\n");
+	ramp = of_get_property(np, "max8649-ramp", NULL);
+	if (ramp == NULL) {
+		dev_err(&client->dev, "ramp is missed\n");
+		goto out;
+	}
+
+	pdata = kzalloc(sizeof(struct max8649_platform_data), GFP_KERNEL);
+	if (pdata == NULL)
+		goto out;
+	pdata->mode = be32_to_cpu(*mode);
+	if (extclk) {
+		pdata->extclk = 1;
+		pdata->extclk_freq = be32_to_cpu(*extclk);
+	}
+	if (ramp) {
+		pdata->ramp_timing = be32_to_cpu(*ramp++);
+		pdata->ramp_down = be32_to_cpu(*ramp);
+	}
+
+	pdata->regulator = kzalloc(sizeof(struct regulator_init_data),
+				GFP_KERNEL);
+	if (pdata->regulator == NULL)
+		goto out_pdata;
+	ret = of_regulator_init_data(np, pdata->regulator);
+	if (ret < 0)
+		goto out_regulator;
+	return pdata;
+
+out_regulator:
+	kfree(pdata->regulator);
+out_pdata:
+	kfree(pdata);
+out:
+	return NULL;
+}
+#else
+static struct max8649_platform_data __devinit
+*max8649_get_alt_pdata(struct i2c_client *client)
+{
+	return 0;
+}
+#endif
+
 static int __devinit max8649_regulator_probe(struct i2c_client *client,
 					     const struct i2c_device_id *id)
 {
@@ -294,6 +358,12 @@ static int __devinit max8649_regulator_probe(struct i2c_client *client,
 	mutex_init(&info->io_lock);
 	i2c_set_clientdata(client, info);
 
+	if (pdata == NULL) {
+		pdata = max8649_get_alt_pdata(client);
+		if (pdata == NULL)
+			return -ENODEV;
+	}
+
 	info->mode = pdata->mode;
 	switch (info->mode) {
 	case 0:
-- 
1.5.6.5

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

* [PATCH] regulator: convert devicetree to platform data on max8649
@ 2011-07-08 10:20                 ` Haojian Zhuang
  0 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-08 10:20 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 drivers/regulator/max8649.c |   70 +++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 70 insertions(+), 0 deletions(-)

diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c
index 30eb9e5..4316a37 100644
--- a/drivers/regulator/max8649.c
+++ b/drivers/regulator/max8649.c
@@ -15,6 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/slab.h>
+#include <linux/of_regulator.h>
 #include <linux/regulator/max8649.h>
 
 #define MAX8649_DCDC_VMIN	750000		/* uV */
@@ -275,6 +276,69 @@ static struct regulator_desc dcdc_desc = {
 	.owner		= THIS_MODULE,
 };
 
+#ifdef CONFIG_OF_REGULATOR
+static struct max8649_platform_data __devinit
+*max8649_get_alt_pdata(struct i2c_client *client)
+{
+	struct device_node *np = client->dev.of_node;
+	struct max8649_platform_data *pdata;
+	const __be32 *mode, *extclk, *ramp;
+	int ret = 0;
+
+	if (np == NULL)
+		goto out;
+
+	mode = of_get_property(np, "max8649-mode", NULL);
+	if (mode == NULL) {
+		dev_err(&client->dev, "mode property is missed\n");
+		goto out;
+	}
+	extclk = of_get_property(np, "ext-clock-frequency", NULL);
+	if (extclk == NULL)
+		dev_dbg(&client->dev, "ext-clock-frequency is not set\n");
+	ramp = of_get_property(np, "max8649-ramp", NULL);
+	if (ramp == NULL) {
+		dev_err(&client->dev, "ramp is missed\n");
+		goto out;
+	}
+
+	pdata = kzalloc(sizeof(struct max8649_platform_data), GFP_KERNEL);
+	if (pdata == NULL)
+		goto out;
+	pdata->mode = be32_to_cpu(*mode);
+	if (extclk) {
+		pdata->extclk = 1;
+		pdata->extclk_freq = be32_to_cpu(*extclk);
+	}
+	if (ramp) {
+		pdata->ramp_timing = be32_to_cpu(*ramp++);
+		pdata->ramp_down = be32_to_cpu(*ramp);
+	}
+
+	pdata->regulator = kzalloc(sizeof(struct regulator_init_data),
+				GFP_KERNEL);
+	if (pdata->regulator == NULL)
+		goto out_pdata;
+	ret = of_regulator_init_data(np, pdata->regulator);
+	if (ret < 0)
+		goto out_regulator;
+	return pdata;
+
+out_regulator:
+	kfree(pdata->regulator);
+out_pdata:
+	kfree(pdata);
+out:
+	return NULL;
+}
+#else
+static struct max8649_platform_data __devinit
+*max8649_get_alt_pdata(struct i2c_client *client)
+{
+	return 0;
+}
+#endif
+
 static int __devinit max8649_regulator_probe(struct i2c_client *client,
 					     const struct i2c_device_id *id)
 {
@@ -294,6 +358,12 @@ static int __devinit max8649_regulator_probe(struct i2c_client *client,
 	mutex_init(&info->io_lock);
 	i2c_set_clientdata(client, info);
 
+	if (pdata == NULL) {
+		pdata = max8649_get_alt_pdata(client);
+		if (pdata == NULL)
+			return -ENODEV;
+	}
+
 	info->mode = pdata->mode;
 	switch (info->mode) {
 	case 0:
-- 
1.5.6.5

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

* [PATCH] mfd: convert devicetree to platform data on max8925
  2011-07-08 10:20                 ` Haojian Zhuang
@ 2011-07-08 10:20                   ` Haojian Zhuang
  -1 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-08 10:20 UTC (permalink / raw)
  To: grant.likely, linux-arm-kernel, devicetree-discuss,
	haojian.zhuang, nico, samuel.ortiz, broonie
  Cc: Haojian Zhuang

Make max8925 to support both platform data and device tree. So a translation
between device tree and platform data is added.

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 drivers/mfd/max8925-i2c.c |  159 ++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 157 insertions(+), 2 deletions(-)

diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c
index 0219115..fb74554 100644
--- a/drivers/mfd/max8925-i2c.c
+++ b/drivers/mfd/max8925-i2c.c
@@ -10,6 +10,9 @@
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/of_irq.h>
+#include <linux/of_regulator.h>
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
 #include <linux/mfd/max8925.h>
@@ -135,6 +138,154 @@ static const struct i2c_device_id max8925_id_table[] = {
 };
 MODULE_DEVICE_TABLE(i2c, max8925_id_table);
 
+#ifdef CONFIG_OF
+static int __devinit max8925_parse_irq(struct i2c_client *i2c,
+					struct max8925_platform_data *pdata)
+{
+	struct device_node *of_node = i2c->dev.of_node;
+
+	pdata->irq_base = irq_alloc_descs(-1, 0, MAX8925_NR_IRQS, 0);
+	irq_domain_add_simple(of_node, pdata->irq_base);
+	return 0;
+}
+
+static void __devinit max8925_parse_backlight(struct device_node *np,
+					struct max8925_platform_data *pdata)
+{
+	struct max8925_backlight_pdata *bk;
+	const __be32 *p;
+
+	bk = kzalloc(sizeof(struct max8925_backlight_pdata), GFP_KERNEL);
+	if (bk == NULL)
+		return;
+	pdata->backlight = bk;
+	p = of_get_property(np, "lxw-scl", NULL);
+	if (p)
+		bk->lxw_scl = be32_to_cpu(*p);
+	p = of_get_property(np, "lxw-freq", NULL);
+	if (p)
+		bk->lxw_freq = be32_to_cpu(*p);
+	p = of_get_property(np, "dual-string", NULL);
+	if (p)
+		bk->dual_string = be32_to_cpu(*p);
+}
+
+static void __devinit max8925_parse_touch(struct device_node *np,
+					struct max8925_platform_data *pdata)
+{
+	struct max8925_touch_pdata *touch;
+	const __be32 *p;
+
+	touch = kzalloc(sizeof(struct max8925_touch_pdata), GFP_KERNEL);
+	if (touch == NULL)
+		return;
+	pdata->touch = touch;
+	p = of_get_property(np, "flags", NULL);
+	if (p)
+		touch->flags = be32_to_cpu(*p);
+	p = of_get_property(np, "interrupts", NULL);
+	if (p)
+		pdata->tsc_irq = irq_of_parse_and_map(np, 0);
+}
+
+static void __devinit max8925_parse_power(struct device_node *np,
+					struct max8925_platform_data *pdata)
+{
+	struct max8925_power_pdata *power;
+	const __be32 *p;
+
+	power = kzalloc(sizeof(struct max8925_power_pdata), GFP_KERNEL);
+	if (power == NULL)
+		return;
+	pdata->power = power;
+	p = of_get_property(np, "battery-detect", NULL);
+	if (p)
+		power->batt_detect = be32_to_cpu(*p) ? 1 : 0;
+	p = of_get_property(np, "topoff-threshold", NULL);
+	if (p)
+		power->topoff_threshold = be32_to_cpu(*p) & 0x3;
+	p = of_get_property(np, "fast-charge", NULL);
+	if (p)
+		power->fast_charge = be32_to_cpu(*p) & 0x7;
+}
+
+static void __devinit max8925_parse_regulator(struct device_node *np,
+					struct max8925_platform_data *pdata)
+{
+	const char *name[MAX8925_MAX_REGULATOR] = {
+			"SD1", "SD2", "SD3", "LDO1", "LDO2", "LDO3", "LDO4",
+			"LDO5", "LDO6", "LDO7", "LDO8", "LDO9", "LDO10",
+			"LDO11", "LDO12", "LDO13", "LDO14", "LDO15", "LDO16",
+			"LDO17", "LDO18", "LDO19", "LDO20"};
+	const char *cp;
+	int i;
+
+	cp = of_get_property(np, "compatible", NULL);
+	if (cp == NULL)
+		return;
+	for (i = 0; i < MAX8925_MAX_REGULATOR; i++) {
+		if (strncmp(cp, name[i], strlen(name[i])))
+			continue;
+		of_regulator_init_data(np, pdata->regulator[i]);
+		break;
+	}
+}
+
+static struct max8925_platform_data __devinit
+*max8925_get_alt_pdata(struct i2c_client *client)
+{
+	struct max8925_platform_data *pdata;
+	struct device_node *of_node = client->dev.of_node;
+	struct device_node *np, *pp = NULL;
+	const char *cp;
+	int ret, i;
+
+	pdata = kzalloc(sizeof(struct max8925_platform_data), GFP_KERNEL);
+	if (pdata == NULL)
+		return NULL;
+	pdata->regulator[0] = kzalloc(sizeof(struct regulator_init_data)
+			* MAX8925_MAX_REGULATOR, GFP_KERNEL);
+	if (pdata->regulator[0] == NULL) {
+		kfree(pdata);
+		return NULL;
+	}
+	for (i = 1; i < MAX8925_MAX_REGULATOR; i++)
+		pdata->regulator[i] = pdata->regulator[i - 1] + 1;
+
+	ret = max8925_parse_irq(client, pdata);
+	if (ret < 0)
+		goto out;
+
+	for (; (np = of_get_next_child(of_node, pp)) != NULL; pp = np) {
+		cp = of_get_property(np, "compatible", NULL);
+		if (cp == NULL)
+			continue;
+		if (!strncmp(cp, "backlight", strlen("backlight")))
+			max8925_parse_backlight(np, pdata);
+		if (!strncmp(cp, "power", strlen("power")))
+			max8925_parse_power(np, pdata);
+		if (!strncmp(cp, "touch", strlen("touch")))
+			max8925_parse_touch(np, pdata);
+		cp = of_get_property(np, "device_type", NULL);
+		if (cp == NULL)
+			continue;
+		if (!strncmp(cp, "regulator", strlen("regulator")))
+			max8925_parse_regulator(np, pdata);
+	}
+	return pdata;
+out:
+	kfree(pdata->regulator[0]);
+	kfree(pdata);
+	return NULL;
+}
+#else
+static struct max8925_platform_data __devinit
+*max8925_get_alt_pdata(struct i2c_client *client)
+{
+	return NULL;
+}
+#endif
+
 static int __devinit max8925_probe(struct i2c_client *client,
 				   const struct i2c_device_id *id)
 {
@@ -142,8 +293,12 @@ static int __devinit max8925_probe(struct i2c_client *client,
 	static struct max8925_chip *chip;
 
 	if (!pdata) {
-		pr_info("%s: platform data is missing\n", __func__);
-		return -EINVAL;
+		pdata = max8925_get_alt_pdata(client);
+		if (!pdata) {
+			pr_info("%s: platform data is missing\n", __func__);
+			return -EINVAL;
+		}
+		client->dev.platform_data = pdata;
 	}
 
 	chip = kzalloc(sizeof(struct max8925_chip), GFP_KERNEL);
-- 
1.5.6.5

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

* [PATCH] mfd: convert devicetree to platform data on max8925
@ 2011-07-08 10:20                   ` Haojian Zhuang
  0 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-08 10:20 UTC (permalink / raw)
  To: linux-arm-kernel

Make max8925 to support both platform data and device tree. So a translation
between device tree and platform data is added.

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 drivers/mfd/max8925-i2c.c |  159 ++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 157 insertions(+), 2 deletions(-)

diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c
index 0219115..fb74554 100644
--- a/drivers/mfd/max8925-i2c.c
+++ b/drivers/mfd/max8925-i2c.c
@@ -10,6 +10,9 @@
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/of_irq.h>
+#include <linux/of_regulator.h>
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
 #include <linux/mfd/max8925.h>
@@ -135,6 +138,154 @@ static const struct i2c_device_id max8925_id_table[] = {
 };
 MODULE_DEVICE_TABLE(i2c, max8925_id_table);
 
+#ifdef CONFIG_OF
+static int __devinit max8925_parse_irq(struct i2c_client *i2c,
+					struct max8925_platform_data *pdata)
+{
+	struct device_node *of_node = i2c->dev.of_node;
+
+	pdata->irq_base = irq_alloc_descs(-1, 0, MAX8925_NR_IRQS, 0);
+	irq_domain_add_simple(of_node, pdata->irq_base);
+	return 0;
+}
+
+static void __devinit max8925_parse_backlight(struct device_node *np,
+					struct max8925_platform_data *pdata)
+{
+	struct max8925_backlight_pdata *bk;
+	const __be32 *p;
+
+	bk = kzalloc(sizeof(struct max8925_backlight_pdata), GFP_KERNEL);
+	if (bk == NULL)
+		return;
+	pdata->backlight = bk;
+	p = of_get_property(np, "lxw-scl", NULL);
+	if (p)
+		bk->lxw_scl = be32_to_cpu(*p);
+	p = of_get_property(np, "lxw-freq", NULL);
+	if (p)
+		bk->lxw_freq = be32_to_cpu(*p);
+	p = of_get_property(np, "dual-string", NULL);
+	if (p)
+		bk->dual_string = be32_to_cpu(*p);
+}
+
+static void __devinit max8925_parse_touch(struct device_node *np,
+					struct max8925_platform_data *pdata)
+{
+	struct max8925_touch_pdata *touch;
+	const __be32 *p;
+
+	touch = kzalloc(sizeof(struct max8925_touch_pdata), GFP_KERNEL);
+	if (touch == NULL)
+		return;
+	pdata->touch = touch;
+	p = of_get_property(np, "flags", NULL);
+	if (p)
+		touch->flags = be32_to_cpu(*p);
+	p = of_get_property(np, "interrupts", NULL);
+	if (p)
+		pdata->tsc_irq = irq_of_parse_and_map(np, 0);
+}
+
+static void __devinit max8925_parse_power(struct device_node *np,
+					struct max8925_platform_data *pdata)
+{
+	struct max8925_power_pdata *power;
+	const __be32 *p;
+
+	power = kzalloc(sizeof(struct max8925_power_pdata), GFP_KERNEL);
+	if (power == NULL)
+		return;
+	pdata->power = power;
+	p = of_get_property(np, "battery-detect", NULL);
+	if (p)
+		power->batt_detect = be32_to_cpu(*p) ? 1 : 0;
+	p = of_get_property(np, "topoff-threshold", NULL);
+	if (p)
+		power->topoff_threshold = be32_to_cpu(*p) & 0x3;
+	p = of_get_property(np, "fast-charge", NULL);
+	if (p)
+		power->fast_charge = be32_to_cpu(*p) & 0x7;
+}
+
+static void __devinit max8925_parse_regulator(struct device_node *np,
+					struct max8925_platform_data *pdata)
+{
+	const char *name[MAX8925_MAX_REGULATOR] = {
+			"SD1", "SD2", "SD3", "LDO1", "LDO2", "LDO3", "LDO4",
+			"LDO5", "LDO6", "LDO7", "LDO8", "LDO9", "LDO10",
+			"LDO11", "LDO12", "LDO13", "LDO14", "LDO15", "LDO16",
+			"LDO17", "LDO18", "LDO19", "LDO20"};
+	const char *cp;
+	int i;
+
+	cp = of_get_property(np, "compatible", NULL);
+	if (cp == NULL)
+		return;
+	for (i = 0; i < MAX8925_MAX_REGULATOR; i++) {
+		if (strncmp(cp, name[i], strlen(name[i])))
+			continue;
+		of_regulator_init_data(np, pdata->regulator[i]);
+		break;
+	}
+}
+
+static struct max8925_platform_data __devinit
+*max8925_get_alt_pdata(struct i2c_client *client)
+{
+	struct max8925_platform_data *pdata;
+	struct device_node *of_node = client->dev.of_node;
+	struct device_node *np, *pp = NULL;
+	const char *cp;
+	int ret, i;
+
+	pdata = kzalloc(sizeof(struct max8925_platform_data), GFP_KERNEL);
+	if (pdata == NULL)
+		return NULL;
+	pdata->regulator[0] = kzalloc(sizeof(struct regulator_init_data)
+			* MAX8925_MAX_REGULATOR, GFP_KERNEL);
+	if (pdata->regulator[0] == NULL) {
+		kfree(pdata);
+		return NULL;
+	}
+	for (i = 1; i < MAX8925_MAX_REGULATOR; i++)
+		pdata->regulator[i] = pdata->regulator[i - 1] + 1;
+
+	ret = max8925_parse_irq(client, pdata);
+	if (ret < 0)
+		goto out;
+
+	for (; (np = of_get_next_child(of_node, pp)) != NULL; pp = np) {
+		cp = of_get_property(np, "compatible", NULL);
+		if (cp == NULL)
+			continue;
+		if (!strncmp(cp, "backlight", strlen("backlight")))
+			max8925_parse_backlight(np, pdata);
+		if (!strncmp(cp, "power", strlen("power")))
+			max8925_parse_power(np, pdata);
+		if (!strncmp(cp, "touch", strlen("touch")))
+			max8925_parse_touch(np, pdata);
+		cp = of_get_property(np, "device_type", NULL);
+		if (cp == NULL)
+			continue;
+		if (!strncmp(cp, "regulator", strlen("regulator")))
+			max8925_parse_regulator(np, pdata);
+	}
+	return pdata;
+out:
+	kfree(pdata->regulator[0]);
+	kfree(pdata);
+	return NULL;
+}
+#else
+static struct max8925_platform_data __devinit
+*max8925_get_alt_pdata(struct i2c_client *client)
+{
+	return NULL;
+}
+#endif
+
 static int __devinit max8925_probe(struct i2c_client *client,
 				   const struct i2c_device_id *id)
 {
@@ -142,8 +293,12 @@ static int __devinit max8925_probe(struct i2c_client *client,
 	static struct max8925_chip *chip;
 
 	if (!pdata) {
-		pr_info("%s: platform data is missing\n", __func__);
-		return -EINVAL;
+		pdata = max8925_get_alt_pdata(client);
+		if (!pdata) {
+			pr_info("%s: platform data is missing\n", __func__);
+			return -EINVAL;
+		}
+		client->dev.platform_data = pdata;
 	}
 
 	chip = kzalloc(sizeof(struct max8925_chip), GFP_KERNEL);
-- 
1.5.6.5

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

* [PATCH] mfd: convert devicetree to platform on 88pm860x
  2011-07-08 10:20                   ` Haojian Zhuang
@ 2011-07-08 10:20                     ` Haojian Zhuang
  -1 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-08 10:20 UTC (permalink / raw)
  To: grant.likely, linux-arm-kernel, devicetree-discuss,
	haojian.zhuang, nico, samuel.ortiz, broonie
  Cc: Haojian Zhuang

Make 88pm860x to support both platform data and device tree. So a translation
between device tree and platform data is added.

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 drivers/mfd/88pm860x-i2c.c |  191 +++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 189 insertions(+), 2 deletions(-)

diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c
index e017dc8..b017e4a 100644
--- a/drivers/mfd/88pm860x-i2c.c
+++ b/drivers/mfd/88pm860x-i2c.c
@@ -10,6 +10,8 @@
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/of_regulator.h>
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
 #include <linux/mfd/88pm860x.h>
@@ -236,6 +238,187 @@ static const struct i2c_device_id pm860x_id_table[] = {
 };
 MODULE_DEVICE_TABLE(i2c, pm860x_id_table);
 
+#ifdef CONFIG_OF
+static int __devinit pm860x_parse_irq(struct i2c_client *i2c,
+				      struct pm860x_platform_data *pdata)
+{
+	struct device_node *of_node = i2c->dev.of_node;
+
+	pdata->irq_base = irq_alloc_descs(-1, 0, 24, 0);
+	irq_domain_add_simple(of_node, pdata->irq_base);
+	return 0;
+}
+
+static void __devinit pm860x_parse_backlight(struct device_node *np,
+					struct pm860x_platform_data *pdata)
+{
+	const __be32 *idx, *iset, *pwm;
+	int i;
+
+	idx = of_get_property(np, "cell-index", NULL);
+	if (idx == NULL)
+		return;
+	iset = of_get_property(np, "iset", NULL);
+	if (iset == NULL)
+		return;
+	pwm = of_get_property(np, "pwm", NULL);
+
+	i = be32_to_cpu(*idx);
+	pdata->backlight[i].iset = be32_to_cpu(*iset);
+	pdata->backlight[i].flags = i;
+	if (pwm)
+		pdata->backlight[i].pwm = be32_to_cpu(*pwm);
+	pdata->num_backlights++;
+}
+
+static void __devinit pm860x_parse_led(struct device_node *np,
+					struct pm860x_platform_data *pdata)
+{
+	const __be32 *idx, *iset;
+	int i;
+
+	idx = of_get_property(np, "cell-index", NULL);
+	if (idx == NULL)
+		return;
+	iset = of_get_property(np, "iset", NULL);
+	if (iset == NULL)
+		return;
+
+	i = be32_to_cpu(*idx);
+	pdata->led[i].iset = be32_to_cpu(*iset);
+	pdata->led[i].flags = i;
+	pdata->num_leds++;
+}
+
+static void __devinit pm860x_parse_touch(struct device_node *np,
+					struct pm860x_platform_data *pdata)
+{
+	struct pm860x_touch_pdata *touch;
+	const __be32 *prebias, *slot, *res, *prechg;
+
+	prebias = of_get_property(np, "prebias", NULL);
+	if (prebias == NULL)
+		return;
+	slot = of_get_property(np, "slot-cycle", NULL);
+	if (slot == NULL)
+		return;
+	res = of_get_property(np, "resistor-xplate", NULL);
+	if (res == NULL)
+		return;
+	prechg = of_get_property(np, "pen-prechg", NULL);
+	if (prechg == NULL)
+		return;
+	touch = kzalloc(sizeof(struct pm860x_touch_pdata), GFP_KERNEL);
+	if (touch == NULL)
+		return;
+	touch->gpadc_prebias = be32_to_cpu(*prebias++);
+	touch->tsi_prebias = be32_to_cpu(*prebias++);
+	touch->pen_prebias = be32_to_cpu(*prebias);
+	touch->slot_cycle = be32_to_cpu(*slot);
+	touch->pen_prechg = be32_to_cpu(*prechg);
+	pdata->touch = touch;
+}
+
+static int data[PM8607_ID_RG_MAX];
+
+static void __devinit pm860x_parse_regulator(struct device_node *np,
+					struct pm860x_platform_data *pdata)
+{
+	const char *name[PM8607_ID_RG_MAX] = {
+		"BUCK1", "BUCK2", "BUCK3", "LDO1", "LDO2", "LDO3", "LOD4",
+		"LDO5", "LDO6", "LDO7", "LDO8", "LDO9", "LDO10", "LDO11",
+		"LDO12", "LDO13", "LDO14", "LDO15"};
+	const char *cp;
+	int i;
+
+	cp = of_get_property(np, "compatible", NULL);
+	if (cp == NULL)
+		return;
+	for (i = 0; i < PM8607_ID_RG_MAX; i++) {
+		if (strncmp(cp, name[i], strlen(name[i])))
+			continue;
+		of_regulator_init_data(np, &pdata->regulator[i]);
+		data[i] = i;
+		pdata->regulator[i].driver_data = &data[i];
+		pdata->num_regulators++;
+		break;
+	}
+}
+
+static struct pm860x_platform_data __devinit
+*pm860x_get_alt_pdata(struct i2c_client *i2c)
+{
+	struct pm860x_platform_data *pdata;
+	struct device_node *of_node = i2c->dev.of_node;
+	struct device_node *np, *pp = NULL;
+	const char *cp;
+	const __be32 *p;
+	int ret;
+
+	pdata = kzalloc(sizeof(struct pm860x_platform_data), GFP_KERNEL);
+	if (pdata == NULL)
+		return NULL;
+	pdata->regulator = kzalloc(sizeof(struct regulator_init_data)
+				* PM8607_ID_RG_MAX, GFP_KERNEL);
+	if (pdata->regulator == NULL)
+		goto out_reg;
+	pdata->led = kzalloc(sizeof(struct pm860x_led_pdata) * 3,
+				GFP_KERNEL);
+	if (pdata->led == NULL)
+		goto out_led;
+	pdata->backlight = kzalloc(sizeof(struct pm860x_backlight_pdata)
+					* 3, GFP_KERNEL);
+	if (pdata->backlight == NULL)
+		goto out_backlight;
+	p = of_get_property(of_node, "i2c-port", NULL);
+	if (p)
+		pdata->i2c_port = be32_to_cpu(*p);
+	p = of_get_property(of_node, "companion-addr", NULL);
+	if (p)
+		pdata->companion_addr = be32_to_cpu(*p);
+	p = of_get_property(of_node, "irq-mode", NULL);
+	if (p)
+		pdata->irq_mode = be32_to_cpu(*p);
+
+	ret = pm860x_parse_irq(i2c, pdata);
+	if (ret < 0)
+		goto out;
+
+	for (; (np = of_get_next_child(of_node, pp)) != NULL; pp = np) {
+		cp = of_get_property(np, "compatible", NULL);
+		if (cp == NULL)
+			continue;
+		if (!strncmp(cp, "backlight", strlen("backlight")))
+			pm860x_parse_backlight(np, pdata);
+		if (!strncmp(cp, "led", strlen("led")))
+			pm860x_parse_led(np, pdata);
+		if (!strncmp(cp, "touch", strlen("touch")))
+			pm860x_parse_touch(np, pdata);
+		cp = of_get_property(np, "device_type", NULL);
+		if (cp == NULL)
+			continue;
+		if (!strncmp(cp, "regulator", strlen("regulator")))
+			pm860x_parse_regulator(np, pdata);
+	}
+	return pdata;
+out:
+	kfree(pdata->backlight);
+out_backlight:
+	kfree(pdata->led);
+out_led:
+	kfree(pdata->regulator);
+out_reg:
+	kfree(pdata);
+	return NULL;
+}
+#else
+static struct pm860x_platform_data __devinit
+*pm860x_get_alt_pdata(struct i2c_client *i2c)
+{
+	return NULL;
+}
+#endif
+
 static int verify_addr(struct i2c_client *i2c)
 {
 	unsigned short addr_8607[] = {0x30, 0x34};
@@ -264,8 +447,12 @@ static int __devinit pm860x_probe(struct i2c_client *client,
 	struct pm860x_chip *chip;
 
 	if (!pdata) {
-		pr_info("No platform data in %s!\n", __func__);
-		return -EINVAL;
+		pdata = pm860x_get_alt_pdata(client);
+		if (!pdata) {
+			pr_info("No platform data in %s!\n", __func__);
+			return -EINVAL;
+		}
+		client->dev.platform_data = pdata;
 	}
 
 	chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL);
-- 
1.5.6.5

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

* [PATCH] mfd: convert devicetree to platform on 88pm860x
@ 2011-07-08 10:20                     ` Haojian Zhuang
  0 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-08 10:20 UTC (permalink / raw)
  To: linux-arm-kernel

Make 88pm860x to support both platform data and device tree. So a translation
between device tree and platform data is added.

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 drivers/mfd/88pm860x-i2c.c |  191 +++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 189 insertions(+), 2 deletions(-)

diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c
index e017dc8..b017e4a 100644
--- a/drivers/mfd/88pm860x-i2c.c
+++ b/drivers/mfd/88pm860x-i2c.c
@@ -10,6 +10,8 @@
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/of_regulator.h>
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
 #include <linux/mfd/88pm860x.h>
@@ -236,6 +238,187 @@ static const struct i2c_device_id pm860x_id_table[] = {
 };
 MODULE_DEVICE_TABLE(i2c, pm860x_id_table);
 
+#ifdef CONFIG_OF
+static int __devinit pm860x_parse_irq(struct i2c_client *i2c,
+				      struct pm860x_platform_data *pdata)
+{
+	struct device_node *of_node = i2c->dev.of_node;
+
+	pdata->irq_base = irq_alloc_descs(-1, 0, 24, 0);
+	irq_domain_add_simple(of_node, pdata->irq_base);
+	return 0;
+}
+
+static void __devinit pm860x_parse_backlight(struct device_node *np,
+					struct pm860x_platform_data *pdata)
+{
+	const __be32 *idx, *iset, *pwm;
+	int i;
+
+	idx = of_get_property(np, "cell-index", NULL);
+	if (idx == NULL)
+		return;
+	iset = of_get_property(np, "iset", NULL);
+	if (iset == NULL)
+		return;
+	pwm = of_get_property(np, "pwm", NULL);
+
+	i = be32_to_cpu(*idx);
+	pdata->backlight[i].iset = be32_to_cpu(*iset);
+	pdata->backlight[i].flags = i;
+	if (pwm)
+		pdata->backlight[i].pwm = be32_to_cpu(*pwm);
+	pdata->num_backlights++;
+}
+
+static void __devinit pm860x_parse_led(struct device_node *np,
+					struct pm860x_platform_data *pdata)
+{
+	const __be32 *idx, *iset;
+	int i;
+
+	idx = of_get_property(np, "cell-index", NULL);
+	if (idx == NULL)
+		return;
+	iset = of_get_property(np, "iset", NULL);
+	if (iset == NULL)
+		return;
+
+	i = be32_to_cpu(*idx);
+	pdata->led[i].iset = be32_to_cpu(*iset);
+	pdata->led[i].flags = i;
+	pdata->num_leds++;
+}
+
+static void __devinit pm860x_parse_touch(struct device_node *np,
+					struct pm860x_platform_data *pdata)
+{
+	struct pm860x_touch_pdata *touch;
+	const __be32 *prebias, *slot, *res, *prechg;
+
+	prebias = of_get_property(np, "prebias", NULL);
+	if (prebias == NULL)
+		return;
+	slot = of_get_property(np, "slot-cycle", NULL);
+	if (slot == NULL)
+		return;
+	res = of_get_property(np, "resistor-xplate", NULL);
+	if (res == NULL)
+		return;
+	prechg = of_get_property(np, "pen-prechg", NULL);
+	if (prechg == NULL)
+		return;
+	touch = kzalloc(sizeof(struct pm860x_touch_pdata), GFP_KERNEL);
+	if (touch == NULL)
+		return;
+	touch->gpadc_prebias = be32_to_cpu(*prebias++);
+	touch->tsi_prebias = be32_to_cpu(*prebias++);
+	touch->pen_prebias = be32_to_cpu(*prebias);
+	touch->slot_cycle = be32_to_cpu(*slot);
+	touch->pen_prechg = be32_to_cpu(*prechg);
+	pdata->touch = touch;
+}
+
+static int data[PM8607_ID_RG_MAX];
+
+static void __devinit pm860x_parse_regulator(struct device_node *np,
+					struct pm860x_platform_data *pdata)
+{
+	const char *name[PM8607_ID_RG_MAX] = {
+		"BUCK1", "BUCK2", "BUCK3", "LDO1", "LDO2", "LDO3", "LOD4",
+		"LDO5", "LDO6", "LDO7", "LDO8", "LDO9", "LDO10", "LDO11",
+		"LDO12", "LDO13", "LDO14", "LDO15"};
+	const char *cp;
+	int i;
+
+	cp = of_get_property(np, "compatible", NULL);
+	if (cp == NULL)
+		return;
+	for (i = 0; i < PM8607_ID_RG_MAX; i++) {
+		if (strncmp(cp, name[i], strlen(name[i])))
+			continue;
+		of_regulator_init_data(np, &pdata->regulator[i]);
+		data[i] = i;
+		pdata->regulator[i].driver_data = &data[i];
+		pdata->num_regulators++;
+		break;
+	}
+}
+
+static struct pm860x_platform_data __devinit
+*pm860x_get_alt_pdata(struct i2c_client *i2c)
+{
+	struct pm860x_platform_data *pdata;
+	struct device_node *of_node = i2c->dev.of_node;
+	struct device_node *np, *pp = NULL;
+	const char *cp;
+	const __be32 *p;
+	int ret;
+
+	pdata = kzalloc(sizeof(struct pm860x_platform_data), GFP_KERNEL);
+	if (pdata == NULL)
+		return NULL;
+	pdata->regulator = kzalloc(sizeof(struct regulator_init_data)
+				* PM8607_ID_RG_MAX, GFP_KERNEL);
+	if (pdata->regulator == NULL)
+		goto out_reg;
+	pdata->led = kzalloc(sizeof(struct pm860x_led_pdata) * 3,
+				GFP_KERNEL);
+	if (pdata->led == NULL)
+		goto out_led;
+	pdata->backlight = kzalloc(sizeof(struct pm860x_backlight_pdata)
+					* 3, GFP_KERNEL);
+	if (pdata->backlight == NULL)
+		goto out_backlight;
+	p = of_get_property(of_node, "i2c-port", NULL);
+	if (p)
+		pdata->i2c_port = be32_to_cpu(*p);
+	p = of_get_property(of_node, "companion-addr", NULL);
+	if (p)
+		pdata->companion_addr = be32_to_cpu(*p);
+	p = of_get_property(of_node, "irq-mode", NULL);
+	if (p)
+		pdata->irq_mode = be32_to_cpu(*p);
+
+	ret = pm860x_parse_irq(i2c, pdata);
+	if (ret < 0)
+		goto out;
+
+	for (; (np = of_get_next_child(of_node, pp)) != NULL; pp = np) {
+		cp = of_get_property(np, "compatible", NULL);
+		if (cp == NULL)
+			continue;
+		if (!strncmp(cp, "backlight", strlen("backlight")))
+			pm860x_parse_backlight(np, pdata);
+		if (!strncmp(cp, "led", strlen("led")))
+			pm860x_parse_led(np, pdata);
+		if (!strncmp(cp, "touch", strlen("touch")))
+			pm860x_parse_touch(np, pdata);
+		cp = of_get_property(np, "device_type", NULL);
+		if (cp == NULL)
+			continue;
+		if (!strncmp(cp, "regulator", strlen("regulator")))
+			pm860x_parse_regulator(np, pdata);
+	}
+	return pdata;
+out:
+	kfree(pdata->backlight);
+out_backlight:
+	kfree(pdata->led);
+out_led:
+	kfree(pdata->regulator);
+out_reg:
+	kfree(pdata);
+	return NULL;
+}
+#else
+static struct pm860x_platform_data __devinit
+*pm860x_get_alt_pdata(struct i2c_client *i2c)
+{
+	return NULL;
+}
+#endif
+
 static int verify_addr(struct i2c_client *i2c)
 {
 	unsigned short addr_8607[] = {0x30, 0x34};
@@ -264,8 +447,12 @@ static int __devinit pm860x_probe(struct i2c_client *client,
 	struct pm860x_chip *chip;
 
 	if (!pdata) {
-		pr_info("No platform data in %s!\n", __func__);
-		return -EINVAL;
+		pdata = pm860x_get_alt_pdata(client);
+		if (!pdata) {
+			pr_info("No platform data in %s!\n", __func__);
+			return -EINVAL;
+		}
+		client->dev.platform_data = pdata;
 	}
 
 	chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL);
-- 
1.5.6.5

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

* [PATCH] ARM: mmp: add DTS file
  2011-07-08 10:20                     ` Haojian Zhuang
@ 2011-07-08 10:20                       ` Haojian Zhuang
  -1 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-08 10:20 UTC (permalink / raw)
  To: grant.likely, linux-arm-kernel, devicetree-discuss,
	haojian.zhuang, nico, samuel.ortiz, broonie
  Cc: Haojian Zhuang

Add DTS file to support brownstone & ttc-dkb.

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 arch/arm/boot/dts/mmp2-brownstone.dts |  319 +++++++++++++++++++++++++++++++++
 arch/arm/boot/dts/ttc-dkb.dts         |  176 ++++++++++++++++++
 arch/arm/mach-mmp/brownstone.c        |   66 ++-----
 arch/arm/mach-mmp/ttc_dkb.c           |   21 ++-
 4 files changed, 530 insertions(+), 52 deletions(-)
 create mode 100644 arch/arm/boot/dts/mmp2-brownstone.dts
 create mode 100644 arch/arm/boot/dts/ttc-dkb.dts

diff --git a/arch/arm/boot/dts/mmp2-brownstone.dts b/arch/arm/boot/dts/mmp2-brownstone.dts
new file mode 100644
index 0000000..5fdabc3
--- /dev/null
+++ b/arch/arm/boot/dts/mmp2-brownstone.dts
@@ -0,0 +1,319 @@
+/dts-v1/;
+
+/include/ "skeleton.dtsi"
+
+/ {
+	model = "Marvell MMP2 Brownstone";
+	compatible = "mrvl,mmp2-brownstone", "mrvl,armada610-brownstone";
+	interrupt-parent = <&mmp_intc>;
+
+	memory {
+		reg = <0x00000000 0x20000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS2,38400 root=/dev/nfs nfsroot=192.168.1.100:192.168.1.101::255.255.255.0::eth0:on";
+		linux,stdout-path = &uart2;
+	};
+
+	soc@d4000000 {
+		compatible = "mrvl,mmp2", "mrvl,armada610", "simple-bus";
+		device_type = "soc";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		mmp_intc: interrupt-controller@d4282000 {
+			compatible = "mrvl,mmp-intc";
+			/*device_type = "intc";*/
+			interrupt-controller;
+			#interrupt-cells = <1>;
+			/*
+			 * interrupts: irq index of parent's irq domain
+			 */
+			interrupts = <0>;
+			interrupt-parent = <&mmp_intc>;
+			sub-interrupts = <64>;
+
+			/* enable bits in conf register */
+			enable_mask = <0x20>;
+
+			/* reg: <offset & size> */
+			reg = <0xd4282000 0x400>;
+		};
+
+		mux_intc4: interrupt-controller@d4282150 {
+			compatible = "mrvl,mux-intc";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			#interrupt-cells = <1>;
+			interrupt-controller;
+			interrupts = <4>;
+			interrupt-parent = <&mmp_intc>;
+			sub-interrupts = <2>;
+			reg = <0xd4282150 0>;
+			status-mask = <0x150 0x168>;
+			/* mfp register & interrupt index */
+			mfp-edge-interrupt = <0xd401e2c4 1>;
+		};
+
+		mux_intc5: interrupt-controller@d4282154 {
+			compatible = "mrvl,mux-intc";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			#interrupt-cells = <1>;
+			interrupt-controller;
+			interrupts = <5>;
+			sub-interrupts = <2>;
+			interrupt-parent = <&mmp_intc>;
+			reg = <0xd4282154 0>;
+			status-mask = <0x154 0x16c>;
+		};
+
+		mux_intc9: interrupt-controller@d4282180 {
+			compatible = "mrvl,mux-intc";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			#interrupt-cells = <1>;
+			interrupt-controller;
+			interrupts = <9>;
+			interrupt-parent = <&mmp_intc>;
+			sub-interrupts = <3>;
+			reg = <0xd4282180 0>;
+			status-mask = <0x180 0x17c>;
+		};
+
+		mux_intc17: interrupt-controller@d4282158 {
+			compatible = "mrvl,mux-intc";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			#interrupt-cells = <1>;
+			interrupt-controller;
+			interrupts = <17>;
+			interrupt-parent = <&mmp_intc>;
+			sub-interrupts = <5>;
+			reg = <0xd4282158 0>;
+			status-mask = <0x158 0x170>;
+		};
+
+		mux_intc35: interrupt-controller@d428215c {
+			compatible = "mrvl,mux-intc";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			#interrupt-cells = <1>;
+			interrupt-controller;
+			interrupts = <35>;
+			interrupt-parent = <&mmp_intc>;
+			sub-interrupts = <15>;
+			reg = <0xd428215c 0>;
+			status-mask = <0x15c 0x174>;
+		};
+
+		mux_intc51: interrupt-controller@d4282160 {
+			compatible = "mrvl,mux-intc";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			#interrupt-cells = <1>;
+			interrupt-controller;
+			interrupts = <51>;
+			interrupt-parent = <&mmp_intc>;
+			sub-interrupts = <2>;
+			reg = <0xd4282160 0>;
+			status-mask = <0x160 0x178>;
+		};
+
+		mux_intc55: interrupt-controller@d4282188 {
+			compatible = "mrvl,mux-intc";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			#interrupt-cells = <1>;
+			interrupt-controller;
+			interrupts = <55>;
+			interrupt-parent = <&mmp_intc>;
+			sub-interrupts = <2>;
+			reg = <0xd4282188 0>;
+			status-mask = <0x188 0x184>;
+		};
+
+		gpio: gpio-controller {
+			compatible = "pxa,gpio";
+			gpio-controller;
+			reg = <
+				0xd4019000 0xb0
+				0xd4019004 0xb0
+				0xd4019008 0xb0
+				0xd4019100 0xb0
+				0xd4019104 0xb0
+				0xd4019108 0xb0>;
+
+			/* gpio-clk-value: <offset & value> */
+			gpio-clk-value = <0xd4015038 0x3>;
+
+			/* gpio-mask: <offset & value> */
+			gpio-mask = <
+				0xd401909c 0xffffffff
+				0xd40190a0 0xffffffff
+				0xd40190a4 0xffffffff
+				0xd401919c 0xffffffff
+				0xd40191a0 0xffffffff
+				0xd40191a4 0xffffffff>;
+			gpio-pins = <0 192>;
+			#interrupt-cells = <1>;
+			interrupt-controller;
+			interrupts = <49>;
+			interrupt-parent = <&mmp_intc>;
+			sub-interrupts = <192>;
+		};
+
+		i2c0: i2c@d4011000 {
+			compatible = "pxa2xx-i2c";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xd4011000 0x60>;
+			cell-index = <0>;
+			i2c-polling = <0>;
+			i2c-frequency = "fast";
+			interrupts = <7>;
+			interrupt-parent = <&mmp_intc>;
+
+			max8649: pmic@60 {
+				compatible = "maxim,max8649";
+				reg = <0x60>;
+				max8649-mode = <2>;	/* VID1 = 1, VID0 = 0 */
+				/* <Ramp Timing, Active Ramp-Down Control > */
+				max8649-ramp = <0 0>;	/* 32mV/us, Deactive */
+
+				device_type = "regulator";
+				voltages = <750000 1380000>;
+				boot-on;
+				always-on;
+				ops-mask = "voltage", "status";
+				supply-name = "vcore";
+			};
+
+			max8925: pmic@3c {
+				compatible = "maxim,max8925";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				interrupt-controller;
+				interrupts = <1>;
+				interrupt-parent = <&mux_intc4>;
+				sub-interrupts = <32>;
+				reg = <0x3c>;
+
+				bk: backlight@0 {
+					compatible = "backlight";
+					reg = <0>;
+				};
+
+				v_mipi: regulator@ldo3 {
+					compatible = "LDO3";
+					device_type = "regulator";
+					voltages = <1000000 1500000>;
+					boot-on;
+					always-on;
+					ops-mask = "voltage", "status";
+					supply-name = "mipi_1.2v";
+					reg = <0>;
+				};
+
+				touch: touch@0 {
+					compatible = "touch";
+					interrupts = <101>;
+					interrupt-parent = <&gpio>;
+					reg = <0>;
+				};
+			};
+		};
+
+		i2c1: i2c@d4031000 {
+			compatible = "pxa2xx-i2c";
+			reg = <0xd4031000 0x60>;
+			cell-index = <1>;
+			i2c-polling = <0>;
+			i2c-frequency = "fast";
+			interrupts = <0>;
+			interrupt-parent = <&mux_intc17>;
+		};
+
+		i2c2: i2c@d4032000 {
+			compatible = "pxa2xx-i2c";
+			reg = <0xd4032000 0x60>;
+			cell-index = <2>;
+			i2c-polling = <0>;
+			i2c-frequency = "fast";
+			interrupts = <1>;
+			interrupt-parent = <&mux_intc17>;
+		};
+
+		i2c3: i2c@d4033000 {
+			compatible = "pxa2xx-i2c";
+			reg = <0xd4033000 0x60>;
+			cell-index = <3>;
+			i2c-polling = <0>;
+			i2c-frequency = "fast";
+			interrupts = <2>;
+			interrupt-parent = <&mux_intc17>;
+		};
+
+		i2c4: i2c@d4033800 {
+			compatible = "pxa2xx-i2c";
+			reg = <0xd4033800 0x60>;
+			cell-index = <4>;
+			i2c-polling = <0>;
+			i2c-frequency = "fast";
+			interrupts = <3>;
+			interrupt-parent = <&mux_intc17>;
+		};
+
+		i2c5: i2c@d4034000 {
+			compatible = "pxa2xx-i2c";
+			reg = <0xd4034000 0x60>;
+			cell-index = <5>;
+			i2c-polling = <0>;
+			i2c-frequency = "fast";
+			interrupts = <4>;
+			interrupt-parent = <&mux_intc17>;
+		};
+
+		uart0: uart@d4030000 {
+			compatible = "pxa,serial";
+			reg = <0xd4030000 0x1000>;
+			reg-shift = <2>;
+			interrupts = <27>;
+			interrupt-parent = <&mmp_intc>;
+			clock-frequency = <26000000>;
+			current-speed = <115200>;
+		};
+
+		uart1: uart@d4017000 {
+			compatible = "pxa,serial";
+			reg = <0xd4017000 0x1000>;
+			reg-shift = <2>;
+			interrupts = <28>;
+			interrupt-parent = <&mmp_intc>;
+			clock-frequency = <26000000>;
+			current-speed = <115200>;
+		};
+
+		uart2: uart@d4018000 {
+			compatible = "pxa,serial";
+			reg = <0xd4018000 0x1000>;
+			reg-shift = <2>;
+			interrupts = <24>;
+			interrupt-parent = <&mmp_intc>;
+			clock-frequency = <26000000>;
+			current-speed = <38400>;
+		};
+
+		uart3: uart@d4016000 {
+			compatible = "pxa,serial";
+			reg = <0xd4016000 0x1000>;
+			reg-shift = <2>;
+			interrupts = <46>;
+			interrupt-parent = <&mmp_intc>;
+			clock-frequency = <26000000>;
+			current-speed = <115200>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/ttc-dkb.dts b/arch/arm/boot/dts/ttc-dkb.dts
new file mode 100644
index 0000000..9d50d12
--- /dev/null
+++ b/arch/arm/boot/dts/ttc-dkb.dts
@@ -0,0 +1,176 @@
+/dts-v1/;
+
+/include/ "skeleton.dtsi"
+
+/ {
+	model = "Marvell TTC DKB";
+	compatible = "mrvl,ttc-dkb", "mrvl,pxa910-dkb";
+	interrupt-parent = <&mmp_intc>;
+
+	memory {
+		reg = <0x00000000 0x20000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200 root=/dev/nfs nfsroot=192.168.1.100:192.168.1.101::255.255.255.0::eth0:on";
+		linux,stdout-path = &uart0;
+	};
+
+	soc@d4000000 {
+		compatible = "mrvl,pxa910", "simple-bus";
+		device_type = "soc";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0xd4000000 0xd4000000 0x00200000	/* APB */
+			0xd4200000 0xd4200000 0x00200000>;	/* AXI */
+
+		mmp_intc: interrupt-controller@d4282000 {
+			compatible = "mrvl,mmp-intc";
+			interrupt-controller;
+			#interrupt-cells = <1>;
+			interrupts = <0>;
+			interrupt-parent = <&mmp_intc>;
+			sub-interrupts = <64>;
+
+			/* enable bits in conf register */
+			enable_mask = <0x51>;
+
+			/* reg: <offset & size> */
+			reg = <0xd4282000 0x400>;
+		};
+
+		gpio: gpio-controller {
+			compatible = "pxa,gpio";
+			gpio-controller;
+			reg = <
+				0xd4019000 0xb0
+				0xd4019004 0xb0
+				0xd4019008 0xb0
+				0xd4019100 0xb0>;
+
+			/* gpio-clk-value: <offset & value> */
+			gpio-clk-value = <0xd4015008 0x3>;
+
+			/* gpio-mask: <offset & value> */
+			gpio-mask = <
+				0xd401909c 0xffffffff
+				0xd40190a0 0xffffffff
+				0xd40190a4 0xffffffff
+				0xd401919c 0xffffffff>;
+			gpio-pins = <0 128>;
+			interrupt-controller;
+			#interrupt-cells = <1>;
+			interrupts = <49>;
+			interrupt-parent = <&mmp_intc>;
+			sub-interrupts = <128>;
+		};
+
+		i2c0: i2c@d4011000 {
+			compatible = "pxa2xx-i2c";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xd4011000 0x60>;
+			cell-index = <0>;
+			i2c-polling = <0>;
+			i2c-frequency = "fast";
+			interrupts = <7>;
+			interrupt-parent = <&mmp_intc>;
+
+			pm860x: pmic@34 {
+				compatible = "88PM860x";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				interrupt-controller;
+				interrupts = <4>;
+				interrupt-parent = <&mmp_intc>;
+				sub-interrupts = <24>;
+				reg = <0x34>;
+				i2c-port = <0>;
+				irq-mode = <0>;
+				companion-addr = <0x11>;
+
+				bk: backlight@0 {
+					compatible = "backlight";
+					cell-index = <0>;
+					iset = <8>;
+					reg = <0>;
+				};
+
+				led0: led@0 {
+					compatible = "led";
+					cell-index = <0>;
+					iset = <8>;
+					reg = <0>;
+				};
+
+				led1: led@1 {
+					compatible = "led";
+					cell-index = <1>;
+					iset = <8>;
+					reg = <0>;
+				};
+
+				led2: led@2 {
+					compatible = "led";
+					cell-index = <2>;
+					iset = <8>;
+					reg = <0>;
+				};
+
+				touch: touch@0 {
+					compatible = "touch";
+					interrupts = <15>;
+					interrupt-parent = <&pm860x>;
+					/* prebias: gpadc & ti & pen */
+					prebias = <1 6 16>;
+					slot-cycle = <1>;
+					pen-prechg = <2>;
+					resistor-xplate = <300>;
+					reg = <0>;
+				};
+
+				v_core: regulator@buck1 {
+					compatible = "BUCK1";
+					device_type = "regulator";
+					voltages = <900000 1400000>;
+					boot-on;
+					always-on;
+					ops-mask = "voltage";
+					constraint-name = "BUCK1";
+					supply-name = "vcc_core";
+					reg = <0>;
+				};
+			};
+		};
+
+		i2c1: i2c@d4037000 {
+			compatible = "pxa2xx-i2c";
+			reg = <0xd4037000 0x60>;
+			cell-index = <1>;
+			i2c-polling = <0>;
+			i2c-frequency = "fast";
+			interrupts = <54>;
+			interrupt-parent = <&mmp_intc>;
+		};
+
+		uart0: uart@d4017000 {
+			compatible = "pxa,serial";
+			reg = <0xd4017000 0x1000>;
+			reg-shift = <2>;
+			interrupts = <27>;
+			interrupt-parent = <&mmp_intc>;
+			clock-frequency = <14745600>;
+			current-speed = <115200>;
+		};
+
+		uart1: uart@d4018000 {
+			compatible = "pxa,serial";
+			reg = <0xd4018000 0x1000>;
+			reg-shift = <2>;
+			interrupts = <28>;
+			interrupt-parent = <&mmp_intc>;
+			clock-frequency = <14745600>;
+			current-speed = <115200>;
+		};
+	};
+};
diff --git a/arch/arm/mach-mmp/brownstone.c b/arch/arm/mach-mmp/brownstone.c
index 7bb78fd..c9848ad 100644
--- a/arch/arm/mach-mmp/brownstone.c
+++ b/arch/arm/mach-mmp/brownstone.c
@@ -12,6 +12,9 @@
 
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
@@ -105,30 +108,6 @@ static unsigned long brownstone_pin_config[] __initdata = {
 	GPIO89_GPIO,
 };
 
-static struct regulator_consumer_supply max8649_supply[] = {
-	REGULATOR_SUPPLY("vcc_core", NULL),
-};
-
-static struct regulator_init_data max8649_init_data = {
-	.constraints	= {
-		.name		= "vcc_core range",
-		.min_uV		= 1150000,
-		.max_uV		= 1280000,
-		.always_on	= 1,
-		.boot_on	= 1,
-		.valid_ops_mask	= REGULATOR_CHANGE_VOLTAGE,
-	},
-	.num_consumer_supplies	= 1,
-	.consumer_supplies	= &max8649_supply[0],
-};
-
-static struct max8649_platform_data brownstone_max8649_info = {
-	.mode		= 2,	/* VID1 = 1, VID0 = 0 */
-	.extclk		= 0,
-	.ramp_timing	= MAX8649_RAMP_32MV,
-	.regulator	= &max8649_init_data,
-};
-
 static struct regulator_consumer_supply brownstone_v_5vp_supplies[] = {
 	REGULATOR_SUPPLY("v_5vp", NULL),
 };
@@ -158,47 +137,38 @@ static struct platform_device brownstone_v_5vp_device = {
 	},
 };
 
-static struct max8925_platform_data brownstone_max8925_info = {
-	.irq_base		= IRQ_BOARD_START,
-};
-
-static struct i2c_board_info brownstone_twsi1_info[] = {
-	[0] = {
-		.type		= "max8649",
-		.addr		= 0x60,
-		.platform_data	= &brownstone_max8649_info,
-	},
-	[1] = {
-		.type		= "max8925",
-		.addr		= 0x3c,
-		.irq		= IRQ_MMP2_PMIC,
-		.platform_data	= &brownstone_max8925_info,
-	},
-};
-
 static struct sdhci_pxa_platdata mmp2_sdh_platdata_mmc0 = {
 	.max_speed	= 25000000,
 };
 
+static __initdata struct of_device_id of_bus_ids[] = {
+	{ .compatible = "simple-bus", },
+	{},
+};
+
 static void __init brownstone_init(void)
 {
 	mfp_config(ARRAY_AND_SIZE(brownstone_pin_config));
 
-	/* on-chip devices */
-	mmp2_add_uart(1);
-	mmp2_add_uart(3);
-	mmp2_add_twsi(1, NULL, ARRAY_AND_SIZE(brownstone_twsi1_info));
+	if (of_platform_bus_probe(NULL, of_bus_ids, NULL) < 0)
+		BUG();
+
 	mmp2_add_sdhost(0, &mmp2_sdh_platdata_mmc0); /* SD/MMC */
 
 	/* enable 5v regulator */
 	platform_device_register(&brownstone_v_5vp_device);
 }
 
+static const char *brownstone_dt_match[] __initdata = {
+	"mrvl,mmp2-brownstone",
+	NULL,
+};
+
 MACHINE_START(BROWNSTONE, "Brownstone Development Platform")
 	/* Maintainer: Haojian Zhuang <haojian.zhuang@marvell.com> */
 	.map_io		= mmp_map_io,
-	.nr_irqs	= BROWNSTONE_NR_IRQS,
-	.init_irq	= mmp2_init_irq,
+	.init_irq	= mmp_init_intc,
 	.timer		= &mmp2_timer,
 	.init_machine	= brownstone_init,
+	.dt_compat	= brownstone_dt_match,
 MACHINE_END
diff --git a/arch/arm/mach-mmp/ttc_dkb.c b/arch/arm/mach-mmp/ttc_dkb.c
index e411039..c19b4dc 100644
--- a/arch/arm/mach-mmp/ttc_dkb.c
+++ b/arch/arm/mach-mmp/ttc_dkb.c
@@ -10,6 +10,9 @@
 
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
@@ -113,21 +116,31 @@ static struct platform_device *ttc_dkb_devices[] = {
 	&ttc_dkb_device_onenand,
 };
 
+static __initdata struct of_device_id of_bus_ids[] = {
+	{ .compatible = "simple-bus", },
+	{},
+};
+
 static void __init ttc_dkb_init(void)
 {
 	mfp_config(ARRAY_AND_SIZE(ttc_dkb_pin_config));
 
-	/* on-chip devices */
-	pxa910_add_uart(1);
+	if (of_platform_bus_probe(NULL, of_bus_ids, NULL) < 0)
+		BUG();
 
 	/* off-chip devices */
 	platform_add_devices(ARRAY_AND_SIZE(ttc_dkb_devices));
 }
 
+static const char *ttc_dkb_dt_match[] __initdata = {
+	"mrvl,ttc-dkb",
+	NULL,
+};
+
 MACHINE_START(TTC_DKB, "PXA910-based TTC_DKB Development Platform")
 	.map_io		= mmp_map_io,
-	.nr_irqs	= TTCDKB_NR_IRQS,
-	.init_irq       = pxa910_init_irq,
+	.init_irq       = mmp_init_intc,
 	.timer          = &pxa910_timer,
 	.init_machine   = ttc_dkb_init,
+	.dt_compat	= ttc_dkb_dt_match,
 MACHINE_END
-- 
1.5.6.5

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

* [PATCH] ARM: mmp: add DTS file
@ 2011-07-08 10:20                       ` Haojian Zhuang
  0 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-08 10:20 UTC (permalink / raw)
  To: linux-arm-kernel

Add DTS file to support brownstone & ttc-dkb.

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 arch/arm/boot/dts/mmp2-brownstone.dts |  319 +++++++++++++++++++++++++++++++++
 arch/arm/boot/dts/ttc-dkb.dts         |  176 ++++++++++++++++++
 arch/arm/mach-mmp/brownstone.c        |   66 ++-----
 arch/arm/mach-mmp/ttc_dkb.c           |   21 ++-
 4 files changed, 530 insertions(+), 52 deletions(-)
 create mode 100644 arch/arm/boot/dts/mmp2-brownstone.dts
 create mode 100644 arch/arm/boot/dts/ttc-dkb.dts

diff --git a/arch/arm/boot/dts/mmp2-brownstone.dts b/arch/arm/boot/dts/mmp2-brownstone.dts
new file mode 100644
index 0000000..5fdabc3
--- /dev/null
+++ b/arch/arm/boot/dts/mmp2-brownstone.dts
@@ -0,0 +1,319 @@
+/dts-v1/;
+
+/include/ "skeleton.dtsi"
+
+/ {
+	model = "Marvell MMP2 Brownstone";
+	compatible = "mrvl,mmp2-brownstone", "mrvl,armada610-brownstone";
+	interrupt-parent = <&mmp_intc>;
+
+	memory {
+		reg = <0x00000000 0x20000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS2,38400 root=/dev/nfs nfsroot=192.168.1.100:192.168.1.101::255.255.255.0::eth0:on";
+		linux,stdout-path = &uart2;
+	};
+
+	soc at d4000000 {
+		compatible = "mrvl,mmp2", "mrvl,armada610", "simple-bus";
+		device_type = "soc";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		mmp_intc: interrupt-controller at d4282000 {
+			compatible = "mrvl,mmp-intc";
+			/*device_type = "intc";*/
+			interrupt-controller;
+			#interrupt-cells = <1>;
+			/*
+			 * interrupts: irq index of parent's irq domain
+			 */
+			interrupts = <0>;
+			interrupt-parent = <&mmp_intc>;
+			sub-interrupts = <64>;
+
+			/* enable bits in conf register */
+			enable_mask = <0x20>;
+
+			/* reg: <offset & size> */
+			reg = <0xd4282000 0x400>;
+		};
+
+		mux_intc4: interrupt-controller at d4282150 {
+			compatible = "mrvl,mux-intc";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			#interrupt-cells = <1>;
+			interrupt-controller;
+			interrupts = <4>;
+			interrupt-parent = <&mmp_intc>;
+			sub-interrupts = <2>;
+			reg = <0xd4282150 0>;
+			status-mask = <0x150 0x168>;
+			/* mfp register & interrupt index */
+			mfp-edge-interrupt = <0xd401e2c4 1>;
+		};
+
+		mux_intc5: interrupt-controller at d4282154 {
+			compatible = "mrvl,mux-intc";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			#interrupt-cells = <1>;
+			interrupt-controller;
+			interrupts = <5>;
+			sub-interrupts = <2>;
+			interrupt-parent = <&mmp_intc>;
+			reg = <0xd4282154 0>;
+			status-mask = <0x154 0x16c>;
+		};
+
+		mux_intc9: interrupt-controller at d4282180 {
+			compatible = "mrvl,mux-intc";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			#interrupt-cells = <1>;
+			interrupt-controller;
+			interrupts = <9>;
+			interrupt-parent = <&mmp_intc>;
+			sub-interrupts = <3>;
+			reg = <0xd4282180 0>;
+			status-mask = <0x180 0x17c>;
+		};
+
+		mux_intc17: interrupt-controller at d4282158 {
+			compatible = "mrvl,mux-intc";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			#interrupt-cells = <1>;
+			interrupt-controller;
+			interrupts = <17>;
+			interrupt-parent = <&mmp_intc>;
+			sub-interrupts = <5>;
+			reg = <0xd4282158 0>;
+			status-mask = <0x158 0x170>;
+		};
+
+		mux_intc35: interrupt-controller at d428215c {
+			compatible = "mrvl,mux-intc";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			#interrupt-cells = <1>;
+			interrupt-controller;
+			interrupts = <35>;
+			interrupt-parent = <&mmp_intc>;
+			sub-interrupts = <15>;
+			reg = <0xd428215c 0>;
+			status-mask = <0x15c 0x174>;
+		};
+
+		mux_intc51: interrupt-controller at d4282160 {
+			compatible = "mrvl,mux-intc";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			#interrupt-cells = <1>;
+			interrupt-controller;
+			interrupts = <51>;
+			interrupt-parent = <&mmp_intc>;
+			sub-interrupts = <2>;
+			reg = <0xd4282160 0>;
+			status-mask = <0x160 0x178>;
+		};
+
+		mux_intc55: interrupt-controller at d4282188 {
+			compatible = "mrvl,mux-intc";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			#interrupt-cells = <1>;
+			interrupt-controller;
+			interrupts = <55>;
+			interrupt-parent = <&mmp_intc>;
+			sub-interrupts = <2>;
+			reg = <0xd4282188 0>;
+			status-mask = <0x188 0x184>;
+		};
+
+		gpio: gpio-controller {
+			compatible = "pxa,gpio";
+			gpio-controller;
+			reg = <
+				0xd4019000 0xb0
+				0xd4019004 0xb0
+				0xd4019008 0xb0
+				0xd4019100 0xb0
+				0xd4019104 0xb0
+				0xd4019108 0xb0>;
+
+			/* gpio-clk-value: <offset & value> */
+			gpio-clk-value = <0xd4015038 0x3>;
+
+			/* gpio-mask: <offset & value> */
+			gpio-mask = <
+				0xd401909c 0xffffffff
+				0xd40190a0 0xffffffff
+				0xd40190a4 0xffffffff
+				0xd401919c 0xffffffff
+				0xd40191a0 0xffffffff
+				0xd40191a4 0xffffffff>;
+			gpio-pins = <0 192>;
+			#interrupt-cells = <1>;
+			interrupt-controller;
+			interrupts = <49>;
+			interrupt-parent = <&mmp_intc>;
+			sub-interrupts = <192>;
+		};
+
+		i2c0: i2c at d4011000 {
+			compatible = "pxa2xx-i2c";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xd4011000 0x60>;
+			cell-index = <0>;
+			i2c-polling = <0>;
+			i2c-frequency = "fast";
+			interrupts = <7>;
+			interrupt-parent = <&mmp_intc>;
+
+			max8649: pmic at 60 {
+				compatible = "maxim,max8649";
+				reg = <0x60>;
+				max8649-mode = <2>;	/* VID1 = 1, VID0 = 0 */
+				/* <Ramp Timing, Active Ramp-Down Control > */
+				max8649-ramp = <0 0>;	/* 32mV/us, Deactive */
+
+				device_type = "regulator";
+				voltages = <750000 1380000>;
+				boot-on;
+				always-on;
+				ops-mask = "voltage", "status";
+				supply-name = "vcore";
+			};
+
+			max8925: pmic at 3c {
+				compatible = "maxim,max8925";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				interrupt-controller;
+				interrupts = <1>;
+				interrupt-parent = <&mux_intc4>;
+				sub-interrupts = <32>;
+				reg = <0x3c>;
+
+				bk: backlight at 0 {
+					compatible = "backlight";
+					reg = <0>;
+				};
+
+				v_mipi: regulator at ldo3 {
+					compatible = "LDO3";
+					device_type = "regulator";
+					voltages = <1000000 1500000>;
+					boot-on;
+					always-on;
+					ops-mask = "voltage", "status";
+					supply-name = "mipi_1.2v";
+					reg = <0>;
+				};
+
+				touch: touch at 0 {
+					compatible = "touch";
+					interrupts = <101>;
+					interrupt-parent = <&gpio>;
+					reg = <0>;
+				};
+			};
+		};
+
+		i2c1: i2c at d4031000 {
+			compatible = "pxa2xx-i2c";
+			reg = <0xd4031000 0x60>;
+			cell-index = <1>;
+			i2c-polling = <0>;
+			i2c-frequency = "fast";
+			interrupts = <0>;
+			interrupt-parent = <&mux_intc17>;
+		};
+
+		i2c2: i2c at d4032000 {
+			compatible = "pxa2xx-i2c";
+			reg = <0xd4032000 0x60>;
+			cell-index = <2>;
+			i2c-polling = <0>;
+			i2c-frequency = "fast";
+			interrupts = <1>;
+			interrupt-parent = <&mux_intc17>;
+		};
+
+		i2c3: i2c at d4033000 {
+			compatible = "pxa2xx-i2c";
+			reg = <0xd4033000 0x60>;
+			cell-index = <3>;
+			i2c-polling = <0>;
+			i2c-frequency = "fast";
+			interrupts = <2>;
+			interrupt-parent = <&mux_intc17>;
+		};
+
+		i2c4: i2c at d4033800 {
+			compatible = "pxa2xx-i2c";
+			reg = <0xd4033800 0x60>;
+			cell-index = <4>;
+			i2c-polling = <0>;
+			i2c-frequency = "fast";
+			interrupts = <3>;
+			interrupt-parent = <&mux_intc17>;
+		};
+
+		i2c5: i2c at d4034000 {
+			compatible = "pxa2xx-i2c";
+			reg = <0xd4034000 0x60>;
+			cell-index = <5>;
+			i2c-polling = <0>;
+			i2c-frequency = "fast";
+			interrupts = <4>;
+			interrupt-parent = <&mux_intc17>;
+		};
+
+		uart0: uart at d4030000 {
+			compatible = "pxa,serial";
+			reg = <0xd4030000 0x1000>;
+			reg-shift = <2>;
+			interrupts = <27>;
+			interrupt-parent = <&mmp_intc>;
+			clock-frequency = <26000000>;
+			current-speed = <115200>;
+		};
+
+		uart1: uart at d4017000 {
+			compatible = "pxa,serial";
+			reg = <0xd4017000 0x1000>;
+			reg-shift = <2>;
+			interrupts = <28>;
+			interrupt-parent = <&mmp_intc>;
+			clock-frequency = <26000000>;
+			current-speed = <115200>;
+		};
+
+		uart2: uart at d4018000 {
+			compatible = "pxa,serial";
+			reg = <0xd4018000 0x1000>;
+			reg-shift = <2>;
+			interrupts = <24>;
+			interrupt-parent = <&mmp_intc>;
+			clock-frequency = <26000000>;
+			current-speed = <38400>;
+		};
+
+		uart3: uart at d4016000 {
+			compatible = "pxa,serial";
+			reg = <0xd4016000 0x1000>;
+			reg-shift = <2>;
+			interrupts = <46>;
+			interrupt-parent = <&mmp_intc>;
+			clock-frequency = <26000000>;
+			current-speed = <115200>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/ttc-dkb.dts b/arch/arm/boot/dts/ttc-dkb.dts
new file mode 100644
index 0000000..9d50d12
--- /dev/null
+++ b/arch/arm/boot/dts/ttc-dkb.dts
@@ -0,0 +1,176 @@
+/dts-v1/;
+
+/include/ "skeleton.dtsi"
+
+/ {
+	model = "Marvell TTC DKB";
+	compatible = "mrvl,ttc-dkb", "mrvl,pxa910-dkb";
+	interrupt-parent = <&mmp_intc>;
+
+	memory {
+		reg = <0x00000000 0x20000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200 root=/dev/nfs nfsroot=192.168.1.100:192.168.1.101::255.255.255.0::eth0:on";
+		linux,stdout-path = &uart0;
+	};
+
+	soc at d4000000 {
+		compatible = "mrvl,pxa910", "simple-bus";
+		device_type = "soc";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0xd4000000 0xd4000000 0x00200000	/* APB */
+			0xd4200000 0xd4200000 0x00200000>;	/* AXI */
+
+		mmp_intc: interrupt-controller at d4282000 {
+			compatible = "mrvl,mmp-intc";
+			interrupt-controller;
+			#interrupt-cells = <1>;
+			interrupts = <0>;
+			interrupt-parent = <&mmp_intc>;
+			sub-interrupts = <64>;
+
+			/* enable bits in conf register */
+			enable_mask = <0x51>;
+
+			/* reg: <offset & size> */
+			reg = <0xd4282000 0x400>;
+		};
+
+		gpio: gpio-controller {
+			compatible = "pxa,gpio";
+			gpio-controller;
+			reg = <
+				0xd4019000 0xb0
+				0xd4019004 0xb0
+				0xd4019008 0xb0
+				0xd4019100 0xb0>;
+
+			/* gpio-clk-value: <offset & value> */
+			gpio-clk-value = <0xd4015008 0x3>;
+
+			/* gpio-mask: <offset & value> */
+			gpio-mask = <
+				0xd401909c 0xffffffff
+				0xd40190a0 0xffffffff
+				0xd40190a4 0xffffffff
+				0xd401919c 0xffffffff>;
+			gpio-pins = <0 128>;
+			interrupt-controller;
+			#interrupt-cells = <1>;
+			interrupts = <49>;
+			interrupt-parent = <&mmp_intc>;
+			sub-interrupts = <128>;
+		};
+
+		i2c0: i2c at d4011000 {
+			compatible = "pxa2xx-i2c";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xd4011000 0x60>;
+			cell-index = <0>;
+			i2c-polling = <0>;
+			i2c-frequency = "fast";
+			interrupts = <7>;
+			interrupt-parent = <&mmp_intc>;
+
+			pm860x: pmic at 34 {
+				compatible = "88PM860x";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				interrupt-controller;
+				interrupts = <4>;
+				interrupt-parent = <&mmp_intc>;
+				sub-interrupts = <24>;
+				reg = <0x34>;
+				i2c-port = <0>;
+				irq-mode = <0>;
+				companion-addr = <0x11>;
+
+				bk: backlight at 0 {
+					compatible = "backlight";
+					cell-index = <0>;
+					iset = <8>;
+					reg = <0>;
+				};
+
+				led0: led at 0 {
+					compatible = "led";
+					cell-index = <0>;
+					iset = <8>;
+					reg = <0>;
+				};
+
+				led1: led at 1 {
+					compatible = "led";
+					cell-index = <1>;
+					iset = <8>;
+					reg = <0>;
+				};
+
+				led2: led at 2 {
+					compatible = "led";
+					cell-index = <2>;
+					iset = <8>;
+					reg = <0>;
+				};
+
+				touch: touch at 0 {
+					compatible = "touch";
+					interrupts = <15>;
+					interrupt-parent = <&pm860x>;
+					/* prebias: gpadc & ti & pen */
+					prebias = <1 6 16>;
+					slot-cycle = <1>;
+					pen-prechg = <2>;
+					resistor-xplate = <300>;
+					reg = <0>;
+				};
+
+				v_core: regulator at buck1 {
+					compatible = "BUCK1";
+					device_type = "regulator";
+					voltages = <900000 1400000>;
+					boot-on;
+					always-on;
+					ops-mask = "voltage";
+					constraint-name = "BUCK1";
+					supply-name = "vcc_core";
+					reg = <0>;
+				};
+			};
+		};
+
+		i2c1: i2c at d4037000 {
+			compatible = "pxa2xx-i2c";
+			reg = <0xd4037000 0x60>;
+			cell-index = <1>;
+			i2c-polling = <0>;
+			i2c-frequency = "fast";
+			interrupts = <54>;
+			interrupt-parent = <&mmp_intc>;
+		};
+
+		uart0: uart at d4017000 {
+			compatible = "pxa,serial";
+			reg = <0xd4017000 0x1000>;
+			reg-shift = <2>;
+			interrupts = <27>;
+			interrupt-parent = <&mmp_intc>;
+			clock-frequency = <14745600>;
+			current-speed = <115200>;
+		};
+
+		uart1: uart at d4018000 {
+			compatible = "pxa,serial";
+			reg = <0xd4018000 0x1000>;
+			reg-shift = <2>;
+			interrupts = <28>;
+			interrupt-parent = <&mmp_intc>;
+			clock-frequency = <14745600>;
+			current-speed = <115200>;
+		};
+	};
+};
diff --git a/arch/arm/mach-mmp/brownstone.c b/arch/arm/mach-mmp/brownstone.c
index 7bb78fd..c9848ad 100644
--- a/arch/arm/mach-mmp/brownstone.c
+++ b/arch/arm/mach-mmp/brownstone.c
@@ -12,6 +12,9 @@
 
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
@@ -105,30 +108,6 @@ static unsigned long brownstone_pin_config[] __initdata = {
 	GPIO89_GPIO,
 };
 
-static struct regulator_consumer_supply max8649_supply[] = {
-	REGULATOR_SUPPLY("vcc_core", NULL),
-};
-
-static struct regulator_init_data max8649_init_data = {
-	.constraints	= {
-		.name		= "vcc_core range",
-		.min_uV		= 1150000,
-		.max_uV		= 1280000,
-		.always_on	= 1,
-		.boot_on	= 1,
-		.valid_ops_mask	= REGULATOR_CHANGE_VOLTAGE,
-	},
-	.num_consumer_supplies	= 1,
-	.consumer_supplies	= &max8649_supply[0],
-};
-
-static struct max8649_platform_data brownstone_max8649_info = {
-	.mode		= 2,	/* VID1 = 1, VID0 = 0 */
-	.extclk		= 0,
-	.ramp_timing	= MAX8649_RAMP_32MV,
-	.regulator	= &max8649_init_data,
-};
-
 static struct regulator_consumer_supply brownstone_v_5vp_supplies[] = {
 	REGULATOR_SUPPLY("v_5vp", NULL),
 };
@@ -158,47 +137,38 @@ static struct platform_device brownstone_v_5vp_device = {
 	},
 };
 
-static struct max8925_platform_data brownstone_max8925_info = {
-	.irq_base		= IRQ_BOARD_START,
-};
-
-static struct i2c_board_info brownstone_twsi1_info[] = {
-	[0] = {
-		.type		= "max8649",
-		.addr		= 0x60,
-		.platform_data	= &brownstone_max8649_info,
-	},
-	[1] = {
-		.type		= "max8925",
-		.addr		= 0x3c,
-		.irq		= IRQ_MMP2_PMIC,
-		.platform_data	= &brownstone_max8925_info,
-	},
-};
-
 static struct sdhci_pxa_platdata mmp2_sdh_platdata_mmc0 = {
 	.max_speed	= 25000000,
 };
 
+static __initdata struct of_device_id of_bus_ids[] = {
+	{ .compatible = "simple-bus", },
+	{},
+};
+
 static void __init brownstone_init(void)
 {
 	mfp_config(ARRAY_AND_SIZE(brownstone_pin_config));
 
-	/* on-chip devices */
-	mmp2_add_uart(1);
-	mmp2_add_uart(3);
-	mmp2_add_twsi(1, NULL, ARRAY_AND_SIZE(brownstone_twsi1_info));
+	if (of_platform_bus_probe(NULL, of_bus_ids, NULL) < 0)
+		BUG();
+
 	mmp2_add_sdhost(0, &mmp2_sdh_platdata_mmc0); /* SD/MMC */
 
 	/* enable 5v regulator */
 	platform_device_register(&brownstone_v_5vp_device);
 }
 
+static const char *brownstone_dt_match[] __initdata = {
+	"mrvl,mmp2-brownstone",
+	NULL,
+};
+
 MACHINE_START(BROWNSTONE, "Brownstone Development Platform")
 	/* Maintainer: Haojian Zhuang <haojian.zhuang@marvell.com> */
 	.map_io		= mmp_map_io,
-	.nr_irqs	= BROWNSTONE_NR_IRQS,
-	.init_irq	= mmp2_init_irq,
+	.init_irq	= mmp_init_intc,
 	.timer		= &mmp2_timer,
 	.init_machine	= brownstone_init,
+	.dt_compat	= brownstone_dt_match,
 MACHINE_END
diff --git a/arch/arm/mach-mmp/ttc_dkb.c b/arch/arm/mach-mmp/ttc_dkb.c
index e411039..c19b4dc 100644
--- a/arch/arm/mach-mmp/ttc_dkb.c
+++ b/arch/arm/mach-mmp/ttc_dkb.c
@@ -10,6 +10,9 @@
 
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
@@ -113,21 +116,31 @@ static struct platform_device *ttc_dkb_devices[] = {
 	&ttc_dkb_device_onenand,
 };
 
+static __initdata struct of_device_id of_bus_ids[] = {
+	{ .compatible = "simple-bus", },
+	{},
+};
+
 static void __init ttc_dkb_init(void)
 {
 	mfp_config(ARRAY_AND_SIZE(ttc_dkb_pin_config));
 
-	/* on-chip devices */
-	pxa910_add_uart(1);
+	if (of_platform_bus_probe(NULL, of_bus_ids, NULL) < 0)
+		BUG();
 
 	/* off-chip devices */
 	platform_add_devices(ARRAY_AND_SIZE(ttc_dkb_devices));
 }
 
+static const char *ttc_dkb_dt_match[] __initdata = {
+	"mrvl,ttc-dkb",
+	NULL,
+};
+
 MACHINE_START(TTC_DKB, "PXA910-based TTC_DKB Development Platform")
 	.map_io		= mmp_map_io,
-	.nr_irqs	= TTCDKB_NR_IRQS,
-	.init_irq       = pxa910_init_irq,
+	.init_irq       = mmp_init_intc,
 	.timer          = &pxa910_timer,
 	.init_machine   = ttc_dkb_init,
+	.dt_compat	= ttc_dkb_dt_match,
 MACHINE_END
-- 
1.5.6.5

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

* Re: [PATCH] ARM: mmp: remove SPARSE_IRQ for mmp
  2011-07-08 10:20 ` Haojian Zhuang
@ 2011-07-08 14:46     ` Grant Likely
  -1 siblings, 0 replies; 58+ messages in thread
From: Grant Likely @ 2011-07-08 14:46 UTC (permalink / raw)
  To: Haojian Zhuang
  Cc: eric.y.miao-Re5JQEeQqe8AvxtiuMwx3w,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	samuel.ortiz-ral2JQCrhuEAvxtiuMwx3w,
	linux-lFZ/pmaqli7XmaaqVzeoHQ, Thomas Gleixner,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	alan-VuQAYsv1563Yd54FQh9/CA

On Fri, Jul 8, 2011 at 4:20 AM, Haojian Zhuang
<haojian.zhuang-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org> wrote:
> Avoid to use SPARSE_IRQ for mmp. There will be irq domain translation between
> DT irq specifier and the Linux irq number.
>
> Signed-off-by: Haojian Zhuang <haojian.zhuang-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>

I believe the goal is to use more sparse_irq, not less, and the
irq_domain code works fine either way.

g.

> ---
>  arch/arm/Kconfig |    1 -
>  1 files changed, 0 insertions(+), 1 deletions(-)
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 17507b8..48748fb 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -545,7 +545,6 @@ config ARCH_MMP
>        select HAVE_SCHED_CLOCK
>        select TICK_ONESHOT
>        select PLAT_PXA
> -       select SPARSE_IRQ
>        help
>          Support for Marvell's PXA168/PXA910(MMP) and MMP2 processor line.
>
> --
> 1.5.6.5
>
>



-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

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

* [PATCH] ARM: mmp: remove SPARSE_IRQ for mmp
@ 2011-07-08 14:46     ` Grant Likely
  0 siblings, 0 replies; 58+ messages in thread
From: Grant Likely @ 2011-07-08 14:46 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 8, 2011 at 4:20 AM, Haojian Zhuang
<haojian.zhuang@marvell.com> wrote:
> Avoid to use SPARSE_IRQ for mmp. There will be irq domain translation between
> DT irq specifier and the Linux irq number.
>
> Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>

I believe the goal is to use more sparse_irq, not less, and the
irq_domain code works fine either way.

g.

> ---
> ?arch/arm/Kconfig | ? ?1 -
> ?1 files changed, 0 insertions(+), 1 deletions(-)
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 17507b8..48748fb 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -545,7 +545,6 @@ config ARCH_MMP
> ? ? ? ?select HAVE_SCHED_CLOCK
> ? ? ? ?select TICK_ONESHOT
> ? ? ? ?select PLAT_PXA
> - ? ? ? select SPARSE_IRQ
> ? ? ? ?help
> ? ? ? ? ?Support for Marvell's PXA168/PXA910(MMP) and MMP2 processor line.
>
> --
> 1.5.6.5
>
>



-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

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

* Re: [PATCH] of: add devicetree API for regulator
  2011-07-08 10:20               ` Haojian Zhuang
@ 2011-07-08 14:51                   ` Grant Likely
  -1 siblings, 0 replies; 58+ messages in thread
From: Grant Likely @ 2011-07-08 14:51 UTC (permalink / raw)
  To: Haojian Zhuang
  Cc: eric.y.miao-Re5JQEeQqe8AvxtiuMwx3w,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	samuel.ortiz-ral2JQCrhuEAvxtiuMwx3w,
	linux-lFZ/pmaqli7XmaaqVzeoHQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	alan-VuQAYsv1563Yd54FQh9/CA

Hi Haojian,

On Fri, Jul 8, 2011 at 4:20 AM, Haojian Zhuang
<haojian.zhuang-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org> wrote:
> Signed-off-by: Haojian Zhuang <haojian.zhuang-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>

No commit description?

> ---
>  drivers/of/Kconfig           |    4 +
>  drivers/of/Makefile          |    1 +
>  drivers/of/of_regulator.c    |  166 ++++++++++++++++++++++++++++++++++++++++++
>  include/linux/of_regulator.h |   34 +++++++++
>  4 files changed, 205 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/of/of_regulator.c
>  create mode 100644 include/linux/of_regulator.h
>
> diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
> index d06a637..edb6601 100644
> --- a/drivers/of/Kconfig
> +++ b/drivers/of/Kconfig
> @@ -75,4 +75,8 @@ config OF_PCI
>        help
>          OpenFirmware PCI bus accessors
>
> +config OF_REGULATOR
> +       def_tristate REGULATOR
> +       depends on REGULATOR
> +
>  endmenu # OF
> diff --git a/drivers/of/Makefile b/drivers/of/Makefile
> index f7861ed..83ca06f 100644
> --- a/drivers/of/Makefile
> +++ b/drivers/of/Makefile
> @@ -10,3 +10,4 @@ obj-$(CONFIG_OF_NET)  += of_net.o
>  obj-$(CONFIG_OF_SPI)   += of_spi.o
>  obj-$(CONFIG_OF_MDIO)  += of_mdio.o
>  obj-$(CONFIG_OF_PCI)   += of_pci.o
> +obj-$(CONFIG_OF_REGULATOR)     += of_regulator.o
> diff --git a/drivers/of/of_regulator.c b/drivers/of/of_regulator.c
> new file mode 100644
> index 0000000..d523302
> --- /dev/null
> +++ b/drivers/of/of_regulator.c
> @@ -0,0 +1,166 @@
> +/*
> + * OF helpers for the Regulator API
> + *
> + * Copyright (c) 2011 Haojian Zhuang <haojian.zhuang-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.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.
> + */
> +#include <linux/kernel.h>
> +#include <linux/of.h>
> +#include <linux/regulator/machine.h>
> +#include <linux/slab.h>
> +#include <linux/string.h>
> +#include <linux/suspend.h>
> +
> +static int of_regulator_init_constraints(struct device_node *of_dev,
> +                               struct regulation_constraints *constraints)
> +{
> +       const __be32 *p;
> +       const char *cp;
> +       const char *ops[] = {"voltage", "current", "mode", "status",
> +                               "drms"};
> +       int i, size, len = 0, tmp = 0;
> +
> +       memset(constraints, 0, sizeof(struct regulation_constraints));
> +
> +       p = of_get_property(of_dev, "voltages", &size);
> +       if (p && size / sizeof(int) == 2) {
> +               constraints->min_uV = be32_to_cpu(*p++);
> +               constraints->max_uV = be32_to_cpu(*p);
> +       }

You can probably simplify a lot of code by using
of_property_read_u32_array(), which is currently in devicetree/next

> +       p = of_get_property(of_dev, "currents", &size);
> +       if (p && size / sizeof(int) == 2) {
> +               constraints->min_uA = be32_to_cpu(*p++);
> +               constraints->max_uA = be32_to_cpu(*p);
> +       }
> +       p = of_get_property(of_dev, "modes-mask", NULL);
> +       if (p)
> +               constraints->valid_modes_mask = be32_to_cpu(*p);
> +       cp = of_get_property(of_dev, "ops-mask", &size);
> +       tmp = 0;
> +       if (cp && size > 0) {
> +               i = 0;
> +               do {
> +                       len = strlen(ops[i]);
> +                       if (!strncmp(cp, ops[i], len)) {
> +                               constraints->valid_ops_mask |= 1 << i;
> +                               /* need to handle '\0' */
> +                               cp += len + 1;
> +                               size = size - len - 1;
> +                               i = 0;
> +                       } else
> +                               i++;
> +               } while (i < ARRAY_SIZE(ops));
> +               if (size > 0)
> +                       printk(KERN_WARNING "Invalid string:%s\n", cp);
> +       }
> +       p = of_get_property(of_dev, "input-uV", NULL);
> +       if (p)
> +               constraints->input_uV = be32_to_cpu(*p);
> +       p = of_get_property(of_dev, "state-pm-disk", &size);
> +       if (p && size / sizeof(int) == 3) {
> +               constraints->state_disk.uV = be32_to_cpu(*p++);
> +               constraints->state_disk.mode = be32_to_cpu(*p++);
> +               tmp = be32_to_cpu(*p);
> +               constraints->state_disk.enabled = (tmp) ? 1 : 0;
> +               constraints->state_disk.disabled = (tmp) ? 0 : 1;
> +       }
> +       p = of_get_property(of_dev, "state-pm-mem", &size);
> +       if (p && size / sizeof(int) == 3) {
> +               constraints->state_mem.uV = be32_to_cpu(*p++);
> +               constraints->state_mem.mode = be32_to_cpu(*p++);
> +               tmp = be32_to_cpu(*p);
> +               constraints->state_mem.enabled = (tmp) ? 1 : 0;
> +               constraints->state_mem.disabled = (tmp) ? 0 : 1;
> +       }
> +       p = of_get_property(of_dev, "state-pm-standby", &size);
> +       if (p && size / sizeof(int) == 3) {
> +               constraints->state_standby.uV = be32_to_cpu(*p++);
> +               constraints->state_standby.mode = be32_to_cpu(*p++);
> +               tmp = be32_to_cpu(*p);
> +               constraints->state_standby.enabled = (tmp) ? 1 : 0;
> +               constraints->state_standby.disabled = (tmp) ? 0 : 1;
> +       }
> +       cp = of_get_property(of_dev, "initial-state", &size);
> +       if (cp) {
> +               if (!strncmp(cp, "pm-suspend-on", size))
> +                       constraints->initial_state = PM_SUSPEND_ON;
> +               if (!strncmp(cp, "pm-suspend-mem", size))
> +                       constraints->initial_state = PM_SUSPEND_MEM;
> +               if (!strncmp(cp, "pm-suspend-standby", size))
> +                       constraints->initial_state = PM_SUSPEND_STANDBY;
> +       }
> +       p = of_get_property(of_dev, "initial_mode", NULL);
> +       if (p)
> +               constraints->initial_mode = be32_to_cpu(*p);
> +       p = of_get_property(of_dev, "always-on", NULL);
> +       if (p)
> +               constraints->always_on = 1;
> +       p = of_get_property(of_dev, "boot-on", NULL);
> +       if (p)
> +               constraints->boot_on = 1;
> +       p = of_get_property(of_dev, "apply-uV", NULL);
> +       if (p)
> +               constraints->apply_uV = 1;
> +       return 0;
> +}

This code is implementing a new binding which needs to be documented
in Documentation/devicetree/bindings.  It is hard to review the patch
without some accompanying documentation about how you expect it to be
used.

> +
> +int of_regulator_init_data(struct device_node *of_dev,
> +                       struct regulator_init_data *data)
> +{
> +       struct regulator_consumer_supply *supply;
> +       const char *p, *str;
> +       int ret, i, size, calc_size, len, count = 0;
> +
> +       if (of_dev == NULL || data == NULL)
> +               return -EINVAL;
> +
> +       p = of_get_property(of_dev, "device_type", &size);
> +       if (p == NULL || strncmp(p, "regulator", size))
> +               return -EINVAL;
> +
> +       ret = of_regulator_init_constraints(of_dev, &data->constraints);
> +       if (ret)
> +               return ret;
> +       p = of_get_property(of_dev, "supply-name", &size);
> +       str = p;
> +       calc_size = size;
> +       while (str && calc_size > 0) {
> +               len = strlen(str);
> +               if (len == 0)
> +                       break;
> +               calc_size = calc_size - len - 1;
> +               str += len + 1;
> +               count++;
> +       }
> +       if (count == 0)
> +               return -EINVAL;
> +
> +       supply = kzalloc(sizeof(struct regulator_consumer_supply) * count,
> +               GFP_KERNEL);
> +       if (supply == NULL)
> +               return -EINVAL;
> +       str = p;
> +       calc_size = size;
> +       i = 0;
> +       while (str && calc_size > 0 && i < count) {
> +               len = strlen(str);
> +               if (len == 0)
> +                       break;
> +               supply[i++].supply = str;
> +               calc_size = calc_size - len - 1;
> +               str += len + 1;
> +       }
> +       data->consumer_supplies = supply;
> +       data->num_consumer_supplies = count;
> +       return 0;
> +}
> +
> +void of_regulator_deinit_data(struct regulator_init_data *data)
> +{
> +       if (data && data->consumer_supplies)
> +               kfree(data->consumer_supplies);
> +}
> diff --git a/include/linux/of_regulator.h b/include/linux/of_regulator.h
> new file mode 100644
> index 0000000..0155bd8
> --- /dev/null
> +++ b/include/linux/of_regulator.h
> @@ -0,0 +1,34 @@
> +/*
> + * Generic Regulator API implementation
> + *
> + * Copyright (c) 2011 Haojian Zhuang <haojian.zhuang-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.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.
> + */
> +
> +#ifndef __LINUX_OF_REGULATOR_H
> +#define __LINUX_OF_REGULATOR_H
> +
> +#if defined(CONFIG_OF_REGULATOR) || defined(CONFIG_OF_REGULATOR_MODULE)
> +#include <linux/regulator/machine.h>
> +
> +extern int of_regulator_init_data(struct device_node *of_node,
> +                               struct regulator_init_data *data);
> +extern void of_regulator_deinit_data(struct regulator_init_data *data);
> +
> +#else
> +static inline int of_regulator_init_data(struct device_node *of_node,
> +                               struct regulator_init_data *data)
> +{
> +       return 0;
> +}
> +
> +static inline void of_regulator_deinit_data(struct regulator_init_data *data)
> +{
> +}
> +#endif /* CONFIG_OF_REGULATOR */
> +
> +#endif /* __LINUX_OF_REGULATOR_H */
> --
> 1.5.6.5
>
>



-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

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

* [PATCH] of: add devicetree API for regulator
@ 2011-07-08 14:51                   ` Grant Likely
  0 siblings, 0 replies; 58+ messages in thread
From: Grant Likely @ 2011-07-08 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Haojian,

On Fri, Jul 8, 2011 at 4:20 AM, Haojian Zhuang
<haojian.zhuang@marvell.com> wrote:
> Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>

No commit description?

> ---
> ?drivers/of/Kconfig ? ? ? ? ? | ? ?4 +
> ?drivers/of/Makefile ? ? ? ? ?| ? ?1 +
> ?drivers/of/of_regulator.c ? ?| ?166 ++++++++++++++++++++++++++++++++++++++++++
> ?include/linux/of_regulator.h | ? 34 +++++++++
> ?4 files changed, 205 insertions(+), 0 deletions(-)
> ?create mode 100644 drivers/of/of_regulator.c
> ?create mode 100644 include/linux/of_regulator.h
>
> diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
> index d06a637..edb6601 100644
> --- a/drivers/of/Kconfig
> +++ b/drivers/of/Kconfig
> @@ -75,4 +75,8 @@ config OF_PCI
> ? ? ? ?help
> ? ? ? ? ?OpenFirmware PCI bus accessors
>
> +config OF_REGULATOR
> + ? ? ? def_tristate REGULATOR
> + ? ? ? depends on REGULATOR
> +
> ?endmenu # OF
> diff --git a/drivers/of/Makefile b/drivers/of/Makefile
> index f7861ed..83ca06f 100644
> --- a/drivers/of/Makefile
> +++ b/drivers/of/Makefile
> @@ -10,3 +10,4 @@ obj-$(CONFIG_OF_NET) ?+= of_net.o
> ?obj-$(CONFIG_OF_SPI) ? += of_spi.o
> ?obj-$(CONFIG_OF_MDIO) ?+= of_mdio.o
> ?obj-$(CONFIG_OF_PCI) ? += of_pci.o
> +obj-$(CONFIG_OF_REGULATOR) ? ? += of_regulator.o
> diff --git a/drivers/of/of_regulator.c b/drivers/of/of_regulator.c
> new file mode 100644
> index 0000000..d523302
> --- /dev/null
> +++ b/drivers/of/of_regulator.c
> @@ -0,0 +1,166 @@
> +/*
> + * OF helpers for the Regulator API
> + *
> + * Copyright (c) 2011 Haojian Zhuang <haojian.zhuang@marvell.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +#include <linux/kernel.h>
> +#include <linux/of.h>
> +#include <linux/regulator/machine.h>
> +#include <linux/slab.h>
> +#include <linux/string.h>
> +#include <linux/suspend.h>
> +
> +static int of_regulator_init_constraints(struct device_node *of_dev,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct regulation_constraints *constraints)
> +{
> + ? ? ? const __be32 *p;
> + ? ? ? const char *cp;
> + ? ? ? const char *ops[] = {"voltage", "current", "mode", "status",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "drms"};
> + ? ? ? int i, size, len = 0, tmp = 0;
> +
> + ? ? ? memset(constraints, 0, sizeof(struct regulation_constraints));
> +
> + ? ? ? p = of_get_property(of_dev, "voltages", &size);
> + ? ? ? if (p && size / sizeof(int) == 2) {
> + ? ? ? ? ? ? ? constraints->min_uV = be32_to_cpu(*p++);
> + ? ? ? ? ? ? ? constraints->max_uV = be32_to_cpu(*p);
> + ? ? ? }

You can probably simplify a lot of code by using
of_property_read_u32_array(), which is currently in devicetree/next

> + ? ? ? p = of_get_property(of_dev, "currents", &size);
> + ? ? ? if (p && size / sizeof(int) == 2) {
> + ? ? ? ? ? ? ? constraints->min_uA = be32_to_cpu(*p++);
> + ? ? ? ? ? ? ? constraints->max_uA = be32_to_cpu(*p);
> + ? ? ? }
> + ? ? ? p = of_get_property(of_dev, "modes-mask", NULL);
> + ? ? ? if (p)
> + ? ? ? ? ? ? ? constraints->valid_modes_mask = be32_to_cpu(*p);
> + ? ? ? cp = of_get_property(of_dev, "ops-mask", &size);
> + ? ? ? tmp = 0;
> + ? ? ? if (cp && size > 0) {
> + ? ? ? ? ? ? ? i = 0;
> + ? ? ? ? ? ? ? do {
> + ? ? ? ? ? ? ? ? ? ? ? len = strlen(ops[i]);
> + ? ? ? ? ? ? ? ? ? ? ? if (!strncmp(cp, ops[i], len)) {
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? constraints->valid_ops_mask |= 1 << i;
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* need to handle '\0' */
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? cp += len + 1;
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? size = size - len - 1;
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? i = 0;
> + ? ? ? ? ? ? ? ? ? ? ? } else
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? i++;
> + ? ? ? ? ? ? ? } while (i < ARRAY_SIZE(ops));
> + ? ? ? ? ? ? ? if (size > 0)
> + ? ? ? ? ? ? ? ? ? ? ? printk(KERN_WARNING "Invalid string:%s\n", cp);
> + ? ? ? }
> + ? ? ? p = of_get_property(of_dev, "input-uV", NULL);
> + ? ? ? if (p)
> + ? ? ? ? ? ? ? constraints->input_uV = be32_to_cpu(*p);
> + ? ? ? p = of_get_property(of_dev, "state-pm-disk", &size);
> + ? ? ? if (p && size / sizeof(int) == 3) {
> + ? ? ? ? ? ? ? constraints->state_disk.uV = be32_to_cpu(*p++);
> + ? ? ? ? ? ? ? constraints->state_disk.mode = be32_to_cpu(*p++);
> + ? ? ? ? ? ? ? tmp = be32_to_cpu(*p);
> + ? ? ? ? ? ? ? constraints->state_disk.enabled = (tmp) ? 1 : 0;
> + ? ? ? ? ? ? ? constraints->state_disk.disabled = (tmp) ? 0 : 1;
> + ? ? ? }
> + ? ? ? p = of_get_property(of_dev, "state-pm-mem", &size);
> + ? ? ? if (p && size / sizeof(int) == 3) {
> + ? ? ? ? ? ? ? constraints->state_mem.uV = be32_to_cpu(*p++);
> + ? ? ? ? ? ? ? constraints->state_mem.mode = be32_to_cpu(*p++);
> + ? ? ? ? ? ? ? tmp = be32_to_cpu(*p);
> + ? ? ? ? ? ? ? constraints->state_mem.enabled = (tmp) ? 1 : 0;
> + ? ? ? ? ? ? ? constraints->state_mem.disabled = (tmp) ? 0 : 1;
> + ? ? ? }
> + ? ? ? p = of_get_property(of_dev, "state-pm-standby", &size);
> + ? ? ? if (p && size / sizeof(int) == 3) {
> + ? ? ? ? ? ? ? constraints->state_standby.uV = be32_to_cpu(*p++);
> + ? ? ? ? ? ? ? constraints->state_standby.mode = be32_to_cpu(*p++);
> + ? ? ? ? ? ? ? tmp = be32_to_cpu(*p);
> + ? ? ? ? ? ? ? constraints->state_standby.enabled = (tmp) ? 1 : 0;
> + ? ? ? ? ? ? ? constraints->state_standby.disabled = (tmp) ? 0 : 1;
> + ? ? ? }
> + ? ? ? cp = of_get_property(of_dev, "initial-state", &size);
> + ? ? ? if (cp) {
> + ? ? ? ? ? ? ? if (!strncmp(cp, "pm-suspend-on", size))
> + ? ? ? ? ? ? ? ? ? ? ? constraints->initial_state = PM_SUSPEND_ON;
> + ? ? ? ? ? ? ? if (!strncmp(cp, "pm-suspend-mem", size))
> + ? ? ? ? ? ? ? ? ? ? ? constraints->initial_state = PM_SUSPEND_MEM;
> + ? ? ? ? ? ? ? if (!strncmp(cp, "pm-suspend-standby", size))
> + ? ? ? ? ? ? ? ? ? ? ? constraints->initial_state = PM_SUSPEND_STANDBY;
> + ? ? ? }
> + ? ? ? p = of_get_property(of_dev, "initial_mode", NULL);
> + ? ? ? if (p)
> + ? ? ? ? ? ? ? constraints->initial_mode = be32_to_cpu(*p);
> + ? ? ? p = of_get_property(of_dev, "always-on", NULL);
> + ? ? ? if (p)
> + ? ? ? ? ? ? ? constraints->always_on = 1;
> + ? ? ? p = of_get_property(of_dev, "boot-on", NULL);
> + ? ? ? if (p)
> + ? ? ? ? ? ? ? constraints->boot_on = 1;
> + ? ? ? p = of_get_property(of_dev, "apply-uV", NULL);
> + ? ? ? if (p)
> + ? ? ? ? ? ? ? constraints->apply_uV = 1;
> + ? ? ? return 0;
> +}

This code is implementing a new binding which needs to be documented
in Documentation/devicetree/bindings.  It is hard to review the patch
without some accompanying documentation about how you expect it to be
used.

> +
> +int of_regulator_init_data(struct device_node *of_dev,
> + ? ? ? ? ? ? ? ? ? ? ? struct regulator_init_data *data)
> +{
> + ? ? ? struct regulator_consumer_supply *supply;
> + ? ? ? const char *p, *str;
> + ? ? ? int ret, i, size, calc_size, len, count = 0;
> +
> + ? ? ? if (of_dev == NULL || data == NULL)
> + ? ? ? ? ? ? ? return -EINVAL;
> +
> + ? ? ? p = of_get_property(of_dev, "device_type", &size);
> + ? ? ? if (p == NULL || strncmp(p, "regulator", size))
> + ? ? ? ? ? ? ? return -EINVAL;
> +
> + ? ? ? ret = of_regulator_init_constraints(of_dev, &data->constraints);
> + ? ? ? if (ret)
> + ? ? ? ? ? ? ? return ret;
> + ? ? ? p = of_get_property(of_dev, "supply-name", &size);
> + ? ? ? str = p;
> + ? ? ? calc_size = size;
> + ? ? ? while (str && calc_size > 0) {
> + ? ? ? ? ? ? ? len = strlen(str);
> + ? ? ? ? ? ? ? if (len == 0)
> + ? ? ? ? ? ? ? ? ? ? ? break;
> + ? ? ? ? ? ? ? calc_size = calc_size - len - 1;
> + ? ? ? ? ? ? ? str += len + 1;
> + ? ? ? ? ? ? ? count++;
> + ? ? ? }
> + ? ? ? if (count == 0)
> + ? ? ? ? ? ? ? return -EINVAL;
> +
> + ? ? ? supply = kzalloc(sizeof(struct regulator_consumer_supply) * count,
> + ? ? ? ? ? ? ? GFP_KERNEL);
> + ? ? ? if (supply == NULL)
> + ? ? ? ? ? ? ? return -EINVAL;
> + ? ? ? str = p;
> + ? ? ? calc_size = size;
> + ? ? ? i = 0;
> + ? ? ? while (str && calc_size > 0 && i < count) {
> + ? ? ? ? ? ? ? len = strlen(str);
> + ? ? ? ? ? ? ? if (len == 0)
> + ? ? ? ? ? ? ? ? ? ? ? break;
> + ? ? ? ? ? ? ? supply[i++].supply = str;
> + ? ? ? ? ? ? ? calc_size = calc_size - len - 1;
> + ? ? ? ? ? ? ? str += len + 1;
> + ? ? ? }
> + ? ? ? data->consumer_supplies = supply;
> + ? ? ? data->num_consumer_supplies = count;
> + ? ? ? return 0;
> +}
> +
> +void of_regulator_deinit_data(struct regulator_init_data *data)
> +{
> + ? ? ? if (data && data->consumer_supplies)
> + ? ? ? ? ? ? ? kfree(data->consumer_supplies);
> +}
> diff --git a/include/linux/of_regulator.h b/include/linux/of_regulator.h
> new file mode 100644
> index 0000000..0155bd8
> --- /dev/null
> +++ b/include/linux/of_regulator.h
> @@ -0,0 +1,34 @@
> +/*
> + * Generic Regulator API implementation
> + *
> + * Copyright (c) 2011 Haojian Zhuang <haojian.zhuang@marvell.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#ifndef __LINUX_OF_REGULATOR_H
> +#define __LINUX_OF_REGULATOR_H
> +
> +#if defined(CONFIG_OF_REGULATOR) || defined(CONFIG_OF_REGULATOR_MODULE)
> +#include <linux/regulator/machine.h>
> +
> +extern int of_regulator_init_data(struct device_node *of_node,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct regulator_init_data *data);
> +extern void of_regulator_deinit_data(struct regulator_init_data *data);
> +
> +#else
> +static inline int of_regulator_init_data(struct device_node *of_node,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct regulator_init_data *data)
> +{
> + ? ? ? return 0;
> +}
> +
> +static inline void of_regulator_deinit_data(struct regulator_init_data *data)
> +{
> +}
> +#endif /* CONFIG_OF_REGULATOR */
> +
> +#endif /* __LINUX_OF_REGULATOR_H */
> --
> 1.5.6.5
>
>



-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

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

* Re: [PATCH] of: add devicetree API for regulator
  2011-07-08 10:20               ` Haojian Zhuang
@ 2011-07-08 18:32                 ` Liam Girdwood
  -1 siblings, 0 replies; 58+ messages in thread
From: Liam Girdwood @ 2011-07-08 18:32 UTC (permalink / raw)
  To: Haojian Zhuang
  Cc: eric.y.miao, nico, devicetree-discuss, broonie, haojian.zhuang,
	grant.likely, samuel.ortiz, linux, linux-arm-kernel, alan

On Fri, 2011-07-08 at 18:20 +0800, Haojian Zhuang wrote:
> Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
> ---
>  drivers/of/Kconfig           |    4 +
>  drivers/of/Makefile          |    1 +
>  drivers/of/of_regulator.c    |  166 ++++++++++++++++++++++++++++++++++++++++++
>  include/linux/of_regulator.h |   34 +++++++++
>  4 files changed, 205 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/of/of_regulator.c
>  create mode 100644 include/linux/of_regulator.h
> 
> diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
> index d06a637..edb6601 100644
> --- a/drivers/of/Kconfig
> +++ b/drivers/of/Kconfig
> @@ -75,4 +75,8 @@ config OF_PCI
>  	help
>  	  OpenFirmware PCI bus accessors
>  
> +config OF_REGULATOR
> +	def_tristate REGULATOR
> +	depends on REGULATOR
> +
>  endmenu # OF
> diff --git a/drivers/of/Makefile b/drivers/of/Makefile
> index f7861ed..83ca06f 100644
> --- a/drivers/of/Makefile
> +++ b/drivers/of/Makefile
> @@ -10,3 +10,4 @@ obj-$(CONFIG_OF_NET)	+= of_net.o
>  obj-$(CONFIG_OF_SPI)	+= of_spi.o
>  obj-$(CONFIG_OF_MDIO)	+= of_mdio.o
>  obj-$(CONFIG_OF_PCI)	+= of_pci.o
> +obj-$(CONFIG_OF_REGULATOR)	+= of_regulator.o
> diff --git a/drivers/of/of_regulator.c b/drivers/of/of_regulator.c
> new file mode 100644
> index 0000000..d523302
> --- /dev/null
> +++ b/drivers/of/of_regulator.c
> @@ -0,0 +1,166 @@
> +/*
> + * OF helpers for the Regulator API
> + *
> + * Copyright (c) 2011 Haojian Zhuang <haojian.zhuang@marvell.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +#include <linux/kernel.h>
> +#include <linux/of.h>
> +#include <linux/regulator/machine.h>
> +#include <linux/slab.h>
> +#include <linux/string.h>
> +#include <linux/suspend.h>
> +
> +static int of_regulator_init_constraints(struct device_node *of_dev,
> +				struct regulation_constraints *constraints)
> +{
> +	const __be32 *p;
> +	const char *cp;
> +	const char *ops[] = {"voltage", "current", "mode", "status",
> +				"drms"};
> +	int i, size, len = 0, tmp = 0;
> +
> +	memset(constraints, 0, sizeof(struct regulation_constraints));
> +
> +	p = of_get_property(of_dev, "voltages", &size);
> +	if (p && size / sizeof(int) == 2) {
> +		constraints->min_uV = be32_to_cpu(*p++);
> +		constraints->max_uV = be32_to_cpu(*p);
> +	}
> +	p = of_get_property(of_dev, "currents", &size);
> +	if (p && size / sizeof(int) == 2) {
> +		constraints->min_uA = be32_to_cpu(*p++);
> +		constraints->max_uA = be32_to_cpu(*p);
> +	}
> +	p = of_get_property(of_dev, "modes-mask", NULL);
> +	if (p)
> +		constraints->valid_modes_mask = be32_to_cpu(*p);
> +	cp = of_get_property(of_dev, "ops-mask", &size);
> +	tmp = 0;
> +	if (cp && size > 0) {
> +		i = 0;
> +		do {
> +			len = strlen(ops[i]);
> +			if (!strncmp(cp, ops[i], len)) {
> +				constraints->valid_ops_mask |= 1 << i;
> +				/* need to handle '\0' */
> +				cp += len + 1;
> +				size = size - len - 1;
> +				i = 0;
> +			} else
> +				i++;
> +		} while (i < ARRAY_SIZE(ops));
> +		if (size > 0)
> +			printk(KERN_WARNING "Invalid string:%s\n", cp);
> +	}

This code could also do with a little more comments describing some of
the more complex logic (like the above block).

Liam

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

* [PATCH] of: add devicetree API for regulator
@ 2011-07-08 18:32                 ` Liam Girdwood
  0 siblings, 0 replies; 58+ messages in thread
From: Liam Girdwood @ 2011-07-08 18:32 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, 2011-07-08 at 18:20 +0800, Haojian Zhuang wrote:
> Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
> ---
>  drivers/of/Kconfig           |    4 +
>  drivers/of/Makefile          |    1 +
>  drivers/of/of_regulator.c    |  166 ++++++++++++++++++++++++++++++++++++++++++
>  include/linux/of_regulator.h |   34 +++++++++
>  4 files changed, 205 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/of/of_regulator.c
>  create mode 100644 include/linux/of_regulator.h
> 
> diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
> index d06a637..edb6601 100644
> --- a/drivers/of/Kconfig
> +++ b/drivers/of/Kconfig
> @@ -75,4 +75,8 @@ config OF_PCI
>  	help
>  	  OpenFirmware PCI bus accessors
>  
> +config OF_REGULATOR
> +	def_tristate REGULATOR
> +	depends on REGULATOR
> +
>  endmenu # OF
> diff --git a/drivers/of/Makefile b/drivers/of/Makefile
> index f7861ed..83ca06f 100644
> --- a/drivers/of/Makefile
> +++ b/drivers/of/Makefile
> @@ -10,3 +10,4 @@ obj-$(CONFIG_OF_NET)	+= of_net.o
>  obj-$(CONFIG_OF_SPI)	+= of_spi.o
>  obj-$(CONFIG_OF_MDIO)	+= of_mdio.o
>  obj-$(CONFIG_OF_PCI)	+= of_pci.o
> +obj-$(CONFIG_OF_REGULATOR)	+= of_regulator.o
> diff --git a/drivers/of/of_regulator.c b/drivers/of/of_regulator.c
> new file mode 100644
> index 0000000..d523302
> --- /dev/null
> +++ b/drivers/of/of_regulator.c
> @@ -0,0 +1,166 @@
> +/*
> + * OF helpers for the Regulator API
> + *
> + * Copyright (c) 2011 Haojian Zhuang <haojian.zhuang@marvell.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +#include <linux/kernel.h>
> +#include <linux/of.h>
> +#include <linux/regulator/machine.h>
> +#include <linux/slab.h>
> +#include <linux/string.h>
> +#include <linux/suspend.h>
> +
> +static int of_regulator_init_constraints(struct device_node *of_dev,
> +				struct regulation_constraints *constraints)
> +{
> +	const __be32 *p;
> +	const char *cp;
> +	const char *ops[] = {"voltage", "current", "mode", "status",
> +				"drms"};
> +	int i, size, len = 0, tmp = 0;
> +
> +	memset(constraints, 0, sizeof(struct regulation_constraints));
> +
> +	p = of_get_property(of_dev, "voltages", &size);
> +	if (p && size / sizeof(int) == 2) {
> +		constraints->min_uV = be32_to_cpu(*p++);
> +		constraints->max_uV = be32_to_cpu(*p);
> +	}
> +	p = of_get_property(of_dev, "currents", &size);
> +	if (p && size / sizeof(int) == 2) {
> +		constraints->min_uA = be32_to_cpu(*p++);
> +		constraints->max_uA = be32_to_cpu(*p);
> +	}
> +	p = of_get_property(of_dev, "modes-mask", NULL);
> +	if (p)
> +		constraints->valid_modes_mask = be32_to_cpu(*p);
> +	cp = of_get_property(of_dev, "ops-mask", &size);
> +	tmp = 0;
> +	if (cp && size > 0) {
> +		i = 0;
> +		do {
> +			len = strlen(ops[i]);
> +			if (!strncmp(cp, ops[i], len)) {
> +				constraints->valid_ops_mask |= 1 << i;
> +				/* need to handle '\0' */
> +				cp += len + 1;
> +				size = size - len - 1;
> +				i = 0;
> +			} else
> +				i++;
> +		} while (i < ARRAY_SIZE(ops));
> +		if (size > 0)
> +			printk(KERN_WARNING "Invalid string:%s\n", cp);
> +	}

This code could also do with a little more comments describing some of
the more complex logic (like the above block).

Liam

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

* Re: [PATCH] of: add devicetree API for regulator
  2011-07-08 14:51                   ` Grant Likely
@ 2011-07-09  1:14                     ` Mark Brown
  -1 siblings, 0 replies; 58+ messages in thread
From: Mark Brown @ 2011-07-09  1:14 UTC (permalink / raw)
  To: Grant Likely
  Cc: eric.y.miao, nico, devicetree-discuss, Haojian Zhuang,
	haojian.zhuang, samuel.ortiz, linux, linux-arm-kernel, alan

On Fri, Jul 08, 2011 at 08:51:17AM -0600, Grant Likely wrote:
> Hi Haojian,
> 
> On Fri, Jul 8, 2011 at 4:20 AM, Haojian Zhuang
> <haojian.zhuang@marvell.com> wrote:
> > Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
> 
> No commit description?

Gah, don't bury major API changes like this in the middle of enourmous
and not perceptibly related machine specific patch serieses if you
expect people to actually see them.

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

* [PATCH] of: add devicetree API for regulator
@ 2011-07-09  1:14                     ` Mark Brown
  0 siblings, 0 replies; 58+ messages in thread
From: Mark Brown @ 2011-07-09  1:14 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 08, 2011 at 08:51:17AM -0600, Grant Likely wrote:
> Hi Haojian,
> 
> On Fri, Jul 8, 2011 at 4:20 AM, Haojian Zhuang
> <haojian.zhuang@marvell.com> wrote:
> > Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
> 
> No commit description?

Gah, don't bury major API changes like this in the middle of enourmous
and not perceptibly related machine specific patch serieses if you
expect people to actually see them.

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

* Re: [PATCH] of: add devicetree API for regulator
  2011-07-08 10:20               ` Haojian Zhuang
@ 2011-07-09  2:03                 ` Mark Brown
  -1 siblings, 0 replies; 58+ messages in thread
From: Mark Brown @ 2011-07-09  2:03 UTC (permalink / raw)
  To: Haojian Zhuang
  Cc: eric.y.miao, nico, devicetree-discuss, haojian.zhuang,
	grant.likely, samuel.ortiz, linux, linux-arm-kernel, alan

On Fri, Jul 08, 2011 at 06:20:24PM +0800, Haojian Zhuang wrote:
> Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>

Overall this looks like a reasonable start but I'm having a hard time
seeing how this would actually be used and there's a *lot* of Linux
specifics in here which aren't going to be acceptable for device tree as
device tree is supposed to be platform neutral.

As a general comment blank lines would *really* improve the legibility
of the code.

> ---
>  drivers/of/Kconfig           |    4 +
>  drivers/of/Makefile          |    1 +
>  drivers/of/of_regulator.c    |  166 ++++++++++++++++++++++++++++++++++++++++++

Why is this in drivers/of?

> +	p = of_get_property(of_dev, "voltages", &size);

voltage_range would probably be better.

> +	if (p && size / sizeof(int) == 2) {
> +		constraints->min_uV = be32_to_cpu(*p++);
> +		constraints->max_uV = be32_to_cpu(*p);
> +	}

This and pretty much all of the rest of the code doesn't look like it's
going to complain about parse problems.  That seems wrong, we'll just
silently ignore things we think we should understand.

> +	p = of_get_property(of_dev, "modes-mask", NULL);
> +	if (p)
> +		constraints->valid_modes_mask = be32_to_cpu(*p);

This probably shouldn't be in the OF bindings at all, the modes are a
Linux specific property.  We probably shouldn't be putting random
bitmasks directly in OF, and certainly not Linux defined ones.  This
applies to an awful lot of the rest of the code too.

> +	cp = of_get_property(of_dev, "ops-mask", &size);
> +	tmp = 0;
> +	if (cp && size > 0) {
> +		i = 0;
> +		do {
> +			len = strlen(ops[i]);
> +			if (!strncmp(cp, ops[i], len)) {
> +				constraints->valid_ops_mask |= 1 << i;
> +				/* need to handle '\0' */
> +				cp += len + 1;
> +				size = size - len - 1;
> +				i = 0;
> +			} else
> +				i++;
> +		} while (i < ARRAY_SIZE(ops));
> +		if (size > 0)
> +			printk(KERN_WARNING "Invalid string:%s\n", cp);
> +	}

If there isn't a helper function for this there should be one.

> +	supply = kzalloc(sizeof(struct regulator_consumer_supply) * count,
> +		GFP_KERNEL);
> +	if (supply == NULL)
> +		return -EINVAL;
> +	str = p;
> +	calc_size = size;
> +	i = 0;
> +	while (str && calc_size > 0 && i < count) {
> +		len = strlen(str);
> +		if (len == 0)
> +			break;
> +		supply[i++].supply = str;
> +		calc_size = calc_size - len - 1;
> +		str += len + 1;
> +	}
> +	data->consumer_supplies = supply;
> +	data->num_consumer_supplies = count;

This isn't going to fly, the consumer devices need to be referenced in
the OF tree rather than via their Linux device names.

> +extern int of_regulator_init_data(struct device_node *of_node,
> +				struct regulator_init_data *data);
> +extern void of_regulator_deinit_data(struct regulator_init_data *data);

How exactly is this supposed to be used?  I'd really expect the
regulator core to be doing this transparently for the drivers.

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

* [PATCH] of: add devicetree API for regulator
@ 2011-07-09  2:03                 ` Mark Brown
  0 siblings, 0 replies; 58+ messages in thread
From: Mark Brown @ 2011-07-09  2:03 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 08, 2011 at 06:20:24PM +0800, Haojian Zhuang wrote:
> Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>

Overall this looks like a reasonable start but I'm having a hard time
seeing how this would actually be used and there's a *lot* of Linux
specifics in here which aren't going to be acceptable for device tree as
device tree is supposed to be platform neutral.

As a general comment blank lines would *really* improve the legibility
of the code.

> ---
>  drivers/of/Kconfig           |    4 +
>  drivers/of/Makefile          |    1 +
>  drivers/of/of_regulator.c    |  166 ++++++++++++++++++++++++++++++++++++++++++

Why is this in drivers/of?

> +	p = of_get_property(of_dev, "voltages", &size);

voltage_range would probably be better.

> +	if (p && size / sizeof(int) == 2) {
> +		constraints->min_uV = be32_to_cpu(*p++);
> +		constraints->max_uV = be32_to_cpu(*p);
> +	}

This and pretty much all of the rest of the code doesn't look like it's
going to complain about parse problems.  That seems wrong, we'll just
silently ignore things we think we should understand.

> +	p = of_get_property(of_dev, "modes-mask", NULL);
> +	if (p)
> +		constraints->valid_modes_mask = be32_to_cpu(*p);

This probably shouldn't be in the OF bindings at all, the modes are a
Linux specific property.  We probably shouldn't be putting random
bitmasks directly in OF, and certainly not Linux defined ones.  This
applies to an awful lot of the rest of the code too.

> +	cp = of_get_property(of_dev, "ops-mask", &size);
> +	tmp = 0;
> +	if (cp && size > 0) {
> +		i = 0;
> +		do {
> +			len = strlen(ops[i]);
> +			if (!strncmp(cp, ops[i], len)) {
> +				constraints->valid_ops_mask |= 1 << i;
> +				/* need to handle '\0' */
> +				cp += len + 1;
> +				size = size - len - 1;
> +				i = 0;
> +			} else
> +				i++;
> +		} while (i < ARRAY_SIZE(ops));
> +		if (size > 0)
> +			printk(KERN_WARNING "Invalid string:%s\n", cp);
> +	}

If there isn't a helper function for this there should be one.

> +	supply = kzalloc(sizeof(struct regulator_consumer_supply) * count,
> +		GFP_KERNEL);
> +	if (supply == NULL)
> +		return -EINVAL;
> +	str = p;
> +	calc_size = size;
> +	i = 0;
> +	while (str && calc_size > 0 && i < count) {
> +		len = strlen(str);
> +		if (len == 0)
> +			break;
> +		supply[i++].supply = str;
> +		calc_size = calc_size - len - 1;
> +		str += len + 1;
> +	}
> +	data->consumer_supplies = supply;
> +	data->num_consumer_supplies = count;

This isn't going to fly, the consumer devices need to be referenced in
the OF tree rather than via their Linux device names.

> +extern int of_regulator_init_data(struct device_node *of_node,
> +				struct regulator_init_data *data);
> +extern void of_regulator_deinit_data(struct regulator_init_data *data);

How exactly is this supposed to be used?  I'd really expect the
regulator core to be doing this transparently for the drivers.

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

* Re: [PATCH] ARM: mmp: remove builtin gpio driver support
  2011-07-08 10:20   ` Haojian Zhuang
@ 2011-07-10  4:02     ` Grant Likely
  -1 siblings, 0 replies; 58+ messages in thread
From: Grant Likely @ 2011-07-10  4:02 UTC (permalink / raw)
  To: Haojian Zhuang
  Cc: eric.y.miao, nico, devicetree-discuss, broonie, haojian.zhuang,
	samuel.ortiz, linux, linux-arm-kernel, alan

On Fri, Jul 08, 2011 at 06:20:18PM +0800, Haojian Zhuang wrote:
> Remove builtin gpio driver support form mmp.
> 
> Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>

Hi Haojian.

I'm not clear what this patch is intending to do.  I understand that
it removes the mmp-specific gpio support, but I looks like don't see the code
that replaces it, which would mean that applying this patch breaks
gpio on mmp platforms.

Am I missing something?

> diff --git a/arch/arm/plat-pxa/Makefile b/arch/arm/plat-pxa/Makefile
> index 3aca5ba..8e432b1 100644
> --- a/arch/arm/plat-pxa/Makefile
> +++ b/arch/arm/plat-pxa/Makefile
> @@ -4,7 +4,9 @@
>  
>  obj-y	:= dma.o
>  
> +ifeq ($(CONFIG_OF),)
>  obj-$(CONFIG_GENERIC_GPIO)	+= gpio.o
> +endif

Be careful about this.  Turning on device tree support must not
disable booting on non-DT machines.

g.

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

* [PATCH] ARM: mmp: remove builtin gpio driver support
@ 2011-07-10  4:02     ` Grant Likely
  0 siblings, 0 replies; 58+ messages in thread
From: Grant Likely @ 2011-07-10  4:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 08, 2011 at 06:20:18PM +0800, Haojian Zhuang wrote:
> Remove builtin gpio driver support form mmp.
> 
> Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>

Hi Haojian.

I'm not clear what this patch is intending to do.  I understand that
it removes the mmp-specific gpio support, but I looks like don't see the code
that replaces it, which would mean that applying this patch breaks
gpio on mmp platforms.

Am I missing something?

> diff --git a/arch/arm/plat-pxa/Makefile b/arch/arm/plat-pxa/Makefile
> index 3aca5ba..8e432b1 100644
> --- a/arch/arm/plat-pxa/Makefile
> +++ b/arch/arm/plat-pxa/Makefile
> @@ -4,7 +4,9 @@
>  
>  obj-y	:= dma.o
>  
> +ifeq ($(CONFIG_OF),)
>  obj-$(CONFIG_GENERIC_GPIO)	+= gpio.o
> +endif

Be careful about this.  Turning on device tree support must not
disable booting on non-DT machines.

g.

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

* Re: [PATCH] ARM: mmp: parse irq from DT
  2011-07-08 10:20     ` Haojian Zhuang
@ 2011-07-10  4:34         ` Grant Likely
  -1 siblings, 0 replies; 58+ messages in thread
From: Grant Likely @ 2011-07-10  4:34 UTC (permalink / raw)
  To: Haojian Zhuang
  Cc: eric.y.miao-Re5JQEeQqe8AvxtiuMwx3w,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	samuel.ortiz-ral2JQCrhuEAvxtiuMwx3w,
	linux-lFZ/pmaqli7XmaaqVzeoHQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	alan-VuQAYsv1563Yd54FQh9/CA

On Fri, Jul 08, 2011 at 06:20:19PM +0800, Haojian Zhuang wrote:
> Parse irq sepcifier from DT and translate it to Linux irq number.
> 
> Signed-off-by: Haojian Zhuang <haojian.zhuang-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
> ---
>  arch/arm/mach-mmp/Makefile |    2 +
>  arch/arm/mach-mmp/common.h |    1 +
>  arch/arm/mach-mmp/intc.c   |  245 ++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 248 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/mach-mmp/intc.c
> 
> diff --git a/arch/arm/mach-mmp/Makefile b/arch/arm/mach-mmp/Makefile
> index 5c68382..e7862ea 100644
> --- a/arch/arm/mach-mmp/Makefile
> +++ b/arch/arm/mach-mmp/Makefile
> @@ -4,6 +4,8 @@
>  
>  obj-y				+= common.o clock.o devices.o time.o
>  
> +obj-$(CONFIG_OF_IRQ)		+= intc.o
> +
>  # SoC support
>  obj-$(CONFIG_CPU_PXA168)	+= pxa168.o irq-pxa168.o
>  obj-$(CONFIG_CPU_PXA910)	+= pxa910.o irq-pxa168.o
> diff --git a/arch/arm/mach-mmp/common.h b/arch/arm/mach-mmp/common.h
> index ec8d65d..1c563c2 100644
> --- a/arch/arm/mach-mmp/common.h
> +++ b/arch/arm/mach-mmp/common.h
> @@ -6,3 +6,4 @@ extern void timer_init(int irq);
>  
>  extern void __init icu_init_irq(void);
>  extern void __init mmp_map_io(void);
> +extern void __init mmp_init_intc(void);
> diff --git a/arch/arm/mach-mmp/intc.c b/arch/arm/mach-mmp/intc.c
> new file mode 100644
> index 0000000..48ad84b
> --- /dev/null
> +++ b/arch/arm/mach-mmp/intc.c
> @@ -0,0 +1,245 @@
> +/*
> + *  linux/arch/arm/mach-mmp/intc.c
> + *
> + *  Generic IRQ handling
> + *
> + *  Author:	Haojian Zhuang <haojian.zhuang-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
> + *  Copyright:	Marvell International Ltd. 2011
> + *
> + *  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 <linux/errno.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/slab.h>
> +
> +struct mmp_intc_info {
> +	unsigned int		mask;
> +	unsigned int		phy_base;
> +	void __iomem		*virt_base;
> +	void __iomem		*mux_status;
> +	void __iomem		*mux_mask;
> +	void __iomem		*mfp_edge;
> +	unsigned int		mfp_edge_index;	/* index in irq domain */
> +	unsigned int		irq_base;
> +};
> +
> +static void mux_irq_unmask(struct irq_data *d)
> +{
> +	struct mmp_intc_info *info = irq_data_get_irq_chip_data(d);
> +	unsigned int data, irq_offs;
> +
> +	irq_offs = d->irq - info->irq_base;
> +	if (info->mfp_edge && (info->mfp_edge_index == irq_offs)) {
> +		data = __raw_readl(info->mfp_edge);
> +		__raw_writel(data | (1 << 6), info->mfp_edge);
> +		__raw_writel(data, info->mfp_edge);
> +	}
> +	data = __raw_readl(info->mux_mask) & ~(1 << (d->irq - info->irq_base));
> +	__raw_writel(data, info->mux_mask);
> +}
> +
> +static void mux_irq_mask(struct irq_data *d)
> +{
> +	struct mmp_intc_info *info = irq_data_get_irq_chip_data(d);
> +	unsigned int data;
> +
> +	data = __raw_readl(info->mux_mask) | (1 << (d->irq - info->irq_base));
> +	__raw_writel(data, info->mux_mask);
> +}
> +
> +static struct irq_chip mux_irq_chip = {
> +	.name		= "mmp mux intc",
> +	.irq_unmask	= mux_irq_unmask,
> +	.irq_mask	= mux_irq_mask,
> +	.irq_ack	= mux_irq_mask,
> +};
> +
> +static void mmp_irq_demux_handler(unsigned int irq, struct irq_desc *desc)
> +{
> +	struct mmp_intc_info *info = irq_get_handler_data(irq);
> +	unsigned long status, mask, n;
> +
> +	mask = __raw_readl(info->mux_mask);
> +	while (1) {
> +		status = __raw_readl(info->mux_status) & ~mask;
> +		if (status == 0)
> +			break;
> +		n = find_first_bit(&status, BITS_PER_LONG);
> +		while (n < BITS_PER_LONG) {
> +			generic_handle_irq(info->irq_base + n);
> +			n = find_next_bit(&status, BITS_PER_LONG, n + 1);
> +		}
> +	}
> +}
> +
> +static void mux_init_intc(struct mmp_intc_info *mmp_info)
> +{
> +	struct device_node *np;
> +	struct mmp_intc_info *mux_info;
> +	const __be32 *nr, *status, *edge;
> +	unsigned int addr = 0, offs = 0;
> +	int cascade, irq_nr, i;
> +
> +	if (mmp_info->virt_base == NULL)
> +		goto out;
> +
> +	for (np = NULL; (np = of_find_all_nodes(np)) != NULL;) {
> +		if (!of_device_is_compatible(np, "mrvl,mux-intc"))
> +			continue;

for_each_compatible_node()

> +		if (of_get_property(np, "interrupt-controller", NULL) == NULL)
> +			continue;
> +		nr = of_get_property(np, "sub-interrupts", NULL);
> +		if (nr == NULL) {
> +			printk(KERN_WARNING "sub-interrupts property "
> +				"is missed\n");
> +			continue;
> +		}
> +		irq_nr = be32_to_cpu(*nr);

There's a new function you can use here that makes reading single property
values easier.  of_platform_read_u32() is queued up in linux-next.

> +		status = of_get_property(np, "status-mask", NULL);
> +		if (status == NULL) {
> +			printk(KERN_WARNING "status-mask property is missed\n");
> +			continue;
> +		}
> +		edge = of_get_property(np, "mfp-edge-interrupt", NULL);
> +
> +		mux_info = kzalloc(sizeof(struct mmp_intc_info), GFP_KERNEL);

kzalloc(sizeof(*mux_info), GFP_KERNEL);

> +		if (mux_info == NULL)
> +			goto out;
> +		mux_info->virt_base = mmp_info->virt_base;
> +		mux_info->mux_status = be32_to_cpu(*status++)
> +					+ mux_info->virt_base;
> +		mux_info->mux_mask = be32_to_cpu(*status)
> +					+ mux_info->virt_base;
> +		if (edge) {
> +			addr = be32_to_cpu(*edge) & PAGE_MASK;
> +			offs = be32_to_cpu(*edge) - addr;
> +			mux_info->mfp_edge = ioremap(addr, PAGE_SIZE) + offs;
> +			mux_info->mfp_edge_index = be32_to_cpu(*++edge);
> +		}
> +
> +		/* allocate new irq */
> +		cascade = irq_of_parse_and_map(np, 0);
> +		mux_info->irq_base = irq_alloc_descs(-1, 0, irq_nr, 0);
> +		irq_domain_add_simple(np, mux_info->irq_base);
> +
> +		i = mux_info->irq_base;
> +		for (; i < mux_info->irq_base + irq_nr; i++) {
> +			irq_set_chip_data(i, mux_info);
> +			mux_irq_mask(irq_get_irq_data(i));
> +			irq_set_chip_and_handler(i, &mux_irq_chip,
> +					handle_level_irq);
> +			set_irq_flags(i, IRQF_VALID);
> +		}
> +
> +		irq_set_handler_data(cascade, mux_info);
> +		irq_set_chained_handler(cascade, mmp_irq_demux_handler);
> +	}
> +out:
> +	return;
> +}

It looks like this function is parsing a new device tree binding.  Any
new bindings needs to be documented in Documentation/devicetree/bindings.

> +
> +static void mmp_irq_unmask(struct irq_data *d)
> +{
> +	struct mmp_intc_info *info = irq_data_get_irq_chip_data(d);
> +
> +	/* ICU_INT_CONF */
> +	__raw_writel(info->mask, info->virt_base + (d->irq << 2));
> +}
> +
> +static void mmp_irq_mask(struct irq_data *d)
> +{
> +	struct mmp_intc_info *info = irq_data_get_irq_chip_data(d);
> +
> +	__raw_writel(0, info->virt_base + (d->irq << 2));
> +}
> +
> +static struct irq_chip mmp_irq_chip = {
> +	.name		= "mmp-intc",
> +	.irq_unmask	= mmp_irq_unmask,
> +	.irq_mask	= mmp_irq_mask,
> +	.irq_ack	= mmp_irq_mask,
> +};

Can you use IRQ_GENERIC_CHIP?

> +
> +void __init mmp_init_intc(void)
> +{
> +	struct mmp_intc_info *info;
> +	struct device_node *np;
> +	const __be32 *enable_mask, *base, *cell, *nr;
> +	int i, irq_nr, phy_base;
> +
> +	np = of_find_compatible_node(NULL, NULL, "mrvl,mmp-intc");
> +
> +	BUG_ON(!np);
> +
> +	of_node_get(np);
> +	if (of_get_property(np, "interrupt-controller", NULL) == NULL)
> +		goto out;
> +	cell = of_get_property(np, "#interrupt-cells", NULL);
> +	if (cell == NULL) {
> +		printk(KERN_ERR "mmp-intc: Device node %s missing "
> +			"interrupt-cells property\n", np->full_name);
> +		goto out;
> +	}
> +	if (be32_to_cpu(*cell) != 1) {
> +		printk(KERN_ERR "mmp-intc: interrupt-cells property is "
> +			"incorrect:%d\n", be32_to_cpu(*cell));
> +		goto out;
> +	}
> +
> +	nr = of_get_property(np, "sub-interrupts", NULL);
> +	if (nr == NULL) {
> +		printk(KERN_ERR "mmp-intc: interrupts property is missed\n");
> +		goto out;
> +	}
> +	irq_nr = be32_to_cpu(*nr);
> +
> +	base = of_get_property(np, "reg", NULL);
> +	if (base == NULL) {
> +		printk(KERN_ERR "intc: Device node %s missing reg property\n",
> +			np->full_name);
> +		goto out;
> +	}
> +	phy_base = of_translate_address(np, base);

Use of_address_to_resource().

> +
> +	info = kzalloc(sizeof(struct mmp_intc_info), GFP_KERNEL);
> +	if (info == NULL)
> +		goto out;
> +
> +	enable_mask = of_get_property(np, "enable_mask", NULL);
> +	if (enable_mask == NULL) {
> +		printk(KERN_ERR "interrupt controller: Device node %s "
> +			"missing interrupt property\n", np->full_name);
> +		goto out_mem;
> +	}
> +	info->mask = be32_to_cpu(*enable_mask);
> +
> +	/* phy_base: 0, phy_size:64 */
> +	info->phy_base = phy_base;
> +	info->virt_base = ioremap(info->phy_base, PAGE_SIZE);
> +
> +	/* allocate new irq */
> +	info->irq_base = irq_alloc_descs(-1, 0, irq_nr, 0);
> +	irq_domain_add_simple(np, 0);

Excellent! Good use of dynamic irqs.

> +
> +	for (i = info->irq_base; i < info->irq_base + irq_nr; i++) {
> +		irq_set_chip_data(i, info);
> +		mmp_irq_mask(irq_get_irq_data(i));
> +		irq_set_chip_and_handler(i, &mmp_irq_chip, handle_level_irq);
> +		set_irq_flags(i, IRQF_VALID);
> +	}
> +	mux_init_intc(info);
> +	of_node_put(np);
> +	return;
> +out_mem:
> +	kfree(info);
> +out:
> +	of_node_put(np);
> +	return;
> +}

There's a lot of duplicate code here between the primary and cascaded
irq controllers.  It can probably be consolidated.

g.

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

* [PATCH] ARM: mmp: parse irq from DT
@ 2011-07-10  4:34         ` Grant Likely
  0 siblings, 0 replies; 58+ messages in thread
From: Grant Likely @ 2011-07-10  4:34 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 08, 2011 at 06:20:19PM +0800, Haojian Zhuang wrote:
> Parse irq sepcifier from DT and translate it to Linux irq number.
> 
> Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
> ---
>  arch/arm/mach-mmp/Makefile |    2 +
>  arch/arm/mach-mmp/common.h |    1 +
>  arch/arm/mach-mmp/intc.c   |  245 ++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 248 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/mach-mmp/intc.c
> 
> diff --git a/arch/arm/mach-mmp/Makefile b/arch/arm/mach-mmp/Makefile
> index 5c68382..e7862ea 100644
> --- a/arch/arm/mach-mmp/Makefile
> +++ b/arch/arm/mach-mmp/Makefile
> @@ -4,6 +4,8 @@
>  
>  obj-y				+= common.o clock.o devices.o time.o
>  
> +obj-$(CONFIG_OF_IRQ)		+= intc.o
> +
>  # SoC support
>  obj-$(CONFIG_CPU_PXA168)	+= pxa168.o irq-pxa168.o
>  obj-$(CONFIG_CPU_PXA910)	+= pxa910.o irq-pxa168.o
> diff --git a/arch/arm/mach-mmp/common.h b/arch/arm/mach-mmp/common.h
> index ec8d65d..1c563c2 100644
> --- a/arch/arm/mach-mmp/common.h
> +++ b/arch/arm/mach-mmp/common.h
> @@ -6,3 +6,4 @@ extern void timer_init(int irq);
>  
>  extern void __init icu_init_irq(void);
>  extern void __init mmp_map_io(void);
> +extern void __init mmp_init_intc(void);
> diff --git a/arch/arm/mach-mmp/intc.c b/arch/arm/mach-mmp/intc.c
> new file mode 100644
> index 0000000..48ad84b
> --- /dev/null
> +++ b/arch/arm/mach-mmp/intc.c
> @@ -0,0 +1,245 @@
> +/*
> + *  linux/arch/arm/mach-mmp/intc.c
> + *
> + *  Generic IRQ handling
> + *
> + *  Author:	Haojian Zhuang <haojian.zhuang@marvell.com>
> + *  Copyright:	Marvell International Ltd. 2011
> + *
> + *  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 <linux/errno.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/slab.h>
> +
> +struct mmp_intc_info {
> +	unsigned int		mask;
> +	unsigned int		phy_base;
> +	void __iomem		*virt_base;
> +	void __iomem		*mux_status;
> +	void __iomem		*mux_mask;
> +	void __iomem		*mfp_edge;
> +	unsigned int		mfp_edge_index;	/* index in irq domain */
> +	unsigned int		irq_base;
> +};
> +
> +static void mux_irq_unmask(struct irq_data *d)
> +{
> +	struct mmp_intc_info *info = irq_data_get_irq_chip_data(d);
> +	unsigned int data, irq_offs;
> +
> +	irq_offs = d->irq - info->irq_base;
> +	if (info->mfp_edge && (info->mfp_edge_index == irq_offs)) {
> +		data = __raw_readl(info->mfp_edge);
> +		__raw_writel(data | (1 << 6), info->mfp_edge);
> +		__raw_writel(data, info->mfp_edge);
> +	}
> +	data = __raw_readl(info->mux_mask) & ~(1 << (d->irq - info->irq_base));
> +	__raw_writel(data, info->mux_mask);
> +}
> +
> +static void mux_irq_mask(struct irq_data *d)
> +{
> +	struct mmp_intc_info *info = irq_data_get_irq_chip_data(d);
> +	unsigned int data;
> +
> +	data = __raw_readl(info->mux_mask) | (1 << (d->irq - info->irq_base));
> +	__raw_writel(data, info->mux_mask);
> +}
> +
> +static struct irq_chip mux_irq_chip = {
> +	.name		= "mmp mux intc",
> +	.irq_unmask	= mux_irq_unmask,
> +	.irq_mask	= mux_irq_mask,
> +	.irq_ack	= mux_irq_mask,
> +};
> +
> +static void mmp_irq_demux_handler(unsigned int irq, struct irq_desc *desc)
> +{
> +	struct mmp_intc_info *info = irq_get_handler_data(irq);
> +	unsigned long status, mask, n;
> +
> +	mask = __raw_readl(info->mux_mask);
> +	while (1) {
> +		status = __raw_readl(info->mux_status) & ~mask;
> +		if (status == 0)
> +			break;
> +		n = find_first_bit(&status, BITS_PER_LONG);
> +		while (n < BITS_PER_LONG) {
> +			generic_handle_irq(info->irq_base + n);
> +			n = find_next_bit(&status, BITS_PER_LONG, n + 1);
> +		}
> +	}
> +}
> +
> +static void mux_init_intc(struct mmp_intc_info *mmp_info)
> +{
> +	struct device_node *np;
> +	struct mmp_intc_info *mux_info;
> +	const __be32 *nr, *status, *edge;
> +	unsigned int addr = 0, offs = 0;
> +	int cascade, irq_nr, i;
> +
> +	if (mmp_info->virt_base == NULL)
> +		goto out;
> +
> +	for (np = NULL; (np = of_find_all_nodes(np)) != NULL;) {
> +		if (!of_device_is_compatible(np, "mrvl,mux-intc"))
> +			continue;

for_each_compatible_node()

> +		if (of_get_property(np, "interrupt-controller", NULL) == NULL)
> +			continue;
> +		nr = of_get_property(np, "sub-interrupts", NULL);
> +		if (nr == NULL) {
> +			printk(KERN_WARNING "sub-interrupts property "
> +				"is missed\n");
> +			continue;
> +		}
> +		irq_nr = be32_to_cpu(*nr);

There's a new function you can use here that makes reading single property
values easier.  of_platform_read_u32() is queued up in linux-next.

> +		status = of_get_property(np, "status-mask", NULL);
> +		if (status == NULL) {
> +			printk(KERN_WARNING "status-mask property is missed\n");
> +			continue;
> +		}
> +		edge = of_get_property(np, "mfp-edge-interrupt", NULL);
> +
> +		mux_info = kzalloc(sizeof(struct mmp_intc_info), GFP_KERNEL);

kzalloc(sizeof(*mux_info), GFP_KERNEL);

> +		if (mux_info == NULL)
> +			goto out;
> +		mux_info->virt_base = mmp_info->virt_base;
> +		mux_info->mux_status = be32_to_cpu(*status++)
> +					+ mux_info->virt_base;
> +		mux_info->mux_mask = be32_to_cpu(*status)
> +					+ mux_info->virt_base;
> +		if (edge) {
> +			addr = be32_to_cpu(*edge) & PAGE_MASK;
> +			offs = be32_to_cpu(*edge) - addr;
> +			mux_info->mfp_edge = ioremap(addr, PAGE_SIZE) + offs;
> +			mux_info->mfp_edge_index = be32_to_cpu(*++edge);
> +		}
> +
> +		/* allocate new irq */
> +		cascade = irq_of_parse_and_map(np, 0);
> +		mux_info->irq_base = irq_alloc_descs(-1, 0, irq_nr, 0);
> +		irq_domain_add_simple(np, mux_info->irq_base);
> +
> +		i = mux_info->irq_base;
> +		for (; i < mux_info->irq_base + irq_nr; i++) {
> +			irq_set_chip_data(i, mux_info);
> +			mux_irq_mask(irq_get_irq_data(i));
> +			irq_set_chip_and_handler(i, &mux_irq_chip,
> +					handle_level_irq);
> +			set_irq_flags(i, IRQF_VALID);
> +		}
> +
> +		irq_set_handler_data(cascade, mux_info);
> +		irq_set_chained_handler(cascade, mmp_irq_demux_handler);
> +	}
> +out:
> +	return;
> +}

It looks like this function is parsing a new device tree binding.  Any
new bindings needs to be documented in Documentation/devicetree/bindings.

> +
> +static void mmp_irq_unmask(struct irq_data *d)
> +{
> +	struct mmp_intc_info *info = irq_data_get_irq_chip_data(d);
> +
> +	/* ICU_INT_CONF */
> +	__raw_writel(info->mask, info->virt_base + (d->irq << 2));
> +}
> +
> +static void mmp_irq_mask(struct irq_data *d)
> +{
> +	struct mmp_intc_info *info = irq_data_get_irq_chip_data(d);
> +
> +	__raw_writel(0, info->virt_base + (d->irq << 2));
> +}
> +
> +static struct irq_chip mmp_irq_chip = {
> +	.name		= "mmp-intc",
> +	.irq_unmask	= mmp_irq_unmask,
> +	.irq_mask	= mmp_irq_mask,
> +	.irq_ack	= mmp_irq_mask,
> +};

Can you use IRQ_GENERIC_CHIP?

> +
> +void __init mmp_init_intc(void)
> +{
> +	struct mmp_intc_info *info;
> +	struct device_node *np;
> +	const __be32 *enable_mask, *base, *cell, *nr;
> +	int i, irq_nr, phy_base;
> +
> +	np = of_find_compatible_node(NULL, NULL, "mrvl,mmp-intc");
> +
> +	BUG_ON(!np);
> +
> +	of_node_get(np);
> +	if (of_get_property(np, "interrupt-controller", NULL) == NULL)
> +		goto out;
> +	cell = of_get_property(np, "#interrupt-cells", NULL);
> +	if (cell == NULL) {
> +		printk(KERN_ERR "mmp-intc: Device node %s missing "
> +			"interrupt-cells property\n", np->full_name);
> +		goto out;
> +	}
> +	if (be32_to_cpu(*cell) != 1) {
> +		printk(KERN_ERR "mmp-intc: interrupt-cells property is "
> +			"incorrect:%d\n", be32_to_cpu(*cell));
> +		goto out;
> +	}
> +
> +	nr = of_get_property(np, "sub-interrupts", NULL);
> +	if (nr == NULL) {
> +		printk(KERN_ERR "mmp-intc: interrupts property is missed\n");
> +		goto out;
> +	}
> +	irq_nr = be32_to_cpu(*nr);
> +
> +	base = of_get_property(np, "reg", NULL);
> +	if (base == NULL) {
> +		printk(KERN_ERR "intc: Device node %s missing reg property\n",
> +			np->full_name);
> +		goto out;
> +	}
> +	phy_base = of_translate_address(np, base);

Use of_address_to_resource().

> +
> +	info = kzalloc(sizeof(struct mmp_intc_info), GFP_KERNEL);
> +	if (info == NULL)
> +		goto out;
> +
> +	enable_mask = of_get_property(np, "enable_mask", NULL);
> +	if (enable_mask == NULL) {
> +		printk(KERN_ERR "interrupt controller: Device node %s "
> +			"missing interrupt property\n", np->full_name);
> +		goto out_mem;
> +	}
> +	info->mask = be32_to_cpu(*enable_mask);
> +
> +	/* phy_base: 0, phy_size:64 */
> +	info->phy_base = phy_base;
> +	info->virt_base = ioremap(info->phy_base, PAGE_SIZE);
> +
> +	/* allocate new irq */
> +	info->irq_base = irq_alloc_descs(-1, 0, irq_nr, 0);
> +	irq_domain_add_simple(np, 0);

Excellent! Good use of dynamic irqs.

> +
> +	for (i = info->irq_base; i < info->irq_base + irq_nr; i++) {
> +		irq_set_chip_data(i, info);
> +		mmp_irq_mask(irq_get_irq_data(i));
> +		irq_set_chip_and_handler(i, &mmp_irq_chip, handle_level_irq);
> +		set_irq_flags(i, IRQF_VALID);
> +	}
> +	mux_init_intc(info);
> +	of_node_put(np);
> +	return;
> +out_mem:
> +	kfree(info);
> +out:
> +	of_node_put(np);
> +	return;
> +}

There's a lot of duplicate code here between the primary and cascaded
irq controllers.  It can probably be consolidated.

g.

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

* Re: [PATCH] tty: serial: support device tree in pxa
  2011-07-08 10:20         ` Haojian Zhuang
@ 2011-07-10  5:11             ` Grant Likely
  -1 siblings, 0 replies; 58+ messages in thread
From: Grant Likely @ 2011-07-10  5:11 UTC (permalink / raw)
  To: Haojian Zhuang
  Cc: eric.y.miao-Re5JQEeQqe8AvxtiuMwx3w,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	samuel.ortiz-ral2JQCrhuEAvxtiuMwx3w,
	linux-lFZ/pmaqli7XmaaqVzeoHQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	alan-VuQAYsv1563Yd54FQh9/CA

On Fri, Jul 08, 2011 at 06:20:21PM +0800, Haojian Zhuang wrote:
> Support both normal platform driver and device tree driver in serial pxa.
> 
> Signed-off-by: Haojian Zhuang <haojian.zhuang-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
> ---
>  drivers/tty/serial/Kconfig     |    4 +-
>  drivers/tty/serial/of_serial.c |   12 +++++
>  drivers/tty/serial/pxa.c       |   91 ++++++++++++++++++++++++++++++++++------
>  include/linux/serial_pxa.h     |   17 +++++++
>  4 files changed, 110 insertions(+), 14 deletions(-)
>  create mode 100644 include/linux/serial_pxa.h
> 
> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
> index 636144c..3f75e0d 100644
> --- a/drivers/tty/serial/Kconfig
> +++ b/drivers/tty/serial/Kconfig
> @@ -663,6 +663,8 @@ config SERIAL_MPSC_CONSOLE
>  config SERIAL_PXA
>  	bool "PXA serial port support"
>  	depends on ARCH_PXA || ARCH_MMP
> +	select SERIAL_OF_PLATFORM
> +	select SERIAL_CORE_CONSOLE
>  	select SERIAL_CORE
>  	help
>  	  If you have a machine based on an Intel XScale PXA2xx CPU you
> @@ -1340,7 +1342,7 @@ config SERIAL_NETX_CONSOLE
>  config SERIAL_OF_PLATFORM
>  	tristate "Serial port on Open Firmware platform bus"
>  	depends on OF
> -	depends on SERIAL_8250 || SERIAL_OF_PLATFORM_NWPSERIAL
> +	depends on SERIAL_8250 || SERIAL_OF_PLATFORM_NWPSERIAL || SERIAL_PXA
>  	help
>  	  If you have a PowerPC based system that has serial ports
>  	  on a platform specific bus, you should enable this option.
> diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
> index e65f1e8..383bff3 100644
> --- a/drivers/tty/serial/of_serial.c
> +++ b/drivers/tty/serial/of_serial.c
> @@ -14,6 +14,7 @@
>  #include <linux/slab.h>
>  #include <linux/serial_core.h>
>  #include <linux/serial_8250.h>
> +#include <linux/serial_pxa.h>
>  #include <linux/of_address.h>
>  #include <linux/of_irq.h>
>  #include <linux/of_platform.h>
> @@ -126,6 +127,11 @@ static int __devinit of_platform_serial_probe(struct platform_device *ofdev)
>  		ret = nwpserial_register_port(&port);
>  		break;
>  #endif
> +#ifdef CONFIG_SERIAL_PXA
> +	case PORT_PXA:
> +		ret = serial_pxa_register_port(&port);
> +		break;
> +#endif
>  	default:
>  		/* need to add code for these */
>  	case PORT_UNKNOWN:
> @@ -163,6 +169,11 @@ static int of_platform_serial_remove(struct platform_device *ofdev)
>  		nwpserial_unregister_port(info->line);
>  		break;
>  #endif
> +#ifdef CONFIG_SERIAL_PXA
> +	case PORT_PXA:
> +		serial_pxa_unregister_port(info->line);
> +		break;
> +#endif
>  	default:
>  		/* need to add code for these */
>  		break;
> @@ -186,6 +197,7 @@ static struct of_device_id __devinitdata of_platform_serial_table[] = {
>  	{ .compatible = "ibm,qpace-nwp-serial",
>  		.data = (void *)PORT_NWPSERIAL, },
>  #endif
> +	{ .compatible = "pxa,serial", .data = (void *)PORT_PXA, },

compatible values should be in the form: "<vendor>,<soc>-<part>", so
in this case it would be "marvel,pxa270-serial" or something similar.

>  	{ .type = "serial",         .data = (void *)PORT_UNKNOWN, },
>  	{ /* end of list */ },
>  };
> diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
> index 4302e6e..fb80fb3 100644
> --- a/drivers/tty/serial/pxa.c
> +++ b/drivers/tty/serial/pxa.c
> @@ -36,10 +36,12 @@
>  #include <linux/circ_buf.h>
>  #include <linux/delay.h>
>  #include <linux/interrupt.h>
> +#include <linux/of.h>
>  #include <linux/platform_device.h>
>  #include <linux/tty.h>
>  #include <linux/tty_flip.h>
>  #include <linux/serial_core.h>
> +#include <linux/serial_pxa.h>
>  #include <linux/clk.h>
>  #include <linux/io.h>
>  #include <linux/slab.h>
> @@ -51,9 +53,14 @@ struct uart_pxa_port {
>  	unsigned char           mcr;
>  	unsigned int            lsr_break_flag;
>  	struct clk		*clk;
> -	char			*name;
> +	char			name[32];

What's the reason for the change to a static array instead of a
pointer?

> +	int			id;
>  };
>  
> +#define PXA_SERIAL_NR		4
> +
> +static DEFINE_MUTEX(serial_pxa_mutex);
> +
>  static inline unsigned int serial_in(struct uart_pxa_port *up, int offset)
>  {
>  	offset <<= 2;
> @@ -346,8 +353,6 @@ static int serial_pxa_startup(struct uart_port *port)
>  	else
>  		up->mcr = 0;
>  
> -	up->port.uartclk = clk_get_rate(up->clk);
> -
>  	/*
>  	 * Allocate the IRQ
>  	 */
> @@ -593,7 +598,7 @@ serial_pxa_type(struct uart_port *port)
>  	return up->name;
>  }
>  
> -static struct uart_pxa_port *serial_pxa_ports[4];
> +static struct uart_pxa_port serial_pxa_ports[PXA_SERIAL_NR];

Why is this being changed into a static array instead of sticking with
the dynamic allocation of uart_pxa_port?

>  static struct uart_driver serial_pxa_reg;
>  
>  #ifdef CONFIG_SERIAL_PXA_CONSOLE
> @@ -645,7 +650,7 @@ static void serial_pxa_console_putchar(struct uart_port *port, int ch)
>  static void
>  serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
>  {
> -	struct uart_pxa_port *up = serial_pxa_ports[co->index];
> +	struct uart_pxa_port *up = &serial_pxa_ports[co->index];
>  	unsigned int ier;
>  
>  	clk_enable(up->clk);
> @@ -679,7 +684,7 @@ serial_pxa_console_setup(struct console *co, char *options)
>  
>  	if (co->index == -1 || co->index >= serial_pxa_reg.nr)
>  		co->index = 0;
> -	up = serial_pxa_ports[co->index];
> +	up = &serial_pxa_ports[co->index];
>  	if (!up)
>  		return -ENODEV;
>  
> @@ -761,6 +766,68 @@ static const struct dev_pm_ops serial_pxa_pm_ops = {
>  };
>  #endif
>  
> +static int serial_pxa_port_size(struct uart_pxa_port *sport)
> +{
> +	return 8 << sport->port.regshift;
> +}
> +
> +int serial_pxa_register_port(struct uart_port *port)
> +{
> +	struct uart_pxa_port *sport = NULL;
> +	char name[32];
> +	int i, ret;
> +
> +	mutex_lock(&serial_pxa_mutex);
> +	for (i = 0; i < PXA_SERIAL_NR; i++) {
> +		if (serial_pxa_ports[i].id == 0) {
> +			sport = &serial_pxa_ports[i];
> +			sprintf(sport->name, "UART%d", i);
> +			sport->id = i + 1;
> +			break;
> +		}
> +	}
> +	sprintf(name, "pxa2xx-uart.%d", i);
> +	sport->clk = clk_get_sys(name, NULL);
> +	if (IS_ERR(sport->clk)) {
> +		ret = PTR_ERR(sport->clk);
> +		goto out;
> +	}
> +	memcpy(&sport->port, port, sizeof(struct uart_port));
> +	sport->port.line = i;
> +	sport->port.fifosize = 64;
> +	sport->port.ops = &serial_pxa_pops;
> +
> +	sport->port.membase = ioremap(sport->port.mapbase,
> +				serial_pxa_port_size(sport));
> +	if (!sport->port.membase) {
> +		ret = -ENOMEM;
> +		goto out_membase;
> +	}
> +
> +	uart_add_one_port(&serial_pxa_reg, &sport->port);
> +	mutex_unlock(&serial_pxa_mutex);
> +
> +	return sport->port.line;
> +
> +out_membase:
> +	clk_put(sport->clk);
> +out:
> +	mutex_unlock(&serial_pxa_mutex);
> +	return ret;
> +}
> +EXPORT_SYMBOL(serial_pxa_register_port);
> +
> +void serial_pxa_unregister_port(int line)
> +{
> +	struct uart_pxa_port *sport = &serial_pxa_ports[line];
> +
> +	mutex_lock(&serial_pxa_mutex);
> +	uart_remove_one_port(&serial_pxa_reg, &sport->port);
> +	sport->port.type = PORT_UNKNOWN;
> +	clk_put(sport->clk);
> +	mutex_unlock(&serial_pxa_mutex);
> +}
> +
>  static int serial_pxa_probe(struct platform_device *dev)
>  {
>  	struct uart_pxa_port *sport;
> @@ -794,12 +861,12 @@ static int serial_pxa_probe(struct platform_device *dev)
>  	sport->port.uartclk = clk_get_rate(sport->clk);
>  
>  	switch (dev->id) {
> -	case 0: sport->name = "FFUART"; break;
> -	case 1: sport->name = "BTUART"; break;
> -	case 2: sport->name = "STUART"; break;
> -	case 3: sport->name = "HWUART"; break;
> +	case 0: strcpy(sport->name, "FFUART"); break;
> +	case 1: strcpy(sport->name, "BTUART"); break;
> +	case 2: strcpy(sport->name, "STUART"); break;
> +	case 3: strcpy(sport->name, "HWUART"); break;
>  	default:
> -		sport->name = "???";
> +		strcpy(sport->name, "???");
>  		break;
>  	}
>  
> @@ -809,8 +876,6 @@ static int serial_pxa_probe(struct platform_device *dev)
>  		goto err_clk;
>  	}
>  
> -	serial_pxa_ports[dev->id] = sport;
> -
>  	uart_add_one_port(&serial_pxa_reg, &sport->port);
>  	platform_set_drvdata(dev, sport);
>  
> diff --git a/include/linux/serial_pxa.h b/include/linux/serial_pxa.h
> new file mode 100644
> index 0000000..565e510
> --- /dev/null
> +++ b/include/linux/serial_pxa.h
> @@ -0,0 +1,17 @@
> +/*
> + *  linux/include/linux/serial_8250.h
> + *
> + *  Marvell Semiconductor Inc.
> + *  Copyright (C) 2011
> + *
> + * 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.
> + */
> +#ifndef _LINUX_SERIAL_PXA_H
> +#define _LINUX_SERIAL_PXA_H
> +
> +extern int serial_pxa_register_port(struct uart_port *);
> +extern void serial_pxa_unregister_port(int);
> +#endif
> -- 
> 1.5.6.5
> 

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

* [PATCH] tty: serial: support device tree in pxa
@ 2011-07-10  5:11             ` Grant Likely
  0 siblings, 0 replies; 58+ messages in thread
From: Grant Likely @ 2011-07-10  5:11 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 08, 2011 at 06:20:21PM +0800, Haojian Zhuang wrote:
> Support both normal platform driver and device tree driver in serial pxa.
> 
> Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
> ---
>  drivers/tty/serial/Kconfig     |    4 +-
>  drivers/tty/serial/of_serial.c |   12 +++++
>  drivers/tty/serial/pxa.c       |   91 ++++++++++++++++++++++++++++++++++------
>  include/linux/serial_pxa.h     |   17 +++++++
>  4 files changed, 110 insertions(+), 14 deletions(-)
>  create mode 100644 include/linux/serial_pxa.h
> 
> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
> index 636144c..3f75e0d 100644
> --- a/drivers/tty/serial/Kconfig
> +++ b/drivers/tty/serial/Kconfig
> @@ -663,6 +663,8 @@ config SERIAL_MPSC_CONSOLE
>  config SERIAL_PXA
>  	bool "PXA serial port support"
>  	depends on ARCH_PXA || ARCH_MMP
> +	select SERIAL_OF_PLATFORM
> +	select SERIAL_CORE_CONSOLE
>  	select SERIAL_CORE
>  	help
>  	  If you have a machine based on an Intel XScale PXA2xx CPU you
> @@ -1340,7 +1342,7 @@ config SERIAL_NETX_CONSOLE
>  config SERIAL_OF_PLATFORM
>  	tristate "Serial port on Open Firmware platform bus"
>  	depends on OF
> -	depends on SERIAL_8250 || SERIAL_OF_PLATFORM_NWPSERIAL
> +	depends on SERIAL_8250 || SERIAL_OF_PLATFORM_NWPSERIAL || SERIAL_PXA
>  	help
>  	  If you have a PowerPC based system that has serial ports
>  	  on a platform specific bus, you should enable this option.
> diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
> index e65f1e8..383bff3 100644
> --- a/drivers/tty/serial/of_serial.c
> +++ b/drivers/tty/serial/of_serial.c
> @@ -14,6 +14,7 @@
>  #include <linux/slab.h>
>  #include <linux/serial_core.h>
>  #include <linux/serial_8250.h>
> +#include <linux/serial_pxa.h>
>  #include <linux/of_address.h>
>  #include <linux/of_irq.h>
>  #include <linux/of_platform.h>
> @@ -126,6 +127,11 @@ static int __devinit of_platform_serial_probe(struct platform_device *ofdev)
>  		ret = nwpserial_register_port(&port);
>  		break;
>  #endif
> +#ifdef CONFIG_SERIAL_PXA
> +	case PORT_PXA:
> +		ret = serial_pxa_register_port(&port);
> +		break;
> +#endif
>  	default:
>  		/* need to add code for these */
>  	case PORT_UNKNOWN:
> @@ -163,6 +169,11 @@ static int of_platform_serial_remove(struct platform_device *ofdev)
>  		nwpserial_unregister_port(info->line);
>  		break;
>  #endif
> +#ifdef CONFIG_SERIAL_PXA
> +	case PORT_PXA:
> +		serial_pxa_unregister_port(info->line);
> +		break;
> +#endif
>  	default:
>  		/* need to add code for these */
>  		break;
> @@ -186,6 +197,7 @@ static struct of_device_id __devinitdata of_platform_serial_table[] = {
>  	{ .compatible = "ibm,qpace-nwp-serial",
>  		.data = (void *)PORT_NWPSERIAL, },
>  #endif
> +	{ .compatible = "pxa,serial", .data = (void *)PORT_PXA, },

compatible values should be in the form: "<vendor>,<soc>-<part>", so
in this case it would be "marvel,pxa270-serial" or something similar.

>  	{ .type = "serial",         .data = (void *)PORT_UNKNOWN, },
>  	{ /* end of list */ },
>  };
> diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
> index 4302e6e..fb80fb3 100644
> --- a/drivers/tty/serial/pxa.c
> +++ b/drivers/tty/serial/pxa.c
> @@ -36,10 +36,12 @@
>  #include <linux/circ_buf.h>
>  #include <linux/delay.h>
>  #include <linux/interrupt.h>
> +#include <linux/of.h>
>  #include <linux/platform_device.h>
>  #include <linux/tty.h>
>  #include <linux/tty_flip.h>
>  #include <linux/serial_core.h>
> +#include <linux/serial_pxa.h>
>  #include <linux/clk.h>
>  #include <linux/io.h>
>  #include <linux/slab.h>
> @@ -51,9 +53,14 @@ struct uart_pxa_port {
>  	unsigned char           mcr;
>  	unsigned int            lsr_break_flag;
>  	struct clk		*clk;
> -	char			*name;
> +	char			name[32];

What's the reason for the change to a static array instead of a
pointer?

> +	int			id;
>  };
>  
> +#define PXA_SERIAL_NR		4
> +
> +static DEFINE_MUTEX(serial_pxa_mutex);
> +
>  static inline unsigned int serial_in(struct uart_pxa_port *up, int offset)
>  {
>  	offset <<= 2;
> @@ -346,8 +353,6 @@ static int serial_pxa_startup(struct uart_port *port)
>  	else
>  		up->mcr = 0;
>  
> -	up->port.uartclk = clk_get_rate(up->clk);
> -
>  	/*
>  	 * Allocate the IRQ
>  	 */
> @@ -593,7 +598,7 @@ serial_pxa_type(struct uart_port *port)
>  	return up->name;
>  }
>  
> -static struct uart_pxa_port *serial_pxa_ports[4];
> +static struct uart_pxa_port serial_pxa_ports[PXA_SERIAL_NR];

Why is this being changed into a static array instead of sticking with
the dynamic allocation of uart_pxa_port?

>  static struct uart_driver serial_pxa_reg;
>  
>  #ifdef CONFIG_SERIAL_PXA_CONSOLE
> @@ -645,7 +650,7 @@ static void serial_pxa_console_putchar(struct uart_port *port, int ch)
>  static void
>  serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
>  {
> -	struct uart_pxa_port *up = serial_pxa_ports[co->index];
> +	struct uart_pxa_port *up = &serial_pxa_ports[co->index];
>  	unsigned int ier;
>  
>  	clk_enable(up->clk);
> @@ -679,7 +684,7 @@ serial_pxa_console_setup(struct console *co, char *options)
>  
>  	if (co->index == -1 || co->index >= serial_pxa_reg.nr)
>  		co->index = 0;
> -	up = serial_pxa_ports[co->index];
> +	up = &serial_pxa_ports[co->index];
>  	if (!up)
>  		return -ENODEV;
>  
> @@ -761,6 +766,68 @@ static const struct dev_pm_ops serial_pxa_pm_ops = {
>  };
>  #endif
>  
> +static int serial_pxa_port_size(struct uart_pxa_port *sport)
> +{
> +	return 8 << sport->port.regshift;
> +}
> +
> +int serial_pxa_register_port(struct uart_port *port)
> +{
> +	struct uart_pxa_port *sport = NULL;
> +	char name[32];
> +	int i, ret;
> +
> +	mutex_lock(&serial_pxa_mutex);
> +	for (i = 0; i < PXA_SERIAL_NR; i++) {
> +		if (serial_pxa_ports[i].id == 0) {
> +			sport = &serial_pxa_ports[i];
> +			sprintf(sport->name, "UART%d", i);
> +			sport->id = i + 1;
> +			break;
> +		}
> +	}
> +	sprintf(name, "pxa2xx-uart.%d", i);
> +	sport->clk = clk_get_sys(name, NULL);
> +	if (IS_ERR(sport->clk)) {
> +		ret = PTR_ERR(sport->clk);
> +		goto out;
> +	}
> +	memcpy(&sport->port, port, sizeof(struct uart_port));
> +	sport->port.line = i;
> +	sport->port.fifosize = 64;
> +	sport->port.ops = &serial_pxa_pops;
> +
> +	sport->port.membase = ioremap(sport->port.mapbase,
> +				serial_pxa_port_size(sport));
> +	if (!sport->port.membase) {
> +		ret = -ENOMEM;
> +		goto out_membase;
> +	}
> +
> +	uart_add_one_port(&serial_pxa_reg, &sport->port);
> +	mutex_unlock(&serial_pxa_mutex);
> +
> +	return sport->port.line;
> +
> +out_membase:
> +	clk_put(sport->clk);
> +out:
> +	mutex_unlock(&serial_pxa_mutex);
> +	return ret;
> +}
> +EXPORT_SYMBOL(serial_pxa_register_port);
> +
> +void serial_pxa_unregister_port(int line)
> +{
> +	struct uart_pxa_port *sport = &serial_pxa_ports[line];
> +
> +	mutex_lock(&serial_pxa_mutex);
> +	uart_remove_one_port(&serial_pxa_reg, &sport->port);
> +	sport->port.type = PORT_UNKNOWN;
> +	clk_put(sport->clk);
> +	mutex_unlock(&serial_pxa_mutex);
> +}
> +
>  static int serial_pxa_probe(struct platform_device *dev)
>  {
>  	struct uart_pxa_port *sport;
> @@ -794,12 +861,12 @@ static int serial_pxa_probe(struct platform_device *dev)
>  	sport->port.uartclk = clk_get_rate(sport->clk);
>  
>  	switch (dev->id) {
> -	case 0: sport->name = "FFUART"; break;
> -	case 1: sport->name = "BTUART"; break;
> -	case 2: sport->name = "STUART"; break;
> -	case 3: sport->name = "HWUART"; break;
> +	case 0: strcpy(sport->name, "FFUART"); break;
> +	case 1: strcpy(sport->name, "BTUART"); break;
> +	case 2: strcpy(sport->name, "STUART"); break;
> +	case 3: strcpy(sport->name, "HWUART"); break;
>  	default:
> -		sport->name = "???";
> +		strcpy(sport->name, "???");
>  		break;
>  	}
>  
> @@ -809,8 +876,6 @@ static int serial_pxa_probe(struct platform_device *dev)
>  		goto err_clk;
>  	}
>  
> -	serial_pxa_ports[dev->id] = sport;
> -
>  	uart_add_one_port(&serial_pxa_reg, &sport->port);
>  	platform_set_drvdata(dev, sport);
>  
> diff --git a/include/linux/serial_pxa.h b/include/linux/serial_pxa.h
> new file mode 100644
> index 0000000..565e510
> --- /dev/null
> +++ b/include/linux/serial_pxa.h
> @@ -0,0 +1,17 @@
> +/*
> + *  linux/include/linux/serial_8250.h
> + *
> + *  Marvell Semiconductor Inc.
> + *  Copyright (C) 2011
> + *
> + * 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.
> + */
> +#ifndef _LINUX_SERIAL_PXA_H
> +#define _LINUX_SERIAL_PXA_H
> +
> +extern int serial_pxa_register_port(struct uart_port *);
> +extern void serial_pxa_unregister_port(int);
> +#endif
> -- 
> 1.5.6.5
> 

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

* Re: [PATCH] i2c: pxa: create dynamic platform device from device tree
  2011-07-08 10:20             ` Haojian Zhuang
@ 2011-07-10  5:26                 ` Grant Likely
  -1 siblings, 0 replies; 58+ messages in thread
From: Grant Likely @ 2011-07-10  5:26 UTC (permalink / raw)
  To: Haojian Zhuang
  Cc: eric.y.miao-Re5JQEeQqe8AvxtiuMwx3w,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	samuel.ortiz-ral2JQCrhuEAvxtiuMwx3w,
	linux-lFZ/pmaqli7XmaaqVzeoHQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	alan-VuQAYsv1563Yd54FQh9/CA

On Fri, Jul 08, 2011 at 06:20:23PM +0800, Haojian Zhuang wrote:
> Create two probe function to support both current platform device and created
> dynamic platform device from device tree. After moving to device tree,
> original implementation of platform device will be removed.
> 
> Use property to present polling mode and frequency mode.
> 
> Signed-off-by: Haojian Zhuang <haojian.zhuang-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
> ---
>  drivers/i2c/busses/i2c-pxa.c |  163 ++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 163 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
> index d603646..7a6d774 100644
> --- a/drivers/i2c/busses/i2c-pxa.c
> +++ b/drivers/i2c/busses/i2c-pxa.c
> @@ -29,6 +29,7 @@
>  #include <linux/errno.h>
>  #include <linux/interrupt.h>
>  #include <linux/i2c-pxa.h>
> +#include <linux/of_device.h>
>  #include <linux/of_i2c.h>
>  #include <linux/platform_device.h>
>  #include <linux/err.h>
> @@ -1044,6 +1045,162 @@ static const struct i2c_algorithm i2c_pxa_pio_algorithm = {
>  	.functionality	= i2c_pxa_functionality,
>  };
>  
> +static const struct of_device_id pxa_i2c_of_match[] = {
> +	{ .compatible = "pxa2xx-i2c",	.data = (void *)REGS_PXA2XX, },
> +	{ .compatible = "pxa3xx-pwri2c", .data = (void *)REGS_PXA3XX, },
> +	{ .compatible = "ce4100-i2c",	.data = (void *)REGS_CE4100, },

New compatible values need to be written up in
Documentation/devicetree/bindings, and strings should be in the form
"<vendor>,<soc>-i2c".  They should also be specific to the soc instead
of trying to be generic (ie. use "marvell,pxa255-i2c" instead of
"marvell,pxa2xx-i2c".

> +	{},
> +};
> +
> +#ifdef CONFIG_OF
> +static int i2c_pxa_of_probe(struct platform_device *of_dev)
> +{

CONFIG_OF should not be an either/or option.  Turning on CONFIG_OF
must not disable non-DT users.

> +	struct device_node *np = of_dev->dev.of_node;
> +	const struct of_device_id *match;
> +	struct i2c_pxa_platform_data *plat = NULL;
> +	struct pxa_i2c *i2c;
> +	struct resource *res;
> +	const __be32 *p;
> +	int i2c_type, irq, data, ret;
> +	int id = 0, poll = 0, fast = 0;
> +
> +	match = of_match_device(pxa_i2c_of_match, &of_dev->dev);
> +	if (match == NULL)
> +		return -ENODEV;
> +	i2c_type = (int)match->data;
> +
> +	p = of_get_property(np, "cell-index", &data);
> +	if (p)
> +		id = be32_to_cpu(*p);

When using the device tree, the bus id should be dynamically
assigned.  Don't use a cell-index property.

> +
> +	p = of_get_property(np, "i2c-polling", &data);
> +	if (p)
> +		poll = be32_to_cpu(*p);
> +
> +	p = of_get_property(np, "i2c-frequency", &data);
> +	if (p && !strncmp((char *)p, "fast", data))
> +		fast = 1;
> +
> +	res = platform_get_resource(of_dev, IORESOURCE_MEM, 0);
> +	irq = platform_get_irq(of_dev, 0);
> +	if (res == NULL || irq < 0)
> +		return -ENODEV;
> +
> +	if (!request_mem_region(res->start, resource_size(res), res->name))
> +		return -ENOMEM;
> +
> +	i2c = kzalloc(sizeof(struct pxa_i2c), GFP_KERNEL);

kzalloc(sizeof(*i2c), GFP_KERNEL)

> +	if (!i2c) {
> +		ret = -ENOMEM;
> +		goto emalloc;
> +	}
> +
> +	i2c->adap.owner   = THIS_MODULE;
> +	i2c->adap.retries = 5;
> +
> +	spin_lock_init(&i2c->lock);
> +	init_waitqueue_head(&i2c->wait);
> +
> +	/*
> +	 * adap.nr comes from cell-index in dts file
> +	 */
> +	i2c->adap.nr = id;
> +	snprintf(i2c->adap.name, sizeof(i2c->adap.name), "pxa2xx-i2c.%u",
> +		 i2c->adap.nr);
> +
> +	i2c->clk = clk_get_sys(i2c->adap.name, NULL);
> +	if (IS_ERR(i2c->clk)) {
> +		ret = PTR_ERR(i2c->clk);
> +		goto eclk;
> +	}
> +
> +	i2c->reg_base = ioremap(res->start, resource_size(res));
> +	if (!i2c->reg_base) {
> +		ret = -EIO;
> +		goto eremap;
> +	}
> +
> +	i2c->reg_ibmr = i2c->reg_base + pxa_reg_layout[i2c_type].ibmr;
> +	i2c->reg_idbr = i2c->reg_base + pxa_reg_layout[i2c_type].idbr;
> +	i2c->reg_icr = i2c->reg_base + pxa_reg_layout[i2c_type].icr;
> +	i2c->reg_isr = i2c->reg_base + pxa_reg_layout[i2c_type].isr;
> +	if (i2c_type != REGS_CE4100)
> +		i2c->reg_isar = i2c->reg_base + pxa_reg_layout[i2c_type].isar;
> +
> +	i2c->iobase = res->start;
> +	i2c->iosize = resource_size(res);
> +
> +	i2c->irq = irq;
> +	i2c->use_pio = poll;
> +	i2c->fast_mode = fast;
> +
> +	i2c->slave_addr = I2C_PXA_SLAVE_ADDR;
> +
> +#ifdef CONFIG_I2C_PXA_SLAVE
> +	if (plat) {
> +		i2c->slave_addr = plat->slave_addr;
> +		i2c->slave = plat->slave;
> +	}
> +#endif
> +
> +	clk_enable(i2c->clk);
> +
> +	if (plat)
> +		i2c->adap.class = plat->class;
> +
> +	if (i2c->use_pio) {
> +		i2c->adap.algo = &i2c_pxa_pio_algorithm;
> +	} else {
> +		i2c->adap.algo = &i2c_pxa_algorithm;
> +		ret = request_irq(irq, i2c_pxa_handler, IRQF_SHARED,
> +				  i2c->adap.name, i2c);
> +		if (ret)
> +			goto ereqirq;
> +	}
> +
> +	i2c_pxa_reset(i2c);
> +
> +	i2c->adap.algo_data = i2c;
> +	i2c->adap.dev.parent = &of_dev->dev;
> +	i2c->adap.dev.of_node = of_dev->dev.of_node;
> +
> +	if (i2c_type == REGS_CE4100)
> +		ret = i2c_add_adapter(&i2c->adap);
> +	else
> +		ret = i2c_add_numbered_adapter(&i2c->adap);
> +	if (ret < 0) {
> +		printk(KERN_INFO "I2C: Failed to add bus\n");
> +		goto eadapt;
> +	}
> +	of_i2c_register_devices(&i2c->adap);
> +
> +	platform_set_drvdata(of_dev, i2c);
> +
> +#ifdef CONFIG_I2C_PXA_SLAVE
> +	printk(KERN_INFO "I2C: %s: PXA I2C adapter, slave address %d\n",
> +	       dev_name(&i2c->adap.dev), i2c->slave_addr);
> +#else
> +	printk(KERN_INFO "I2C: %s: PXA I2C adapter\n",
> +	       dev_name(&i2c->adap.dev));
> +#endif
> +	return 0;
> +
> +eadapt:
> +	if (!i2c->use_pio)
> +		free_irq(irq, i2c);
> +ereqirq:
> +	clk_disable(i2c->clk);
> +	iounmap(i2c->reg_base);
> +eremap:
> +	clk_put(i2c->clk);
> +eclk:
> +	kfree(i2c);
> +emalloc:
> +	release_mem_region(res->start, resource_size(res));
> +	return ret;
> +}
> +#else
> +
>  static int i2c_pxa_probe(struct platform_device *dev)
>  {
>  	struct pxa_i2c *i2c;
> @@ -1174,6 +1331,7 @@ emalloc:
>  	release_mem_region(res->start, resource_size(res));
>  	return ret;
>  }
> +#endif
>  
>  static int __exit i2c_pxa_remove(struct platform_device *dev)
>  {
> @@ -1228,12 +1386,17 @@ static const struct dev_pm_ops i2c_pxa_dev_pm_ops = {
>  #endif
>  
>  static struct platform_driver i2c_pxa_driver = {
> +#ifdef CONFIG_OF
> +	.probe		= i2c_pxa_of_probe,
> +#else
>  	.probe		= i2c_pxa_probe,
> +#endif
>  	.remove		= __exit_p(i2c_pxa_remove),
>  	.driver		= {
>  		.name	= "pxa2xx-i2c",
>  		.owner	= THIS_MODULE,
>  		.pm	= I2C_PXA_DEV_PM_OPS,
> +		.of_match_table	= pxa_i2c_of_match,
>  	},
>  	.id_table	= i2c_pxa_id_table,
>  };
> -- 
> 1.5.6.5
> 

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

* [PATCH] i2c: pxa: create dynamic platform device from device tree
@ 2011-07-10  5:26                 ` Grant Likely
  0 siblings, 0 replies; 58+ messages in thread
From: Grant Likely @ 2011-07-10  5:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 08, 2011 at 06:20:23PM +0800, Haojian Zhuang wrote:
> Create two probe function to support both current platform device and created
> dynamic platform device from device tree. After moving to device tree,
> original implementation of platform device will be removed.
> 
> Use property to present polling mode and frequency mode.
> 
> Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
> ---
>  drivers/i2c/busses/i2c-pxa.c |  163 ++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 163 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
> index d603646..7a6d774 100644
> --- a/drivers/i2c/busses/i2c-pxa.c
> +++ b/drivers/i2c/busses/i2c-pxa.c
> @@ -29,6 +29,7 @@
>  #include <linux/errno.h>
>  #include <linux/interrupt.h>
>  #include <linux/i2c-pxa.h>
> +#include <linux/of_device.h>
>  #include <linux/of_i2c.h>
>  #include <linux/platform_device.h>
>  #include <linux/err.h>
> @@ -1044,6 +1045,162 @@ static const struct i2c_algorithm i2c_pxa_pio_algorithm = {
>  	.functionality	= i2c_pxa_functionality,
>  };
>  
> +static const struct of_device_id pxa_i2c_of_match[] = {
> +	{ .compatible = "pxa2xx-i2c",	.data = (void *)REGS_PXA2XX, },
> +	{ .compatible = "pxa3xx-pwri2c", .data = (void *)REGS_PXA3XX, },
> +	{ .compatible = "ce4100-i2c",	.data = (void *)REGS_CE4100, },

New compatible values need to be written up in
Documentation/devicetree/bindings, and strings should be in the form
"<vendor>,<soc>-i2c".  They should also be specific to the soc instead
of trying to be generic (ie. use "marvell,pxa255-i2c" instead of
"marvell,pxa2xx-i2c".

> +	{},
> +};
> +
> +#ifdef CONFIG_OF
> +static int i2c_pxa_of_probe(struct platform_device *of_dev)
> +{

CONFIG_OF should not be an either/or option.  Turning on CONFIG_OF
must not disable non-DT users.

> +	struct device_node *np = of_dev->dev.of_node;
> +	const struct of_device_id *match;
> +	struct i2c_pxa_platform_data *plat = NULL;
> +	struct pxa_i2c *i2c;
> +	struct resource *res;
> +	const __be32 *p;
> +	int i2c_type, irq, data, ret;
> +	int id = 0, poll = 0, fast = 0;
> +
> +	match = of_match_device(pxa_i2c_of_match, &of_dev->dev);
> +	if (match == NULL)
> +		return -ENODEV;
> +	i2c_type = (int)match->data;
> +
> +	p = of_get_property(np, "cell-index", &data);
> +	if (p)
> +		id = be32_to_cpu(*p);

When using the device tree, the bus id should be dynamically
assigned.  Don't use a cell-index property.

> +
> +	p = of_get_property(np, "i2c-polling", &data);
> +	if (p)
> +		poll = be32_to_cpu(*p);
> +
> +	p = of_get_property(np, "i2c-frequency", &data);
> +	if (p && !strncmp((char *)p, "fast", data))
> +		fast = 1;
> +
> +	res = platform_get_resource(of_dev, IORESOURCE_MEM, 0);
> +	irq = platform_get_irq(of_dev, 0);
> +	if (res == NULL || irq < 0)
> +		return -ENODEV;
> +
> +	if (!request_mem_region(res->start, resource_size(res), res->name))
> +		return -ENOMEM;
> +
> +	i2c = kzalloc(sizeof(struct pxa_i2c), GFP_KERNEL);

kzalloc(sizeof(*i2c), GFP_KERNEL)

> +	if (!i2c) {
> +		ret = -ENOMEM;
> +		goto emalloc;
> +	}
> +
> +	i2c->adap.owner   = THIS_MODULE;
> +	i2c->adap.retries = 5;
> +
> +	spin_lock_init(&i2c->lock);
> +	init_waitqueue_head(&i2c->wait);
> +
> +	/*
> +	 * adap.nr comes from cell-index in dts file
> +	 */
> +	i2c->adap.nr = id;
> +	snprintf(i2c->adap.name, sizeof(i2c->adap.name), "pxa2xx-i2c.%u",
> +		 i2c->adap.nr);
> +
> +	i2c->clk = clk_get_sys(i2c->adap.name, NULL);
> +	if (IS_ERR(i2c->clk)) {
> +		ret = PTR_ERR(i2c->clk);
> +		goto eclk;
> +	}
> +
> +	i2c->reg_base = ioremap(res->start, resource_size(res));
> +	if (!i2c->reg_base) {
> +		ret = -EIO;
> +		goto eremap;
> +	}
> +
> +	i2c->reg_ibmr = i2c->reg_base + pxa_reg_layout[i2c_type].ibmr;
> +	i2c->reg_idbr = i2c->reg_base + pxa_reg_layout[i2c_type].idbr;
> +	i2c->reg_icr = i2c->reg_base + pxa_reg_layout[i2c_type].icr;
> +	i2c->reg_isr = i2c->reg_base + pxa_reg_layout[i2c_type].isr;
> +	if (i2c_type != REGS_CE4100)
> +		i2c->reg_isar = i2c->reg_base + pxa_reg_layout[i2c_type].isar;
> +
> +	i2c->iobase = res->start;
> +	i2c->iosize = resource_size(res);
> +
> +	i2c->irq = irq;
> +	i2c->use_pio = poll;
> +	i2c->fast_mode = fast;
> +
> +	i2c->slave_addr = I2C_PXA_SLAVE_ADDR;
> +
> +#ifdef CONFIG_I2C_PXA_SLAVE
> +	if (plat) {
> +		i2c->slave_addr = plat->slave_addr;
> +		i2c->slave = plat->slave;
> +	}
> +#endif
> +
> +	clk_enable(i2c->clk);
> +
> +	if (plat)
> +		i2c->adap.class = plat->class;
> +
> +	if (i2c->use_pio) {
> +		i2c->adap.algo = &i2c_pxa_pio_algorithm;
> +	} else {
> +		i2c->adap.algo = &i2c_pxa_algorithm;
> +		ret = request_irq(irq, i2c_pxa_handler, IRQF_SHARED,
> +				  i2c->adap.name, i2c);
> +		if (ret)
> +			goto ereqirq;
> +	}
> +
> +	i2c_pxa_reset(i2c);
> +
> +	i2c->adap.algo_data = i2c;
> +	i2c->adap.dev.parent = &of_dev->dev;
> +	i2c->adap.dev.of_node = of_dev->dev.of_node;
> +
> +	if (i2c_type == REGS_CE4100)
> +		ret = i2c_add_adapter(&i2c->adap);
> +	else
> +		ret = i2c_add_numbered_adapter(&i2c->adap);
> +	if (ret < 0) {
> +		printk(KERN_INFO "I2C: Failed to add bus\n");
> +		goto eadapt;
> +	}
> +	of_i2c_register_devices(&i2c->adap);
> +
> +	platform_set_drvdata(of_dev, i2c);
> +
> +#ifdef CONFIG_I2C_PXA_SLAVE
> +	printk(KERN_INFO "I2C: %s: PXA I2C adapter, slave address %d\n",
> +	       dev_name(&i2c->adap.dev), i2c->slave_addr);
> +#else
> +	printk(KERN_INFO "I2C: %s: PXA I2C adapter\n",
> +	       dev_name(&i2c->adap.dev));
> +#endif
> +	return 0;
> +
> +eadapt:
> +	if (!i2c->use_pio)
> +		free_irq(irq, i2c);
> +ereqirq:
> +	clk_disable(i2c->clk);
> +	iounmap(i2c->reg_base);
> +eremap:
> +	clk_put(i2c->clk);
> +eclk:
> +	kfree(i2c);
> +emalloc:
> +	release_mem_region(res->start, resource_size(res));
> +	return ret;
> +}
> +#else
> +
>  static int i2c_pxa_probe(struct platform_device *dev)
>  {
>  	struct pxa_i2c *i2c;
> @@ -1174,6 +1331,7 @@ emalloc:
>  	release_mem_region(res->start, resource_size(res));
>  	return ret;
>  }
> +#endif
>  
>  static int __exit i2c_pxa_remove(struct platform_device *dev)
>  {
> @@ -1228,12 +1386,17 @@ static const struct dev_pm_ops i2c_pxa_dev_pm_ops = {
>  #endif
>  
>  static struct platform_driver i2c_pxa_driver = {
> +#ifdef CONFIG_OF
> +	.probe		= i2c_pxa_of_probe,
> +#else
>  	.probe		= i2c_pxa_probe,
> +#endif
>  	.remove		= __exit_p(i2c_pxa_remove),
>  	.driver		= {
>  		.name	= "pxa2xx-i2c",
>  		.owner	= THIS_MODULE,
>  		.pm	= I2C_PXA_DEV_PM_OPS,
> +		.of_match_table	= pxa_i2c_of_match,
>  	},
>  	.id_table	= i2c_pxa_id_table,
>  };
> -- 
> 1.5.6.5
> 

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

* Re: [PATCH] mfd: convert devicetree to platform data on max8925
  2011-07-08 10:20                   ` Haojian Zhuang
@ 2011-07-10  7:20                       ` Grant Likely
  -1 siblings, 0 replies; 58+ messages in thread
From: Grant Likely @ 2011-07-10  7:20 UTC (permalink / raw)
  To: Haojian Zhuang
  Cc: eric.y.miao-Re5JQEeQqe8AvxtiuMwx3w,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	samuel.ortiz-ral2JQCrhuEAvxtiuMwx3w,
	linux-lFZ/pmaqli7XmaaqVzeoHQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	alan-VuQAYsv1563Yd54FQh9/CA

On Fri, Jul 08, 2011 at 06:20:26PM +0800, Haojian Zhuang wrote:
> Make max8925 to support both platform data and device tree. So a translation
> between device tree and platform data is added.
> 
> Signed-off-by: Haojian Zhuang <haojian.zhuang-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
> ---
>  drivers/mfd/max8925-i2c.c |  159 ++++++++++++++++++++++++++++++++++++++++++++-
>  1 files changed, 157 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c
> index 0219115..fb74554 100644
> --- a/drivers/mfd/max8925-i2c.c
> +++ b/drivers/mfd/max8925-i2c.c
> @@ -10,6 +10,9 @@
>   */
>  #include <linux/kernel.h>
>  #include <linux/module.h>
> +#include <linux/irq.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_regulator.h>
>  #include <linux/platform_device.h>
>  #include <linux/i2c.h>
>  #include <linux/mfd/max8925.h>
> @@ -135,6 +138,154 @@ static const struct i2c_device_id max8925_id_table[] = {
>  };
>  MODULE_DEVICE_TABLE(i2c, max8925_id_table);
>  
> +#ifdef CONFIG_OF
> +static int __devinit max8925_parse_irq(struct i2c_client *i2c,
> +					struct max8925_platform_data *pdata)
> +{
> +	struct device_node *of_node = i2c->dev.of_node;
> +
> +	pdata->irq_base = irq_alloc_descs(-1, 0, MAX8925_NR_IRQS, 0);
> +	irq_domain_add_simple(of_node, pdata->irq_base);

of_node is only used once.  This could simply be:

	irq_domain_add_simple(i2c->dev.of_node, pdata->irq_base);

> +	return 0;
> +}
> +
> +static void __devinit max8925_parse_backlight(struct device_node *np,
> +					struct max8925_platform_data *pdata)
> +{
> +	struct max8925_backlight_pdata *bk;
> +	const __be32 *p;
> +
> +	bk = kzalloc(sizeof(struct max8925_backlight_pdata), GFP_KERNEL);
> +	if (bk == NULL)
> +		return;
> +	pdata->backlight = bk;
> +	p = of_get_property(np, "lxw-scl", NULL);
> +	if (p)
> +		bk->lxw_scl = be32_to_cpu(*p);
> +	p = of_get_property(np, "lxw-freq", NULL);
> +	if (p)
> +		bk->lxw_freq = be32_to_cpu(*p);
> +	p = of_get_property(np, "dual-string", NULL);
> +	if (p)
> +		bk->dual_string = be32_to_cpu(*p);

of_property_read_u32() and of_property_read_string() would help you here.

This implements a new binding.  Needs to be documented.

> +}
> +
> +static void __devinit max8925_parse_touch(struct device_node *np,
> +					struct max8925_platform_data *pdata)
> +{
> +	struct max8925_touch_pdata *touch;
> +	const __be32 *p;
> +
> +	touch = kzalloc(sizeof(struct max8925_touch_pdata), GFP_KERNEL);
> +	if (touch == NULL)
> +		return;
> +	pdata->touch = touch;
> +	p = of_get_property(np, "flags", NULL);
> +	if (p)
> +		touch->flags = be32_to_cpu(*p);
> +	p = of_get_property(np, "interrupts", NULL);
> +	if (p)
> +		pdata->tsc_irq = irq_of_parse_and_map(np, 0);

irq_of_parse_and_map() can be called directly.  It will return NO_IRQ
if the irq cannot be parsed.

> +}
> +
> +static void __devinit max8925_parse_power(struct device_node *np,
> +					struct max8925_platform_data *pdata)
> +{
> +	struct max8925_power_pdata *power;
> +	const __be32 *p;
> +
> +	power = kzalloc(sizeof(struct max8925_power_pdata), GFP_KERNEL);
> +	if (power == NULL)
> +		return;
> +	pdata->power = power;
> +	p = of_get_property(np, "battery-detect", NULL);
> +	if (p)
> +		power->batt_detect = be32_to_cpu(*p) ? 1 : 0;
> +	p = of_get_property(np, "topoff-threshold", NULL);
> +	if (p)
> +		power->topoff_threshold = be32_to_cpu(*p) & 0x3;
> +	p = of_get_property(np, "fast-charge", NULL);
> +	if (p)
> +		power->fast_charge = be32_to_cpu(*p) & 0x7;

Needs to be documented.

> +}
> +
> +static void __devinit max8925_parse_regulator(struct device_node *np,
> +					struct max8925_platform_data *pdata)
> +{
> +	const char *name[MAX8925_MAX_REGULATOR] = {
> +			"SD1", "SD2", "SD3", "LDO1", "LDO2", "LDO3", "LDO4",
> +			"LDO5", "LDO6", "LDO7", "LDO8", "LDO9", "LDO10",
> +			"LDO11", "LDO12", "LDO13", "LDO14", "LDO15", "LDO16",
> +			"LDO17", "LDO18", "LDO19", "LDO20"};
> +	const char *cp;
> +	int i;
> +
> +	cp = of_get_property(np, "compatible", NULL);
> +	if (cp == NULL)
> +		return;
> +	for (i = 0; i < MAX8925_MAX_REGULATOR; i++) {
> +		if (strncmp(cp, name[i], strlen(name[i])))
> +			continue;
> +		of_regulator_init_data(np, pdata->regulator[i]);
> +		break;

You don't need to open-code the parsing of compatible values.  Use
of_match_node() instead with an of_device_id table.

> +	}
> +}
> +
> +static struct max8925_platform_data __devinit
> +*max8925_get_alt_pdata(struct i2c_client *client)
> +{
> +	struct max8925_platform_data *pdata;
> +	struct device_node *of_node = client->dev.of_node;
> +	struct device_node *np, *pp = NULL;
> +	const char *cp;
> +	int ret, i;
> +
> +	pdata = kzalloc(sizeof(struct max8925_platform_data), GFP_KERNEL);

sizeof(*pdata)

> +	if (pdata == NULL)
> +		return NULL;
> +	pdata->regulator[0] = kzalloc(sizeof(struct regulator_init_data)
> +			* MAX8925_MAX_REGULATOR, GFP_KERNEL);

ditto.

Is it appropriate to allocated the entire table of regulators?  From
the parse_regulator function above, it looks like only one of the
regulators will actually get registered (I've not dug deeply into what
the driver needs here though).

> +	if (pdata->regulator[0] == NULL) {
> +		kfree(pdata);
> +		return NULL;
> +	}
> +	for (i = 1; i < MAX8925_MAX_REGULATOR; i++)
> +		pdata->regulator[i] = pdata->regulator[i - 1] + 1;
> +
> +	ret = max8925_parse_irq(client, pdata);
> +	if (ret < 0)
> +		goto out;
> +
> +	for (; (np = of_get_next_child(of_node, pp)) != NULL; pp = np) {
> +		cp = of_get_property(np, "compatible", NULL);
> +		if (cp == NULL)
> +			continue;
> +		if (!strncmp(cp, "backlight", strlen("backlight")))
> +			max8925_parse_backlight(np, pdata);
> +		if (!strncmp(cp, "power", strlen("power")))
> +			max8925_parse_power(np, pdata);
> +		if (!strncmp(cp, "touch", strlen("touch")))
> +			max8925_parse_touch(np, pdata);
> +		cp = of_get_property(np, "device_type", NULL);
> +		if (cp == NULL)
> +			continue;
> +		if (!strncmp(cp, "regulator", strlen("regulator")))
> +			max8925_parse_regulator(np, pdata);
> +	}
> +	return pdata;
> +out:
> +	kfree(pdata->regulator[0]);
> +	kfree(pdata);
> +	return NULL;
> +}
> +#else
> +static struct max8925_platform_data __devinit
> +*max8925_get_alt_pdata(struct i2c_client *client)
> +{
> +	return NULL;
> +}
> +#endif
> +
>  static int __devinit max8925_probe(struct i2c_client *client,
>  				   const struct i2c_device_id *id)
>  {
> @@ -142,8 +293,12 @@ static int __devinit max8925_probe(struct i2c_client *client,
>  	static struct max8925_chip *chip;
>  
>  	if (!pdata) {
> -		pr_info("%s: platform data is missing\n", __func__);
> -		return -EINVAL;
> +		pdata = max8925_get_alt_pdata(client);
> +		if (!pdata) {
> +			pr_info("%s: platform data is missing\n", __func__);
> +			return -EINVAL;
> +		}
> +		client->dev.platform_data = pdata;

Don't write to dev.platform_data.  Device drivers must treat
platform_data as immutable, and it is illegal to modify it.  If
platform_data is used outside of the probe function, then the driver
needs to be refactored to copy the data out of pdata and into the
driver's private data structure so that the data can be sourced from
either pdata or DT.

g.

>  	}
>  
>  	chip = kzalloc(sizeof(struct max8925_chip), GFP_KERNEL);
> -- 
> 1.5.6.5
> 

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

* [PATCH] mfd: convert devicetree to platform data on max8925
@ 2011-07-10  7:20                       ` Grant Likely
  0 siblings, 0 replies; 58+ messages in thread
From: Grant Likely @ 2011-07-10  7:20 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 08, 2011 at 06:20:26PM +0800, Haojian Zhuang wrote:
> Make max8925 to support both platform data and device tree. So a translation
> between device tree and platform data is added.
> 
> Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
> ---
>  drivers/mfd/max8925-i2c.c |  159 ++++++++++++++++++++++++++++++++++++++++++++-
>  1 files changed, 157 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c
> index 0219115..fb74554 100644
> --- a/drivers/mfd/max8925-i2c.c
> +++ b/drivers/mfd/max8925-i2c.c
> @@ -10,6 +10,9 @@
>   */
>  #include <linux/kernel.h>
>  #include <linux/module.h>
> +#include <linux/irq.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_regulator.h>
>  #include <linux/platform_device.h>
>  #include <linux/i2c.h>
>  #include <linux/mfd/max8925.h>
> @@ -135,6 +138,154 @@ static const struct i2c_device_id max8925_id_table[] = {
>  };
>  MODULE_DEVICE_TABLE(i2c, max8925_id_table);
>  
> +#ifdef CONFIG_OF
> +static int __devinit max8925_parse_irq(struct i2c_client *i2c,
> +					struct max8925_platform_data *pdata)
> +{
> +	struct device_node *of_node = i2c->dev.of_node;
> +
> +	pdata->irq_base = irq_alloc_descs(-1, 0, MAX8925_NR_IRQS, 0);
> +	irq_domain_add_simple(of_node, pdata->irq_base);

of_node is only used once.  This could simply be:

	irq_domain_add_simple(i2c->dev.of_node, pdata->irq_base);

> +	return 0;
> +}
> +
> +static void __devinit max8925_parse_backlight(struct device_node *np,
> +					struct max8925_platform_data *pdata)
> +{
> +	struct max8925_backlight_pdata *bk;
> +	const __be32 *p;
> +
> +	bk = kzalloc(sizeof(struct max8925_backlight_pdata), GFP_KERNEL);
> +	if (bk == NULL)
> +		return;
> +	pdata->backlight = bk;
> +	p = of_get_property(np, "lxw-scl", NULL);
> +	if (p)
> +		bk->lxw_scl = be32_to_cpu(*p);
> +	p = of_get_property(np, "lxw-freq", NULL);
> +	if (p)
> +		bk->lxw_freq = be32_to_cpu(*p);
> +	p = of_get_property(np, "dual-string", NULL);
> +	if (p)
> +		bk->dual_string = be32_to_cpu(*p);

of_property_read_u32() and of_property_read_string() would help you here.

This implements a new binding.  Needs to be documented.

> +}
> +
> +static void __devinit max8925_parse_touch(struct device_node *np,
> +					struct max8925_platform_data *pdata)
> +{
> +	struct max8925_touch_pdata *touch;
> +	const __be32 *p;
> +
> +	touch = kzalloc(sizeof(struct max8925_touch_pdata), GFP_KERNEL);
> +	if (touch == NULL)
> +		return;
> +	pdata->touch = touch;
> +	p = of_get_property(np, "flags", NULL);
> +	if (p)
> +		touch->flags = be32_to_cpu(*p);
> +	p = of_get_property(np, "interrupts", NULL);
> +	if (p)
> +		pdata->tsc_irq = irq_of_parse_and_map(np, 0);

irq_of_parse_and_map() can be called directly.  It will return NO_IRQ
if the irq cannot be parsed.

> +}
> +
> +static void __devinit max8925_parse_power(struct device_node *np,
> +					struct max8925_platform_data *pdata)
> +{
> +	struct max8925_power_pdata *power;
> +	const __be32 *p;
> +
> +	power = kzalloc(sizeof(struct max8925_power_pdata), GFP_KERNEL);
> +	if (power == NULL)
> +		return;
> +	pdata->power = power;
> +	p = of_get_property(np, "battery-detect", NULL);
> +	if (p)
> +		power->batt_detect = be32_to_cpu(*p) ? 1 : 0;
> +	p = of_get_property(np, "topoff-threshold", NULL);
> +	if (p)
> +		power->topoff_threshold = be32_to_cpu(*p) & 0x3;
> +	p = of_get_property(np, "fast-charge", NULL);
> +	if (p)
> +		power->fast_charge = be32_to_cpu(*p) & 0x7;

Needs to be documented.

> +}
> +
> +static void __devinit max8925_parse_regulator(struct device_node *np,
> +					struct max8925_platform_data *pdata)
> +{
> +	const char *name[MAX8925_MAX_REGULATOR] = {
> +			"SD1", "SD2", "SD3", "LDO1", "LDO2", "LDO3", "LDO4",
> +			"LDO5", "LDO6", "LDO7", "LDO8", "LDO9", "LDO10",
> +			"LDO11", "LDO12", "LDO13", "LDO14", "LDO15", "LDO16",
> +			"LDO17", "LDO18", "LDO19", "LDO20"};
> +	const char *cp;
> +	int i;
> +
> +	cp = of_get_property(np, "compatible", NULL);
> +	if (cp == NULL)
> +		return;
> +	for (i = 0; i < MAX8925_MAX_REGULATOR; i++) {
> +		if (strncmp(cp, name[i], strlen(name[i])))
> +			continue;
> +		of_regulator_init_data(np, pdata->regulator[i]);
> +		break;

You don't need to open-code the parsing of compatible values.  Use
of_match_node() instead with an of_device_id table.

> +	}
> +}
> +
> +static struct max8925_platform_data __devinit
> +*max8925_get_alt_pdata(struct i2c_client *client)
> +{
> +	struct max8925_platform_data *pdata;
> +	struct device_node *of_node = client->dev.of_node;
> +	struct device_node *np, *pp = NULL;
> +	const char *cp;
> +	int ret, i;
> +
> +	pdata = kzalloc(sizeof(struct max8925_platform_data), GFP_KERNEL);

sizeof(*pdata)

> +	if (pdata == NULL)
> +		return NULL;
> +	pdata->regulator[0] = kzalloc(sizeof(struct regulator_init_data)
> +			* MAX8925_MAX_REGULATOR, GFP_KERNEL);

ditto.

Is it appropriate to allocated the entire table of regulators?  From
the parse_regulator function above, it looks like only one of the
regulators will actually get registered (I've not dug deeply into what
the driver needs here though).

> +	if (pdata->regulator[0] == NULL) {
> +		kfree(pdata);
> +		return NULL;
> +	}
> +	for (i = 1; i < MAX8925_MAX_REGULATOR; i++)
> +		pdata->regulator[i] = pdata->regulator[i - 1] + 1;
> +
> +	ret = max8925_parse_irq(client, pdata);
> +	if (ret < 0)
> +		goto out;
> +
> +	for (; (np = of_get_next_child(of_node, pp)) != NULL; pp = np) {
> +		cp = of_get_property(np, "compatible", NULL);
> +		if (cp == NULL)
> +			continue;
> +		if (!strncmp(cp, "backlight", strlen("backlight")))
> +			max8925_parse_backlight(np, pdata);
> +		if (!strncmp(cp, "power", strlen("power")))
> +			max8925_parse_power(np, pdata);
> +		if (!strncmp(cp, "touch", strlen("touch")))
> +			max8925_parse_touch(np, pdata);
> +		cp = of_get_property(np, "device_type", NULL);
> +		if (cp == NULL)
> +			continue;
> +		if (!strncmp(cp, "regulator", strlen("regulator")))
> +			max8925_parse_regulator(np, pdata);
> +	}
> +	return pdata;
> +out:
> +	kfree(pdata->regulator[0]);
> +	kfree(pdata);
> +	return NULL;
> +}
> +#else
> +static struct max8925_platform_data __devinit
> +*max8925_get_alt_pdata(struct i2c_client *client)
> +{
> +	return NULL;
> +}
> +#endif
> +
>  static int __devinit max8925_probe(struct i2c_client *client,
>  				   const struct i2c_device_id *id)
>  {
> @@ -142,8 +293,12 @@ static int __devinit max8925_probe(struct i2c_client *client,
>  	static struct max8925_chip *chip;
>  
>  	if (!pdata) {
> -		pr_info("%s: platform data is missing\n", __func__);
> -		return -EINVAL;
> +		pdata = max8925_get_alt_pdata(client);
> +		if (!pdata) {
> +			pr_info("%s: platform data is missing\n", __func__);
> +			return -EINVAL;
> +		}
> +		client->dev.platform_data = pdata;

Don't write to dev.platform_data.  Device drivers must treat
platform_data as immutable, and it is illegal to modify it.  If
platform_data is used outside of the probe function, then the driver
needs to be refactored to copy the data out of pdata and into the
driver's private data structure so that the data can be sourced from
either pdata or DT.

g.

>  	}
>  
>  	chip = kzalloc(sizeof(struct max8925_chip), GFP_KERNEL);
> -- 
> 1.5.6.5
> 

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

* Re: [PATCH] mfd: convert devicetree to platform on 88pm860x
  2011-07-08 10:20                     ` Haojian Zhuang
@ 2011-07-10  7:21                         ` Grant Likely
  -1 siblings, 0 replies; 58+ messages in thread
From: Grant Likely @ 2011-07-10  7:21 UTC (permalink / raw)
  To: Haojian Zhuang
  Cc: eric.y.miao-Re5JQEeQqe8AvxtiuMwx3w,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	samuel.ortiz-ral2JQCrhuEAvxtiuMwx3w,
	linux-lFZ/pmaqli7XmaaqVzeoHQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	alan-VuQAYsv1563Yd54FQh9/CA

On Fri, Jul 08, 2011 at 06:20:27PM +0800, Haojian Zhuang wrote:
> Make 88pm860x to support both platform data and device tree. So a translation
> between device tree and platform data is added.
> 
> Signed-off-by: Haojian Zhuang <haojian.zhuang-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
> ---
>  drivers/mfd/88pm860x-i2c.c |  191 +++++++++++++++++++++++++++++++++++++++++++-
>  1 files changed, 189 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c
> index e017dc8..b017e4a 100644
> --- a/drivers/mfd/88pm860x-i2c.c
> +++ b/drivers/mfd/88pm860x-i2c.c
> @@ -10,6 +10,8 @@
>   */
>  #include <linux/kernel.h>
>  #include <linux/module.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_regulator.h>
>  #include <linux/platform_device.h>
>  #include <linux/i2c.h>
>  #include <linux/mfd/88pm860x.h>
> @@ -236,6 +238,187 @@ static const struct i2c_device_id pm860x_id_table[] = {
>  };
>  MODULE_DEVICE_TABLE(i2c, pm860x_id_table);
>  
> +#ifdef CONFIG_OF
> +static int __devinit pm860x_parse_irq(struct i2c_client *i2c,
> +				      struct pm860x_platform_data *pdata)
> +{
> +	struct device_node *of_node = i2c->dev.of_node;
> +
> +	pdata->irq_base = irq_alloc_descs(-1, 0, 24, 0);
> +	irq_domain_add_simple(of_node, pdata->irq_base);
> +	return 0;
> +}
> +
> +static void __devinit pm860x_parse_backlight(struct device_node *np,
> +					struct pm860x_platform_data *pdata)
> +{
> +	const __be32 *idx, *iset, *pwm;
> +	int i;
> +
> +	idx = of_get_property(np, "cell-index", NULL);
> +	if (idx == NULL)
> +		return;
> +	iset = of_get_property(np, "iset", NULL);
> +	if (iset == NULL)
> +		return;
> +	pwm = of_get_property(np, "pwm", NULL);
> +
> +	i = be32_to_cpu(*idx);
> +	pdata->backlight[i].iset = be32_to_cpu(*iset);
> +	pdata->backlight[i].flags = i;
> +	if (pwm)
> +		pdata->backlight[i].pwm = be32_to_cpu(*pwm);
> +	pdata->num_backlights++;
> +}
> +
> +static void __devinit pm860x_parse_led(struct device_node *np,
> +					struct pm860x_platform_data *pdata)
> +{
> +	const __be32 *idx, *iset;
> +	int i;
> +
> +	idx = of_get_property(np, "cell-index", NULL);
> +	if (idx == NULL)
> +		return;
> +	iset = of_get_property(np, "iset", NULL);
> +	if (iset == NULL)
> +		return;
> +
> +	i = be32_to_cpu(*idx);
> +	pdata->led[i].iset = be32_to_cpu(*iset);
> +	pdata->led[i].flags = i;
> +	pdata->num_leds++;
> +}
> +
> +static void __devinit pm860x_parse_touch(struct device_node *np,
> +					struct pm860x_platform_data *pdata)
> +{
> +	struct pm860x_touch_pdata *touch;
> +	const __be32 *prebias, *slot, *res, *prechg;
> +
> +	prebias = of_get_property(np, "prebias", NULL);
> +	if (prebias == NULL)
> +		return;
> +	slot = of_get_property(np, "slot-cycle", NULL);
> +	if (slot == NULL)
> +		return;
> +	res = of_get_property(np, "resistor-xplate", NULL);
> +	if (res == NULL)
> +		return;
> +	prechg = of_get_property(np, "pen-prechg", NULL);
> +	if (prechg == NULL)
> +		return;
> +	touch = kzalloc(sizeof(struct pm860x_touch_pdata), GFP_KERNEL);
> +	if (touch == NULL)
> +		return;
> +	touch->gpadc_prebias = be32_to_cpu(*prebias++);
> +	touch->tsi_prebias = be32_to_cpu(*prebias++);
> +	touch->pen_prebias = be32_to_cpu(*prebias);
> +	touch->slot_cycle = be32_to_cpu(*slot);
> +	touch->pen_prechg = be32_to_cpu(*prechg);
> +	pdata->touch = touch;
> +}
> +
> +static int data[PM8607_ID_RG_MAX];
> +
> +static void __devinit pm860x_parse_regulator(struct device_node *np,
> +					struct pm860x_platform_data *pdata)
> +{
> +	const char *name[PM8607_ID_RG_MAX] = {
> +		"BUCK1", "BUCK2", "BUCK3", "LDO1", "LDO2", "LDO3", "LOD4",
> +		"LDO5", "LDO6", "LDO7", "LDO8", "LDO9", "LDO10", "LDO11",
> +		"LDO12", "LDO13", "LDO14", "LDO15"};
> +	const char *cp;
> +	int i;
> +
> +	cp = of_get_property(np, "compatible", NULL);
> +	if (cp == NULL)
> +		return;
> +	for (i = 0; i < PM8607_ID_RG_MAX; i++) {
> +		if (strncmp(cp, name[i], strlen(name[i])))
> +			continue;
> +		of_regulator_init_data(np, &pdata->regulator[i]);
> +		data[i] = i;
> +		pdata->regulator[i].driver_data = &data[i];
> +		pdata->num_regulators++;
> +		break;
> +	}
> +}
> +
> +static struct pm860x_platform_data __devinit
> +*pm860x_get_alt_pdata(struct i2c_client *i2c)
> +{
> +	struct pm860x_platform_data *pdata;
> +	struct device_node *of_node = i2c->dev.of_node;
> +	struct device_node *np, *pp = NULL;
> +	const char *cp;
> +	const __be32 *p;
> +	int ret;
> +
> +	pdata = kzalloc(sizeof(struct pm860x_platform_data), GFP_KERNEL);
> +	if (pdata == NULL)
> +		return NULL;
> +	pdata->regulator = kzalloc(sizeof(struct regulator_init_data)
> +				* PM8607_ID_RG_MAX, GFP_KERNEL);
> +	if (pdata->regulator == NULL)
> +		goto out_reg;
> +	pdata->led = kzalloc(sizeof(struct pm860x_led_pdata) * 3,
> +				GFP_KERNEL);
> +	if (pdata->led == NULL)
> +		goto out_led;
> +	pdata->backlight = kzalloc(sizeof(struct pm860x_backlight_pdata)
> +					* 3, GFP_KERNEL);
> +	if (pdata->backlight == NULL)
> +		goto out_backlight;
> +	p = of_get_property(of_node, "i2c-port", NULL);
> +	if (p)
> +		pdata->i2c_port = be32_to_cpu(*p);
> +	p = of_get_property(of_node, "companion-addr", NULL);
> +	if (p)
> +		pdata->companion_addr = be32_to_cpu(*p);
> +	p = of_get_property(of_node, "irq-mode", NULL);
> +	if (p)
> +		pdata->irq_mode = be32_to_cpu(*p);

As commented earlier, new binding needs to be documented.

> +
> +	ret = pm860x_parse_irq(i2c, pdata);
> +	if (ret < 0)
> +		goto out;
> +
> +	for (; (np = of_get_next_child(of_node, pp)) != NULL; pp = np) {
> +		cp = of_get_property(np, "compatible", NULL);
> +		if (cp == NULL)
> +			continue;
> +		if (!strncmp(cp, "backlight", strlen("backlight")))
> +			pm860x_parse_backlight(np, pdata);
> +		if (!strncmp(cp, "led", strlen("led")))
> +			pm860x_parse_led(np, pdata);
> +		if (!strncmp(cp, "touch", strlen("touch")))
> +			pm860x_parse_touch(np, pdata);
> +		cp = of_get_property(np, "device_type", NULL);
> +		if (cp == NULL)
> +			continue;
> +		if (!strncmp(cp, "regulator", strlen("regulator")))
> +			pm860x_parse_regulator(np, pdata);
> +	}
> +	return pdata;
> +out:
> +	kfree(pdata->backlight);
> +out_backlight:
> +	kfree(pdata->led);
> +out_led:
> +	kfree(pdata->regulator);
> +out_reg:
> +	kfree(pdata);
> +	return NULL;
> +}
> +#else
> +static struct pm860x_platform_data __devinit
> +*pm860x_get_alt_pdata(struct i2c_client *i2c)
> +{
> +	return NULL;
> +}
> +#endif
> +
>  static int verify_addr(struct i2c_client *i2c)
>  {
>  	unsigned short addr_8607[] = {0x30, 0x34};
> @@ -264,8 +447,12 @@ static int __devinit pm860x_probe(struct i2c_client *client,
>  	struct pm860x_chip *chip;
>  
>  	if (!pdata) {
> -		pr_info("No platform data in %s!\n", __func__);
> -		return -EINVAL;
> +		pdata = pm860x_get_alt_pdata(client);
> +		if (!pdata) {
> +			pr_info("No platform data in %s!\n", __func__);
> +			return -EINVAL;
> +		}
> +		client->dev.platform_data = pdata;

Ditto here to comment on last patch.  Don't modify platform_data in a device driver.

>  	}
>  
>  	chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL);
> -- 
> 1.5.6.5
> 

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

* [PATCH] mfd: convert devicetree to platform on 88pm860x
@ 2011-07-10  7:21                         ` Grant Likely
  0 siblings, 0 replies; 58+ messages in thread
From: Grant Likely @ 2011-07-10  7:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 08, 2011 at 06:20:27PM +0800, Haojian Zhuang wrote:
> Make 88pm860x to support both platform data and device tree. So a translation
> between device tree and platform data is added.
> 
> Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
> ---
>  drivers/mfd/88pm860x-i2c.c |  191 +++++++++++++++++++++++++++++++++++++++++++-
>  1 files changed, 189 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c
> index e017dc8..b017e4a 100644
> --- a/drivers/mfd/88pm860x-i2c.c
> +++ b/drivers/mfd/88pm860x-i2c.c
> @@ -10,6 +10,8 @@
>   */
>  #include <linux/kernel.h>
>  #include <linux/module.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_regulator.h>
>  #include <linux/platform_device.h>
>  #include <linux/i2c.h>
>  #include <linux/mfd/88pm860x.h>
> @@ -236,6 +238,187 @@ static const struct i2c_device_id pm860x_id_table[] = {
>  };
>  MODULE_DEVICE_TABLE(i2c, pm860x_id_table);
>  
> +#ifdef CONFIG_OF
> +static int __devinit pm860x_parse_irq(struct i2c_client *i2c,
> +				      struct pm860x_platform_data *pdata)
> +{
> +	struct device_node *of_node = i2c->dev.of_node;
> +
> +	pdata->irq_base = irq_alloc_descs(-1, 0, 24, 0);
> +	irq_domain_add_simple(of_node, pdata->irq_base);
> +	return 0;
> +}
> +
> +static void __devinit pm860x_parse_backlight(struct device_node *np,
> +					struct pm860x_platform_data *pdata)
> +{
> +	const __be32 *idx, *iset, *pwm;
> +	int i;
> +
> +	idx = of_get_property(np, "cell-index", NULL);
> +	if (idx == NULL)
> +		return;
> +	iset = of_get_property(np, "iset", NULL);
> +	if (iset == NULL)
> +		return;
> +	pwm = of_get_property(np, "pwm", NULL);
> +
> +	i = be32_to_cpu(*idx);
> +	pdata->backlight[i].iset = be32_to_cpu(*iset);
> +	pdata->backlight[i].flags = i;
> +	if (pwm)
> +		pdata->backlight[i].pwm = be32_to_cpu(*pwm);
> +	pdata->num_backlights++;
> +}
> +
> +static void __devinit pm860x_parse_led(struct device_node *np,
> +					struct pm860x_platform_data *pdata)
> +{
> +	const __be32 *idx, *iset;
> +	int i;
> +
> +	idx = of_get_property(np, "cell-index", NULL);
> +	if (idx == NULL)
> +		return;
> +	iset = of_get_property(np, "iset", NULL);
> +	if (iset == NULL)
> +		return;
> +
> +	i = be32_to_cpu(*idx);
> +	pdata->led[i].iset = be32_to_cpu(*iset);
> +	pdata->led[i].flags = i;
> +	pdata->num_leds++;
> +}
> +
> +static void __devinit pm860x_parse_touch(struct device_node *np,
> +					struct pm860x_platform_data *pdata)
> +{
> +	struct pm860x_touch_pdata *touch;
> +	const __be32 *prebias, *slot, *res, *prechg;
> +
> +	prebias = of_get_property(np, "prebias", NULL);
> +	if (prebias == NULL)
> +		return;
> +	slot = of_get_property(np, "slot-cycle", NULL);
> +	if (slot == NULL)
> +		return;
> +	res = of_get_property(np, "resistor-xplate", NULL);
> +	if (res == NULL)
> +		return;
> +	prechg = of_get_property(np, "pen-prechg", NULL);
> +	if (prechg == NULL)
> +		return;
> +	touch = kzalloc(sizeof(struct pm860x_touch_pdata), GFP_KERNEL);
> +	if (touch == NULL)
> +		return;
> +	touch->gpadc_prebias = be32_to_cpu(*prebias++);
> +	touch->tsi_prebias = be32_to_cpu(*prebias++);
> +	touch->pen_prebias = be32_to_cpu(*prebias);
> +	touch->slot_cycle = be32_to_cpu(*slot);
> +	touch->pen_prechg = be32_to_cpu(*prechg);
> +	pdata->touch = touch;
> +}
> +
> +static int data[PM8607_ID_RG_MAX];
> +
> +static void __devinit pm860x_parse_regulator(struct device_node *np,
> +					struct pm860x_platform_data *pdata)
> +{
> +	const char *name[PM8607_ID_RG_MAX] = {
> +		"BUCK1", "BUCK2", "BUCK3", "LDO1", "LDO2", "LDO3", "LOD4",
> +		"LDO5", "LDO6", "LDO7", "LDO8", "LDO9", "LDO10", "LDO11",
> +		"LDO12", "LDO13", "LDO14", "LDO15"};
> +	const char *cp;
> +	int i;
> +
> +	cp = of_get_property(np, "compatible", NULL);
> +	if (cp == NULL)
> +		return;
> +	for (i = 0; i < PM8607_ID_RG_MAX; i++) {
> +		if (strncmp(cp, name[i], strlen(name[i])))
> +			continue;
> +		of_regulator_init_data(np, &pdata->regulator[i]);
> +		data[i] = i;
> +		pdata->regulator[i].driver_data = &data[i];
> +		pdata->num_regulators++;
> +		break;
> +	}
> +}
> +
> +static struct pm860x_platform_data __devinit
> +*pm860x_get_alt_pdata(struct i2c_client *i2c)
> +{
> +	struct pm860x_platform_data *pdata;
> +	struct device_node *of_node = i2c->dev.of_node;
> +	struct device_node *np, *pp = NULL;
> +	const char *cp;
> +	const __be32 *p;
> +	int ret;
> +
> +	pdata = kzalloc(sizeof(struct pm860x_platform_data), GFP_KERNEL);
> +	if (pdata == NULL)
> +		return NULL;
> +	pdata->regulator = kzalloc(sizeof(struct regulator_init_data)
> +				* PM8607_ID_RG_MAX, GFP_KERNEL);
> +	if (pdata->regulator == NULL)
> +		goto out_reg;
> +	pdata->led = kzalloc(sizeof(struct pm860x_led_pdata) * 3,
> +				GFP_KERNEL);
> +	if (pdata->led == NULL)
> +		goto out_led;
> +	pdata->backlight = kzalloc(sizeof(struct pm860x_backlight_pdata)
> +					* 3, GFP_KERNEL);
> +	if (pdata->backlight == NULL)
> +		goto out_backlight;
> +	p = of_get_property(of_node, "i2c-port", NULL);
> +	if (p)
> +		pdata->i2c_port = be32_to_cpu(*p);
> +	p = of_get_property(of_node, "companion-addr", NULL);
> +	if (p)
> +		pdata->companion_addr = be32_to_cpu(*p);
> +	p = of_get_property(of_node, "irq-mode", NULL);
> +	if (p)
> +		pdata->irq_mode = be32_to_cpu(*p);

As commented earlier, new binding needs to be documented.

> +
> +	ret = pm860x_parse_irq(i2c, pdata);
> +	if (ret < 0)
> +		goto out;
> +
> +	for (; (np = of_get_next_child(of_node, pp)) != NULL; pp = np) {
> +		cp = of_get_property(np, "compatible", NULL);
> +		if (cp == NULL)
> +			continue;
> +		if (!strncmp(cp, "backlight", strlen("backlight")))
> +			pm860x_parse_backlight(np, pdata);
> +		if (!strncmp(cp, "led", strlen("led")))
> +			pm860x_parse_led(np, pdata);
> +		if (!strncmp(cp, "touch", strlen("touch")))
> +			pm860x_parse_touch(np, pdata);
> +		cp = of_get_property(np, "device_type", NULL);
> +		if (cp == NULL)
> +			continue;
> +		if (!strncmp(cp, "regulator", strlen("regulator")))
> +			pm860x_parse_regulator(np, pdata);
> +	}
> +	return pdata;
> +out:
> +	kfree(pdata->backlight);
> +out_backlight:
> +	kfree(pdata->led);
> +out_led:
> +	kfree(pdata->regulator);
> +out_reg:
> +	kfree(pdata);
> +	return NULL;
> +}
> +#else
> +static struct pm860x_platform_data __devinit
> +*pm860x_get_alt_pdata(struct i2c_client *i2c)
> +{
> +	return NULL;
> +}
> +#endif
> +
>  static int verify_addr(struct i2c_client *i2c)
>  {
>  	unsigned short addr_8607[] = {0x30, 0x34};
> @@ -264,8 +447,12 @@ static int __devinit pm860x_probe(struct i2c_client *client,
>  	struct pm860x_chip *chip;
>  
>  	if (!pdata) {
> -		pr_info("No platform data in %s!\n", __func__);
> -		return -EINVAL;
> +		pdata = pm860x_get_alt_pdata(client);
> +		if (!pdata) {
> +			pr_info("No platform data in %s!\n", __func__);
> +			return -EINVAL;
> +		}
> +		client->dev.platform_data = pdata;

Ditto here to comment on last patch.  Don't modify platform_data in a device driver.

>  	}
>  
>  	chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL);
> -- 
> 1.5.6.5
> 

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

* Re: [PATCH] ARM: mmp: add DTS file
  2011-07-08 10:20                       ` Haojian Zhuang
@ 2011-07-10  7:35                           ` Grant Likely
  -1 siblings, 0 replies; 58+ messages in thread
From: Grant Likely @ 2011-07-10  7:35 UTC (permalink / raw)
  To: Haojian Zhuang
  Cc: eric.y.miao-Re5JQEeQqe8AvxtiuMwx3w,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	samuel.ortiz-ral2JQCrhuEAvxtiuMwx3w,
	linux-lFZ/pmaqli7XmaaqVzeoHQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	alan-VuQAYsv1563Yd54FQh9/CA

On Fri, Jul 08, 2011 at 06:20:28PM +0800, Haojian Zhuang wrote:
> Add DTS file to support brownstone & ttc-dkb.
> 
> Signed-off-by: Haojian Zhuang <haojian.zhuang-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>

Hi Haojian.

Overall, the patch series is moving in the right direction.  I've made
a lot of comments, but they shouldn't be difficult to resolve.  I look
forward to seeing the next version of the series.  Comments below...

> ---
>  arch/arm/boot/dts/mmp2-brownstone.dts |  319 +++++++++++++++++++++++++++++++++
>  arch/arm/boot/dts/ttc-dkb.dts         |  176 ++++++++++++++++++
>  arch/arm/mach-mmp/brownstone.c        |   66 ++-----
>  arch/arm/mach-mmp/ttc_dkb.c           |   21 ++-
>  4 files changed, 530 insertions(+), 52 deletions(-)
>  create mode 100644 arch/arm/boot/dts/mmp2-brownstone.dts
>  create mode 100644 arch/arm/boot/dts/ttc-dkb.dts
> 
> diff --git a/arch/arm/boot/dts/mmp2-brownstone.dts b/arch/arm/boot/dts/mmp2-brownstone.dts
> new file mode 100644
> index 0000000..5fdabc3
> --- /dev/null
> +++ b/arch/arm/boot/dts/mmp2-brownstone.dts
> @@ -0,0 +1,319 @@
> +/dts-v1/;
> +
> +/include/ "skeleton.dtsi"
> +
> +/ {
> +	model = "Marvell MMP2 Brownstone";
> +	compatible = "mrvl,mmp2-brownstone", "mrvl,armada610-brownstone";

You've already heard me harp on this, but I'll say it one more time
and then shut up.  Every new compatible property must be documented as
to what it means.

> +	interrupt-parent = <&mmp_intc>;
> +
> +	memory {
> +		reg = <0x00000000 0x20000000>;
> +	};
> +
> +	chosen {
> +		bootargs = "console=ttyS2,38400 root=/dev/nfs nfsroot=192.168.1.100:192.168.1.101::255.255.255.0::eth0:on";
> +		linux,stdout-path = &uart2;
> +	};
> +
> +	soc@d4000000 {
> +		compatible = "mrvl,mmp2", "mrvl,armada610", "simple-bus";
> +		device_type = "soc";

Drop device_type.

> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		ranges;
> +
> +		mmp_intc: interrupt-controller@d4282000 {
> +			compatible = "mrvl,mmp-intc";
> +			/*device_type = "intc";*/

Even the commented out device_type should be removed.  :-)

> +			interrupt-controller;
> +			#interrupt-cells = <1>;
> +			/*
> +			 * interrupts: irq index of parent's irq domain
> +			 */
> +			interrupts = <0>;

Drop this property.  Linux gets to decide what the first irq should
be.  It isn't a characteristic of hardware, and 'interrupts' already
has a strict definition.

> +			interrupt-parent = <&mmp_intc>;

Drop this, it doesn't make sense for an interrupt controller to claim
itself as its interrupt parent.

> +			sub-interrupts = <64>;

What is this for?

> +
> +			/* enable bits in conf register */
> +			enable_mask = <0x20>;

Convention is to not use underscore '_' in property names.  Use a dash '-' instead.
> +
> +			/* reg: <offset & size> */
> +			reg = <0xd4282000 0x400>;
> +		};
> +
> +		mux_intc4: interrupt-controller@d4282150 {
> +			compatible = "mrvl,mux-intc";
> +			#address-cells = <1>;
> +			#size-cells = <1>;
> +			#interrupt-cells = <1>;
> +			interrupt-controller;
> +			interrupts = <4>;
> +			interrupt-parent = <&mmp_intc>;

This line can be dropped since the root node already has mmp_intc as
the default interrupt parent.

> +			sub-interrupts = <2>;
> +			reg = <0xd4282150 0>;
> +			status-mask = <0x150 0x168>;
> +			/* mfp register & interrupt index */
> +			mfp-edge-interrupt = <0xd401e2c4 1>;
> +		};
[...]
> +		gpio: gpio-controller {
> +			compatible = "pxa,gpio";

mrvl,pxa255-gpio, or similar.

> +			gpio-controller;
> +			reg = <
> +				0xd4019000 0xb0
> +				0xd4019004 0xb0
> +				0xd4019008 0xb0
> +				0xd4019100 0xb0
> +				0xd4019104 0xb0
> +				0xd4019108 0xb0>;

This looks wrong.  The address ranges overlap.  Why not simply:
<0xd4019000 0x200>;

> +
> +			/* gpio-clk-value: <offset & value> */
> +			gpio-clk-value = <0xd4015038 0x3>;
> +
> +			/* gpio-mask: <offset & value> */
> +			gpio-mask = <
> +				0xd401909c 0xffffffff
> +				0xd40190a0 0xffffffff
> +				0xd40190a4 0xffffffff
> +				0xd401919c 0xffffffff
> +				0xd40191a0 0xffffffff
> +				0xd40191a4 0xffffffff>;
> +			gpio-pins = <0 192>;
> +			#interrupt-cells = <1>;
> +			interrupt-controller;
> +			interrupts = <49>;
> +			interrupt-parent = <&mmp_intc>;
> +			sub-interrupts = <192>;
> +		};

[...]

> diff --git a/arch/arm/mach-mmp/brownstone.c b/arch/arm/mach-mmp/brownstone.c
> index 7bb78fd..c9848ad 100644
> --- a/arch/arm/mach-mmp/brownstone.c
> +++ b/arch/arm/mach-mmp/brownstone.c
> @@ -12,6 +12,9 @@
>  
>  #include <linux/init.h>
>  #include <linux/kernel.h>
> +#include <linux/of.h>
> +#include <linux/of_fdt.h>
> +#include <linux/of_platform.h>
>  #include <linux/platform_device.h>
>  #include <linux/io.h>
>  #include <linux/gpio.h>
> @@ -105,30 +108,6 @@ static unsigned long brownstone_pin_config[] __initdata = {
>  	GPIO89_GPIO,
>  };
>  
> -static struct regulator_consumer_supply max8649_supply[] = {
> -	REGULATOR_SUPPLY("vcc_core", NULL),
> -};
> -
> -static struct regulator_init_data max8649_init_data = {
> -	.constraints	= {
> -		.name		= "vcc_core range",
> -		.min_uV		= 1150000,
> -		.max_uV		= 1280000,
> -		.always_on	= 1,
> -		.boot_on	= 1,
> -		.valid_ops_mask	= REGULATOR_CHANGE_VOLTAGE,
> -	},
> -	.num_consumer_supplies	= 1,
> -	.consumer_supplies	= &max8649_supply[0],
> -};
> -
> -static struct max8649_platform_data brownstone_max8649_info = {
> -	.mode		= 2,	/* VID1 = 1, VID0 = 0 */
> -	.extclk		= 0,
> -	.ramp_timing	= MAX8649_RAMP_32MV,
> -	.regulator	= &max8649_init_data,
> -};
> -
>  static struct regulator_consumer_supply brownstone_v_5vp_supplies[] = {
>  	REGULATOR_SUPPLY("v_5vp", NULL),
>  };
> @@ -158,47 +137,38 @@ static struct platform_device brownstone_v_5vp_device = {
>  	},
>  };
>  
> -static struct max8925_platform_data brownstone_max8925_info = {
> -	.irq_base		= IRQ_BOARD_START,
> -};
> -
> -static struct i2c_board_info brownstone_twsi1_info[] = {
> -	[0] = {
> -		.type		= "max8649",
> -		.addr		= 0x60,
> -		.platform_data	= &brownstone_max8649_info,
> -	},
> -	[1] = {
> -		.type		= "max8925",
> -		.addr		= 0x3c,
> -		.irq		= IRQ_MMP2_PMIC,
> -		.platform_data	= &brownstone_max8925_info,
> -	},
> -};
> -
>  static struct sdhci_pxa_platdata mmp2_sdh_platdata_mmc0 = {
>  	.max_speed	= 25000000,
>  };
>  
> +static __initdata struct of_device_id of_bus_ids[] = {
> +	{ .compatible = "simple-bus", },
> +	{},
> +};
> +
>  static void __init brownstone_init(void)
>  {
>  	mfp_config(ARRAY_AND_SIZE(brownstone_pin_config));
>  
> -	/* on-chip devices */
> -	mmp2_add_uart(1);
> -	mmp2_add_uart(3);
> -	mmp2_add_twsi(1, NULL, ARRAY_AND_SIZE(brownstone_twsi1_info));
> +	if (of_platform_bus_probe(NULL, of_bus_ids, NULL) < 0)
> +		BUG();
> +
>  	mmp2_add_sdhost(0, &mmp2_sdh_platdata_mmc0); /* SD/MMC */
>  
>  	/* enable 5v regulator */
>  	platform_device_register(&brownstone_v_5vp_device);
>  }
>  
> +static const char *brownstone_dt_match[] __initdata = {
> +	"mrvl,mmp2-brownstone",
> +	NULL,
> +};
> +
>  MACHINE_START(BROWNSTONE, "Brownstone Development Platform")
>  	/* Maintainer: Haojian Zhuang <haojian.zhuang-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org> */
>  	.map_io		= mmp_map_io,
> -	.nr_irqs	= BROWNSTONE_NR_IRQS,
> -	.init_irq	= mmp2_init_irq,
> +	.init_irq	= mmp_init_intc,
>  	.timer		= &mmp2_timer,
>  	.init_machine	= brownstone_init,
> +	.dt_compat	= brownstone_dt_match,
>  MACHINE_END

I suggest instead of directly modifying the brownstone board file,
create a new DT board file, make it support the brownstone and other
boards, than then remove the old board files when the DT
implementation is equal to the non-dt version.

> diff --git a/arch/arm/mach-mmp/ttc_dkb.c b/arch/arm/mach-mmp/ttc_dkb.c
> index e411039..c19b4dc 100644
> --- a/arch/arm/mach-mmp/ttc_dkb.c
> +++ b/arch/arm/mach-mmp/ttc_dkb.c
> @@ -10,6 +10,9 @@
>  
>  #include <linux/init.h>
>  #include <linux/kernel.h>
> +#include <linux/of.h>
> +#include <linux/of_fdt.h>
> +#include <linux/of_platform.h>
>  #include <linux/platform_device.h>
>  #include <linux/mtd/mtd.h>
>  #include <linux/mtd/partitions.h>
> @@ -113,21 +116,31 @@ static struct platform_device *ttc_dkb_devices[] = {
>  	&ttc_dkb_device_onenand,
>  };
>  
> +static __initdata struct of_device_id of_bus_ids[] = {
> +	{ .compatible = "simple-bus", },
> +	{},
> +};
> +
>  static void __init ttc_dkb_init(void)
>  {
>  	mfp_config(ARRAY_AND_SIZE(ttc_dkb_pin_config));
>  
> -	/* on-chip devices */
> -	pxa910_add_uart(1);
> +	if (of_platform_bus_probe(NULL, of_bus_ids, NULL) < 0)
> +		BUG();
>  
>  	/* off-chip devices */
>  	platform_add_devices(ARRAY_AND_SIZE(ttc_dkb_devices));
>  }
>  
> +static const char *ttc_dkb_dt_match[] __initdata = {
> +	"mrvl,ttc-dkb",
> +	NULL,
> +};
> +
>  MACHINE_START(TTC_DKB, "PXA910-based TTC_DKB Development Platform")
>  	.map_io		= mmp_map_io,
> -	.nr_irqs	= TTCDKB_NR_IRQS,
> -	.init_irq       = pxa910_init_irq,
> +	.init_irq       = mmp_init_intc,
>  	.timer          = &pxa910_timer,
>  	.init_machine   = ttc_dkb_init,
> +	.dt_compat	= ttc_dkb_dt_match,
>  MACHINE_END
> -- 
> 1.5.6.5
> 

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

* [PATCH] ARM: mmp: add DTS file
@ 2011-07-10  7:35                           ` Grant Likely
  0 siblings, 0 replies; 58+ messages in thread
From: Grant Likely @ 2011-07-10  7:35 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 08, 2011 at 06:20:28PM +0800, Haojian Zhuang wrote:
> Add DTS file to support brownstone & ttc-dkb.
> 
> Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>

Hi Haojian.

Overall, the patch series is moving in the right direction.  I've made
a lot of comments, but they shouldn't be difficult to resolve.  I look
forward to seeing the next version of the series.  Comments below...

> ---
>  arch/arm/boot/dts/mmp2-brownstone.dts |  319 +++++++++++++++++++++++++++++++++
>  arch/arm/boot/dts/ttc-dkb.dts         |  176 ++++++++++++++++++
>  arch/arm/mach-mmp/brownstone.c        |   66 ++-----
>  arch/arm/mach-mmp/ttc_dkb.c           |   21 ++-
>  4 files changed, 530 insertions(+), 52 deletions(-)
>  create mode 100644 arch/arm/boot/dts/mmp2-brownstone.dts
>  create mode 100644 arch/arm/boot/dts/ttc-dkb.dts
> 
> diff --git a/arch/arm/boot/dts/mmp2-brownstone.dts b/arch/arm/boot/dts/mmp2-brownstone.dts
> new file mode 100644
> index 0000000..5fdabc3
> --- /dev/null
> +++ b/arch/arm/boot/dts/mmp2-brownstone.dts
> @@ -0,0 +1,319 @@
> +/dts-v1/;
> +
> +/include/ "skeleton.dtsi"
> +
> +/ {
> +	model = "Marvell MMP2 Brownstone";
> +	compatible = "mrvl,mmp2-brownstone", "mrvl,armada610-brownstone";

You've already heard me harp on this, but I'll say it one more time
and then shut up.  Every new compatible property must be documented as
to what it means.

> +	interrupt-parent = <&mmp_intc>;
> +
> +	memory {
> +		reg = <0x00000000 0x20000000>;
> +	};
> +
> +	chosen {
> +		bootargs = "console=ttyS2,38400 root=/dev/nfs nfsroot=192.168.1.100:192.168.1.101::255.255.255.0::eth0:on";
> +		linux,stdout-path = &uart2;
> +	};
> +
> +	soc at d4000000 {
> +		compatible = "mrvl,mmp2", "mrvl,armada610", "simple-bus";
> +		device_type = "soc";

Drop device_type.

> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		ranges;
> +
> +		mmp_intc: interrupt-controller at d4282000 {
> +			compatible = "mrvl,mmp-intc";
> +			/*device_type = "intc";*/

Even the commented out device_type should be removed.  :-)

> +			interrupt-controller;
> +			#interrupt-cells = <1>;
> +			/*
> +			 * interrupts: irq index of parent's irq domain
> +			 */
> +			interrupts = <0>;

Drop this property.  Linux gets to decide what the first irq should
be.  It isn't a characteristic of hardware, and 'interrupts' already
has a strict definition.

> +			interrupt-parent = <&mmp_intc>;

Drop this, it doesn't make sense for an interrupt controller to claim
itself as its interrupt parent.

> +			sub-interrupts = <64>;

What is this for?

> +
> +			/* enable bits in conf register */
> +			enable_mask = <0x20>;

Convention is to not use underscore '_' in property names.  Use a dash '-' instead.
> +
> +			/* reg: <offset & size> */
> +			reg = <0xd4282000 0x400>;
> +		};
> +
> +		mux_intc4: interrupt-controller at d4282150 {
> +			compatible = "mrvl,mux-intc";
> +			#address-cells = <1>;
> +			#size-cells = <1>;
> +			#interrupt-cells = <1>;
> +			interrupt-controller;
> +			interrupts = <4>;
> +			interrupt-parent = <&mmp_intc>;

This line can be dropped since the root node already has mmp_intc as
the default interrupt parent.

> +			sub-interrupts = <2>;
> +			reg = <0xd4282150 0>;
> +			status-mask = <0x150 0x168>;
> +			/* mfp register & interrupt index */
> +			mfp-edge-interrupt = <0xd401e2c4 1>;
> +		};
[...]
> +		gpio: gpio-controller {
> +			compatible = "pxa,gpio";

mrvl,pxa255-gpio, or similar.

> +			gpio-controller;
> +			reg = <
> +				0xd4019000 0xb0
> +				0xd4019004 0xb0
> +				0xd4019008 0xb0
> +				0xd4019100 0xb0
> +				0xd4019104 0xb0
> +				0xd4019108 0xb0>;

This looks wrong.  The address ranges overlap.  Why not simply:
<0xd4019000 0x200>;

> +
> +			/* gpio-clk-value: <offset & value> */
> +			gpio-clk-value = <0xd4015038 0x3>;
> +
> +			/* gpio-mask: <offset & value> */
> +			gpio-mask = <
> +				0xd401909c 0xffffffff
> +				0xd40190a0 0xffffffff
> +				0xd40190a4 0xffffffff
> +				0xd401919c 0xffffffff
> +				0xd40191a0 0xffffffff
> +				0xd40191a4 0xffffffff>;
> +			gpio-pins = <0 192>;
> +			#interrupt-cells = <1>;
> +			interrupt-controller;
> +			interrupts = <49>;
> +			interrupt-parent = <&mmp_intc>;
> +			sub-interrupts = <192>;
> +		};

[...]

> diff --git a/arch/arm/mach-mmp/brownstone.c b/arch/arm/mach-mmp/brownstone.c
> index 7bb78fd..c9848ad 100644
> --- a/arch/arm/mach-mmp/brownstone.c
> +++ b/arch/arm/mach-mmp/brownstone.c
> @@ -12,6 +12,9 @@
>  
>  #include <linux/init.h>
>  #include <linux/kernel.h>
> +#include <linux/of.h>
> +#include <linux/of_fdt.h>
> +#include <linux/of_platform.h>
>  #include <linux/platform_device.h>
>  #include <linux/io.h>
>  #include <linux/gpio.h>
> @@ -105,30 +108,6 @@ static unsigned long brownstone_pin_config[] __initdata = {
>  	GPIO89_GPIO,
>  };
>  
> -static struct regulator_consumer_supply max8649_supply[] = {
> -	REGULATOR_SUPPLY("vcc_core", NULL),
> -};
> -
> -static struct regulator_init_data max8649_init_data = {
> -	.constraints	= {
> -		.name		= "vcc_core range",
> -		.min_uV		= 1150000,
> -		.max_uV		= 1280000,
> -		.always_on	= 1,
> -		.boot_on	= 1,
> -		.valid_ops_mask	= REGULATOR_CHANGE_VOLTAGE,
> -	},
> -	.num_consumer_supplies	= 1,
> -	.consumer_supplies	= &max8649_supply[0],
> -};
> -
> -static struct max8649_platform_data brownstone_max8649_info = {
> -	.mode		= 2,	/* VID1 = 1, VID0 = 0 */
> -	.extclk		= 0,
> -	.ramp_timing	= MAX8649_RAMP_32MV,
> -	.regulator	= &max8649_init_data,
> -};
> -
>  static struct regulator_consumer_supply brownstone_v_5vp_supplies[] = {
>  	REGULATOR_SUPPLY("v_5vp", NULL),
>  };
> @@ -158,47 +137,38 @@ static struct platform_device brownstone_v_5vp_device = {
>  	},
>  };
>  
> -static struct max8925_platform_data brownstone_max8925_info = {
> -	.irq_base		= IRQ_BOARD_START,
> -};
> -
> -static struct i2c_board_info brownstone_twsi1_info[] = {
> -	[0] = {
> -		.type		= "max8649",
> -		.addr		= 0x60,
> -		.platform_data	= &brownstone_max8649_info,
> -	},
> -	[1] = {
> -		.type		= "max8925",
> -		.addr		= 0x3c,
> -		.irq		= IRQ_MMP2_PMIC,
> -		.platform_data	= &brownstone_max8925_info,
> -	},
> -};
> -
>  static struct sdhci_pxa_platdata mmp2_sdh_platdata_mmc0 = {
>  	.max_speed	= 25000000,
>  };
>  
> +static __initdata struct of_device_id of_bus_ids[] = {
> +	{ .compatible = "simple-bus", },
> +	{},
> +};
> +
>  static void __init brownstone_init(void)
>  {
>  	mfp_config(ARRAY_AND_SIZE(brownstone_pin_config));
>  
> -	/* on-chip devices */
> -	mmp2_add_uart(1);
> -	mmp2_add_uart(3);
> -	mmp2_add_twsi(1, NULL, ARRAY_AND_SIZE(brownstone_twsi1_info));
> +	if (of_platform_bus_probe(NULL, of_bus_ids, NULL) < 0)
> +		BUG();
> +
>  	mmp2_add_sdhost(0, &mmp2_sdh_platdata_mmc0); /* SD/MMC */
>  
>  	/* enable 5v regulator */
>  	platform_device_register(&brownstone_v_5vp_device);
>  }
>  
> +static const char *brownstone_dt_match[] __initdata = {
> +	"mrvl,mmp2-brownstone",
> +	NULL,
> +};
> +
>  MACHINE_START(BROWNSTONE, "Brownstone Development Platform")
>  	/* Maintainer: Haojian Zhuang <haojian.zhuang@marvell.com> */
>  	.map_io		= mmp_map_io,
> -	.nr_irqs	= BROWNSTONE_NR_IRQS,
> -	.init_irq	= mmp2_init_irq,
> +	.init_irq	= mmp_init_intc,
>  	.timer		= &mmp2_timer,
>  	.init_machine	= brownstone_init,
> +	.dt_compat	= brownstone_dt_match,
>  MACHINE_END

I suggest instead of directly modifying the brownstone board file,
create a new DT board file, make it support the brownstone and other
boards, than then remove the old board files when the DT
implementation is equal to the non-dt version.

> diff --git a/arch/arm/mach-mmp/ttc_dkb.c b/arch/arm/mach-mmp/ttc_dkb.c
> index e411039..c19b4dc 100644
> --- a/arch/arm/mach-mmp/ttc_dkb.c
> +++ b/arch/arm/mach-mmp/ttc_dkb.c
> @@ -10,6 +10,9 @@
>  
>  #include <linux/init.h>
>  #include <linux/kernel.h>
> +#include <linux/of.h>
> +#include <linux/of_fdt.h>
> +#include <linux/of_platform.h>
>  #include <linux/platform_device.h>
>  #include <linux/mtd/mtd.h>
>  #include <linux/mtd/partitions.h>
> @@ -113,21 +116,31 @@ static struct platform_device *ttc_dkb_devices[] = {
>  	&ttc_dkb_device_onenand,
>  };
>  
> +static __initdata struct of_device_id of_bus_ids[] = {
> +	{ .compatible = "simple-bus", },
> +	{},
> +};
> +
>  static void __init ttc_dkb_init(void)
>  {
>  	mfp_config(ARRAY_AND_SIZE(ttc_dkb_pin_config));
>  
> -	/* on-chip devices */
> -	pxa910_add_uart(1);
> +	if (of_platform_bus_probe(NULL, of_bus_ids, NULL) < 0)
> +		BUG();
>  
>  	/* off-chip devices */
>  	platform_add_devices(ARRAY_AND_SIZE(ttc_dkb_devices));
>  }
>  
> +static const char *ttc_dkb_dt_match[] __initdata = {
> +	"mrvl,ttc-dkb",
> +	NULL,
> +};
> +
>  MACHINE_START(TTC_DKB, "PXA910-based TTC_DKB Development Platform")
>  	.map_io		= mmp_map_io,
> -	.nr_irqs	= TTCDKB_NR_IRQS,
> -	.init_irq       = pxa910_init_irq,
> +	.init_irq       = mmp_init_intc,
>  	.timer          = &pxa910_timer,
>  	.init_machine   = ttc_dkb_init,
> +	.dt_compat	= ttc_dkb_dt_match,
>  MACHINE_END
> -- 
> 1.5.6.5
> 

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

* Re: [PATCH] mfd: convert devicetree to platform data on max8925
  2011-07-10  7:20                       ` Grant Likely
@ 2011-07-10  9:17                           ` Mark Brown
  -1 siblings, 0 replies; 58+ messages in thread
From: Mark Brown @ 2011-07-10  9:17 UTC (permalink / raw)
  To: Grant Likely
  Cc: eric.y.miao-Re5JQEeQqe8AvxtiuMwx3w,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Haojian Zhuang,
	samuel.ortiz-ral2JQCrhuEAvxtiuMwx3w,
	linux-lFZ/pmaqli7XmaaqVzeoHQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	alan-VuQAYsv1563Yd54FQh9/CA

On Sun, Jul 10, 2011 at 04:20:27PM +0900, Grant Likely wrote:
> On Fri, Jul 08, 2011 at 06:20:26PM +0800, Haojian Zhuang wrote:

> > +	if (pdata == NULL)
> > +		return NULL;
> > +	pdata->regulator[0] = kzalloc(sizeof(struct regulator_init_data)
> > +			* MAX8925_MAX_REGULATOR, GFP_KERNEL);

> ditto.

> Is it appropriate to allocated the entire table of regulators?  From
> the parse_regulator function above, it looks like only one of the
> regulators will actually get registered (I've not dug deeply into what
> the driver needs here though).

If the code/binding doesn't allow the use of all the regulators on the
device the code is probably wrong, it'd be very unusual to have hardware
like that.

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

* [PATCH] mfd: convert devicetree to platform data on max8925
@ 2011-07-10  9:17                           ` Mark Brown
  0 siblings, 0 replies; 58+ messages in thread
From: Mark Brown @ 2011-07-10  9:17 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Jul 10, 2011 at 04:20:27PM +0900, Grant Likely wrote:
> On Fri, Jul 08, 2011 at 06:20:26PM +0800, Haojian Zhuang wrote:

> > +	if (pdata == NULL)
> > +		return NULL;
> > +	pdata->regulator[0] = kzalloc(sizeof(struct regulator_init_data)
> > +			* MAX8925_MAX_REGULATOR, GFP_KERNEL);

> ditto.

> Is it appropriate to allocated the entire table of regulators?  From
> the parse_regulator function above, it looks like only one of the
> regulators will actually get registered (I've not dug deeply into what
> the driver needs here though).

If the code/binding doesn't allow the use of all the regulators on the
device the code is probably wrong, it'd be very unusual to have hardware
like that.

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

* Re: [PATCH] mfd: convert devicetree to platform data on max8925
  2011-07-10  9:17                           ` Mark Brown
@ 2011-07-10 10:40                               ` Grant Likely
  -1 siblings, 0 replies; 58+ messages in thread
From: Grant Likely @ 2011-07-10 10:40 UTC (permalink / raw)
  To: Mark Brown
  Cc: eric.y.miao-Re5JQEeQqe8AvxtiuMwx3w,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Haojian Zhuang,
	samuel.ortiz-ral2JQCrhuEAvxtiuMwx3w,
	linux-lFZ/pmaqli7XmaaqVzeoHQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	alan-VuQAYsv1563Yd54FQh9/CA

On Sun, Jul 10, 2011 at 6:17 PM, Mark Brown
<broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org> wrote:
> On Sun, Jul 10, 2011 at 04:20:27PM +0900, Grant Likely wrote:
>> On Fri, Jul 08, 2011 at 06:20:26PM +0800, Haojian Zhuang wrote:
>
>> > +   if (pdata == NULL)
>> > +           return NULL;
>> > +   pdata->regulator[0] = kzalloc(sizeof(struct regulator_init_data)
>> > +                   * MAX8925_MAX_REGULATOR, GFP_KERNEL);
>
>> ditto.
>
>> Is it appropriate to allocated the entire table of regulators?  From
>> the parse_regulator function above, it looks like only one of the
>> regulators will actually get registered (I've not dug deeply into what
>> the driver needs here though).
>
> If the code/binding doesn't allow the use of all the regulators on the
> device the code is probably wrong, it'd be very unusual to have hardware
> like that.

I was wondering about that.  I was just going by what I could
understand of the code.

g.

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

* [PATCH] mfd: convert devicetree to platform data on max8925
@ 2011-07-10 10:40                               ` Grant Likely
  0 siblings, 0 replies; 58+ messages in thread
From: Grant Likely @ 2011-07-10 10:40 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Jul 10, 2011 at 6:17 PM, Mark Brown
<broonie@opensource.wolfsonmicro.com> wrote:
> On Sun, Jul 10, 2011 at 04:20:27PM +0900, Grant Likely wrote:
>> On Fri, Jul 08, 2011 at 06:20:26PM +0800, Haojian Zhuang wrote:
>
>> > + ? if (pdata == NULL)
>> > + ? ? ? ? ? return NULL;
>> > + ? pdata->regulator[0] = kzalloc(sizeof(struct regulator_init_data)
>> > + ? ? ? ? ? ? ? ? ? * MAX8925_MAX_REGULATOR, GFP_KERNEL);
>
>> ditto.
>
>> Is it appropriate to allocated the entire table of regulators? ?From
>> the parse_regulator function above, it looks like only one of the
>> regulators will actually get registered (I've not dug deeply into what
>> the driver needs here though).
>
> If the code/binding doesn't allow the use of all the regulators on the
> device the code is probably wrong, it'd be very unusual to have hardware
> like that.

I was wondering about that.  I was just going by what I could
understand of the code.

g.

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

* Re: [PATCH] ARM: mmp: remove builtin gpio driver support
  2011-07-10  4:02     ` Grant Likely
@ 2011-07-11  5:05         ` Haojian Zhuang
  -1 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-11  5:05 UTC (permalink / raw)
  To: Grant Likely
  Cc: eric.y.miao-Re5JQEeQqe8AvxtiuMwx3w,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	Haojian Zhuang, samuel.ortiz-ral2JQCrhuEAvxtiuMwx3w,
	linux-lFZ/pmaqli7XmaaqVzeoHQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	alan-VuQAYsv1563Yd54FQh9/CA

On Sat, 2011-07-09 at 21:02 -0700, Grant Likely wrote:
> On Fri, Jul 08, 2011 at 06:20:18PM +0800, Haojian Zhuang wrote:
> > Remove builtin gpio driver support form mmp.
> > 
> > Signed-off-by: Haojian Zhuang <haojian.zhuang-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
> 
> Hi Haojian.
> 
> I'm not clear what this patch is intending to do.  I understand that
> it removes the mmp-specific gpio support, but I looks like don't see the code
> that replaces it, which would mean that applying this patch breaks
> gpio on mmp platforms.
> 
> Am I missing something?
> 
I'm sorry that I shouldn't loop this patch since my new gpio driver
isn't contained in this patch series.

I'm willing to add one operation to select using original gpio driver or
the new one. Since the original gpio driver is shared between ARCH-PXA
and ARCH-mmp. I don't want patch breaking the implementation in
ARCH-PXA.

Thanks
Haojian

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

* [PATCH] ARM: mmp: remove builtin gpio driver support
@ 2011-07-11  5:05         ` Haojian Zhuang
  0 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-11  5:05 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, 2011-07-09 at 21:02 -0700, Grant Likely wrote:
> On Fri, Jul 08, 2011 at 06:20:18PM +0800, Haojian Zhuang wrote:
> > Remove builtin gpio driver support form mmp.
> > 
> > Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
> 
> Hi Haojian.
> 
> I'm not clear what this patch is intending to do.  I understand that
> it removes the mmp-specific gpio support, but I looks like don't see the code
> that replaces it, which would mean that applying this patch breaks
> gpio on mmp platforms.
> 
> Am I missing something?
> 
I'm sorry that I shouldn't loop this patch since my new gpio driver
isn't contained in this patch series.

I'm willing to add one operation to select using original gpio driver or
the new one. Since the original gpio driver is shared between ARCH-PXA
and ARCH-mmp. I don't want patch breaking the implementation in
ARCH-PXA.

Thanks
Haojian

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

* Re: [PATCH] ARM: mmp: add DTS file
  2011-07-10  7:35                           ` Grant Likely
@ 2011-07-11  5:21                             ` Haojian Zhuang
  -1 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-11  5:21 UTC (permalink / raw)
  To: Grant Likely
  Cc: eric.y.miao, nico, devicetree-discuss, broonie, haojian.zhuang,
	Haojian Zhuang, samuel.ortiz, linux, linux-arm-kernel, alan

On Sun, 2011-07-10 at 00:35 -0700, Grant Likely wrote:
> On Fri, Jul 08, 2011 at 06:20:28PM +0800, Haojian Zhuang wrote:
> > Add DTS file to support brownstone & ttc-dkb.
> > 
> > Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
> 
> Hi Haojian.
> 
> Overall, the patch series is moving in the right direction.  I've made
> a lot of comments, but they shouldn't be difficult to resolve.  I look
> forward to seeing the next version of the series.  Comments below...
> 
> > ---
> >  arch/arm/boot/dts/mmp2-brownstone.dts |  319 +++++++++++++++++++++++++++++++++
> >  arch/arm/boot/dts/ttc-dkb.dts         |  176 ++++++++++++++++++
> >  arch/arm/mach-mmp/brownstone.c        |   66 ++-----
> >  arch/arm/mach-mmp/ttc_dkb.c           |   21 ++-
> >  4 files changed, 530 insertions(+), 52 deletions(-)
> >  create mode 100644 arch/arm/boot/dts/mmp2-brownstone.dts
> >  create mode 100644 arch/arm/boot/dts/ttc-dkb.dts
> > 
> > diff --git a/arch/arm/boot/dts/mmp2-brownstone.dts b/arch/arm/boot/dts/mmp2-brownstone.dts
> > new file mode 100644
> > index 0000000..5fdabc3
> > --- /dev/null
> > +++ b/arch/arm/boot/dts/mmp2-brownstone.dts
> > @@ -0,0 +1,319 @@
> > +/dts-v1/;
> > +
> > +/include/ "skeleton.dtsi"
> > +

> > +			interrupt-controller;
> > +			#interrupt-cells = <1>;

> > +			sub-interrupts = <64>;
> 
> What is this for?
> 
Because I need to know how much interrupts could be supported in this
domain? For example, mux4, mux5, ... and supported in mmp2 silicon.
Although they have similar interface, the interrupt numbers are
different in different mux. So I need a property to tell parser that how
much interrupts should be allocated for this interrupt domain.


> > +			gpio-controller;
> > +			reg = <
> > +				0xd4019000 0xb0
> > +				0xd4019004 0xb0
> > +				0xd4019008 0xb0
> > +				0xd4019100 0xb0
> > +				0xd4019104 0xb0
> > +				0xd4019108 0xb0>;
> 
> This looks wrong.  The address ranges overlap.  Why not simply:
> <0xd4019000 0x200>;
> 
These six registers means the start address of six gpio banks. The
registers are overlapped. And internal register of gpio bank are same in
both ARCH-PXA and ARCH-MMP. The only difference is the start register of
each gpio bank.
And there're different gpio numbers in different silicons. If I can
transfer the start gpio address from DTS file, I needn't to hard code
them in gpio driver. If I only write it as <0xd4019000 0x200>, it can't
help driver to understand how much gpio banks existed. Unless I provide
a new property on gpio bank. What's your opinion on this?

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

* [PATCH] ARM: mmp: add DTS file
@ 2011-07-11  5:21                             ` Haojian Zhuang
  0 siblings, 0 replies; 58+ messages in thread
From: Haojian Zhuang @ 2011-07-11  5:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, 2011-07-10 at 00:35 -0700, Grant Likely wrote:
> On Fri, Jul 08, 2011 at 06:20:28PM +0800, Haojian Zhuang wrote:
> > Add DTS file to support brownstone & ttc-dkb.
> > 
> > Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
> 
> Hi Haojian.
> 
> Overall, the patch series is moving in the right direction.  I've made
> a lot of comments, but they shouldn't be difficult to resolve.  I look
> forward to seeing the next version of the series.  Comments below...
> 
> > ---
> >  arch/arm/boot/dts/mmp2-brownstone.dts |  319 +++++++++++++++++++++++++++++++++
> >  arch/arm/boot/dts/ttc-dkb.dts         |  176 ++++++++++++++++++
> >  arch/arm/mach-mmp/brownstone.c        |   66 ++-----
> >  arch/arm/mach-mmp/ttc_dkb.c           |   21 ++-
> >  4 files changed, 530 insertions(+), 52 deletions(-)
> >  create mode 100644 arch/arm/boot/dts/mmp2-brownstone.dts
> >  create mode 100644 arch/arm/boot/dts/ttc-dkb.dts
> > 
> > diff --git a/arch/arm/boot/dts/mmp2-brownstone.dts b/arch/arm/boot/dts/mmp2-brownstone.dts
> > new file mode 100644
> > index 0000000..5fdabc3
> > --- /dev/null
> > +++ b/arch/arm/boot/dts/mmp2-brownstone.dts
> > @@ -0,0 +1,319 @@
> > +/dts-v1/;
> > +
> > +/include/ "skeleton.dtsi"
> > +

> > +			interrupt-controller;
> > +			#interrupt-cells = <1>;

> > +			sub-interrupts = <64>;
> 
> What is this for?
> 
Because I need to know how much interrupts could be supported in this
domain? For example, mux4, mux5, ... and supported in mmp2 silicon.
Although they have similar interface, the interrupt numbers are
different in different mux. So I need a property to tell parser that how
much interrupts should be allocated for this interrupt domain.


> > +			gpio-controller;
> > +			reg = <
> > +				0xd4019000 0xb0
> > +				0xd4019004 0xb0
> > +				0xd4019008 0xb0
> > +				0xd4019100 0xb0
> > +				0xd4019104 0xb0
> > +				0xd4019108 0xb0>;
> 
> This looks wrong.  The address ranges overlap.  Why not simply:
> <0xd4019000 0x200>;
> 
These six registers means the start address of six gpio banks. The
registers are overlapped. And internal register of gpio bank are same in
both ARCH-PXA and ARCH-MMP. The only difference is the start register of
each gpio bank.
And there're different gpio numbers in different silicons. If I can
transfer the start gpio address from DTS file, I needn't to hard code
them in gpio driver. If I only write it as <0xd4019000 0x200>, it can't
help driver to understand how much gpio banks existed. Unless I provide
a new property on gpio bank. What's your opinion on this?

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

* Re: [PATCH] ARM: mmp: remove builtin gpio driver support
  2011-07-11  5:05         ` Haojian Zhuang
@ 2011-07-11 11:44           ` Eric Miao
  -1 siblings, 0 replies; 58+ messages in thread
From: Eric Miao @ 2011-07-11 11:44 UTC (permalink / raw)
  To: Haojian Zhuang
  Cc: Haojian Zhuang, linux, nico, devicetree-discuss, broonie,
	haojian.zhuang, Grant Likely, samuel.ortiz, linux-arm-kernel,
	alan

On Mon, Jul 11, 2011 at 1:05 PM, Haojian Zhuang
<haojian.zhuang@marvell.com> wrote:
> On Sat, 2011-07-09 at 21:02 -0700, Grant Likely wrote:
>> On Fri, Jul 08, 2011 at 06:20:18PM +0800, Haojian Zhuang wrote:
>> > Remove builtin gpio driver support form mmp.
>> >
>> > Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
>>
>> Hi Haojian.
>>
>> I'm not clear what this patch is intending to do.  I understand that
>> it removes the mmp-specific gpio support, but I looks like don't see the code
>> that replaces it, which would mean that applying this patch breaks
>> gpio on mmp platforms.
>>
>> Am I missing something?
>>
> I'm sorry that I shouldn't loop this patch since my new gpio driver
> isn't contained in this patch series.
>
> I'm willing to add one operation to select using original gpio driver or
> the new one. Since the original gpio driver is shared between ARCH-PXA
> and ARCH-mmp. I don't want patch breaking the implementation in
> ARCH-PXA.

The built-in version is used for those timing critical situations. In some
best cases, it can be optimized to only one load/store instruction, which
is extremely useful for those bit-banging operations like I2C/SPI emulation
with GPIO.

>
> Thanks
> Haojian
>
>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH] ARM: mmp: remove builtin gpio driver support
@ 2011-07-11 11:44           ` Eric Miao
  0 siblings, 0 replies; 58+ messages in thread
From: Eric Miao @ 2011-07-11 11:44 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 11, 2011 at 1:05 PM, Haojian Zhuang
<haojian.zhuang@marvell.com> wrote:
> On Sat, 2011-07-09 at 21:02 -0700, Grant Likely wrote:
>> On Fri, Jul 08, 2011 at 06:20:18PM +0800, Haojian Zhuang wrote:
>> > Remove builtin gpio driver support form mmp.
>> >
>> > Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
>>
>> Hi Haojian.
>>
>> I'm not clear what this patch is intending to do. ?I understand that
>> it removes the mmp-specific gpio support, but I looks like don't see the code
>> that replaces it, which would mean that applying this patch breaks
>> gpio on mmp platforms.
>>
>> Am I missing something?
>>
> I'm sorry that I shouldn't loop this patch since my new gpio driver
> isn't contained in this patch series.
>
> I'm willing to add one operation to select using original gpio driver or
> the new one. Since the original gpio driver is shared between ARCH-PXA
> and ARCH-mmp. I don't want patch breaking the implementation in
> ARCH-PXA.

The built-in version is used for those timing critical situations. In some
best cases, it can be optimized to only one load/store instruction, which
is extremely useful for those bit-banging operations like I2C/SPI emulation
with GPIO.

>
> Thanks
> Haojian
>
>

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

end of thread, other threads:[~2011-07-11 11:44 UTC | newest]

Thread overview: 58+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-07-08 10:20 [PATCH] ARM: mmp: remove SPARSE_IRQ for mmp Haojian Zhuang
2011-07-08 10:20 ` Haojian Zhuang
2011-07-08 10:20 ` [PATCH] ARM: mmp: remove builtin gpio driver support Haojian Zhuang
2011-07-08 10:20   ` Haojian Zhuang
2011-07-08 10:20   ` [PATCH] ARM: mmp: parse irq from DT Haojian Zhuang
2011-07-08 10:20     ` Haojian Zhuang
2011-07-08 10:20     ` [PATCH] ARM: mmp: support OF by default Haojian Zhuang
2011-07-08 10:20       ` Haojian Zhuang
2011-07-08 10:20       ` [PATCH] tty: serial: support device tree in pxa Haojian Zhuang
2011-07-08 10:20         ` Haojian Zhuang
2011-07-08 10:20         ` [PATCH] tty: serial: check ops before registering console Haojian Zhuang
2011-07-08 10:20           ` Haojian Zhuang
2011-07-08 10:20           ` [PATCH] i2c: pxa: create dynamic platform device from device tree Haojian Zhuang
2011-07-08 10:20             ` Haojian Zhuang
2011-07-08 10:20             ` [PATCH] of: add devicetree API for regulator Haojian Zhuang
2011-07-08 10:20               ` Haojian Zhuang
2011-07-08 10:20               ` [PATCH] regulator: convert devicetree to platform data on max8649 Haojian Zhuang
2011-07-08 10:20                 ` Haojian Zhuang
2011-07-08 10:20                 ` [PATCH] mfd: convert devicetree to platform data on max8925 Haojian Zhuang
2011-07-08 10:20                   ` Haojian Zhuang
2011-07-08 10:20                   ` [PATCH] mfd: convert devicetree to platform on 88pm860x Haojian Zhuang
2011-07-08 10:20                     ` Haojian Zhuang
2011-07-08 10:20                     ` [PATCH] ARM: mmp: add DTS file Haojian Zhuang
2011-07-08 10:20                       ` Haojian Zhuang
     [not found]                       ` <1310120428-22700-12-git-send-email-haojian.zhuang-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
2011-07-10  7:35                         ` Grant Likely
2011-07-10  7:35                           ` Grant Likely
2011-07-11  5:21                           ` Haojian Zhuang
2011-07-11  5:21                             ` Haojian Zhuang
     [not found]                     ` <1310120428-22700-11-git-send-email-haojian.zhuang-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
2011-07-10  7:21                       ` [PATCH] mfd: convert devicetree to platform on 88pm860x Grant Likely
2011-07-10  7:21                         ` Grant Likely
     [not found]                   ` <1310120428-22700-10-git-send-email-haojian.zhuang-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
2011-07-10  7:20                     ` [PATCH] mfd: convert devicetree to platform data on max8925 Grant Likely
2011-07-10  7:20                       ` Grant Likely
     [not found]                       ` <20110710072027.GE10912-e0URQFbLeQY2iJbIjFUEsiwD8/FfD2ys@public.gmane.org>
2011-07-10  9:17                         ` Mark Brown
2011-07-10  9:17                           ` Mark Brown
     [not found]                           ` <20110710091729.GA23521-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
2011-07-10 10:40                             ` Grant Likely
2011-07-10 10:40                               ` Grant Likely
     [not found]               ` <1310120428-22700-8-git-send-email-haojian.zhuang-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
2011-07-08 14:51                 ` [PATCH] of: add devicetree API for regulator Grant Likely
2011-07-08 14:51                   ` Grant Likely
2011-07-09  1:14                   ` Mark Brown
2011-07-09  1:14                     ` Mark Brown
2011-07-08 18:32               ` Liam Girdwood
2011-07-08 18:32                 ` Liam Girdwood
2011-07-09  2:03               ` Mark Brown
2011-07-09  2:03                 ` Mark Brown
     [not found]             ` <1310120428-22700-7-git-send-email-haojian.zhuang-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
2011-07-10  5:26               ` [PATCH] i2c: pxa: create dynamic platform device from device tree Grant Likely
2011-07-10  5:26                 ` Grant Likely
     [not found]         ` <1310120428-22700-5-git-send-email-haojian.zhuang-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
2011-07-10  5:11           ` [PATCH] tty: serial: support device tree in pxa Grant Likely
2011-07-10  5:11             ` Grant Likely
     [not found]     ` <1310120428-22700-3-git-send-email-haojian.zhuang-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
2011-07-10  4:34       ` [PATCH] ARM: mmp: parse irq from DT Grant Likely
2011-07-10  4:34         ` Grant Likely
2011-07-10  4:02   ` [PATCH] ARM: mmp: remove builtin gpio driver support Grant Likely
2011-07-10  4:02     ` Grant Likely
     [not found]     ` <20110710040218.GA10912-e0URQFbLeQY2iJbIjFUEsiwD8/FfD2ys@public.gmane.org>
2011-07-11  5:05       ` Haojian Zhuang
2011-07-11  5:05         ` Haojian Zhuang
2011-07-11 11:44         ` Eric Miao
2011-07-11 11:44           ` Eric Miao
     [not found] ` <1310120428-22700-1-git-send-email-haojian.zhuang-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
2011-07-08 14:46   ` [PATCH] ARM: mmp: remove SPARSE_IRQ for mmp Grant Likely
2011-07-08 14:46     ` Grant Likely

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.