diff options
| -rw-r--r-- | Documentation/devicetree/bindings/gpio/sodaville.txt | 48 | ||||
| -rw-r--r-- | arch/arm/mach-omap1/gpio15xx.c | 7 | ||||
| -rw-r--r-- | arch/arm/mach-omap1/gpio16xx.c | 47 | ||||
| -rw-r--r-- | arch/arm/mach-omap1/gpio7xx.c | 14 | ||||
| -rw-r--r-- | arch/arm/mach-omap2/gpio.c | 36 | ||||
| -rw-r--r-- | arch/arm/mach-omap2/pm34xx.c | 14 | ||||
| -rw-r--r-- | arch/arm/plat-omap/include/plat/gpio.h | 29 | ||||
| -rw-r--r-- | arch/x86/platform/ce4100/falconfalls.dts | 7 | ||||
| -rw-r--r-- | drivers/gpio/Kconfig | 14 | ||||
| -rw-r--r-- | drivers/gpio/Makefile | 2 | ||||
| -rw-r--r-- | drivers/gpio/gpio-mc9s08dz60.c | 161 | ||||
| -rw-r--r-- | drivers/gpio/gpio-omap.c | 1086 | ||||
| -rw-r--r-- | drivers/gpio/gpio-pl061.c | 7 | ||||
| -rw-r--r-- | drivers/gpio/gpio-sodaville.c | 302 | ||||
| -rw-r--r-- | drivers/gpio/gpio-tps65910.c | 20 | ||||
| -rw-r--r-- | drivers/gpio/gpiolib.c | 8 | ||||
| -rw-r--r-- | drivers/of/gpio.c | 9 | ||||
| -rw-r--r-- | include/linux/mfd/tps65910.h | 8 | ||||
| -rw-r--r-- | include/linux/of_gpio.h | 27 | 
19 files changed, 1144 insertions, 702 deletions
diff --git a/Documentation/devicetree/bindings/gpio/sodaville.txt b/Documentation/devicetree/bindings/gpio/sodaville.txt new file mode 100644 index 00000000000..563eff22b97 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/sodaville.txt @@ -0,0 +1,48 @@ +GPIO controller on CE4100 / Sodaville SoCs +========================================== + +The bindings for CE4100's GPIO controller match the generic description +which is covered by the gpio.txt file in this folder. + +The only additional property is the intel,muxctl property which holds the +value which is written into the MUXCNTL register. + +There is no compatible property for now because the driver is probed via +PCI id (vendor 0x8086 device 0x2e67). + +The interrupt specifier consists of two cells encoded as follows: + - <1st cell>: The interrupt-number that identifies the interrupt source. + - <2nd cell>: The level-sense information, encoded as follows: +		4 - active high level-sensitive +		8 - active low level-sensitive + +Example of the GPIO device and one user: + +	pcigpio: gpio@b,1 { +			/* two cells for GPIO and interrupt */ +			#gpio-cells = <2>; +			#interrupt-cells = <2>; +			compatible = "pci8086,2e67.2", +					   "pci8086,2e67", +					   "pciclassff0000", +					   "pciclassff00"; + +			reg = <0x15900 0x0 0x0 0x0 0x0>; +			/* Interrupt line of the gpio device */ +			interrupts = <15 1>; +			/* It is an interrupt and GPIO controller itself */ +			interrupt-controller; +			gpio-controller; +			intel,muxctl = <0>; +	}; + +	testuser@20 { +			compatible = "example,testuser"; +			/* User the 11th GPIO line as an active high triggered +			 * level interrupt +			 */ +			interrupts = <11 8>; +			interrupt-parent = <&pcigpio>; +			/* Use this GPIO also with the gpio functions */ +			gpios = <&pcigpio 11 0>; +	}; diff --git a/arch/arm/mach-omap1/gpio15xx.c b/arch/arm/mach-omap1/gpio15xx.c index 399da4ce017..634903ef829 100644 --- a/arch/arm/mach-omap1/gpio15xx.c +++ b/arch/arm/mach-omap1/gpio15xx.c @@ -42,11 +42,12 @@ static struct omap_gpio_reg_offs omap15xx_mpuio_regs = {  	.irqstatus	= OMAP_MPUIO_GPIO_INT,  	.irqenable	= OMAP_MPUIO_GPIO_MASKIT,  	.irqenable_inv	= true, +	.irqctrl	= OMAP_MPUIO_GPIO_INT_EDGE,  };  static struct __initdata omap_gpio_platform_data omap15xx_mpu_gpio_config = {  	.virtual_irq_start	= IH_MPUIO_BASE, -	.bank_type		= METHOD_MPUIO, +	.is_mpuio		= true,  	.bank_width		= 16,  	.bank_stride		= 1,  	.regs			= &omap15xx_mpuio_regs, @@ -83,11 +84,12 @@ static struct omap_gpio_reg_offs omap15xx_gpio_regs = {  	.irqstatus	= OMAP1510_GPIO_INT_STATUS,  	.irqenable	= OMAP1510_GPIO_INT_MASK,  	.irqenable_inv	= true, +	.irqctrl	= OMAP1510_GPIO_INT_CONTROL, +	.pinctrl	= OMAP1510_GPIO_PIN_CONTROL,  };  static struct __initdata omap_gpio_platform_data omap15xx_gpio_config = {  	.virtual_irq_start	= IH_GPIO_BASE, -	.bank_type		= METHOD_GPIO_1510,  	.bank_width		= 16,  	.regs                   = &omap15xx_gpio_regs,  }; @@ -115,7 +117,6 @@ static int __init omap15xx_gpio_init(void)  	platform_device_register(&omap15xx_mpu_gpio);  	platform_device_register(&omap15xx_gpio); -	gpio_bank_count = 2;  	return 0;  }  postcore_initcall(omap15xx_gpio_init); diff --git a/arch/arm/mach-omap1/gpio16xx.c b/arch/arm/mach-omap1/gpio16xx.c index 0f399bd0e70..1c5f90e1742 100644 --- a/arch/arm/mach-omap1/gpio16xx.c +++ b/arch/arm/mach-omap1/gpio16xx.c @@ -24,6 +24,9 @@  #define OMAP1610_GPIO4_BASE		0xfffbbc00  #define OMAP1_MPUIO_VBASE		OMAP1_MPUIO_BASE +/* smart idle, enable wakeup */ +#define SYSCONFIG_WORD			0x14 +  /* mpu gpio */  static struct __initdata resource omap16xx_mpu_gpio_resources[] = {  	{ @@ -45,11 +48,12 @@ static struct omap_gpio_reg_offs omap16xx_mpuio_regs = {  	.irqstatus	= OMAP_MPUIO_GPIO_INT,  	.irqenable	= OMAP_MPUIO_GPIO_MASKIT,  	.irqenable_inv	= true, +	.irqctrl	= OMAP_MPUIO_GPIO_INT_EDGE,  };  static struct __initdata omap_gpio_platform_data omap16xx_mpu_gpio_config = {  	.virtual_irq_start	= IH_MPUIO_BASE, -	.bank_type		= METHOD_MPUIO, +	.is_mpuio		= true,  	.bank_width		= 16,  	.bank_stride		= 1,  	.regs                   = &omap16xx_mpuio_regs, @@ -89,11 +93,13 @@ static struct omap_gpio_reg_offs omap16xx_gpio_regs = {  	.irqenable	= OMAP1610_GPIO_IRQENABLE1,  	.set_irqenable	= OMAP1610_GPIO_SET_IRQENABLE1,  	.clr_irqenable	= OMAP1610_GPIO_CLEAR_IRQENABLE1, +	.wkup_en	= OMAP1610_GPIO_WAKEUPENABLE, +	.edgectrl1	= OMAP1610_GPIO_EDGE_CTRL1, +	.edgectrl2	= OMAP1610_GPIO_EDGE_CTRL2,  };  static struct __initdata omap_gpio_platform_data omap16xx_gpio1_config = {  	.virtual_irq_start	= IH_GPIO_BASE, -	.bank_type		= METHOD_GPIO_1610,  	.bank_width		= 16,  	.regs                   = &omap16xx_gpio_regs,  }; @@ -123,7 +129,6 @@ static struct __initdata resource omap16xx_gpio2_resources[] = {  static struct __initdata omap_gpio_platform_data omap16xx_gpio2_config = {  	.virtual_irq_start	= IH_GPIO_BASE + 16, -	.bank_type		= METHOD_GPIO_1610,  	.bank_width		= 16,  	.regs                   = &omap16xx_gpio_regs,  }; @@ -153,7 +158,6 @@ static struct __initdata resource omap16xx_gpio3_resources[] = {  static struct __initdata omap_gpio_platform_data omap16xx_gpio3_config = {  	.virtual_irq_start	= IH_GPIO_BASE + 32, -	.bank_type		= METHOD_GPIO_1610,  	.bank_width		= 16,  	.regs                   = &omap16xx_gpio_regs,  }; @@ -183,7 +187,6 @@ static struct __initdata resource omap16xx_gpio4_resources[] = {  static struct __initdata omap_gpio_platform_data omap16xx_gpio4_config = {  	.virtual_irq_start	= IH_GPIO_BASE + 48, -	.bank_type		= METHOD_GPIO_1610,  	.bank_width		= 16,  	.regs                   = &omap16xx_gpio_regs,  }; @@ -214,14 +217,42 @@ static struct __initdata platform_device * omap16xx_gpio_dev[] = {  static int __init omap16xx_gpio_init(void)  {  	int i; +	void __iomem *base; +	struct resource *res; +	struct platform_device *pdev; +	struct omap_gpio_platform_data *pdata;  	if (!cpu_is_omap16xx())  		return -EINVAL; -	for (i = 0; i < ARRAY_SIZE(omap16xx_gpio_dev); i++) -		platform_device_register(omap16xx_gpio_dev[i]); +	for (i = 0; i < ARRAY_SIZE(omap16xx_gpio_dev); i++) { +		pdev = omap16xx_gpio_dev[i]; +		pdata = pdev->dev.platform_data; + +		res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +		if (unlikely(!res)) { +			dev_err(&pdev->dev, "Invalid mem resource.\n"); +			return -ENODEV; +		} + +		base = ioremap(res->start, resource_size(res)); +		if (unlikely(!base)) { +			dev_err(&pdev->dev, "ioremap failed.\n"); +			return -ENOMEM; +		} -	gpio_bank_count = ARRAY_SIZE(omap16xx_gpio_dev); +		__raw_writel(SYSCONFIG_WORD, base + OMAP1610_GPIO_SYSCONFIG); +		iounmap(base); + +		/* +		 * Enable system clock for GPIO module. +		 * The CAM_CLK_CTRL *is* really the right place. +		 */ +		omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04, +					ULPD_CAM_CLK_CTRL); + +		platform_device_register(omap16xx_gpio_dev[i]); +	}  	return 0;  } diff --git a/arch/arm/mach-omap1/gpio7xx.c b/arch/arm/mach-omap1/gpio7xx.c index 5ab63eab0ff..4771d6b68b9 100644 --- a/arch/arm/mach-omap1/gpio7xx.c +++ b/arch/arm/mach-omap1/gpio7xx.c @@ -47,12 +47,13 @@ static struct omap_gpio_reg_offs omap7xx_mpuio_regs = {  	.irqstatus	= OMAP_MPUIO_GPIO_INT / 2,  	.irqenable	= OMAP_MPUIO_GPIO_MASKIT / 2,  	.irqenable_inv	= true, +	.irqctrl	= OMAP_MPUIO_GPIO_INT_EDGE >> 1,  };  static struct __initdata omap_gpio_platform_data omap7xx_mpu_gpio_config = {  	.virtual_irq_start	= IH_MPUIO_BASE, -	.bank_type		= METHOD_MPUIO, -	.bank_width		= 32, +	.is_mpuio		= true, +	.bank_width		= 16,  	.bank_stride		= 2,  	.regs                   = &omap7xx_mpuio_regs,  }; @@ -88,11 +89,11 @@ static struct omap_gpio_reg_offs omap7xx_gpio_regs = {  	.irqstatus	= OMAP7XX_GPIO_INT_STATUS,  	.irqenable	= OMAP7XX_GPIO_INT_MASK,  	.irqenable_inv	= true, +	.irqctrl	= OMAP7XX_GPIO_INT_CONTROL,  };  static struct __initdata omap_gpio_platform_data omap7xx_gpio1_config = {  	.virtual_irq_start	= IH_GPIO_BASE, -	.bank_type		= METHOD_GPIO_7XX,  	.bank_width		= 32,  	.regs			= &omap7xx_gpio_regs,  }; @@ -122,7 +123,6 @@ static struct __initdata resource omap7xx_gpio2_resources[] = {  static struct __initdata omap_gpio_platform_data omap7xx_gpio2_config = {  	.virtual_irq_start	= IH_GPIO_BASE + 32, -	.bank_type		= METHOD_GPIO_7XX,  	.bank_width		= 32,  	.regs			= &omap7xx_gpio_regs,  }; @@ -152,7 +152,6 @@ static struct __initdata resource omap7xx_gpio3_resources[] = {  static struct __initdata omap_gpio_platform_data omap7xx_gpio3_config = {  	.virtual_irq_start	= IH_GPIO_BASE + 64, -	.bank_type		= METHOD_GPIO_7XX,  	.bank_width		= 32,  	.regs			= &omap7xx_gpio_regs,  }; @@ -182,7 +181,6 @@ static struct __initdata resource omap7xx_gpio4_resources[] = {  static struct __initdata omap_gpio_platform_data omap7xx_gpio4_config = {  	.virtual_irq_start	= IH_GPIO_BASE + 96, -	.bank_type		= METHOD_GPIO_7XX,  	.bank_width		= 32,  	.regs			= &omap7xx_gpio_regs,  }; @@ -212,7 +210,6 @@ static struct __initdata resource omap7xx_gpio5_resources[] = {  static struct __initdata omap_gpio_platform_data omap7xx_gpio5_config = {  	.virtual_irq_start	= IH_GPIO_BASE + 128, -	.bank_type		= METHOD_GPIO_7XX,  	.bank_width		= 32,  	.regs			= &omap7xx_gpio_regs,  }; @@ -242,7 +239,6 @@ static struct __initdata resource omap7xx_gpio6_resources[] = {  static struct __initdata omap_gpio_platform_data omap7xx_gpio6_config = {  	.virtual_irq_start	= IH_GPIO_BASE + 160, -	.bank_type		= METHOD_GPIO_7XX,  	.bank_width		= 32,  	.regs			= &omap7xx_gpio_regs,  }; @@ -282,8 +278,6 @@ static int __init omap7xx_gpio_init(void)  	for (i = 0; i < ARRAY_SIZE(omap7xx_gpio_dev); i++)  		platform_device_register(omap7xx_gpio_dev[i]); -	gpio_bank_count = ARRAY_SIZE(omap7xx_gpio_dev); -  	return 0;  }  postcore_initcall(omap7xx_gpio_init); diff --git a/arch/arm/mach-omap2/gpio.c b/arch/arm/mach-omap2/gpio.c index 8cbfbc2918c..1e0b750afca 100644 --- a/arch/arm/mach-omap2/gpio.c +++ b/arch/arm/mach-omap2/gpio.c @@ -23,6 +23,9 @@  #include <plat/omap_hwmod.h>  #include <plat/omap_device.h> +#include <plat/omap-pm.h> + +#include "powerdomain.h"  static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)  { @@ -31,6 +34,7 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)  	struct omap_gpio_dev_attr *dev_attr;  	char *name = "omap_gpio";  	int id; +	struct powerdomain *pwrdm;  	/*  	 * extract the device id from name field available in the @@ -52,7 +56,7 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)  	pdata->bank_width = dev_attr->bank_width;  	pdata->dbck_flag = dev_attr->dbck_flag;  	pdata->virtual_irq_start = IH_GPIO_BASE + 32 * (id - 1); - +	pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count;  	pdata->regs = kzalloc(sizeof(struct omap_gpio_reg_offs), GFP_KERNEL);  	if (!pdata) {  		pr_err("gpio%d: Memory allocation failed\n", id); @@ -61,8 +65,15 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)  	switch (oh->class->rev) {  	case 0: +		if (id == 1) +			/* non-wakeup GPIO pins for OMAP2 Bank1 */ +			pdata->non_wakeup_gpios = 0xe203ffc0; +		else if (id == 2) +			/* non-wakeup GPIO pins for OMAP2 Bank2 */ +			pdata->non_wakeup_gpios = 0x08700040; +		/* fall through */ +  	case 1: -		pdata->bank_type = METHOD_GPIO_24XX;  		pdata->regs->revision = OMAP24XX_GPIO_REVISION;  		pdata->regs->direction = OMAP24XX_GPIO_OE;  		pdata->regs->datain = OMAP24XX_GPIO_DATAIN; @@ -72,13 +83,19 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)  		pdata->regs->irqstatus = OMAP24XX_GPIO_IRQSTATUS1;  		pdata->regs->irqstatus2 = OMAP24XX_GPIO_IRQSTATUS2;  		pdata->regs->irqenable = OMAP24XX_GPIO_IRQENABLE1; +		pdata->regs->irqenable2 = OMAP24XX_GPIO_IRQENABLE2;  		pdata->regs->set_irqenable = OMAP24XX_GPIO_SETIRQENABLE1;  		pdata->regs->clr_irqenable = OMAP24XX_GPIO_CLEARIRQENABLE1;  		pdata->regs->debounce = OMAP24XX_GPIO_DEBOUNCE_VAL;  		pdata->regs->debounce_en = OMAP24XX_GPIO_DEBOUNCE_EN; +		pdata->regs->ctrl = OMAP24XX_GPIO_CTRL; +		pdata->regs->wkup_en = OMAP24XX_GPIO_WAKE_EN; +		pdata->regs->leveldetect0 = OMAP24XX_GPIO_LEVELDETECT0; +		pdata->regs->leveldetect1 = OMAP24XX_GPIO_LEVELDETECT1; +		pdata->regs->risingdetect = OMAP24XX_GPIO_RISINGDETECT; +		pdata->regs->fallingdetect = OMAP24XX_GPIO_FALLINGDETECT;  		break;  	case 2: -		pdata->bank_type = METHOD_GPIO_44XX;  		pdata->regs->revision = OMAP4_GPIO_REVISION;  		pdata->regs->direction = OMAP4_GPIO_OE;  		pdata->regs->datain = OMAP4_GPIO_DATAIN; @@ -88,10 +105,17 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)  		pdata->regs->irqstatus = OMAP4_GPIO_IRQSTATUS0;  		pdata->regs->irqstatus2 = OMAP4_GPIO_IRQSTATUS1;  		pdata->regs->irqenable = OMAP4_GPIO_IRQSTATUSSET0; +		pdata->regs->irqenable2 = OMAP4_GPIO_IRQSTATUSSET1;  		pdata->regs->set_irqenable = OMAP4_GPIO_IRQSTATUSSET0;  		pdata->regs->clr_irqenable = OMAP4_GPIO_IRQSTATUSCLR0;  		pdata->regs->debounce = OMAP4_GPIO_DEBOUNCINGTIME;  		pdata->regs->debounce_en = OMAP4_GPIO_DEBOUNCENABLE; +		pdata->regs->ctrl = OMAP4_GPIO_CTRL; +		pdata->regs->wkup_en = OMAP4_GPIO_IRQWAKEN0; +		pdata->regs->leveldetect0 = OMAP4_GPIO_LEVELDETECT0; +		pdata->regs->leveldetect1 = OMAP4_GPIO_LEVELDETECT1; +		pdata->regs->risingdetect = OMAP4_GPIO_RISINGDETECT; +		pdata->regs->fallingdetect = OMAP4_GPIO_FALLINGDETECT;  		break;  	default:  		WARN(1, "Invalid gpio bank_type\n"); @@ -99,6 +123,9 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)  		return -EINVAL;  	} +	pwrdm = omap_hwmod_get_pwrdm(oh); +	pdata->loses_context = pwrdm_can_ever_lose_context(pwrdm); +  	pdev = omap_device_build(name, id - 1, oh, pdata,  				sizeof(*pdata),	NULL, 0, false);  	kfree(pdata); @@ -109,9 +136,6 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)  		return PTR_ERR(pdev);  	} -	omap_device_disable_idle_on_suspend(pdev); - -	gpio_bank_count++;  	return 0;  } diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index fc698757892..59c6dc16dd1 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -75,16 +75,6 @@ static struct powerdomain *mpu_pwrdm, *neon_pwrdm;  static struct powerdomain *core_pwrdm, *per_pwrdm;  static struct powerdomain *cam_pwrdm; -static inline void omap3_per_save_context(void) -{ -	omap_gpio_save_context(); -} - -static inline void omap3_per_restore_context(void) -{ -	omap_gpio_restore_context(); -} -  static void omap3_enable_io_chain(void)  {  	int timeout = 0; @@ -332,8 +322,6 @@ void omap_sram_idle(void)  	if (per_next_state < PWRDM_POWER_ON) {  		per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0;  		omap2_gpio_prepare_for_idle(per_going_off); -		if (per_next_state == PWRDM_POWER_OFF) -				omap3_per_save_context();  	}  	/* CORE */ @@ -399,8 +387,6 @@ void omap_sram_idle(void)  	if (per_next_state < PWRDM_POWER_ON) {  		per_prev_state = pwrdm_read_prev_pwrst(per_pwrdm);  		omap2_gpio_resume_after_idle(); -		if (per_prev_state == PWRDM_POWER_OFF) -			omap3_per_restore_context();  	}  	/* Disable IO-PAD and IO-CHAIN wakeup */ diff --git a/arch/arm/plat-omap/include/plat/gpio.h b/arch/arm/plat-omap/include/plat/gpio.h index 9e86ee0aed0..cb75b657b04 100644 --- a/arch/arm/plat-omap/include/plat/gpio.h +++ b/arch/arm/plat-omap/include/plat/gpio.h @@ -162,13 +162,6 @@  				 IH_MPUIO_BASE + ((nr) & 0x0f) : \  				 IH_GPIO_BASE + (nr)) -#define METHOD_MPUIO		0 -#define METHOD_GPIO_1510	1 -#define METHOD_GPIO_1610	2 -#define METHOD_GPIO_7XX		3 -#define METHOD_GPIO_24XX	5 -#define METHOD_GPIO_44XX	6 -  struct omap_gpio_dev_attr {  	int bank_width;		/* GPIO bank width */  	bool dbck_flag;		/* dbck required or not - True for OMAP3&4 */ @@ -184,10 +177,21 @@ struct omap_gpio_reg_offs {  	u16 irqstatus;  	u16 irqstatus2;  	u16 irqenable; +	u16 irqenable2;  	u16 set_irqenable;  	u16 clr_irqenable;  	u16 debounce;  	u16 debounce_en; +	u16 ctrl; +	u16 wkup_en; +	u16 leveldetect0; +	u16 leveldetect1; +	u16 risingdetect; +	u16 fallingdetect; +	u16 irqctrl; +	u16 edgectrl1; +	u16 edgectrl2; +	u16 pinctrl;  	bool irqenable_inv;  }; @@ -198,19 +202,20 @@ struct omap_gpio_platform_data {  	int bank_width;		/* GPIO bank width */  	int bank_stride;	/* Only needed for omap1 MPUIO */  	bool dbck_flag;		/* dbck required or not - True for OMAP3&4 */ +	bool loses_context;	/* whether the bank would ever lose context */ +	bool is_mpuio;		/* whether the bank is of type MPUIO */ +	u32 non_wakeup_gpios;  	struct omap_gpio_reg_offs *regs; -}; -/* TODO: Analyze removing gpio_bank_count usage from driver code */ -extern int gpio_bank_count; +	/* Return context loss count due to PM states changing */ +	int (*get_context_loss_count)(struct device *dev); +};  extern void omap2_gpio_prepare_for_idle(int off_mode);  extern void omap2_gpio_resume_after_idle(void);  extern void omap_set_gpio_debounce(int gpio, int enable);  extern void omap_set_gpio_debounce_time(int gpio, int enable); -extern void omap_gpio_save_context(void); -extern void omap_gpio_restore_context(void);  /*-------------------------------------------------------------------------*/  /* Wrappers for "new style" GPIO calls, using the new infrastructure diff --git a/arch/x86/platform/ce4100/falconfalls.dts b/arch/x86/platform/ce4100/falconfalls.dts index e70be38ce03..ce874f872cc 100644 --- a/arch/x86/platform/ce4100/falconfalls.dts +++ b/arch/x86/platform/ce4100/falconfalls.dts @@ -208,16 +208,19 @@  					interrupts = <14 1>;  				}; -				gpio@b,1 { +				pcigpio: gpio@b,1 { +					#gpio-cells = <2>; +					#interrupt-cells = <2>;  					compatible = "pci8086,2e67.2",  						   "pci8086,2e67",  						   "pciclassff0000",  						   "pciclassff00"; -					#gpio-cells = <2>;  					reg = <0x15900 0x0 0x0 0x0 0x0>;  					interrupts = <15 1>; +					interrupt-controller;  					gpio-controller; +					intel,muxctl = <0>;  				};  				i2c-controller@b,2 { diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d0c41188d4e..dbb1909ca0a 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -225,6 +225,12 @@ config GPIO_MAX732X_IRQ  	  Say yes here to enable the max732x to be used as an interrupt  	  controller. It requires the driver to be built in the kernel. +config GPIO_MC9S08DZ60 +	bool "MX35 3DS BOARD MC9S08DZ60 GPIO functions" +	depends on I2C && MACH_MX35_3DS +	help +	  Select this to enable the MC9S08DZ60 GPIO driver +  config GPIO_PCA953X  	tristate "PCA953x, PCA955x, TCA64xx, and MAX7310 I/O ports"  	depends on I2C @@ -411,6 +417,14 @@ config GPIO_ML_IOH  	  Hub) which is for IVI(In-Vehicle Infotainment) use.  	  This driver can access the IOH's GPIO device. +config GPIO_SODAVILLE +	bool "Intel Sodaville GPIO support" +	depends on X86 && PCI && OF +	select GPIO_GENERIC +	select GENERIC_IRQ_CHIP +	help +	  Say Y here to support Intel Sodaville GPIO. +  config GPIO_TIMBERDALE  	bool "Support for timberdale GPIO IP"  	depends on MFD_TIMBERDALE && HAS_IOMEM diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index fa10df604c0..593bdcd1976 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_GPIO_MAX7300)	+= gpio-max7300.o  obj-$(CONFIG_GPIO_MAX7301)	+= gpio-max7301.o  obj-$(CONFIG_GPIO_MAX732X)	+= gpio-max732x.o  obj-$(CONFIG_GPIO_MC33880)	+= gpio-mc33880.o +obj-$(CONFIG_GPIO_MC9S08DZ60)	+= gpio-mc9s08dz60.o  obj-$(CONFIG_GPIO_MCP23S08)	+= gpio-mcp23s08.o  obj-$(CONFIG_GPIO_ML_IOH)	+= gpio-ml-ioh.o  obj-$(CONFIG_GPIO_MPC5200)	+= gpio-mpc5200.o @@ -45,6 +46,7 @@ obj-$(CONFIG_GPIO_RDC321X)	+= gpio-rdc321x.o  obj-$(CONFIG_PLAT_SAMSUNG)	+= gpio-samsung.o  obj-$(CONFIG_ARCH_SA1100)	+= gpio-sa1100.o  obj-$(CONFIG_GPIO_SCH)		+= gpio-sch.o +obj-$(CONFIG_GPIO_SODAVILLE)	+= gpio-sodaville.o  obj-$(CONFIG_GPIO_STMPE)	+= gpio-stmpe.o  obj-$(CONFIG_GPIO_SX150X)	+= gpio-sx150x.o  obj-$(CONFIG_GPIO_TC3589X)	+= gpio-tc3589x.o diff --git a/drivers/gpio/gpio-mc9s08dz60.c b/drivers/gpio/gpio-mc9s08dz60.c new file mode 100644 index 00000000000..2738cc44d63 --- /dev/null +++ b/drivers/gpio/gpio-mc9s08dz60.c @@ -0,0 +1,161 @@ +/* + * Copyright 2009-2012 Freescale Semiconductor, Inc. All Rights Reserved. + * + * Author: Wu Guoxing <b39297@freescale.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/gpio.h> + +#define GPIO_GROUP_NUM 2 +#define GPIO_NUM_PER_GROUP 8 +#define GPIO_NUM (GPIO_GROUP_NUM*GPIO_NUM_PER_GROUP) + +struct mc9s08dz60 { +	struct i2c_client *client; +	struct gpio_chip chip; +}; + +static inline struct mc9s08dz60 *to_mc9s08dz60(struct gpio_chip *gc) +{ +	return container_of(gc, struct mc9s08dz60, chip); +} + + +static void mc9s_gpio_to_reg_and_bit(int offset, u8 *reg, u8 *bit) +{ +	*reg = 0x20 + offset / GPIO_NUM_PER_GROUP; +	*bit = offset % GPIO_NUM_PER_GROUP; +} + +static int mc9s08dz60_get_value(struct gpio_chip *gc, unsigned offset) +{ +	u8 reg, bit; +	s32 value; +	struct mc9s08dz60 *mc9s = to_mc9s08dz60(gc); + +	mc9s_gpio_to_reg_and_bit(offset, ®, &bit); +	value = i2c_smbus_read_byte_data(mc9s->client, reg); + +	return (value >= 0) ? (value >> bit) & 0x1 : 0; +} + +static int mc9s08dz60_set(struct mc9s08dz60 *mc9s, unsigned offset, int val) +{ +	u8 reg, bit; +	s32 value; + +	mc9s_gpio_to_reg_and_bit(offset, ®, &bit); +	value = i2c_smbus_read_byte_data(mc9s->client, reg); +	if (value >= 0) { +		if (val) +			value |= 1 << bit; +		else +			value &= ~(1 << bit); + +		return i2c_smbus_write_byte_data(mc9s->client, reg, value); +	} else +		return value; + +} + + +static void mc9s08dz60_set_value(struct gpio_chip *gc, unsigned offset, int val) +{ +	struct mc9s08dz60 *mc9s = to_mc9s08dz60(gc); + +	mc9s08dz60_set(mc9s, offset, val); +} + +static int mc9s08dz60_direction_output(struct gpio_chip *gc, +				       unsigned offset, int val) +{ +	struct mc9s08dz60 *mc9s = to_mc9s08dz60(gc); + +	return mc9s08dz60_set(mc9s, offset, val); +} + +static int mc9s08dz60_probe(struct i2c_client *client, +			    const struct i2c_device_id *id) +{ +	int ret = 0; +	struct mc9s08dz60 *mc9s; + +	mc9s = kzalloc(sizeof(*mc9s), GFP_KERNEL); +	if (!mc9s) +		return -ENOMEM; + +	mc9s->chip.label = client->name; +	mc9s->chip.base = -1; +	mc9s->chip.dev = &client->dev; +	mc9s->chip.owner = THIS_MODULE; +	mc9s->chip.ngpio = GPIO_NUM; +	mc9s->chip.can_sleep = 1; +	mc9s->chip.get = mc9s08dz60_get_value; +	mc9s->chip.set = mc9s08dz60_set_value; +	mc9s->chip.direction_output = mc9s08dz60_direction_output; +	mc9s->client = client; +	i2c_set_clientdata(client, mc9s); + +	ret = gpiochip_add(&mc9s->chip); +	if (ret) +		goto error; + +	return 0; + + error: +	kfree(mc9s); +	return ret; +} + +static int mc9s08dz60_remove(struct i2c_client *client) +{ +	struct mc9s08dz60 *mc9s; +	int ret; + +	mc9s = i2c_get_clientdata(client); + +	ret = gpiochip_remove(&mc9s->chip); +	if (!ret) +		kfree(mc9s); + +	return ret; + +} + +static const struct i2c_device_id mc9s08dz60_id[] = { +	{"mc9s08dz60", 0}, +	{}, +}; + +MODULE_DEVICE_TABLE(i2c, mc9s08dz60_id); + +static struct i2c_driver mc9s08dz60_i2c_driver = { +	.driver = { +		.owner = THIS_MODULE, +		.name = "mc9s08dz60", +	}, +	.probe = mc9s08dz60_probe, +	.remove = mc9s08dz60_remove, +	.id_table = mc9s08dz60_id, +}; + +module_i2c_driver(mc9s08dz60_i2c_driver); + +MODULE_AUTHOR("Freescale Semiconductor, Inc. " +		"Wu Guoxing <b39297@freescale.com>"); +MODULE_DESCRIPTION("mc9s08dz60 gpio function on mx35 3ds board"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 0b056297917..f49bd6f47a5 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -21,6 +21,7 @@  #include <linux/io.h>  #include <linux/slab.h>  #include <linux/pm_runtime.h> +#include <linux/pm.h>  #include <mach/hardware.h>  #include <asm/irq.h> @@ -28,19 +29,36 @@  #include <asm/gpio.h>  #include <asm/mach/irq.h> +#define OFF_MODE	1 + +static LIST_HEAD(omap_gpio_list); + +struct gpio_regs { +	u32 irqenable1; +	u32 irqenable2; +	u32 wake_en; +	u32 ctrl; +	u32 oe; +	u32 leveldetect0; +	u32 leveldetect1; +	u32 risingdetect; +	u32 fallingdetect; +	u32 dataout; +	u32 debounce; +	u32 debounce_en; +}; +  struct gpio_bank { +	struct list_head node;  	unsigned long pbase;  	void __iomem *base;  	u16 irq;  	u16 virtual_irq_start; -	int method;  	u32 suspend_wakeup; -#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS)  	u32 saved_wakeup; -#endif  	u32 non_wakeup_gpios;  	u32 enabled_non_wakeup_gpios; - +	struct gpio_regs context;  	u32 saved_datain;  	u32 saved_fallingdetect;  	u32 saved_risingdetect; @@ -51,44 +69,27 @@ struct gpio_bank {  	struct clk *dbck;  	u32 mod_usage;  	u32 dbck_enable_mask; +	bool dbck_enabled;  	struct device *dev; +	bool is_mpuio;  	bool dbck_flag; +	bool loses_context;  	int stride;  	u32 width; +	int context_loss_count; +	u16 id; +	int power_mode; +	bool workaround_enabled;  	void (*set_dataout)(struct gpio_bank *bank, int gpio, int enable); +	int (*get_context_loss_count)(struct device *dev);  	struct omap_gpio_reg_offs *regs;  }; -#ifdef CONFIG_ARCH_OMAP3 -struct omap3_gpio_regs { -	u32 irqenable1; -	u32 irqenable2; -	u32 wake_en; -	u32 ctrl; -	u32 oe; -	u32 leveldetect0; -	u32 leveldetect1; -	u32 risingdetect; -	u32 fallingdetect; -	u32 dataout; -}; - -static struct omap3_gpio_regs gpio_context[OMAP34XX_NR_GPIOS]; -#endif - -/* - * TODO: Cleanup gpio_bank usage as it is having information - * related to all instances of the device - */ -static struct gpio_bank *gpio_bank; - -/* TODO: Analyze removing gpio_bank_count usage from driver code */ -int gpio_bank_count; -  #define GPIO_INDEX(bank, gpio) (gpio % bank->width)  #define GPIO_BIT(bank, gpio) (1 << GPIO_INDEX(bank, gpio)) +#define GPIO_MOD_CTRL_BIT	BIT(0)  static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)  { @@ -102,6 +103,7 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)  	else  		l &= ~(1 << gpio);  	__raw_writel(l, reg); +	bank->context.oe = l;  } @@ -132,6 +134,7 @@ static void _set_gpio_dataout_mask(struct gpio_bank *bank, int gpio, int enable)  	else  		l &= ~gpio_bit;  	__raw_writel(l, reg); +	bank->context.dataout = l;  }  static int _get_gpio_datain(struct gpio_bank *bank, int gpio) @@ -160,6 +163,22 @@ static inline void _gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set)  	__raw_writel(l, base + reg);  } +static inline void _gpio_dbck_enable(struct gpio_bank *bank) +{ +	if (bank->dbck_enable_mask && !bank->dbck_enabled) { +		clk_enable(bank->dbck); +		bank->dbck_enabled = true; +	} +} + +static inline void _gpio_dbck_disable(struct gpio_bank *bank) +{ +	if (bank->dbck_enable_mask && bank->dbck_enabled) { +		clk_disable(bank->dbck); +		bank->dbck_enabled = false; +	} +} +  /**   * _set_gpio_debounce - low level gpio debounce time   * @bank: the gpio bank we're acting upon @@ -188,70 +207,74 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,  	l = GPIO_BIT(bank, gpio); +	clk_enable(bank->dbck);  	reg = bank->base + bank->regs->debounce;  	__raw_writel(debounce, reg);  	reg = bank->base + bank->regs->debounce_en;  	val = __raw_readl(reg); -	if (debounce) { +	if (debounce)  		val |= l; -		clk_enable(bank->dbck); -	} else { +	else  		val &= ~l; -		clk_disable(bank->dbck); -	}  	bank->dbck_enable_mask = val;  	__raw_writel(val, reg); +	clk_disable(bank->dbck); +	/* +	 * Enable debounce clock per module. +	 * This call is mandatory because in omap_gpio_request() when +	 * *_runtime_get_sync() is called,  _gpio_dbck_enable() within +	 * runtime callbck fails to turn on dbck because dbck_enable_mask +	 * used within _gpio_dbck_enable() is still not initialized at +	 * that point. Therefore we have to enable dbck here. +	 */ +	_gpio_dbck_enable(bank); +	if (bank->dbck_enable_mask) { +		bank->context.debounce = debounce; +		bank->context.debounce_en = val; +	}  } -#ifdef CONFIG_ARCH_OMAP2PLUS -static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio, +static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio,  						int trigger)  {  	void __iomem *base = bank->base;  	u32 gpio_bit = 1 << gpio; -	if (cpu_is_omap44xx()) { -		_gpio_rmw(base, OMAP4_GPIO_LEVELDETECT0, gpio_bit, -			  trigger & IRQ_TYPE_LEVEL_LOW); -		_gpio_rmw(base, OMAP4_GPIO_LEVELDETECT1, gpio_bit, -			  trigger & IRQ_TYPE_LEVEL_HIGH); -		_gpio_rmw(base, OMAP4_GPIO_RISINGDETECT, gpio_bit, -			  trigger & IRQ_TYPE_EDGE_RISING); -		_gpio_rmw(base, OMAP4_GPIO_FALLINGDETECT, gpio_bit, -			  trigger & IRQ_TYPE_EDGE_FALLING); -	} else { -		_gpio_rmw(base, OMAP24XX_GPIO_LEVELDETECT0, gpio_bit, -			  trigger & IRQ_TYPE_LEVEL_LOW); -		_gpio_rmw(base, OMAP24XX_GPIO_LEVELDETECT1, gpio_bit, -			  trigger & IRQ_TYPE_LEVEL_HIGH); -		_gpio_rmw(base, OMAP24XX_GPIO_RISINGDETECT, gpio_bit, -			  trigger & IRQ_TYPE_EDGE_RISING); -		_gpio_rmw(base, OMAP24XX_GPIO_FALLINGDETECT, gpio_bit, -			  trigger & IRQ_TYPE_EDGE_FALLING); -	} +	_gpio_rmw(base, bank->regs->leveldetect0, gpio_bit, +		  trigger & IRQ_TYPE_LEVEL_LOW); +	_gpio_rmw(base, bank->regs->leveldetect1, gpio_bit, +		  trigger & IRQ_TYPE_LEVEL_HIGH); +	_gpio_rmw(base, bank->regs->risingdetect, gpio_bit, +		  trigger & IRQ_TYPE_EDGE_RISING); +	_gpio_rmw(base, bank->regs->fallingdetect, gpio_bit, +		  trigger & IRQ_TYPE_EDGE_FALLING); + +	bank->context.leveldetect0 = +			__raw_readl(bank->base + bank->regs->leveldetect0); +	bank->context.leveldetect1 = +			__raw_readl(bank->base + bank->regs->leveldetect1); +	bank->context.risingdetect = +			__raw_readl(bank->base + bank->regs->risingdetect); +	bank->context.fallingdetect = +			__raw_readl(bank->base + bank->regs->fallingdetect); +  	if (likely(!(bank->non_wakeup_gpios & gpio_bit))) { -		if (cpu_is_omap44xx()) { -			_gpio_rmw(base, OMAP4_GPIO_IRQWAKEN0, gpio_bit, -				  trigger != 0); -		} else { -			/* -			 * GPIO wakeup request can only be generated on edge -			 * transitions -			 */ -			if (trigger & IRQ_TYPE_EDGE_BOTH) -				__raw_writel(1 << gpio, bank->base -					+ OMAP24XX_GPIO_SETWKUENA); -			else -				__raw_writel(1 << gpio, bank->base -					+ OMAP24XX_GPIO_CLEARWKUENA); -		} +		_gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0); +		bank->context.wake_en = +			__raw_readl(bank->base + bank->regs->wkup_en);  	} +  	/* This part needs to be executed always for OMAP{34xx, 44xx} */ -	if (cpu_is_omap34xx() || cpu_is_omap44xx() || -			(bank->non_wakeup_gpios & gpio_bit)) { +	if (!bank->regs->irqctrl) { +		/* On omap24xx proceed only when valid GPIO bit is set */ +		if (bank->non_wakeup_gpios) { +			if (!(bank->non_wakeup_gpios & gpio_bit)) +				goto exit; +		} +  		/*  		 * Log the edge gpio and manually trigger the IRQ  		 * after resume if the input level changes @@ -264,17 +287,11 @@ static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio,  			bank->enabled_non_wakeup_gpios &= ~gpio_bit;  	} -	if (cpu_is_omap44xx()) { -		bank->level_mask = -			__raw_readl(bank->base + OMAP4_GPIO_LEVELDETECT0) | -			__raw_readl(bank->base + OMAP4_GPIO_LEVELDETECT1); -	} else { -		bank->level_mask = -			__raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0) | -			__raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1); -	} +exit: +	bank->level_mask = +		__raw_readl(bank->base + bank->regs->leveldetect0) | +		__raw_readl(bank->base + bank->regs->leveldetect1);  } -#endif  #ifdef CONFIG_ARCH_OMAP1  /* @@ -286,23 +303,10 @@ static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio)  	void __iomem *reg = bank->base;  	u32 l = 0; -	switch (bank->method) { -	case METHOD_MPUIO: -		reg += OMAP_MPUIO_GPIO_INT_EDGE / bank->stride; -		break; -#ifdef CONFIG_ARCH_OMAP15XX -	case METHOD_GPIO_1510: -		reg += OMAP1510_GPIO_INT_CONTROL; -		break; -#endif -#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) -	case METHOD_GPIO_7XX: -		reg += OMAP7XX_GPIO_INT_CONTROL; -		break; -#endif -	default: +	if (!bank->regs->irqctrl)  		return; -	} + +	reg += bank->regs->irqctrl;  	l = __raw_readl(reg);  	if ((l >> gpio) & 1) @@ -312,31 +316,21 @@ static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio)  	__raw_writel(l, reg);  } +#else +static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) {}  #endif  static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)  {  	void __iomem *reg = bank->base; +	void __iomem *base = bank->base;  	u32 l = 0; -	switch (bank->method) { -#ifdef CONFIG_ARCH_OMAP1 -	case METHOD_MPUIO: -		reg += OMAP_MPUIO_GPIO_INT_EDGE / bank->stride; -		l = __raw_readl(reg); -		if ((trigger & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) -			bank->toggle_mask |= 1 << gpio; -		if (trigger & IRQ_TYPE_EDGE_RISING) -			l |= 1 << gpio; -		else if (trigger & IRQ_TYPE_EDGE_FALLING) -			l &= ~(1 << gpio); -		else -			goto bad; -		break; -#endif -#ifdef CONFIG_ARCH_OMAP15XX -	case METHOD_GPIO_1510: -		reg += OMAP1510_GPIO_INT_CONTROL; +	if (bank->regs->leveldetect0 && bank->regs->wkup_en) { +		set_gpio_trigger(bank, gpio, trigger); +	} else if (bank->regs->irqctrl) { +		reg += bank->regs->irqctrl; +  		l = __raw_readl(reg);  		if ((trigger & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH)  			bank->toggle_mask |= 1 << gpio; @@ -345,15 +339,15 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)  		else if (trigger & IRQ_TYPE_EDGE_FALLING)  			l &= ~(1 << gpio);  		else -			goto bad; -		break; -#endif -#ifdef CONFIG_ARCH_OMAP16XX -	case METHOD_GPIO_1610: +			return -EINVAL; + +		__raw_writel(l, reg); +	} else if (bank->regs->edgectrl1) {  		if (gpio & 0x08) -			reg += OMAP1610_GPIO_EDGE_CTRL2; +			reg += bank->regs->edgectrl2;  		else -			reg += OMAP1610_GPIO_EDGE_CTRL1; +			reg += bank->regs->edgectrl1; +  		gpio &= 0x07;  		l = __raw_readl(reg);  		l &= ~(3 << (gpio << 1)); @@ -361,40 +355,14 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)  			l |= 2 << (gpio << 1);  		if (trigger & IRQ_TYPE_EDGE_FALLING)  			l |= 1 << (gpio << 1); -		if (trigger) -			/* Enable wake-up during idle for dynamic tick */ -			__raw_writel(1 << gpio, bank->base + OMAP1610_GPIO_SET_WAKEUPENA); -		else -			__raw_writel(1 << gpio, bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA); -		break; -#endif -#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) -	case METHOD_GPIO_7XX: -		reg += OMAP7XX_GPIO_INT_CONTROL; -		l = __raw_readl(reg); -		if ((trigger & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) -			bank->toggle_mask |= 1 << gpio; -		if (trigger & IRQ_TYPE_EDGE_RISING) -			l |= 1 << gpio; -		else if (trigger & IRQ_TYPE_EDGE_FALLING) -			l &= ~(1 << gpio); -		else -			goto bad; -		break; -#endif -#ifdef CONFIG_ARCH_OMAP2PLUS -	case METHOD_GPIO_24XX: -	case METHOD_GPIO_44XX: -		set_24xx_gpio_triggering(bank, gpio, trigger); -		return 0; -#endif -	default: -		goto bad; + +		/* Enable wake-up during idle for dynamic tick */ +		_gpio_rmw(base, bank->regs->wkup_en, 1 << gpio, trigger); +		bank->context.wake_en = +			__raw_readl(bank->base + bank->regs->wkup_en); +		__raw_writel(l, reg);  	} -	__raw_writel(l, reg);  	return 0; -bad: -	return -EINVAL;  }  static int gpio_irq_type(struct irq_data *d, unsigned type) @@ -412,12 +380,12 @@ static int gpio_irq_type(struct irq_data *d, unsigned type)  	if (type & ~IRQ_TYPE_SENSE_MASK)  		return -EINVAL; -	/* OMAP1 allows only only edge triggering */ -	if (!cpu_class_is_omap2() -			&& (type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH))) +	bank = irq_data_get_irq_chip_data(d); + +	if (!bank->regs->leveldetect0 && +		(type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)))  		return -EINVAL; -	bank = irq_data_get_irq_chip_data(d);  	spin_lock_irqsave(&bank->lock, flags);  	retval = _set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), type);  	spin_unlock_irqrestore(&bank->lock, flags); @@ -484,6 +452,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)  	}  	__raw_writel(l, reg); +	bank->context.irqenable1 = l;  }  static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) @@ -504,6 +473,7 @@ static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)  	}  	__raw_writel(l, reg); +	bank->context.irqenable1 = l;  }  static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable) @@ -567,38 +537,39 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)  	struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);  	unsigned long flags; -	spin_lock_irqsave(&bank->lock, flags); +	/* +	 * If this is the first gpio_request for the bank, +	 * enable the bank module. +	 */ +	if (!bank->mod_usage) +		pm_runtime_get_sync(bank->dev); +	spin_lock_irqsave(&bank->lock, flags);  	/* Set trigger to none. You need to enable the desired trigger with  	 * request_irq() or set_irq_type().  	 */  	_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); -#ifdef CONFIG_ARCH_OMAP15XX -	if (bank->method == METHOD_GPIO_1510) { -		void __iomem *reg; +	if (bank->regs->pinctrl) { +		void __iomem *reg = bank->base + bank->regs->pinctrl;  		/* Claim the pin for MPU */ -		reg = bank->base + OMAP1510_GPIO_PIN_CONTROL;  		__raw_writel(__raw_readl(reg) | (1 << offset), reg);  	} -#endif -	if (!cpu_class_is_omap1()) { -		if (!bank->mod_usage) { -			void __iomem *reg = bank->base; -			u32 ctrl; -			if (cpu_is_omap24xx() || cpu_is_omap34xx()) -				reg += OMAP24XX_GPIO_CTRL; -			else if (cpu_is_omap44xx()) -				reg += OMAP4_GPIO_CTRL; -			ctrl = __raw_readl(reg); -			/* Module is enabled, clocks are not gated */ -			ctrl &= 0xFFFFFFFE; -			__raw_writel(ctrl, reg); -		} -		bank->mod_usage |= 1 << offset; +	if (bank->regs->ctrl && !bank->mod_usage) { +		void __iomem *reg = bank->base + bank->regs->ctrl; +		u32 ctrl; + +		ctrl = __raw_readl(reg); +		/* Module is enabled, clocks are not gated */ +		ctrl &= ~GPIO_MOD_CTRL_BIT; +		__raw_writel(ctrl, reg); +		bank->context.ctrl = ctrl;  	} + +	bank->mod_usage |= 1 << offset; +  	spin_unlock_irqrestore(&bank->lock, flags);  	return 0; @@ -607,48 +578,40 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)  static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)  {  	struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip); +	void __iomem *base = bank->base;  	unsigned long flags;  	spin_lock_irqsave(&bank->lock, flags); -#ifdef CONFIG_ARCH_OMAP16XX -	if (bank->method == METHOD_GPIO_1610) { -		/* Disable wake-up during idle for dynamic tick */ -		void __iomem *reg = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA; -		__raw_writel(1 << offset, reg); -	} -#endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) -	if (bank->method == METHOD_GPIO_24XX) { -		/* Disable wake-up during idle for dynamic tick */ -		void __iomem *reg = bank->base + OMAP24XX_GPIO_CLEARWKUENA; -		__raw_writel(1 << offset, reg); -	} -#endif -#ifdef CONFIG_ARCH_OMAP4 -	if (bank->method == METHOD_GPIO_44XX) { + +	if (bank->regs->wkup_en) {  		/* Disable wake-up during idle for dynamic tick */ -		void __iomem *reg = bank->base + OMAP4_GPIO_IRQWAKEN0; -		__raw_writel(1 << offset, reg); +		_gpio_rmw(base, bank->regs->wkup_en, 1 << offset, 0); +		bank->context.wake_en = +			__raw_readl(bank->base + bank->regs->wkup_en);  	} -#endif -	if (!cpu_class_is_omap1()) { -		bank->mod_usage &= ~(1 << offset); -		if (!bank->mod_usage) { -			void __iomem *reg = bank->base; -			u32 ctrl; -			if (cpu_is_omap24xx() || cpu_is_omap34xx()) -				reg += OMAP24XX_GPIO_CTRL; -			else if (cpu_is_omap44xx()) -				reg += OMAP4_GPIO_CTRL; -			ctrl = __raw_readl(reg); -			/* Module is disabled, clocks are gated */ -			ctrl |= 1; -			__raw_writel(ctrl, reg); -		} +	bank->mod_usage &= ~(1 << offset); + +	if (bank->regs->ctrl && !bank->mod_usage) { +		void __iomem *reg = bank->base + bank->regs->ctrl; +		u32 ctrl; + +		ctrl = __raw_readl(reg); +		/* Module is disabled, clocks are gated */ +		ctrl |= GPIO_MOD_CTRL_BIT; +		__raw_writel(ctrl, reg); +		bank->context.ctrl = ctrl;  	} +  	_reset_gpio(bank, bank->chip.base + offset);  	spin_unlock_irqrestore(&bank->lock, flags); + +	/* +	 * If this is the last gpio to be freed in the bank, +	 * disable the bank module. +	 */ +	if (!bank->mod_usage) +		pm_runtime_put(bank->dev);  }  /* @@ -674,6 +637,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)  	bank = irq_get_handler_data(irq);  	isr_reg = bank->base + bank->regs->irqstatus; +	pm_runtime_get_sync(bank->dev);  	if (WARN_ON(!isr_reg))  		goto exit; @@ -685,12 +649,8 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)  		enabled = _get_gpio_irqbank_mask(bank);  		isr_saved = isr = __raw_readl(isr_reg) & enabled; -		if (cpu_is_omap15xx() && (bank->method == METHOD_MPUIO)) -			isr &= 0x0000ffff; - -		if (cpu_class_is_omap2()) { +		if (bank->level_mask)  			level_mask = bank->level_mask & enabled; -		}  		/* clear edge sensitive interrupts before handler(s) are  		called so that we don't miss any interrupt occurred while @@ -718,7 +678,6 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)  			if (!(isr & 1))  				continue; -#ifdef CONFIG_ARCH_OMAP1  			/*  			 * Some chips can't respond to both rising and falling  			 * at the same time.  If this irq was requested with @@ -728,7 +687,6 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)  			 */  			if (bank->toggle_mask & (1 << gpio_index))  				_toggle_gpio_edge_triggering(bank, gpio_index); -#endif  			generic_handle_irq(gpio_irq);  		} @@ -740,6 +698,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)  exit:  	if (!unmasked)  		chained_irq_exit(chip, desc); +	pm_runtime_put(bank->dev);  }  static void gpio_irq_shutdown(struct irq_data *d) @@ -808,14 +767,6 @@ static struct irq_chip gpio_irq_chip = {  /*---------------------------------------------------------------------*/ -#ifdef CONFIG_ARCH_OMAP1 - -#define bank_is_mpuio(bank)	((bank)->method == METHOD_MPUIO) - -#ifdef CONFIG_ARCH_OMAP16XX - -#include <linux/platform_device.h> -  static int omap_mpuio_suspend_noirq(struct device *dev)  {  	struct platform_device *pdev = to_platform_device(dev); @@ -869,32 +820,16 @@ static struct platform_device omap_mpuio_device = {  	/* could list the /proc/iomem resources */  }; -static inline void mpuio_init(void) +static inline void mpuio_init(struct gpio_bank *bank)  { -	struct gpio_bank *bank = &gpio_bank[0];  	platform_set_drvdata(&omap_mpuio_device, bank);  	if (platform_driver_register(&omap_mpuio_driver) == 0)  		(void) platform_device_register(&omap_mpuio_device);  } -#else -static inline void mpuio_init(void) {} -#endif	/* 16xx */ - -#else - -#define bank_is_mpuio(bank)	0 -static inline void mpuio_init(void) {} - -#endif -  /*---------------------------------------------------------------------*/ -/* REVISIT these are stupid implementations!  replace by ones that - * don't switch on METHOD_* and which mostly avoid spinlocks - */ -  static int gpio_input(struct gpio_chip *chip, unsigned offset)  {  	struct gpio_bank *bank; @@ -1007,78 +942,32 @@ static void __init omap_gpio_show_rev(struct gpio_bank *bank)   */  static struct lock_class_key gpio_lock_class; -static inline int init_gpio_info(struct platform_device *pdev) +static void omap_gpio_mod_init(struct gpio_bank *bank)  { -	/* TODO: Analyze removing gpio_bank_count usage from driver code */ -	gpio_bank = kzalloc(gpio_bank_count * sizeof(struct gpio_bank), -				GFP_KERNEL); -	if (!gpio_bank) { -		dev_err(&pdev->dev, "Memory alloc failed for gpio_bank\n"); -		return -ENOMEM; -	} -	return 0; -} +	void __iomem *base = bank->base; +	u32 l = 0xffffffff; -/* TODO: Cleanup cpu_is_* checks */ -static void omap_gpio_mod_init(struct gpio_bank *bank, int id) -{ -	if (cpu_class_is_omap2()) { -		if (cpu_is_omap44xx()) { -			__raw_writel(0xffffffff, bank->base + -					OMAP4_GPIO_IRQSTATUSCLR0); -			__raw_writel(0x00000000, bank->base + -					 OMAP4_GPIO_DEBOUNCENABLE); -			/* Initialize interface clk ungated, module enabled */ -			__raw_writel(0, bank->base + OMAP4_GPIO_CTRL); -		} else if (cpu_is_omap34xx()) { -			__raw_writel(0x00000000, bank->base + -					OMAP24XX_GPIO_IRQENABLE1); -			__raw_writel(0xffffffff, bank->base + -					OMAP24XX_GPIO_IRQSTATUS1); -			__raw_writel(0x00000000, bank->base + -					OMAP24XX_GPIO_DEBOUNCE_EN); +	if (bank->width == 16) +		l = 0xffff; -			/* Initialize interface clk ungated, module enabled */ -			__raw_writel(0, bank->base + OMAP24XX_GPIO_CTRL); -		} else if (cpu_is_omap24xx()) { -			static const u32 non_wakeup_gpios[] = { -				0xe203ffc0, 0x08700040 -			}; -			if (id < ARRAY_SIZE(non_wakeup_gpios)) -				bank->non_wakeup_gpios = non_wakeup_gpios[id]; -		} -	} else if (cpu_class_is_omap1()) { -		if (bank_is_mpuio(bank)) -			__raw_writew(0xffff, bank->base + -				OMAP_MPUIO_GPIO_MASKIT / bank->stride); -		if (cpu_is_omap15xx() && bank->method == METHOD_GPIO_1510) { -			__raw_writew(0xffff, bank->base -						+ OMAP1510_GPIO_INT_MASK); -			__raw_writew(0x0000, bank->base -						+ OMAP1510_GPIO_INT_STATUS); -		} -		if (cpu_is_omap16xx() && bank->method == METHOD_GPIO_1610) { -			__raw_writew(0x0000, bank->base -						+ OMAP1610_GPIO_IRQENABLE1); -			__raw_writew(0xffff, bank->base -						+ OMAP1610_GPIO_IRQSTATUS1); -			__raw_writew(0x0014, bank->base -						+ OMAP1610_GPIO_SYSCONFIG); - -			/* -			 * Enable system clock for GPIO module. -			 * The CAM_CLK_CTRL *is* really the right place. -			 */ -			omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04, -						ULPD_CAM_CLK_CTRL); -		} -		if (cpu_is_omap7xx() && bank->method == METHOD_GPIO_7XX) { -			__raw_writel(0xffffffff, bank->base -						+ OMAP7XX_GPIO_INT_MASK); -			__raw_writel(0x00000000, bank->base -						+ OMAP7XX_GPIO_INT_STATUS); -		} +	if (bank->is_mpuio) { +		__raw_writel(l, bank->base + bank->regs->irqenable); +		return;  	} + +	_gpio_rmw(base, bank->regs->irqenable, l, bank->regs->irqenable_inv); +	_gpio_rmw(base, bank->regs->irqstatus, l, +					bank->regs->irqenable_inv == false); +	_gpio_rmw(base, bank->regs->irqenable, l, bank->regs->debounce_en != 0); +	_gpio_rmw(base, bank->regs->irqenable, l, bank->regs->ctrl != 0); +	if (bank->regs->debounce_en) +		_gpio_rmw(base, bank->regs->debounce_en, 0, 1); + +	/* Save OE default value (0xffffffff) in the context */ +	bank->context.oe = __raw_readl(bank->base + bank->regs->direction); +	 /* Initialize interface clk ungated, module enabled */ +	if (bank->regs->ctrl) +		_gpio_rmw(base, bank->regs->ctrl, 0, 1);  }  static __init void @@ -1101,8 +990,8 @@ omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start,  	ct->chip.irq_mask = irq_gc_mask_set_bit;  	ct->chip.irq_unmask = irq_gc_mask_clr_bit;  	ct->chip.irq_set_type = gpio_irq_type; -	/* REVISIT: assuming only 16xx supports MPUIO wake events */ -	if (cpu_is_omap16xx()) + +	if (bank->regs->wkup_en)  		ct->chip.irq_set_wake = gpio_wake_enable,  	ct->regs.mask = OMAP_MPUIO_GPIO_INT / bank->stride; @@ -1115,7 +1004,6 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank)  	int j;  	static int gpio; -	bank->mod_usage = 0;  	/*  	 * REVISIT eventually switch from OMAP-specific gpio structs  	 * over to the generic ones @@ -1128,11 +1016,10 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank)  	bank->chip.set_debounce = gpio_debounce;  	bank->chip.set = gpio_set;  	bank->chip.to_irq = gpio_2irq; -	if (bank_is_mpuio(bank)) { +	if (bank->is_mpuio) {  		bank->chip.label = "mpuio"; -#ifdef CONFIG_ARCH_OMAP16XX -		bank->chip.dev = &omap_mpuio_device.dev; -#endif +		if (bank->regs->wkup_en) +			bank->chip.dev = &omap_mpuio_device.dev;  		bank->chip.base = OMAP_MPUIO(0);  	} else {  		bank->chip.label = "gpio"; @@ -1147,7 +1034,7 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank)  		     j < bank->virtual_irq_start + bank->width; j++) {  		irq_set_lockdep_class(j, &gpio_lock_class);  		irq_set_chip_data(j, bank); -		if (bank_is_mpuio(bank)) { +		if (bank->is_mpuio) {  			omap_mpuio_alloc_gc(bank, j, bank->width);  		} else {  			irq_set_chip(j, &gpio_irq_chip); @@ -1161,42 +1048,44 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank)  static int __devinit omap_gpio_probe(struct platform_device *pdev)  { -	static int gpio_init_done;  	struct omap_gpio_platform_data *pdata;  	struct resource *res; -	int id;  	struct gpio_bank *bank; +	int ret = 0; -	if (!pdev->dev.platform_data) -		return -EINVAL; - -	pdata = pdev->dev.platform_data; - -	if (!gpio_init_done) { -		int ret; - -		ret = init_gpio_info(pdev); -		if (ret) -			return ret; +	if (!pdev->dev.platform_data) { +		ret = -EINVAL; +		goto err_exit;  	} -	id = pdev->id; -	bank = &gpio_bank[id]; +	bank = kzalloc(sizeof(struct gpio_bank), GFP_KERNEL); +	if (!bank) { +		dev_err(&pdev->dev, "Memory alloc failed for gpio_bank\n"); +		ret = -ENOMEM; +		goto err_exit; +	}  	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);  	if (unlikely(!res)) { -		dev_err(&pdev->dev, "GPIO Bank %i Invalid IRQ resource\n", id); -		return -ENODEV; +		dev_err(&pdev->dev, "GPIO Bank %i Invalid IRQ resource\n", +				pdev->id); +		ret = -ENODEV; +		goto err_free;  	}  	bank->irq = res->start; +	bank->id = pdev->id; + +	pdata = pdev->dev.platform_data;  	bank->virtual_irq_start = pdata->virtual_irq_start; -	bank->method = pdata->bank_type;  	bank->dev = &pdev->dev;  	bank->dbck_flag = pdata->dbck_flag;  	bank->stride = pdata->bank_stride;  	bank->width = pdata->bank_width; - +	bank->is_mpuio = pdata->is_mpuio; +	bank->non_wakeup_gpios = pdata->non_wakeup_gpios; +	bank->loses_context = pdata->loses_context; +	bank->get_context_loss_count = pdata->get_context_loss_count;  	bank->regs = pdata->regs;  	if (bank->regs->set_dataout && bank->regs->clr_dataout) @@ -1209,369 +1098,310 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)  	/* Static mapping, never released */  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	if (unlikely(!res)) { -		dev_err(&pdev->dev, "GPIO Bank %i Invalid mem resource\n", id); -		return -ENODEV; +		dev_err(&pdev->dev, "GPIO Bank %i Invalid mem resource\n", +				pdev->id); +		ret = -ENODEV; +		goto err_free;  	}  	bank->base = ioremap(res->start, resource_size(res));  	if (!bank->base) { -		dev_err(&pdev->dev, "Could not ioremap gpio bank%i\n", id); -		return -ENOMEM; +		dev_err(&pdev->dev, "Could not ioremap gpio bank%i\n", +				pdev->id); +		ret = -ENOMEM; +		goto err_free;  	} +	platform_set_drvdata(pdev, bank); +  	pm_runtime_enable(bank->dev); +	pm_runtime_irq_safe(bank->dev);  	pm_runtime_get_sync(bank->dev); -	omap_gpio_mod_init(bank, id); +	if (bank->is_mpuio) +		mpuio_init(bank); + +	omap_gpio_mod_init(bank);  	omap_gpio_chip_init(bank);  	omap_gpio_show_rev(bank); -	if (!gpio_init_done) -		gpio_init_done = 1; +	pm_runtime_put(bank->dev); -	return 0; +	list_add_tail(&bank->node, &omap_gpio_list); + +	return ret; + +err_free: +	kfree(bank); +err_exit: +	return ret;  } -#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS) -static int omap_gpio_suspend(void) +#ifdef CONFIG_ARCH_OMAP2PLUS + +#if defined(CONFIG_PM_SLEEP) +static int omap_gpio_suspend(struct device *dev)  { -	int i; +	struct platform_device *pdev = to_platform_device(dev); +	struct gpio_bank *bank = platform_get_drvdata(pdev); +	void __iomem *base = bank->base; +	void __iomem *wakeup_enable; +	unsigned long flags; -	if (!cpu_class_is_omap2() && !cpu_is_omap16xx()) +	if (!bank->mod_usage || !bank->loses_context)  		return 0; -	for (i = 0; i < gpio_bank_count; i++) { -		struct gpio_bank *bank = &gpio_bank[i]; -		void __iomem *wake_status; -		void __iomem *wake_clear; -		void __iomem *wake_set; -		unsigned long flags; +	if (!bank->regs->wkup_en || !bank->suspend_wakeup) +		return 0; -		switch (bank->method) { -#ifdef CONFIG_ARCH_OMAP16XX -		case METHOD_GPIO_1610: -			wake_status = bank->base + OMAP1610_GPIO_WAKEUPENABLE; -			wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA; -			wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA; -			break; -#endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) -		case METHOD_GPIO_24XX: -			wake_status = bank->base + OMAP24XX_GPIO_WAKE_EN; -			wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA; -			wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA; -			break; -#endif -#ifdef CONFIG_ARCH_OMAP4 -		case METHOD_GPIO_44XX: -			wake_status = bank->base + OMAP4_GPIO_IRQWAKEN0; -			wake_clear = bank->base + OMAP4_GPIO_IRQWAKEN0; -			wake_set = bank->base + OMAP4_GPIO_IRQWAKEN0; -			break; -#endif -		default: -			continue; -		} +	wakeup_enable = bank->base + bank->regs->wkup_en; -		spin_lock_irqsave(&bank->lock, flags); -		bank->saved_wakeup = __raw_readl(wake_status); -		__raw_writel(0xffffffff, wake_clear); -		__raw_writel(bank->suspend_wakeup, wake_set); -		spin_unlock_irqrestore(&bank->lock, flags); -	} +	spin_lock_irqsave(&bank->lock, flags); +	bank->saved_wakeup = __raw_readl(wakeup_enable); +	_gpio_rmw(base, bank->regs->wkup_en, 0xffffffff, 0); +	_gpio_rmw(base, bank->regs->wkup_en, bank->suspend_wakeup, 1); +	spin_unlock_irqrestore(&bank->lock, flags);  	return 0;  } -static void omap_gpio_resume(void) +static int omap_gpio_resume(struct device *dev)  { -	int i; +	struct platform_device *pdev = to_platform_device(dev); +	struct gpio_bank *bank = platform_get_drvdata(pdev); +	void __iomem *base = bank->base; +	unsigned long flags; -	if (!cpu_class_is_omap2() && !cpu_is_omap16xx()) -		return; +	if (!bank->mod_usage || !bank->loses_context) +		return 0; -	for (i = 0; i < gpio_bank_count; i++) { -		struct gpio_bank *bank = &gpio_bank[i]; -		void __iomem *wake_clear; -		void __iomem *wake_set; -		unsigned long flags; +	if (!bank->regs->wkup_en || !bank->saved_wakeup) +		return 0; -		switch (bank->method) { -#ifdef CONFIG_ARCH_OMAP16XX -		case METHOD_GPIO_1610: -			wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA; -			wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA; -			break; -#endif -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) -		case METHOD_GPIO_24XX: -			wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA; -			wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA; -			break; -#endif -#ifdef CONFIG_ARCH_OMAP4 -		case METHOD_GPIO_44XX: -			wake_clear = bank->base + OMAP4_GPIO_IRQWAKEN0; -			wake_set = bank->base + OMAP4_GPIO_IRQWAKEN0; -			break; -#endif -		default: -			continue; -		} +	spin_lock_irqsave(&bank->lock, flags); +	_gpio_rmw(base, bank->regs->wkup_en, 0xffffffff, 0); +	_gpio_rmw(base, bank->regs->wkup_en, bank->saved_wakeup, 1); +	spin_unlock_irqrestore(&bank->lock, flags); -		spin_lock_irqsave(&bank->lock, flags); -		__raw_writel(0xffffffff, wake_clear); -		__raw_writel(bank->saved_wakeup, wake_set); -		spin_unlock_irqrestore(&bank->lock, flags); -	} +	return 0;  } +#endif /* CONFIG_PM_SLEEP */ -static struct syscore_ops omap_gpio_syscore_ops = { -	.suspend	= omap_gpio_suspend, -	.resume		= omap_gpio_resume, -}; - -#endif +#if defined(CONFIG_PM_RUNTIME) +static void omap_gpio_restore_context(struct gpio_bank *bank); -#ifdef CONFIG_ARCH_OMAP2PLUS +static int omap_gpio_runtime_suspend(struct device *dev) +{ +	struct platform_device *pdev = to_platform_device(dev); +	struct gpio_bank *bank = platform_get_drvdata(pdev); +	u32 l1 = 0, l2 = 0; +	unsigned long flags; -static int workaround_enabled; +	spin_lock_irqsave(&bank->lock, flags); +	if (bank->power_mode != OFF_MODE) { +		bank->power_mode = 0; +		goto update_gpio_context_count; +	} +	/* +	 * If going to OFF, remove triggering for all +	 * non-wakeup GPIOs.  Otherwise spurious IRQs will be +	 * generated.  See OMAP2420 Errata item 1.101. +	 */ +	if (!(bank->enabled_non_wakeup_gpios)) +		goto update_gpio_context_count; -void omap2_gpio_prepare_for_idle(int off_mode) -{ -	int i, c = 0; -	int min = 0; +	bank->saved_datain = __raw_readl(bank->base + +						bank->regs->datain); +	l1 = __raw_readl(bank->base + bank->regs->fallingdetect); +	l2 = __raw_readl(bank->base + bank->regs->risingdetect); -	if (cpu_is_omap34xx()) -		min = 1; +	bank->saved_fallingdetect = l1; +	bank->saved_risingdetect = l2; +	l1 &= ~bank->enabled_non_wakeup_gpios; +	l2 &= ~bank->enabled_non_wakeup_gpios; -	for (i = min; i < gpio_bank_count; i++) { -		struct gpio_bank *bank = &gpio_bank[i]; -		u32 l1 = 0, l2 = 0; -		int j; +	__raw_writel(l1, bank->base + bank->regs->fallingdetect); +	__raw_writel(l2, bank->base + bank->regs->risingdetect); -		for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++) -			clk_disable(bank->dbck); +	bank->workaround_enabled = true; -		if (!off_mode) -			continue; +update_gpio_context_count: +	if (bank->get_context_loss_count) +		bank->context_loss_count = +				bank->get_context_loss_count(bank->dev); -		/* If going to OFF, remove triggering for all -		 * non-wakeup GPIOs.  Otherwise spurious IRQs will be -		 * generated.  See OMAP2420 Errata item 1.101. */ -		if (!(bank->enabled_non_wakeup_gpios)) -			continue; +	_gpio_dbck_disable(bank); +	spin_unlock_irqrestore(&bank->lock, flags); -		if (cpu_is_omap24xx() || cpu_is_omap34xx()) { -			bank->saved_datain = __raw_readl(bank->base + -					OMAP24XX_GPIO_DATAIN); -			l1 = __raw_readl(bank->base + -					OMAP24XX_GPIO_FALLINGDETECT); -			l2 = __raw_readl(bank->base + -					OMAP24XX_GPIO_RISINGDETECT); -		} +	return 0; +} -		if (cpu_is_omap44xx()) { -			bank->saved_datain = __raw_readl(bank->base + -						OMAP4_GPIO_DATAIN); -			l1 = __raw_readl(bank->base + -						OMAP4_GPIO_FALLINGDETECT); -			l2 = __raw_readl(bank->base + -						OMAP4_GPIO_RISINGDETECT); -		} +static int omap_gpio_runtime_resume(struct device *dev) +{ +	struct platform_device *pdev = to_platform_device(dev); +	struct gpio_bank *bank = platform_get_drvdata(pdev); +	int context_lost_cnt_after; +	u32 l = 0, gen, gen0, gen1; +	unsigned long flags; -		bank->saved_fallingdetect = l1; -		bank->saved_risingdetect = l2; -		l1 &= ~bank->enabled_non_wakeup_gpios; -		l2 &= ~bank->enabled_non_wakeup_gpios; +	spin_lock_irqsave(&bank->lock, flags); +	_gpio_dbck_enable(bank); +	if (!bank->enabled_non_wakeup_gpios || !bank->workaround_enabled) { +		spin_unlock_irqrestore(&bank->lock, flags); +		return 0; +	} -		if (cpu_is_omap24xx() || cpu_is_omap34xx()) { -			__raw_writel(l1, bank->base + -					OMAP24XX_GPIO_FALLINGDETECT); -			__raw_writel(l2, bank->base + -					OMAP24XX_GPIO_RISINGDETECT); +	if (bank->get_context_loss_count) { +		context_lost_cnt_after = +			bank->get_context_loss_count(bank->dev); +		if (context_lost_cnt_after != bank->context_loss_count || +						!context_lost_cnt_after) { +			omap_gpio_restore_context(bank); +		} else { +			spin_unlock_irqrestore(&bank->lock, flags); +			return 0;  		} +	} -		if (cpu_is_omap44xx()) { -			__raw_writel(l1, bank->base + OMAP4_GPIO_FALLINGDETECT); -			__raw_writel(l2, bank->base + OMAP4_GPIO_RISINGDETECT); -		} +	__raw_writel(bank->saved_fallingdetect, +			bank->base + bank->regs->fallingdetect); +	__raw_writel(bank->saved_risingdetect, +			bank->base + bank->regs->risingdetect); +	l = __raw_readl(bank->base + bank->regs->datain); -		c++; -	} -	if (!c) { -		workaround_enabled = 0; -		return; -	} -	workaround_enabled = 1; -} +	/* +	 * Check if any of the non-wakeup interrupt GPIOs have changed +	 * state.  If so, generate an IRQ by software.  This is +	 * horribly racy, but it's the best we can do to work around +	 * this silicon bug. +	 */ +	l ^= bank->saved_datain; +	l &= bank->enabled_non_wakeup_gpios; -void omap2_gpio_resume_after_idle(void) -{ -	int i; -	int min = 0; +	/* +	 * No need to generate IRQs for the rising edge for gpio IRQs +	 * configured with falling edge only; and vice versa. +	 */ +	gen0 = l & bank->saved_fallingdetect; +	gen0 &= bank->saved_datain; -	if (cpu_is_omap34xx()) -		min = 1; -	for (i = min; i < gpio_bank_count; i++) { -		struct gpio_bank *bank = &gpio_bank[i]; -		u32 l = 0, gen, gen0, gen1; -		int j; +	gen1 = l & bank->saved_risingdetect; +	gen1 &= ~(bank->saved_datain); -		for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++) -			clk_enable(bank->dbck); +	/* FIXME: Consider GPIO IRQs with level detections properly! */ +	gen = l & (~(bank->saved_fallingdetect) & ~(bank->saved_risingdetect)); +	/* Consider all GPIO IRQs needed to be updated */ +	gen |= gen0 | gen1; -		if (!workaround_enabled) -			continue; +	if (gen) { +		u32 old0, old1; -		if (!(bank->enabled_non_wakeup_gpios)) -			continue; +		old0 = __raw_readl(bank->base + bank->regs->leveldetect0); +		old1 = __raw_readl(bank->base + bank->regs->leveldetect1);  		if (cpu_is_omap24xx() || cpu_is_omap34xx()) { -			__raw_writel(bank->saved_fallingdetect, -				 bank->base + OMAP24XX_GPIO_FALLINGDETECT); -			__raw_writel(bank->saved_risingdetect, -				 bank->base + OMAP24XX_GPIO_RISINGDETECT); -			l = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN); +			__raw_writel(old0 | gen, bank->base + +						bank->regs->leveldetect0); +			__raw_writel(old1 | gen, bank->base + +						bank->regs->leveldetect1);  		}  		if (cpu_is_omap44xx()) { -			__raw_writel(bank->saved_fallingdetect, -				 bank->base + OMAP4_GPIO_FALLINGDETECT); -			__raw_writel(bank->saved_risingdetect, -				 bank->base + OMAP4_GPIO_RISINGDETECT); -			l = __raw_readl(bank->base + OMAP4_GPIO_DATAIN); +			__raw_writel(old0 | l, bank->base + +						bank->regs->leveldetect0); +			__raw_writel(old1 | l, bank->base + +						bank->regs->leveldetect1);  		} +		__raw_writel(old0, bank->base + bank->regs->leveldetect0); +		__raw_writel(old1, bank->base + bank->regs->leveldetect1); +	} -		/* Check if any of the non-wakeup interrupt GPIOs have changed -		 * state.  If so, generate an IRQ by software.  This is -		 * horribly racy, but it's the best we can do to work around -		 * this silicon bug. */ -		l ^= bank->saved_datain; -		l &= bank->enabled_non_wakeup_gpios; - -		/* -		 * No need to generate IRQs for the rising edge for gpio IRQs -		 * configured with falling edge only; and vice versa. -		 */ -		gen0 = l & bank->saved_fallingdetect; -		gen0 &= bank->saved_datain; +	bank->workaround_enabled = false; +	spin_unlock_irqrestore(&bank->lock, flags); -		gen1 = l & bank->saved_risingdetect; -		gen1 &= ~(bank->saved_datain); +	return 0; +} +#endif /* CONFIG_PM_RUNTIME */ -		/* FIXME: Consider GPIO IRQs with level detections properly! */ -		gen = l & (~(bank->saved_fallingdetect) & -				~(bank->saved_risingdetect)); -		/* Consider all GPIO IRQs needed to be updated */ -		gen |= gen0 | gen1; +void omap2_gpio_prepare_for_idle(int pwr_mode) +{ +	struct gpio_bank *bank; -		if (gen) { -			u32 old0, old1; +	list_for_each_entry(bank, &omap_gpio_list, node) { +		if (!bank->mod_usage || !bank->loses_context) +			continue; -			if (cpu_is_omap24xx() || cpu_is_omap34xx()) { -				old0 = __raw_readl(bank->base + -					OMAP24XX_GPIO_LEVELDETECT0); -				old1 = __raw_readl(bank->base + -					OMAP24XX_GPIO_LEVELDETECT1); -				__raw_writel(old0 | gen, bank->base + -					OMAP24XX_GPIO_LEVELDETECT0); -				__raw_writel(old1 | gen, bank->base + -					OMAP24XX_GPIO_LEVELDETECT1); -				__raw_writel(old0, bank->base + -					OMAP24XX_GPIO_LEVELDETECT0); -				__raw_writel(old1, bank->base + -					OMAP24XX_GPIO_LEVELDETECT1); -			} +		bank->power_mode = pwr_mode; -			if (cpu_is_omap44xx()) { -				old0 = __raw_readl(bank->base + -						OMAP4_GPIO_LEVELDETECT0); -				old1 = __raw_readl(bank->base + -						OMAP4_GPIO_LEVELDETECT1); -				__raw_writel(old0 | l, bank->base + -						OMAP4_GPIO_LEVELDETECT0); -				__raw_writel(old1 | l, bank->base + -						OMAP4_GPIO_LEVELDETECT1); -				__raw_writel(old0, bank->base + -						OMAP4_GPIO_LEVELDETECT0); -				__raw_writel(old1, bank->base + -						OMAP4_GPIO_LEVELDETECT1); -			} -		} +		pm_runtime_put_sync_suspend(bank->dev);  	} -  } -#endif - -#ifdef CONFIG_ARCH_OMAP3 -/* save the registers of bank 2-6 */ -void omap_gpio_save_context(void) +void omap2_gpio_resume_after_idle(void)  { -	int i; +	struct gpio_bank *bank; -	/* saving banks from 2-6 only since GPIO1 is in WKUP */ -	for (i = 1; i < gpio_bank_count; i++) { -		struct gpio_bank *bank = &gpio_bank[i]; -		gpio_context[i].irqenable1 = -			__raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE1); -		gpio_context[i].irqenable2 = -			__raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE2); -		gpio_context[i].wake_en = -			__raw_readl(bank->base + OMAP24XX_GPIO_WAKE_EN); -		gpio_context[i].ctrl = -			__raw_readl(bank->base + OMAP24XX_GPIO_CTRL); -		gpio_context[i].oe = -			__raw_readl(bank->base + OMAP24XX_GPIO_OE); -		gpio_context[i].leveldetect0 = -			__raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0); -		gpio_context[i].leveldetect1 = -			__raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1); -		gpio_context[i].risingdetect = -			__raw_readl(bank->base + OMAP24XX_GPIO_RISINGDETECT); -		gpio_context[i].fallingdetect = -			__raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT); -		gpio_context[i].dataout = -			__raw_readl(bank->base + OMAP24XX_GPIO_DATAOUT); +	list_for_each_entry(bank, &omap_gpio_list, node) { +		if (!bank->mod_usage || !bank->loses_context) +			continue; + +		pm_runtime_get_sync(bank->dev);  	}  } -/* restore the required registers of bank 2-6 */ -void omap_gpio_restore_context(void) +#if defined(CONFIG_PM_RUNTIME) +static void omap_gpio_restore_context(struct gpio_bank *bank)  { -	int i; +	__raw_writel(bank->context.wake_en, +				bank->base + bank->regs->wkup_en); +	__raw_writel(bank->context.ctrl, bank->base + bank->regs->ctrl); +	__raw_writel(bank->context.leveldetect0, +				bank->base + bank->regs->leveldetect0); +	__raw_writel(bank->context.leveldetect1, +				bank->base + bank->regs->leveldetect1); +	__raw_writel(bank->context.risingdetect, +				bank->base + bank->regs->risingdetect); +	__raw_writel(bank->context.fallingdetect, +				bank->base + bank->regs->fallingdetect); +	if (bank->regs->set_dataout && bank->regs->clr_dataout) +		__raw_writel(bank->context.dataout, +				bank->base + bank->regs->set_dataout); +	else +		__raw_writel(bank->context.dataout, +				bank->base + bank->regs->dataout); +	__raw_writel(bank->context.oe, bank->base + bank->regs->direction); -	for (i = 1; i < gpio_bank_count; i++) { -		struct gpio_bank *bank = &gpio_bank[i]; -		__raw_writel(gpio_context[i].irqenable1, -				bank->base + OMAP24XX_GPIO_IRQENABLE1); -		__raw_writel(gpio_context[i].irqenable2, -				bank->base + OMAP24XX_GPIO_IRQENABLE2); -		__raw_writel(gpio_context[i].wake_en, -				bank->base + OMAP24XX_GPIO_WAKE_EN); -		__raw_writel(gpio_context[i].ctrl, -				bank->base + OMAP24XX_GPIO_CTRL); -		__raw_writel(gpio_context[i].oe, -				bank->base + OMAP24XX_GPIO_OE); -		__raw_writel(gpio_context[i].leveldetect0, -				bank->base + OMAP24XX_GPIO_LEVELDETECT0); -		__raw_writel(gpio_context[i].leveldetect1, -				bank->base + OMAP24XX_GPIO_LEVELDETECT1); -		__raw_writel(gpio_context[i].risingdetect, -				bank->base + OMAP24XX_GPIO_RISINGDETECT); -		__raw_writel(gpio_context[i].fallingdetect, -				bank->base + OMAP24XX_GPIO_FALLINGDETECT); -		__raw_writel(gpio_context[i].dataout, -				bank->base + OMAP24XX_GPIO_DATAOUT); +	if (bank->dbck_enable_mask) { +		__raw_writel(bank->context.debounce, bank->base + +					bank->regs->debounce); +		__raw_writel(bank->context.debounce_en, +					bank->base + bank->regs->debounce_en);  	} + +	__raw_writel(bank->context.irqenable1, +				bank->base + bank->regs->irqenable); +	__raw_writel(bank->context.irqenable2, +				bank->base + bank->regs->irqenable2);  } +#endif /* CONFIG_PM_RUNTIME */ +#else +#define omap_gpio_suspend NULL +#define omap_gpio_resume NULL +#define omap_gpio_runtime_suspend NULL +#define omap_gpio_runtime_resume NULL  #endif +static const struct dev_pm_ops gpio_pm_ops = { +	SET_SYSTEM_SLEEP_PM_OPS(omap_gpio_suspend, omap_gpio_resume) +	SET_RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume, +									NULL) +}; +  static struct platform_driver omap_gpio_driver = {  	.probe		= omap_gpio_probe,  	.driver		= {  		.name	= "omap_gpio", +		.pm	= &gpio_pm_ops,  	},  }; @@ -1585,17 +1415,3 @@ static int __init omap_gpio_drv_reg(void)  	return platform_driver_register(&omap_gpio_driver);  }  postcore_initcall(omap_gpio_drv_reg); - -static int __init omap_gpio_sysinit(void) -{ -	mpuio_init(); - -#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS) -	if (cpu_is_omap16xx() || cpu_class_is_omap2()) -		register_syscore_ops(&omap_gpio_syscore_ops); -#endif - -	return 0; -} - -arch_initcall(omap_gpio_sysinit); diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 77c9cc70fa7..b4b5da4fd2c 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -352,7 +352,12 @@ static int pl061_resume(struct device *dev)  	return 0;  } -static SIMPLE_DEV_PM_OPS(pl061_dev_pm_ops, pl061_suspend, pl061_resume); +static const struct dev_pm_ops pl061_dev_pm_ops = { +	.suspend = pl061_suspend, +	.resume = pl061_resume, +	.freeze = pl061_suspend, +	.restore = pl061_resume, +};  #endif  static struct amba_id pl061_ids[] = { diff --git a/drivers/gpio/gpio-sodaville.c b/drivers/gpio/gpio-sodaville.c new file mode 100644 index 00000000000..9ba15d31d24 --- /dev/null +++ b/drivers/gpio/gpio-sodaville.c @@ -0,0 +1,302 @@ +/* + *  GPIO interface for Intel Sodaville SoCs. + * + *  Copyright (c) 2010, 2011 Intel Corporation + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License 2 as published + *  by the Free Software Foundation. + * + */ + +#include <linux/errno.h> +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/platform_device.h> +#include <linux/of_irq.h> +#include <linux/basic_mmio_gpio.h> + +#define DRV_NAME		"sdv_gpio" +#define SDV_NUM_PUB_GPIOS	12 +#define PCI_DEVICE_ID_SDV_GPIO	0x2e67 +#define GPIO_BAR		0 + +#define GPOUTR		0x00 +#define GPOER		0x04 +#define GPINR		0x08 + +#define GPSTR		0x0c +#define GPIT1R0		0x10 +#define GPIO_INT	0x14 +#define GPIT1R1		0x18 + +#define GPMUXCTL	0x1c + +struct sdv_gpio_chip_data { +	int irq_base; +	void __iomem *gpio_pub_base; +	struct irq_domain id; +	struct irq_chip_generic *gc; +	struct bgpio_chip bgpio; +}; + +static int sdv_gpio_pub_set_type(struct irq_data *d, unsigned int type) +{ +	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); +	struct sdv_gpio_chip_data *sd = gc->private; +	void __iomem *type_reg; +	u32 irq_offs = d->irq - sd->irq_base; +	u32 reg; + +	if (irq_offs < 8) +		type_reg = sd->gpio_pub_base + GPIT1R0; +	else +		type_reg = sd->gpio_pub_base + GPIT1R1; + +	reg = readl(type_reg); + +	switch (type) { +	case IRQ_TYPE_LEVEL_HIGH: +		reg &= ~BIT(4 * (irq_offs % 8)); +		break; + +	case IRQ_TYPE_LEVEL_LOW: +		reg |= BIT(4 * (irq_offs % 8)); +		break; + +	default: +		return -EINVAL; +	} + +	writel(reg, type_reg); +	return 0; +} + +static irqreturn_t sdv_gpio_pub_irq_handler(int irq, void *data) +{ +	struct sdv_gpio_chip_data *sd = data; +	u32 irq_stat = readl(sd->gpio_pub_base + GPSTR); + +	irq_stat &= readl(sd->gpio_pub_base + GPIO_INT); +	if (!irq_stat) +		return IRQ_NONE; + +	while (irq_stat) { +		u32 irq_bit = __fls(irq_stat); + +		irq_stat &= ~BIT(irq_bit); +		generic_handle_irq(sd->irq_base + irq_bit); +	} + +	return IRQ_HANDLED; +} + +static int sdv_xlate(struct irq_domain *h, struct device_node *node, +		const u32 *intspec, u32 intsize, irq_hw_number_t *out_hwirq, +		u32 *out_type) +{ +	u32 line, type; + +	if (node != h->of_node) +		return -EINVAL; + +	if (intsize < 2) +		return -EINVAL; + +	line = *intspec; +	*out_hwirq = line; + +	intspec++; +	type = *intspec; + +	switch (type) { +	case IRQ_TYPE_LEVEL_LOW: +	case IRQ_TYPE_LEVEL_HIGH: +		*out_type = type; +		break; +	default: +		return -EINVAL; +	} +	return 0; +} + +static struct irq_domain_ops irq_domain_sdv_ops = { +	.dt_translate	= sdv_xlate, +}; + +static __devinit int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd, +		struct pci_dev *pdev) +{ +	struct irq_chip_type *ct; +	int ret; + +	sd->irq_base = irq_alloc_descs(-1, 0, SDV_NUM_PUB_GPIOS, -1); +	if (sd->irq_base < 0) +		return sd->irq_base; + +	/* mask + ACK all interrupt sources */ +	writel(0, sd->gpio_pub_base + GPIO_INT); +	writel((1 << 11) - 1, sd->gpio_pub_base + GPSTR); + +	ret = request_irq(pdev->irq, sdv_gpio_pub_irq_handler, IRQF_SHARED, +			"sdv_gpio", sd); +	if (ret) +		goto out_free_desc; + +	sd->id.irq_base = sd->irq_base; +	sd->id.of_node = of_node_get(pdev->dev.of_node); +	sd->id.ops = &irq_domain_sdv_ops; + +	/* +	 * This gpio irq controller latches level irqs. Testing shows that if +	 * we unmask & ACK the IRQ before the source of the interrupt is gone +	 * then the interrupt is active again. +	 */ +	sd->gc = irq_alloc_generic_chip("sdv-gpio", 1, sd->irq_base, +			sd->gpio_pub_base, handle_fasteoi_irq); +	if (!sd->gc) { +		ret = -ENOMEM; +		goto out_free_irq; +	} + +	sd->gc->private = sd; +	ct = sd->gc->chip_types; +	ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW; +	ct->regs.eoi = GPSTR; +	ct->regs.mask = GPIO_INT; +	ct->chip.irq_mask = irq_gc_mask_clr_bit; +	ct->chip.irq_unmask = irq_gc_mask_set_bit; +	ct->chip.irq_eoi = irq_gc_eoi; +	ct->chip.irq_set_type = sdv_gpio_pub_set_type; + +	irq_setup_generic_chip(sd->gc, IRQ_MSK(SDV_NUM_PUB_GPIOS), +			IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST, +			IRQ_LEVEL | IRQ_NOPROBE); + +	irq_domain_add(&sd->id); +	return 0; +out_free_irq: +	free_irq(pdev->irq, sd); +out_free_desc: +	irq_free_descs(sd->irq_base, SDV_NUM_PUB_GPIOS); +	return ret; +} + +static int __devinit sdv_gpio_probe(struct pci_dev *pdev, +					const struct pci_device_id *pci_id) +{ +	struct sdv_gpio_chip_data *sd; +	unsigned long addr; +	const void *prop; +	int len; +	int ret; +	u32 mux_val; + +	sd = kzalloc(sizeof(struct sdv_gpio_chip_data), GFP_KERNEL); +	if (!sd) +		return -ENOMEM; +	ret = pci_enable_device(pdev); +	if (ret) { +		dev_err(&pdev->dev, "can't enable device.\n"); +		goto done; +	} + +	ret = pci_request_region(pdev, GPIO_BAR, DRV_NAME); +	if (ret) { +		dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", GPIO_BAR); +		goto disable_pci; +	} + +	addr = pci_resource_start(pdev, GPIO_BAR); +	if (!addr) +		goto release_reg; +	sd->gpio_pub_base = ioremap(addr, pci_resource_len(pdev, GPIO_BAR)); + +	prop = of_get_property(pdev->dev.of_node, "intel,muxctl", &len); +	if (prop && len == 4) { +		mux_val = of_read_number(prop, 1); +		writel(mux_val, sd->gpio_pub_base + GPMUXCTL); +	} + +	ret = bgpio_init(&sd->bgpio, &pdev->dev, 4, +			sd->gpio_pub_base + GPINR, sd->gpio_pub_base + GPOUTR, +			NULL, sd->gpio_pub_base + GPOER, NULL, false); +	if (ret) +		goto unmap; +	sd->bgpio.gc.ngpio = SDV_NUM_PUB_GPIOS; + +	ret = gpiochip_add(&sd->bgpio.gc); +	if (ret < 0) { +		dev_err(&pdev->dev, "gpiochip_add() failed.\n"); +		goto unmap; +	} + +	ret = sdv_register_irqsupport(sd, pdev); +	if (ret) +		goto unmap; + +	pci_set_drvdata(pdev, sd); +	dev_info(&pdev->dev, "Sodaville GPIO driver registered.\n"); +	return 0; + +unmap: +	iounmap(sd->gpio_pub_base); +release_reg: +	pci_release_region(pdev, GPIO_BAR); +disable_pci: +	pci_disable_device(pdev); +done: +	kfree(sd); +	return ret; +} + +static void sdv_gpio_remove(struct pci_dev *pdev) +{ +	struct sdv_gpio_chip_data *sd = pci_get_drvdata(pdev); + +	irq_domain_del(&sd->id); +	free_irq(pdev->irq, sd); +	irq_free_descs(sd->irq_base, SDV_NUM_PUB_GPIOS); + +	if (gpiochip_remove(&sd->bgpio.gc)) +		dev_err(&pdev->dev, "gpiochip_remove() failed.\n"); + +	pci_release_region(pdev, GPIO_BAR); +	iounmap(sd->gpio_pub_base); +	pci_disable_device(pdev); +	kfree(sd); +} + +static struct pci_device_id sdv_gpio_pci_ids[] __devinitdata = { +	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_SDV_GPIO) }, +	{ 0, }, +}; + +static struct pci_driver sdv_gpio_driver = { +	.name = DRV_NAME, +	.id_table = sdv_gpio_pci_ids, +	.probe = sdv_gpio_probe, +	.remove = sdv_gpio_remove, +}; + +static int __init sdv_gpio_init(void) +{ +	return pci_register_driver(&sdv_gpio_driver); +} +module_init(sdv_gpio_init); + +static void __exit sdv_gpio_exit(void) +{ +	pci_unregister_driver(&sdv_gpio_driver); +} +module_exit(sdv_gpio_exit); + +MODULE_AUTHOR("Hans J. Koch <hjk@linutronix.de>"); +MODULE_DESCRIPTION("GPIO interface for Intel Sodaville SoCs"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c index 91f45b965d1..7eef648a335 100644 --- a/drivers/gpio/gpio-tps65910.c +++ b/drivers/gpio/gpio-tps65910.c @@ -69,6 +69,7 @@ static int tps65910_gpio_input(struct gpio_chip *gc, unsigned offset)  void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base)  {  	int ret; +	struct tps65910_board *board_data;  	if (!gpio_base)  		return; @@ -80,10 +81,10 @@ void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base)  	switch(tps65910_chip_id(tps65910)) {  	case TPS65910: -		tps65910->gpio.ngpio	= 6; +		tps65910->gpio.ngpio	= TPS65910_NUM_GPIO;  		break;  	case TPS65911: -		tps65910->gpio.ngpio	= 9; +		tps65910->gpio.ngpio	= TPS65911_NUM_GPIO;  		break;  	default:  		return; @@ -95,6 +96,21 @@ void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base)  	tps65910->gpio.set		= tps65910_gpio_set;  	tps65910->gpio.get		= tps65910_gpio_get; +	/* Configure sleep control for gpios */ +	board_data = dev_get_platdata(tps65910->dev); +	if (board_data) { +		int i; +		for (i = 0; i < tps65910->gpio.ngpio; ++i) { +			if (board_data->en_gpio_sleep[i]) { +				ret = tps65910_set_bits(tps65910, +					TPS65910_GPIO0 + i, GPIO_SLEEP_MASK); +				if (ret < 0) +					dev_warn(tps65910->dev, +						"GPIO Sleep setting failed\n"); +			} +		} +	} +  	ret = gpiochip_add(&tps65910->gpio);  	if (ret) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 17fdf4b6af9..d77354068b9 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -873,6 +873,7 @@ void gpio_unexport(unsigned gpio)  {  	struct gpio_desc	*desc;  	int			status = 0; +	struct device		*dev = NULL;  	if (!gpio_is_valid(gpio)) {  		status = -EINVAL; @@ -884,19 +885,20 @@ void gpio_unexport(unsigned gpio)  	desc = &gpio_desc[gpio];  	if (test_bit(FLAG_EXPORT, &desc->flags)) { -		struct device	*dev = NULL;  		dev = class_find_device(&gpio_class, NULL, desc, match_export);  		if (dev) {  			gpio_setup_irq(desc, dev, 0);  			clear_bit(FLAG_EXPORT, &desc->flags); -			put_device(dev); -			device_unregister(dev);  		} else  			status = -ENODEV;  	}  	mutex_unlock(&sysfs_lock); +	if (dev) { +		device_unregister(dev); +		put_device(dev); +	}  done:  	if (status)  		pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c index 7e62d15d60f..e034b38590a 100644 --- a/drivers/of/gpio.c +++ b/drivers/of/gpio.c @@ -78,8 +78,9 @@ err0:  EXPORT_SYMBOL(of_get_named_gpio_flags);  /** - * of_gpio_count - Count GPIOs for a device + * of_gpio_named_count - Count GPIOs for a device   * @np:		device node to count GPIOs for + * @propname:	property name containing gpio specifier(s)   *   * The function returns the count of GPIOs specified for a node.   * @@ -93,14 +94,14 @@ EXPORT_SYMBOL(of_get_named_gpio_flags);   * defines four GPIOs (so this function will return 4), two of which   * are not specified.   */ -unsigned int of_gpio_count(struct device_node *np) +unsigned int of_gpio_named_count(struct device_node *np, const char* propname)  {  	unsigned int cnt = 0;  	do {  		int ret; -		ret = of_parse_phandle_with_args(np, "gpios", "#gpio-cells", +		ret = of_parse_phandle_with_args(np, propname, "#gpio-cells",  						 cnt, NULL);  		/* A hole in the gpios = <> counts anyway. */  		if (ret < 0 && ret != -EEXIST) @@ -109,7 +110,7 @@ unsigned int of_gpio_count(struct device_node *np)  	return cnt;  } -EXPORT_SYMBOL(of_gpio_count); +EXPORT_SYMBOL(of_gpio_named_count);  /**   * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags diff --git a/include/linux/mfd/tps65910.h b/include/linux/mfd/tps65910.h index d0cb12eba40..9071902bd22 100644 --- a/include/linux/mfd/tps65910.h +++ b/include/linux/mfd/tps65910.h @@ -657,6 +657,8 @@  /*Register GPIO  (0x80) register.RegisterDescription */ +#define GPIO_SLEEP_MASK                         0x80 +#define GPIO_SLEEP_SHIFT                        7  #define GPIO_DEB_MASK                           0x10  #define GPIO_DEB_SHIFT                          4  #define GPIO_PUEN_MASK                          0x08 @@ -740,6 +742,11 @@  #define TPS65910_GPIO_STS				BIT(1)  #define TPS65910_GPIO_SET				BIT(0) +/* Max number of TPS65910/11 GPIOs */ +#define TPS65910_NUM_GPIO				6 +#define TPS65911_NUM_GPIO				9 +#define TPS6591X_MAX_NUM_GPIO				9 +  /* Regulator Index Definitions */  #define TPS65910_REG_VRTC				0  #define TPS65910_REG_VIO				1 @@ -779,6 +786,7 @@ struct tps65910_board {  	int irq_base;  	int vmbch_threshold;  	int vmbch2_threshold; +	bool en_gpio_sleep[TPS6591X_MAX_NUM_GPIO];  	struct regulator_init_data *tps65910_pmic_init_data[TPS65910_NUM_REGS];  }; diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h index b254052a49d..81733d12cbe 100644 --- a/include/linux/of_gpio.h +++ b/include/linux/of_gpio.h @@ -50,7 +50,8 @@ static inline struct of_mm_gpio_chip *to_of_mm_gpio_chip(struct gpio_chip *gc)  extern int of_get_named_gpio_flags(struct device_node *np,  		const char *list_name, int index, enum of_gpio_flags *flags); -extern unsigned int of_gpio_count(struct device_node *np); +extern unsigned int of_gpio_named_count(struct device_node *np, +					const char* propname);  extern int of_mm_gpiochip_add(struct device_node *np,  			      struct of_mm_gpio_chip *mm_gc); @@ -71,7 +72,8 @@ static inline int of_get_named_gpio_flags(struct device_node *np,  	return -ENOSYS;  } -static inline unsigned int of_gpio_count(struct device_node *np) +static inline unsigned int of_gpio_named_count(struct device_node *np, +					const char* propname)  {  	return 0;  } @@ -89,6 +91,27 @@ static inline void of_gpiochip_remove(struct gpio_chip *gc) { }  #endif /* CONFIG_OF_GPIO */  /** + * of_gpio_count - Count GPIOs for a device + * @np:		device node to count GPIOs for + * + * The function returns the count of GPIOs specified for a node. + * + * Note that the empty GPIO specifiers counts too. For example, + * + * gpios = <0 + *          &pio1 1 2 + *          0 + *          &pio2 3 4>; + * + * defines four GPIOs (so this function will return 4), two of which + * are not specified. + */ +static inline unsigned int of_gpio_count(struct device_node *np) +{ +	return of_gpio_named_count(np, "gpios"); +} + +/**   * of_get_gpio_flags() - Get a GPIO number and flags to use with GPIO API   * @np:		device node to get GPIO from   * @index:	index of the GPIO  |