Skip to contentSkip to conversation

ARM: mmp: remove SPARSE_IRQ for mmp

PATCH New Haojian Zhuang 5 participants 29 messages Jul 8, 2011 – Jul 11, 2011

Subsystems (9)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 ARM: mmp: remove SPARSE_IRQ for mmp

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

---
 arch/arm/Kconfig |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)
arch/arm/Kconfig +0 -1
index 17507b8..48748fb 100644
@@ -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.
 
Signature · 1 line
1.5.6.5
#1 lore raw

PATCH 1/1 ARM: mmp: remove builtin gpio driver support

Remove builtin gpio driver support form mmp.

---
 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(-)
arch/arm/mach-mmp/include/mach/gpio.h +3 -24
index 7bfb827..829f165 100644
@@ -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 */
arch/arm/mach-mmp/mmp2.c +0 -17
index 8e6c3ac..d3f9b3b 100644
@@ -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)
arch/arm/mach-mmp/pxa168.c +0 -17
index 72b4e76..4f41ea2 100644
@@ -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 */
arch/arm/mach-mmp/pxa910.c +0 -17
index 8f92ccd..e71a45a 100644
@@ -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 */
arch/arm/plat-pxa/Makefile +2 -0
index 3aca5ba..8e432b1 100644
@@ -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
Signature · 1 line
1.5.6.5
#2 lore raw

PATCH 1/1 ARM: mmp: parse irq from DT

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

---
 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
arch/arm/mach-mmp/Makefile +2 -0
index 5c68382..e7862ea 100644
@@ -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
arch/arm/mach-mmp/common.h +1 -0
index ec8d65d..1c563c2 100644
@@ -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);
arch/arm/mach-mmp/intc.c new file +245 -0

245 lines not on this page · raw message

Signature · 1 line
1.5.6.5
#3 lore raw

PATCH 1/1 ARM: mmp: support OF by default

Support open firmware by default.

---
 arch/arm/Kconfig |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
arch/arm/Kconfig +1 -0
index 48748fb..7b083a0 100644
@@ -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.
 
Signature · 1 line
1.5.6.5
#4 lore raw

PATCH 1/1 tty: serial: support device tree in pxa

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

---
 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
drivers/tty/serial/Kconfig +3 -1
index 636144c..3f75e0d 100644
@@ -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.
drivers/tty/serial/of_serial.c +12 -0
index e65f1e8..383bff3 100644
@@ -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 */ },
 };
drivers/tty/serial/pxa.c +78 -13

152 lines not on this page · raw message

include/linux/serial_pxa.h new file +17 -0
new file mode 100644
index 0000000..565e510
@@ -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
Signature · 1 line
1.5.6.5
#5 lore raw

PATCH 1/1 tty: serial: check ops before registering console

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

---
 drivers/tty/serial/pxa.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/tty/serial/pxa.c +1 -1
index fb80fb3..b117fab 100644
@@ -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)
Signature · 1 line
1.5.6.5
#6 lore raw

PATCH 1/1 i2c: pxa: create dynamic platform device from device tree

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.

---
 drivers/i2c/busses/i2c-pxa.c |  163 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 163 insertions(+), 0 deletions(-)
drivers/i2c/busses/i2c-pxa.c +163 -0
index d603646..7a6d774 100644
@@ -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,
 };
Signature · 1 line
1.5.6.5
#7 lore raw

PATCH 1/1 of: add devicetree API for regulator

---
 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
drivers/of/Kconfig +4 -0
index d06a637..edb6601 100644
@@ -75,4 +75,8 @@ config OF_PCI
 	help
 	  OpenFirmware PCI bus accessors
 
+config OF_REGULATOR
+	def_tristate REGULATOR
+	depends on REGULATOR
+
 endmenu # OF
drivers/of/Makefile +1 -0
index f7861ed..83ca06f 100644
@@ -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
drivers/of/of_regulator.c new file +166 -0

166 lines not on this page · raw message

include/linux/of_regulator.h new file +34 -0
new file mode 100644
index 0000000..0155bd8
@@ -0,0 +1,34 @@
+/*
+ * Generic Regulator API implementation
+ *
+ * Copyright (c) 2011 Haojian Zhuang <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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 */
Signature · 1 line
1.5.6.5
#8 lore raw

PATCH 1/1 regulator: convert devicetree to platform data on max8649

---
 drivers/regulator/max8649.c |   70 +++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 70 insertions(+), 0 deletions(-)
drivers/regulator/max8649.c +70 -0
index 30eb9e5..4316a37 100644
@@ -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:
Signature · 1 line
1.5.6.5
#9 lore raw

PATCH 1/1 mfd: convert devicetree to platform data on max8925

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

---
 drivers/mfd/max8925-i2c.c |  159 ++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 157 insertions(+), 2 deletions(-)
drivers/mfd/max8925-i2c.c +157 -2
index 0219115..fb74554 100644
@@ -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);
Signature · 1 line
1.5.6.5
#10 lore raw

PATCH 1/1 mfd: convert devicetree to platform on 88pm860x

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

---
 drivers/mfd/88pm860x-i2c.c |  191 +++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 189 insertions(+), 2 deletions(-)
drivers/mfd/88pm860x-i2c.c +189 -2
index e017dc8..b017e4a 100644
@@ -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);
Signature · 1 line
1.5.6.5
#11 lore raw

PATCH 1/1 ARM: mmp: add DTS file

Add DTS file to support brownstone & ttc-dkb.

---
 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
arch/arm/boot/dts/mmp2-brownstone.dts new file +319 -0
new file mode 100644
index 0000000..5fdabc3
@@ -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>;
+		};
+	};
+};
arch/arm/boot/dts/ttc-dkb.dts new file +176 -0

176 lines not on this page · raw message

arch/arm/mach-mmp/brownstone.c +18 -48

101 lines not on this page · raw message

arch/arm/mach-mmp/ttc_dkb.c +17 -4
index e411039..c19b4dc 100644
@@ -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
Signature · 1 line
1.5.6.5
#12 lore raw

PATCH 1/1 ARM: mmp: add DTS file

Quoted 3 lines · Haojian Zhuang

Add DTS file to support brownstone & ttc-dkb.

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...

Quoted 15 lines
---
 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
arch/arm/boot/dts/mmp2-brownstone.dts new file +0 -0
new file mode 100644
index 0000000..5fdabc3

arch/arm/boot/dts/mmp2-brownstone.dts line 7

Quoted 7 lines
arch/arm/boot/dts/mmp2-brownstone.dts new file +7 -0
@@ -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.

Quoted 4 lines
arch/arm/boot/dts/mmp2-brownstone.dts new file +4 -0
+	interrupt-parent = <&mmp_intc>;
+
+	memory {
+		reg = <0x00000000 0x20000000>;

arch/arm/boot/dts/mmp2-brownstone.dts line 21

Quoted 10 lines
arch/arm/boot/dts/mmp2-brownstone.dts new file +10 -0
+	};
+
+	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.

arch/arm/boot/dts/mmp2-brownstone.dts line 28

Quoted 7 lines
arch/arm/boot/dts/mmp2-brownstone.dts new file +7 -0
+		#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. :-)

arch/arm/boot/dts/mmp2-brownstone.dts line 34

Quoted 6 lines
arch/arm/boot/dts/mmp2-brownstone.dts new file +6 -0
+			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.

arch/arm/boot/dts/mmp2-brownstone.dts line 35

Quoted 1 line
arch/arm/boot/dts/mmp2-brownstone.dts new file +1 -0
+			interrupt-parent = <&mmp_intc>;

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

arch/arm/boot/dts/mmp2-brownstone.dts line 36

Quoted 1 line
arch/arm/boot/dts/mmp2-brownstone.dts new file +1 -0
+			sub-interrupts = <64>;

What is this for?

arch/arm/boot/dts/mmp2-brownstone.dts line 39

Quoted 3 lines
arch/arm/boot/dts/mmp2-brownstone.dts new file +3 -0
+
+			/* enable bits in conf register */
+			enable_mask = <0x20>;

Convention is to not use underscore '_' in property names. Use a dash '-' instead.

arch/arm/boot/dts/mmp2-brownstone.dts line 52

Quoted 13 lines
arch/arm/boot/dts/mmp2-brownstone.dts new file +13 -0
+
+			/* 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.

Quoted 6 lines
arch/arm/boot/dts/mmp2-brownstone.dts new file +6 -0
+			sub-interrupts = <2>;
+			reg = <0xd4282150 0>;
+			status-mask = <0x150 0x168>;
+			/* mfp register & interrupt index */
+			mfp-edge-interrupt = <0xd401e2c4 1>;
+		};

[...]

arch/arm/boot/dts/mmp2-brownstone.dts

Quoted 2 lines
arch/arm/boot/dts/mmp2-brownstone.dts new file +2 -0
+		gpio: gpio-controller {
+			compatible = "pxa,gpio";

mrvl,pxa255-gpio, or similar.

arch/arm/boot/dts/mmp2-brownstone.dts line 147

Quoted 8 lines
arch/arm/boot/dts/mmp2-brownstone.dts new file +8 -0
+			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>;

Quoted 19 lines
arch/arm/boot/dts/mmp2-brownstone.dts new file +19 -0
+
+			/* 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>;
+		};

[...]

Quoted 98 lines
arch/arm/mach-mmp/brownstone.c +16 -46
index 7bb78fd..c9848ad 100644
@@ -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,
+};
+

arch/arm/mach-mmp/brownstone.c static struct platform_device brownstone_v_5vp_device = { · line 174

Quoted 10 lines
arch/arm/mach-mmp/brownstone.c +2 -2
 MACHINE_START(BROWNSTONE, "Brownstone Development Platform")
 	/* Maintainer: Haojian Zhuang <[email protected]> */
 	.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.

Quoted 53 lines
arch/arm/mach-mmp/ttc_dkb.c +17 -4
index e411039..c19b4dc 100644
@@ -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
Signature · 1 line
1.5.6.5
#13 lore raw

PATCH 1/1 ARM: mmp: add DTS file

Quoted 31 lines · Grant Likely
Quoted 3 lines · Haojian Zhuang

Add DTS file to support brownstone & ttc-dkb.

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...

Quoted 19 lines
---
 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
arch/arm/boot/dts/mmp2-brownstone.dts new file +4 -0
new file mode 100644
index 0000000..5fdabc3
@@ -0,0 +1,319 @@
+/dts-v1/;
+
+/include/ "skeleton.dtsi"
+
Quoted 7 lines

arch/arm/boot/dts/mmp2-brownstone.dts line 36

Quoted 4 lines
arch/arm/boot/dts/mmp2-brownstone.dts new file +3 -0
+			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.

Quoted 12 lines

arch/arm/boot/dts/mmp2-brownstone.dts line 147

Quoted 8 lines
arch/arm/boot/dts/mmp2-brownstone.dts new file +8 -0
+			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?

#14 lore raw

PATCH 1/1 mfd: convert devicetree to platform on 88pm860x

In reply to Haojian Zhuang
Quoted 156 lines · Haojian Zhuang

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

---
 drivers/mfd/88pm860x-i2c.c |  191 +++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 189 insertions(+), 2 deletions(-)
drivers/mfd/88pm860x-i2c.c +133 -0
index e017dc8..b017e4a 100644
@@ -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)

drivers/mfd/88pm860x-i2c.c static const struct i2c_device_id pm860x_id_table[] = { · line 381

Quoted 10 lines
drivers/mfd/88pm860x-i2c.c +10 -0
+		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.

Quoted 45 lines
drivers/mfd/88pm860x-i2c.c +40 -0
+
+	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;

drivers/mfd/88pm860x-i2c.c static int __devinit pm860x_probe(struct i2c_client *client, · line 455

Quoted 10 lines
drivers/mfd/88pm860x-i2c.c +6 -2
 
 	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.

Quoted 6 lines
drivers/mfd/88pm860x-i2c.c +0 -0
 	}
 
 	chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL);
Signature · 1 line
1.5.6.5
#15 lore raw

PATCH 1/1 mfd: convert devicetree to platform data on max8925

In reply to Haojian Zhuang
Quoted 24 lines · Haojian Zhuang

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

---
 drivers/mfd/max8925-i2c.c |  159 ++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 157 insertions(+), 2 deletions(-)
drivers/mfd/max8925-i2c.c +3 -0
index 0219115..fb74554 100644
@@ -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[] = {
 };

drivers/mfd/max8925-i2c.c static const struct i2c_device_id max8925_id_table[] = { · line 148

Quoted 10 lines
drivers/mfd/max8925-i2c.c +8 -0
 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);
Quoted 12 lines
drivers/mfd/max8925-i2c.c +12 -0
+	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;

drivers/mfd/max8925-i2c.c static const struct i2c_device_id max8925_id_table[] = { · line 170

Quoted 10 lines
drivers/mfd/max8925-i2c.c +10 -0
+	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.

Quoted 8 lines
drivers/mfd/max8925-i2c.c +8 -0
+}
+
+static void __devinit max8925_parse_touch(struct device_node *np,
+					struct max8925_platform_data *pdata)
+{
+	struct max8925_touch_pdata *touch;
+	const __be32 *p;
+

drivers/mfd/max8925-i2c.c static const struct i2c_device_id max8925_id_table[] = { · line 188

Quoted 10 lines
drivers/mfd/max8925-i2c.c +10 -0
+	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.

Quoted 11 lines
drivers/mfd/max8925-i2c.c +11 -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;

drivers/mfd/max8925-i2c.c static const struct i2c_device_id max8925_id_table[] = { · line 209

Quoted 10 lines
drivers/mfd/max8925-i2c.c +10 -0
+	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.

Quoted 11 lines
drivers/mfd/max8925-i2c.c +11 -0
+}
+
+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;

drivers/mfd/max8925-i2c.c static const struct i2c_device_id max8925_id_table[] = { · line 230

Quoted 10 lines
drivers/mfd/max8925-i2c.c +10 -0
+	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.

drivers/mfd/max8925-i2c.c static const struct i2c_device_id max8925_id_table[] = { · line 243

Quoted 13 lines
drivers/mfd/max8925-i2c.c +13 -0
+	}
+}
+
+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)

drivers/mfd/max8925-i2c.c static const struct i2c_device_id max8925_id_table[] = { · line 247

Quoted 4 lines
drivers/mfd/max8925-i2c.c +4 -0
+	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).

Quoted 46 lines
drivers/mfd/max8925-i2c.c +41 -0
+	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;

drivers/mfd/max8925-i2c.c static int __devinit max8925_probe(struct i2c_client *client, · line 301

Quoted 10 lines
drivers/mfd/max8925-i2c.c +6 -2
 
 	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.

Quoted 6 lines
drivers/mfd/max8925-i2c.c +0 -0
 	}
 
 	chip = kzalloc(sizeof(struct max8925_chip), GFP_KERNEL);
Signature · 1 line
1.5.6.5
#16 lore raw

PATCH 1/1 mfd: convert devicetree to platform data on max8925

Quoted 9 lines · Grant Likely

drivers/mfd/max8925-i2c.c static const struct i2c_device_id max8925_id_table[] = { · line 247

Quoted 4 lines · Haojian Zhuang
drivers/mfd/max8925-i2c.c +4 -0
+	if (pdata == NULL)
+		return NULL;
+	pdata->regulator[0] = kzalloc(sizeof(struct regulator_init_data)
+			* MAX8925_MAX_REGULATOR, GFP_KERNEL);

ditto.

Quoted 4 lines

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.

#17 lore raw

PATCH 1/1 mfd: convert devicetree to platform data on max8925

Quoted 10 lines · Mark Brown
Quoted 8 lines · Grant Likely
Quoted 4 lines · Haojian Zhuang

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

ditto.

Quoted 8 lines
Quoted 4 lines

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.

#18 lore raw

PATCH 1/1 of: add devicetree API for regulator

In reply to Haojian Zhuang

Hi Haojian,

Quoted 1 line · Haojian Zhuang

No commit description?

Quoted 60 lines

---

?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

drivers/of/Kconfig +0 -0
index d06a637..edb6601 100644
@@ -75,4 +75,8 @@ config OF_PCI

? ? ? ?help
? ? ? ? ?OpenFirmware PCI bus accessors

drivers/of/Kconfig +4 -0
+config OF_REGULATOR
+ ? ? ? def_tristate REGULATOR
+ ? ? ? depends on REGULATOR
+

?endmenu # OF

drivers/of/Makefile +0 -0
index f7861ed..83ca06f 100644
@@ -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

drivers/of/Makefile +1 -0
+obj-$(CONFIG_OF_REGULATOR) ? ? += of_regulator.o
drivers/of/of_regulator.c new file +23 -0
new file mode 100644
index 0000000..d523302
@@ -0,0 +1,166 @@
+/*
+ * OF helpers for the Regulator API
+ *
+ * Copyright (c) 2011 Haojian Zhuang <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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",

drivers/of/of_regulator.c line 33

Quoted 10 lines
drivers/of/of_regulator.c new file +10 -0
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "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

Quoted 66 lines
drivers/of/of_regulator.c new file +66 -0
+ ? ? ? 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);

drivers/of/of_regulator.c line 109

Quoted 10 lines
drivers/of/of_regulator.c new file +10 -0
+ ? ? ? 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.

Quoted 101 lines
drivers/of/of_regulator.c new file +57 -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);
+}
include/linux/of_regulator.h new file +34 -1
new file mode 100644
index 0000000..0155bd8
@@ -0,0 +1,34 @@
+/*
+ * Generic Regulator API implementation
+ *
+ * Copyright (c) 2011 Haojian Zhuang <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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

Signature · 2 lines
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
#19 lore raw

PATCH 1/1 of: add devicetree API for regulator

Quoted 7 lines · Grant Likely

Hi Haojian,

Quoted 1 line · Haojian Zhuang

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.

#20 lore raw

PATCH 1/1 of: add devicetree API for regulator

In reply to Haojian Zhuang
Quoted 87 lines · Haojian Zhuang
---
 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
drivers/of/Kconfig +4 -0
index d06a637..edb6601 100644
@@ -75,4 +75,8 @@ config OF_PCI
 	help
 	  OpenFirmware PCI bus accessors
 
+config OF_REGULATOR
+	def_tristate REGULATOR
+	depends on REGULATOR
+
 endmenu # OF
drivers/of/Makefile +1 -0
index f7861ed..83ca06f 100644
@@ -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
drivers/of/of_regulator.c new file +49 -0
new file mode 100644
index 0000000..d523302
@@ -0,0 +1,166 @@
+/*
+ * OF helpers for the Regulator API
+ *
+ * Copyright (c) 2011 Haojian Zhuang <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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;

drivers/of/of_regulator.c line 59

Quoted 10 lines
drivers/of/of_regulator.c new file +10 -0
+				/* 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

#21 lore raw

PATCH 1/1 of: add devicetree API for regulator

In reply to Haojian Zhuang
Quoted 1 line · Haojian Zhuang

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.

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

Why is this in drivers/of?

drivers/of/of_regulator.c line 29

Quoted 1 line
drivers/of/of_regulator.c new file +1 -0
+	p = of_get_property(of_dev, "voltages", &size);

voltage_range would probably be better.

drivers/of/of_regulator.c line 33

Quoted 4 lines
drivers/of/of_regulator.c new file +4 -0
+	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.

drivers/of/of_regulator.c line 41

Quoted 3 lines
drivers/of/of_regulator.c new file +3 -0
+	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.

Quoted 8 lines
drivers/of/of_regulator.c new file +8 -0
+	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;

drivers/of/of_regulator.c line 59

Quoted 10 lines
drivers/of/of_regulator.c new file +10 -0
+				/* 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.

Quoted 7 lines
drivers/of/of_regulator.c new file +7 -0
+	supply = kzalloc(sizeof(struct regulator_consumer_supply) * count,
+		GFP_KERNEL);
+	if (supply == NULL)
+		return -EINVAL;
+	str = p;
+	calc_size = size;
+	i = 0;

drivers/of/of_regulator.c line 158

Quoted 10 lines
drivers/of/of_regulator.c new file +10 -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.

include/linux/of_regulator.h line 20

Quoted 3 lines
include/linux/of_regulator.h new file +3 -0
+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.

#22 lore raw

PATCH 1/1 i2c: pxa: create dynamic platform device from device tree

In reply to Haojian Zhuang
Quoted 24 lines · 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.

---
 drivers/i2c/busses/i2c-pxa.c |  163 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 163 insertions(+), 0 deletions(-)
drivers/i2c/busses/i2c-pxa.c +1 -0
index d603646..7a6d774 100644
@@ -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>

drivers/i2c/busses/i2c-pxa.c static const struct i2c_algorithm i2c_pxa_pio_algorithm = { · line 1051

Quoted 7 lines
drivers/i2c/busses/i2c-pxa.c +4 -0
@@ -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".

drivers/i2c/busses/i2c-pxa.c static const struct i2c_algorithm i2c_pxa_pio_algorithm = { · line 1057

Quoted 6 lines
drivers/i2c/busses/i2c-pxa.c +6 -0
+	{},
+};
+
+#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.

Quoted 7 lines
drivers/i2c/busses/i2c-pxa.c +7 -0
+	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;

drivers/i2c/busses/i2c-pxa.c static const struct i2c_algorithm i2c_pxa_pio_algorithm = { · line 1074

Quoted 10 lines
drivers/i2c/busses/i2c-pxa.c +10 -0
+	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.

Quoted 8 lines
drivers/i2c/busses/i2c-pxa.c +8 -0
+
+	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;

drivers/i2c/busses/i2c-pxa.c static const struct i2c_algorithm i2c_pxa_pio_algorithm = { · line 1092

Quoted 10 lines
drivers/i2c/busses/i2c-pxa.c +10 -0
+
+	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)

Quoted 143 lines
drivers/i2c/busses/i2c-pxa.c +117 -0
+	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,
 };
Signature · 1 line
1.5.6.5
#23 lore raw

PATCH 1/1 tty: serial: support device tree in pxa

In reply to Haojian Zhuang
Quoted 70 lines · Haojian Zhuang

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

---
 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
drivers/tty/serial/Kconfig +3 -1
index 636144c..3f75e0d 100644
@@ -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.
drivers/tty/serial/of_serial.c +11 -0
index e65f1e8..383bff3 100644
@@ -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;

drivers/tty/serial/of_serial.c static struct of_device_id __devinitdata of_platform_serial_table[] = { · line 200

Quoted 4 lines
drivers/tty/serial/of_serial.c +1 -0
@@ -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.

Quoted 21 lines
drivers/tty/serial/of_serial.c +0 -0
 	{ .type = "serial",         .data = (void *)PORT_UNKNOWN, },
 	{ /* end of list */ },
 };
drivers/tty/serial/pxa.c +2 -0
index 4302e6e..fb80fb3 100644
@@ -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>

drivers/tty/serial/pxa.c struct uart_pxa_port { · line 56

Quoted 5 lines
drivers/tty/serial/pxa.c +1 -1
@@ -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?

Quoted 20 lines
drivers/tty/serial/pxa.c +5 -2
+	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
 	 */

drivers/tty/serial/pxa.c serial_pxa_type(struct uart_port *port) · line 601

Quoted 5 lines
drivers/tty/serial/pxa.c +1 -1
@@ -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?

Quoted 143 lines
drivers/tty/serial/pxa.c +69 -9
 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);
 
include/linux/serial_pxa.h new file +17 -0
new file mode 100644
index 0000000..565e510
@@ -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
Signature · 1 line
1.5.6.5
#24 lore raw

PATCH 1/1 ARM: mmp: parse irq from DT

In reply to Haojian Zhuang
Quoted 123 lines · Haojian Zhuang

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

---
 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
arch/arm/mach-mmp/Makefile +2 -0
index 5c68382..e7862ea 100644
@@ -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
arch/arm/mach-mmp/common.h +1 -0
index ec8d65d..1c563c2 100644
@@ -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);
arch/arm/mach-mmp/intc.c new file +85 -0
new file mode 100644
index 0000000..48ad84b
@@ -0,0 +1,245 @@
+/*
+ *  linux/arch/arm/mach-mmp/intc.c
+ *
+ *  Generic IRQ handling
+ *
+ *  Author:	Haojian Zhuang <[email protected]>
+ *  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;

arch/arm/mach-mmp/intc.c line 95

Quoted 10 lines
arch/arm/mach-mmp/intc.c new file +10 -0
+	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()

arch/arm/mach-mmp/intc.c line 104

Quoted 9 lines
arch/arm/mach-mmp/intc.c new file +9 -0
+		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.

arch/arm/mach-mmp/intc.c line 112

Quoted 8 lines
arch/arm/mach-mmp/intc.c new file +8 -0
+		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);

Quoted 24 lines
arch/arm/mach-mmp/intc.c new file +24 -0
+		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,

arch/arm/mach-mmp/intc.c line 146

Quoted 10 lines
arch/arm/mach-mmp/intc.c new file +10 -0
+					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.

Quoted 12 lines
arch/arm/mach-mmp/intc.c new file +12 -0
+
+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);

arch/arm/mach-mmp/intc.c line 168

Quoted 10 lines
arch/arm/mach-mmp/intc.c new file +10 -0
+
+	__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?

Quoted 31 lines
arch/arm/mach-mmp/intc.c new file +31 -0
+
+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;

arch/arm/mach-mmp/intc.c line 209

Quoted 10 lines
arch/arm/mach-mmp/intc.c new file +10 -0
+	}
+	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().

Quoted 10 lines
arch/arm/mach-mmp/intc.c new file +10 -0
+
+	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;

arch/arm/mach-mmp/intc.c line 229

Quoted 10 lines
arch/arm/mach-mmp/intc.c new file +10 -0
+	}
+	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.

Quoted 6 lines
arch/arm/mach-mmp/intc.c new file +6 -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);

arch/arm/mach-mmp/intc.c line 245

Quoted 10 lines
arch/arm/mach-mmp/intc.c new file +10 -0
+	}
+	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.

#25 lore raw

PATCH 1/1 ARM: mmp: remove builtin gpio driver support

In reply to Haojian Zhuang
Quoted 3 lines · Haojian Zhuang

Remove builtin gpio driver support form mmp.

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?

arch/arm/plat-pxa/Makefile line 9

Quoted 11 lines
arch/arm/plat-pxa/Makefile +2 -0
index 3aca5ba..8e432b1 100644
@@ -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.

#26 lore raw

PATCH 1/1 ARM: mmp: remove builtin gpio driver support

Quoted 5 lines · Grant Likely
Quoted 3 lines · Haojian Zhuang

Remove builtin gpio driver support form mmp.

Quoted 9 lines

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

#27 lore raw

PATCH 1/1 ARM: mmp: remove builtin gpio driver support

Quoted 15 lines · Haojian Zhuang
Quoted 5 lines · Grant Likely
Quoted 3 lines · Haojian Zhuang

Remove builtin gpio driver support form mmp.

Quoted 9 lines

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?

Quoted 7 lines

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.

Quoted 5 lines

Thanks
Haojian

#28 lore raw

PATCH 1/1 ARM: mmp: remove SPARSE_IRQ for mmp

In reply to Haojian Zhuang
Quoted 4 lines · Haojian Zhuang

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

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

g.

Quoted 20 lines

---
?arch/arm/Kconfig | ? ?1 -
?1 files changed, 0 insertions(+), 1 deletions(-)

arch/arm/Kconfig +0 -0
index 17507b8..48748fb 100644
@@ -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

Signature · 2 lines
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.