Skip to contentSkip to conversation

Add device tree support for gpio-mxs

PATCH New Shawn Guo 3 participants 7 messages May 4, 2012 – May 18, 2012

Subsystems (5)
lore
Share & tools
lore

Shawn Guo

author
#0 lore raw

cover Add device tree support for gpio-mxs

This patch series cleans up gpio-mxs a bit, and then adds device tree support for the driver. Currently, the irqdomain for gpio is still added in platform code, and should be moved into driver later with the help from the generic-irq-chip irqdomain support.

It's based on mxs device tree branch, and might be easier to go via arm-soc tree.

Shawn Guo (4):
gpio/mxs: use devm_* helpers to make error handling simple gpio/mxs: get rid of the use of cpu_is_xxx gpio/mxs: add device tree probe
ARM: mxs: add gpio support for device tree boot

 .../devicetree/bindings/gpio/gpio-mxs.txt          |   87 +++++++++++
 arch/arm/boot/dts/imx23.dtsi                       |   35 +++++-
 arch/arm/boot/dts/imx28.dtsi                       |   55 +++++++-
 arch/arm/mach-mxs/devices/platform-gpio-mxs.c      |   24 +---
 arch/arm/mach-mxs/include/mach/common.h            |    5 +-
 arch/arm/mach-mxs/mach-mxs.c                       |   12 ++
 arch/arm/mach-mxs/mm.c                             |   10 ++
 drivers/gpio/gpio-mxs.c                            |  156 ++++++++++++--------
 8 files changed, 296 insertions(+), 88 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/gpio/gpio-mxs.txt
Signature · 1 line
1.7.5.4
author
#1 lore raw

PATCH 1/4 gpio/mxs: use devm_* helpers to make error handling simple

It uses devm_* helpers to make the error handling of probe clean and simple.

---
 drivers/gpio/gpio-mxs.c |   52 +++++++++++-----------------------------------
 1 files changed, 13 insertions(+), 39 deletions(-)
drivers/gpio/gpio-mxs.c +13 -39
index 385c58e..95a11db 100644
@@ -186,44 +186,29 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev)
 	struct resource *iores = NULL;
 	int err;
 
-	port = kzalloc(sizeof(struct mxs_gpio_port), GFP_KERNEL);
+	port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
 	if (!port)
 		return -ENOMEM;
 
 	port->id = pdev->id;
 	port->virtual_irq_start = MXS_GPIO_IRQ_START + port->id * 32;
 
+	port->irq = platform_get_irq(pdev, 0);
+	if (port->irq < 0)
+		return port->irq;
+
 	/*
 	 * map memory region only once, as all the gpio ports
 	 * share the same one
 	 */
 	if (!base) {
 		iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-		if (!iores) {
-			err = -ENODEV;
-			goto out_kfree;
-		}
-
-		if (!request_mem_region(iores->start, resource_size(iores),
-					pdev->name)) {
-			err = -EBUSY;
-			goto out_kfree;
-		}
-
-		base = ioremap(iores->start, resource_size(iores));
-		if (!base) {
-			err = -ENOMEM;
-			goto out_release_mem;
-		}
+		base = devm_request_and_ioremap(&pdev->dev, iores);
+		if (!base)
+			return -EADDRNOTAVAIL;
 	}
 	port->base = base;
 
-	port->irq = platform_get_irq(pdev, 0);
-	if (port->irq < 0) {
-		err = -EINVAL;
-		goto out_iounmap;
-	}
-
 	/*
 	 * select the pin interrupt functionality but initially
 	 * disable the interrupts
@@ -246,29 +231,18 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev)
 			 port->base + PINCTRL_DOUT(port->id), NULL,
 			 port->base + PINCTRL_DOE(port->id), NULL, false);
 	if (err)
-		goto out_iounmap;
+		return err;
 
 	port->bgc.gc.to_irq = mxs_gpio_to_irq;
 	port->bgc.gc.base = port->id * 32;
 
 	err = gpiochip_add(&port->bgc.gc);
-	if (err)
-		goto out_bgpio_remove;
+	if (err) {
+		bgpio_remove(&port->bgc);
+		return err;
+	}
 
 	return 0;
-
-out_bgpio_remove:
-	bgpio_remove(&port->bgc);
-out_iounmap:
-	if (iores)
-		iounmap(port->base);
-out_release_mem:
-	if (iores)
-		release_mem_region(iores->start, resource_size(iores));
-out_kfree:
-	kfree(port);
-	dev_info(&pdev->dev, "%s failed with errno %d\n", __func__, err);
-	return err;
 }
 
 static struct platform_driver mxs_gpio_driver = {
Signature · 1 line
1.7.5.4
author
#2 lore raw

PATCH 2/4 gpio/mxs: get rid of the use of cpu_is_xxx

In reply to Shawn Guo

It removes the use of cpu_is_xxx from gpio-mxs driver and instead use platform_device_id to identify the device. Accordingly, mxs platform code is changed to register gpio device with different names, and the registeration are done in soc specific initialization functions now, so postcore_initcall(mxs_add_mxs_gpio) gets removed.

---
 arch/arm/mach-mxs/devices/platform-gpio-mxs.c |   24 +-------
 arch/arm/mach-mxs/include/mach/common.h       |    5 +-
 arch/arm/mach-mxs/mm.c                        |   10 +++
 drivers/gpio/gpio-mxs.c                       |   74 +++++++++++++++++-------
 4 files changed, 67 insertions(+), 46 deletions(-)
arch/arm/mach-mxs/devices/platform-gpio-mxs.c +2 -22
index ed0885e..cd99f19 100644
@@ -14,7 +14,7 @@
 #include <mach/devices-common.h>
 
 struct platform_device *__init mxs_add_gpio(
-	int id, resource_size_t iobase, int irq)
+	char *name, int id, resource_size_t iobase, int irq)
 {
 	struct resource res[] = {
 		{
@@ -29,25 +29,5 @@ struct platform_device *__init mxs_add_gpio(
 	};
 
 	return platform_device_register_resndata(&mxs_apbh_bus,
-			"gpio-mxs", id, res, ARRAY_SIZE(res), NULL, 0);
+			name, id, res, ARRAY_SIZE(res), NULL, 0);
 }
-
-static int __init mxs_add_mxs_gpio(void)
-{
-	if (cpu_is_mx23()) {
-		mxs_add_gpio(0, MX23_PINCTRL_BASE_ADDR, MX23_INT_GPIO0);
-		mxs_add_gpio(1, MX23_PINCTRL_BASE_ADDR, MX23_INT_GPIO1);
-		mxs_add_gpio(2, MX23_PINCTRL_BASE_ADDR, MX23_INT_GPIO2);
-	}
-
-	if (cpu_is_mx28()) {
-		mxs_add_gpio(0, MX28_PINCTRL_BASE_ADDR, MX28_INT_GPIO0);
-		mxs_add_gpio(1, MX28_PINCTRL_BASE_ADDR, MX28_INT_GPIO1);
-		mxs_add_gpio(2, MX28_PINCTRL_BASE_ADDR, MX28_INT_GPIO2);
-		mxs_add_gpio(3, MX28_PINCTRL_BASE_ADDR, MX28_INT_GPIO3);
-		mxs_add_gpio(4, MX28_PINCTRL_BASE_ADDR, MX28_INT_GPIO4);
-	}
-
-	return 0;
-}
-postcore_initcall(mxs_add_mxs_gpio);
arch/arm/mach-mxs/include/mach/common.h +3 -2
index b212553..cc4a417 100644
@@ -20,13 +20,11 @@ extern void mxs_restart(char, const char *);
 extern int mxs_saif_clkmux_select(unsigned int clkmux);
 
 extern void mx23_soc_init(void);
-extern int mx23_register_gpios(void);
 extern int mx23_clocks_init(void);
 extern void mx23_map_io(void);
 extern void mx23_init_irq(void);
 
 extern void mx28_soc_init(void);
-extern int mx28_register_gpios(void);
 extern int mx28_clocks_init(void);
 extern void mx28_map_io(void);
 extern void mx28_init_irq(void);
@@ -37,4 +35,7 @@ extern int mxs_clkctrl_timeout(unsigned int reg_offset, unsigned int mask);
 
 extern struct platform_device *mxs_add_dma(const char *devid,
 						resource_size_t base);
+extern struct platform_device *mxs_add_gpio(char *name, int id,
+					    resource_size_t iobase, int irq);
+
 #endif /* __MACH_MXS_COMMON_H__ */
arch/arm/mach-mxs/mm.c +10 -0
index 6a1acad..478696e 100644
@@ -66,10 +66,20 @@ void __init mx23_soc_init(void)
 {
 	mxs_add_dma("imx23-dma-apbh", MX23_APBH_DMA_BASE_ADDR);
 	mxs_add_dma("imx23-dma-apbx", MX23_APBX_DMA_BASE_ADDR);
+
+	mxs_add_gpio("imx23-gpio", 0, MX23_PINCTRL_BASE_ADDR, MX23_INT_GPIO0);
+	mxs_add_gpio("imx23-gpio", 1, MX23_PINCTRL_BASE_ADDR, MX23_INT_GPIO1);
+	mxs_add_gpio("imx23-gpio", 2, MX23_PINCTRL_BASE_ADDR, MX23_INT_GPIO2);
 }
 
 void __init mx28_soc_init(void)
 {
 	mxs_add_dma("imx28-dma-apbh", MX23_APBH_DMA_BASE_ADDR);
 	mxs_add_dma("imx28-dma-apbx", MX23_APBX_DMA_BASE_ADDR);
+
+	mxs_add_gpio("imx28-gpio", 0, MX28_PINCTRL_BASE_ADDR, MX28_INT_GPIO0);
+	mxs_add_gpio("imx28-gpio", 1, MX28_PINCTRL_BASE_ADDR, MX28_INT_GPIO1);
+	mxs_add_gpio("imx28-gpio", 2, MX28_PINCTRL_BASE_ADDR, MX28_INT_GPIO2);
+	mxs_add_gpio("imx28-gpio", 3, MX28_PINCTRL_BASE_ADDR, MX28_INT_GPIO3);
+	mxs_add_gpio("imx28-gpio", 4, MX28_PINCTRL_BASE_ADDR, MX28_INT_GPIO4);
 }
drivers/gpio/gpio-mxs.c +52 -22

160 lines not on this page · raw message

Signature · 1 line
1.7.5.4
author
#3 lore raw

PATCH 3/4 gpio/mxs: add device tree probe

In reply to Shawn Guo

It adds device tree probe for gpio-mxs driver.

---
 .../devicetree/bindings/gpio/gpio-mxs.txt          |   87 ++++++++++++++++++++
 drivers/gpio/gpio-mxs.c                            |   36 +++++++-
 2 files changed, 119 insertions(+), 4 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/gpio/gpio-mxs.txt
Documentation/devicetree/bindings/gpio/gpio-mxs.txt new file +87 -0
new file mode 100644
index 0000000..0c35673
@@ -0,0 +1,87 @@
+* Freescale MXS GPIO controller
+
+The Freescale MXS GPIO controller is part of MXS PIN controller.  The
+GPIOs are organized in port/bank.  Each port consists of 32 GPIOs.
+
+As the GPIO controller is embedded in the PIN controller and all the
+GPIO ports share the same IO space with PIN controller, the GPIO node
+will be represented as sub-nodes of MXS pinctrl node.
+
+Required properties for GPIO node:
+- compatible : Should be "fsl,<soc>-gpio".  The supported SoCs include
+  imx23 and imx28.
+- interrupts : Should be the port interrupt shared by all 32 pins.
+- gpio-controller : Marks the device node as a gpio controller.
+- #gpio-cells : Should be two.  The first cell is the pin number and
+  the second cell is used to specify optional parameters (currently
+  unused).
+- interrupt-controller: Marks the device node as an interrupt controller.
+- #interrupt-cells : Should be 2.  The first cell is the GPIO number.
+  The second cell bits[3:0] is used to specify trigger type and level flags:
+      1 = low-to-high edge triggered.
+      2 = high-to-low edge triggered.
+      4 = active high level-sensitive.
+      8 = active low level-sensitive.
+
+Note: Each GPIO port should have an alias correctly numbered in "aliases"
+node.
+
+Examples:
+
+aliases {
+	gpio0 = &gpio0;
+	gpio1 = &gpio1;
+	gpio2 = &gpio2;
+	gpio3 = &gpio3;
+	gpio4 = &gpio4;
+};
+
+pinctrl at 80018000 {
+	compatible = "fsl,imx28-pinctrl", "simple-bus";
+	reg = <0x80018000 2000>;
+
+	gpio0: gpio at 0 {
+		compatible = "fsl,imx28-gpio";
+		interrupts = <127>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpio1: gpio at 1 {
+		compatible = "fsl,imx28-gpio";
+		interrupts = <126>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpio2: gpio at 2 {
+		compatible = "fsl,imx28-gpio";
+		interrupts = <125>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpio3: gpio at 3 {
+		compatible = "fsl,imx28-gpio";
+		interrupts = <124>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpio4: gpio at 4 {
+		compatible = "fsl,imx28-gpio";
+		interrupts = <123>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+};
drivers/gpio/gpio-mxs.c +32 -4
index 38ae56f..429228b 100644
@@ -25,6 +25,9 @@
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/basic_mmio_gpio.h>
@@ -207,8 +210,19 @@ static struct platform_device_id mxs_gpio_ids[] = {
 };
 MODULE_DEVICE_TABLE(platform, mxs_gpio_ids);
 
+static const struct of_device_id mxs_gpio_dt_ids[] = {
+	{ .compatible = "fsl,imx23-gpio", .data = (void *) IMX23_GPIO, },
+	{ .compatible = "fsl,imx28-gpio", .data = (void *) IMX28_GPIO, },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxs_gpio_dt_ids);
+
 static int __devinit mxs_gpio_probe(struct platform_device *pdev)
 {
+	const struct of_device_id *of_id =
+			of_match_device(mxs_gpio_dt_ids, &pdev->dev);
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *parent;
 	static void __iomem *base;
 	struct mxs_gpio_port *port;
 	struct resource *iores = NULL;
@@ -218,8 +232,15 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev)
 	if (!port)
 		return -ENOMEM;
 
-	port->id = pdev->id;
-	port->devid = pdev->id_entry->driver_data;
+	if (np) {
+		port->id = of_alias_get_id(np, "gpio");
+		if (port->id < 0)
+			return port->id;
+		port->devid = (enum mxs_gpio_id) of_id->data;
+	} else {
+		port->id = pdev->id;
+		port->devid = pdev->id_entry->driver_data;
+	}
 	port->virtual_irq_start = MXS_GPIO_IRQ_START + port->id * 32;
 
 	port->irq = platform_get_irq(pdev, 0);
@@ -231,8 +252,14 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev)
 	 * share the same one
 	 */
 	if (!base) {
-		iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-		base = devm_request_and_ioremap(&pdev->dev, iores);
+		if (np) {
+			parent = of_get_parent(np);
+			base = of_iomap(parent, 0);
+			of_node_put(parent);
+		} else {
+			iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+			base = devm_request_and_ioremap(&pdev->dev, iores);
+		}
 		if (!base)
 			return -EADDRNOTAVAIL;
 	}
@@ -278,6 +305,7 @@ static struct platform_driver mxs_gpio_driver = {
 	.driver		= {
 		.name	= "gpio-mxs",
 		.owner	= THIS_MODULE,
+		.of_match_table = mxs_gpio_dt_ids,
 	},
 	.probe		= mxs_gpio_probe,
 	.id_table	= mxs_gpio_ids,
Signature · 1 line
1.7.5.4
author
#4 lore raw

PATCH 4/4 ARM: mxs: add gpio support for device tree boot

In reply to Shawn Guo

It adds gpio support for device tree boot.

---
 arch/arm/boot/dts/imx23.dtsi |   35 ++++++++++++++++++++++++++-
 arch/arm/boot/dts/imx28.dtsi |   55 +++++++++++++++++++++++++++++++++++++++++-
 arch/arm/mach-mxs/mach-mxs.c |   12 +++++++++
 3 files changed, 100 insertions(+), 2 deletions(-)
arch/arm/boot/dts/imx23.dtsi +34 -1
index 7761ed0..8c83bc4 100644
@@ -14,6 +14,12 @@
 / {
 	interrupt-parent = <&icoll>;
 
+	aliases {
+		gpio0 = &gpio0;
+		gpio1 = &gpio1;
+		gpio2 = &gpio2;
+	};
+
 	cpus {
 		cpu at 0 {
 			compatible = "arm,arm926ejs";
@@ -72,8 +78,35 @@
 			};
 
 			pinctrl at 80018000 {
+				compatible = "fsl,imx23-pinctrl", "simple-bus";
 				reg = <0x80018000 2000>;
-				status = "disabled";
+
+				gpio0: gpio at 0 {
+					compatible = "fsl,imx23-gpio", "fsl,mxs-gpio";
+					interrupts = <16>;
+					gpio-controller;
+					#gpio-cells = <2>;
+					interrupt-controller;
+					#interrupt-cells = <2>;
+				};
+
+				gpio1: gpio at 1 {
+					compatible = "fsl,imx23-gpio", "fsl,mxs-gpio";
+					interrupts = <17>;
+					gpio-controller;
+					#gpio-cells = <2>;
+					interrupt-controller;
+					#interrupt-cells = <2>;
+				};
+
+				gpio2: gpio at 2 {
+					compatible = "fsl,imx23-gpio", "fsl,mxs-gpio";
+					interrupts = <18>;
+					gpio-controller;
+					#gpio-cells = <2>;
+					interrupt-controller;
+					#interrupt-cells = <2>;
+				};
 			};
 
 			digctl at 8001c000 {
arch/arm/boot/dts/imx28.dtsi +54 -1

68 lines not on this page · raw message

arch/arm/mach-mxs/mach-mxs.c +12 -0
index ae07c9d..309f781 100644
@@ -26,8 +26,20 @@ static int __init mxs_icoll_add_irq_domain(struct device_node *np,
 	return 0;
 }
 
+static int __init mxs_gpio_add_irq_domain(struct device_node *np,
+				struct device_node *interrupt_parent)
+{
+	static int gpio_irq_base = MXS_GPIO_IRQ_START;
+
+	irq_domain_add_legacy(np, 32, gpio_irq_base, 0, &irq_domain_simple_ops, NULL);
+	gpio_irq_base += 32;
+
+	return 0;
+}
+
 static const struct of_device_id mxs_irq_match[] __initconst = {
 	{ .compatible = "fsl,mxs-icoll", .data = mxs_icoll_add_irq_domain, },
+	{ .compatible = "fsl,mxs-gpio", .data = mxs_gpio_add_irq_domain, },
 	{ /* sentinel */ }
 };
 
Signature · 1 line
1.7.5.4
#5 lore raw

cover Add device tree support for gpio-mxs

In reply to Shawn Guo
Quoted 7 lines · Shawn Guo

This patch series cleans up gpio-mxs a bit, and then adds device tree support for the driver. ?Currently, the irqdomain for gpio is still added in platform code, and should be moved into driver later with the help from the generic-irq-chip irqdomain support.

It's based on mxs device tree branch, and might be easier to go via arm-soc tree.

This all looks good to me.

Yours,
Linus Walleij

#6 lore raw

cover Add device tree support for gpio-mxs

Quoted 7 lines · Linus Walleij
Quoted 5 lines · Shawn Guo

This patch series cleans up gpio-mxs a bit, and then adds device tree support for the driver. ??Currently, the irqdomain for gpio is still added in platform code, and should be moved into driver later with the help from the generic-irq-chip irqdomain support.

Quoted 5 lines
Quoted 2 lines

It's based on mxs device tree branch, and might be easier to go via arm-soc tree.

This all looks good to me.

Same here.

For all 4 patches and for the pinmux one you posted later. Feel free to merge them via arm-soc.

g.