Structured similar to the existing QE GPIO support. Signed-off-by: Peter Korsgaard <[EMAIL PROTECTED]> --- .../powerpc/dts-bindings/fsl/83xx_gpio.txt | 33 +++++ arch/powerpc/sysdev/Kconfig | 9 ++ arch/powerpc/sysdev/Makefile | 1 + arch/powerpc/sysdev/mpc83xx_gpio.c | 141 ++++++++++++++++++++ 4 files changed, 184 insertions(+), 0 deletions(-) create mode 100644 Documentation/powerpc/dts-bindings/fsl/83xx_gpio.txt create mode 100644 arch/powerpc/sysdev/mpc83xx_gpio.c
diff --git a/Documentation/powerpc/dts-bindings/fsl/83xx_gpio.txt b/Documentation/powerpc/dts-bindings/fsl/83xx_gpio.txt new file mode 100644 index 0000000..f43f048 --- /dev/null +++ b/Documentation/powerpc/dts-bindings/fsl/83xx_gpio.txt @@ -0,0 +1,33 @@ +GPIO controllers on MPC831x/834x/837x SoCs + +Every GPIO controller node must have #gpio-cells property defined, +this information will be used to translate gpio-specifiers. + +Required properties: +- compatible : "fsl,mpc8349-gpio" +- #gpio-cells : Should be two. The first cell is the pin number and the + second cell is used to specify optional parameters (currently unused). + - interrupts : Interrupt mapping for GPIO IRQ (currently unused). + - interrupt-parent : Phandle for the interrupt controller that + services interrupts for this device. +- gpio-controller : Marks the port as GPIO controller. + +Example of gpio-controller nodes for a MPC8349 SoC: + + gpio1: [EMAIL PROTECTED] { + #gpio-cells = <2>; + compatible = "fsl,mpc8349-gpio"; + reg = <0xc00 0x100>; + interrupts = <74 0x8>; + interrupt-parent = <&ipic>; + gpio-controller; + }; + + gpio2: [EMAIL PROTECTED] { + #gpio-cells = <2>; + compatible = "fsl,mpc8349-gpio"; + reg = <0xd00 0x100>; + interrupts = <75 0x8>; + interrupt-parent = <&ipic>; + gpio-controller; + }; diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig index 72fb35b..d28c3c5 100644 --- a/arch/powerpc/sysdev/Kconfig +++ b/arch/powerpc/sysdev/Kconfig @@ -6,3 +6,12 @@ config PPC4xx_PCI_EXPRESS bool depends on PCI && 4xx default n + +config MPC83xx_GPIO + bool "MPC83xx GPIO support" + depends on PPC_MPC831x || PPC_MPC834x || PPC_MPC837x + select GENERIC_GPIO + select ARCH_REQUIRE_GPIOLIB + help + Say Y here if you're going to use hardware that connects to the + MPC831x/834x/837x GPIOs. diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index a90054b..ced5793 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o obj-$(CONFIG_FSL_PCI) += fsl_pci.o $(fsl-msi-obj-y) obj-$(CONFIG_FSL_LBC) += fsl_lbc.o obj-$(CONFIG_FSL_GTM) += fsl_gtm.o +obj-$(CONFIG_MPC83xx_GPIO) += mpc83xx_gpio.o obj-$(CONFIG_RAPIDIO) += fsl_rio.o obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ diff --git a/arch/powerpc/sysdev/mpc83xx_gpio.c b/arch/powerpc/sysdev/mpc83xx_gpio.c new file mode 100644 index 0000000..a8a132d --- /dev/null +++ b/arch/powerpc/sysdev/mpc83xx_gpio.c @@ -0,0 +1,141 @@ +/* + * GPIOs on MPC831x/834x/837x + * + * Copyright (C) 2008 Peter Korsgaard <[EMAIL PROTECTED]> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/gpio.h> + +#define GPIO_DIR 0x00 +#define GPIO_ODR 0x04 +#define GPIO_DAT 0x08 +#define GPIO_IER 0x0c +#define GPIO_IMR 0x10 +#define GPIO_ICR 0x14 + +struct mpc83xx_gpio_chip { + struct of_mm_gpio_chip mm_gc; + spinlock_t lock; +}; + +static inline struct mpc83xx_gpio_chip * +to_mpc83xx_gpio_chip(struct of_mm_gpio_chip *mm) +{ + return container_of(mm, struct mpc83xx_gpio_chip, mm_gc); +} + +static int mpc83xx_gpio_get(struct gpio_chip *gc, unsigned int gpio) +{ + struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); + u32 bit = 1u << (31-gpio); + + return !!(in_be32(mm->regs + GPIO_DAT) & bit); +} + +static void mpc83xx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) +{ + struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); + struct mpc83xx_gpio_chip *mpc83xx_gc = to_mpc83xx_gpio_chip(mm); + unsigned long flags; + u32 data, bit = 1u << (31-gpio); + + spin_lock_irqsave(&mpc83xx_gc->lock, flags); + + data = in_be32(mm->regs + GPIO_DAT); + if (val) + data |= bit; + else + data &= ~bit; + out_be32(mm->regs + GPIO_DAT, data); + + spin_unlock_irqrestore(&mpc83xx_gc->lock, flags); +} + +static int mpc83xx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) +{ + struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); + struct mpc83xx_gpio_chip *mpc83xx_gc = to_mpc83xx_gpio_chip(mm); + unsigned long flags; + u32 bit = 1u << (31-gpio); + + spin_lock_irqsave(&mpc83xx_gc->lock, flags); + + out_be32(mm->regs + GPIO_DIR, + in_be32(mm->regs + GPIO_DIR) & ~bit); + + spin_unlock_irqrestore(&mpc83xx_gc->lock, flags); + + return 0; +} + +static int mpc83xx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) +{ + struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); + struct mpc83xx_gpio_chip *mpc83xx_gc = to_mpc83xx_gpio_chip(mm); + unsigned long flags; + u32 bit = 1u << (31-gpio); + + mpc83xx_gpio_set(gc, gpio, val); + + spin_lock_irqsave(&mpc83xx_gc->lock, flags); + out_be32(mm->regs + GPIO_DIR, + in_be32(mm->regs + GPIO_DIR) | bit); + + spin_unlock_irqrestore(&mpc83xx_gc->lock, flags); + + return 0; +} + +static int __init mpc83xx_add_gpiochips(void) +{ + struct device_node *np; + + for_each_compatible_node(np, NULL, "fsl,mpc8349-gpio") { + int ret; + struct mpc83xx_gpio_chip *mpc83xx_gc; + struct of_mm_gpio_chip *mm_gc; + struct of_gpio_chip *of_gc; + struct gpio_chip *gc; + + mpc83xx_gc = kzalloc(sizeof(*mpc83xx_gc), GFP_KERNEL); + if (!mpc83xx_gc) { + ret = -ENOMEM; + goto err; + } + + spin_lock_init(&mpc83xx_gc->lock); + + mm_gc = &mpc83xx_gc->mm_gc; + of_gc = &mm_gc->of_gc; + gc = &of_gc->gc; + + of_gc->gpio_cells = 2; + gc->ngpio = 32; + gc->direction_input = mpc83xx_gpio_dir_in; + gc->direction_output = mpc83xx_gpio_dir_out; + gc->get = mpc83xx_gpio_get; + gc->set = mpc83xx_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(mpc83xx_gc); + /* try others anyway */ + } + return 0; +} +arch_initcall(mpc83xx_add_gpiochips); -- 1.5.6.3 _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev