diff options
-rw-r--r-- | Documentation/powerpc/booting-without-of.txt | 27 | ||||
-rw-r--r-- | arch/powerpc/sysdev/qe_lib/Kconfig | 9 | ||||
-rw-r--r-- | arch/powerpc/sysdev/qe_lib/Makefile | 1 | ||||
-rw-r--r-- | arch/powerpc/sysdev/qe_lib/gpio.c | 146 | ||||
-rw-r--r-- | include/asm-powerpc/qe.h | 3 |
5 files changed, 186 insertions, 0 deletions
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt index 8675ebca2cf..b68684d39f9 100644 --- a/Documentation/powerpc/booting-without-of.txt +++ b/Documentation/powerpc/booting-without-of.txt @@ -1736,6 +1736,33 @@ platforms are moved over to use the flattened-device-tree model. ...... }; + Note that "par_io" nodes are obsolete, and should not be used for + the new device trees. Instead, each Par I/O bank should be represented + via its own gpio-controller node: + + Required properties: + - #gpio-cells : should be "2". + - compatible : should be "fsl,<chip>-qe-pario-bank", + "fsl,mpc8323-qe-pario-bank". + - reg : offset to the register set and its length. + - gpio-controller : node to identify gpio controllers. + + Example: + qe_pio_a: gpio-controller@1400 { + #gpio-cells = <2>; + compatible = "fsl,mpc8360-qe-pario-bank", + "fsl,mpc8323-qe-pario-bank"; + reg = <0x1400 0x18>; + gpio-controller; + }; + + qe_pio_e: gpio-controller@1460 { + #gpio-cells = <2>; + compatible = "fsl,mpc8360-qe-pario-bank", + "fsl,mpc8323-qe-pario-bank"; + reg = <0x1460 0x18>; + gpio-controller; + }; vi) Pin configuration nodes diff --git a/arch/powerpc/sysdev/qe_lib/Kconfig b/arch/powerpc/sysdev/qe_lib/Kconfig index 76ffbc48d4b..4bb18f57901 100644 --- a/arch/powerpc/sysdev/qe_lib/Kconfig +++ b/arch/powerpc/sysdev/qe_lib/Kconfig @@ -24,3 +24,12 @@ config QE_USB bool help QE USB Host Controller support + +config QE_GPIO + bool "QE GPIO support" + depends on QUICC_ENGINE + select GENERIC_GPIO + select HAVE_GPIO_LIB + help + Say Y here if you're going to use hardware that connects to the + QE GPIOs. diff --git a/arch/powerpc/sysdev/qe_lib/Makefile b/arch/powerpc/sysdev/qe_lib/Makefile index e9ff8884f74..f1855c18529 100644 --- a/arch/powerpc/sysdev/qe_lib/Makefile +++ b/arch/powerpc/sysdev/qe_lib/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_UCC) += ucc.o obj-$(CONFIG_UCC_SLOW) += ucc_slow.o obj-$(CONFIG_UCC_FAST) += ucc_fast.o obj-$(CONFIG_QE_USB) += usb.o +obj-$(CONFIG_QE_GPIO) += gpio.o diff --git a/arch/powerpc/sysdev/qe_lib/gpio.c b/arch/powerpc/sysdev/qe_lib/gpio.c new file mode 100644 index 00000000000..c712e245dc4 --- /dev/null +++ b/arch/powerpc/sysdev/qe_lib/gpio.c @@ -0,0 +1,146 @@ +/* + * QUICC Engine GPIOs + * + * Copyright (c) MontaVista Software, Inc. 2008. + * + * 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/spinlock.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/gpio.h> +#include <asm/qe.h> + +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 qe_pio_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 qe_pio_regs __iomem *regs = mm_gc->regs; + u32 pin_mask = 1 << (QE_PIO_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 qe_pio_regs __iomem *regs = mm_gc->regs; + unsigned long flags; + u32 pin_mask = 1 << (QE_PIO_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, QE_PIO_DIR_IN, 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, QE_PIO_DIR_OUT, 0, 0, 0); + + spin_unlock_irqrestore(&qe_gc->lock, flags); + + qe_gpio_set(gc, gpio, val); + + return 0; +} + +void __init qe_add_gpiochips(void) +{ + struct device_node *np; + + for_each_compatible_node(np, NULL, "fsl,mpc8323-qe-pario-bank") { + int ret; + 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 = QE_PIO_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; + continue; +err: + pr_err("%s: registration failed with status %d\n", + np->full_name, ret); + kfree(qe_gc); + /* try others anyway */ + } +} diff --git a/include/asm-powerpc/qe.h b/include/asm-powerpc/qe.h index c4523acad48..01e3c70b93a 100644 --- a/include/asm-powerpc/qe.h +++ b/include/asm-powerpc/qe.h @@ -100,8 +100,11 @@ struct qe_pio_regs { #endif }; +extern void __init qe_add_gpiochips(void); extern int par_io_init(struct device_node *np); extern int par_io_of_config(struct device_node *np); +#define QE_PIO_DIR_IN 2 +#define QE_PIO_DIR_OUT 1 extern void __par_io_config_pin(struct qe_pio_regs __iomem *par_io, u8 pin, int dir, int open_drain, int assignment, int has_irq); |