Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] drivers: bus: omap_interconnect: Fix rand-config build warning
From: Tony Lindgren @ 2012-10-31 23:26 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <508E29E9.7020809@ti.com>

* Lokesh Vutla <lokeshvutla@ti.com> [121029 00:03]:
> Is the above discussion fine for you ?
> Will you pick this patch or
> you want any more modifications ?

Let's see what Arnd says.

Regards,

Tony

^ permalink raw reply

* [PATCH 07/11] ARM: OMAP: Move omap-pm-noop.c local to mach-omap2
From: Tony Lindgren @ 2012-10-31 23:11 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1654531.W5JISgHidu@avalon>

* Laurent Pinchart <laurent.pinchart@ideasonboard.com> [121031 16:03]:
> Hi Tony,
> 
> On Wednesday 31 October 2012 13:58:50 Tony Lindgren wrote:
> > * Tony Lindgren <tony@atomide.com> [121030 16:55]:
> > > This code should be private to mach-omap2.
> > > 
> > > The only use for it in for omap1 has been in dmtimer.c
> > > to check for context loss. However, omap1 does not
> > > lose context during idle, so the code is not needed.
> > > Further, omap1 timer has OMAP_TIMER_ALWON set, so omap1
> > > was not hitting omap_pm_get_dev_context_loss_count()
> > > test.
> > 
> > Noticed one issue with my test compiles in the
> > omap-for-v3.8/cleanup-headers branch that can be
> > fixed along with this patch.
> > 
> > --- a/drivers/media/platform/omap3isp/ispvideo.c
> > +++ b/drivers/media/platform/omap3isp/ispvideo.c
> > @@ -36,7 +36,6 @@
> >  #include <media/v4l2-ioctl.h>
> >  #include <plat/iommu.h>
> >  #include <plat/iovmm.h>
> > -#include <plat/omap-pm.h>
> 
> The reason this was included was to call omap_pm_set_min_bus_tput() in earlier 
> versions of the driver. We'll have to discuss what to replace that with, but 
> that's another topic.

OK thanks.

> > > @@ -730,6 +732,7 @@ static int __devinit omap_dm_timer_probe(struct
> > > platform_device *pdev)> 
> > >  	timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
> > >  	timer->pdev = pdev;
> > >  	timer->capability = pdata->timer_capability;
> > > 
> > > +	timer->get_context_loss_count = pdata->get_context_loss_count;
> > > 
> > >  	/* Skip pm_runtime_enable for OMAP1 */
> > >  	if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
> > > 
> > > diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h
> > > b/arch/arm/plat-omap/include/plat/dmtimer.h index 85868e9..3f5b9cf 100644
> > > --- a/arch/arm/plat-omap/include/plat/dmtimer.h
> > > +++ b/arch/arm/plat-omap/include/plat/dmtimer.h
> > > @@ -94,6 +94,7 @@ struct dmtimer_platform_data {
> > > 
> > >  	/* set_timer_src - Only used for OMAP1 devices */
> > >  	int (*set_timer_src)(struct platform_device *pdev, int source);
> > >  	u32 timer_capability;
> > > 
> > > +	int (*get_context_loss_count)(struct device *);
> 
> That's a step forward for the common zImage, but one step backward for DT 
> support :-) I'm fine with this for now, but do you already have an idea on how 
> to solve that ?

When it's converted to be a device driver, it can do it
using runtime PM calls.

Regards,

Tony

^ permalink raw reply

* [PATCH v3 9/9] pinctrl: single: dump pinmux register value
From: Haojian Zhuang @ 2012-10-31 23:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1351724661-29050-1-git-send-email-haojian.zhuang@gmail.com>

Dump pinmux register value, not only function part in the pinmux
register.

Also fix the issue on caluclating pin offset. The last parameter
should be pin number, not register offset.

Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
 drivers/pinctrl/pinctrl-single.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 3b97b65..72017e7 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -283,15 +283,15 @@ static int pcs_get_group_pins(struct pinctrl_dev *pctldev,
 
 static void pcs_pin_dbg_show(struct pinctrl_dev *pctldev,
 					struct seq_file *s,
-					unsigned offset)
+					unsigned pin)
 {
 	struct pcs_device *pcs;
-	unsigned val;
+	unsigned val, mux_bytes;
 
 	pcs = pinctrl_dev_get_drvdata(pctldev);
 
-	val = pcs->read(pcs->base + offset);
-	val &= pcs->fmask;
+	mux_bytes = pcs->width / BITS_PER_BYTE;
+	val = pcs->read(pcs->base + pin * mux_bytes);
 
 	seq_printf(s, "%08x %s " , val, DRIVER_NAME);
 }
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH v3 8/9] i2c: pxa: configure pinmux
From: Haojian Zhuang @ 2012-10-31 23:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1351724661-29050-1-git-send-email-haojian.zhuang@gmail.com>

Configure pins by pinctrl driver.

Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
Cc: Ben Dooks <ben-linux@fluff.org>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
---
 drivers/i2c/busses/i2c-pxa.c |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 7c8b5d0..11e4a30 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -32,6 +32,7 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_i2c.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/err.h>
 #include <linux/clk.h>
@@ -1051,6 +1052,7 @@ static int i2c_pxa_probe_dt(struct platform_device *pdev, struct pxa_i2c *i2c,
 			    enum pxa_i2c_types *i2c_types)
 {
 	struct device_node *np = pdev->dev.of_node;
+	struct pinctrl *pinctrl;
 	const struct of_device_id *of_id =
 			of_match_device(i2c_pxa_dt_ids, &pdev->dev);
 	int ret;
@@ -1063,6 +1065,9 @@ static int i2c_pxa_probe_dt(struct platform_device *pdev, struct pxa_i2c *i2c,
 		return ret;
 	}
 	pdev->id = ret;
+	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+	if (IS_ERR(pinctrl))
+		return -EPROBE_DEFER;
 	if (of_get_property(np, "mrvl,i2c-polling", NULL))
 		i2c->use_pio = 1;
 	if (of_get_property(np, "mrvl,i2c-fast-mode", NULL))
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH v3 7/9] i2c: pxa: use devm_kzalloc
From: Haojian Zhuang @ 2012-10-31 23:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1351724661-29050-1-git-send-email-haojian.zhuang@gmail.com>

Use devm_kzalloc & add checking in probe() function.

Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
Cc: Ben Dooks <ben-linux@fluff.org>
---
 drivers/i2c/busses/i2c-pxa.c |   26 ++++++++++----------------
 1 file changed, 10 insertions(+), 16 deletions(-)

diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 1034d93..7c8b5d0 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -1078,6 +1078,8 @@ static int i2c_pxa_probe_pdata(struct platform_device *pdev,
 	struct i2c_pxa_platform_data *plat = pdev->dev.platform_data;
 	const struct platform_device_id *id = platform_get_device_id(pdev);
 
+	if (!id)
+		return -EINVAL;
 	*i2c_types = id->driver_data;
 	if (plat) {
 		i2c->use_pio = plat->use_pio;
@@ -1094,29 +1096,23 @@ static int i2c_pxa_probe(struct platform_device *dev)
 	struct resource *res = NULL;
 	int ret, irq;
 
-	i2c = kzalloc(sizeof(struct pxa_i2c), GFP_KERNEL);
-	if (!i2c) {
-		ret = -ENOMEM;
-		goto emalloc;
-	}
+	i2c = devm_kzalloc(&dev->dev, sizeof(struct pxa_i2c), GFP_KERNEL);
+	if (!i2c)
+		return -ENOMEM;
 
 	ret = i2c_pxa_probe_dt(dev, i2c, &i2c_type);
 	if (ret > 0)
 		ret = i2c_pxa_probe_pdata(dev, i2c, &i2c_type);
 	if (ret < 0)
-		goto eclk;
+		return ret;
 
 	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
 	irq = platform_get_irq(dev, 0);
-	if (res == NULL || irq < 0) {
-		ret = -ENODEV;
-		goto eclk;
-	}
+	if (res == NULL || irq < 0)
+		return -ENODEV;
 
-	if (!request_mem_region(res->start, resource_size(res), res->name)) {
-		ret = -ENOMEM;
-		goto eclk;
-	}
+	if (!request_mem_region(res->start, resource_size(res), res->name))
+		return -ENOMEM;
 
 	i2c->adap.owner   = THIS_MODULE;
 	i2c->adap.retries = 5;
@@ -1209,8 +1205,6 @@ ereqirq:
 eremap:
 	clk_put(i2c->clk);
 eclk:
-	kfree(i2c);
-emalloc:
 	release_mem_region(res->start, resource_size(res));
 	return ret;
 }
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH v3 6/9] tty: pxa: configure pin
From: Haojian Zhuang @ 2012-10-31 23:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1351724661-29050-1-git-send-email-haojian.zhuang@gmail.com>

Configure pins by pinctrl driver.

Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
---
 drivers/tty/serial/pxa.c |    8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index 9033fc6..02dc771 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -37,6 +37,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/of.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
@@ -809,6 +810,7 @@ static int serial_pxa_probe_dt(struct platform_device *pdev,
 			       struct uart_pxa_port *sport)
 {
 	struct device_node *np = pdev->dev.of_node;
+	struct pinctrl *pinctrl;
 	int ret;
 
 	if (!np)
@@ -819,6 +821,10 @@ static int serial_pxa_probe_dt(struct platform_device *pdev,
 		dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
 		return ret;
 	}
+	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+	if (IS_ERR(pinctrl))
+		return -EPROBE_DEFER;
+
 	sport->port.line = ret;
 	return 0;
 }
@@ -857,7 +863,7 @@ static int serial_pxa_probe(struct platform_device *dev)
 	ret = serial_pxa_probe_dt(dev, sport);
 	if (ret > 0)
 		sport->port.line = dev->id;
-	else if (ret < 0)
+	if (ret < 0)
 		goto err_clk;
 	snprintf(sport->name, PXA_NAME_LEN - 1, "UART%d", sport->port.line + 1);
 
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH v3 5/9] document: devicetree: bind pinconf with pin-single
From: Haojian Zhuang @ 2012-10-31 23:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1351724661-29050-1-git-send-email-haojian.zhuang@gmail.com>

Add comments with pinconf & gpio range in the document of
pinctrl-single.

Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
 .../devicetree/bindings/pinctrl/pinctrl-single.txt |   66 ++++++++++++++++++++
 1 file changed, 66 insertions(+)

diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
index 2c81e45..15f4dae 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
@@ -17,6 +17,41 @@ Optional properties:
 - pinctrl-single,bit-per-mux : boolean to indicate that one register controls
   more than one pin
 
+- pinctrl-single,gpio-ranges : gpio range list of phandles.
+  Must be present if gpio range phandle is specified.
+  This property should be existing in .dtsi files for those silicons.
+
+- pinctrl-single,gpio : array with gpio range start, size & register
+  offset. Must be present if gpio range phandle is specified.
+  This property should be existing in .dts files for those boards.
+
+- pinctrl-single,gpio-func : gpio function value in the pinmux register.
+  Must be present if gpio range phandle is specified.
+  This property should be existing in .dts files for those boards.
+
+- pinctrl-single,power-source-mask : mask of setting power source in
+  the pinmux register
+
+- pinctrl-single,power-source : value of setting power source field
+  in the pinmux register
+
+- pinctrl-single,bias-mask : mask of setting bias value in the pinmux
+  register
+
+- pinctrl-single,bias-disable : value of disabling bias in the pinmux
+  register
+
+- pinctrl-single,bias-pull-down : value of setting bias pull down in
+  the pinmux register
+
+- pinctrl-single,bias-pull-up : value of setting bias pull up in the
+  pinmux register
+
+- pinctrl-single,bias : value of setting bias in the pinmux register
+
+- pinctrl-single,input-schmitt-mask : mask of setting input schmitt
+  in the pinmux register
+
 This driver assumes that there is only one register for each pin (unless the
 pinctrl-single,bit-per-mux is set), and uses the common pinctrl bindings as
 specified in the pinctrl-bindings.txt document in this directory.
@@ -42,6 +77,15 @@ Where 0xdc is the offset from the pinctrl register base address for the
 device pinctrl register, 0x18 is the desired value, and 0xff is the sub mask to
 be used when applying this change to the register.
 
+In case pinctrl device supports gpio function, it needs to define gpio range.
+All the phandles of gpio range list should be set in below:
+
+	pinctrl-single,gpio-ranges = <[phandle of gpio range]>;
+
+	[phandle of gpio range]: {
+		pinctrl-single,gpio = <0 55 0x0dc>;
+		pinctrl-single,gpio-func = <0>;
+	};
 Example:
 
 /* SoC common file */
@@ -76,6 +120,28 @@ control_devconf0: pinmux at 48002274 {
 	pinctrl-single,function-mask = <0x5F>;
 };
 
+/* third controller instance for pins in gpio domain */
+pmx_gpio: pinmux at d401e000 {
+	compatible = "pinctrl-single";
+	reg = <0xd401e000 0x0330>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	pinctrl-single,register-width = <32>;
+	pinctrl-single,function-mask = <7>;
+	pinctrl-single,gpio-ranges = <&gpiorange0 &gpiorange1>;
+};
+
+gpiorange0: gpiorange at d401e0dc {
+	pinctrl-single,gpio = <0 55 0x0dc>;
+	pinctrl-single,gpio-func = <0>;
+};
+
+gpiorange1: gpiorange at d401e2f0 {
+	pinctrl-single,gpio = <55 5 0x2f0>;
+	pinctrl-single,gpio-func = <1>;
+};
+
+
 /* board specific .dts file */
 
 &pmx_core {
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH v3 4/9] ARM: dts: support pinctrl single in pxa910
From: Haojian Zhuang @ 2012-10-31 23:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1351724661-29050-1-git-send-email-haojian.zhuang@gmail.com>

Add pinctrl-single support with device tree in pxa910 dkb platform.

Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
 arch/arm/boot/dts/pxa910-dkb.dts |  187 +++++++++++++++++++++++++++++++++++++-
 arch/arm/boot/dts/pxa910.dtsi    |   77 ++++++++++++++++
 2 files changed, 263 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/pxa910-dkb.dts b/arch/arm/boot/dts/pxa910-dkb.dts
index 595492a..394396a 100644
--- a/arch/arm/boot/dts/pxa910-dkb.dts
+++ b/arch/arm/boot/dts/pxa910-dkb.dts
@@ -24,10 +24,195 @@
 
 	soc {
 		apb at d4000000 {
-			uart1: uart at d4017000 {
+			pmx: pinmux at d401e000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&board_pins>;
+
+				board_pins: pinmux_board_pins {
+					/* pins not owned by device driver */
+				};
+				uart1_pins: pinmux_uart1_pins {
+					pinctrl-single,pins = <
+						0x198 0x6	/* GPIO47_UART1_RXD */
+						0x19c 0x6	/* GPIO48_UART1_TXD */
+					>;
+					pinctrl-single,power-source = <0x2>;
+					pinctrl-single,bias = <0x6>;
+				};
+				uart2_pins: pinmux_uart2_pins {
+					pinctrl-single,pins = <
+						0x150 0x4	/* GPIO29_UART2_CTS */
+						0x154 0x4	/* GPIO30_UART2_RTS */
+						0x158 0x4	/* GPIO31_UART2_TXD */
+						0x15c 0x4	/* GPIO32_UART2_RXD */
+					>;
+					pinctrl-single,power-source = <0x2>;
+					pinctrl-single,bias = <0>;
+				};
+				uart3_pins: pinmux_uart3_pins {
+					pinctrl-single,pins = <
+						0x188 0x7	/* GPIO43_UART3_RXD */
+						0x18c 0x7	/* GPIO44_UART3_TXD */
+					>;
+					pinctrl-single,power-source = <0x2>;
+					pinctrl-single,bias = <0>;
+				};
+				twsi1_pins: pinmux_twsi1_pins {
+					pinctrl-single,pins = <
+						0x1b0 0x2	/* GPIO53_TWSI_SCL */
+						0x1b4 0x2	/* GPIO54_TWSI_SDA */
+					>;
+					pinctrl-single,power-source = <0x2>;
+					pinctrl-single,bias = <0>;
+				};
+				nand_pins: pinmux_nand_pins {
+					pinctrl-single,pins = <
+						0x040 0x0	/* ND_IO0 */
+						0x03c 0x0	/* ND_IO1 */
+						0x038 0x0	/* ND_IO2 */
+						0x034 0x0	/* ND_IO3 */
+						0x030 0x0	/* ND_IO4 */
+						0x02c 0x0	/* ND_IO5 */
+						0x028 0x0	/* ND_IO6 */
+						0x024 0x0	/* ND_IO7 */
+						0x020 0x0	/* ND_IO8 */
+						0x01c 0x0	/* ND_IO9 */
+						0x018 0x0	/* ND_IO10 */
+						0x014 0x0	/* ND_IO11 */
+						0x010 0x0	/* ND_IO12 */
+						0x00c 0x0	/* ND_IO13 */
+						0x008 0x0	/* ND_IO14 */
+						0x004 0x0	/* ND_IO15 */
+						0x044 0x0	/* ND_nCS0 */
+						0x060 0x1	/* ND_ALE */
+						0x05c 0x0	/* ND_CLE */
+						0x054 0x1	/* ND_nWE */
+						0x058 0x1	/* ND_nRE */
+						0x068 0x0	/* ND_RDY0 */
+					>;
+					pinctrl-single,power-source = <0x2>;
+					pinctrl-single,bias = <0>;
+				};
+				mmc1_ldata_pins: pinmux_mmc1_ldata_pins {
+					pinctrl-single,pins = <
+						0x0a0 0x0	/* MMC1_DATA0 */
+						0x09c 0x0	/* MMC1_DATA1 */
+						0x098 0x0	/* MMC1_DATA2 */
+						0x094 0x0	/* MMC1_DATA3 */
+					>;
+					pinctrl-single,power-source = <0x3>;
+					pinctrl-single,bias = <0>;
+				};
+				mmc1_hdata_pins: pinmux_mmc1_hdata_pins {
+					pinctrl-single,pins = <
+						0x090 0x0	/* MMC1_DATA4 */
+						0x08c 0x0	/* MMC1_DATA5 */
+						0x088 0x0	/* MMC1_DATA6 */
+						0x084 0x0	/* MMC1_DATA7 */
+					>;
+					pinctrl-single,power-source = <0x2>;
+					pinctrl-single,bias = <0>;
+				};
+				mmc1_clk_pins: pinmux_mmc1_clk_pins {
+					pinctrl-single,pins = <
+						0x0a4 0x0	/* MMC1_CMD */
+						0x0a8 0x0	/* MMC1_CLK */
+					>;
+					pinctrl-single,power-source = <0x3>;
+					pinctrl-single,bias = <0>;
+				};
+				mmc1_cd_pins: pinmux_mmc1_cd_pins {
+					pinctrl-single,pins = <
+						0x0ac 0x0	/* MMC1_CD */
+						0x0b0 0x0	/* MMC1_WP */
+					>;
+					pinctrl-single,power-source = <0x2>;
+					pinctrl-single,bias = <0>;
+				};
+				mmc2_pins: pinmux_mmc2_pins {
+					pinctrl-single,pins = <
+						0x180 0x1	/* MMC2_CMD */
+						0x184 0x1	/* MMC2_CLK */
+						0x17c 0x1	/* MMC2_DATA0 */
+						0x178 0x1	/* MMC2_DATA1 */
+						0x174 0x1	/* MMC2_DATA2 */
+						0x170 0x1	/* MMC2_DATA3 */
+					>;
+					pinctrl-single,power-source = <0x2>;
+					pinctrl-single,bias = <0>;
+				};
+				w1_pins: pinmux_w1_pins {
+					pinctrl-single,pins = <
+						0x0cc 0x2	/* CLK_REQ_W1 */
+					>;
+					pinctrl-single,power-source = <0x2>;
+					pinctrl-single,bias = <0>;
+				};
+				ssp1_pins: pinmux_ssp1_pins {
+					pinctrl-single,pins = <
+						0x130 0x1	/* GPIO21_SSP1_SCLK */
+						0x134 0x1	/* GPIO22_SSP1_FRM */
+						0x138 0x1	/* GPIO23_SSP1_TXD */
+						0x13c 0x1	/* GPIO24_SSP1_RXD */
+					>;
+					pinctrl-single,power-source = <0x2>;
+					pinctrl-single,bias = <0>;
+				};
+				keypad_pins: pinmux_keypad_pins {
+					pinctrl-single,pins = <
+						0x0dc 0x1	/* GPIO0_MKIN0 */
+						0x0e0 0x1	/* GPIO1_MKOUT0 */
+						0x0e4 0x1	/* GPIO2_MKIN1 */
+						0x0e8 0x1	/* GPIO3_MKOUT1 */
+						0x0ec 0x1	/* GPIO4_MKIN2 */
+						0x0f0 0x1	/* GPIO5_MKOUT2 */
+						0x0f4 0x1	/* GPIO6_MKIN3 */
+						0x0f8 0x1	/* GPIO7_MKOUT3 */
+						0x0fc 0x1	/* GPIO8_MKIN4 */
+						0x100 0x1	/* GPIO9_MKOUT4 */
+						0x10c 0x1	/* GPIO12_MKIN6 */
+					>;
+					pinctrl-single,power-source = <0x2>;
+					pinctrl-single,bias = <0>;
+				};
+				nfc_pins: pinmux_nfc_pins {
+					pinctrl-single,pins = <
+						0x120 0x0	/* GPIO17 */
+					>;
+					pinctrl-single,power-source = <0x2>;
+					pinctrl-single,bias = <0>;
+				};
+				wlan_pins: pinmux_wlan_pins {
+					pinctrl-single,pins = <
+						0x114 0x0	/* GPIO14 */
+						0x12c 0x0	/* GPIO20 */
+						0x160 0x0	/* GPIO33 */
+						0x164 0x0	/* GPIO34 */
+						0x168 0x0	/* GPIO35 */
+						0x16c 0x0	/* GPIO36 */
+					>;
+					pinctrl-single,power-source = <0x2>;
+					pinctrl-single,bias = <0>;
+				};
+			};
+			uart1: uart at d4017000 {	/* FFUART */
+				pinctrl-names = "default";
+				pinctrl-0 = <&uart1_pins>;
+				status = "okay";
+			};
+			uart2: uart at d4018000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&uart2_pins>;
+				status = "okay";
+			};
+			uart3: uart at d4036000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&uart3_pins>;
 				status = "okay";
 			};
 			twsi1: i2c at d4011000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&twsi1_pins>;
 				status = "okay";
 
 				pmic: 88pm860x at 34 {
diff --git a/arch/arm/boot/dts/pxa910.dtsi b/arch/arm/boot/dts/pxa910.dtsi
index 825aaca..a11a582 100644
--- a/arch/arm/boot/dts/pxa910.dtsi
+++ b/arch/arm/boot/dts/pxa910.dtsi
@@ -54,6 +54,83 @@
 			reg = <0xd4000000 0x00200000>;
 			ranges;
 
+			pmx: pinmux at d401e000 {
+				compatible = "pinctrl-single";
+				reg = <0xd401e000 0x0330>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				pinctrl-single,register-width = <32>;
+				pinctrl-single,function-mask = <7>;
+				pinctrl-single,gpio-ranges = <&gpiorange0 &gpiorange1
+								&gpiorange2 &gpiorange3
+								&gpiorange4 &gpiorange5
+								&gpiorange6 &gpiorange7
+								&gpiorange8 &gpiorange9
+								&gpiorange10>;
+				pinctrl-single,power-source-mask = <0x1800>;
+				pinctrl-single,bias-mask = <0xe000>;
+				pinctrl-single,bias-disable = <0>;
+				pinctrl-single,bias-pull-down = <0xa000>;
+				pinctrl-single,bias-pull-up = <0xc000>;
+				pinctrl-single,input-schmitt-mask = <0x70>;
+
+				gpiorange0: gpiorange at d401e0dc {
+					/* GPIO0 ~ GPIO54 */
+					pinctrl-single,gpio = <0 55 0x0dc>;
+					pinctrl-single,gpio-func = <0>;
+				};
+				gpiorange1: gpiorange at d401e2f0 {
+					/* GPIO55 ~ GPIO59 */
+					pinctrl-single,gpio = <55 5 0x2f0>;
+					pinctrl-single,gpio-func = <1>;
+				};
+				gpiorange2: gpiorange at d401e304 {
+					/* GPIO60 ~ GPIO66 */
+					pinctrl-single,gpio = <60 7 0x304>;
+					pinctrl-single,gpio-func = <0>;
+				};
+				gpiorange3: gpiorange at d401e1b8 {
+					/* GPIO67 ~ GPIO109 */
+					pinctrl-single,gpio = <67 43 0x1b8>;
+					pinctrl-single,gpio-func = <0>;
+				};
+				gpiorange4: gpiorange at d401e298 {
+					/* GPIO110 ~ GPIO116 */
+					pinctrl-single,gpio = <110 7 0x298>;
+					pinctrl-single,gpio-func = <0>;
+				};
+				gpiorange5: gpiorange at d401e0b4 {
+					/* GPIO117 ~ GPIO120 */
+					pinctrl-single,gpio = <117 4 0x0b4>;
+					pinctrl-single,gpio-func = <1>;
+				};
+				gpiorange6: gpiorange at d401e32c {
+					/* GPIO121 */
+					pinctrl-single,gpio = <121 1 0x32c>;
+					pinctrl-single,gpio-func = <0>;
+				};
+				gpiorange7: gpiorange at d401e0c8 {
+					/* GPIO122 ~ GPIO123 */
+					pinctrl-single,gpio = <122 2 0x0c8>;
+					pinctrl-single,gpio-func = <1>;
+				};
+				gpiorange8: gpiorange at d401e0d0 {
+					/* GPIO124 */
+					pinctrl-single,gpio = <124 1 0x0d0>;
+					pinctrl-single,gpio-func = <0>;
+				};
+				gpiorange9: gpiorange at d401e0d4 {
+					/* GPIO125 */
+					pinctrl-single,gpio = <125 1 0x0d4>;
+					pinctrl-single,gpio-func = <1>;
+				};
+				gpiorange10: gpiorange at d401e06c {
+					/* GPIO126 ~ GPIO127 */
+					pinctrl-single,gpio = <126 2 0x06c>;
+					pinctrl-single,gpio-func = <0>;
+				};
+			};
+
 			timer0: timer at d4014000 {
 				compatible = "mrvl,mmp-timer";
 				reg = <0xd4014000 0x100>;
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH v3 3/9] pinctrl: single: support pinconf generic
From: Haojian Zhuang @ 2012-10-31 23:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1351724661-29050-1-git-send-email-haojian.zhuang@gmail.com>

Add pinconf generic support with POWER SOURCE, BIAS PULL.

Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
 drivers/pinctrl/Kconfig          |    1 +
 drivers/pinctrl/pinctrl-single.c |  276 ++++++++++++++++++++++++++++++++++++--
 2 files changed, 266 insertions(+), 11 deletions(-)

diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 7bf914d..e9f2d2d 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -139,6 +139,7 @@ config PINCTRL_SINGLE
 	depends on OF
 	select PINMUX
 	select PINCONF
+	select GENERIC_PINCONF
 	help
 	  This selects the device tree based generic pinctrl driver.
 
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index a7c5fdd..3b97b65 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -20,6 +20,7 @@
 #include <linux/of_device.h>
 #include <linux/of_address.h>
 
+#include <linux/pinctrl/pinconf-generic.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/pinmux.h>
 
@@ -28,6 +29,9 @@
 #define DRIVER_NAME			"pinctrl-single"
 #define PCS_MUX_PINS_NAME		"pinctrl-single,pins"
 #define PCS_MUX_BITS_NAME		"pinctrl-single,bits"
+#define PCS_BIAS_NAME			"pinctrl-single,bias"
+#define PCS_POWER_SOURCE_NAME		"pinctrl-single,power-source"
+#define PCS_SCHMITT_NAME		"pinctrl-single,input-schmitt"
 #define PCS_REG_NAME_LEN		((sizeof(unsigned long) * 2) + 1)
 #define PCS_OFF_DISABLED		~0U
 #define PCS_MAX_GPIO_VALUES		3
@@ -130,6 +134,15 @@ struct pcs_name {
  * @fshift:	function register shift
  * @foff:	value to turn mux off
  * @fmax:	max number of functions in fmask
+ * @bmask:	bias mask in pinconf
+ * @bshift:	bias register shift
+ * @bdis:	bias disable value in pinconf
+ * @bpullup:	bias pull up value in pinconf
+ * @bpulldown:	bias pull down value in pinconf
+ * @ismask:	input schmitt mask in pinconf
+ * @isshift:	input schmitt register shift
+ * @psmask:	power source mask in pinconf
+ * @psshift:	power source register shift
  * @names:	array of register names for pins
  * @pins:	physical pins on the SoC
  * @pgtree:	pingroup index radix tree
@@ -156,6 +169,15 @@ struct pcs_device {
 	unsigned fshift;
 	unsigned foff;
 	unsigned fmax;
+	unsigned bmask;
+	unsigned bshift;
+	unsigned bdis;
+	unsigned bpullup;
+	unsigned bpulldown;
+	unsigned ismask;
+	unsigned isshift;
+	unsigned psmask;
+	unsigned psshift;
 	bool bits_per_mux;
 	struct pcs_name *names;
 	struct pcs_data pins;
@@ -452,28 +474,163 @@ static struct pinmux_ops pcs_pinmux_ops = {
 	.gpio_request_enable = pcs_request_gpio,
 };
 
+static void pcs_free_pingroups(struct pcs_device *pcs);
+
 static int pcs_pinconf_get(struct pinctrl_dev *pctldev,
 				unsigned pin, unsigned long *config)
 {
+	struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+	enum pin_config_param param = pinconf_to_config_param(*config);
+	unsigned data;
+	u32 offset;
+
+	offset = pin * (pcs->width / BITS_PER_BYTE);
+	data = pcs->read(pcs->base + offset);
+
+	switch (param) {
+	case PIN_CONFIG_POWER_SOURCE:
+		if (pcs->psmask == PCS_OFF_DISABLED
+			|| pcs->psshift == PCS_OFF_DISABLED)
+			return -ENOTSUPP;
+		data &= pcs->psmask;
+		data = data >> pcs->psshift;
+		*config = data;
+		return 0;
+		break;
+	case PIN_CONFIG_BIAS_DISABLE:
+		if (pcs->bmask == PCS_OFF_DISABLED
+			|| pcs->bshift == PCS_OFF_DISABLED
+			|| pcs->bdis == PCS_OFF_DISABLED)
+			return -ENOTSUPP;
+		data &= pcs->bmask;
+		*config = 0;
+		if (data == pcs->bdis)
+			return 0;
+		else
+			return -EINVAL;
+		break;
+	case PIN_CONFIG_BIAS_PULL_UP:
+		if (pcs->bmask == PCS_OFF_DISABLED
+			|| pcs->bshift == PCS_OFF_DISABLED
+			|| pcs->bpullup == PCS_OFF_DISABLED)
+			return -ENOTSUPP;
+		data &= pcs->bmask;
+		*config = 0;
+		if (data == pcs->bpullup)
+			return 0;
+		else
+			return -EINVAL;
+		break;
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		if (pcs->bmask == PCS_OFF_DISABLED
+			|| pcs->bshift == PCS_OFF_DISABLED
+			|| pcs->bpulldown == PCS_OFF_DISABLED)
+			return -ENOTSUPP;
+		data &= pcs->bmask;
+		*config = 0;
+		if (data == pcs->bpulldown)
+			return 0;
+		else
+			return -EINVAL;
+		break;
+	default:
+		break;
+	}
 	return -ENOTSUPP;
 }
 
 static int pcs_pinconf_set(struct pinctrl_dev *pctldev,
 				unsigned pin, unsigned long config)
 {
-	return -ENOTSUPP;
+	struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+	enum pin_config_param config_param = pinconf_to_config_param(config);
+	unsigned ret, mask = ~0UL;
+	u32 offset, data;
+
+	switch (config_param) {
+	case PIN_CONFIG_POWER_SOURCE:
+		if (pcs->psmask == PCS_OFF_DISABLED
+			|| pcs->psshift == PCS_OFF_DISABLED)
+			return 0;
+		mask = pcs->psmask;
+		data = (pinconf_to_config_argument(config) << pcs->psshift)
+			& pcs->psmask;
+		break;
+	case PIN_CONFIG_BIAS_DISABLE:
+		if (pcs->bmask == PCS_OFF_DISABLED
+			|| pcs->bshift == PCS_OFF_DISABLED)
+			return 0;
+		mask = pcs->bmask;
+		data = (pinconf_to_config_argument(config) << pcs->bshift)
+			& pcs->bmask;
+		break;
+	default:
+		return 0;
+	}
+	offset = pin * (pcs->width / BITS_PER_BYTE);
+	ret = pcs->read(pcs->base + offset) & ~mask;
+	pcs->write(ret | data, pcs->base + offset);
+	return 0;
 }
 
 static int pcs_pinconf_group_get(struct pinctrl_dev *pctldev,
 				unsigned group, unsigned long *config)
 {
-	return -ENOTSUPP;
+	struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+	struct pcs_pingroup *pins;
+
+	pins = radix_tree_lookup(&pcs->pgtree, group);
+	if (!pins) {
+		dev_err(pcs->dev, "%s could not find pingroup%i\n",
+			__func__, group);
+		return -EINVAL;
+	}
+	return pcs_pinconf_get(pctldev, pins->gpins[0], config);
 }
 
 static int pcs_pinconf_group_set(struct pinctrl_dev *pctldev,
 				unsigned group, unsigned long config)
 {
-	return -ENOTSUPP;
+	struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+	enum pin_config_param config_param = pinconf_to_config_param(config);
+	struct pcs_pingroup *pins;
+	u32 offset, data;
+	unsigned ret, mask = ~0UL;
+	int i;
+
+	switch (config_param) {
+	case PIN_CONFIG_POWER_SOURCE:
+		if (pcs->psmask == PCS_OFF_DISABLED
+			|| pcs->psshift == PCS_OFF_DISABLED)
+			return 0;
+		mask = pcs->psmask;
+		data = (pinconf_to_config_argument(config) << pcs->psshift)
+			& pcs->psmask;
+		break;
+	case PIN_CONFIG_BIAS_DISABLE:
+		if (pcs->bmask == PCS_OFF_DISABLED
+			|| pcs->bshift == PCS_OFF_DISABLED)
+			return 0;
+		mask = pcs->bmask;
+		data = (pinconf_to_config_argument(config) << pcs->bshift)
+			& pcs->bmask;
+		break;
+	default:
+		return 0;
+	}
+
+	pins = radix_tree_lookup(&pcs->pgtree, group);
+	if (!pins) {
+		dev_err(pcs->dev, "%s could not find pingroup%i\n",
+			__func__, group);
+		return -EINVAL;
+	}
+	for (i = 0; i < pins->ngpins; i++) {
+		offset = pins->gpins[i] * (pcs->width / BITS_PER_BYTE);
+		ret = pcs->read(pcs->base + offset) & ~mask;
+		pcs->write(ret | data, pcs->base + offset);
+	}
+	return 0;
 }
 
 static void pcs_pinconf_dbg_show(struct pinctrl_dev *pctldev,
@@ -487,6 +644,7 @@ static void pcs_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
 }
 
 static struct pinconf_ops pcs_pinconf_ops = {
+	.is_generic = true,
 	.pin_config_get = pcs_pinconf_get,
 	.pin_config_set = pcs_pinconf_set,
 	.pin_config_group_get = pcs_pinconf_group_get,
@@ -688,6 +846,7 @@ static int pcs_get_pin_by_offset(struct pcs_device *pcs, unsigned offset)
  * @pcs: pinctrl driver instance
  * @np: device node of the mux entry
  * @map: map entry
+ * @num_configs: number of pin configurations
  * @pgnames: pingroup names
  *
  * Note that this binding currently supports only sets of one register + value.
@@ -704,12 +863,16 @@ static int pcs_get_pin_by_offset(struct pcs_device *pcs, unsigned offset)
 static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
 						struct device_node *np,
 						struct pinctrl_map **map,
+						unsigned num_configs,
 						const char **pgnames)
 {
 	struct pcs_func_vals *vals;
+	struct pinctrl_map *p = *map;
 	const __be32 *mux;
 	int size, params, rows, *pins, index = 0, found = 0, res = -ENOMEM;
 	struct pcs_function *function;
+	unsigned long *config;
+	u32 value;
 
 	if (pcs->bits_per_mux) {
 		params = 3;
@@ -772,12 +935,42 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
 	if (res < 0)
 		goto free_function;
 
-	(*map)->type = PIN_MAP_TYPE_MUX_GROUP;
-	(*map)->data.mux.group = np->name;
-	(*map)->data.mux.function = np->name;
+	p->type = PIN_MAP_TYPE_MUX_GROUP;
+	p->data.mux.group = np->name;
+	p->data.mux.function = np->name;
+
+	if (!num_configs)
+		return 0;
+	config = devm_kzalloc(pcs->dev, sizeof(*config) * num_configs,
+			      GFP_KERNEL);
+	if (!config) {
+		res = -ENOMEM;
+		goto free_pingroup;
+	}
+	index = 0;
+	if (!of_property_read_u32(np, PCS_SCHMITT_NAME, &value))
+		config[index++] =
+			pinconf_to_config_packed(PIN_CONFIG_INPUT_SCHMITT,
+						 value & 0xffff);
+	if (!of_property_read_u32(np, PCS_BIAS_NAME, &value))
+		config[index++] =
+			pinconf_to_config_packed(PIN_CONFIG_BIAS_DISABLE,
+						 value & 0xffff);
+	if (!of_property_read_u32(np, PCS_POWER_SOURCE_NAME, &value))
+		config[index++] =
+			pinconf_to_config_packed(PIN_CONFIG_POWER_SOURCE,
+						 value & 0xffff);
+	p++;
+	p->type = PIN_MAP_TYPE_CONFIGS_GROUP;
+	p->data.configs.group_or_pin = np->name;
+	p->data.configs.configs = config;
+	p->data.configs.num_configs = num_configs;
 
 	return 0;
 
+free_pingroup:
+	pcs_free_pingroups(pcs);
+
 free_function:
 	pcs_remove_function(pcs, function);
 
@@ -789,6 +982,30 @@ free_vals:
 
 	return res;
 }
+
+static int pcs_dt_check_maps(struct device_node *np, unsigned *num_maps,
+			     unsigned *num_configs)
+{
+	unsigned size;
+
+	*num_maps = 0;
+	*num_configs = 0;
+	if (of_get_property(np, PCS_MUX_PINS_NAME, &size)
+		|| of_get_property(np, PCS_MUX_BITS_NAME, &size))
+		(*num_maps)++;
+	if (of_get_property(np, PCS_SCHMITT_NAME, &size))
+		(*num_configs)++;
+	if (of_get_property(np, PCS_BIAS_NAME, &size))
+		(*num_configs)++;
+	if (of_get_property(np, PCS_POWER_SOURCE_NAME, &size))
+		(*num_configs)++;
+	if (*num_configs)
+		(*num_maps)++;
+	if (!(*num_maps))
+		return -EINVAL;
+	return 0;
+}
+
 /**
  * pcs_dt_node_to_map() - allocates and parses pinctrl maps
  * @pctldev: pinctrl instance
@@ -802,29 +1019,32 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev,
 {
 	struct pcs_device *pcs;
 	const char **pgnames;
+	unsigned num_configs;
 	int ret;
 
 	pcs = pinctrl_dev_get_drvdata(pctldev);
 
-	*map = devm_kzalloc(pcs->dev, sizeof(**map), GFP_KERNEL);
+	ret = pcs_dt_check_maps(np_config, num_maps, &num_configs);
+	if (ret)
+		return ret;
+
+	*map = devm_kzalloc(pcs->dev, sizeof(**map) * (*num_maps), GFP_KERNEL);
 	if (!map)
 		return -ENOMEM;
 
-	*num_maps = 0;
-
 	pgnames = devm_kzalloc(pcs->dev, sizeof(*pgnames), GFP_KERNEL);
 	if (!pgnames) {
 		ret = -ENOMEM;
 		goto free_map;
 	}
 
-	ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map, pgnames);
+	ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map,
+					  num_configs, pgnames);
 	if (ret < 0) {
 		dev_err(pcs->dev, "no pins entries for %s\n",
 			np_config->name);
 		goto free_pgnames;
 	}
-	*num_maps = 1;
 
 	return 0;
 
@@ -1009,6 +1229,40 @@ static int __devinit pcs_probe(struct platform_device *pdev)
 	pcs->bits_per_mux = of_property_read_bool(np,
 						  "pinctrl-single,bit-per-mux");
 
+	ret = of_property_read_u32(np, "pinctrl-single,power-source-mask",
+					&pcs->psmask);
+	if (ret) {
+		pcs->psmask = PCS_OFF_DISABLED;
+		pcs->psshift = PCS_OFF_DISABLED;
+	} else
+		pcs->psshift = ffs(pcs->psmask) - 1;
+	ret = of_property_read_u32(np, "pinctrl-single,bias-mask",
+					&pcs->bmask);
+	if (ret) {
+		pcs->bmask = PCS_OFF_DISABLED;
+		pcs->bshift = PCS_OFF_DISABLED;
+	} else
+		pcs->bshift = ffs(pcs->bmask) - 1;
+	ret = of_property_read_u32(np, "pinctrl-single,bias-disable",
+					&pcs->bdis);
+	if (ret)
+		pcs->bdis = PCS_OFF_DISABLED;
+	ret = of_property_read_u32(np, "pinctrl-single,bias-pull-up",
+					&pcs->bpullup);
+	if (ret)
+		pcs->bpullup = PCS_OFF_DISABLED;
+	ret = of_property_read_u32(np, "pinctrl-single,bias-pull-down",
+					&pcs->bpulldown);
+	if (ret)
+		pcs->bpulldown = PCS_OFF_DISABLED;
+	ret = of_property_read_u32(np, "pinctrl-single,input-schmitt-mask",
+					&pcs->ismask);
+	if (ret) {
+		pcs->ismask = PCS_OFF_DISABLED;
+		pcs->isshift = PCS_OFF_DISABLED;
+	} else
+		pcs->isshift = ffs(pcs->ismask) - 1;
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
 		dev_err(pcs->dev, "could not get resource\n");
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH v3 2/9] pinctrl: single: support gpio request and free
From: Haojian Zhuang @ 2012-10-31 23:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1351724661-29050-1-git-send-email-haojian.zhuang@gmail.com>

Marvell's PXA/MMP silicon also match the behavior of pinctrl-single.
Each pin binds to one register. A lot of pins could be configured
as gpio.

Now add these properties in below.
<gpio range phandle>:
	include "pinctrl-single,gpio" & "pinctrl,gpio-func" properties.

	pinctrl-single,gpio: <gpio base, npins in range, register offset>

	pinctrl-single,gpio-func: <gpio function value in mux>

pinctrl-single,gpio-ranges: phandle list of gpio range array

Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
 drivers/pinctrl/pinctrl-single.c |  100 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 98 insertions(+), 2 deletions(-)

diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 726a729..a7c5fdd 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -30,6 +30,7 @@
 #define PCS_MUX_BITS_NAME		"pinctrl-single,bits"
 #define PCS_REG_NAME_LEN		((sizeof(unsigned long) * 2) + 1)
 #define PCS_OFF_DISABLED		~0U
+#define PCS_MAX_GPIO_VALUES		3
 
 /**
  * struct pcs_pingroup - pingroups for a function
@@ -77,6 +78,18 @@ struct pcs_function {
 };
 
 /**
+ * struct pcs_gpio_range - pinctrl gpio range
+ * @range:	subrange of the GPIO number space
+ * @gpio_func:	gpio function value in the pinmux register
+ * @func_en:	need to handle gpio function in the pinmux register
+ */
+struct pcs_gpio_range {
+	struct pinctrl_gpio_range range;
+	int gpio_func;
+	unsigned func_en:1;
+};
+
+/**
  * struct pcs_data - wrapper for data needed by pinctrl framework
  * @pa:		pindesc array
  * @cur:	index to current element
@@ -123,8 +136,10 @@ struct pcs_name {
  * @ftree:	function index radix tree
  * @pingroups:	list of pingroups
  * @functions:	list of functions
+ * @ranges:	list of gpio ranges
  * @ngroups:	number of pingroups
  * @nfuncs:	number of functions
+ * @nranges:	number of gpio ranges
  * @desc:	pin controller descriptor
  * @read:	register read function to use
  * @write:	register write function to use
@@ -148,8 +163,10 @@ struct pcs_device {
 	struct radix_tree_root ftree;
 	struct list_head pingroups;
 	struct list_head functions;
+	struct list_head ranges;
 	unsigned ngroups;
 	unsigned nfuncs;
+	unsigned nranges;
 	struct pinctrl_desc desc;
 	unsigned (*read)(void __iomem *reg);
 	void (*write)(unsigned val, void __iomem *reg);
@@ -403,9 +420,27 @@ static void pcs_disable(struct pinctrl_dev *pctldev, unsigned fselector,
 }
 
 static int pcs_request_gpio(struct pinctrl_dev *pctldev,
-			struct pinctrl_gpio_range *range, unsigned offset)
+			    struct pinctrl_gpio_range *range, unsigned pin)
 {
-	return -ENOTSUPP;
+	struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+	struct pcs_gpio_range *gpio = NULL;
+	int end, mux_bytes;
+	unsigned data;
+
+	gpio = container_of(range, struct pcs_gpio_range, range);
+	if (!gpio->func_en)
+		return -ENOTSUPP;
+	end = range->pin_base + range->npins - 1;
+	if (pin < range->pin_base || pin > end) {
+		dev_err(pctldev->dev, "pin %d isn't in the range of "
+			"%d to %d\n", pin, range->pin_base, end);
+		return -EINVAL;
+	}
+	mux_bytes = pcs->width / BITS_PER_BYTE;
+	data = pcs->read(pcs->base + pin * mux_bytes) & ~pcs->fmask;
+	data |= gpio->gpio_func;
+	pcs->write(data, pcs->base + pin * mux_bytes);
+	return 0;
 }
 
 static struct pinmux_ops pcs_pinmux_ops = {
@@ -879,6 +914,62 @@ static void pcs_free_resources(struct pcs_device *pcs)
 
 static struct of_device_id pcs_of_match[];
 
+static int __devinit pcs_add_gpio_range(struct device_node *node,
+					struct pcs_device *pcs)
+{
+	struct pcs_gpio_range *gpio;
+	struct device_node *np;
+	const __be32 *list;
+	const char list_name[] = "pinctrl-single,gpio-ranges";
+	const char name[] = "pinctrl-single";
+	u32 gpiores[PCS_MAX_GPIO_VALUES];
+	int ret, size, i, mux_bytes = 0;
+
+	list = of_get_property(node, list_name, &size);
+	if (!list)
+		return 0;
+	size = size / sizeof(*list);
+	for (i = 0; i < size; i++) {
+		np = of_parse_phandle(node, list_name, i);
+		memset(gpiores, 0, sizeof(u32) * PCS_MAX_GPIO_VALUES);
+		ret = of_property_read_u32_array(np, "pinctrl-single,gpio",
+						 gpiores, PCS_MAX_GPIO_VALUES);
+		if (ret < 0)
+			return -ENOENT;
+		gpio = devm_kzalloc(pcs->dev, sizeof(*gpio), GFP_KERNEL);
+		if (!gpio) {
+			dev_err(pcs->dev, "failed to allocate pcs gpio\n");
+			return -ENOMEM;
+		}
+		gpio->range.id = i;
+		gpio->range.base = gpiores[0];
+		gpio->range.npins = gpiores[1];
+		gpio->range.name = devm_kzalloc(pcs->dev, sizeof(name),
+						GFP_KERNEL);
+		if (!gpio->range.name) {
+			dev_err(pcs->dev, "failed to allocate range name\n");
+			return -ENOMEM;
+		}
+		memcpy(&gpio->range.name, name, sizeof(name));
+		mux_bytes = pcs->width / BITS_PER_BYTE;
+		gpio->range.pin_base = gpiores[2] / mux_bytes;
+		memset(gpiores, 0, sizeof(u32) * PCS_MAX_GPIO_VALUES);
+		ret = of_property_read_u32(np, "pinctrl-single,gpio-func",
+					   &gpio->gpio_func);
+		if (ret < 0)
+			return -ENOENT;
+		gpio->func_en = 1;
+
+		mutex_lock(&pcs->mutex);
+		list_add_tail(&gpio->range.node, &pcs->ranges);
+		pcs->nranges++;
+		mutex_unlock(&pcs->mutex);
+
+		pinctrl_add_gpio_range(pcs->pctl, &gpio->range);
+	}
+	return 0;
+}
+
 static int __devinit pcs_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
@@ -900,6 +991,7 @@ static int __devinit pcs_probe(struct platform_device *pdev)
 	mutex_init(&pcs->mutex);
 	INIT_LIST_HEAD(&pcs->pingroups);
 	INIT_LIST_HEAD(&pcs->functions);
+	INIT_LIST_HEAD(&pcs->ranges);
 
 	PCS_GET_PROP_U32("pinctrl-single,register-width", &pcs->width,
 			 "register width not specified\n");
@@ -975,6 +1067,10 @@ static int __devinit pcs_probe(struct platform_device *pdev)
 		goto free;
 	}
 
+	ret = pcs_add_gpio_range(np, pcs);
+	if (ret < 0)
+		goto free;
+
 	dev_info(pcs->dev, "%i pins at pa %p size %u\n",
 		 pcs->desc.npins, pcs->base, pcs->size);
 
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH v3 1/9] ARM: mmp: select pinctrl driver
From: Haojian Zhuang @ 2012-10-31 23:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1351724661-29050-1-git-send-email-haojian.zhuang@gmail.com>

Pinctrl driver is necessary for MMP DT & MMP2 DT platforms.

Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
---
 arch/arm/mach-mmp/Kconfig |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm/mach-mmp/Kconfig b/arch/arm/mach-mmp/Kconfig
index 178d4da..ebdda83 100644
--- a/arch/arm/mach-mmp/Kconfig
+++ b/arch/arm/mach-mmp/Kconfig
@@ -89,6 +89,8 @@ config MACH_MMP_DT
 	select CPU_PXA168
 	select CPU_PXA910
 	select USE_OF
+	select PINCTRL
+	select PINCTRL_SINGLE
 	help
 	  Include support for Marvell MMP2 based platforms using
 	  the device tree. Needn't select any other machine while
@@ -99,6 +101,8 @@ config MACH_MMP2_DT
 	depends on !CPU_MOHAWK
 	select CPU_MMP2
 	select USE_OF
+	select PINCTRL
+	select PINCTRL_SINGLE
 	help
 	  Include support for Marvell MMP2 based platforms using
 	  the device tree.
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH v3 0/9]: pinctrl-single support DT
From: Haojian Zhuang @ 2012-10-31 23:04 UTC (permalink / raw)
  To: linux-arm-kernel

Changelog:
v3:
1. Add more comments in document.
2. Replace pcs_readl() & pcs_writel() by pcs->read() & pcs->write().
3. Clean code.

v2:
1. Remove "pinctrl-single,gpio-mask". Since GPIO function is one of the
mux function in the pinmux register of both OMAP and PXA/MMP silicons.
Use "pinctrl-single,function-mask" instead.
2. Remove "pinctrl-single,gpio-enable" & "pinctrl-single,gpio-disable".
Use "pinctrl-single,gpio-func" instead. Because GPIO mode is only one
of the mux functions in the pinmux register. Defining "gpio-enable" &
"gpio-disable" are redundant.
3. Define register with __iomem, not u32 type.
4. Remove "pinctrl-single,input-schmit-shift",
"pinctrl-single,power-source-shift", "pinctrl-single,bias-shift". All
these properties could be calculated by mask fields.
5. Return -EPROBE_DEFER if pinmux could be got in device driver. And
the device driver would be probed again deferred.

^ permalink raw reply

* [PATCH 07/11] ARM: OMAP: Move omap-pm-noop.c local to mach-omap2
From: Laurent Pinchart @ 2012-10-31 23:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20121031205850.GO12739@atomide.com>

Hi Tony,

On Wednesday 31 October 2012 13:58:50 Tony Lindgren wrote:
> * Tony Lindgren <tony@atomide.com> [121030 16:55]:
> > This code should be private to mach-omap2.
> > 
> > The only use for it in for omap1 has been in dmtimer.c
> > to check for context loss. However, omap1 does not
> > lose context during idle, so the code is not needed.
> > Further, omap1 timer has OMAP_TIMER_ALWON set, so omap1
> > was not hitting omap_pm_get_dev_context_loss_count()
> > test.
> 
> Noticed one issue with my test compiles in the
> omap-for-v3.8/cleanup-headers branch that can be
> fixed along with this patch.
> 
> --- a/drivers/media/platform/omap3isp/ispvideo.c
> +++ b/drivers/media/platform/omap3isp/ispvideo.c
> @@ -36,7 +36,6 @@
>  #include <media/v4l2-ioctl.h>
>  #include <plat/iommu.h>
>  #include <plat/iovmm.h>
> -#include <plat/omap-pm.h>

The reason this was included was to call omap_pm_set_min_bus_tput() in earlier 
versions of the driver. We'll have to discuss what to replace that with, but 
that's another topic.

>  #include "ispvideo.h"
>  #include "isp.h"
> 
> I'll fold that into this patch.
>
> Regards,
> 
> Tony
> 
> > Cc: Jon Hunter <jon-hunter@ti.com>
> > Cc: Kevin Hilman <khilman@deeprootsystems.com>
> > Signed-off-by: Tony Lindgren <tony@atomide.com>
> > ---
> > 
> >  arch/arm/mach-omap2/Makefile              |    1 +
> >  arch/arm/mach-omap2/omap-pm-noop.c        |    4 ++--
> >  arch/arm/mach-omap2/timer.c               |    2 ++
> >  arch/arm/plat-omap/Makefile               |    1 -
> >  arch/arm/plat-omap/dmtimer.c              |   17 ++++++++++-------
> >  arch/arm/plat-omap/include/plat/dmtimer.h |    2 ++
> >  6 files changed, 17 insertions(+), 10 deletions(-)
> >  rename arch/arm/{plat-omap/omap-pm-noop.c => mach-omap2/omap-pm-noop.c}
> >  (99%)> 
> > diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
> > index e3de5d4..b118ed5 100644
> > --- a/arch/arm/mach-omap2/Makefile
> > +++ b/arch/arm/mach-omap2/Makefile
> > @@ -70,6 +70,7 @@ obj-$(CONFIG_ARCH_OMAP4)		+= pm44xx.o
> > omap-mpuss-lowpower.o> 
> >  obj-$(CONFIG_ARCH_OMAP4)		+= sleep44xx.o
> >  obj-$(CONFIG_SOC_OMAP5)			+= omap-mpuss-lowpower.o sleep44xx.o
> >  obj-$(CONFIG_PM_DEBUG)			+= pm-debug.o
> > 
> > +obj-$(CONFIG_OMAP_PM_NOOP)		+= omap-pm-noop.o
> > 
> >  obj-$(CONFIG_POWER_AVS_OMAP)		+= sr_device.o
> >  obj-$(CONFIG_POWER_AVS_OMAP_CLASS3)	+= smartreflex-class3.o
> > 
> > diff --git a/arch/arm/plat-omap/omap-pm-noop.c
> > b/arch/arm/mach-omap2/omap-pm-noop.c similarity index 99%
> > rename from arch/arm/plat-omap/omap-pm-noop.c
> > rename to arch/arm/mach-omap2/omap-pm-noop.c
> > index 198685b..6a3be2b 100644
> > --- a/arch/arm/plat-omap/omap-pm-noop.c
> > +++ b/arch/arm/mach-omap2/omap-pm-noop.c
> > @@ -22,8 +22,8 @@
> > 
> >  #include <linux/device.h>
> >  #include <linux/platform_device.h>
> > 
> > -#include "../mach-omap2/omap_device.h"
> > -#include "../mach-omap2/omap-pm.h"
> > +#include "omap_device.h"
> > +#include "omap-pm.h"
> > 
> >  static bool off_mode_enabled;
> >  static int dummy_context_loss_counter;
> > 
> > diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
> > index 565e575..95e4478 100644
> > --- a/arch/arm/mach-omap2/timer.c
> > +++ b/arch/arm/mach-omap2/timer.c
> > @@ -559,6 +559,8 @@ static int __init omap_timer_init(struct omap_hwmod
> > *oh, void *unused)> 
> >  	if (timer_dev_attr)
> >  	
> >  		pdata->timer_capability = timer_dev_attr->timer_capability;
> > 
> > +	pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count;
> > +
> > 
> >  	pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata),
> >  	
> >  				 NULL, 0, 0);
> > 
> > diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
> > index 4bd0ace..50da9bf 100644
> > --- a/arch/arm/plat-omap/Makefile
> > +++ b/arch/arm/plat-omap/Makefile
> > @@ -19,4 +19,3 @@ obj-y += $(i2c-omap-m) $(i2c-omap-y)
> > 
> >  # OMAP mailbox framework
> >  obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o
> > 
> > -obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o
> > diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
> > index 4a0b30a..9a0bbc4 100644
> > --- a/arch/arm/plat-omap/dmtimer.c
> > +++ b/arch/arm/plat-omap/dmtimer.c
> > @@ -45,8 +45,6 @@
> > 
> >  #include <mach/hardware.h>
> > 
> > -#include "../mach-omap2/omap-pm.h"
> > -
> > 
> >  static u32 omap_reserved_systimers;
> >  static LIST_HEAD(omap_timer_list);
> >  static DEFINE_SPINLOCK(dm_timer_lock);
> > 
> > @@ -349,7 +347,8 @@ int omap_dm_timer_start(struct omap_dm_timer *timer)
> > 
> >  	omap_dm_timer_enable(timer);
> >  	
> >  	if (!(timer->capability & OMAP_TIMER_ALWON)) {
> > 
> > -		if (omap_pm_get_dev_context_loss_count(&timer->pdev->dev) !=
> > +		if (timer->get_context_loss_count &&
> > +			timer->get_context_loss_count(&timer->pdev->dev) !=
> > 
> >  				timer->ctx_loss_count)
> >  			
> >  			omap_timer_restore_context(timer);
> >  	
> >  	}
> > 
> > @@ -378,9 +377,11 @@ int omap_dm_timer_stop(struct omap_dm_timer *timer)
> > 
> >  	__omap_dm_timer_stop(timer, timer->posted, rate);
> > 
> > -	if (!(timer->capability & OMAP_TIMER_ALWON))
> > -		timer->ctx_loss_count =
> > -			omap_pm_get_dev_context_loss_count(&timer->pdev->dev);
> > +	if (!(timer->capability & OMAP_TIMER_ALWON)) {
> > +		if (timer->get_context_loss_count)
> > +			timer->ctx_loss_count =
> > +				timer->get_context_loss_count(&timer->pdev->dev);
> > +	}
> > 
> >  	/*
> >  	
> >  	 * Since the register values are computed and written within
> > 
> > @@ -496,7 +497,8 @@ int omap_dm_timer_set_load_start(struct omap_dm_timer
> > *timer, int autoreload,> 
> >  	omap_dm_timer_enable(timer);
> >  	
> >  	if (!(timer->capability & OMAP_TIMER_ALWON)) {
> > 
> > -		if (omap_pm_get_dev_context_loss_count(&timer->pdev->dev) !=
> > +		if (timer->get_context_loss_count &&
> > +			timer->get_context_loss_count(&timer->pdev->dev) !=
> > 
> >  				timer->ctx_loss_count)
> >  			
> >  			omap_timer_restore_context(timer);
> >  	
> >  	}
> > 
> > @@ -730,6 +732,7 @@ static int __devinit omap_dm_timer_probe(struct
> > platform_device *pdev)> 
> >  	timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
> >  	timer->pdev = pdev;
> >  	timer->capability = pdata->timer_capability;
> > 
> > +	timer->get_context_loss_count = pdata->get_context_loss_count;
> > 
> >  	/* Skip pm_runtime_enable for OMAP1 */
> >  	if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
> > 
> > diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h
> > b/arch/arm/plat-omap/include/plat/dmtimer.h index 85868e9..3f5b9cf 100644
> > --- a/arch/arm/plat-omap/include/plat/dmtimer.h
> > +++ b/arch/arm/plat-omap/include/plat/dmtimer.h
> > @@ -94,6 +94,7 @@ struct dmtimer_platform_data {
> > 
> >  	/* set_timer_src - Only used for OMAP1 devices */
> >  	int (*set_timer_src)(struct platform_device *pdev, int source);
> >  	u32 timer_capability;
> > 
> > +	int (*get_context_loss_count)(struct device *);

That's a step forward for the common zImage, but one step backward for DT 
support :-) I'm fine with this for now, but do you already have an idea on how 
to solve that ?

> >  };
> >  
> >  int omap_dm_timer_reserve_systimer(int id);
> > 
> > @@ -263,6 +264,7 @@ struct omap_dm_timer {
> > 
> >  	unsigned reserved:1;
> >  	unsigned posted:1;
> >  	struct timer_regs context;
> > 
> > +	int (*get_context_loss_count)(struct device *);
> > 
> >  	int ctx_loss_count;
> >  	int revision;
> >  	u32 capability;
> > 

-- 
Regards,

Laurent Pinchart

^ permalink raw reply

* [PATCH v2 5/9] document: devicetree: bind pinconf with pin-single
From: Haojian Zhuang @ 2012-10-31 22:51 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <5091A5AA.7000207@wwwdotorg.org>

On Wed, Oct 31, 2012 at 11:26 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 10/31/2012 10:58 AM, Haojian Zhuang wrote:
>> On Tue, Oct 23, 2012 at 6:44 AM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>> 3) Why is pinctrl-single,gpio-func optional? Presumably you always need
>>> to program the pinmux HW to select the GPIO function. Yet, the driver
>>> code in an earlier patch seems to deliberately do nothing if this
>>> property is missing. Shouldn't the DT parsing return an error instead?
>>>
>> pinctrl-single,gpio-func is optional for above reason.
>
> Presumably the node that contains the pinctrl-single,gpio-func property
> is optional, but once you have such a node, pinctrl-single,gpio-func is
> required?
>
Yes, gpio-func is must required if the phandle of gpio range is defined.
I'll add such comments in document.

>>> I suppose it's OK that a generic pin controller binding would use the
>>> generic pin configuration config options. I'm still not convinced that
>>> the semantics of generic pin control make sense. Maybe if they're just
>>> arbitrary names for SoC-specific things it's fine though.
>>>
>>> Do these patches expose /all/ generic pin configuration options? It
>>> doesn't seem worth exposing only some of them and ignoring others.
>>
>> I believe general pinconf can't support all cases in different silicons.
>
> I tend to agree.
>
>> And we still have some common features that could be covered in general
>> pinconf. So we need a structure to support both pinconf & specific pinconf.
>
> But that tends to imply that adding support for generic pinconf into the
> pinctrl-simple driver isnt' actually going to be useful for anyone. If
> pinctrl-single only supports some part of your HW, how can you use it?
> Or, do you intend to somehow make pinctrl-single support both the common
> generic pinconf stuff, and somehow be extensible to support any
> SoC-specific pin config fields?

I'm intend to make pinctrl-single to support both the common generic pinconf
stuff and any SoC-specific pinconf. I'll try to handle it. But they
won't be included
in V3.

^ permalink raw reply

* [RFC PATCH] dt: describe base reset signal binding
From: Stephen Warren @ 2012-10-31 22:47 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20121031103221.18780.43096@nucleus>

On 10/31/2012 04:32 AM, Mike Turquette wrote:
> Quoting Stephen Warren (2012-10-30 11:02:05)
>> On 10/29/2012 12:32 PM, Mike Turquette wrote:
>>> Quoting Stephen Warren (2012-10-23 14:45:56)
>>>> What do people think of this? Does it sound like a good idea to go ahead
>>>> with a reset subsystem? Should we simply add a new API to the common clock
>>>> subsystem instead (and assume that reset and clock domains match 1:1).
>>>> Should this be implemented as part of the generic power management domains;
>>>> see include/linux/pm_domain.h instead?
>>>>
>>>
>>> Hi Stephen,
>>>
>>> I'm not sure a "reset subsystem" is necessary, but I also do not like
>>> using clocks as the keys for IP reset.
>>
>> I'm not sure what you're suggesting as an alternative to a reset
>> subsystem (or API if you want something that sounds smaller!) :-)
> 
> My point was that I do not know if a new subsystem is necessary or not.
> Your suggestion to "simply add a new API to the common clock subsystem"
> is an example of an alternative to a whole new subsystem.  However I
> instinctively feel that the clock api is not the right place for
> reseting devices.

driver/base/power is about the only related place I can think of given a
quick look. However, in a similar way to clocks, I don't think there's
necessarily a 1:1 relationship between power domains and reset domains
either, so driver/base/power doesn't feel like a good fit in just the
same way that drivers/clk doesn't.

I wonder if a drivers/base/reset/ or drivers/base/reset.c would be
appropriate?

>>> I think it is more common to map IPs to struct device, no?
>>
>> It is indeed probably common that there's a 1:1 mapping between IP
>> blocks and struct device. However, I'm sure there are plenty of
>> counter-examples; IP blocks with multiple reset domains (hence struct
>> devices that encompass multiple reset domains, or reset domains that
>> encompass multiple struct devices), just as there are many examples of
>> non-1:1 mappings between struct device and struct clk.
> 
> In OMAP code we handle IP resets through the hwmod code and I prefer
> that IP-centric approach to associating IP resets with a clock node.
> Perhaps the hwmod approach could serve as inspiration for a new generic
> way to reset modules.

OK, I'm not even slightly familiar with the hwmod code, but I keep
hearing about it, so I'll go take a quick look.

^ permalink raw reply

* [PATCH 04/11] ARM: OMAP: Move omap2+ specific parts of sram.c to mach-omap2
From: Tony Lindgren @ 2012-10-31 22:40 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20121030235249.25936.15471.stgit@muffinssi.local>

* Tony Lindgren <tony@atomide.com> [121030 16:54]:
> Let's make the omap2+ specific parts private to mach-omap2.
> 
> This leaves just a minimal shared code into plat-omap like
> it should be.

Found an error with make randconfig if we have
CONFIG_OMAP4_ERRATA_I688 enabled, I'll fold in the
following fix to this patch.

Regards,

Tony


--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -32,6 +32,7 @@
 #include "hsmmc.h"
 #include "omap4-sar-layout.h"
 #include "omap-secure.h"
+#include "sram.h"
 
 #ifdef CONFIG_CACHE_L2X0
 static void __iomem *l2cache_base;

^ permalink raw reply

* [PATCH 0/9] ARM: Kirkwood: Convert to pinctrl
From: Josh Coombs @ 2012-10-31 22:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20121028165711.GG15824@lunn.ch>

Sorry it took me so long to test on my GoFlex Net.  Working fine.

tested by: Joshua Coombs <josh.coombs@gmail.com>


On Sun, Oct 28, 2012 at 12:57 PM, Andrew Lunn <andrew@lunn.ch> wrote:

> On Wed, Oct 24, 2012 at 04:53:45PM +0200, Andrew Lunn wrote:
> > This patchset converts all DT kirkwood boards to using pinctrl.
>
> Thanks for the feedback everybody gave.
>
> Progress has been made:
>
> The bug causing the lockups has been found, fixed and passed upstream.
>
> I factored out the repeated pinmux definitions for sata0, sata1, spi,
> twsi0, uart0, uart1.
>
> I fixed a few types reported by testers.
>
> I found a solution to many of the gpio_request() failures. The ones
> for controlling power to SATA or USB i've replaced with a regulator in
> DT. The regulator will grab the GPIO, set it to output, and driver it
> high/low as required. I just hope we don't have an ordering issue.
> The regulator framework seems to load quite early and probes all the
> regulators. This fails, because pinctrl has not yet loaded, so the
> gpio framework returns EPROBE_DEFER. This is not fatal to the
> regulator framework, it tries again later. But this later is after
> most of the rest of the drivers have loaded. So we might get into
> issues where uboot has not enabled power to USB/SATA, the driver is
> probed and fails because of the lack of power, and once things of gone
> wrong, we turn the power on.
>
> I still expect problems with GPIOs used for power off. I've not yet
> touched them. Again, a regulator makes sense, but there is no 'out of
> the box' regulator type or property which adds itself to pm_power_off.
>
> The last problem is:
>
>         /* Set NAS to turn back on after a power failure */
>         dnskw_gpio_register(37, "dnskw:power:recover", 1);
>
> I think its a bit of a stretch calling this a regulator.
>
> Since the current patchset is 18 patches, plus a few other bug fixes
> and dependencies, i'm not going to post them all here. I think we are
> still at the smoke/no-smoke stage of testing. Please pull from:
>
> git://github.com/lunn/linux.git v3.7-rc2-pinctrl-v2
>
> and let me know if things work, what typo's need fixing, where the
> smoke comes out, etc.
>
>       Thanks
>         Andrew
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121031/08091f97/attachment-0001.html>

^ permalink raw reply

* [PATCH 08/10] pinctrl: single: support pinconf generic
From: Haojian Zhuang @ 2012-10-31 22:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20121025234328.GF11928@atomide.com>

On Fri, Oct 26, 2012 at 1:43 AM, Tony Lindgren <tony@atomide.com> wrote:
> * Tony Lindgren <tony@atomide.com> [121022 10:11]:
>> * Haojian Zhuang <haojian.zhuang@gmail.com> [121022 03:11]:
>> > On Sat, Oct 20, 2012 at 3:13 AM, Tony Lindgren <tony@atomide.com> wrote:
>> > > * Haojian Zhuang <haojian.zhuang@gmail.com> [121018 02:08]:
>> > >> Add pinconf generic support with POWER SOURCE, BIAS PULL.
>> > > ...
>> > >
>> > >> +     case PIN_CONFIG_POWER_SOURCE:
>> > >> +             if (pcs->psmask == PCS_OFF_DISABLED
>> > >> +                     || pcs->psshift == PCS_OFF_DISABLED)
>> > >> +                     return -ENOTSUPP;
>> > >> +             data &= pcs->psmask;
>> > >> +             data = data >> pcs->psshift;
>> > >> +             *config = data;
>> > >> +             return 0;
>> > >> +             break;
>> > >
>> > > Hmm, only slightly related to this patch, mostly a generic
>> > > question to others: Do others have any mux registers with
>> > > status bits for things like PIN_CONFIG_POWER_SOURCE?
>> > >
>> > > I could use PIN_CONFIG_POWER_SOURCE for controlling the PBIAS
>> > > for omap MMC. But there's also a status bit that needs to be
>> > > checked for that. I think there was some other similar mux
>> > > register for USB PHY that has a status register.
>> > >
>> > > So I'm wondering should the checking for status bit be handled
>> > > in the pinctrl consume driver? Or should we have some bindings
>> > > for that?
>> > >
>> >
>> > Do you mean that the status register only exists in USB PHY controller or
>> > MMC controller?
>>
>> The status register is in the MMC PBIAS register that is mux
>> related otherwise. From OMAP4470_ES1.0_PUBLIC_TRM_vE.pdf,
>> Table 19-599. CONTROL_PBIASLITE:
>>
>> Bits
>> 26    MMC1_PWDNZ
>> 25    MMC1_PBIASLITE_HIZ_MODE
>> 24    MMC1_PBIASLITE_SUPPLY_HI_OUT
>> 23    MMC1_PBIASLITE_VMODE_ERROR      then this bit needs to clear..
>> 22    MMC1_PBIASLITE_PWRDNZ
>> 21    MMC1_PBIASLITE_VMODE            ..after VMODE bit is set to 3V
>>
>> > If so, could we use regulator framework in USB PHY or MMC driver?
>>
>> Yes we could use regulator framework for that that. Or just read the
>> status in the MMC driver for that bit if nobody else has mixed
>> mux-regulator needs like this.
>>
>> The sequence is MMC specific, so from that point of view it would
>> make sense to have the logic in the MMC driver.
>
> Well it turns out the VMODE_ERROR bit is not just for VMODE, it's a
> comparator that can also triggers for the other invalid states for
> CONTROL_PBIASLITE pinconf register. So hiding VMODE_ERROR into a
> regulator would be wrong. For now, VMODE best handled using
> PIN_CONFIG_POWER_SOURCE and let the MMC driver do the checking
> using the pinconf API.
>
I'm seeking whether there's more flexible way to support your case.
The fix won't
be contained in v3 round.

^ permalink raw reply

* [PATCH v2 5/9] document: devicetree: bind pinconf with pin-single
From: Stephen Warren @ 2012-10-31 22:26 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAN1soZy8xXGs8zEiZV0kV0dGVdXfZ9ogx83sFgPG76d0i8yH4A@mail.gmail.com>

On 10/31/2012 10:58 AM, Haojian Zhuang wrote:
> On Tue, Oct 23, 2012 at 6:44 AM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 10/22/2012 10:08 AM, Haojian Zhuang wrote:
>>> Add comments with pinconf & gpio range in the document of
>>> pinctrl-single.
...
>>> diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
...
>>> @@ -17,6 +17,36 @@ Optional properties:
>>>  - pinctrl-single,bit-per-mux : boolean to indicate that one register controls
>>>    more than one pin
>>>
>>> +- pinctrl-single,gpio-ranges : gpio range list
>>> +
>>> +- pinctrl-single,gpio : array with gpio range start, size & register
>>> +  offset
>>> +
>>> +- pinctrl-single,gpio-func : gpio function value in the pinmux register
...
>> 2) pinctrl-single,gpio is listed as optional. Presumably it's not; every
>> GPIO range node must have this property?
>>
> Yes, they must be included in GPIO range node. But if GPIO feature
> isn't supported in the pinctrl device, pinctrl-single,gpio is still optional.
> I'll add more comments on this.
> 
>> 3) Why is pinctrl-single,gpio-func optional? Presumably you always need
>> to program the pinmux HW to select the GPIO function. Yet, the driver
>> code in an earlier patch seems to deliberately do nothing if this
>> property is missing. Shouldn't the DT parsing return an error instead?
>>
> pinctrl-single,gpio-func is optional for above reason.

Presumably the node that contains the pinctrl-single,gpio-func property
is optional, but once you have such a node, pinctrl-single,gpio-func is
required?

>>> +- pinctrl-single,power-source-mask : mask of setting power source in
>>> +  the pinmux register
>>> +
>>> +- pinctrl-single,power-source : value of setting power source field
>>> +  in the pinmux register
...
>> I suppose it's OK that a generic pin controller binding would use the
>> generic pin configuration config options. I'm still not convinced that
>> the semantics of generic pin control make sense. Maybe if they're just
>> arbitrary names for SoC-specific things it's fine though.
>>
>> Do these patches expose /all/ generic pin configuration options? It
>> doesn't seem worth exposing only some of them and ignoring others.
>
> I believe general pinconf can't support all cases in different silicons.

I tend to agree.

> And we still have some common features that could be covered in general
> pinconf. So we need a structure to support both pinconf & specific pinconf.

But that tends to imply that adding support for generic pinconf into the
pinctrl-simple driver isnt' actually going to be useful for anyone. If
pinctrl-single only supports some part of your HW, how can you use it?
Or, do you intend to somehow make pinctrl-single support both the common
generic pinconf stuff, and somehow be extensible to support any
SoC-specific pin config fields?

^ permalink raw reply

* [PATCH 13/11] ARM: OMAP2+: Fix relative includes for serial.h
From: Tony Lindgren @ 2012-10-31 22:08 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20121030234852.25936.12482.stgit@muffinssi.local>

As discussed on linux-arm-kernel, we want to avoid
relative includes for the arch/arm/*omap* code:

http://www.spinics.net/lists/linux-omap/msg80520.html

Fix serial.h by moving it to mach/serial.h.

Signed-off-by: Tony Lindgren <tony@atomide.com>

diff --git a/arch/arm/mach-omap2/include/mach/debug-macro.S b/arch/arm/mach-omap2/include/mach/debug-macro.S
index 4b5cbdf..cfaed13 100644
--- a/arch/arm/mach-omap2/include/mach/debug-macro.S
+++ b/arch/arm/mach-omap2/include/mach/debug-macro.S
@@ -13,7 +13,7 @@
 
 #include <linux/serial_reg.h>
 
-#include <../mach-omap2/serial.h>
+#include <mach/serial.h>
 
 #define UART_OFFSET(addr)	((addr) & 0x00ffffff)
 
diff --git a/arch/arm/mach-omap2/include/mach/serial.h b/arch/arm/mach-omap2/include/mach/serial.h
new file mode 100644
index 0000000..70eda00
--- /dev/null
+++ b/arch/arm/mach-omap2/include/mach/serial.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support- Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * Memory entry used for the DEBUG_LL UART configuration, relative to
+ * start of RAM. See also uncompress.h and debug-macro.S.
+ *
+ * Note that using a memory location for storing the UART configuration
+ * has at least two limitations:
+ *
+ * 1. Kernel uncompress code cannot overlap OMAP_UART_INFO as the
+ *    uncompress code could then partially overwrite itself
+ * 2. We assume printascii is called at least once before paging_init,
+ *    and addruart has a chance to read OMAP_UART_INFO
+ */
+#define OMAP_UART_INFO_OFS	0x3ffc
+
+/* OMAP2 serial ports */
+#define OMAP2_UART1_BASE	0x4806a000
+#define OMAP2_UART2_BASE	0x4806c000
+#define OMAP2_UART3_BASE	0x4806e000
+
+/* OMAP3 serial ports */
+#define OMAP3_UART1_BASE	OMAP2_UART1_BASE
+#define OMAP3_UART2_BASE	OMAP2_UART2_BASE
+#define OMAP3_UART3_BASE	0x49020000
+#define OMAP3_UART4_BASE	0x49042000	/* Only on 36xx */
+#define OMAP3_UART4_AM35XX_BASE	0x4809E000	/* Only on AM35xx */
+
+/* OMAP4 serial ports */
+#define OMAP4_UART1_BASE	OMAP2_UART1_BASE
+#define OMAP4_UART2_BASE	OMAP2_UART2_BASE
+#define OMAP4_UART3_BASE	0x48020000
+#define OMAP4_UART4_BASE	0x4806e000
+
+/* TI81XX serial ports */
+#define TI81XX_UART1_BASE	0x48020000
+#define TI81XX_UART2_BASE	0x48022000
+#define TI81XX_UART3_BASE	0x48024000
+
+/* AM3505/3517 UART4 */
+#define AM35XX_UART4_BASE	0x4809E000	/* Only on AM3505/3517 */
+
+/* AM33XX serial port */
+#define AM33XX_UART1_BASE	0x44E09000
+
+/* OMAP5 serial ports */
+#define OMAP5_UART1_BASE	OMAP2_UART1_BASE
+#define OMAP5_UART2_BASE	OMAP2_UART2_BASE
+#define OMAP5_UART3_BASE	OMAP4_UART3_BASE
+#define OMAP5_UART4_BASE	OMAP4_UART4_BASE
+#define OMAP5_UART5_BASE	0x48066000
+#define OMAP5_UART6_BASE	0x48068000
+
+/* External port on Zoom2/3 */
+#define ZOOM_UART_BASE		0x10000000
+#define ZOOM_UART_VIRT		0xfa400000
+
+#define OMAP_PORT_SHIFT		2
+#define ZOOM_PORT_SHIFT		1
+
+#define OMAP24XX_BASE_BAUD	(48000000/16)
+
+/*
+ * DEBUG_LL port encoding stored into the UART1 scratchpad register by
+ * decomp_setup in uncompress.h
+ */
+#define OMAP2UART1		21
+#define OMAP2UART2		22
+#define OMAP2UART3		23
+#define OMAP3UART1		OMAP2UART1
+#define OMAP3UART2		OMAP2UART2
+#define OMAP3UART3		33
+#define OMAP3UART4		34		/* Only on 36xx */
+#define OMAP4UART1		OMAP2UART1
+#define OMAP4UART2		OMAP2UART2
+#define OMAP4UART3		43
+#define OMAP4UART4		44
+#define TI81XXUART1		81
+#define TI81XXUART2		82
+#define TI81XXUART3		83
+#define AM33XXUART1		84
+#define OMAP5UART3		OMAP4UART3
+#define OMAP5UART4		OMAP4UART4
+#define ZOOM_UART		95		/* Only on zoom2/3 */
+
+#ifndef __ASSEMBLER__
+
+struct omap_board_data;
+struct omap_uart_port_info;
+
+extern void omap_serial_init(void);
+extern void omap_serial_board_init(struct omap_uart_port_info *platform_data);
+extern void omap_serial_init_port(struct omap_board_data *bdata,
+		struct omap_uart_port_info *platform_data);
+#endif
diff --git a/arch/arm/mach-omap2/include/mach/uncompress.h b/arch/arm/mach-omap2/include/mach/uncompress.h
index 28d1ec0..8e3546d 100644
--- a/arch/arm/mach-omap2/include/mach/uncompress.h
+++ b/arch/arm/mach-omap2/include/mach/uncompress.h
@@ -23,7 +23,7 @@
 #include <asm/memory.h>
 #include <asm/mach-types.h>
 
-#include <../mach-omap2/serial.h>
+#include <mach/serial.h>
 
 #define MDR1_MODE_MASK			0x07
 
diff --git a/arch/arm/mach-omap2/serial.h b/arch/arm/mach-omap2/serial.h
index 6a68062..c4014f0 100644
--- a/arch/arm/mach-omap2/serial.h
+++ b/arch/arm/mach-omap2/serial.h
@@ -1,112 +1 @@
-/*
- * arch/arm/plat-omap/include/mach/serial.h
- *
- * Copyright (C) 2009 Texas Instruments
- * Added OMAP4 support- Santosh Shilimkar <santosh.shilimkar@ti.com>
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef __ASM_ARCH_SERIAL_H
-#define __ASM_ARCH_SERIAL_H
-
-#include <linux/init.h>
-
-/*
- * Memory entry used for the DEBUG_LL UART configuration, relative to
- * start of RAM. See also uncompress.h and debug-macro.S.
- *
- * Note that using a memory location for storing the UART configuration
- * has at least two limitations:
- *
- * 1. Kernel uncompress code cannot overlap OMAP_UART_INFO as the
- *    uncompress code could then partially overwrite itself
- * 2. We assume printascii is called at least once before paging_init,
- *    and addruart has a chance to read OMAP_UART_INFO
- */
-#define OMAP_UART_INFO_OFS	0x3ffc
-
-/* OMAP2 serial ports */
-#define OMAP2_UART1_BASE	0x4806a000
-#define OMAP2_UART2_BASE	0x4806c000
-#define OMAP2_UART3_BASE	0x4806e000
-
-/* OMAP3 serial ports */
-#define OMAP3_UART1_BASE	OMAP2_UART1_BASE
-#define OMAP3_UART2_BASE	OMAP2_UART2_BASE
-#define OMAP3_UART3_BASE	0x49020000
-#define OMAP3_UART4_BASE	0x49042000	/* Only on 36xx */
-#define OMAP3_UART4_AM35XX_BASE	0x4809E000	/* Only on AM35xx */
-
-/* OMAP4 serial ports */
-#define OMAP4_UART1_BASE	OMAP2_UART1_BASE
-#define OMAP4_UART2_BASE	OMAP2_UART2_BASE
-#define OMAP4_UART3_BASE	0x48020000
-#define OMAP4_UART4_BASE	0x4806e000
-
-/* TI81XX serial ports */
-#define TI81XX_UART1_BASE	0x48020000
-#define TI81XX_UART2_BASE	0x48022000
-#define TI81XX_UART3_BASE	0x48024000
-
-/* AM3505/3517 UART4 */
-#define AM35XX_UART4_BASE	0x4809E000	/* Only on AM3505/3517 */
-
-/* AM33XX serial port */
-#define AM33XX_UART1_BASE	0x44E09000
-
-/* OMAP5 serial ports */
-#define OMAP5_UART1_BASE	OMAP2_UART1_BASE
-#define OMAP5_UART2_BASE	OMAP2_UART2_BASE
-#define OMAP5_UART3_BASE	OMAP4_UART3_BASE
-#define OMAP5_UART4_BASE	OMAP4_UART4_BASE
-#define OMAP5_UART5_BASE	0x48066000
-#define OMAP5_UART6_BASE	0x48068000
-
-/* External port on Zoom2/3 */
-#define ZOOM_UART_BASE		0x10000000
-#define ZOOM_UART_VIRT		0xfa400000
-
-#define OMAP_PORT_SHIFT		2
-#define ZOOM_PORT_SHIFT		1
-
-#define OMAP24XX_BASE_BAUD	(48000000/16)
-
-/*
- * DEBUG_LL port encoding stored into the UART1 scratchpad register by
- * decomp_setup in uncompress.h
- */
-#define OMAP2UART1		21
-#define OMAP2UART2		22
-#define OMAP2UART3		23
-#define OMAP3UART1		OMAP2UART1
-#define OMAP3UART2		OMAP2UART2
-#define OMAP3UART3		33
-#define OMAP3UART4		34		/* Only on 36xx */
-#define OMAP4UART1		OMAP2UART1
-#define OMAP4UART2		OMAP2UART2
-#define OMAP4UART3		43
-#define OMAP4UART4		44
-#define TI81XXUART1		81
-#define TI81XXUART2		82
-#define TI81XXUART3		83
-#define AM33XXUART1		84
-#define OMAP5UART3		OMAP4UART3
-#define OMAP5UART4		OMAP4UART4
-#define ZOOM_UART		95		/* Only on zoom2/3 */
-
-#ifndef __ASSEMBLER__
-
-struct omap_board_data;
-struct omap_uart_port_info;
-
-extern void omap_serial_init(void);
-extern void omap_serial_board_init(struct omap_uart_port_info *platform_data);
-extern void omap_serial_init_port(struct omap_board_data *bdata,
-		struct omap_uart_port_info *platform_data);
-#endif
-
-#endif
+#include <mach/serial.h>

^ permalink raw reply related

* [RFC 1/7] capebus: Core capebus support
From: Pantelis Antoniou @ 2012-10-31 22:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CA+Bv8XZ5WnhsKqYA6TBv8wh6OvOdU-G8XhuV2dO49O1qX_FRgg@mail.gmail.com>


On Oct 31, 2012, at 11:55 PM, Russ Dill wrote:

> On Wed, Oct 31, 2012 at 9:52 AM, Pantelis Antoniou
> <panto@antoniou-consulting.com> wrote:
>> Introducing capebus; a bus that allows small boards (capes) to connect
>> to a complex SoC using simple expansion connectors.
>> 

[snip]
>> +       if (drv) {
>> +               /* call the removed bus method (if added prev.) */
>> +               if (cape_dev->added) {
>> +                       BUG_ON(cape_dev->bus == NULL);
>> +                       BUG_ON(cape_dev->bus->ops == NULL);
>> +                       if (cape_dev->bus->ops->dev_removed)
>> +                               cape_dev->bus->ops->dev_removed(cape_dev);
>> +                       cape_dev->added = 0;
>> +               }
> 
> Is there any case where added will not track drv?


Yes, there is a corner case here.

There is the case where while the device is created there is no matching
driver yet. Either that's the case of a not supported cape, or the
cape driver hasn't been loaded yet.

We do need the device to be created, so that the user can browse in the
sysfs it's eeprom attributes.

There's some further complications with runtime cape overrides, but
that's the gist of it.


>> --
>> 1.7.12
>> 
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html

Regards

-- Pantelis

^ permalink raw reply

* [PATCH 0/8] zynq COMMON_CLK support
From: Josh Cartwright @ 2012-10-31 22:06 UTC (permalink / raw)
  To: linux-arm-kernel

This patchset implements COMMON_CLK support for the zynq.  At this
point, only the basic fundamental clocks are modelled, and only
passively; for rate calculation.  of_clk bindings are implemented to
allow specifying clock/peripheral relationships in the device tree.

Patch 1 and 2 are a followup to my early patch: "ARM: zynq: move ttc
timer code to drivers/clocksource".  Patch 1 moves the definition
sys_timer definition out of the ttc code, and into the zynq common code.
Patch 2 is the actual rename, and makefile cleanup.

Patch 3 adds a description of the second uart to zynq-ep107.dts.  I did
this pre-split (patch 4), because I felt it might make reviewing easier.

Patch 4 uses zynq-ep107.dts as a reference to create zynq-7000.dtsi,
which is intended to be a common dtsi snippet for inclusion in
describing zynq-7000 based boards.  zynq-zc702.dts is created as an
example consumer.  The zynq-ep107.dts file is removed entirely (it
describes, presumably, a board not available to consumers).

Patch 5 is the real meat; it adds an implementation of the clk models
for the PLLs, the CPU clock network, and basic (simplified) clk models
for the essential peripherals (UART and the TTC).

Patch 6 removes CONFIG_OF conditional code from the xilinx uart driver.
The zynq kernel requires CONFIG_OF, and this hardware is not currently
used on any other non CONFIG_OF platform.

Patch 7 adds support to the xilinx_uartps driver to allow getting clock
rate information form the device tree.

Patch 8 implements DT support for the ttc, including pulling clock tree
info.

---
There are some specific concerns that I had that I would like some
guidance on:

Two identical timers on the board have historically been statically
allocated to act as the system clocksource, and the clockevent_device.
With patch 8, this distinction is done in the device tree by tweaking
with the compatible properties of which of the timers you want used for
what purpose.

I feel, however, that this is an abuse of the device tree, which should
only be used to describe hardware, not to layout a policy on how the
hardware is used.

So, if it's not in the device tree, then where?  Do I go back to the
static allocation routine, such that the first matching ttc node in the
tree becomes the clockevent_device, and the second one a clocksource?
That seems like a hack.

Is it somehow possible to have all of the timers registered as both a
clocksource and a clockevent_device, and have some higher level logic
make the policy decision as to which timer is used for what?

An additional question regarding of_clk bindings:

	my_clock {
		#clock-cells = <0>;
		clock-output-names = "my_out_clock";
	};
	node_a {
		clocks = <&clk>;
		clock-names = "my_clock";
		clock-ranges;

		node_b {
			/* ... */
		};
	};

In this scenario, should I be expecting of_clk_get(node_b, 0) to
retrieve a handle to parent's consumed clock (due to clock-ranges)?  I
could make this work using of_clk_get_by_name(node_b, "my_clock"), but I
was somewhat surprised the former didn't work.

Thanks (and sorry for the novel),
   Josh

---
Josh Cartwright (8):
  ARM: zynq: move arm-specific sys_timer out of ttc
  ARM: zynq: move ttc timer code to drivers/clocksource
  ARM: zynq: dts: add description of the second uart
  ARM: zynq: dts: split up device tree
  ARM: zynq: add COMMON_CLK support
  serial: xilinx_uartps: kill CONFIG_OF conditional
  serial: xilinx_uartps: get clock rate info from dts
  clocksource: xilinx_ttc: add OF_CLK support

 .../devicetree/bindings/clock/zynq-7000.txt        |  55 ++++
 arch/arm/Kconfig                                   |   1 +
 arch/arm/boot/dts/Makefile                         |   1 +
 arch/arm/boot/dts/zynq-7000.dtsi                   | 166 ++++++++++
 arch/arm/boot/dts/zynq-ep107.dts                   |  63 ----
 arch/arm/boot/dts/zynq-zc702.dts                   |  44 +++
 arch/arm/mach-zynq/Makefile                        |   2 +-
 arch/arm/mach-zynq/common.c                        |  29 +-
 arch/arm/mach-zynq/timer.c                         | 298 -----------------
 drivers/clk/Makefile                               |   1 +
 drivers/clk/clk-zynq.c                             | 355 +++++++++++++++++++++
 drivers/clocksource/Makefile                       |   1 +
 drivers/clocksource/xilinx_ttc.c                   | 326 +++++++++++++++++++
 drivers/tty/serial/xilinx_uartps.c                 |  39 +--
 include/linux/clk/zynq.h                           |  24 ++
 .../common.h => include/linux/xilinx_ttc.h         |   8 +-
 16 files changed, 1022 insertions(+), 391 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/zynq-7000.txt
 create mode 100644 arch/arm/boot/dts/zynq-7000.dtsi
 delete mode 100644 arch/arm/boot/dts/zynq-ep107.dts
 create mode 100644 arch/arm/boot/dts/zynq-zc702.dts
 delete mode 100644 arch/arm/mach-zynq/timer.c
 create mode 100644 drivers/clk/clk-zynq.c
 create mode 100644 drivers/clocksource/xilinx_ttc.c
 create mode 100644 include/linux/clk/zynq.h
 rename arch/arm/mach-zynq/common.h => include/linux/xilinx_ttc.h (81%)

-- 
1.8.0

^ permalink raw reply

* [RFC 0/7] Capebus; a bus for SoCs using simple expansion connectors
From: Pantelis Antoniou @ 2012-10-31 22:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CA+Bv8XZEpw=811-EMCMFKgZ7z03=U-KxaXBh4oMphdzwO18f8Q@mail.gmail.com>

Hi Russ,

On Oct 31, 2012, at 11:56 PM, Russ Dill wrote:

> On Wed, Oct 31, 2012 at 9:52 AM, Pantelis Antoniou
> <panto@antoniou-consulting.com> wrote:
>> Capebus is created to address the problem of many SoCs that can provide a
>> multitude of hardware interfaces but in order to keep costs down the main
>> boards only support a limited number of them. The rest are typically brought
>> out to pin connectors on to which other boards, named capes are connected and
>> allow those peripherals to be used.
>> 
>> These capes connect to the SoC interfaces but might also contain various other
>> parts that may need some kind of driver to work.
>> 
>> Since SoCs have limited pins and pin muxing options, not all capes can work
>> together so some kind of resource tracking (at least for the pins in use) is
>> required.
>> 
>> Before capebus all of this took place in the board support file, and frankly
>> for boards with too many capes it was becoming unmanageable.
>> 
>> Capebus provides a virtual bus, which along with a board specific controller,
>> cape drivers can be written using the standard Linux device model.
>> 
>> The core capebus infrastructure is not depended on any specific board.
>> However capebus needs a board controller to provide services to the cape devices
>> it controls. Services like addressing and resource reservation are provided
>> by the board controller.
>> 
>> Capebus at the moment only support TI's Beaglebone platform.
>> 
>> This RFC introduces the core concept; most supporting patches
>> have been posted to the relevant places.
> 
> There are quite a few TODOs in the code, any chance you could
> summarize them in the next header email?

Yes,

Most of them deal with dealing properly with removal of the board driver and the core
capebus stuff. And of course PM is not yet handled properly.

After I get on with this part of the review, I plan to fill in the docs and 
flesh out the TODOs more.

Regards

-- Pantelis

^ permalink raw reply

* [RFC 0/7] Capebus; a bus for SoCs using simple expansion connectors
From: Russ Dill @ 2012-10-31 21:56 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1351702333-8456-1-git-send-email-panto@antoniou-consulting.com>

On Wed, Oct 31, 2012 at 9:52 AM, Pantelis Antoniou
<panto@antoniou-consulting.com> wrote:
> Capebus is created to address the problem of many SoCs that can provide a
> multitude of hardware interfaces but in order to keep costs down the main
> boards only support a limited number of them. The rest are typically brought
> out to pin connectors on to which other boards, named capes are connected and
> allow those peripherals to be used.
>
> These capes connect to the SoC interfaces but might also contain various other
> parts that may need some kind of driver to work.
>
> Since SoCs have limited pins and pin muxing options, not all capes can work
> together so some kind of resource tracking (at least for the pins in use) is
> required.
>
> Before capebus all of this took place in the board support file, and frankly
> for boards with too many capes it was becoming unmanageable.
>
> Capebus provides a virtual bus, which along with a board specific controller,
> cape drivers can be written using the standard Linux device model.
>
> The core capebus infrastructure is not depended on any specific board.
> However capebus needs a board controller to provide services to the cape devices
> it controls. Services like addressing and resource reservation are provided
> by the board controller.
>
> Capebus at the moment only support TI's Beaglebone platform.
>
> This RFC introduces the core concept; most supporting patches
> have been posted to the relevant places.

There are quite a few TODOs in the code, any chance you could
summarize them in the next header email?

^ permalink raw reply

* [RFC 1/7] capebus: Core capebus support
From: Russ Dill @ 2012-10-31 21:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1351702333-8456-2-git-send-email-panto@antoniou-consulting.com>

On Wed, Oct 31, 2012 at 9:52 AM, Pantelis Antoniou
<panto@antoniou-consulting.com> wrote:
> Introducing capebus; a bus that allows small boards (capes) to connect
> to a complex SoC using simple expansion connectors.
>
> Up to now to support these kind of boards, one had to hack the board files,
> and do all sort of gymnastics to handle all the different cases of
> conflict resolution.
>
> Capebus provides abstractions that keep the pain to a minimum.
>
> This part of the series is introducing the core capebus functionality
> dealing with the basic bus & driver probe functions.
>
> Signed-off-by: Pantelis Antoniou <panto@antoniou-consulting.com>
> ---
>  drivers/Kconfig                  |   2 +
>  drivers/Makefile                 |   3 +
>  drivers/capebus/Kconfig          |  17 ++
>  drivers/capebus/Makefile         |   8 +
>  drivers/capebus/capebus-driver.c | 608 +++++++++++++++++++++++++++++++++++++++
>  drivers/capebus/capebus-probe.c  | 320 +++++++++++++++++++++
>  drivers/capebus/capebus-sysfs.c  |  52 ++++
>  include/linux/capebus.h          | 298 +++++++++++++++++++
>  8 files changed, 1308 insertions(+)
>  create mode 100644 drivers/capebus/Kconfig
>  create mode 100644 drivers/capebus/Makefile
>  create mode 100644 drivers/capebus/capebus-driver.c
>  create mode 100644 drivers/capebus/capebus-probe.c
>  create mode 100644 drivers/capebus/capebus-sysfs.c
>  create mode 100644 include/linux/capebus.h
>
> diff --git a/drivers/Kconfig b/drivers/Kconfig
> index dbdefa3..bfbe1d1 100644
> --- a/drivers/Kconfig
> +++ b/drivers/Kconfig
> @@ -156,4 +156,6 @@ source "drivers/pwm/Kconfig"
>
>  source "drivers/irqchip/Kconfig"
>
> +source "drivers/capebus/Kconfig"
> +
>  endmenu
> diff --git a/drivers/Makefile b/drivers/Makefile
> index a16a8d0..d7a103b 100644
> --- a/drivers/Makefile
> +++ b/drivers/Makefile
> @@ -145,3 +145,6 @@ obj-$(CONFIG_EXTCON)                += extcon/
>  obj-$(CONFIG_MEMORY)           += memory/
>  obj-$(CONFIG_IIO)              += iio/
>  obj-$(CONFIG_VME_BUS)          += vme/
> +
> +# Capebus
> +obj-$(CONFIG_CAPEBUS)          += capebus/
> diff --git a/drivers/capebus/Kconfig b/drivers/capebus/Kconfig
> new file mode 100644
> index 0000000..cea1b68
> --- /dev/null
> +++ b/drivers/capebus/Kconfig
> @@ -0,0 +1,17 @@
> +#
> +# Capebus core support
> +#
> +
> +menu "CAPEBUS support"
> +
> +config CAPEBUS
> +       bool "Capebus support"
> +       default n
> +       help
> +         Enable to support capebus devices.
> +
> +source "drivers/capebus/boards/Kconfig"
> +
> +source "drivers/capebus/capes/Kconfig"
> +
> +endmenu
> diff --git a/drivers/capebus/Makefile b/drivers/capebus/Makefile
> new file mode 100644
> index 0000000..45aa303
> --- /dev/null
> +++ b/drivers/capebus/Makefile
> @@ -0,0 +1,8 @@
> +#
> +# Makefile for CAPEBUS devices
> +#
> +
> +obj-$(CONFIG_CAPEBUS)          += capebus-probe.o \
> +                                          capebus-driver.o capebus-sysfs.o
> +obj-$(CONFIG_CAPEBUS)          += boards/
> +obj-$(CONFIG_CAPEBUS)          += capes/
> diff --git a/drivers/capebus/capebus-driver.c b/drivers/capebus/capebus-driver.c
> new file mode 100644
> index 0000000..82b1d1b
> --- /dev/null
> +++ b/drivers/capebus/capebus-driver.c
> @@ -0,0 +1,608 @@
> +/*
> + * Capebus driver infrastructure
> + *
> + * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com>
> + * Copyright (C) 2012 Texas Instruments Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/device.h>
> +#include <linux/mempolicy.h>
> +#include <linux/string.h>
> +#include <linux/slab.h>
> +#include <linux/cpu.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/suspend.h>
> +
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/of_platform.h>
> +
> +#include <linux/capebus.h>
> +
> +/**
> + * capebus_match_device - Tell if a cape device structure has a
> + *                        matching cape device id structure
> + * @drv: the cape driver to match against
> + * @dev: the cape device structure to match against
> + *
> + * Used by a driver to check whether a cape device present in the
> + * system is in its list of supported devices.  Returns the matching
> + * cape_device_id structure or %NULL if there is no match.
> + */
> +static const struct cape_device_id *capebus_match_device(
> +               struct cape_driver *drv, struct cape_dev *dev)
> +{
> +       struct cape_bus *bus = dev->bus;
> +       struct cape_slot *slot = dev->slot;
> +
> +       BUG_ON(bus == NULL);
> +       BUG_ON(slot == NULL);
> +       BUG_ON(bus->ops == NULL);
> +       BUG_ON(bus->ops->get_dev_id == NULL);
> +
> +       return bus->ops->get_dev_id(slot);
> +}
> +
> +/**
> + * capebus_device_probe - check if a driver wants to claim a
> + *                          specific cape device
> + * @dev: cape device being probed
> + *
> + * returns 0 on success, else error.
> + * side-effect: cape_dev->driver is set to drv when drv claims cape_dev.
> + */
> +static int capebus_device_probe(struct device *dev)
> +{
> +       const struct cape_device_id *id;
> +       int error = 0;
> +       struct cape_driver *drv;
> +       struct cape_dev *cape_dev;
> +       struct device *parent;
> +
> +       drv = to_cape_driver(dev->driver);
> +       cape_dev = to_cape_dev(dev);
> +       cape_dev = capebus_dev_get(cape_dev);
> +
> +       /* sanity checks */
> +       if (cape_dev == NULL ||
> +               cape_dev->bus == NULL || cape_dev->bus->ops == NULL ||
> +               cape_dev->driver != NULL || drv->probe == NULL) {
> +               error = -EINVAL;
> +               goto err_no_sanity;
> +       }
> +
> +       id = capebus_match_device(drv, cape_dev);
> +       if (!id) {
> +               error = -ENODEV;
> +               goto err_no_match;
> +       }
> +
> +       /* The parent device must be in active state when probing */
> +       parent = cape_dev->dev.parent;
> +       if (parent)
> +               pm_runtime_get_sync(parent);
> +
> +       /* Unbound cape devices are always set to disabled and suspended.
> +        * During probe, the device is set to enabled and active and the
> +        * usage count is incremented.  If the driver supports runtime PM,
> +        * it should call pm_runtime_put_noidle() in its probe routine and
> +        * pm_runtime_get_noresume() in its remove routine.
> +        */
> +       pm_runtime_get_noresume(&cape_dev->dev);
> +       pm_runtime_set_active(&cape_dev->dev);
> +       pm_runtime_enable(&cape_dev->dev);
> +
> +       /* call the driver's probe method */
> +       error = drv->probe(cape_dev, id);
> +
> +       /* release the parent no matter what */
> +       if (parent)
> +               pm_runtime_put(parent);
> +
> +       if (error != 0)
> +               goto err_probe_fail;
> +
> +       /* call the probed bus method */
> +       if (cape_dev->bus->ops->dev_probed != NULL) {
> +               error = cape_dev->bus->ops->dev_probed(cape_dev);
> +               if (error != 0)
> +                       goto err_dev_probed_fail;
> +       }
> +
> +       /* all is fine... */
> +       cape_dev->driver = drv;
> +       cape_dev->added = 1;
> +
> +       return 0;
> +
> +err_dev_probed_fail:
> +       if (drv->remove) {
> +               pm_runtime_get_sync(&cape_dev->dev);
> +               drv->remove(cape_dev);
> +               pm_runtime_put_noidle(&cape_dev->dev);
> +       }
> +err_probe_fail:
> +       pm_runtime_disable(&cape_dev->dev);
> +       pm_runtime_set_suspended(&cape_dev->dev);
> +       pm_runtime_put_noidle(&cape_dev->dev);
> +err_no_match:
> +       /* nothing */
> +err_no_sanity:
> +       capebus_dev_put(cape_dev);
> +       return error;
> +}
> +
> +static int capebus_device_remove(struct device *dev)
> +{
> +       struct cape_dev *cape_dev = to_cape_dev(dev);
> +       struct cape_driver *drv = cape_dev->driver;
> +
> +       if (drv) {
> +               /* call the removed bus method (if added prev.) */
> +               if (cape_dev->added) {
> +                       BUG_ON(cape_dev->bus == NULL);
> +                       BUG_ON(cape_dev->bus->ops == NULL);
> +                       if (cape_dev->bus->ops->dev_removed)
> +                               cape_dev->bus->ops->dev_removed(cape_dev);
> +                       cape_dev->added = 0;
> +               }

Is there any case where added will not track drv?

> +               if (drv->remove) {
> +                       pm_runtime_get_sync(dev);
> +                       drv->remove(cape_dev);
> +                       pm_runtime_put_noidle(dev);
> +               }
> +               cape_dev->driver = NULL;
> +       }
> +
> +       /* Undo the runtime PM settings in local_capebus_probe() */
> +       pm_runtime_disable(dev);
> +       pm_runtime_set_suspended(dev);
> +       pm_runtime_put_noidle(dev);
> +
> +       capebus_dev_put(cape_dev);
> +       return 0;
> +}
> +
> +static void capebus_device_shutdown(struct device *dev)
> +{
> +       struct cape_dev *cape_dev = to_cape_dev(dev);
> +       struct cape_driver *drv = cape_dev->driver;
> +
> +       if (drv && drv->shutdown)
> +               drv->shutdown(cape_dev);
> +
> +       capebus_disable_device(cape_dev);
> +
> +       if (!device_may_wakeup(dev))
> +               capebus_enable_wake(cape_dev, false);
> +}
> +
> +static int capebus_bus_match(struct device *dev, struct device_driver *drv);
> +static int capebus_device_probe(struct device *dev);
> +static int capebus_device_remove(struct device *dev);
> +static void capebus_device_shutdown(struct device *dev);
> +
> +struct bus_type capebus_bus_type = {
> +       .name           = "capebus",
> +       .match          = capebus_bus_match,
> +       .probe          = capebus_device_probe,
> +       .remove         = capebus_device_remove,
> +       .shutdown       = capebus_device_shutdown,
> +       .dev_attrs      = capebus_dev_attrs,
> +       .bus_attrs      = capebus_bus_attrs,
> +       .pm             = NULL, /* No PM for now */
> +};
> +EXPORT_SYMBOL(capebus_bus_type);
> +
> +/**
> + * __capebus_register_driver - register a new capebus driver
> + * @drv: the driver structure to register
> + * @owner: owner module of drv
> + * @mod_name: module name string
> + *
> + * Adds the driver structure to the list of registered drivers.
> + * Returns a negative value on error, otherwise 0.
> + * If no error occurred, the driver remains registered even if
> + * no device was claimed during registration.
> + */
> +int __capebus_register_driver(struct cape_driver *drv, struct module *owner,
> +                         const char *mod_name)
> +{
> +       /* initialize common driver fields */
> +       drv->driver.bus = &capebus_bus_type;
> +       drv->driver.owner = owner;
> +       drv->driver.mod_name = mod_name;
> +
> +       /* register with core */
> +       return driver_register(&drv->driver);
> +}
> +EXPORT_SYMBOL(__capebus_register_driver);
> +
> +/**
> + * capebus_unregister_driver - unregister a capebus driver
> + * @drv: the driver structure to unregister
> + *
> + * Deletes the driver structure from the list of registered cape drivers,
> + * gives it a chance to clean up by calling its remove() function for
> + * each device it was responsible for, and marks those devices as
> + * driverless.
> + */
> +
> +void
> +capebus_unregister_driver(struct cape_driver *drv)
> +{
> +       /* TODO: not really working properly */
> +       driver_unregister(&drv->driver);
> +}
> +EXPORT_SYMBOL(capebus_unregister_driver);
> +
> +/**
> + * capebus_bus_match - Tell if a cape device structure has a matching
> + *                     cape device id structure
> + * @dev: the cape device structure to match against
> + * @drv: the device driver to search for matching cape device id structures
> + *
> + * Used by a driver to check whether a cape device present in the
> + * system is in its list of supported devices. Returns the matching
> + * cape_device_id structure or %NULL if there is no match.
> + */
> +static int capebus_bus_match(struct device *dev, struct device_driver *drv)
> +{
> +       struct cape_dev *cape_dev = to_cape_dev(dev);
> +       struct cape_driver *cape_drv = to_cape_driver(drv);
> +       const struct cape_device_id *found_id;
> +
> +       found_id = capebus_match_device(cape_drv, cape_dev);
> +       if (found_id)
> +               return 1;
> +
> +       return 0;
> +}
> +
> +/**
> + * capebus_dev_get - increments the reference count of the capebus
> + *                   device structure
> + * @dev: the device being referenced
> + *
> + * Each live reference to a device should be refcounted.
> + *
> + * Drivers for cape devices should normally record such references in
> + * their probe() methods, when they bind to a device, and release
> + * them by calling capebus_dev_put(), in their disconnect() methods.
> + *
> + * A pointer to the device with the incremented reference counter is returned.
> + */
> +struct cape_dev *capebus_dev_get(struct cape_dev *dev)
> +{
> +       if (dev)
> +               get_device(&dev->dev);
> +       return dev;
> +}
> +EXPORT_SYMBOL(capebus_dev_get);
> +
> +/**
> + * capebus_dev_put - release a use of the capebus device structure
> + * @dev: device that's been disconnected
> + *
> + * Must be called when a user of a device is finished with it.  When the last
> + * user of the device calls this function, the memory of the device is freed.
> + */
> +void capebus_dev_put(struct cape_dev *dev)
> +{
> +       if (dev)
> +               put_device(&dev->dev);
> +}
> +EXPORT_SYMBOL(capebus_dev_put);
> +
> +static int __init capebus_driver_init(void)
> +{
> +       return bus_register(&capebus_bus_type);
> +}
> +
> +postcore_initcall(capebus_driver_init);
> +
> +const struct of_device_id *
> +capebus_of_match_device(struct cape_dev *cdev,
> +               const char *property, const char *value)
> +{
> +       struct cape_bus *bus = cdev->bus;
> +       struct device *dev = &cdev->dev;
> +       struct device_node *pnode = cape_bus_to_parent_of_node(bus);
> +       struct device_node *node;
> +       const struct of_device_id *match;
> +       const char* cp;
> +       int cplen, l;
> +
> +       dev_dbg(dev, "Iterating on parent of node "
> +                       "name='%s' type='%s' full_name='%s'\n",
> +                       pnode->name, pnode->type, pnode->full_name);
> +
> +       match = NULL;
> +       for_each_child_of_node(pnode, node) {
> +
> +               dev->of_node = node;
> +               match = of_match_device(dev->driver->of_match_table, dev);
> +               if (!match)
> +                       goto next_node;
> +
> +               cp = of_get_property(node, property, &cplen);
> +               if (cp == NULL)
> +                       goto next_node;
> +
> +               while (cplen > 0) {
> +                       if (of_compat_cmp(cp, value, strlen(value)) == 0)
> +                               break;
> +                       l = strlen(cp) + 1;
> +                       cp += l;
> +                       cplen -= l;
> +               }
> +
> +               /* matched */
> +               if (cplen > 0)
> +                       break;
> +next_node:
> +               match = NULL;
> +               dev->of_node = NULL;
> +       }
> +
> +       if (match == NULL) {
> +               dev_dbg(dev, "Failed to find matching child-node\n");
> +               return NULL;
> +       }
> +
> +       dev_dbg(dev, "Found matching child node "
> +                       "name='%s' type='%s' "
> +                       "full_name='%s' (compatible='%s')\n",
> +               node->name, node->type, node->full_name,
> +               match->compatible);
> +
> +       return match;
> +}
> +EXPORT_SYMBOL(capebus_of_match_device);
> +
> +struct device_node *
> +capebus_of_compatible_device_property_match(struct cape_dev *dev,
> +               const struct of_device_id *matches,
> +               const char *prop, const char *prop_value)
> +{
> +       const struct of_device_id *match;
> +       struct device_node *node, *cnode;
> +       const char* cp;
> +       int cplen, l;
> +
> +       if (prop == NULL || prop_value == NULL)
> +               goto try_non_property;
> +
> +       /* at first try secondary match */
> +       for_each_child_of_node(dev->dev.of_node, node) {
> +
> +               cp = of_get_property(node, prop, &cplen);
> +               if (cp == NULL)
> +                       continue;
> +
> +               while (cplen > 0) {
> +                       if (of_compat_cmp(cp, prop_value,
> +                                               strlen(prop_value)) == 0)
> +                               break;
> +                       l = strlen(cp) + 1;
> +                       cp += l;
> +                       cplen -= l;
> +               }
> +
> +               /* not matched */
> +               if (cplen <= 0)
> +                       continue;
> +
> +               /* now iterate in the children nodes */
> +               for_each_child_of_node(node, cnode) {
> +
> +                       match = of_match_node(matches, cnode);
> +                       if (match) {
> +                               /* release reference to parent, keep this one */
> +                               of_node_put(node);
> +                               return cnode;
> +                       }
> +               }
> +       }
> +
> +try_non_property:
> +       for_each_child_of_node(dev->dev.of_node, node) {
> +
> +               match = of_match_node(matches, node);
> +               if (match)
> +                       return node;
> +       }
> +
> +       return NULL;
> +}
> +EXPORT_SYMBOL(capebus_of_compatible_device_property_match);
> +
> +struct platform_device *
> +capebus_of_platform_compatible_device_create(struct cape_dev *dev,
> +               const struct of_device_id *matches,
> +               const char *pdev_name,
> +               const char *prop, const char *prop_value)
> +{
> +       struct device_node *node;
> +       struct platform_device *pdev;
> +
> +       node = capebus_of_compatible_device_property_match(dev, matches, prop,
> +                       prop_value);
> +       if (node == NULL)
> +               return ERR_PTR(-ENXIO);
> +
> +       pdev = of_platform_device_create(node, pdev_name, dev->bus->dev.parent);
> +
> +       /* release the reference to the node */
> +       of_node_put(node);
> +       node = NULL;
> +
> +       if (pdev == NULL) {
> +               dev_err(&dev->dev, "Failed to create platform device '%s'\n",
> +                               pdev_name);
> +               return ERR_PTR(-ENODEV);
> +       }
> +
> +       return pdev;
> +}
> +EXPORT_SYMBOL(capebus_of_platform_compatible_device_create);
> +
> +struct device_node *
> +capebus_of_find_property_node(struct cape_dev *dev,
> +               const char *prop, const char *prop_value,
> +               const char *name)
> +{
> +       struct device_node *node;
> +       const char* cp;
> +       int cplen, l;
> +       struct property *pp;
> +
> +       node = NULL;
> +       if (prop == NULL || prop_value == NULL)
> +               goto find_direct;
> +
> +       /* at first try secondary match */
> +       for_each_child_of_node(dev->dev.of_node, node) {
> +
> +               cp = of_get_property(node, prop, &cplen);
> +               if (cp == NULL)
> +                       continue;
> +
> +               while (cplen > 0) {
> +                       if (of_compat_cmp(cp, prop_value,
> +                                               strlen(prop_value)) == 0)
> +                               break;
> +                       l = strlen(cp) + 1;
> +                       cp += l;
> +                       cplen -= l;
> +               }
> +
> +               /* not matched */
> +               if (cplen <= 0)
> +                       continue;
> +
> +               /* found ? */
> +               pp = of_find_property(node, name, NULL);
> +               if (pp != NULL)
> +                       return node;
> +       }
> +find_direct:
> +       pp = of_find_property(dev->dev.of_node, name, NULL);
> +       if (pp == NULL)
> +               return NULL;
> +
> +       return of_node_get(dev->dev.of_node);
> +}
> +EXPORT_SYMBOL_GPL(capebus_of_find_property_node);
> +
> +struct property *
> +capebus_of_find_property(struct cape_dev *dev,
> +               const char *prop, const char *prop_value,
> +               const char *name, int *lenp)
> +{
> +       struct device_node *node;
> +       struct property *pp;
> +
> +       node = capebus_of_find_property_node(dev, prop, prop_value, name);
> +       if (node == NULL)
> +               return NULL;
> +
> +       pp = of_find_property(node, name, lenp);
> +
> +       of_node_put(node);
> +
> +       return pp;
> +}
> +EXPORT_SYMBOL_GPL(capebus_of_find_property);
> +
> +const void *capebus_of_get_property(struct cape_dev *dev,
> +               const char *prop, const char *prop_value,
> +               const char *name, int *lenp)
> +{
> +       struct property *pp;
> +
> +       pp = capebus_of_find_property(dev, prop, prop_value, name, lenp);
> +       return pp ? pp->value : NULL;
> +}
> +EXPORT_SYMBOL_GPL(capebus_of_get_property);
> +
> +/* node exists, but it's not available? make it so */
> +int capebus_of_device_node_enable(struct device_node *node)
> +{
> +       struct property *prop;
> +       int ret;
> +
> +       prop = kzalloc(sizeof(*prop), GFP_KERNEL);
> +       if (prop == NULL)
> +               goto err_no_prop_mem;
> +
> +       prop->name = kstrdup("status", GFP_KERNEL);
> +       if (prop->name == NULL)
> +               goto err_no_name_mem;
> +
> +       prop->value = kstrdup("okay", GFP_KERNEL);
> +       if (prop->value == NULL)
> +               goto err_no_value_mem;
> +
> +       prop->length = strlen(prop->value) + 1;
> +       set_bit(OF_DYNAMIC, &prop->_flags);
> +
> +       ret = prom_update_property(node, prop);
> +       if (ret != 0)
> +               goto err_update_failed;
> +
> +       return 0;
> +
> +err_update_failed:
> +       kfree(prop->value);
> +err_no_value_mem:
> +       kfree(prop->name);
> +err_no_name_mem:
> +       kfree(prop);
> +err_no_prop_mem:
> +       return -ENOMEM;
> +}
> +EXPORT_SYMBOL_GPL(capebus_of_device_node_enable);
> +
> +/* Make sure this node is activated (even if it was disabled) */
> +int capebus_of_platform_device_enable(struct device_node *node)
> +{
> +       struct platform_device *pdev, *ppdev;
> +       int ret;
> +
> +       if (of_device_is_available(node))
> +               return 0;
> +
> +       ret = capebus_of_device_node_enable(node);
> +       if (ret != 0)
> +               return ret;
> +
> +       /* now we need to find the parent of the node */
> +       ppdev = of_find_device_by_node(node->parent);
> +
> +       pdev = of_platform_device_create(node, NULL,
> +                       ppdev ? &ppdev->dev : NULL);
> +       if (IS_ERR_OR_NULL(pdev)) {
> +               ret = pdev ? PTR_ERR(pdev) : -ENODEV;
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL_GPL(capebus_of_platform_device_enable);
> diff --git a/drivers/capebus/capebus-probe.c b/drivers/capebus/capebus-probe.c
> new file mode 100644
> index 0000000..b46e915
> --- /dev/null
> +++ b/drivers/capebus/capebus-probe.c
> @@ -0,0 +1,320 @@
> +/*
> + * Capebus bus infrastructure
> + *
> + * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com>
> + * Copyright (C) 2012 Texas Instruments Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/of_i2c.h>
> +#include <linux/of_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/err.h>
> +#include <linux/list.h>
> +#include <linux/mutex.h>
> +#include <linux/slab.h>
> +
> +#include <linux/capebus.h>
> +
> +LIST_HEAD(cape_buses);
> +EXPORT_SYMBOL(cape_buses);
> +
> +DEFINE_MUTEX(cape_buses_mutex);
> +EXPORT_SYMBOL(cape_buses_mutex);
> +
> +/*
> + * Cape Bus Class
> + */
> +static void release_capebus_dev(struct device *dev)
> +{
> +       struct cape_dev *cape_dev = to_cape_dev(dev);
> +
> +       kfree(cape_dev);
> +}
> +
> +static struct class capebus_class = {
> +       .name           = "capebus",
> +       .dev_release    = &release_capebus_dev,
> +};
> +
> +static int __init capebus_class_init(void)
> +{
> +       return class_register(&capebus_class);
> +}
> +postcore_initcall(capebus_class_init);
> +
> +static struct cape_bus *cape_bus_find(const char *name, int busno)
> +{
> +       struct cape_bus *bus;
> +       int found;
> +
> +       if (busno < 0)
> +               return NULL;
> +
> +       found = 0;
> +       cape_bus_for_each(bus) {
> +               if (strcmp(name, bus->name) == 0 && bus->busno == busno) {
> +                       found = 1;
> +                       break;
> +               }
> +       }
> +       return found ? bus : NULL;
> +}
> +
> +static int cape_bus_pick_busno(const char *name, int busno)
> +{
> +       struct cape_bus *bus;
> +
> +       BUG_ON(name == NULL);
> +
> +       /* fixed id */
> +       if (busno >= 0)
> +               return busno;
> +
> +       /* dynamic id */
> +       busno = -1;
> +       cape_bus_for_each(bus) {
> +               /* name must match */
> +               if (strcmp(name, bus->name) != 0)
> +                       continue;
> +               busno = max(busno, bus->busno);
> +       }
> +       return busno + 1;
> +}
> +
> +int cape_bus_register(struct cape_bus *bus, const char *name, int busno,
> +               struct device *parent, struct cape_bus_ops *ops)
> +{
> +       struct cape_bus *b2;
> +       int r;
> +
> +       if (name == NULL)
> +               return -EINVAL;
> +
> +       INIT_LIST_HEAD(&bus->node);
> +       INIT_LIST_HEAD(&bus->devices);
> +       INIT_LIST_HEAD(&bus->slots);
> +
> +       /* do everything under lock */
> +       mutex_lock(&cape_buses_mutex);
> +
> +       b2 = cape_bus_find(name, busno);
> +       if (b2 != NULL) {
> +               if (parent != NULL)
> +                       dev_err(parent, "capebus %s:%d in use\n", name, busno);
> +               else
> +                       pr_err("capebus %s:%d in use\n", name, busno);
> +               r = -EBUSY;
> +               goto err_unlock;
> +       }
> +       bus->name = name;
> +       bus->busno = cape_bus_pick_busno(name, busno);
> +       bus->ops = ops;
> +
> +       bus->dev.class = &capebus_class;
> +       bus->dev.parent = parent;
> +       dev_set_name(&bus->dev, "%s:%d", bus->name, bus->busno);
> +       r = device_register(&bus->dev);
> +       if (r != 0) {
> +               if (parent != NULL)
> +                       dev_err(parent, "capebus #%d failed to register dev\n",
> +                                       bus->busno);
> +               else
> +                       pr_err("capebus #%d failed to register dev\n",
> +                                       bus->busno);
> +               goto err_unlock;
> +       }
> +
> +       list_add_tail(&bus->node, &cape_buses);
> +       mutex_unlock(&cape_buses_mutex);
> +
> +       dev_info(&bus->dev, "Registered\n");
> +
> +       return 0;
> +err_unlock:
> +       mutex_unlock(&cape_buses_mutex);
> +       return r;
> +}
> +
> +int cape_bus_deregister(struct cape_bus *bus)
> +{
> +       return -EINVAL; /* not yet supported */
> +}
> +
> +/* must have cape_buses_mutex */
> +struct cape_slot *cape_slot_find(struct cape_bus *bus, int slotno)
> +{
> +       struct cape_slot *slot;
> +       int found;
> +
> +       found = 0;
> +       cape_slot_for_each(bus, slot) {
> +               if (slot->slotno == slotno) {
> +                       found = 1;
> +                       break;
> +               }
> +       }
> +       return found ? slot : NULL;
> +}
> +
> +/**
> + * cape_bus_release_dev - free a cape device structure when all users
> + *                        of it are finished.
> + * @dev: device that's been disconnected
> + *
> + * Will be called only by the device core when all users of this cape device are
> + * done.
> + */
> +static void cape_bus_release_dev(struct device *dev)
> +{
> +       struct cape_dev *cdev;
> +
> +       cdev = to_cape_dev(dev);
> +       /* cape_release_capabilities(cdev); TODO */
> +       /* cape_release_of_node(cdev); TODO */
> +       kfree(cdev);
> +}
> +
> +/* mutex lock must be held */
> +static struct cape_dev *cape_bus_scan_slot(struct cape_slot *slot)
> +{
> +       struct cape_bus *bus = slot->bus;
> +       struct cape_dev *dev;
> +       const struct cape_device_id *id;
> +
> +       /* get the ID (if a device exists) */
> +       id = bus->ops->get_dev_id(slot);
> +       if (id == NULL)
> +               return ERR_PTR(-ENODEV);
> +
> +       /* slot must not have a device yet */
> +       dev = slot->dev;
> +       if (dev == NULL) {
> +               dev = kzalloc(sizeof(*dev), GFP_KERNEL);
> +               if (dev == NULL) {
> +                       dev_info(&bus->dev, "Failed to allocate cape device "
> +                                       "for slot #%d\n", slot->slotno);
> +                       return ERR_PTR(-ENOMEM);
> +               }
> +
> +               INIT_LIST_HEAD(&dev->bus_list);
> +               dev->bus = bus;
> +               dev->slot = slot;
> +       }
> +
> +       dev->id = id;
> +       dev->text_id = bus->ops->get_text_dev_id(slot);
> +
> +       /* capebus_set_of_node(dev); TODO */
> +
> +       return dev;
> +}
> +
> +int cape_bus_scan_one_slot(struct cape_bus *bus, struct cape_slot *slot)
> +{
> +       struct cape_dev *dev;
> +       int r;
> +
> +       mutex_lock(&cape_buses_mutex);
> +
> +       dev = slot->dev;
> +       if (dev == NULL) {
> +
> +               dev = cape_bus_scan_slot(slot);
> +               if (IS_ERR(dev)) {
> +                       r = PTR_ERR(dev);
> +                       goto err_out;
> +               }
> +
> +               dev_info(&bus->dev, "Slot #%d id='%s'\n", slot->slotno,
> +                               dev->text_id ? dev->text_id : "");
> +
> +               slot->dev = dev;
> +
> +               dev->dev.release = cape_bus_release_dev;
> +               dev->dev.parent = &dev->bus->dev;
> +               dev->dev.bus = &capebus_bus_type;
> +               dev_set_name(&dev->dev, "%s-%d:%d",
> +                            dev->bus->name, dev->bus->busno,
> +                            dev->slot->slotno);
> +
> +               list_add_tail(&dev->bus_list, &bus->devices);
> +
> +       } else {
> +               dev_info(&bus->dev, "Slot #%d id='%s' - rescan\n", slot->slotno,
> +                               dev->text_id ? dev->text_id : "");
> +
> +               if (dev->added) {
> +                       r = -EEXIST;
> +                       goto err_out;
> +               }
> +       }
> +
> +       r = device_register(&dev->dev);
> +       if (r != 0) {
> +               dev_info(&bus->dev, "Slot #%d id='%s' - "
> +                               "Failed to register\n",
> +                               slot->slotno,
> +                               dev->text_id ? dev->text_id : "");
> +               r = 0;
> +       } else {
> +               if (dev->bus->ops->dev_registered)
> +                       dev->bus->ops->dev_registered(dev);
> +       }
> +
> +err_out:
> +       mutex_unlock(&cape_buses_mutex);
> +
> +       return r;
> +}
> +
> +int cape_bus_register_slot(struct cape_bus *bus, struct cape_slot *slot,
> +               int slotno)
> +{
> +       struct cape_slot *s2;
> +       int r;
> +
> +       r = 0;
> +
> +       /* invalid (slot must always be numbered - no hotplug) */
> +       if (slotno < 0) {
> +               dev_err(&bus->dev, "Slot registration #%d failed\n", slotno);
> +               return -EINVAL;
> +       }
> +
> +       mutex_lock(&cape_buses_mutex);
> +       s2 = cape_slot_find(bus, slotno);
> +       if (s2 != NULL) {
> +               dev_err(&bus->dev, "Slot #%d already exists\n", slotno);
> +               mutex_unlock(&cape_buses_mutex);
> +               return -EINVAL;
> +       }
> +
> +       INIT_LIST_HEAD(&slot->node);
> +       slot->bus = bus;
> +       list_add(&slot->node, &bus->slots);
> +       slot->slotno = slotno;
> +       slot->dev = NULL;
> +       mutex_unlock(&cape_buses_mutex);
> +
> +       dev_info(&bus->dev, "Slot #%d registered\n", slot->slotno);
> +
> +       return cape_bus_scan_one_slot(bus, slot);
> +}
> diff --git a/drivers/capebus/capebus-sysfs.c b/drivers/capebus/capebus-sysfs.c
> new file mode 100644
> index 0000000..81c21fe
> --- /dev/null
> +++ b/drivers/capebus/capebus-sysfs.c
> @@ -0,0 +1,52 @@
> +/*
> + * drivers/capebus/capebus-sysfs.c
> + *
> + * sysfs for capebus devices
> + *
> + * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com>
> + * Copyright (C) 2012 Texas Instruments Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + *
> + * Modeled after PCI's pci-sysfs.c
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/stat.h>
> +#include <linux/export.h>
> +#include <linux/fs.h>
> +#include <linux/slab.h>
> +#include <linux/pm_runtime.h>
> +
> +#include <linux/capebus.h>
> +
> +static ssize_t id_show(struct device *dev,
> +                              struct device_attribute *attr, char *buf)
> +{
> +       struct cape_dev *cdev;
> +
> +       cdev = to_cape_dev(dev);
> +       return sprintf(buf, "%s\n", cdev->text_id);
> +}
> +
> +struct device_attribute capebus_dev_attrs[] = {
> +       __ATTR_RO(id),
> +       __ATTR_NULL,
> +};
> +
> +struct bus_attribute capebus_bus_attrs[] = {
> +       __ATTR_NULL
> +};
> diff --git a/include/linux/capebus.h b/include/linux/capebus.h
> new file mode 100644
> index 0000000..7524401
> --- /dev/null
> +++ b/include/linux/capebus.h
> @@ -0,0 +1,298 @@
> +/*
> + * capebus.h
> + *
> + * Cape bus defines and function prototypes
> + *
> + * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com>
> + * Copyright (C) 2012 Texas Instruments Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +#ifndef LINUX_CAPEBUS_H
> +#define LINUX_CAPEBUS_H
> +
> +#include <linux/list.h>
> +#include <linux/device.h>
> +#include <linux/spinlock.h>
> +#include <linux/types.h>
> +#include <linux/atomic.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +
> +struct cape_device_id {
> +       const char *cntrlboard; /* controlling board; i.e. "beaglebone" */
> +       int len;                /* opaque addressing data */
> +       const void *data;
> +};
> +
> +struct cape_dev;
> +struct cape_bus;
> +struct cape_slot;
> +
> +struct cape_slot {
> +       struct list_head        node;
> +       struct cape_bus         *bus;   /* the bus this slot is on */
> +       int                     slotno; /* index of this slot */
> +       struct cape_dev         *dev;   /* the device (if found) */
> +};
> +
> +struct cape_driver {
> +       struct list_head node;
> +       int (*probe)(struct cape_dev *dev, const struct cape_device_id *id);
> +       void (*remove)(struct cape_dev *dev);
> +       int  (*suspend) (struct cape_dev *dev, pm_message_t state);
> +       int  (*suspend_late) (struct cape_dev *dev, pm_message_t state);
> +       int  (*resume_early) (struct cape_dev *dev);
> +       int  (*resume) (struct cape_dev *dev);
> +       void (*shutdown) (struct cape_dev *dev);
> +       struct device_driver driver;
> +};
> +
> +/*
> + * capebus_register_driver must be a macro so that
> + * KBUILD_MODNAME can be expanded
> + */
> +#define capebus_register_driver(driver)                \
> +       __capebus_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
> +
> +int __capebus_register_driver(struct cape_driver *drv, struct module *owner,
> +                         const char *mod_name);
> +
> +void capebus_unregister_driver(struct cape_driver *dev);
> +
> +/**
> + * module_capebus_driver() - Helper macro for registering a capebus driver
> + * @__capebus_driver: capebus_driver struct
> + *
> + * Helper macro for capebus drivers which do not do anything special in module
> + * init/exit. This eliminates a lot of boilerplate. Each module may only
> + * use this macro once, and calling it replaces module_init() and module_exit()
> + */
> +#define module_capebus_driver(__capebus_driver) \
> +       module_driver(__capebus_driver, capebus_register_driver, \
> +                      capebus_unregister_driver)
> +
> +#define        to_cape_driver(n) container_of(n, struct cape_driver, driver)
> +
> +struct cape_bus_ops {
> +       const struct cape_device_id *(*get_dev_id)(struct cape_slot *slot);
> +       const char *(*get_text_dev_id)(struct cape_slot *slot);
> +       int (*dev_probed)(struct cape_dev *dev);        /* probed succesfully */
> +       void (*dev_removed)(struct cape_dev *dev);      /* removed */
> +       int (*dev_registered)(struct cape_dev *dev);    /* registered OK */
> +};
> +
> +struct cape_bus {
> +       struct list_head        node;
> +       const char              *name;
> +       struct list_head        devices;
> +       struct cape_dev         *self;
> +       struct list_head        slots;
> +       struct cape_bus_ops     *ops;
> +       int                     busno;
> +       struct device           dev;
> +       /* TODO: resources.... */
> +};
> +
> +#define        to_cape_bus(n) container_of(n, struct cape_bus, dev)
> +
> +#define cape_bus_to_parent_of_node(n) ((n)->dev.parent->of_node)
> +
> +struct cape_dev {
> +       struct list_head        bus_list;       /* node in per-bus list     */
> +       struct cape_bus         *bus;           /* bus this device is on    */
> +       struct cape_slot        *slot;          /* cape slot of this device */
> +       struct cape_driver      *driver;        /* driver of this device    */
> +       struct device           dev;
> +       atomic_t                enable_cnt;     /* capebus_enable_device    */
> +                                               /* has been called          */
> +       const struct cape_device_id *id;
> +       const char              *text_id;
> +       unsigned int            added : 1;      /* device has been added    */
> +       void                    *drv_priv;      /* driver private data      */
> +};
> +
> +#define        to_cape_dev(n) container_of(n, struct cape_dev, dev)
> +
> +struct cape_dev *capebus_dev_get(struct cape_dev *dev);
> +void capebus_dev_put(struct cape_dev *dev);
> +
> +/* must have cape_buses_mutex */
> +#define cape_bus_for_each(_bus) \
> +       list_for_each_entry(_bus, &cape_buses, node)
> +
> +#define cape_bus_for_each_safe(_bus, _busn) \
> +       list_for_each_entry_safe(_bus, _busn, &cape_buses, node)
> +
> +int cape_bus_register(struct cape_bus *bus, const char *name, int busno,
> +               struct device *parent, struct cape_bus_ops *ops);
> +
> +/* must have cape_buses_mutex */
> +#define cape_slot_for_each(_bus, _slot) \
> +       list_for_each_entry(_slot, &(_bus)->slots, node)
> +
> +#define cape_slot_for_each_safe(_bus, _slot, _slotn) \
> +       list_for_each_entry_safe(_slot, _slotn, &(_bus)->slots, node)
> +
> +int cape_bus_register_slot(struct cape_bus *bus,
> +               struct cape_slot *slot, int slotno);
> +
> +int cape_bus_scan_one_slot(struct cape_bus *bus, struct cape_slot *slot);
> +int cape_bus_scan(struct cape_bus *bus);
> +
> +extern struct list_head cape_buses;
> +extern struct mutex cape_buses_mutex;
> +
> +static inline int capebus_is_enabled(struct cape_dev *cdev)
> +{
> +       return atomic_read(&cdev->enable_cnt) > 0;
> +}
> +
> +static inline int capebus_enable_device(struct cape_dev *cdev)
> +{
> +       if (atomic_add_return(1, &cdev->enable_cnt) > 1)
> +               return 0;               /* already enabled */
> +
> +       /* XXX do enable */
> +
> +       return 0;
> +}
> +
> +static inline void capebus_disable_device(struct cape_dev *cdev)
> +{
> +       if (atomic_sub_return(1, &cdev->enable_cnt) != 0)
> +               return;
> +
> +       /* callback to disable device? */
> +}
> +
> +static inline int capebus_enable_wake(struct cape_dev *dev, int what)
> +{
> +       return 0;
> +}
> +
> +extern struct device_attribute capebus_dev_attrs[];
> +extern struct bus_attribute capebus_bus_attrs[];
> +
> +extern struct bus_type capebus_bus_type;
> +
> +const struct of_device_id *
> +capebus_of_match_device(struct cape_dev *cdev,
> +               const char *property, const char *value);
> +
> +struct device_node *
> +capebus_of_compatible_device_property_match(struct cape_dev *dev,
> +               const struct of_device_id *matches,
> +               const char *prop, const char *prop_value);
> +
> +struct platform_device *
> +capebus_of_platform_compatible_device_create(struct cape_dev *dev,
> +               const struct of_device_id *matches,
> +               const char *pdev_name,
> +               const char *prop, const char *prop_value);
> +
> +/* of tree support */
> +
> +struct device_node *
> +capebus_of_find_property_node(struct cape_dev *dev,
> +               const char *prop, const char *prop_value,
> +               const char *name);
> +
> +struct property *
> +capebus_of_find_property(struct cape_dev *dev,
> +               const char *prop, const char *prop_value,
> +               const char *name, int *lenp);
> +
> +const void *capebus_of_get_property(struct cape_dev *dev,
> +               const char *prop, const char *prop_value,
> +               const char *name, int *lenp);
> +
> +static inline int capebus_of_property_read_u32_array(struct cape_dev *dev,
> +               const char *prop, const char *prop_value,
> +               const char *name, u32 *out_values, size_t sz)
> +{
> +       struct device_node *node;
> +       int ret;
> +
> +       node = capebus_of_find_property_node(dev, prop, prop_value, name);
> +       ret = of_property_read_u32_array(node, name, out_values, sz);
> +       of_node_put(node);
> +       return ret;
> +}
> +
> +static inline int capebus_of_property_read_u32(struct cape_dev *dev,
> +               const char *prop, const char *prop_value,
> +              const char *name, u32 *out_value)
> +{
> +       return capebus_of_property_read_u32_array(dev, prop,
> +                       prop_value, name, out_value, 1);
> +}
> +
> +static inline bool capebus_of_property_read_bool(struct cape_dev *dev,
> +               const char *prop, const char *prop_value,
> +               const char *name)
> +{
> +       struct device_node *node;
> +       bool ret;
> +
> +       node = capebus_of_find_property_node(dev, prop, prop_value, name);
> +       ret = of_property_read_bool(node, name);
> +       of_node_put(node);
> +       return ret;
> +}
> +
> +static inline int capebus_of_property_read_string(struct cape_dev *dev,
> +               const char *prop, const char *prop_value,
> +               const char *name, const char **out_string)
> +{
> +       struct device_node *node;
> +       int ret;
> +
> +       node = capebus_of_find_property_node(dev, prop, prop_value, name);
> +       ret = of_property_read_string(node, name, out_string);
> +       of_node_put(node);
> +       return ret;
> +}
> +
> +static inline int capebus_of_property_read_string_index(struct cape_dev *dev,
> +               const char *prop, const char *prop_value,
> +               const char *name, int index, const char **out_string)
> +{
> +       struct device_node *node;
> +       int ret;
> +
> +       node = capebus_of_find_property_node(dev, prop, prop_value, name);
> +       ret = of_property_read_string_index(node, name, index, out_string);
> +       of_node_put(node);
> +       return ret;
> +}
> +
> +static inline int capebus_of_property_read_u64(struct cape_dev *dev,
> +               const char *prop, const char *prop_value,
> +               const char *name, u64 *out_value)
> +{
> +       struct device_node *node;
> +       int ret;
> +
> +       node = capebus_of_find_property_node(dev, prop, prop_value, name);
> +       ret = of_property_read_u64(node, name, out_value);
> +       of_node_put(node);
> +       return ret;
> +}
> +
> +int capebus_of_device_node_enable(struct device_node *node);
> +int capebus_of_platform_device_enable(struct device_node *node);
> +
> +#endif
> --
> 1.7.12
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox