[PATCH 5/5] ARM: pxa: move gpio driver into drivers directory

Grant Likely grant.likely at secretlab.ca
Thu Sep 29 18:27:23 EDT 2011


On Thu, Sep 29, 2011 at 11:19:06PM +0800, Haojian Zhuang wrote:
> Move gpio driver from plat-pxa to drivers/gpio directory. Only leave
> gpio number macro in mach/gpio.h.
> 
> Signed-off-by: Haojian Zhuang <haojian.zhuang at marvell.com>
> ---
>  arch/arm/mach-mmp/Kconfig             |    3 +
>  arch/arm/mach-mmp/Makefile            |    2 +-
>  arch/arm/mach-mmp/aspenite.c          |    4 +-
>  arch/arm/mach-mmp/flint.c             |    4 +-
>  arch/arm/mach-mmp/gpio.c              |   89 ++++++
>  arch/arm/mach-mmp/gplugd.c            |    2 +-
>  arch/arm/mach-mmp/include/mach/gpio.h |   24 +--
>  arch/arm/mach-mmp/include/mach/irqs.h |    4 +-
>  arch/arm/mach-mmp/mmp2.c              |   17 --
>  arch/arm/mach-mmp/pxa168.c            |   17 --
>  arch/arm/mach-mmp/pxa910.c            |   17 --
>  arch/arm/mach-mmp/tavorevb.c          |    4 +-
>  arch/arm/mach-mmp/teton_bga.c         |    2 +-
>  arch/arm/mach-mmp/ttc_dkb.c           |    2 +-
>  arch/arm/mach-pxa/Kconfig             |    6 +
>  arch/arm/mach-pxa/Makefile            |    2 +-
>  arch/arm/mach-pxa/gpio.c              |   92 ++++++
>  arch/arm/mach-pxa/include/mach/gpio.h |   64 -----
>  arch/arm/mach-pxa/pxa25x.c            |    3 -
>  arch/arm/mach-pxa/pxa27x.c            |    2 -
>  arch/arm/mach-pxa/pxa3xx.c            |    2 -
>  arch/arm/mach-pxa/pxa95x.c            |    2 -
>  arch/arm/plat-pxa/Makefile            |    1 -
>  arch/arm/plat-pxa/gpio.c              |  352 -----------------------
>  arch/arm/plat-pxa/include/plat/gpio.h |   65 -----
>  drivers/gpio/Kconfig                  |    6 +
>  drivers/gpio/Makefile                 |    1 +
>  drivers/gpio/gpio-pxa.c               |  500 +++++++++++++++++++++++++++++++++
>  include/linux/gpio-pxa.h              |  105 +++++++
>  29 files changed, 816 insertions(+), 578 deletions(-)
>  create mode 100644 arch/arm/mach-mmp/gpio.c
>  create mode 100644 arch/arm/mach-pxa/gpio.c
>  delete mode 100644 arch/arm/plat-pxa/gpio.c
>  delete mode 100644 arch/arm/plat-pxa/include/plat/gpio.h
>  create mode 100644 drivers/gpio/gpio-pxa.c
>  create mode 100644 include/linux/gpio-pxa.h
> 
> diff --git a/arch/arm/mach-mmp/Kconfig b/arch/arm/mach-mmp/Kconfig
> index 56ef5f6..47810fb 100644
> --- a/arch/arm/mach-mmp/Kconfig
> +++ b/arch/arm/mach-mmp/Kconfig
> @@ -89,18 +89,21 @@ endmenu
>  config CPU_PXA168
>  	bool
>  	select CPU_MOHAWK
> +	select GPIO_PXA
>  	help
>  	  Select code specific to PXA168
>  
>  config CPU_PXA910
>  	bool
>  	select CPU_MOHAWK
> +	select GPIO_PXA
>  	help
>  	  Select code specific to PXA910
>  
>  config CPU_MMP2
>  	bool
>  	select CPU_PJ4
> +	select GPIO_PXA
>  	help
>  	  Select code specific to MMP2. MMP2 is ARMv7 compatible.
>  endif
> diff --git a/arch/arm/mach-mmp/Makefile b/arch/arm/mach-mmp/Makefile
> index b0ac942..5af46eb 100644
> --- a/arch/arm/mach-mmp/Makefile
> +++ b/arch/arm/mach-mmp/Makefile
> @@ -2,7 +2,7 @@
>  # Makefile for Marvell's PXA168 processors line
>  #
>  
> -obj-y				+= common.o clock.o devices.o time.o
> +obj-y				+= common.o clock.o devices.o time.o gpio.o
>  
>  # SoC support
>  obj-$(CONFIG_CPU_PXA168)	+= pxa168.o irq-pxa168.o
> diff --git a/arch/arm/mach-mmp/aspenite.c b/arch/arm/mach-mmp/aspenite.c
> index 6b19812..88770cf 100644
> --- a/arch/arm/mach-mmp/aspenite.c
> +++ b/arch/arm/mach-mmp/aspenite.c
> @@ -119,8 +119,8 @@ static struct resource smc91x_resources[] = {
>  		.flags	= IORESOURCE_MEM,
>  	},
>  	[1] = {
> -		.start	= pxa_gpio_to_irq(27),
> -		.end	= pxa_gpio_to_irq(27),
> +		.start	= mmp_gpio_to_irq(27),
> +		.end	= mmp_gpio_to_irq(27),
>  		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
>  	}
>  };
> diff --git a/arch/arm/mach-mmp/flint.c b/arch/arm/mach-mmp/flint.c
> index f466a2c..19dfdf5 100644
> --- a/arch/arm/mach-mmp/flint.c
> +++ b/arch/arm/mach-mmp/flint.c
> @@ -87,8 +87,8 @@ static struct resource smc91x_resources[] = {
>  		.flags  = IORESOURCE_MEM,
>  	},
>  	[1] = {
> -		.start  = pxa_gpio_to_irq(155),
> -		.end    = pxa_gpio_to_irq(155),
> +		.start  = mmp_gpio_to_irq(155),
> +		.end    = mmp_gpio_to_irq(155),
>  		.flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
>  	}
>  };
> diff --git a/arch/arm/mach-mmp/gpio.c b/arch/arm/mach-mmp/gpio.c
> new file mode 100644
> index 0000000..345341d5
> --- /dev/null
> +++ b/arch/arm/mach-mmp/gpio.c
> @@ -0,0 +1,89 @@
> +/*
> + *  linux/arch/arm/mach-mmp/gpio.c
> + *
> + *  MMP series specific gpio init
> + *
> + *  Copyright (C) 2011 Marvell International Ltd.
> + *
> + *  Author:
> + *  	Haojian Zhuang <haojian.zhuang at marvell.com>
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License version 2 as
> + *  published by the Free Software Foundation.
> + */
> +
> +#include <linux/gpio-pxa.h>
> +#include <linux/platform_device.h>
> +
> +#include <asm/io.h>
> +
> +#include <mach/cputype.h>
> +#include <mach/irqs.h>
> +#include <mach/regs-apbc.h>
> +
> +#define GPIO_REGS_VIRT	(APB_VIRT_BASE + 0x19000)
> +#define APMASK(i)	(GPIO_REGS_VIRT + BANK_OFF(i) + 0x09c)
> +
> +static struct __initdata pxa_gpio_platform_data mmp_gpio_config;
> +
> +static struct __initdata resource mmp_resources_gpio[] = {
> +	{
> +		.start	= 0xd4010000,
> +		.end	= 0xd401ffff,
> +		.flags	= IORESOURCE_MEM,
> +	}, {
> +		.start	= IRQ_PXA168_GPIOX,
> +		.end	= IRQ_PXA168_GPIOX,
> +		.name	= "gpio_mux",
> +		.flags	= IORESOURCE_IRQ,
> +	},
> +};
> +
> +static struct platform_device mmp_gpio = {
> +	.name		= "pxa-gpio",
> +	.id		= -1,
> +	.num_resources	= ARRAY_SIZE(mmp_resources_gpio),
> +	.resource	= mmp_resources_gpio,
> +};
> +
> +static int __init mmp_gpio_init(void)
> +{
> +	int size = sizeof(struct pxa_gpio_platform_data);
> +	u32 reg_base = GPIO_REGS_VIRT;
> +	int i;
> +
> +	if (cpu_is_pxa168() || cpu_is_pxa910()) {
> +		/* enable GPIO clock */
> +		__raw_writel(APBC_APBCLK | APBC_FNCLK, APBC_PXA168_GPIO);
> +		
> +		/* unmask GPIO edge detection for all 4 banks - APMASKx */
> +		for (i = 0; i < 4; i++)
> +			__raw_writel(0xffffffff, APMASK(i));
> +		mmp_gpio_config.gpio_type = MMP_GPIO;
> +		mmp_gpio_config.gpio_end = 127;
> +	} else if (cpu_is_mmp2()) {
> +		/* enable GPIO clock */
> +		__raw_writel(APBC_APBCLK | APBC_FNCLK, APBC_MMP2_GPIO);
> +		
> +		/* unmask GPIO edge detection for all 6 banks -- APMASKx */
> +		for (i = 0; i < 6; i++)
> +			__raw_writel(0xffffffff, APMASK(i));
> +		mmp_gpio_config.gpio_type = MMP2_GPIO;
> +		mmp_gpio_config.gpio_end = 191;
> +	} else
> +		return 0;
> +
> +	pxa_gpio_regs.gplr = reg_base + GPLR_OFFSET;
> +	pxa_gpio_regs.gpdr = reg_base + GPDR_OFFSET;
> +	pxa_gpio_regs.gpsr = reg_base + GPSR_OFFSET;
> +	pxa_gpio_regs.gpcr = reg_base + GPCR_OFFSET;
> +	pxa_gpio_regs.grer = reg_base + GRER_OFFSET;
> +	pxa_gpio_regs.gfer = reg_base + GFER_OFFSET;
> +	pxa_gpio_regs.gedr = reg_base + GEDR_OFFSET;
> +
> +	platform_device_add_data(&mmp_gpio, &mmp_gpio_config, size);
> +	platform_device_register(&mmp_gpio);
> +	return 0;
> +}
> +postcore_initcall(mmp_gpio_init);

You'll also want to bail on this init function if a DT is passed to
the kernel.  Otherwise it looks okay.

> diff --git a/arch/arm/mach-mmp/gplugd.c b/arch/arm/mach-mmp/gplugd.c
> index 98e25d9..32776f3 100644
> --- a/arch/arm/mach-mmp/gplugd.c
> +++ b/arch/arm/mach-mmp/gplugd.c
> @@ -9,11 +9,11 @@
>   */
>  
>  #include <linux/init.h>
> +#include <linux/gpio.h>
>  
>  #include <asm/mach/arch.h>
>  #include <asm/mach-types.h>
>  
> -#include <mach/gpio.h>
>  #include <mach/pxa168.h>
>  #include <mach/mfp-pxa168.h>
>  
> diff --git a/arch/arm/mach-mmp/include/mach/gpio.h b/arch/arm/mach-mmp/include/mach/gpio.h
> index 89d499e..9a2f4e1 100644
> --- a/arch/arm/mach-mmp/include/mach/gpio.h
> +++ b/arch/arm/mach-mmp/include/mach/gpio.h
> @@ -3,31 +3,9 @@
>  
>  #include <mach/addr-map.h>
>  #include <mach/irqs.h>
> -#include <asm-generic/gpio.h>
>  
> -#define GPIO_REGS_VIRT	(APB_VIRT_BASE + 0x19000)
> -
> -#define BANK_OFF(n)	(((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2))
> -#define GPIO_REG(x)	(*((volatile u32 *)(GPIO_REGS_VIRT + (x))))
> +#define GPIO_REGS_VIRT		(APB_VIRT_BASE + 0x19000)

Nit: don't change the whitespace on this line because it isn't
actually changing functionally, but diff makes it look like it is.

I assume these remaining macros will be removed/reworked in a future
patch?

>  
>  #define NR_BUILTIN_GPIO		IRQ_GPIO_NUM
>  
> -#define gpio_to_bank(gpio)	((gpio) >> 5)
> -
> -#define __gpio_is_inverted(gpio)	(0)
> -#define __gpio_is_occupied(gpio)	(0)
> -
> -/* NOTE: these macros are defined here to make optimization of
> - * gpio_{get,set}_value() to work when 'gpio' is a constant.
> - * Usage of these macros otherwise is no longer recommended,
> - * use generic GPIO API whenever possible.
> - */
> -#define GPIO_bit(gpio)	(1 << ((gpio) & 0x1f))
> -
> -#define GPLR(x)		GPIO_REG(BANK_OFF(gpio_to_bank(x)) + 0x00)
> -#define GPDR(x)		GPIO_REG(BANK_OFF(gpio_to_bank(x)) + 0x0c)
> -#define GPSR(x)		GPIO_REG(BANK_OFF(gpio_to_bank(x)) + 0x18)
> -#define GPCR(x)		GPIO_REG(BANK_OFF(gpio_to_bank(x)) + 0x24)
> -
> -#include <plat/gpio.h>
>  #endif /* __ASM_MACH_GPIO_H */
> diff --git a/arch/arm/mach-mmp/include/mach/irqs.h b/arch/arm/mach-mmp/include/mach/irqs.h
> index 2971a00..6a72198 100644
> --- a/arch/arm/mach-mmp/include/mach/irqs.h
> +++ b/arch/arm/mach-mmp/include/mach/irqs.h
> @@ -220,8 +220,8 @@
>  
>  #define IRQ_GPIO_START			128
>  #define IRQ_GPIO_NUM			192
> -#define pxa_gpio_to_irq(gpio)		(IRQ_GPIO_START + (gpio))
> -#define pxa_irq_to_gpio(irq)		((irq) - IRQ_GPIO_START)
> +#define mmp_gpio_to_irq(gpio)		(IRQ_GPIO_START + (gpio))
> +#define mmp_irq_to_gpio(irq)		((irq) - IRQ_GPIO_START)
>  
>  #define IRQ_BOARD_START			(IRQ_GPIO_START + IRQ_GPIO_NUM)
>  
> diff --git a/arch/arm/mach-mmp/mmp2.c b/arch/arm/mach-mmp/mmp2.c
> index 1935834..5d31333 100644
> --- a/arch/arm/mach-mmp/mmp2.c
> +++ b/arch/arm/mach-mmp/mmp2.c
> @@ -33,8 +33,6 @@
>  
>  #define MFPR_VIRT_BASE	(APB_VIRT_BASE + 0x1e000)
>  
> -#define APMASK(i)	(GPIO_REGS_VIRT + BANK_OFF(i) + 0x9c)
> -
>  static struct mfp_addr_map mmp2_addr_map[] __initdata = {
>  
>  	MFP_ADDR_X(GPIO0, GPIO58, 0x54),
> @@ -94,24 +92,9 @@ void mmp2_clear_pmic_int(void)
>  	__raw_writel(data, mfpr_pmic);
>  }
>  
> -static void __init mmp2_init_gpio(void)
> -{
> -	int i;
> -
> -	/* enable GPIO clock */
> -	__raw_writel(APBC_APBCLK | APBC_FNCLK, APBC_MMP2_GPIO);
> -
> -	/* unmask GPIO edge detection for all 6 banks -- APMASKx */
> -	for (i = 0; i < 6; i++)
> -		__raw_writel(0xffffffff, APMASK(i));
> -
> -	pxa_init_gpio(IRQ_MMP2_GPIO, 0, 167, NULL);
> -}
> -
>  void __init mmp2_init_irq(void)
>  {
>  	mmp2_init_icu();
> -	mmp2_init_gpio();
>  }
>  
>  static void sdhc_clk_enable(struct clk *clk)
> diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c
> index e6f6789..630453a 100644
> --- a/arch/arm/mach-mmp/pxa168.c
> +++ b/arch/arm/mach-mmp/pxa168.c
> @@ -43,26 +43,9 @@ static struct mfp_addr_map pxa168_mfp_addr_map[] __initdata =
>  	MFP_ADDR_END,
>  };
>  
> -#define APMASK(i)	(GPIO_REGS_VIRT + BANK_OFF(i) + 0x09c)
> -
> -static void __init pxa168_init_gpio(void)
> -{
> -	int i;
> -
> -	/* enable GPIO clock */
> -	__raw_writel(APBC_APBCLK | APBC_FNCLK, APBC_PXA168_GPIO);
> -
> -	/* unmask GPIO edge detection for all 4 banks - APMASKx */
> -	for (i = 0; i < 4; i++)
> -		__raw_writel(0xffffffff, APMASK(i));
> -
> -	pxa_init_gpio(IRQ_PXA168_GPIOX, 0, 127, NULL);
> -}
> -
>  void __init pxa168_init_irq(void)
>  {
>  	icu_init_irq();
> -	pxa168_init_gpio();
>  }
>  
>  /* APB peripheral clocks */
> diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c
> index c70b4dd..19ebfe3 100644
> --- a/arch/arm/mach-mmp/pxa910.c
> +++ b/arch/arm/mach-mmp/pxa910.c
> @@ -77,26 +77,9 @@ static struct mfp_addr_map pxa910_mfp_addr_map[] __initdata =
>  	MFP_ADDR_END,
>  };
>  
> -#define APMASK(i)	(GPIO_REGS_VIRT + BANK_OFF(i) + 0x09c)
> -
> -static void __init pxa910_init_gpio(void)
> -{
> -	int i;
> -
> -	/* enable GPIO clock */
> -	__raw_writel(APBC_APBCLK | APBC_FNCLK, APBC_PXA910_GPIO);
> -
> -	/* unmask GPIO edge detection for all 4 banks - APMASKx */
> -	for (i = 0; i < 4; i++)
> -		__raw_writel(0xffffffff, APMASK(i));
> -
> -	pxa_init_gpio(IRQ_PXA910_AP_GPIO, 0, 127, NULL);
> -}
> -
>  void __init pxa910_init_irq(void)
>  {
>  	icu_init_irq();
> -	pxa910_init_gpio();
>  }
>  
>  /* APB peripheral clocks */
> diff --git a/arch/arm/mach-mmp/tavorevb.c b/arch/arm/mach-mmp/tavorevb.c
> index c5e1529..c15fa2b 100644
> --- a/arch/arm/mach-mmp/tavorevb.c
> +++ b/arch/arm/mach-mmp/tavorevb.c
> @@ -70,8 +70,8 @@ static struct resource smc91x_resources[] = {
>  		.flags	= IORESOURCE_MEM,
>  	},
>  	[1] = {
> -		.start	= pxa_gpio_to_irq(80),
> -		.end	= pxa_gpio_to_irq(80),
> +		.start	= mmp_gpio_to_irq(80),
> +		.end	= mmp_gpio_to_irq(80),
>  		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
>  	}
>  };
> diff --git a/arch/arm/mach-mmp/teton_bga.c b/arch/arm/mach-mmp/teton_bga.c
> index 79bbbc2..4539fe3 100644
> --- a/arch/arm/mach-mmp/teton_bga.c
> +++ b/arch/arm/mach-mmp/teton_bga.c
> @@ -66,7 +66,7 @@ static struct pxa27x_keypad_platform_data teton_bga_keypad_info __initdata = {
>  static struct i2c_board_info teton_bga_i2c_info[] __initdata = {
>  	{
>  		I2C_BOARD_INFO("ds1337", 0x68),
> -		.irq = pxa_gpio_to_irq(RTC_INT_GPIO)
> +		.irq = mmp_gpio_to_irq(RTC_INT_GPIO)
>  	},
>  };
>  
> diff --git a/arch/arm/mach-mmp/ttc_dkb.c b/arch/arm/mach-mmp/ttc_dkb.c
> index a420b07..b27e17e 100644
> --- a/arch/arm/mach-mmp/ttc_dkb.c
> +++ b/arch/arm/mach-mmp/ttc_dkb.c
> @@ -136,7 +136,7 @@ static struct i2c_board_info ttc_dkb_i2c_info[] = {
>  	{
>  		.type		= "max7312",
>  		.addr		= 0x23,
> -		.irq		= pxa_gpio_to_irq(80),
> +		.irq		= mmp_gpio_to_irq(80),
>  		.platform_data	= &max7312_data,
>  	},
>  };
> diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
> index cd19309..2b81f95 100644
> --- a/arch/arm/mach-pxa/Kconfig
> +++ b/arch/arm/mach-pxa/Kconfig
> @@ -604,24 +604,28 @@ endmenu
>  config PXA25x
>  	bool
>  	select CPU_XSCALE
> +	select GPIO_PXA
>  	help
>  	  Select code specific to PXA21x/25x/26x variants
>  
>  config PXA27x
>  	bool
>  	select CPU_XSCALE
> +	select GPIO_PXA
>  	help
>  	  Select code specific to PXA27x variants
>  
>  config CPU_PXA26x
>  	bool
>  	select PXA25x
> +	select GPIO_PXA
>  	help
>  	  Select code specific to PXA26x (codename Dalhart)
>  
>  config PXA3xx
>  	bool
>  	select CPU_XSC3
> +	select GPIO_PXA
>  	help
>  	  Select code specific to PXA3xx variants
>  
> @@ -647,6 +651,7 @@ config CPU_PXA320
>  config CPU_PXA930
>  	bool
>  	select PXA3xx
> +	select GPIO_PXA
>  	help
>  	  PXA930 (codename Tavor-P)
>  
> @@ -659,6 +664,7 @@ config CPU_PXA935
>  config PXA95x
>  	bool
>  	select CPU_PJ4
> +	select GPIO_PXA
>  	help
>  	  Select code specific to PXA95x variants
>  
> diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
> index cc39d17..ab34cae 100644
> --- a/arch/arm/mach-pxa/Makefile
> +++ b/arch/arm/mach-pxa/Makefile
> @@ -3,7 +3,7 @@
>  #
>  
>  # Common support (must be linked before board specific support)
> -obj-y				+= clock.o devices.o generic.o irq.o \
> +obj-y				+= clock.o devices.o generic.o irq.o gpio.o\
>  				   time.o reset.o
>  obj-$(CONFIG_PM)		+= pm.o sleep.o standby.o
>  
> diff --git a/arch/arm/mach-pxa/gpio.c b/arch/arm/mach-pxa/gpio.c
> new file mode 100644
> index 0000000..de65c59
> --- /dev/null
> +++ b/arch/arm/mach-pxa/gpio.c
> @@ -0,0 +1,92 @@
> +/*
> + *  linux/arch/arm/mach-pxa/gpio.c
> + *
> + *  PXA series specific gpio init
> + *
> + *  Copyright (C) 2011 Marvell International Ltd.
> + *
> + *  Author:
> + *  	Haojian Zhuang <haojian.zhuang at marvell.com>
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License version 2 as
> + *  published by the Free Software Foundation.
> + */
> +
> +#include <linux/gpio-pxa.h>
> +#include <linux/platform_device.h>
> +
> +#include <mach/hardware.h>
> +#include <mach/irqs.h>
> +
> +static struct __initdata pxa_gpio_platform_data pxa_gpio_config;
> +
> +static struct __initdata resource pxa_resources_gpio[] = {

static struct resource pxa_resources_gpio[] __initdata = {

> +	{
> +		.start	= 0x40e00000,
> +		.end	= 0x40e0ffff,
> +		.flags	= IORESOURCE_MEM,
> +	}, {
> +		.start	= IRQ_GPIO0,
> +		.end	= IRQ_GPIO0,
> +		.name	= "gpio0",
> +		.flags	= IORESOURCE_IRQ,
> +	}, {
> +		.start	= IRQ_GPIO1,
> +		.end	= IRQ_GPIO1,
> +		.name	= "gpio1",
> +		.flags	= IORESOURCE_IRQ,
> +	}, {
> +		.start	= IRQ_GPIO_2_x,
> +		.end	= IRQ_GPIO_2_x,
> +		.name	= "gpio_mux",
> +		.flags	= IORESOURCE_IRQ,
> +	},
> +};
> +
> +static struct platform_device pxa_gpio = {
> +	.name		= "pxa-gpio",
> +	.id		= -1,
> +	.num_resources	= ARRAY_SIZE(pxa_resources_gpio),
> +	.resource	= pxa_resources_gpio,
> +};
> +
> +static int __init pxa_gpio_init(void)
> +{
> +	int size = sizeof(struct pxa_gpio_platform_data);
> +	u32 reg_base = io_p2v(0x40E00000);
> +
> +	if (cpu_is_pxa25x()) {
> +#ifdef CONFIG_PXA26x
> +		pxa_gpio_config.gpio_type = PXA26X_GPIO;
> +		pxa_gpio_config.gpio_end = 89;
> +#else
> +		pxa_gpio_config.gpio_type = PXA25X_GPIO;
> +		pxa_gpio_config.gpio_end = 84;
> +#endif

Not multiplatform friendly.  The subarch may not support
multiplatform, but that's no excuse for adding either/or #ifdef
blocks.  I'd rather see one #ifdef for PXA26x and another for PXA25x,
and the code organizes so that they can peacefully co-exist.

> +	} else if (cpu_is_pxa27x()) {
> +		pxa_gpio_config.gpio_type = PXA27X_GPIO;
> +		pxa_gpio_config.gpio_end = 120;
> +	} else if (cpu_is_pxa93x() || cpu_is_pxa95x()) {
> +		pxa_gpio_config.gpio_type = PXA93X_GPIO;
> +		pxa_gpio_config.gpio_end = 191;
> +	} else if (cpu_is_pxa3xx()) {
> +		pxa_gpio_config.gpio_type = PXA3XX_GPIO;
> +		pxa_gpio_config.gpio_end = 127;
> +	} else
> +		return 0;
> +
> +	pxa_gpio_regs.gplr = reg_base + GPLR_OFFSET;
> +	pxa_gpio_regs.gpdr = reg_base + GPDR_OFFSET;
> +	pxa_gpio_regs.gpsr = reg_base + GPSR_OFFSET;
> +	pxa_gpio_regs.gpcr = reg_base + GPCR_OFFSET;
> +	pxa_gpio_regs.grer = reg_base + GRER_OFFSET;
> +	pxa_gpio_regs.gfer = reg_base + GFER_OFFSET;
> +	pxa_gpio_regs.gedr = reg_base + GEDR_OFFSET;
> +	pxa_gpio_regs.gafr = reg_base + GAFR_OFFSET;

I'd rather have this layout knowledge as part of the driver
rather than using platform data to pass stuff.  The driver can make
the selection either based on device name, or by testing
cpio_is_pxa*() directly.  We already have the mechanisms needed for
this.

Same goes for mmp_gpio_init().

> +
> +	platform_device_add_data(&pxa_gpio, &pxa_gpio_config, size);
> +	platform_device_register(&pxa_gpio);
> +	return 0;
> +}
> +postcore_initcall(pxa_gpio_init);

Same as mmp_gpio_init, this function needs to be skipped if a DT is
passed to the kernel.

> diff --git a/arch/arm/mach-pxa/include/mach/gpio.h b/arch/arm/mach-pxa/include/mach/gpio.h
> index d58efb5..6db7f59 100644
> --- a/arch/arm/mach-pxa/include/mach/gpio.h
> +++ b/arch/arm/mach-pxa/include/mach/gpio.h
> @@ -25,71 +25,7 @@
>  #define __ASM_ARCH_PXA_GPIO_H
>  
>  #include <mach/irqs.h>
> -#include <mach/hardware.h>
> -#include <asm-generic/gpio.h>
> -
> -#define GPIO_REGS_VIRT	io_p2v(0x40E00000)
> -
> -#define BANK_OFF(n)	(((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2))
> -#define GPIO_REG(x)	(*(volatile u32 *)(GPIO_REGS_VIRT + (x)))
> -
> -/* More handy macros.  The argument is a literal GPIO number. */
> -
> -#define GPIO_bit(x)	(1 << ((x) & 0x1f))
> -
> -/* GPIO Pin Level Registers */
> -#define GPLR(x)		GPIO_REG(BANK_OFF((x) >> 5) + 0x00)
> -/* GPIO Pin Direction Registers */
> -#define GPDR(x)		GPIO_REG(BANK_OFF((x) >> 5) + 0x0c)
> -/* GPIO Pin Output Set Registers */
> -#define GPSR(x)		GPIO_REG(BANK_OFF((x) >> 5) + 0x18)
> -/* GPIO Pin Output Clear Registers */
> -#define GPCR(x)		GPIO_REG(BANK_OFF((x) >> 5) + 0x24)
> -/* GPIO Rising Edge Detect Registers */
> -#define GRER(x)		GPIO_REG(BANK_OFF((x) >> 5) + 0x30)
> -/* GPIO Falling Edge Detect Registers */
> -#define GFER(x)		GPIO_REG(BANK_OFF((x) >> 5) + 0x3c)
> -/* GPIO Edge Detect Status Registers */
> -#define GEDR(x)		GPIO_REG(BANK_OFF((x) >> 5) + 0x48)
> -/* GPIO Alternate Function Select Registers */
> -#define GAFR(x)		GPIO_REG(0x54 + (((x) & 0x70) >> 2))
> -
>  
>  #define NR_BUILTIN_GPIO		PXA_GPIO_IRQ_NUM
>  
> -#define gpio_to_bank(gpio)	((gpio) >> 5)
> -
> -#ifdef CONFIG_CPU_PXA26x
> -/* GPIO86/87/88/89 on PXA26x have their direction bits in GPDR2 inverted,
> - * as well as their Alternate Function value being '1' for GPIO in GAFRx.
> - */
> -static inline int __gpio_is_inverted(unsigned gpio)
> -{
> -	return cpu_is_pxa25x() && gpio > 85;
> -}
> -#else
> -static inline int __gpio_is_inverted(unsigned gpio) { return 0; }
> -#endif
> -
> -/*
> - * On PXA25x and PXA27x, GAFRx and GPDRx together decide the alternate
> - * function of a GPIO, and GPDRx cannot be altered once configured. It
> - * is attributed as "occupied" here (I know this terminology isn't
> - * accurate, you are welcome to propose a better one :-)
> - */
> -static inline int __gpio_is_occupied(unsigned gpio)
> -{
> -	if (cpu_is_pxa27x() || cpu_is_pxa25x()) {
> -		int af = (GAFR(gpio) >> ((gpio & 0xf) * 2)) & 0x3;
> -		int dir = GPDR(gpio) & GPIO_bit(gpio);
> -
> -		if (__gpio_is_inverted(gpio))
> -			return af != 1 || dir == 0;
> -		else
> -			return af != 0 || dir != 0;
> -	} else
> -		return GPDR(gpio) & GPIO_bit(gpio);
> -}
> -
> -#include <plat/gpio.h>
>  #endif
> diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
> index 2ae1739..1c5070d 100644
> --- a/arch/arm/mach-pxa/pxa25x.c
> +++ b/arch/arm/mach-pxa/pxa25x.c
> @@ -311,14 +311,12 @@ set_pwer:
>  void __init pxa25x_init_irq(void)
>  {
>  	pxa_init_irq(32, pxa25x_set_wake);
> -	pxa_init_gpio(IRQ_GPIO_2_x, 2, 84, pxa25x_set_wake);
>  }
>  
>  #ifdef CONFIG_CPU_PXA26x
>  void __init pxa26x_init_irq(void)
>  {
>  	pxa_init_irq(32, pxa25x_set_wake);
> -	pxa_init_gpio(IRQ_GPIO_2_x, 2, 89, pxa25x_set_wake);
>  }
>  #endif
>  
> @@ -368,7 +366,6 @@ static int __init pxa25x_init(void)
>  
>  		register_syscore_ops(&pxa_irq_syscore_ops);
>  		register_syscore_ops(&pxa2xx_mfp_syscore_ops);
> -		register_syscore_ops(&pxa_gpio_syscore_ops);
>  		register_syscore_ops(&pxa2xx_clock_syscore_ops);
>  
>  		ret = platform_add_devices(pxa25x_devices,
> diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
> index 03d0728..638edf4 100644
> --- a/arch/arm/mach-pxa/pxa27x.c
> +++ b/arch/arm/mach-pxa/pxa27x.c
> @@ -385,7 +385,6 @@ static int pxa27x_set_wake(struct irq_data *d, unsigned int on)
>  void __init pxa27x_init_irq(void)
>  {
>  	pxa_init_irq(34, pxa27x_set_wake);
> -	pxa_init_gpio(IRQ_GPIO_2_x, 2, 120, pxa27x_set_wake);
>  }
>  
>  static struct map_desc pxa27x_io_desc[] __initdata = {
> @@ -454,7 +453,6 @@ static int __init pxa27x_init(void)
>  
>  		register_syscore_ops(&pxa_irq_syscore_ops);
>  		register_syscore_ops(&pxa2xx_mfp_syscore_ops);
> -		register_syscore_ops(&pxa_gpio_syscore_ops);
>  		register_syscore_ops(&pxa2xx_clock_syscore_ops);
>  
>  		ret = platform_add_devices(devices, ARRAY_SIZE(devices));
> diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
> index f18a6eb..fe4db28 100644
> --- a/arch/arm/mach-pxa/pxa3xx.c
> +++ b/arch/arm/mach-pxa/pxa3xx.c
> @@ -389,7 +389,6 @@ void __init pxa3xx_init_irq(void)
>  
>  	pxa_init_irq(56, pxa3xx_set_wake);
>  	pxa_init_ext_wakeup_irq(pxa3xx_set_wake);
> -	pxa_init_gpio(IRQ_GPIO_2_x, 2, 127, NULL);
>  }
>  
>  static struct map_desc pxa3xx_io_desc[] __initdata = {
> @@ -461,7 +460,6 @@ static int __init pxa3xx_init(void)
>  
>  		register_syscore_ops(&pxa_irq_syscore_ops);
>  		register_syscore_ops(&pxa3xx_mfp_syscore_ops);
> -		register_syscore_ops(&pxa_gpio_syscore_ops);
>  		register_syscore_ops(&pxa3xx_clock_syscore_ops);
>  
>  		ret = platform_add_devices(devices, ARRAY_SIZE(devices));
> diff --git a/arch/arm/mach-pxa/pxa95x.c b/arch/arm/mach-pxa/pxa95x.c
> index de25ceb..b115829 100644
> --- a/arch/arm/mach-pxa/pxa95x.c
> +++ b/arch/arm/mach-pxa/pxa95x.c
> @@ -235,7 +235,6 @@ static struct clk_lookup pxa95x_clkregs[] = {
>  void __init pxa95x_init_irq(void)
>  {
>  	pxa_init_irq(96, NULL);
> -	pxa_init_gpio(IRQ_GPIO_2_x, 2, 127, NULL);
>  }
>  
>  /*
> @@ -282,7 +281,6 @@ static int __init pxa95x_init(void)
>  			return ret;
>  
>  		register_syscore_ops(&pxa_irq_syscore_ops);
> -		register_syscore_ops(&pxa_gpio_syscore_ops);
>  		register_syscore_ops(&pxa3xx_clock_syscore_ops);
>  
>  		ret = platform_add_devices(devices, ARRAY_SIZE(devices));
> diff --git a/arch/arm/plat-pxa/Makefile b/arch/arm/plat-pxa/Makefile
> index 3aca5ba..f302d04 100644
> --- a/arch/arm/plat-pxa/Makefile
> +++ b/arch/arm/plat-pxa/Makefile
> @@ -4,7 +4,6 @@
>  
>  obj-y	:= dma.o
>  
> -obj-$(CONFIG_GENERIC_GPIO)	+= gpio.o
>  obj-$(CONFIG_PXA3xx)		+= mfp.o
>  obj-$(CONFIG_PXA95x)		+= mfp.o
>  obj-$(CONFIG_ARCH_MMP)		+= mfp.o
> diff --git a/arch/arm/plat-pxa/gpio.c b/arch/arm/plat-pxa/gpio.c
> deleted file mode 100644
> index d667d8d..0000000
> --- a/arch/arm/plat-pxa/gpio.c
> +++ /dev/null
> @@ -1,352 +0,0 @@
> -/*
> - *  linux/arch/arm/plat-pxa/gpio.c
> - *
> - *  Generic PXA GPIO handling
> - *
> - *  Author:	Nicolas Pitre
> - *  Created:	Jun 15, 2001
> - *  Copyright:	MontaVista Software Inc.
> - *
> - *  This program is free software; you can redistribute it and/or modify
> - *  it under the terms of the GNU General Public License version 2 as
> - *  published by the Free Software Foundation.
> - */
> -#include <linux/gpio.h>
> -#include <linux/init.h>
> -#include <linux/irq.h>
> -#include <linux/io.h>
> -#include <linux/syscore_ops.h>
> -#include <linux/slab.h>
> -
> -int pxa_last_gpio;
> -
> -struct pxa_gpio_chip {
> -	struct gpio_chip chip;
> -	void __iomem	*regbase;
> -	char label[10];
> -
> -	unsigned long	irq_mask;
> -	unsigned long	irq_edge_rise;
> -	unsigned long	irq_edge_fall;
> -
> -#ifdef CONFIG_PM
> -	unsigned long	saved_gplr;
> -	unsigned long	saved_gpdr;
> -	unsigned long	saved_grer;
> -	unsigned long	saved_gfer;
> -#endif
> -};
> -
> -static DEFINE_SPINLOCK(gpio_lock);
> -static struct pxa_gpio_chip *pxa_gpio_chips;
> -
> -#define for_each_gpio_chip(i, c)			\
> -	for (i = 0, c = &pxa_gpio_chips[0]; i <= pxa_last_gpio; i += 32, c++)
> -
> -static inline void __iomem *gpio_chip_base(struct gpio_chip *c)
> -{
> -	return container_of(c, struct pxa_gpio_chip, chip)->regbase;
> -}
> -
> -static inline struct pxa_gpio_chip *gpio_to_pxachip(unsigned gpio)
> -{
> -	return &pxa_gpio_chips[gpio_to_bank(gpio)];
> -}
> -
> -static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
> -{
> -	void __iomem *base = gpio_chip_base(chip);
> -	uint32_t value, mask = 1 << offset;
> -	unsigned long flags;
> -
> -	spin_lock_irqsave(&gpio_lock, flags);
> -
> -	value = __raw_readl(base + GPDR_OFFSET);
> -	if (__gpio_is_inverted(chip->base + offset))
> -		value |= mask;
> -	else
> -		value &= ~mask;
> -	__raw_writel(value, base + GPDR_OFFSET);
> -
> -	spin_unlock_irqrestore(&gpio_lock, flags);
> -	return 0;
> -}
> -
> -static int pxa_gpio_direction_output(struct gpio_chip *chip,
> -				     unsigned offset, int value)
> -{
> -	void __iomem *base = gpio_chip_base(chip);
> -	uint32_t tmp, mask = 1 << offset;
> -	unsigned long flags;
> -
> -	__raw_writel(mask, base + (value ? GPSR_OFFSET : GPCR_OFFSET));
> -
> -	spin_lock_irqsave(&gpio_lock, flags);
> -
> -	tmp = __raw_readl(base + GPDR_OFFSET);
> -	if (__gpio_is_inverted(chip->base + offset))
> -		tmp &= ~mask;
> -	else
> -		tmp |= mask;
> -	__raw_writel(tmp, base + GPDR_OFFSET);
> -
> -	spin_unlock_irqrestore(&gpio_lock, flags);
> -	return 0;
> -}
> -
> -static int pxa_gpio_get(struct gpio_chip *chip, unsigned offset)
> -{
> -	return __raw_readl(gpio_chip_base(chip) + GPLR_OFFSET) & (1 << offset);
> -}
> -
> -static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
> -{
> -	__raw_writel(1 << offset, gpio_chip_base(chip) +
> -				(value ? GPSR_OFFSET : GPCR_OFFSET));
> -}
> -
> -static int __init pxa_init_gpio_chip(int gpio_end)
> -{
> -	int i, gpio, nbanks = gpio_to_bank(gpio_end) + 1;
> -	struct pxa_gpio_chip *chips;
> -
> -	chips = kzalloc(nbanks * sizeof(struct pxa_gpio_chip), GFP_KERNEL);
> -	if (chips == NULL) {
> -		pr_err("%s: failed to allocate GPIO chips\n", __func__);
> -		return -ENOMEM;
> -	}
> -
> -	for (i = 0, gpio = 0; i < nbanks; i++, gpio += 32) {
> -		struct gpio_chip *c = &chips[i].chip;
> -
> -		sprintf(chips[i].label, "gpio-%d", i);
> -		chips[i].regbase = (void __iomem *)GPIO_BANK(i);
> -
> -		c->base  = gpio;
> -		c->label = chips[i].label;
> -
> -		c->direction_input  = pxa_gpio_direction_input;
> -		c->direction_output = pxa_gpio_direction_output;
> -		c->get = pxa_gpio_get;
> -		c->set = pxa_gpio_set;
> -
> -		/* number of GPIOs on last bank may be less than 32 */
> -		c->ngpio = (gpio + 31 > gpio_end) ? (gpio_end - gpio + 1) : 32;
> -		gpiochip_add(c);
> -	}
> -	pxa_gpio_chips = chips;
> -	return 0;
> -}
> -
> -/* Update only those GRERx and GFERx edge detection register bits if those
> - * bits are set in c->irq_mask
> - */
> -static inline void update_edge_detect(struct pxa_gpio_chip *c)
> -{
> -	uint32_t grer, gfer;
> -
> -	grer = __raw_readl(c->regbase + GRER_OFFSET) & ~c->irq_mask;
> -	gfer = __raw_readl(c->regbase + GFER_OFFSET) & ~c->irq_mask;
> -	grer |= c->irq_edge_rise & c->irq_mask;
> -	gfer |= c->irq_edge_fall & c->irq_mask;
> -	__raw_writel(grer, c->regbase + GRER_OFFSET);
> -	__raw_writel(gfer, c->regbase + GFER_OFFSET);
> -}
> -
> -static int pxa_gpio_irq_type(struct irq_data *d, unsigned int type)
> -{
> -	struct pxa_gpio_chip *c;
> -	int gpio = pxa_irq_to_gpio(d->irq);
> -	unsigned long gpdr, mask = GPIO_bit(gpio);
> -
> -	c = gpio_to_pxachip(gpio);
> -
> -	if (type == IRQ_TYPE_PROBE) {
> -		/* Don't mess with enabled GPIOs using preconfigured edges or
> -		 * GPIOs set to alternate function or to output during probe
> -		 */
> -		if ((c->irq_edge_rise | c->irq_edge_fall) & GPIO_bit(gpio))
> -			return 0;
> -
> -		if (__gpio_is_occupied(gpio))
> -			return 0;
> -
> -		type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
> -	}
> -
> -	gpdr = __raw_readl(c->regbase + GPDR_OFFSET);
> -
> -	if (__gpio_is_inverted(gpio))
> -		__raw_writel(gpdr | mask,  c->regbase + GPDR_OFFSET);
> -	else
> -		__raw_writel(gpdr & ~mask, c->regbase + GPDR_OFFSET);
> -
> -	if (type & IRQ_TYPE_EDGE_RISING)
> -		c->irq_edge_rise |= mask;
> -	else
> -		c->irq_edge_rise &= ~mask;
> -
> -	if (type & IRQ_TYPE_EDGE_FALLING)
> -		c->irq_edge_fall |= mask;
> -	else
> -		c->irq_edge_fall &= ~mask;
> -
> -	update_edge_detect(c);
> -
> -	pr_debug("%s: IRQ%d (GPIO%d) - edge%s%s\n", __func__, d->irq, gpio,
> -		((type & IRQ_TYPE_EDGE_RISING)  ? " rising"  : ""),
> -		((type & IRQ_TYPE_EDGE_FALLING) ? " falling" : ""));
> -	return 0;
> -}
> -
> -static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc)
> -{
> -	struct pxa_gpio_chip *c;
> -	int loop, gpio, gpio_base, n;
> -	unsigned long gedr;
> -
> -	do {
> -		loop = 0;
> -		for_each_gpio_chip(gpio, c) {
> -			gpio_base = c->chip.base;
> -
> -			gedr = __raw_readl(c->regbase + GEDR_OFFSET);
> -			gedr = gedr & c->irq_mask;
> -			__raw_writel(gedr, c->regbase + GEDR_OFFSET);
> -
> -			n = find_first_bit(&gedr, BITS_PER_LONG);
> -			while (n < BITS_PER_LONG) {
> -				loop = 1;
> -
> -				generic_handle_irq(pxa_gpio_to_irq(gpio_base + n));
> -				n = find_next_bit(&gedr, BITS_PER_LONG, n + 1);
> -			}
> -		}
> -	} while (loop);
> -}
> -
> -static void pxa_ack_muxed_gpio(struct irq_data *d)
> -{
> -	int gpio = pxa_irq_to_gpio(d->irq);
> -	struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
> -
> -	__raw_writel(GPIO_bit(gpio), c->regbase + GEDR_OFFSET);
> -}
> -
> -static void pxa_mask_muxed_gpio(struct irq_data *d)
> -{
> -	int gpio = pxa_irq_to_gpio(d->irq);
> -	struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
> -	uint32_t grer, gfer;
> -
> -	c->irq_mask &= ~GPIO_bit(gpio);
> -
> -	grer = __raw_readl(c->regbase + GRER_OFFSET) & ~GPIO_bit(gpio);
> -	gfer = __raw_readl(c->regbase + GFER_OFFSET) & ~GPIO_bit(gpio);
> -	__raw_writel(grer, c->regbase + GRER_OFFSET);
> -	__raw_writel(gfer, c->regbase + GFER_OFFSET);
> -}
> -
> -static void pxa_unmask_muxed_gpio(struct irq_data *d)
> -{
> -	int gpio = pxa_irq_to_gpio(d->irq);
> -	struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
> -
> -	c->irq_mask |= GPIO_bit(gpio);
> -	update_edge_detect(c);
> -}
> -
> -static struct irq_chip pxa_muxed_gpio_chip = {
> -	.name		= "GPIO",
> -	.irq_ack	= pxa_ack_muxed_gpio,
> -	.irq_mask	= pxa_mask_muxed_gpio,
> -	.irq_unmask	= pxa_unmask_muxed_gpio,
> -	.irq_set_type	= pxa_gpio_irq_type,
> -};
> -
> -void __init pxa_init_gpio(int mux_irq, int start, int end,
> -			  int (*fn)(struct irq_data *, unsigned int))
> -{
> -	struct pxa_gpio_chip *c;
> -	int gpio, irq;
> -
> -	pxa_last_gpio = end;
> -
> -	/* Initialize GPIO chips */
> -	pxa_init_gpio_chip(end);
> -
> -	/* clear all GPIO edge detects */
> -	for_each_gpio_chip(gpio, c) {
> -		__raw_writel(0, c->regbase + GFER_OFFSET);
> -		__raw_writel(0, c->regbase + GRER_OFFSET);
> -		__raw_writel(~0,c->regbase + GEDR_OFFSET);
> -	}
> -
> -#ifdef CONFIG_ARCH_PXA
> -	irq = gpio_to_irq(0);
> -	irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
> -				 handle_edge_irq);
> -	set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
> -	irq_set_chained_handler(IRQ_GPIO0, pxa_gpio_demux_handler);
> -
> -	irq = gpio_to_irq(1);
> -	irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
> -				 handle_edge_irq);
> -	set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
> -	irq_set_chained_handler(IRQ_GPIO1, pxa_gpio_demux_handler);
> -#endif
> -
> -	for (irq  = pxa_gpio_to_irq(start); irq <= pxa_gpio_to_irq(end);
> -		irq++) {
> -		irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
> -					 handle_edge_irq);
> -		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
> -	}
> -
> -	/* Install handler for GPIO>=2 edge detect interrupts */
> -	irq_set_chained_handler(mux_irq, pxa_gpio_demux_handler);
> -	pxa_muxed_gpio_chip.irq_set_wake = fn;
> -}
> -
> -#ifdef CONFIG_PM
> -static int pxa_gpio_suspend(void)
> -{
> -	struct pxa_gpio_chip *c;
> -	int gpio;
> -
> -	for_each_gpio_chip(gpio, c) {
> -		c->saved_gplr = __raw_readl(c->regbase + GPLR_OFFSET);
> -		c->saved_gpdr = __raw_readl(c->regbase + GPDR_OFFSET);
> -		c->saved_grer = __raw_readl(c->regbase + GRER_OFFSET);
> -		c->saved_gfer = __raw_readl(c->regbase + GFER_OFFSET);
> -
> -		/* Clear GPIO transition detect bits */
> -		__raw_writel(0xffffffff, c->regbase + GEDR_OFFSET);
> -	}
> -	return 0;
> -}
> -
> -static void pxa_gpio_resume(void)
> -{
> -	struct pxa_gpio_chip *c;
> -	int gpio;
> -
> -	for_each_gpio_chip(gpio, c) {
> -		/* restore level with set/clear */
> -		__raw_writel( c->saved_gplr, c->regbase + GPSR_OFFSET);
> -		__raw_writel(~c->saved_gplr, c->regbase + GPCR_OFFSET);
> -
> -		__raw_writel(c->saved_grer, c->regbase + GRER_OFFSET);
> -		__raw_writel(c->saved_gfer, c->regbase + GFER_OFFSET);
> -		__raw_writel(c->saved_gpdr, c->regbase + GPDR_OFFSET);
> -	}
> -}
> -#else
> -#define pxa_gpio_suspend	NULL
> -#define pxa_gpio_resume		NULL
> -#endif
> -
> -struct syscore_ops pxa_gpio_syscore_ops = {
> -	.suspend	= pxa_gpio_suspend,
> -	.resume		= pxa_gpio_resume,
> -};
> diff --git a/arch/arm/plat-pxa/include/plat/gpio.h b/arch/arm/plat-pxa/include/plat/gpio.h
> deleted file mode 100644
> index d31c2a5..0000000
> --- a/arch/arm/plat-pxa/include/plat/gpio.h
> +++ /dev/null
> @@ -1,65 +0,0 @@
> -#ifndef __PLAT_GPIO_H
> -#define __PLAT_GPIO_H
> -
> -#define __ARM_GPIOLIB_COMPLEX
> -
> -struct irq_data;
> -
> -/*
> - * We handle the GPIOs by banks, each bank covers up to 32 GPIOs with
> - * one set of registers. The register offsets are organized below:
> - *
> - *           GPLR    GPDR    GPSR    GPCR    GRER    GFER    GEDR
> - * BANK 0 - 0x0000  0x000C  0x0018  0x0024  0x0030  0x003C  0x0048
> - * BANK 1 - 0x0004  0x0010  0x001C  0x0028  0x0034  0x0040  0x004C
> - * BANK 2 - 0x0008  0x0014  0x0020  0x002C  0x0038  0x0044  0x0050
> - *
> - * BANK 3 - 0x0100  0x010C  0x0118  0x0124  0x0130  0x013C  0x0148
> - * BANK 4 - 0x0104  0x0110  0x011C  0x0128  0x0134  0x0140  0x014C
> - * BANK 5 - 0x0108  0x0114  0x0120  0x012C  0x0138  0x0144  0x0150
> - *
> - * NOTE:
> - *   BANK 3 is only available on PXA27x and later processors.
> - *   BANK 4 and 5 are only available on PXA935
> - */
> -
> -#define GPIO_BANK(n)	(GPIO_REGS_VIRT + BANK_OFF(n))
> -
> -#define GPLR_OFFSET	0x00
> -#define GPDR_OFFSET	0x0C
> -#define GPSR_OFFSET	0x18
> -#define GPCR_OFFSET	0x24
> -#define GRER_OFFSET	0x30
> -#define GFER_OFFSET	0x3C
> -#define GEDR_OFFSET	0x48
> -
> -static inline int gpio_get_value(unsigned gpio)
> -{
> -	if (__builtin_constant_p(gpio) && (gpio < NR_BUILTIN_GPIO))
> -		return GPLR(gpio) & GPIO_bit(gpio);
> -	else
> -		return __gpio_get_value(gpio);
> -}
> -
> -static inline void gpio_set_value(unsigned gpio, int value)
> -{
> -	if (__builtin_constant_p(gpio) && (gpio < NR_BUILTIN_GPIO)) {
> -		if (value)
> -			GPSR(gpio) = GPIO_bit(gpio);
> -		else
> -			GPCR(gpio) = GPIO_bit(gpio);
> -	} else
> -		__gpio_set_value(gpio, value);
> -}
> -
> -#define gpio_cansleep		__gpio_cansleep
> -
> -/* NOTE: some PXAs have fewer on-chip GPIOs (like PXA255, with 85).
> - * Those cases currently cause holes in the GPIO number space, the
> - * actual number of the last GPIO is recorded by 'pxa_last_gpio'.
> - */
> -extern int pxa_last_gpio;
> -
> -extern void pxa_init_gpio(int mux_irq, int start, int end,
> -			  int (*fn)(struct irq_data *, unsigned int));
> -#endif /* __PLAT_GPIO_H */
> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> index 6465030..08fe9f6 100644
> --- a/drivers/gpio/Kconfig
> +++ b/drivers/gpio/Kconfig
> @@ -141,6 +141,12 @@ config GPIO_PL061
>  	help
>  	  Say yes here to support the PrimeCell PL061 GPIO device
>  
> +config GPIO_PXA
> +	def_bool y
> +	depends on ARCH_PXA || ARCH_MMP
> +	help
> +	  Say yes here to support the PXA GPIO device
> +
>  config GPIO_XILINX
>  	bool "Xilinx GPIO support"
>  	depends on PPC_OF || MICROBLAZE
> diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
> index a4c8ac9..194899f 100644
> --- a/drivers/gpio/Makefile
> +++ b/drivers/gpio/Makefile
> @@ -40,6 +40,7 @@ obj-$(CONFIG_GPIO_PCA953X)	+= gpio-pca953x.o
>  obj-$(CONFIG_GPIO_PCF857X)	+= gpio-pcf857x.o
>  obj-$(CONFIG_GPIO_PCH)		+= gpio-pch.o
>  obj-$(CONFIG_GPIO_PL061)	+= gpio-pl061.o
> +obj-$(CONFIG_GPIO_PXA)		+= gpio-pxa.o
>  obj-$(CONFIG_GPIO_RDC321X)	+= gpio-rdc321x.o
>  obj-$(CONFIG_ARCH_SA1100)	+= gpio-sa1100.o
>  obj-$(CONFIG_PLAT_SAMSUNG)	+= gpio-samsung.o
> diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
> new file mode 100644
> index 0000000..21d1394
> --- /dev/null
> +++ b/drivers/gpio/gpio-pxa.c
> @@ -0,0 +1,500 @@
> +/*
> + *  linux/arch/arm/plat-pxa/gpio.c
> + *
> + *  Generic PXA GPIO handling
> + *
> + *  Author:	Nicolas Pitre
> + *  Created:	Jun 15, 2001
> + *  Copyright:	MontaVista Software Inc.
> + *
> + *  Copyright (C) 2011 Marvell Technology
> + *  Moved to drivers/gpio - Haojian Zhuang <haojian.zhuang at marvell.com>
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License version 2 as
> + *  published by the Free Software Foundation.
> + */
> +
> +#include <linux/gpio.h>
> +#include <linux/gpio-pxa.h>
> +#include <linux/irq.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/syscore_ops.h>
> +
> +static int pxa_last_gpio;
> +
> +struct pxa_gpio_irq_data {
> +	int	gpio_type;
> +	int	irq_gpio0;
> +	int	irq_gpio1;
> +	int	irq_mux;
> +};
> +
> +struct pxa_gpio_chip {
> +	struct gpio_chip		chip;
> +	void __iomem			*regbase;
> +	char				label[10];
> +
> +	unsigned long			irq_mask;
> +	unsigned long			irq_edge_rise;
> +	unsigned long			irq_edge_fall;
> +	struct pxa_gpio_irq_data	*data;
> +
> +#ifdef CONFIG_PM
> +	unsigned long			saved_gplr;
> +	unsigned long			saved_gpdr;
> +	unsigned long			saved_grer;
> +	unsigned long			saved_gfer;
> +#endif
> +};
> +
> +struct pxa_gpio_regs pxa_gpio_regs;
> +
> +static DEFINE_SPINLOCK(gpio_lock);
> +static struct pxa_gpio_chip *pxa_gpio_chips;
> +
> +#define for_each_gpio_chip(i, c)			\
> +	for (i = 0, c = &pxa_gpio_chips[0]; i <= pxa_last_gpio; i += 32, c++)
> +
> +static inline void __iomem *gpio_chip_base(struct gpio_chip *c)
> +{
> +	return container_of(c, struct pxa_gpio_chip, chip)->regbase;
> +}
> +
> +static inline struct pxa_gpio_chip *gpio_to_pxachip(unsigned gpio)
> +{
> +	return &pxa_gpio_chips[gpio_to_bank(gpio)];
> +}
> +
> +static int __gpio_is_inverted(int gpio)
> +{
> +	struct pxa_gpio_chip *c;
> +	struct pxa_gpio_irq_data *data;
> +
> +	c = gpio_to_pxachip(gpio);
> +	data = c->data;
> +#ifdef CONFIG_ARCH_PXA
> +	if (gpio_is_pxa_type(data->gpio_type)) {
> +		if (data->gpio_type == PXA26X_GPIO && gpio > 84)
> +			return 1;
> +		else
> +			return 0;
> +	}
> +#endif
> +#ifdef CONFIG_ARCH_MMP
> +	if (gpio_is_mmp_type(data->gpio_type))
> +		return 0;
> +#endif

Instead of encoding it into pdata, it would be simpler to select the
type by assiging an (platform_driver*)->id_table and using the .data
member in the table to select the correct initialization data.  That
means using the name of the device to select the correct
initialization.

> +	return 0;
> +}
> +
> +static int __gpio_is_irq(int gpio)
> +{
> +	struct pxa_gpio_chip *c;
> +	struct pxa_gpio_irq_data *data;
> +	int af = 0, dir = 0;
> +	int ret;
> +
> +	c = gpio_to_pxachip(gpio);
> +	data = c->data;
> +	switch (data->gpio_type) {
> +	case PXA25X_GPIO:
> +	case PXA26X_GPIO:
> +	case PXA27X_GPIO:
> +		af = (GAFR(gpio) >> ((gpio & 0xf) * 2)) & 0x3;
> +		dir = GPDR(gpio) & GPIO_bit(gpio);
> +		if ((data->gpio_type == PXA26X_GPIO) && (gpio > 84))
> +			ret = (af != 1) || (dir == 0);
> +		else
> +			ret = (af != 0) || (dir != 0);
> +		break;
> +	default:
> +		ret = GPDR(gpio) & GPIO_bit(gpio);
> +		break;
> +	}
> +	return ret;
> +}
> +
> +static inline int mgpio_to_irq(int gpio)
> +{
> +	struct pxa_gpio_chip *c;
> +	struct pxa_gpio_irq_data *data;
> +
> +	c = gpio_to_pxachip(gpio);
> +	data = c->data;
> +#ifdef CONFIG_ARCH_PXA
> +	if (gpio_is_pxa_type(data->gpio_type))
> +		return pxa_gpio_to_irq(gpio);
> +#endif
> +#ifdef CONFIG_ARCH_MMP
> +	if (gpio_is_mmp_type(data->gpio_type))
> +		return mmp_gpio_to_irq(gpio);
> +#endif
> +	return 0;
> +}
> +
> +static inline int mirq_to_gpio(struct irq_data *d)
> +{
> +	struct pxa_gpio_irq_data *data = irq_data_get_irq_chip_data(d);
> +
> +#ifdef CONFIG_ARCH_PXA
> +	if (gpio_is_pxa_type(data->gpio_type))
> +		return pxa_irq_to_gpio(d->irq);
> +#endif
> +#ifdef CONFIG_ARCH_MMP
> +	if (gpio_is_mmp_type(data->gpio_type))
> +		return mmp_irq_to_gpio(d->irq);
> +#endif
> +	return 0;
> +}
> +
> +static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
> +{
> +	void __iomem *base = gpio_chip_base(chip);
> +	uint32_t value, mask = 1 << offset;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&gpio_lock, flags);
> +
> +	value = __raw_readl(base + GPDR_OFFSET);
> +	if (__gpio_is_inverted(chip->base + offset))
> +		value |= mask;
> +	else
> +		value &= ~mask;
> +	__raw_writel(value, base + GPDR_OFFSET);
> +
> +	spin_unlock_irqrestore(&gpio_lock, flags);
> +	return 0;
> +}
> +
> +static int pxa_gpio_direction_output(struct gpio_chip *chip,
> +				     unsigned offset, int value)
> +{
> +	void __iomem *base = gpio_chip_base(chip);
> +	uint32_t tmp, mask = 1 << offset;
> +	unsigned long flags;
> +
> +	__raw_writel(mask, base + (value ? GPSR_OFFSET : GPCR_OFFSET));
> +
> +	spin_lock_irqsave(&gpio_lock, flags);
> +
> +	tmp = __raw_readl(base + GPDR_OFFSET);
> +	if (__gpio_is_inverted(chip->base + offset))
> +		tmp &= ~mask;
> +	else
> +		tmp |= mask;
> +	__raw_writel(tmp, base + GPDR_OFFSET);
> +
> +	spin_unlock_irqrestore(&gpio_lock, flags);
> +	return 0;
> +}
> +
> +static int pxa_gpio_get(struct gpio_chip *chip, unsigned offset)
> +{
> +	return __raw_readl(gpio_chip_base(chip) + GPLR_OFFSET) & (1 << offset);
> +}
> +
> +static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
> +{
> +	__raw_writel(1 << offset, gpio_chip_base(chip) +
> +				(value ? GPSR_OFFSET : GPCR_OFFSET));
> +}
> +
> +static int __init pxa_init_gpio_chip(int gpio_end,
> +				     struct pxa_gpio_irq_data *data)
> +{
> +	int i, gpio, nbanks = gpio_to_bank(gpio_end) + 1;
> +	struct pxa_gpio_chip *chips;
> +
> +	chips = kzalloc(nbanks * sizeof(struct pxa_gpio_chip), GFP_KERNEL);
> +	if (chips == NULL) {
> +		pr_err("%s: failed to allocate GPIO chips\n", __func__);
> +		return -ENOMEM;
> +	}
> +
> +	for (i = 0, gpio = 0; i < nbanks; i++, gpio += 32) {
> +		struct gpio_chip *c = &chips[i].chip;
> +
> +		sprintf(chips[i].label, "gpio-%d", i);
> +		chips[i].regbase = (void __iomem *)GPIO_BANK(i);
> +		chips[i].data = data;
> +
> +		c->base  = gpio;
> +		c->label = chips[i].label;
> +
> +		c->direction_input  = pxa_gpio_direction_input;
> +		c->direction_output = pxa_gpio_direction_output;
> +		c->get = pxa_gpio_get;
> +		c->set = pxa_gpio_set;
> +
> +		/* number of GPIOs on last bank may be less than 32 */
> +		c->ngpio = (gpio + 31 > gpio_end) ? (gpio_end - gpio + 1) : 32;
> +		gpiochip_add(c);
> +	}
> +	pxa_gpio_chips = chips;
> +	return 0;
> +}
> +
> +/* Update only those GRERx and GFERx edge detection register bits if those
> + * bits are set in c->irq_mask
> + */
> +static inline void update_edge_detect(struct pxa_gpio_chip *c)
> +{
> +	uint32_t grer, gfer;
> +
> +	grer = __raw_readl(c->regbase + GRER_OFFSET) & ~c->irq_mask;
> +	gfer = __raw_readl(c->regbase + GFER_OFFSET) & ~c->irq_mask;
> +	grer |= c->irq_edge_rise & c->irq_mask;
> +	gfer |= c->irq_edge_fall & c->irq_mask;
> +	__raw_writel(grer, c->regbase + GRER_OFFSET);
> +	__raw_writel(gfer, c->regbase + GFER_OFFSET);
> +}
> +
> +static int pxa_gpio_irq_type(struct irq_data *d, unsigned int type)
> +{
> +	struct pxa_gpio_chip *c;
> +	int gpio = mirq_to_gpio(d);
> +	unsigned long gpdr, mask = GPIO_bit(gpio);
> +
> +	c = gpio_to_pxachip(gpio);
> +
> +	if (type == IRQ_TYPE_PROBE) {
> +		/* Don't mess with enabled GPIOs using preconfigured edges or
> +		 * GPIOs set to alternate function or to output during probe
> +		 */
> +		if ((c->irq_edge_rise | c->irq_edge_fall) & GPIO_bit(gpio))
> +			return 0;
> +
> +		if (!__gpio_is_irq(gpio))
> +			return 0;
> +
> +		type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
> +	}
> +
> +	gpdr = __raw_readl(c->regbase + GPDR_OFFSET);
> +
> +	if (__gpio_is_inverted(gpio))
> +		__raw_writel(gpdr | mask,  c->regbase + GPDR_OFFSET);
> +	else
> +		__raw_writel(gpdr & ~mask, c->regbase + GPDR_OFFSET);
> +
> +	if (type & IRQ_TYPE_EDGE_RISING)
> +		c->irq_edge_rise |= mask;
> +	else
> +		c->irq_edge_rise &= ~mask;
> +
> +	if (type & IRQ_TYPE_EDGE_FALLING)
> +		c->irq_edge_fall |= mask;
> +	else
> +		c->irq_edge_fall &= ~mask;
> +
> +	update_edge_detect(c);
> +
> +	pr_debug("%s: IRQ%d (GPIO%d) - edge%s%s\n", __func__, d->irq, gpio,
> +		((type & IRQ_TYPE_EDGE_RISING)  ? " rising"  : ""),
> +		((type & IRQ_TYPE_EDGE_FALLING) ? " falling" : ""));
> +	return 0;
> +}
> +
> +static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc)
> +{
> +	struct pxa_gpio_chip *c;
> +	int loop, gpio, gpio_base, n;
> +	unsigned long gedr;
> +
> +	do {
> +		loop = 0;
> +		for_each_gpio_chip(gpio, c) {
> +			gpio_base = c->chip.base;
> +
> +			gedr = __raw_readl(c->regbase + GEDR_OFFSET);
> +			gedr = gedr & c->irq_mask;
> +			__raw_writel(gedr, c->regbase + GEDR_OFFSET);
> +
> +			n = find_first_bit(&gedr, BITS_PER_LONG);
> +			while (n < BITS_PER_LONG) {
> +				loop = 1;
> +
> +				irq = mgpio_to_irq(gpio_base + n);
> +				generic_handle_irq(irq);
> +				n = find_next_bit(&gedr, BITS_PER_LONG, n + 1);
> +			}
> +		}
> +	} while (loop);
> +}
> +
> +static void pxa_ack_muxed_gpio(struct irq_data *d)
> +{
> +	int gpio = mirq_to_gpio(d);
> +	struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
> +
> +	__raw_writel(GPIO_bit(gpio), c->regbase + GEDR_OFFSET);
> +}
> +
> +static void pxa_mask_muxed_gpio(struct irq_data *d)
> +{
> +	int gpio = mirq_to_gpio(d);
> +	struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
> +	uint32_t grer, gfer;
> +
> +	c->irq_mask &= ~GPIO_bit(gpio);
> +
> +	grer = __raw_readl(c->regbase + GRER_OFFSET) & ~GPIO_bit(gpio);
> +	gfer = __raw_readl(c->regbase + GFER_OFFSET) & ~GPIO_bit(gpio);
> +	__raw_writel(grer, c->regbase + GRER_OFFSET);
> +	__raw_writel(gfer, c->regbase + GFER_OFFSET);
> +}
> +
> +static void pxa_unmask_muxed_gpio(struct irq_data *d)
> +{
> +	int gpio = mirq_to_gpio(d);
> +	struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
> +
> +	c->irq_mask |= GPIO_bit(gpio);
> +	update_edge_detect(c);
> +}
> +
> +static struct irq_chip pxa_muxed_gpio_chip = {
> +	.name		= "GPIO",
> +	.irq_ack	= pxa_ack_muxed_gpio,
> +	.irq_mask	= pxa_mask_muxed_gpio,
> +	.irq_unmask	= pxa_unmask_muxed_gpio,
> +	.irq_set_type	= pxa_gpio_irq_type,
> +};
> +
> +
> +static int __init pxa_gpio_probe(struct platform_device *pdev)

This needs to be __devinit for correctness.

> +{
> +	struct pxa_gpio_platform_data *pdata;
> +	struct pxa_gpio_chip *c;
> +	struct pxa_gpio_irq_data *mux_data;
> +	int gpio, irq;
> +	int irq0 = 0, irq1 = 0, irq_mux, gpio_offset = 0;
> +
> +	if (!pdev->dev.platform_data)
> +		return -EINVAL;
> +	pdata = pdev->dev.platform_data;
> +	pxa_last_gpio = pdata->gpio_end;
> +
> +	mux_data = kzalloc(sizeof(struct pxa_gpio_irq_data), GFP_KERNEL);
> +	if (mux_data < 0)
> +		return -ENOMEM;
> +
> +	irq0 = platform_get_irq_byname(pdev, "gpio0");
> +	irq1 = platform_get_irq_byname(pdev, "gpio1");
> +	irq_mux = platform_get_irq_byname(pdev, "gpio_mux");
> +	if ((irq0 > 0 && irq1 < 0) || (irq0 < 0 && irq1 > 0) || (irq_mux < 0))
> +		return -EINVAL;
> +
> +	if (irq0 > 0) {
> +		mux_data->irq_gpio0 = irq0;
> +		mux_data->irq_gpio1 = irq1;
> +		gpio_offset = 2;
> +	}
> +	mux_data->irq_mux = irq_mux;
> +	mux_data->gpio_type = pdata->gpio_type;
> +
> +	/* Initialize GPIO chips */
> +	pxa_init_gpio_chip(pdata->gpio_end, mux_data);
> +
> +	/* clear all GPIO edge detects */
> +	for_each_gpio_chip(gpio, c) {
> +		__raw_writel(0, c->regbase + GFER_OFFSET);
> +		__raw_writel(0, c->regbase + GRER_OFFSET);
> +		__raw_writel(~0,c->regbase + GEDR_OFFSET);
> +	}
> +
> +#ifdef CONFIG_ARCH_PXA
> +	if (irq0 > 0) {
> +		irq = pxa_gpio_to_irq(0);
> +		irq_set_chip_data(irq, mux_data);
> +		irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
> +					 handle_edge_irq);
> +		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
> +		irq_set_chained_handler(irq0, pxa_gpio_demux_handler);
> +
> +		irq = pxa_gpio_to_irq(1);
> +		irq_set_chip_data(irq, mux_data);
> +		irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
> +					 handle_edge_irq);
> +		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
> +		irq_set_chained_handler(irq1, pxa_gpio_demux_handler);
> +	}
> +#endif	/* CONFIG_ARCH_PXA */
> +
> +	for (irq = mgpio_to_irq(gpio_offset);
> +		irq <= mgpio_to_irq(pdata->gpio_end); irq++) {
> +		irq_set_chip_data(irq, mux_data);
> +		irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
> +					 handle_edge_irq);
> +		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
> +	}
> +
> +	irq_set_chained_handler(irq_mux, pxa_gpio_demux_handler);
> +	return 0;
> +}
> +
> +static struct platform_driver pxa_gpio_driver = {
> +	.probe		= pxa_gpio_probe,
> +	.driver		= {
> +		.owner	= THIS_MODULE,
> +		.name	= "pxa-gpio",
> +	},
> +};
> +
> +static int __init pxa_gpio_init(void)
> +{
> +	return platform_driver_register(&pxa_gpio_driver);
> +}
> +postcore_initcall(pxa_gpio_init);
> +
> +#ifdef CONFIG_PM
> +static int pxa_gpio_suspend(void)
> +{
> +	struct pxa_gpio_chip *c;
> +	int gpio;
> +
> +	for_each_gpio_chip(gpio, c) {
> +		c->saved_gplr = __raw_readl(c->regbase + GPLR_OFFSET);
> +		c->saved_gpdr = __raw_readl(c->regbase + GPDR_OFFSET);
> +		c->saved_grer = __raw_readl(c->regbase + GRER_OFFSET);
> +		c->saved_gfer = __raw_readl(c->regbase + GFER_OFFSET);
> +
> +		/* Clear GPIO transition detect bits */
> +		__raw_writel(0xffffffff, c->regbase + GEDR_OFFSET);
> +	}
> +	return 0;
> +}
> +
> +static void pxa_gpio_resume(void)
> +{
> +	struct pxa_gpio_chip *c;
> +	int gpio;
> +
> +	for_each_gpio_chip(gpio, c) {
> +		/* restore level with set/clear */
> +		__raw_writel( c->saved_gplr, c->regbase + GPSR_OFFSET);
> +		__raw_writel(~c->saved_gplr, c->regbase + GPCR_OFFSET);
> +
> +		__raw_writel(c->saved_grer, c->regbase + GRER_OFFSET);
> +		__raw_writel(c->saved_gfer, c->regbase + GFER_OFFSET);
> +		__raw_writel(c->saved_gpdr, c->regbase + GPDR_OFFSET);
> +	}
> +}
> +#else
> +#define pxa_gpio_suspend	NULL
> +#define pxa_gpio_resume		NULL
> +#endif
> +
> +struct syscore_ops pxa_gpio_syscore_ops = {
> +	.suspend	= pxa_gpio_suspend,
> +	.resume		= pxa_gpio_resume,
> +};
> +
> +static int __init pxa_gpio_sysinit(void)
> +{
> +	register_syscore_ops(&pxa_gpio_syscore_ops);
> +	return 0;
> +}
> +postcore_initcall(pxa_gpio_sysinit);
> diff --git a/include/linux/gpio-pxa.h b/include/linux/gpio-pxa.h
> new file mode 100644
> index 0000000..97d89af
> --- /dev/null
> +++ b/include/linux/gpio-pxa.h
> @@ -0,0 +1,105 @@
> +#ifndef __GPIO_PXA_H
> +#define __GPIO_PXA_H
> +
> +#include <asm/io.h>
> +
> +/*
> + * We handle the GPIOs by banks, each bank covers up to 32 GPIOs with
> + * one set of registers. The register offsets are organized below:
> + *
> + * GPLR -- GPIO Pin Level Registers
> + * GPDR -- GPIO Pin Direction Registers
> + * GPSR -- GPIO Pin Output Set Registers
> + * GPCR -- GPIO Pin Output Clear Registers
> + * GRER -- GPIO Rising Edge Detect Registers
> + * GFER -- GPIO Falling Edge Detect Registers
> + * GEDR -- GPIO Edge Detect Status Registers
> + *
> + *           GPLR    GPDR    GPSR    GPCR    GRER    GFER    GEDR
> + * BANK 0 - 0x0000  0x000C  0x0018  0x0024  0x0030  0x003C  0x0048
> + * BANK 1 - 0x0004  0x0010  0x001C  0x0028  0x0034  0x0040  0x004C
> + * BANK 2 - 0x0008  0x0014  0x0020  0x002C  0x0038  0x0044  0x0050
> + *
> + * BANK 3 - 0x0100  0x010C  0x0118  0x0124  0x0130  0x013C  0x0148
> + * BANK 4 - 0x0104  0x0110  0x011C  0x0128  0x0134  0x0140  0x014C
> + * BANK 5 - 0x0108  0x0114  0x0120  0x012C  0x0138  0x0144  0x0150
> + *
> + * NOTE:
> + *   BANK 3 is only available on PXA27x and later processors.
> + *   BANK 4 and 5 are only available on PXA935
> + */
> +
> +#define BANK_OFF(n)	(((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2))
> +
> +#define gpio_to_bank(x)	((x) >> 5)
> +
> +/* More handy macros.  The argument is a literal GPIO number. */
> +
> +#define GPIO_bit(x)	(1 << ((x) & 0x1f))
> +
> +#define GPLR_OFFSET	0x00
> +#define GPDR_OFFSET	0x0C
> +#define GPSR_OFFSET	0x18
> +#define GPCR_OFFSET	0x24
> +#define GRER_OFFSET	0x30
> +#define GFER_OFFSET	0x3C
> +#define GEDR_OFFSET	0x48
> +#define GAFR_OFFSET	0x54
> +
> +enum {
> +	/*
> +	 * Interrupt of GPIO0 & GPIO1 is dependant in PXA series.
> +	 * Interrupt of all GPIO is muxed into one in MMP series.
> +	 */
> +	PXA25X_GPIO = 0,
> +	PXA26X_GPIO,
> +	PXA27X_GPIO,
> +	PXA3XX_GPIO,
> +	PXA93X_GPIO,
> +	MMP_GPIO = 0x10,
> +	MMP2_GPIO,
> +};
> +
> +#define MASK_GPIO_PXA				0x0f
> +#define MASK_GPIO_MMP				0xf0
> +
> +struct pxa_gpio_platform_data {
> +	int	gpio_end;
> +	int	gpio_type;
> +};
> +
> +static inline int gpio_is_pxa_type(int type)
> +{
> +	return type & MASK_GPIO_PXA;
> +}
> +
> +static inline int gpio_is_mmp_type(int type)
> +{
> +	return type & MASK_GPIO_MMP;
> +}
> +
> +struct pxa_gpio_regs {
> +	u32	gplr;
> +	u32	gpdr;
> +	u32	gpsr;
> +	u32	gpcr;
> +	u32	grer;
> +	u32	gfer;
> +	u32	gedr;
> +	u32	gafr;
> +};
> +
> +extern struct pxa_gpio_regs pxa_gpio_regs;
> +
> +#define GPLR(x)		(*(volatile u32 *)(pxa_gpio_regs.gplr + BANK_OFF((x >> 5))))
> +#define GPDR(x)		(*(volatile u32 *)(pxa_gpio_regs.gpdr + BANK_OFF((x >> 5))))
> +#define GPSR(x)		(*(volatile u32 *)(pxa_gpio_regs.gpsr + BANK_OFF((x >> 5))))
> +#define GPCR(x)		(*(volatile u32 *)(pxa_gpio_regs.gpcr + BANK_OFF((x >> 5))))
> +#define GRER(x)		(*(volatile u32 *)(pxa_gpio_regs.grer + BANK_OFF((x >> 5))))
> +#define GFER(x)		(*(volatile u32 *)(pxa_gpio_regs.gfer + BANK_OFF((x >> 5))))
> +#define GEDR(x)		(*(volatile u32 *)(pxa_gpio_regs.gedr + BANK_OFF((x >> 5))))
> +#define GAFR(x)		(*(volatile u32 *)(pxa_gpio_regs.gafr + (((x) & 0x70) >> 2)))
> +
> +#define GPIO_BANK(n)	(pxa_gpio_regs.gplr + BANK_OFF(n))

All these macros really need a pxa_gpio prefix, but that can be done
in a separate patch.

> +
> +#endif	/* __GPIO_PXA_H */
> -- 
> 1.7.2.5
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel



More information about the linux-arm-kernel mailing list