Patchwork [1/2] gpio: move mpc8xxx/512x gpio driver to drivers/gpio

login
register
mail settings
Submitter Wolfram Sang
Date Sept. 20, 2011, 5:32 p.m.
Message ID <1316539941-14092-1-git-send-email-w.sang@pengutronix.de>
Download mbox | patch
Permalink /patch/115612/
State Changes Requested
Headers show

Comments

Wolfram Sang - Sept. 20, 2011, 5:32 p.m.
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>
---

I'd think this should go via ppc, so it is in sync with the defconfig update of
patch 2/2.

 arch/powerpc/configs/85xx/p1023rds_defconfig    |    2 +-
 arch/powerpc/configs/85xx/xes_mpc85xx_defconfig |    2 +-
 arch/powerpc/configs/mpc85xx_defconfig          |    2 +-
 arch/powerpc/configs/mpc85xx_smp_defconfig      |    2 +-
 arch/powerpc/configs/ppc6xx_defconfig           |    2 +-
 arch/powerpc/platforms/512x/Kconfig             |    1 +
 arch/powerpc/platforms/83xx/Kconfig             |    9 +-
 arch/powerpc/platforms/85xx/Kconfig             |   12 +-
 arch/powerpc/platforms/86xx/Kconfig             |    1 +
 arch/powerpc/platforms/Kconfig                  |   10 -
 arch/powerpc/sysdev/Makefile                    |    1 -
 arch/powerpc/sysdev/mpc8xxx_gpio.c              |  395 -----------------------
 drivers/gpio/Kconfig                            |    8 +
 drivers/gpio/Makefile                           |    1 +
 drivers/gpio/gpio-mpc8xxx.c                     |  395 +++++++++++++++++++++++
 15 files changed, 425 insertions(+), 418 deletions(-)
 delete mode 100644 arch/powerpc/sysdev/mpc8xxx_gpio.c
 create mode 100644 drivers/gpio/gpio-mpc8xxx.c
Wolfram Sang - Sept. 20, 2011, 5:34 p.m.
On Tue, Sep 20, 2011 at 07:32:20PM +0200, Wolfram Sang wrote:
> 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>
> ---
> 
> I'd think this should go via ppc, so it is in sync with the defconfig update of
> patch 2/2.

Forgot to mention: Both patches tested on a MPC5121-based board with
linux 3.1-rc6 (couldn't find an alternative location for ppc-next).
Grant Likely - Sept. 20, 2011, 5:59 p.m.
On Tue, Sep 20, 2011 at 07:32:20PM +0200, Wolfram Sang wrote:
> 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>
> ---
> 
> I'd think this should go via ppc, so it is in sync with the defconfig update of
> patch 2/2.
> 
>  arch/powerpc/configs/85xx/p1023rds_defconfig    |    2 +-
>  arch/powerpc/configs/85xx/xes_mpc85xx_defconfig |    2 +-
>  arch/powerpc/configs/mpc85xx_defconfig          |    2 +-
>  arch/powerpc/configs/mpc85xx_smp_defconfig      |    2 +-
>  arch/powerpc/configs/ppc6xx_defconfig           |    2 +-
>  arch/powerpc/platforms/512x/Kconfig             |    1 +
>  arch/powerpc/platforms/83xx/Kconfig             |    9 +-
>  arch/powerpc/platforms/85xx/Kconfig             |   12 +-
>  arch/powerpc/platforms/86xx/Kconfig             |    1 +
>  arch/powerpc/platforms/Kconfig                  |   10 -
>  arch/powerpc/sysdev/Makefile                    |    1 -
>  arch/powerpc/sysdev/mpc8xxx_gpio.c              |  395 -----------------------
>  drivers/gpio/Kconfig                            |    8 +
>  drivers/gpio/Makefile                           |    1 +
>  drivers/gpio/gpio-mpc8xxx.c                     |  395 +++++++++++++++++++++++

Please resubmit and use the --find-renames flag so to keep the diff
showing only the actual changes.

g.

>  15 files changed, 425 insertions(+), 418 deletions(-)
>  delete mode 100644 arch/powerpc/sysdev/mpc8xxx_gpio.c
>  create mode 100644 drivers/gpio/gpio-mpc8xxx.c
> 
> diff --git a/arch/powerpc/configs/85xx/p1023rds_defconfig b/arch/powerpc/configs/85xx/p1023rds_defconfig
> index 3ff5a81..c091aaf 100644
> --- a/arch/powerpc/configs/85xx/p1023rds_defconfig
> +++ b/arch/powerpc/configs/85xx/p1023rds_defconfig
> @@ -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
> diff --git a/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig b/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig
> index 5ea3124..1cd6fcb 100644
> --- a/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig
> +++ b/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig
> @@ -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
> diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig
> index a3467bf..2500912 100644
> --- a/arch/powerpc/configs/mpc85xx_defconfig
> +++ b/arch/powerpc/configs/mpc85xx_defconfig
> @@ -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
> diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig
> index 9693f6e..a4ba13b 100644
> --- a/arch/powerpc/configs/mpc85xx_smp_defconfig
> +++ b/arch/powerpc/configs/mpc85xx_smp_defconfig
> @@ -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
> diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig
> index 04360f9..c47f2be 100644
> --- a/arch/powerpc/configs/ppc6xx_defconfig
> +++ b/arch/powerpc/configs/ppc6xx_defconfig
> @@ -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
> diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
> index 27b0651..b3ebce1 100644
> --- a/arch/powerpc/platforms/512x/Kconfig
> +++ b/arch/powerpc/platforms/512x/Kconfig
> @@ -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"
> diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig
> index 73f4135..670a033 100644
> --- a/arch/powerpc/platforms/83xx/Kconfig
> +++ b/arch/powerpc/platforms/83xx/Kconfig
> @@ -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
> diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
> index 498534c..1b393f4 100644
> --- a/arch/powerpc/platforms/85xx/Kconfig
> +++ b/arch/powerpc/platforms/85xx/Kconfig
> @@ -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
> diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig
> index a0b5638..8d6599d 100644
> --- a/arch/powerpc/platforms/86xx/Kconfig
> +++ b/arch/powerpc/platforms/86xx/Kconfig
> @@ -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.
>  
> diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
> index b9ba861..c0cb1ea 100644
> --- a/arch/powerpc/platforms/Kconfig
> +++ b/arch/powerpc/platforms/Kconfig
> @@ -333,16 +333,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
> diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
> index cf736ca..84e1325 100644
> --- a/arch/powerpc/sysdev/Makefile
> +++ b/arch/powerpc/sysdev/Makefile
> @@ -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
> index fb4963a..0000000
> --- a/arch/powerpc/sysdev/mpc8xxx_gpio.c
> +++ /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);
> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> index d539efd..4744cf2 100644
> --- a/drivers/gpio/Kconfig
> +++ b/drivers/gpio/Kconfig
> @@ -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
> diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
> index 9588948..828bba9 100644
> --- a/drivers/gpio/Makefile
> +++ b/drivers/gpio/Makefile
> @@ -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
> index 0000000..fb4963a
> --- /dev/null
> +++ b/drivers/gpio/gpio-mpc8xxx.c
> @@ -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);
> -- 
> 1.7.5.4
>

Patch

diff --git a/arch/powerpc/configs/85xx/p1023rds_defconfig b/arch/powerpc/configs/85xx/p1023rds_defconfig
index 3ff5a81..c091aaf 100644
--- a/arch/powerpc/configs/85xx/p1023rds_defconfig
+++ b/arch/powerpc/configs/85xx/p1023rds_defconfig
@@ -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
diff --git a/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig b/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig
index 5ea3124..1cd6fcb 100644
--- a/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig
+++ b/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig
@@ -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
diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig
index a3467bf..2500912 100644
--- a/arch/powerpc/configs/mpc85xx_defconfig
+++ b/arch/powerpc/configs/mpc85xx_defconfig
@@ -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
diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig
index 9693f6e..a4ba13b 100644
--- a/arch/powerpc/configs/mpc85xx_smp_defconfig
+++ b/arch/powerpc/configs/mpc85xx_smp_defconfig
@@ -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
diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig
index 04360f9..c47f2be 100644
--- a/arch/powerpc/configs/ppc6xx_defconfig
+++ b/arch/powerpc/configs/ppc6xx_defconfig
@@ -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
diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
index 27b0651..b3ebce1 100644
--- a/arch/powerpc/platforms/512x/Kconfig
+++ b/arch/powerpc/platforms/512x/Kconfig
@@ -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"
diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig
index 73f4135..670a033 100644
--- a/arch/powerpc/platforms/83xx/Kconfig
+++ b/arch/powerpc/platforms/83xx/Kconfig
@@ -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
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index 498534c..1b393f4 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -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
diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig
index a0b5638..8d6599d 100644
--- a/arch/powerpc/platforms/86xx/Kconfig
+++ b/arch/powerpc/platforms/86xx/Kconfig
@@ -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.
 
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index b9ba861..c0cb1ea 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -333,16 +333,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
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index cf736ca..84e1325 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -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
index fb4963a..0000000
--- a/arch/powerpc/sysdev/mpc8xxx_gpio.c
+++ /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);
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index d539efd..4744cf2 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -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
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 9588948..828bba9 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -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
index 0000000..fb4963a
--- /dev/null
+++ b/drivers/gpio/gpio-mpc8xxx.c
@@ -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);