gpio: move mpc8xxx/512x gpio driver to drivers/gpio
authorWolfram Sang <w.sang@pengutronix.de>
Wed, 21 Sep 2011 10:49:20 +0000 (12:49 +0200)
committerAnatolij Gustschin <agust@denx.de>
Thu, 22 Sep 2011 22:14:15 +0000 (00:14 +0200)
Move the driver to the place where it is expected to be nowadays. Also
rename its CONFIG-name to match the rest and adapt the defconfigs.
Finally, move selection of REQUIRE_GPIOLIB or WANTS_OPTIONAL_GPIOLIB to
the platforms, because this option is per-platform and not per-driver.

Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
Cc: Anatolij Gustschin <agust@denx.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
15 files changed:
arch/powerpc/configs/85xx/p1023rds_defconfig
arch/powerpc/configs/85xx/xes_mpc85xx_defconfig
arch/powerpc/configs/mpc85xx_defconfig
arch/powerpc/configs/mpc85xx_smp_defconfig
arch/powerpc/configs/ppc6xx_defconfig
arch/powerpc/platforms/512x/Kconfig
arch/powerpc/platforms/83xx/Kconfig
arch/powerpc/platforms/85xx/Kconfig
arch/powerpc/platforms/86xx/Kconfig
arch/powerpc/platforms/Kconfig
arch/powerpc/sysdev/Makefile
arch/powerpc/sysdev/mpc8xxx_gpio.c [deleted file]
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-mpc8xxx.c [new file with mode: 0644]

index 3ff5a81c709f2f9febae80a5e1edd3a3a1ee9ca1..c091aaf7685f60efce4d72d989e2503ab3a11310 100644 (file)
@@ -24,7 +24,7 @@ CONFIG_P1023_RDS=y
 CONFIG_QUICC_ENGINE=y
 CONFIG_QE_GPIO=y
 CONFIG_CPM2=y
-CONFIG_MPC8xxx_GPIO=y
+CONFIG_GPIO_MPC8XXX=y
 CONFIG_HIGHMEM=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
index 5ea3124518fddd030460299c5a4e9319aead3652..1cd6fcb368e95f5d26a6eae5db157796c94f21de 100644 (file)
@@ -20,7 +20,7 @@ CONFIG_MODULE_FORCE_UNLOAD=y
 CONFIG_MODVERSIONS=y
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_XES_MPC85xx=y
-CONFIG_MPC8xxx_GPIO=y
+CONFIG_GPIO_MPC8XXX=y
 CONFIG_HIGHMEM=y
 CONFIG_MATH_EMULATION=y
 CONFIG_SPARSE_IRQ=y
index a3467bfb767100aaf71a4c6e2b666a7448060020..250091207452d029b1f6c959f41e59e1748e08b6 100644 (file)
@@ -41,7 +41,7 @@ CONFIG_TQM8560=y
 CONFIG_SBC8548=y
 CONFIG_QUICC_ENGINE=y
 CONFIG_QE_GPIO=y
-CONFIG_MPC8xxx_GPIO=y
+CONFIG_GPIO_MPC8XXX=y
 CONFIG_HIGHMEM=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
index 9693f6ed3da066ad0fe7839fa399826987274c0f..a4ba13b0ef1f9a92df4b164e00fe942bd9490c3c 100644 (file)
@@ -42,7 +42,7 @@ CONFIG_TQM8560=y
 CONFIG_SBC8548=y
 CONFIG_QUICC_ENGINE=y
 CONFIG_QE_GPIO=y
-CONFIG_MPC8xxx_GPIO=y
+CONFIG_GPIO_MPC8XXX=y
 CONFIG_HIGHMEM=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
index 04360f9b010939686b142791b7a24607d79e91c4..c47f2becfbc303c63a5e76b208ad4263a34b7563 100644 (file)
@@ -70,7 +70,7 @@ CONFIG_TAU_AVERAGE=y
 CONFIG_QUICC_ENGINE=y
 CONFIG_QE_GPIO=y
 CONFIG_PPC_BESTCOMM=y
-CONFIG_MPC8xxx_GPIO=y
+CONFIG_GPIO_MPC8XXX=y
 CONFIG_MCU_MPC8349EMITX=m
 CONFIG_HIGHMEM=y
 CONFIG_NO_HZ=y
index 27b0651221d157598f72fc7932bfc78b95b4d31f..b3ebce1aec075e7c699e0ead4448d631cd9722a6 100644 (file)
@@ -6,6 +6,7 @@ config PPC_MPC512x
        select PPC_CLOCK
        select PPC_PCI_CHOICE
        select FSL_PCI if PCI
+       select ARCH_WANT_OPTIONAL_GPIOLIB
 
 config MPC5121_ADS
        bool "Freescale MPC5121E ADS"
index 73f4135f3a1a6e8780e976b83fa0afc4a73d902f..670a033264c0f1626af64f79b7b4fd23da797ec4 100644 (file)
@@ -114,18 +114,21 @@ config KMETER1
 
 endif
 
-# used for usb
+# used for usb & gpio
 config PPC_MPC831x
        bool
+       select ARCH_WANT_OPTIONAL_GPIOLIB
 
 # used for math-emu
 config PPC_MPC832x
        bool
 
-# used for usb
+# used for usb & gpio
 config PPC_MPC834x
        bool
+       select ARCH_WANT_OPTIONAL_GPIOLIB
 
-# used for usb
+# used for usb & gpio
 config PPC_MPC837x
        bool
+       select ARCH_WANT_OPTIONAL_GPIOLIB
index 498534cd5265b2ca8c48e9f6f094ed6fa15993a8..1b393f40c63969fde1bafc31d1fdd79f3793e988 100644 (file)
@@ -177,7 +177,8 @@ config P2040_RDB
        select PPC_E500MC
        select PHYS_64BIT
        select SWIOTLB
-       select MPC8xxx_GPIO
+       select ARCH_REQUIRE_GPIOLIB
+       select GPIO_MPC8XXX
        select HAS_RAPIDIO
        select PPC_EPAPR_HV_PIC
        help
@@ -189,7 +190,8 @@ config P3041_DS
        select PPC_E500MC
        select PHYS_64BIT
        select SWIOTLB
-       select MPC8xxx_GPIO
+       select ARCH_REQUIRE_GPIOLIB
+       select GPIO_MPC8XXX
        select HAS_RAPIDIO
        select PPC_EPAPR_HV_PIC
        help
@@ -201,7 +203,8 @@ config P4080_DS
        select PPC_E500MC
        select PHYS_64BIT
        select SWIOTLB
-       select MPC8xxx_GPIO
+       select ARCH_REQUIRE_GPIOLIB
+       select GPIO_MPC8XXX
        select HAS_RAPIDIO
        select PPC_EPAPR_HV_PIC
        help
@@ -216,7 +219,8 @@ config P5020_DS
        select PPC_E500MC
        select PHYS_64BIT
        select SWIOTLB
-       select MPC8xxx_GPIO
+       select ARCH_REQUIRE_GPIOLIB
+       select GPIO_MPC8XXX
        select HAS_RAPIDIO
        select PPC_EPAPR_HV_PIC
        help
index a0b5638c5dc8bfef5cbfcc1d57b759c8f57bd387..8d6599d54ea6caadf8476cc42ba56734b1edfbcc 100644 (file)
@@ -4,6 +4,7 @@ menuconfig PPC_86xx
        depends on 6xx
        select FSL_SOC
        select ALTIVEC
+       select ARCH_WANT_OPTIONAL_GPIOLIB
        help
          The Freescale E600 SoCs have 74xx cores.
 
index 6de27d275728946aa3ebf94aa7cc8bc37442b558..9fdb9b6ab37119ade67227916fc932a3058830d0 100644 (file)
@@ -334,16 +334,6 @@ config OF_RTC
 
 source "arch/powerpc/sysdev/bestcomm/Kconfig"
 
-config MPC8xxx_GPIO
-       bool "MPC512x/MPC8xxx GPIO support"
-       depends on PPC_MPC512x || PPC_MPC831x || PPC_MPC834x || PPC_MPC837x || \
-                  FSL_SOC_BOOKE || PPC_86xx
-       select GENERIC_GPIO
-       select ARCH_REQUIRE_GPIOLIB
-       help
-         Say Y here if you're going to use hardware that connects to the
-         MPC512x/831x/834x/837x/8572/8610 GPIOs.
-
 config SIMPLE_GPIO
        bool "Support for simple, memory-mapped GPIO controllers"
        depends on PPC
index cf736ca0cf051bd9192fd190bea664c1a64b5427..84e13253aec5ca7f9ed6c021e1d1585ead0213de 100644 (file)
@@ -18,7 +18,6 @@ obj-$(CONFIG_FSL_PCI)         += fsl_pci.o $(fsl-msi-obj-y)
 obj-$(CONFIG_FSL_PMC)          += fsl_pmc.o
 obj-$(CONFIG_FSL_LBC)          += fsl_lbc.o
 obj-$(CONFIG_FSL_GTM)          += fsl_gtm.o
-obj-$(CONFIG_MPC8xxx_GPIO)     += mpc8xxx_gpio.o
 obj-$(CONFIG_FSL_85XX_CACHE_SRAM)      += fsl_85xx_l2ctlr.o fsl_85xx_cache_sram.o
 obj-$(CONFIG_SIMPLE_GPIO)      += simple_gpio.o
 obj-$(CONFIG_FSL_RIO)          += fsl_rio.o
diff --git a/arch/powerpc/sysdev/mpc8xxx_gpio.c b/arch/powerpc/sysdev/mpc8xxx_gpio.c
deleted file mode 100644 (file)
index fb4963a..0000000
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- * GPIOs on MPC512x/8349/8572/8610 and compatible
- *
- * Copyright (C) 2008 Peter Korsgaard <jacmet@sunsite.dk>
- *
- * 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>
-#include <linux/slab.h>
-#include <linux/irq.h>
-
-#define MPC8XXX_GPIO_PINS      32
-
-#define GPIO_DIR               0x00
-#define GPIO_ODR               0x04
-#define GPIO_DAT               0x08
-#define GPIO_IER               0x0c
-#define GPIO_IMR               0x10
-#define GPIO_ICR               0x14
-#define GPIO_ICR2              0x18
-
-struct mpc8xxx_gpio_chip {
-       struct of_mm_gpio_chip mm_gc;
-       spinlock_t lock;
-
-       /*
-        * shadowed data register to be able to clear/set output pins in
-        * open drain mode safely
-        */
-       u32 data;
-       struct irq_host *irq;
-       void *of_dev_id_data;
-};
-
-static inline u32 mpc8xxx_gpio2mask(unsigned int gpio)
-{
-       return 1u << (MPC8XXX_GPIO_PINS - 1 - gpio);
-}
-
-static inline struct mpc8xxx_gpio_chip *
-to_mpc8xxx_gpio_chip(struct of_mm_gpio_chip *mm)
-{
-       return container_of(mm, struct mpc8xxx_gpio_chip, mm_gc);
-}
-
-static void mpc8xxx_gpio_save_regs(struct of_mm_gpio_chip *mm)
-{
-       struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
-
-       mpc8xxx_gc->data = in_be32(mm->regs + GPIO_DAT);
-}
-
-/* Workaround GPIO 1 errata on MPC8572/MPC8536. The status of GPIOs
- * defined as output cannot be determined by reading GPDAT register,
- * so we use shadow data register instead. The status of input pins
- * is determined by reading GPDAT register.
- */
-static int mpc8572_gpio_get(struct gpio_chip *gc, unsigned int gpio)
-{
-       u32 val;
-       struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
-       struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
-
-       val = in_be32(mm->regs + GPIO_DAT) & ~in_be32(mm->regs + GPIO_DIR);
-
-       return (val | mpc8xxx_gc->data) & mpc8xxx_gpio2mask(gpio);
-}
-
-static int mpc8xxx_gpio_get(struct gpio_chip *gc, unsigned int gpio)
-{
-       struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
-
-       return in_be32(mm->regs + GPIO_DAT) & mpc8xxx_gpio2mask(gpio);
-}
-
-static void mpc8xxx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
-{
-       struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
-       struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
-       unsigned long flags;
-
-       spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
-
-       if (val)
-               mpc8xxx_gc->data |= mpc8xxx_gpio2mask(gpio);
-       else
-               mpc8xxx_gc->data &= ~mpc8xxx_gpio2mask(gpio);
-
-       out_be32(mm->regs + GPIO_DAT, mpc8xxx_gc->data);
-
-       spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
-}
-
-static int mpc8xxx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
-{
-       struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
-       struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
-       unsigned long flags;
-
-       spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
-
-       clrbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio));
-
-       spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
-
-       return 0;
-}
-
-static int mpc8xxx_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 mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
-       unsigned long flags;
-
-       mpc8xxx_gpio_set(gc, gpio, val);
-
-       spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
-
-       setbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio));
-
-       spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
-
-       return 0;
-}
-
-static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
-{
-       struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
-       struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
-
-       if (mpc8xxx_gc->irq && offset < MPC8XXX_GPIO_PINS)
-               return irq_create_mapping(mpc8xxx_gc->irq, offset);
-       else
-               return -ENXIO;
-}
-
-static void mpc8xxx_gpio_irq_cascade(unsigned int irq, struct irq_desc *desc)
-{
-       struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_desc_get_handler_data(desc);
-       struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
-       unsigned int mask;
-
-       mask = in_be32(mm->regs + GPIO_IER) & in_be32(mm->regs + GPIO_IMR);
-       if (mask)
-               generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq,
-                                                    32 - ffs(mask)));
-}
-
-static void mpc8xxx_irq_unmask(struct irq_data *d)
-{
-       struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
-       struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
-       unsigned long flags;
-
-       spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
-
-       setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
-
-       spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
-}
-
-static void mpc8xxx_irq_mask(struct irq_data *d)
-{
-       struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
-       struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
-       unsigned long flags;
-
-       spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
-
-       clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
-
-       spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
-}
-
-static void mpc8xxx_irq_ack(struct irq_data *d)
-{
-       struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
-       struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
-
-       out_be32(mm->regs + GPIO_IER, mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
-}
-
-static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
-{
-       struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
-       struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
-       unsigned long flags;
-
-       switch (flow_type) {
-       case IRQ_TYPE_EDGE_FALLING:
-               spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
-               setbits32(mm->regs + GPIO_ICR,
-                         mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
-               spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
-               break;
-
-       case IRQ_TYPE_EDGE_BOTH:
-               spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
-               clrbits32(mm->regs + GPIO_ICR,
-                         mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
-               spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int mpc512x_irq_set_type(struct irq_data *d, unsigned int flow_type)
-{
-       struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
-       struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
-       unsigned long gpio = irqd_to_hwirq(d);
-       void __iomem *reg;
-       unsigned int shift;
-       unsigned long flags;
-
-       if (gpio < 16) {
-               reg = mm->regs + GPIO_ICR;
-               shift = (15 - gpio) * 2;
-       } else {
-               reg = mm->regs + GPIO_ICR2;
-               shift = (15 - (gpio % 16)) * 2;
-       }
-
-       switch (flow_type) {
-       case IRQ_TYPE_EDGE_FALLING:
-       case IRQ_TYPE_LEVEL_LOW:
-               spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
-               clrsetbits_be32(reg, 3 << shift, 2 << shift);
-               spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
-               break;
-
-       case IRQ_TYPE_EDGE_RISING:
-       case IRQ_TYPE_LEVEL_HIGH:
-               spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
-               clrsetbits_be32(reg, 3 << shift, 1 << shift);
-               spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
-               break;
-
-       case IRQ_TYPE_EDGE_BOTH:
-               spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
-               clrbits32(reg, 3 << shift);
-               spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static struct irq_chip mpc8xxx_irq_chip = {
-       .name           = "mpc8xxx-gpio",
-       .irq_unmask     = mpc8xxx_irq_unmask,
-       .irq_mask       = mpc8xxx_irq_mask,
-       .irq_ack        = mpc8xxx_irq_ack,
-       .irq_set_type   = mpc8xxx_irq_set_type,
-};
-
-static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq,
-                               irq_hw_number_t hw)
-{
-       struct mpc8xxx_gpio_chip *mpc8xxx_gc = h->host_data;
-
-       if (mpc8xxx_gc->of_dev_id_data)
-               mpc8xxx_irq_chip.irq_set_type = mpc8xxx_gc->of_dev_id_data;
-
-       irq_set_chip_data(virq, h->host_data);
-       irq_set_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq);
-       irq_set_irq_type(virq, IRQ_TYPE_NONE);
-
-       return 0;
-}
-
-static int mpc8xxx_gpio_irq_xlate(struct irq_host *h, struct device_node *ct,
-                                 const u32 *intspec, unsigned int intsize,
-                                 irq_hw_number_t *out_hwirq,
-                                 unsigned int *out_flags)
-
-{
-       /* interrupt sense values coming from the device tree equal either
-        * EDGE_FALLING or EDGE_BOTH
-        */
-       *out_hwirq = intspec[0];
-       *out_flags = intspec[1];
-
-       return 0;
-}
-
-static struct irq_host_ops mpc8xxx_gpio_irq_ops = {
-       .map    = mpc8xxx_gpio_irq_map,
-       .xlate  = mpc8xxx_gpio_irq_xlate,
-};
-
-static struct of_device_id mpc8xxx_gpio_ids[] __initdata = {
-       { .compatible = "fsl,mpc8349-gpio", },
-       { .compatible = "fsl,mpc8572-gpio", },
-       { .compatible = "fsl,mpc8610-gpio", },
-       { .compatible = "fsl,mpc5121-gpio", .data = mpc512x_irq_set_type, },
-       { .compatible = "fsl,qoriq-gpio",   },
-       {}
-};
-
-static void __init mpc8xxx_add_controller(struct device_node *np)
-{
-       struct mpc8xxx_gpio_chip *mpc8xxx_gc;
-       struct of_mm_gpio_chip *mm_gc;
-       struct gpio_chip *gc;
-       const struct of_device_id *id;
-       unsigned hwirq;
-       int ret;
-
-       mpc8xxx_gc = kzalloc(sizeof(*mpc8xxx_gc), GFP_KERNEL);
-       if (!mpc8xxx_gc) {
-               ret = -ENOMEM;
-               goto err;
-       }
-
-       spin_lock_init(&mpc8xxx_gc->lock);
-
-       mm_gc = &mpc8xxx_gc->mm_gc;
-       gc = &mm_gc->gc;
-
-       mm_gc->save_regs = mpc8xxx_gpio_save_regs;
-       gc->ngpio = MPC8XXX_GPIO_PINS;
-       gc->direction_input = mpc8xxx_gpio_dir_in;
-       gc->direction_output = mpc8xxx_gpio_dir_out;
-       if (of_device_is_compatible(np, "fsl,mpc8572-gpio"))
-               gc->get = mpc8572_gpio_get;
-       else
-               gc->get = mpc8xxx_gpio_get;
-       gc->set = mpc8xxx_gpio_set;
-       gc->to_irq = mpc8xxx_gpio_to_irq;
-
-       ret = of_mm_gpiochip_add(np, mm_gc);
-       if (ret)
-               goto err;
-
-       hwirq = irq_of_parse_and_map(np, 0);
-       if (hwirq == NO_IRQ)
-               goto skip_irq;
-
-       mpc8xxx_gc->irq =
-               irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, MPC8XXX_GPIO_PINS,
-                              &mpc8xxx_gpio_irq_ops, MPC8XXX_GPIO_PINS);
-       if (!mpc8xxx_gc->irq)
-               goto skip_irq;
-
-       id = of_match_node(mpc8xxx_gpio_ids, np);
-       if (id)
-               mpc8xxx_gc->of_dev_id_data = id->data;
-
-       mpc8xxx_gc->irq->host_data = mpc8xxx_gc;
-
-       /* ack and mask all irqs */
-       out_be32(mm_gc->regs + GPIO_IER, 0xffffffff);
-       out_be32(mm_gc->regs + GPIO_IMR, 0);
-
-       irq_set_handler_data(hwirq, mpc8xxx_gc);
-       irq_set_chained_handler(hwirq, mpc8xxx_gpio_irq_cascade);
-
-skip_irq:
-       return;
-
-err:
-       pr_err("%s: registration failed with status %d\n",
-              np->full_name, ret);
-       kfree(mpc8xxx_gc);
-
-       return;
-}
-
-static int __init mpc8xxx_add_gpiochips(void)
-{
-       struct device_node *np;
-
-       for_each_matching_node(np, mpc8xxx_gpio_ids)
-               mpc8xxx_add_controller(np);
-
-       return 0;
-}
-arch_initcall(mpc8xxx_add_gpiochips);
index d539efd96d4b8d5b7c032c5c0767543da7413cd7..4744cf246d4a6a9b86431c4249807e3bf6ee7ee3 100644 (file)
@@ -103,6 +103,14 @@ config GPIO_MPC5200
        def_bool y
        depends on PPC_MPC52xx
 
+config GPIO_MPC8XXX
+       bool "MPC512x/MPC8xxx GPIO support"
+       depends on PPC_MPC512x || PPC_MPC831x || PPC_MPC834x || PPC_MPC837x || \
+                  FSL_SOC_BOOKE || PPC_86xx
+       help
+         Say Y here if you're going to use hardware that connects to the
+         MPC512x/831x/834x/837x/8572/8610 GPIOs.
+
 config GPIO_MSM_V1
        tristate "Qualcomm MSM GPIO v1"
        depends on GPIOLIB && ARCH_MSM
index 9588948c96f08b2e8487b6333d7151fd1e914267..828bba9883c3b648c16e45db2632eeddf83e912c 100644 (file)
@@ -27,6 +27,7 @@ obj-$(CONFIG_GPIO_MC33880)    += gpio-mc33880.o
 obj-$(CONFIG_GPIO_MCP23S08)    += gpio-mcp23s08.o
 obj-$(CONFIG_GPIO_ML_IOH)      += gpio-ml-ioh.o
 obj-$(CONFIG_GPIO_MPC5200)     += gpio-mpc5200.o
+obj-$(CONFIG_GPIO_MPC8XXX)     += gpio-mpc8xxx.o
 obj-$(CONFIG_GPIO_MSM_V1)      += gpio-msm-v1.o
 obj-$(CONFIG_GPIO_MSM_V2)      += gpio-msm-v2.o
 obj-$(CONFIG_GPIO_MXC)         += gpio-mxc.o
diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c
new file mode 100644 (file)
index 0000000..fb4963a
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * GPIOs on MPC512x/8349/8572/8610 and compatible
+ *
+ * Copyright (C) 2008 Peter Korsgaard <jacmet@sunsite.dk>
+ *
+ * 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>
+#include <linux/slab.h>
+#include <linux/irq.h>
+
+#define MPC8XXX_GPIO_PINS      32
+
+#define GPIO_DIR               0x00
+#define GPIO_ODR               0x04
+#define GPIO_DAT               0x08
+#define GPIO_IER               0x0c
+#define GPIO_IMR               0x10
+#define GPIO_ICR               0x14
+#define GPIO_ICR2              0x18
+
+struct mpc8xxx_gpio_chip {
+       struct of_mm_gpio_chip mm_gc;
+       spinlock_t lock;
+
+       /*
+        * shadowed data register to be able to clear/set output pins in
+        * open drain mode safely
+        */
+       u32 data;
+       struct irq_host *irq;
+       void *of_dev_id_data;
+};
+
+static inline u32 mpc8xxx_gpio2mask(unsigned int gpio)
+{
+       return 1u << (MPC8XXX_GPIO_PINS - 1 - gpio);
+}
+
+static inline struct mpc8xxx_gpio_chip *
+to_mpc8xxx_gpio_chip(struct of_mm_gpio_chip *mm)
+{
+       return container_of(mm, struct mpc8xxx_gpio_chip, mm_gc);
+}
+
+static void mpc8xxx_gpio_save_regs(struct of_mm_gpio_chip *mm)
+{
+       struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+
+       mpc8xxx_gc->data = in_be32(mm->regs + GPIO_DAT);
+}
+
+/* Workaround GPIO 1 errata on MPC8572/MPC8536. The status of GPIOs
+ * defined as output cannot be determined by reading GPDAT register,
+ * so we use shadow data register instead. The status of input pins
+ * is determined by reading GPDAT register.
+ */
+static int mpc8572_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+       u32 val;
+       struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
+       struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+
+       val = in_be32(mm->regs + GPIO_DAT) & ~in_be32(mm->regs + GPIO_DIR);
+
+       return (val | mpc8xxx_gc->data) & mpc8xxx_gpio2mask(gpio);
+}
+
+static int mpc8xxx_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+       struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
+
+       return in_be32(mm->regs + GPIO_DAT) & mpc8xxx_gpio2mask(gpio);
+}
+
+static void mpc8xxx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+       struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
+       struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+       unsigned long flags;
+
+       spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+
+       if (val)
+               mpc8xxx_gc->data |= mpc8xxx_gpio2mask(gpio);
+       else
+               mpc8xxx_gc->data &= ~mpc8xxx_gpio2mask(gpio);
+
+       out_be32(mm->regs + GPIO_DAT, mpc8xxx_gc->data);
+
+       spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+}
+
+static int mpc8xxx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+       struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
+       struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+       unsigned long flags;
+
+       spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+
+       clrbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio));
+
+       spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+
+       return 0;
+}
+
+static int mpc8xxx_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 mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+       unsigned long flags;
+
+       mpc8xxx_gpio_set(gc, gpio, val);
+
+       spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+
+       setbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio));
+
+       spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+
+       return 0;
+}
+
+static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+       struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
+       struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+
+       if (mpc8xxx_gc->irq && offset < MPC8XXX_GPIO_PINS)
+               return irq_create_mapping(mpc8xxx_gc->irq, offset);
+       else
+               return -ENXIO;
+}
+
+static void mpc8xxx_gpio_irq_cascade(unsigned int irq, struct irq_desc *desc)
+{
+       struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_desc_get_handler_data(desc);
+       struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
+       unsigned int mask;
+
+       mask = in_be32(mm->regs + GPIO_IER) & in_be32(mm->regs + GPIO_IMR);
+       if (mask)
+               generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq,
+                                                    32 - ffs(mask)));
+}
+
+static void mpc8xxx_irq_unmask(struct irq_data *d)
+{
+       struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
+       struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+
+       setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
+
+       spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+}
+
+static void mpc8xxx_irq_mask(struct irq_data *d)
+{
+       struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
+       struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+
+       clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
+
+       spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+}
+
+static void mpc8xxx_irq_ack(struct irq_data *d)
+{
+       struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
+       struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
+
+       out_be32(mm->regs + GPIO_IER, mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
+}
+
+static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
+{
+       struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
+       struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
+       unsigned long flags;
+
+       switch (flow_type) {
+       case IRQ_TYPE_EDGE_FALLING:
+               spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+               setbits32(mm->regs + GPIO_ICR,
+                         mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
+               spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+               break;
+
+       case IRQ_TYPE_EDGE_BOTH:
+               spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+               clrbits32(mm->regs + GPIO_ICR,
+                         mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
+               spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int mpc512x_irq_set_type(struct irq_data *d, unsigned int flow_type)
+{
+       struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
+       struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
+       unsigned long gpio = irqd_to_hwirq(d);
+       void __iomem *reg;
+       unsigned int shift;
+       unsigned long flags;
+
+       if (gpio < 16) {
+               reg = mm->regs + GPIO_ICR;
+               shift = (15 - gpio) * 2;
+       } else {
+               reg = mm->regs + GPIO_ICR2;
+               shift = (15 - (gpio % 16)) * 2;
+       }
+
+       switch (flow_type) {
+       case IRQ_TYPE_EDGE_FALLING:
+       case IRQ_TYPE_LEVEL_LOW:
+               spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+               clrsetbits_be32(reg, 3 << shift, 2 << shift);
+               spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+               break;
+
+       case IRQ_TYPE_EDGE_RISING:
+       case IRQ_TYPE_LEVEL_HIGH:
+               spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+               clrsetbits_be32(reg, 3 << shift, 1 << shift);
+               spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+               break;
+
+       case IRQ_TYPE_EDGE_BOTH:
+               spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+               clrbits32(reg, 3 << shift);
+               spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct irq_chip mpc8xxx_irq_chip = {
+       .name           = "mpc8xxx-gpio",
+       .irq_unmask     = mpc8xxx_irq_unmask,
+       .irq_mask       = mpc8xxx_irq_mask,
+       .irq_ack        = mpc8xxx_irq_ack,
+       .irq_set_type   = mpc8xxx_irq_set_type,
+};
+
+static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq,
+                               irq_hw_number_t hw)
+{
+       struct mpc8xxx_gpio_chip *mpc8xxx_gc = h->host_data;
+
+       if (mpc8xxx_gc->of_dev_id_data)
+               mpc8xxx_irq_chip.irq_set_type = mpc8xxx_gc->of_dev_id_data;
+
+       irq_set_chip_data(virq, h->host_data);
+       irq_set_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq);
+       irq_set_irq_type(virq, IRQ_TYPE_NONE);
+
+       return 0;
+}
+
+static int mpc8xxx_gpio_irq_xlate(struct irq_host *h, struct device_node *ct,
+                                 const u32 *intspec, unsigned int intsize,
+                                 irq_hw_number_t *out_hwirq,
+                                 unsigned int *out_flags)
+
+{
+       /* interrupt sense values coming from the device tree equal either
+        * EDGE_FALLING or EDGE_BOTH
+        */
+       *out_hwirq = intspec[0];
+       *out_flags = intspec[1];
+
+       return 0;
+}
+
+static struct irq_host_ops mpc8xxx_gpio_irq_ops = {
+       .map    = mpc8xxx_gpio_irq_map,
+       .xlate  = mpc8xxx_gpio_irq_xlate,
+};
+
+static struct of_device_id mpc8xxx_gpio_ids[] __initdata = {
+       { .compatible = "fsl,mpc8349-gpio", },
+       { .compatible = "fsl,mpc8572-gpio", },
+       { .compatible = "fsl,mpc8610-gpio", },
+       { .compatible = "fsl,mpc5121-gpio", .data = mpc512x_irq_set_type, },
+       { .compatible = "fsl,qoriq-gpio",   },
+       {}
+};
+
+static void __init mpc8xxx_add_controller(struct device_node *np)
+{
+       struct mpc8xxx_gpio_chip *mpc8xxx_gc;
+       struct of_mm_gpio_chip *mm_gc;
+       struct gpio_chip *gc;
+       const struct of_device_id *id;
+       unsigned hwirq;
+       int ret;
+
+       mpc8xxx_gc = kzalloc(sizeof(*mpc8xxx_gc), GFP_KERNEL);
+       if (!mpc8xxx_gc) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       spin_lock_init(&mpc8xxx_gc->lock);
+
+       mm_gc = &mpc8xxx_gc->mm_gc;
+       gc = &mm_gc->gc;
+
+       mm_gc->save_regs = mpc8xxx_gpio_save_regs;
+       gc->ngpio = MPC8XXX_GPIO_PINS;
+       gc->direction_input = mpc8xxx_gpio_dir_in;
+       gc->direction_output = mpc8xxx_gpio_dir_out;
+       if (of_device_is_compatible(np, "fsl,mpc8572-gpio"))
+               gc->get = mpc8572_gpio_get;
+       else
+               gc->get = mpc8xxx_gpio_get;
+       gc->set = mpc8xxx_gpio_set;
+       gc->to_irq = mpc8xxx_gpio_to_irq;
+
+       ret = of_mm_gpiochip_add(np, mm_gc);
+       if (ret)
+               goto err;
+
+       hwirq = irq_of_parse_and_map(np, 0);
+       if (hwirq == NO_IRQ)
+               goto skip_irq;
+
+       mpc8xxx_gc->irq =
+               irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, MPC8XXX_GPIO_PINS,
+                              &mpc8xxx_gpio_irq_ops, MPC8XXX_GPIO_PINS);
+       if (!mpc8xxx_gc->irq)
+               goto skip_irq;
+
+       id = of_match_node(mpc8xxx_gpio_ids, np);
+       if (id)
+               mpc8xxx_gc->of_dev_id_data = id->data;
+
+       mpc8xxx_gc->irq->host_data = mpc8xxx_gc;
+
+       /* ack and mask all irqs */
+       out_be32(mm_gc->regs + GPIO_IER, 0xffffffff);
+       out_be32(mm_gc->regs + GPIO_IMR, 0);
+
+       irq_set_handler_data(hwirq, mpc8xxx_gc);
+       irq_set_chained_handler(hwirq, mpc8xxx_gpio_irq_cascade);
+
+skip_irq:
+       return;
+
+err:
+       pr_err("%s: registration failed with status %d\n",
+              np->full_name, ret);
+       kfree(mpc8xxx_gc);
+
+       return;
+}
+
+static int __init mpc8xxx_add_gpiochips(void)
+{
+       struct device_node *np;
+
+       for_each_matching_node(np, mpc8xxx_gpio_ids)
+               mpc8xxx_add_controller(np);
+
+       return 0;
+}
+arch_initcall(mpc8xxx_add_gpiochips);