* [PATCH 1/4] OF helpers for the GPIO API
2008-03-11 18:40 [PATCH 0/4] GPIO LIB API support for OF and PowerPC Anton Vorontsov
@ 2008-03-11 18:42 ` Anton Vorontsov
2008-03-11 18:42 ` [PATCH 2/4] [POWERPC] Implement support for the GPIO LIB API Anton Vorontsov
` (2 subsequent siblings)
3 siblings, 0 replies; 7+ messages in thread
From: Anton Vorontsov @ 2008-03-11 18:42 UTC (permalink / raw)
To: linuxppc-dev; +Cc: David Miller
This patch implements various helpers to support OF bindings for
the GPIO LIB API.
Previously this was PowerPC specific, but it seems this code
isn't arch-dependent anyhow, so let's place it into of/.
SPARC will not see this addition yet, real hardware seem to not use
GPIOs at all. But this might change:
http://www.leox.org/docs/faq_MLleon.html
"16-bit I/O port" sounds promising. :-)
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
drivers/of/Kconfig | 6 ++
drivers/of/Makefile | 1 +
drivers/of/gpio.c | 202 +++++++++++++++++++++++++++++++++++++++++++++++
include/linux/of_gpio.h | 96 ++++++++++++++++++++++
4 files changed, 305 insertions(+), 0 deletions(-)
create mode 100644 drivers/of/gpio.c
create mode 100644 include/linux/of_gpio.h
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index c03072b..3354ad7 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -1,3 +1,9 @@
config OF_DEVICE
def_bool y
depends on OF && (SPARC || PPC_OF)
+
+config OF_GPIO
+ def_bool y
+ depends on OF && PPC_OF && HAVE_GPIO_LIB
+ help
+ OpenFirmware GPIO accessors
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index ab9be5d..5a61f70 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -1,2 +1,3 @@
obj-y = base.o
obj-$(CONFIG_OF_DEVICE) += device.o platform.o
+obj-$(CONFIG_OF_GPIO) += gpio.o
diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c
new file mode 100644
index 0000000..ed1c161
--- /dev/null
+++ b/drivers/of/gpio.c
@@ -0,0 +1,202 @@
+/*
+ * OF helpers for the GPIO API
+ *
+ * Copyright (c) 2007-2008 MontaVista Software, Inc.
+ *
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <asm/prom.h>
+
+int of_get_gpio(struct device_node *np, int index)
+{
+ int ret = -EINVAL;
+ struct device_node *gc;
+ struct of_gpio_chip *of_gc = NULL;
+ int size;
+ const u32 *gpios;
+ u32 nr_cells;
+ int i;
+ const void *gpio_spec;
+ const u32 *gpio_cells;
+ int gpio_index = 0;
+
+ gpios = of_get_property(np, "gpios", &size);
+ if (!gpios) {
+ ret = -ENOENT;
+ goto err0;
+ }
+ nr_cells = size / sizeof(u32);
+
+ for (i = 0; i < nr_cells; gpio_index++) {
+ const phandle *gpio_phandle;
+
+ gpio_phandle = gpios + i;
+ gpio_spec = gpio_phandle + 1;
+
+ /* one cell hole in the gpios = <>; */
+ if (!*gpio_phandle) {
+ if (gpio_index == index)
+ return -ENOENT;
+ i++;
+ continue;
+ }
+
+ gc = of_find_node_by_phandle(*gpio_phandle);
+ if (!gc) {
+ pr_debug("%s: could not find phandle for gpios\n",
+ np->full_name);
+ goto err0;
+ }
+
+ of_gc = gc->data;
+ if (!of_gc) {
+ pr_debug("%s: gpio controller %s isn't registered\n",
+ np->full_name, gc->full_name);
+ goto err1;
+ }
+
+ gpio_cells = of_get_property(gc, "#gpio-cells", &size);
+ if (!gpio_cells || size != sizeof(*gpio_cells) ||
+ *gpio_cells != of_gc->gpio_cells) {
+ pr_debug("%s: wrong #gpio-cells for %s\n",
+ np->full_name, gc->full_name);
+ goto err1;
+ }
+
+ /* Next phandle is at phandle cells + #gpio-cells */
+ i += sizeof(*gpio_phandle) / sizeof(u32) + *gpio_cells;
+ if (i >= nr_cells + 1) {
+ pr_debug("%s: insufficient gpio-spec length\n",
+ np->full_name);
+ goto err1;
+ }
+
+ if (gpio_index == index)
+ break;
+
+ of_gc = NULL;
+ of_node_put(gc);
+ }
+
+ if (!of_gc) {
+ ret = -ENOENT;
+ goto err0;
+ }
+
+ ret = of_gc->xlate(of_gc, np, gpio_spec);
+ if (ret < 0)
+ goto err1;
+
+ ret += of_gc->gc.base;
+err1:
+ of_node_put(gc);
+err0:
+ pr_debug("%s exited with status %d\n", __func__, ret);
+ return ret;
+}
+EXPORT_SYMBOL(of_get_gpio);
+
+static int of_gpio_simple_xlate(struct of_gpio_chip *of_gc,
+ struct device_node *np,
+ const void *gpio_spec)
+{
+ const u32 *gpio = gpio_spec;
+
+ if (*gpio > of_gc->gc.ngpio)
+ return -EINVAL;
+
+ return *gpio;
+}
+
+/* Should be sufficient for now, later we'll use dynamic bases. */
+#if defined(CONFIG_PPC32) || defined(CONFIG_SPARC32)
+#define GPIOS_PER_CHIP 32
+#else
+#define GPIOS_PER_CHIP 64
+#endif
+
+static int of_get_gpiochip_base(struct device_node *np)
+{
+ struct device_node *gc = NULL;
+ int gpiochip_base = 0;
+
+ while ((gc = of_find_all_nodes(gc))) {
+ if (!of_get_property(gc, "gpio-controller", NULL))
+ continue;
+
+ if (gc != np) {
+ gpiochip_base += GPIOS_PER_CHIP;
+ continue;
+ }
+
+ of_node_put(gc);
+
+ if (gpiochip_base >= ARCH_NR_GPIOS)
+ return -ENOSPC;
+
+ return gpiochip_base;
+ }
+
+ return -ENOENT;
+}
+
+int of_mm_gpiochip_add(struct device_node *np,
+ struct of_mm_gpio_chip *mm_gc)
+{
+ int ret = -ENOMEM;
+ struct of_gpio_chip *of_gc = &mm_gc->of_gc;
+ struct gpio_chip *gc = &of_gc->gc;
+
+ gc->label = kstrdup(np->full_name, GFP_KERNEL);
+ if (!gc->label)
+ goto err0;
+
+ mm_gc->regs = of_iomap(np, 0);
+ if (!mm_gc->regs)
+ goto err1;
+
+ gc->base = of_get_gpiochip_base(np);
+ if (gc->base < 0) {
+ ret = gc->base;
+ goto err1;
+ }
+
+ if (!of_gc->xlate)
+ of_gc->xlate = of_gpio_simple_xlate;
+
+ if (mm_gc->save_regs)
+ mm_gc->save_regs(mm_gc);
+
+ np->data = of_gc;
+
+ ret = gpiochip_add(gc);
+ if (ret)
+ goto err2;
+
+ /* We don't want to lose the node and its ->data */
+ of_node_get(np);
+
+ pr_debug("%s: registered as generic GPIO chip, base is %d\n",
+ np->full_name, gc->base);
+ return 0;
+err2:
+ np->data = NULL;
+ iounmap(mm_gc->regs);
+err1:
+ kfree(gc->label);
+err0:
+ pr_err("%s: GPIO chip registration failed with status %d\n",
+ np->full_name, ret);
+ return ret;
+}
+EXPORT_SYMBOL(of_mm_gpiochip_add);
diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h
new file mode 100644
index 0000000..ca313f0
--- /dev/null
+++ b/include/linux/of_gpio.h
@@ -0,0 +1,96 @@
+/*
+ * Generic GPIO API implementation for PowerPC.
+ *
+ * Copyright (c) 2007-2008 MontaVista Software, Inc.
+ *
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __LINUX_OF_GPIO_H
+#define __LINUX_OF_GPIO_H
+
+#include <asm/gpio.h>
+
+#ifdef CONFIG_OF_GPIO
+
+/*
+ * Generic OF GPIO chip
+ */
+struct of_gpio_chip {
+ struct gpio_chip gc;
+ int gpio_cells;
+ int (*xlate)(struct of_gpio_chip *of_gc, struct device_node *np,
+ const void *gpio_spec);
+};
+
+static inline struct of_gpio_chip *to_of_gpio_chip(struct gpio_chip *gc)
+{
+ return container_of(gc, struct of_gpio_chip, gc);
+}
+
+/*
+ * OF GPIO chip for memory mapped banks
+ */
+struct of_mm_gpio_chip {
+ struct of_gpio_chip of_gc;
+ void (*save_regs)(struct of_mm_gpio_chip *mm_gc);
+ void __iomem *regs;
+};
+
+static inline struct of_mm_gpio_chip *to_of_mm_gpio_chip(struct gpio_chip *gc)
+{
+ struct of_gpio_chip *of_gc = to_of_gpio_chip(gc);
+
+ return container_of(of_gc, struct of_mm_gpio_chip, of_gc);
+}
+
+/**
+ * of_get_gpio - Get a GPIO number from the device tree to use with GPIO API
+ * @np: device node to get GPIO from
+ * @index: index of the GPIO
+ *
+ * Returns GPIO number to use with Linux generic GPIO API, or one of the errno
+ * value on the error condition.
+ */
+extern int of_get_gpio(struct device_node *np, int index);
+
+/**
+ * of_mm_gpiochip_add - Add memory mapped GPIO chip (bank)
+ * @np: device node of the GPIO chip
+ * @mm_gc: pointer to the of_mm_gpio_chip allocated structure
+ *
+ * To use this function you should allocate and fill mm_gc with:
+ *
+ * 1) In the gpio_chip structure:
+ * - all the callbacks
+ *
+ * 2) In the of_gpio_chip structure:
+ * - gpio_cells
+ * - xlate callback (optional)
+ *
+ * 3) In the of_mm_gpio_chip structure:
+ * - save_regs callback (optional)
+ *
+ * If succeeded, this function will map bank's memory and will
+ * do all necessary work for you. Then you'll able to use .regs
+ * to manage GPIOs from the callbacks.
+ */
+extern int of_mm_gpiochip_add(struct device_node *np,
+ struct of_mm_gpio_chip *mm_gc);
+
+#else
+
+/* Drivers may not strictly depend on the GPIO support, so let them link. */
+static inline int of_get_gpio(struct device_node *np, int index)
+{
+ return -ENOSYS;
+}
+
+#endif /* CONFIG_OF_GPIO */
+
+#endif /* __LINUX_OF_GPIO_H */
--
1.5.2.2
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/4] [POWERPC] Implement support for the GPIO LIB API
2008-03-11 18:40 [PATCH 0/4] GPIO LIB API support for OF and PowerPC Anton Vorontsov
2008-03-11 18:42 ` [PATCH 1/4] OF helpers for the GPIO API Anton Vorontsov
@ 2008-03-11 18:42 ` Anton Vorontsov
2008-04-03 11:05 ` Laurent Pinchart
2008-03-11 18:42 ` [PATCH 3/4] [POWERPC] QE: split par_io_config_pin() Anton Vorontsov
2008-03-11 18:42 ` [PATCH 4/4] [POWERPC] QE: implement support for the GPIO LIB API Anton Vorontsov
3 siblings, 1 reply; 7+ messages in thread
From: Anton Vorontsov @ 2008-03-11 18:42 UTC (permalink / raw)
To: linuxppc-dev
This patch implements support for the GPIO LIB API. Two calls
unimplemented though: irq_to_gpio and gpio_to_irq.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
Documentation/powerpc/booting-without-of.txt | 52 ++++++++++++++++++++++++
arch/powerpc/Kconfig | 5 ++
include/asm-powerpc/gpio.h | 55 ++++++++++++++++++++++++++
3 files changed, 112 insertions(+), 0 deletions(-)
create mode 100644 include/asm-powerpc/gpio.h
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index b506245..e9e0c2f 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -66,6 +66,10 @@ Table of Contents
3) OpenPIC Interrupt Controllers
4) ISA Interrupt Controllers
+ VIII - Specifying GPIO information for devices
+ 1) gpios property
+ 2) gpio-controller nodes
+
Appendix A - Sample SOC node for MPC8540
@@ -2925,6 +2929,54 @@ encodings listed below:
2 = high to low edge sensitive type enabled
3 = low to high edge sensitive type enabled
+VIII - Specifying GPIO information for devices
+==============================================
+
+1) gpios property
+-----------------
+
+Nodes that makes use of GPIOs should define them using `gpios' property,
+format of which is: <&gpio-controller1-phandle gpio1-specifier
+ &gpio-controller2-phandle gpio2-specifier
+ 0 /* holes are permitted, means no GPIO 3 */
+ &gpio-controller4-phandle gpio4-specifier
+ ...>;
+
+Note that gpio-specifier length is controller dependent.
+
+gpio-specifier may encode: bank, pin position inside the bank,
+whether pin is open-drain and whether pin is logically inverted.
+
+Example of the node using GPIOs:
+
+ node {
+ gpios = <&qe_pio_e 18 0>;
+ };
+
+In this example gpio-specifier is "18 0" and encodes GPIO pin number,
+and empty GPIO flags as accepted by the "qe_pio_e" gpio-controller.
+
+2) gpio-controller nodes
+------------------------
+
+Every GPIO controller node must have #gpio-cells property defined,
+this information will be used to translate gpio-specifiers.
+
+Example of two SOC GPIO banks defined as gpio-controller nodes:
+
+ qe_pio_a: gpio-controller@1400 {
+ #gpio-cells = <2>;
+ compatible = "fsl,qe-pario-bank-a", "fsl,qe-pario-bank";
+ reg = <0x1400 0x18>;
+ gpio-controller;
+ };
+
+ qe_pio_e: gpio-controller@1460 {
+ #gpio-cells = <2>;
+ compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
+ reg = <0x1460 0x18>;
+ gpio-controller;
+ };
Appendix A - Sample SOC node for MPC8540
========================================
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 0b27cbd..f328509 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -81,6 +81,11 @@ config GENERIC_FIND_NEXT_BIT
bool
default y
+config GENERIC_GPIO
+ bool
+ help
+ Generic GPIO API support
+
config ARCH_NO_VIRT_TO_BUS
def_bool PPC64
diff --git a/include/asm-powerpc/gpio.h b/include/asm-powerpc/gpio.h
new file mode 100644
index 0000000..057840d
--- /dev/null
+++ b/include/asm-powerpc/gpio.h
@@ -0,0 +1,55 @@
+/*
+ * Generic GPIO API implementation for PowerPC.
+ *
+ * Copyright (c) 2007-2008 MontaVista Software, Inc.
+ *
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __ASM_POWERPC_GPIO_H
+#define __ASM_POWERPC_GPIO_H
+
+#include <asm-generic/gpio.h>
+
+#ifdef CONFIG_HAVE_GPIO_LIB
+
+/*
+ * We don't (yet) implement inlined/rapid versions for on-chip gpios.
+ * Just call gpiolib.
+ */
+static inline int gpio_get_value(unsigned int gpio)
+{
+ return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned int gpio, int value)
+{
+ __gpio_set_value(gpio, value);
+}
+
+static inline int gpio_cansleep(unsigned int gpio)
+{
+ return __gpio_cansleep(gpio);
+}
+
+/*
+ * Not implemented, yet.
+ */
+static inline int gpio_to_irq(unsigned int gpio)
+{
+ return -ENOSYS;
+}
+
+static inline int irq_to_gpio(unsigned int irq)
+{
+ return -EINVAL;
+}
+
+#endif /* CONFIG_HAVE_GPIO_LIB */
+
+#endif /* __ASM_POWERPC_GPIO_H */
--
1.5.2.2
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 2/4] [POWERPC] Implement support for the GPIO LIB API
2008-03-11 18:42 ` [PATCH 2/4] [POWERPC] Implement support for the GPIO LIB API Anton Vorontsov
@ 2008-04-03 11:05 ` Laurent Pinchart
2008-04-03 12:18 ` Anton Vorontsov
0 siblings, 1 reply; 7+ messages in thread
From: Laurent Pinchart @ 2008-04-03 11:05 UTC (permalink / raw)
To: linuxppc-dev
[-- Attachment #1: Type: text/plain, Size: 2379 bytes --]
Hi Anton,
On Tuesday 11 March 2008 19:42, Anton Vorontsov wrote:
> This patch implements support for the GPIO LIB API. Two calls
> unimplemented though: irq_to_gpio and gpio_to_irq.
>
> Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
> ---
> Documentation/powerpc/booting-without-of.txt | 52 ++++++++++++++++++++++++
> arch/powerpc/Kconfig | 5 ++
> include/asm-powerpc/gpio.h | 55 ++++++++++++++++++++++++++
> 3 files changed, 112 insertions(+), 0 deletions(-)
> create mode 100644 include/asm-powerpc/gpio.h
[snip]
> diff --git a/include/asm-powerpc/gpio.h b/include/asm-powerpc/gpio.h
> new file mode 100644
> index 0000000..057840d
> --- /dev/null
> +++ b/include/asm-powerpc/gpio.h
> @@ -0,0 +1,55 @@
> +/*
> + * Generic GPIO API implementation for PowerPC.
> + *
> + * Copyright (c) 2007-2008 MontaVista Software, Inc.
> + *
> + * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#ifndef __ASM_POWERPC_GPIO_H
> +#define __ASM_POWERPC_GPIO_H
> +
> +#include <asm-generic/gpio.h>
> +
> +#ifdef CONFIG_HAVE_GPIO_LIB
> +
> +/*
> + * We don't (yet) implement inlined/rapid versions for on-chip gpios.
> + * Just call gpiolib.
> + */
> +static inline int gpio_get_value(unsigned int gpio)
> +{
> + return __gpio_get_value(gpio);
> +}
> +
> +static inline void gpio_set_value(unsigned int gpio, int value)
> +{
> + __gpio_set_value(gpio, value);
> +}
> +
> +static inline int gpio_cansleep(unsigned int gpio)
> +{
> + return __gpio_cansleep(gpio);
> +}
> +
> +/*
> + * Not implemented, yet.
> + */
> +static inline int gpio_to_irq(unsigned int gpio)
> +{
> + return -ENOSYS;
> +}
> +
> +static inline int irq_to_gpio(unsigned int irq)
> +{
> + return -EINVAL;
> +}
You should include <linux/errno.h>.
> +#endif /* CONFIG_HAVE_GPIO_LIB */
> +
> +#endif /* __ASM_POWERPC_GPIO_H */
Best regards,
--
Laurent Pinchart
CSE Semaphore Belgium
Chaussée de Bruxelles, 732A
B-1410 Waterloo
Belgium
T +32 (2) 387 42 59
F +32 (2) 387 42 75
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2/4] [POWERPC] Implement support for the GPIO LIB API
2008-04-03 11:05 ` Laurent Pinchart
@ 2008-04-03 12:18 ` Anton Vorontsov
0 siblings, 0 replies; 7+ messages in thread
From: Anton Vorontsov @ 2008-04-03 12:18 UTC (permalink / raw)
To: Laurent Pinchart; +Cc: linuxppc-dev
On Thu, Apr 03, 2008 at 01:05:51PM +0200, Laurent Pinchart wrote:
> Hi Anton,
>
> On Tuesday 11 March 2008 19:42, Anton Vorontsov wrote:
> > This patch implements support for the GPIO LIB API. Two calls
> > unimplemented though: irq_to_gpio and gpio_to_irq.
> >
> > Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
> > ---
> > Documentation/powerpc/booting-without-of.txt | 52 ++++++++++++++++++++++++
> > arch/powerpc/Kconfig | 5 ++
> > include/asm-powerpc/gpio.h | 55 ++++++++++++++++++++++++++
> > 3 files changed, 112 insertions(+), 0 deletions(-)
> > create mode 100644 include/asm-powerpc/gpio.h
>
> [snip]
>
> > diff --git a/include/asm-powerpc/gpio.h b/include/asm-powerpc/gpio.h
> > new file mode 100644
> > index 0000000..057840d
> > --- /dev/null
> > +++ b/include/asm-powerpc/gpio.h
> > @@ -0,0 +1,55 @@
> > +/*
> > + * Generic GPIO API implementation for PowerPC.
> > + *
> > + * Copyright (c) 2007-2008 MontaVista Software, Inc.
> > + *
> > + * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + */
> > +
> > +#ifndef __ASM_POWERPC_GPIO_H
> > +#define __ASM_POWERPC_GPIO_H
> > +
> > +#include <asm-generic/gpio.h>
> > +
> > +#ifdef CONFIG_HAVE_GPIO_LIB
> > +
> > +/*
> > + * We don't (yet) implement inlined/rapid versions for on-chip gpios.
> > + * Just call gpiolib.
> > + */
> > +static inline int gpio_get_value(unsigned int gpio)
> > +{
> > + return __gpio_get_value(gpio);
> > +}
> > +
> > +static inline void gpio_set_value(unsigned int gpio, int value)
> > +{
> > + __gpio_set_value(gpio, value);
> > +}
> > +
> > +static inline int gpio_cansleep(unsigned int gpio)
> > +{
> > + return __gpio_cansleep(gpio);
> > +}
> > +
> > +/*
> > + * Not implemented, yet.
> > + */
> > +static inline int gpio_to_irq(unsigned int gpio)
> > +{
> > + return -ENOSYS;
> > +}
> > +
> > +static inline int irq_to_gpio(unsigned int irq)
> > +{
> > + return -EINVAL;
> > +}
>
> You should include <linux/errno.h>.
Yeah, much thanks for catching this!
--
Anton Vorontsov
email: cboumailru@gmail.com
irc://irc.freenode.net/bd2
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 3/4] [POWERPC] QE: split par_io_config_pin()
2008-03-11 18:40 [PATCH 0/4] GPIO LIB API support for OF and PowerPC Anton Vorontsov
2008-03-11 18:42 ` [PATCH 1/4] OF helpers for the GPIO API Anton Vorontsov
2008-03-11 18:42 ` [PATCH 2/4] [POWERPC] Implement support for the GPIO LIB API Anton Vorontsov
@ 2008-03-11 18:42 ` Anton Vorontsov
2008-03-11 18:42 ` [PATCH 4/4] [POWERPC] QE: implement support for the GPIO LIB API Anton Vorontsov
3 siblings, 0 replies; 7+ messages in thread
From: Anton Vorontsov @ 2008-03-11 18:42 UTC (permalink / raw)
To: linuxppc-dev
This patch splits par_io_config_pin so we can use it with GPIO LIB API.
Also add a comment regarding #ifdef CONFIG_PPC_85xx being legacy.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
arch/powerpc/sysdev/qe_lib/qe_io.c | 60 +++++++++++++++++++++++------------
1 files changed, 39 insertions(+), 21 deletions(-)
diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/sysdev/qe_lib/qe_io.c
index 93916a4..a3f9c3f 100644
--- a/arch/powerpc/sysdev/qe_lib/qe_io.c
+++ b/arch/powerpc/sysdev/qe_lib/qe_io.c
@@ -38,6 +38,10 @@ struct port_regs {
__be32 cppar1; /* Pin assignment register */
__be32 cppar2; /* Pin assignment register */
#ifdef CONFIG_PPC_85xx
+ /*
+ * This is needed for legacy support only, should go away,
+ * because we started using per-bank gpio chips.
+ */
u8 pad[8];
#endif
};
@@ -64,28 +68,29 @@ int par_io_init(struct device_node *np)
return 0;
}
-int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain,
- int assignment, int has_irq)
+static void __par_io_config_pin(struct port_regs __iomem *par_io,
+ u8 pin, int dir, int open_drain,
+ int assignment, int has_irq)
{
- u32 pin_mask1bit, pin_mask2bits, new_mask2bits, tmp_val;
-
- if (!par_io)
- return -1;
+ u32 pin_mask1bit;
+ u32 pin_mask2bits;
+ u32 new_mask2bits;
+ u32 tmp_val;
/* calculate pin location for single and 2 bits information */
pin_mask1bit = (u32) (1 << (NUM_OF_PINS - (pin + 1)));
/* Set open drain, if required */
- tmp_val = in_be32(&par_io[port].cpodr);
+ tmp_val = in_be32(&par_io->cpodr);
if (open_drain)
- out_be32(&par_io[port].cpodr, pin_mask1bit | tmp_val);
+ out_be32(&par_io->cpodr, pin_mask1bit | tmp_val);
else
- out_be32(&par_io[port].cpodr, ~pin_mask1bit & tmp_val);
+ out_be32(&par_io->cpodr, ~pin_mask1bit & tmp_val);
/* define direction */
tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ?
- in_be32(&par_io[port].cpdir2) :
- in_be32(&par_io[port].cpdir1);
+ in_be32(&par_io->cpdir2) :
+ in_be32(&par_io->cpdir1);
/* get all bits mask for 2 bit per port */
pin_mask2bits = (u32) (0x3 << (NUM_OF_PINS -
@@ -97,36 +102,49 @@ int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain,
/* clear and set 2 bits mask */
if (pin > (NUM_OF_PINS / 2) - 1) {
- out_be32(&par_io[port].cpdir2,
+ out_be32(&par_io->cpdir2,
~pin_mask2bits & tmp_val);
tmp_val &= ~pin_mask2bits;
- out_be32(&par_io[port].cpdir2, new_mask2bits | tmp_val);
+ out_be32(&par_io->cpdir2, new_mask2bits | tmp_val);
} else {
- out_be32(&par_io[port].cpdir1,
+ out_be32(&par_io->cpdir1,
~pin_mask2bits & tmp_val);
tmp_val &= ~pin_mask2bits;
- out_be32(&par_io[port].cpdir1, new_mask2bits | tmp_val);
+ out_be32(&par_io->cpdir1, new_mask2bits | tmp_val);
}
/* define pin assignment */
tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ?
- in_be32(&par_io[port].cppar2) :
- in_be32(&par_io[port].cppar1);
+ in_be32(&par_io->cppar2) :
+ in_be32(&par_io->cppar1);
new_mask2bits = (u32) (assignment << (NUM_OF_PINS -
(pin % (NUM_OF_PINS / 2) + 1) * 2));
/* clear and set 2 bits mask */
if (pin > (NUM_OF_PINS / 2) - 1) {
- out_be32(&par_io[port].cppar2,
+ out_be32(&par_io->cppar2,
~pin_mask2bits & tmp_val);
tmp_val &= ~pin_mask2bits;
- out_be32(&par_io[port].cppar2, new_mask2bits | tmp_val);
+ out_be32(&par_io->cppar2, new_mask2bits | tmp_val);
} else {
- out_be32(&par_io[port].cppar1,
+ out_be32(&par_io->cppar1,
~pin_mask2bits & tmp_val);
tmp_val &= ~pin_mask2bits;
- out_be32(&par_io[port].cppar1, new_mask2bits | tmp_val);
+ out_be32(&par_io->cppar1, new_mask2bits | tmp_val);
}
+}
+
+/*
+ * This is "legacy" function that takes port number as an argument
+ * instead of pointer to the appropriate bank.
+ */
+int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain,
+ int assignment, int has_irq)
+{
+ if (!par_io || port >= num_par_io_ports)
+ return -EINVAL;
+ __par_io_config_pin(&par_io[port], pin, dir, open_drain, assignment,
+ has_irq);
return 0;
}
EXPORT_SYMBOL(par_io_config_pin);
--
1.5.2.2
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 4/4] [POWERPC] QE: implement support for the GPIO LIB API
2008-03-11 18:40 [PATCH 0/4] GPIO LIB API support for OF and PowerPC Anton Vorontsov
` (2 preceding siblings ...)
2008-03-11 18:42 ` [PATCH 3/4] [POWERPC] QE: split par_io_config_pin() Anton Vorontsov
@ 2008-03-11 18:42 ` Anton Vorontsov
3 siblings, 0 replies; 7+ messages in thread
From: Anton Vorontsov @ 2008-03-11 18:42 UTC (permalink / raw)
To: linuxppc-dev
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
Documentation/powerpc/booting-without-of.txt | 32 ++++---
arch/powerpc/platforms/Kconfig | 2 +
arch/powerpc/sysdev/qe_lib/qe_io.c | 137 +++++++++++++++++++++++++-
3 files changed, 158 insertions(+), 13 deletions(-)
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index e9e0c2f..113884b 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -1703,24 +1703,32 @@ platforms are moved over to use the flattened-device-tree model.
information.
Required properties:
- - device_type : should be "par_io".
+ - #gpio-cells : should be "2".
+ - compatible : should be "fsl,qe-pario-bank-<bank>", "fsl,qe-pario-bank"
- reg : offset to the register set and its length.
- - num-ports : number of Parallel I/O ports
+ - gpio-controller : node to identify gpio controllers.
- Example:
- par_io@1400 {
- reg = <1400 100>;
- #address-cells = <1>;
- #size-cells = <0>;
- device_type = "par_io";
- num-ports = <7>;
- ucc_pin@01 {
- ......
- };
+ For example, two QE Par I/O banks:
+ qe_pio_a: gpio-controller@1400 {
+ #gpio-cells = <2>;
+ compatible = "fsl,qe-pario-bank-a", "fsl,qe-pario-bank";
+ reg = <0x1400 0x18>;
+ gpio-controller;
+ };
+ qe_pio_e: gpio-controller@1460 {
+ #gpio-cells = <2>;
+ compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
+ reg = <0x1460 0x18>;
+ gpio-controller;
+ };
vi) Pin configuration nodes
+ NOTE: pin configuration nodes are obsolete. Usually, their existance
+ is an evidence of the firmware shortcomings. Such fixups are
+ better handled by the Linux board file, not the device tree.
+
Required properties:
- linux,phandle : phandle of this node; likely referenced by a QE
device.
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index 0afd225..2d91ed9 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -271,6 +271,8 @@ config QUICC_ENGINE
bool
select PPC_LIB_RHEAP
select CRC32
+ select GENERIC_GPIO
+ select HAVE_GPIO_LIB
help
The QUICC Engine (QE) is a new generation of communications
coprocessors on Freescale embedded CPUs (akin to CPM in older chips).
diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/sysdev/qe_lib/qe_io.c
index a3f9c3f..a4a195a 100644
--- a/arch/powerpc/sysdev/qe_lib/qe_io.c
+++ b/arch/powerpc/sysdev/qe_lib/qe_io.c
@@ -20,7 +20,8 @@
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/ioport.h>
-
+#include <linux/spinlock.h>
+#include <linux/of_gpio.h>
#include <asm/io.h>
#include <asm/qe.h>
#include <asm/prom.h>
@@ -214,6 +215,140 @@ int par_io_of_config(struct device_node *np)
}
EXPORT_SYMBOL(par_io_of_config);
+/*
+ * GPIO LIB API implementation
+ */
+
+struct qe_gpio_chip {
+ struct of_mm_gpio_chip mm_gc;
+ spinlock_t lock;
+
+ /* shadowed data register to clear/set bits safely */
+ u32 cpdata;
+};
+
+static inline struct qe_gpio_chip *
+to_qe_gpio_chip(struct of_mm_gpio_chip *mm_gc)
+{
+ return container_of(mm_gc, struct qe_gpio_chip, mm_gc);
+}
+
+static void qe_gpio_save_regs(struct of_mm_gpio_chip *mm_gc)
+{
+ struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc);
+ struct port_regs __iomem *regs = mm_gc->regs;
+
+ qe_gc->cpdata = in_be32(®s->cpdata);
+}
+
+static int qe_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct port_regs __iomem *regs = mm_gc->regs;
+ u32 pin_mask;
+
+ /* calculate pin location */
+ pin_mask = (u32) (1 << (NUM_OF_PINS - 1 - gpio));
+
+ return !!(in_be32(®s->cpdata) & pin_mask);
+}
+
+static void qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc);
+ struct port_regs __iomem *regs = mm_gc->regs;
+ unsigned long flags;
+ u32 pin_mask = 1 << (NUM_OF_PINS - 1 - gpio);
+
+ spin_lock_irqsave(&qe_gc->lock, flags);
+
+ if (val)
+ qe_gc->cpdata |= pin_mask;
+ else
+ qe_gc->cpdata &= ~pin_mask;
+
+ out_be32(®s->cpdata, qe_gc->cpdata);
+
+ spin_unlock_irqrestore(&qe_gc->lock, flags);
+}
+
+static int qe_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&qe_gc->lock, flags);
+
+ __par_io_config_pin(mm_gc->regs, gpio, 2, 0, 0, 0);
+
+ spin_unlock_irqrestore(&qe_gc->lock, flags);
+
+ return 0;
+}
+
+static int qe_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&qe_gc->lock, flags);
+
+ __par_io_config_pin(mm_gc->regs, gpio, 1, 0, 0, 0);
+
+ spin_unlock_irqrestore(&qe_gc->lock, flags);
+
+ qe_gpio_set(gc, gpio, val);
+
+ return 0;
+}
+
+static int __init qe_add_gpiochips(void)
+{
+ int ret;
+ struct device_node *np;
+
+ for_each_compatible_node(np, NULL, "fsl,qe-pario-bank") {
+ struct qe_gpio_chip *qe_gc;
+ struct of_mm_gpio_chip *mm_gc;
+ struct of_gpio_chip *of_gc;
+ struct gpio_chip *gc;
+
+ qe_gc = kzalloc(sizeof(*qe_gc), GFP_KERNEL);
+ if (!qe_gc) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ spin_lock_init(&qe_gc->lock);
+
+ mm_gc = &qe_gc->mm_gc;
+ of_gc = &mm_gc->of_gc;
+ gc = &of_gc->gc;
+
+ mm_gc->save_regs = qe_gpio_save_regs;
+ of_gc->gpio_cells = 2;
+ gc->ngpio = NUM_OF_PINS;
+ gc->direction_input = qe_gpio_dir_in;
+ gc->direction_output = qe_gpio_dir_out;
+ gc->get = qe_gpio_get;
+ gc->set = qe_gpio_set;
+
+ ret = of_mm_gpiochip_add(np, mm_gc);
+ if (ret)
+ goto err;
+ }
+
+ return 0;
+err:
+ pr_err("%s: registration failed with status %d\n", np->full_name, ret);
+ of_node_put(np);
+ return ret;
+}
+arch_initcall(qe_add_gpiochips);
+
#ifdef DEBUG
static void dump_par_io(void)
{
--
1.5.2.2
^ permalink raw reply related [flat|nested] 7+ messages in thread