This is the bulk of GPIO changes for the v3.18 development
cycle:
 
 - Increase the default ARCH_NR_GPIO from 256 to 512. This
   was done to avoid having a custom <asm/gpio.h> header for
   the x86 architecture - GPIO is custom and complicated
   enough as it is already! We want to move to a radix to
   store the descriptors going forward, and finally get rid
   of this fixed array size altogether.
 
 - Endgame patching of the gpio_remove() semantics initiated
   by Abdoulaye Berthe. It is not accepted by the system that
   the removal of a GPIO chip fails during e.g. reboot or
   shutdown, and therefore the return value has now painfully
   been refactored away. For special cases like GPIO expanders
   on a hot-pluggable bus like USB, we may later add some
   gpiochip_try_remove() call, but for the cases we have now,
   return values are moot.
 
 - Some incremental refactoring of the gpiolib core and ACPI
   GPIO library for more descriptor usage.
 
 - Refactor the chained IRQ handler set-up method to handle
   also threaded, nested interrupts and set up the parent IRQ
   correctly. Switch STMPE and TC3589x drivers to use this
   registration method.
 
 - Add a .irq_not_threaded flag to the struct gpio_chip, so
   that also GPIO expanders that block but are still not
   using threaded IRQ handlers.
 
 - New drivers for the ARM64 X-Gene SoC GPIO controller.
 
 - The syscon GPIO driver has been improved to handle the
   "DSP GPIO" found on the TI Keystone 2 SoC:s.
 
 - ADNP driver switched to use gpiolib irqchip helpers.
 
 - Refactor the DWAPB driver to support being instantiated
   from and MFD cell (platform device).
 
 - Incremental feature improvement in the Zynq, MCP23S08,
   DWAPB, OMAP, Xilinx and Crystalcove drivers.
 
 - Various minor fixes.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJUNOr0AAoJEEEQszewGV1z9toP/2ISXRnsi3+jlqVmEGm/y6EA
 PPwJOiYnOhZR2/fTCHIF0PNbIi9pw7xKnzxttYCu4uCz7geHX+FfTwUZ2/KWMfqi
 ZJ9kEoOVVKzKjmL/m2a2tO4IRSBHqJ8dF3yvaNjS3AL7EDfG6F5STErQurdLEynK
 SeJZ2OwM/vRFCac6F7oDlqAUTu3xYGbVD8+zI0H0V/ReocosFlEwcbl2S8ctDWUd
 h98M+gY+A8rxkvVMnmQ/k7rUTme/glDQ3z5xVx+uHbS2/a5M1jSM/71cXE6YnSrR
 it0CK7CHomq2RzHsKf7oH7GD4kFkukMwFKeMoqz75JWz3352VZPTF53chCIqRSgO
 hrgGwZ7WF6pUUUhsn1ZdZsnBPA2Fou2uwslyLSAiE+OYEH2/NSVIOUcorjQcWqU/
 0Kix5yb8X1ZzRMhR+TVrTD5V0jguqp2buXq+0P2XlU6MoO2vy7iNf2eXvPg8sF8C
 anjTCKgmkzy7eyT2uzfDaNZAyfSBKb1TiKiR9zA0SRChJkCi1ErJEXDGeHiptvSA
 +D2k68Ils2LqsvdrnEd2XvVFMllh0iq7b+16o7D+Els0WRbnHpfYCaqfOuF5F4U0
 SmeyI0ruawNDc5e9EBKXstt0/R9AMOetyTcTu29U2ZVo90zGaT1ofT8+R1jJ0kGa
 bPARJZrgecgv1E9Qnnnd
 =8InA
 -----END PGP SIGNATURE-----
Merge tag 'gpio-v3.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio
Pull GPIO changes from Linus Walleij:
 "This is the bulk of GPIO changes for the v3.18 development cycle:
   - Increase the default ARCH_NR_GPIO from 256 to 512.  This was done
     to avoid having a custom <asm/gpio.h> header for the x86
     architecture - GPIO is custom and complicated enough as it is
     already! We want to move to a radix to store the descriptors going
     forward, and finally get rid of this fixed array size altogether.
   - Endgame patching of the gpio_remove() semantics initiated by
     Abdoulaye Berthe.  It is not accepted by the system that the
     removal of a GPIO chip fails during eg reboot or shutdown, and
     therefore the return value has now painfully been refactored away.
     For special cases like GPIO expanders on a hot-pluggable bus like
     USB, we may later add some gpiochip_try_remove() call, but for the
     cases we have now, return values are moot.
   - Some incremental refactoring of the gpiolib core and ACPI GPIO
     library for more descriptor usage.
   - Refactor the chained IRQ handler set-up method to handle also
     threaded, nested interrupts and set up the parent IRQ correctly.
     Switch STMPE and TC3589x drivers to use this registration method.
   - Add a .irq_not_threaded flag to the struct gpio_chip, so that also
     GPIO expanders that block but are still not using threaded IRQ
     handlers.
   - New drivers for the ARM64 X-Gene SoC GPIO controller.
   - The syscon GPIO driver has been improved to handle the "DSP GPIO"
     found on the TI Keystone 2 SoC:s.
   - ADNP driver switched to use gpiolib irqchip helpers.
   - Refactor the DWAPB driver to support being instantiated from and
     MFD cell (platform device).
   - Incremental feature improvement in the Zynq, MCP23S08, DWAPB, OMAP,
     Xilinx and Crystalcove drivers.
   - Various minor fixes"
* tag 'gpio-v3.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (52 commits)
  gpio: pch: Build context save/restore only for PM
  pinctrl: abx500: get rid of unused variable
  gpio: ks8695: fix 'else should follow close brace '}''
  gpio: stmpe: add verbose debug code
  gpio: stmpe: fix up interrupt enable logic
  gpio: staticize xway_stp_init()
  gpio: handle also nested irqchips in the chained handler set-up
  gpio: set parent irq on chained handlers
  gpiolib: irqchip: use irq_find_mapping while removing irqchip
  gpio: crystalcove: support virtual GPIO
  pinctrl: bcm281xx: make Kconfig dependency more strict
  gpio: kona: enable only on BCM_MOBILE or for compile testing
  gpio, bcm-kona, LLVMLinux: Remove use of __initconst
  gpio: Fix ngpio in gpio-xilinx driver
  gpio: dwapb: fix pointer to integer cast
  gpio: xgene: Remove unneeded #ifdef CONFIG_OF guard
  gpio: xgene: Remove unneeded forward declation for struct xgene_gpio
  gpio: xgene: Fix missing spin_lock_init()
  gpio: ks8695: fix switch case indentation
  gpiolib: add irq_not_threaded flag to gpio_chip
  ...
	
	
This commit is contained in:
		
				commit
				
					
						ea584595fc
					
				
			
		
					 65 changed files with 1297 additions and 659 deletions
				
			
		
							
								
								
									
										39
									
								
								Documentation/devicetree/bindings/gpio/gpio-dsp-keystone.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								Documentation/devicetree/bindings/gpio/gpio-dsp-keystone.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,39 @@
 | 
			
		|||
Keystone 2 DSP GPIO controller bindings
 | 
			
		||||
 | 
			
		||||
HOST OS userland running on ARM can send interrupts to DSP cores using
 | 
			
		||||
the DSP GPIO controller IP. It provides 28 IRQ signals per each DSP core.
 | 
			
		||||
This is one of the component used by the IPC mechanism used on Keystone SOCs.
 | 
			
		||||
 | 
			
		||||
For example TCI6638K2K SoC has 8 DSP GPIO controllers:
 | 
			
		||||
 - 8 for C66x CorePacx CPUs 0-7
 | 
			
		||||
 | 
			
		||||
Keystone 2 DSP GPIO controller has specific features:
 | 
			
		||||
- each GPIO can be configured only as output pin;
 | 
			
		||||
- setting GPIO value to 1 causes IRQ generation on target DSP core;
 | 
			
		||||
- reading pin value returns 0 - if IRQ was handled or 1 - IRQ is still
 | 
			
		||||
  pending.
 | 
			
		||||
 | 
			
		||||
Required Properties:
 | 
			
		||||
- compatible: should be "ti,keystone-dsp-gpio"
 | 
			
		||||
- ti,syscon-dev: phandle/offset pair. The phandle to syscon used to
 | 
			
		||||
  access device state control registers and the offset of device's specific
 | 
			
		||||
  registers within device state control registers range.
 | 
			
		||||
- gpio-controller: Marks the device node as a gpio controller.
 | 
			
		||||
- #gpio-cells: Should be 2.
 | 
			
		||||
 | 
			
		||||
Please refer to gpio.txt in this directory for details of the common GPIO
 | 
			
		||||
bindings used by client devices.
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
	dspgpio0: keystone_dsp_gpio@02620240 {
 | 
			
		||||
		compatible = "ti,keystone-dsp-gpio";
 | 
			
		||||
		ti,syscon-dev = <&devctrl 0x240>;
 | 
			
		||||
		gpio-controller;
 | 
			
		||||
		#gpio-cells = <2>;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	dsp0: dsp0 {
 | 
			
		||||
		compatible = "linux,rproc-user";
 | 
			
		||||
		...
 | 
			
		||||
		kick-gpio = <&dspgpio0 27>;
 | 
			
		||||
	};
 | 
			
		||||
							
								
								
									
										39
									
								
								Documentation/devicetree/bindings/gpio/gpio-pca953x.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								Documentation/devicetree/bindings/gpio/gpio-pca953x.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,39 @@
 | 
			
		|||
* NXP PCA953x I2C GPIO multiplexer
 | 
			
		||||
 | 
			
		||||
Required properties:
 | 
			
		||||
 - compatible: Has to contain one of the following:
 | 
			
		||||
	nxp,pca9505
 | 
			
		||||
	nxp,pca9534
 | 
			
		||||
	nxp,pca9535
 | 
			
		||||
	nxp,pca9536
 | 
			
		||||
	nxp,pca9537
 | 
			
		||||
	nxp,pca9538
 | 
			
		||||
	nxp,pca9539
 | 
			
		||||
	nxp,pca9554
 | 
			
		||||
	nxp,pca9555
 | 
			
		||||
	nxp,pca9556
 | 
			
		||||
	nxp,pca9557
 | 
			
		||||
	nxp,pca9574
 | 
			
		||||
	nxp,pca9575
 | 
			
		||||
	nxp,pca9698
 | 
			
		||||
	maxim,max7310
 | 
			
		||||
	maxim,max7312
 | 
			
		||||
	maxim,max7313
 | 
			
		||||
	maxim,max7315
 | 
			
		||||
	ti,pca6107
 | 
			
		||||
	ti,tca6408
 | 
			
		||||
	ti,tca6416
 | 
			
		||||
	ti,tca6424
 | 
			
		||||
	exar,xra1202
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	gpio@20 {
 | 
			
		||||
		compatible = "nxp,pca9505";
 | 
			
		||||
		reg = <0x20>;
 | 
			
		||||
		pinctrl-names = "default";
 | 
			
		||||
		pinctrl-0 = <&pinctrl_pca9505>;
 | 
			
		||||
		interrupt-parent = <&gpio3>;
 | 
			
		||||
		interrupts = <23 IRQ_TYPE_LEVEL_LOW>;
 | 
			
		||||
	};
 | 
			
		||||
							
								
								
									
										22
									
								
								Documentation/devicetree/bindings/gpio/gpio-xgene.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								Documentation/devicetree/bindings/gpio/gpio-xgene.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
APM X-Gene SoC GPIO controller bindings
 | 
			
		||||
 | 
			
		||||
This is a gpio controller that is part of the flash controller.
 | 
			
		||||
This gpio controller controls a total of 48 gpios.
 | 
			
		||||
 | 
			
		||||
Required properties:
 | 
			
		||||
- compatible: "apm,xgene-gpio" for X-Gene GPIO controller
 | 
			
		||||
- reg: Physical base address and size of the controller's registers
 | 
			
		||||
- #gpio-cells: Should be two.
 | 
			
		||||
	- first cell is the pin number
 | 
			
		||||
	- second cell is used to specify the gpio polarity:
 | 
			
		||||
		0 = active high
 | 
			
		||||
		1 = active low
 | 
			
		||||
- gpio-controller: Marks the device node as a GPIO controller.
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
	gpio0: gpio0@1701c000 {
 | 
			
		||||
		compatible = "apm,xgene-gpio";
 | 
			
		||||
		reg = <0x0 0x1701c000 0x0 0x40>;
 | 
			
		||||
		gpio-controller;
 | 
			
		||||
		#gpio-cells = <2>;
 | 
			
		||||
	};
 | 
			
		||||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ Required properties:
 | 
			
		|||
- gpio-controller : Marks the device node as a gpio controller.
 | 
			
		||||
- #gpio-cells : Should be one.  It is the pin number.
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
Example for a MMP platform:
 | 
			
		||||
 | 
			
		||||
	gpio: gpio@d4019000 {
 | 
			
		||||
		compatible = "marvell,mmp-gpio";
 | 
			
		||||
| 
						 | 
				
			
			@ -32,6 +32,19 @@ Example:
 | 
			
		|||
		#interrupt-cells = <1>;
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
Example for a PXA3xx platform:
 | 
			
		||||
 | 
			
		||||
	gpio: gpio@40e00000 {
 | 
			
		||||
		compatible = "intel,pxa3xx-gpio";
 | 
			
		||||
		reg = <0x40e00000 0x10000>;
 | 
			
		||||
		interrupt-names = "gpio0", "gpio1", "gpio_mux";
 | 
			
		||||
		interrupts = <8 9 10>;
 | 
			
		||||
		gpio-controller;
 | 
			
		||||
		#gpio-cells = <0x2>;
 | 
			
		||||
		interrupt-controller;
 | 
			
		||||
		#interrupt-cells = <0x2>;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
* Marvell Orion GPIO Controller
 | 
			
		||||
 | 
			
		||||
Required properties:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -124,7 +124,8 @@ symbol:
 | 
			
		|||
* gpiochip_set_chained_irqchip(): sets up a chained irq handler for a
 | 
			
		||||
  gpio_chip from a parent IRQ and passes the struct gpio_chip* as handler
 | 
			
		||||
  data. (Notice handler data, since the irqchip data is likely used by the
 | 
			
		||||
  parent irqchip!) This is for the chained type of chip.
 | 
			
		||||
  parent irqchip!) This is for the chained type of chip. This is also used
 | 
			
		||||
  to set up a nested irqchip if NULL is passed as handler.
 | 
			
		||||
 | 
			
		||||
To use the helpers please keep the following in mind:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -178,7 +179,8 @@ does not help since it pins the module to the kernel forever (it calls
 | 
			
		|||
try_module_get()). A GPIO driver can use the following functions instead
 | 
			
		||||
to request and free descriptors without being pinned to the kernel forever.
 | 
			
		||||
 | 
			
		||||
	int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label)
 | 
			
		||||
	struct gpio_desc *gpiochip_request_own_desc(struct gpio_desc *desc,
 | 
			
		||||
						    const char *label)
 | 
			
		||||
 | 
			
		||||
	void gpiochip_free_own_desc(struct gpio_desc *desc)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -243,18 +243,12 @@ err_ioremap:
 | 
			
		|||
static int scoop_remove(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct scoop_dev *sdev = platform_get_drvdata(pdev);
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (!sdev)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	if (sdev->gpio.base != -1) {
 | 
			
		||||
		ret = gpiochip_remove(&sdev->gpio);
 | 
			
		||||
		if (ret) {
 | 
			
		||||
			dev_err(&pdev->dev, "Can't remove gpio chip: %d\n", ret);
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (sdev->gpio.base != -1)
 | 
			
		||||
		gpiochip_remove(&sdev->gpio);
 | 
			
		||||
 | 
			
		||||
	platform_set_drvdata(pdev, NULL);
 | 
			
		||||
	iounmap(sdev->base);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -789,11 +789,11 @@ void __init txx9_iocled_init(unsigned long baseaddr,
 | 
			
		|||
	if (platform_device_add(pdev))
 | 
			
		||||
		goto out_pdev;
 | 
			
		||||
	return;
 | 
			
		||||
 | 
			
		||||
out_pdev:
 | 
			
		||||
	platform_device_put(pdev);
 | 
			
		||||
out_gpio:
 | 
			
		||||
	if (gpiochip_remove(&iocled->chip))
 | 
			
		||||
		return;
 | 
			
		||||
	gpiochip_remove(&iocled->chip);
 | 
			
		||||
out_unmap:
 | 
			
		||||
	iounmap(iocled->mmioaddr);
 | 
			
		||||
out_free:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -141,7 +141,8 @@ static int mcu_gpiochip_add(struct mcu *mcu)
 | 
			
		|||
 | 
			
		||||
static int mcu_gpiochip_remove(struct mcu *mcu)
 | 
			
		||||
{
 | 
			
		||||
	return gpiochip_remove(&mcu->gc);
 | 
			
		||||
	gpiochip_remove(&mcu->gc);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int mcu_probe(struct i2c_client *client, const struct i2c_device_id *id)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -128,10 +128,8 @@ int __init x3proto_gpio_setup(void)
 | 
			
		|||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_irq:
 | 
			
		||||
	ret = gpiochip_remove(&x3proto_gpio_chip);
 | 
			
		||||
	if (unlikely(ret))
 | 
			
		||||
		pr_err("Failed deregistering GPIO\n");
 | 
			
		||||
 | 
			
		||||
	gpiochip_remove(&x3proto_gpio_chip);
 | 
			
		||||
	ret = 0;
 | 
			
		||||
err_gpio:
 | 
			
		||||
	synchronize_irq(ilsel);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -255,5 +255,6 @@ int bcma_gpio_init(struct bcma_drv_cc *cc)
 | 
			
		|||
int bcma_gpio_unregister(struct bcma_drv_cc *cc)
 | 
			
		||||
{
 | 
			
		||||
	bcma_gpio_irq_domain_exit(cc);
 | 
			
		||||
	return gpiochip_remove(&cc->gpio);
 | 
			
		||||
	gpiochip_remove(&cc->gpio);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -136,7 +136,6 @@ config GPIO_DWAPB
 | 
			
		|||
	tristate "Synopsys DesignWare APB GPIO driver"
 | 
			
		||||
	select GPIO_GENERIC
 | 
			
		||||
	select GENERIC_IRQ_CHIP
 | 
			
		||||
	depends on OF_GPIO
 | 
			
		||||
	help
 | 
			
		||||
	  Say Y or M here to build support for the Synopsys DesignWare APB
 | 
			
		||||
	  GPIO block.
 | 
			
		||||
| 
						 | 
				
			
			@ -334,6 +333,15 @@ config GPIO_TZ1090_PDC
 | 
			
		|||
	help
 | 
			
		||||
	  Say yes here to support Toumaz Xenif TZ1090 PDC GPIOs.
 | 
			
		||||
 | 
			
		||||
config GPIO_XGENE
 | 
			
		||||
	bool "APM X-Gene GPIO controller support"
 | 
			
		||||
	depends on ARM64 && OF_GPIO
 | 
			
		||||
	help
 | 
			
		||||
	  This driver is to support the GPIO block within the APM X-Gene SoC
 | 
			
		||||
	  platform's generic flash controller. The GPIO pins are muxed with
 | 
			
		||||
	  the generic flash controller's address and data pins. Say yes
 | 
			
		||||
	  here to enable the GFC GPIO functionality.
 | 
			
		||||
 | 
			
		||||
config GPIO_XILINX
 | 
			
		||||
	bool "Xilinx GPIO support"
 | 
			
		||||
	depends on PPC_OF || MICROBLAZE || ARCH_ZYNQ
 | 
			
		||||
| 
						 | 
				
			
			@ -681,6 +689,7 @@ config GPIO_ADP5588_IRQ
 | 
			
		|||
config GPIO_ADNP
 | 
			
		||||
	tristate "Avionic Design N-bit GPIO expander"
 | 
			
		||||
	depends on I2C && OF_GPIO
 | 
			
		||||
	select GPIOLIB_IRQCHIP
 | 
			
		||||
	help
 | 
			
		||||
	  This option enables support for N GPIOs found on Avionic Design
 | 
			
		||||
	  I2C GPIO expanders. The register space will be extended by powers
 | 
			
		||||
| 
						 | 
				
			
			@ -796,7 +805,6 @@ config GPIO_MAX7301
 | 
			
		|||
 | 
			
		||||
config GPIO_MCP23S08
 | 
			
		||||
	tristate "Microchip MCP23xxx I/O expander"
 | 
			
		||||
	depends on OF_GPIO
 | 
			
		||||
	depends on (SPI_MASTER && !I2C) || I2C
 | 
			
		||||
	help
 | 
			
		||||
	  SPI/I2C driver for Microchip MCP23S08/MCP23S17/MCP23008/MCP23017
 | 
			
		||||
| 
						 | 
				
			
			@ -880,7 +888,7 @@ config GPIO_MSIC
 | 
			
		|||
 | 
			
		||||
config GPIO_BCM_KONA
 | 
			
		||||
	bool "Broadcom Kona GPIO"
 | 
			
		||||
	depends on OF_GPIO
 | 
			
		||||
	depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST)
 | 
			
		||||
	help
 | 
			
		||||
	  Turn on GPIO support for Broadcom "Kona" chips.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -101,6 +101,7 @@ obj-$(CONFIG_GPIO_VX855)	+= gpio-vx855.o
 | 
			
		|||
obj-$(CONFIG_GPIO_WM831X)	+= gpio-wm831x.o
 | 
			
		||||
obj-$(CONFIG_GPIO_WM8350)	+= gpio-wm8350.o
 | 
			
		||||
obj-$(CONFIG_GPIO_WM8994)	+= gpio-wm8994.o
 | 
			
		||||
obj-$(CONFIG_GPIO_XGENE)	+= gpio-xgene.o
 | 
			
		||||
obj-$(CONFIG_GPIO_XILINX)	+= gpio-xilinx.o
 | 
			
		||||
obj-$(CONFIG_GPIO_XTENSA)	+= gpio-xtensa.o
 | 
			
		||||
obj-$(CONFIG_GPIO_ZEVIO)	+= gpio-zevio.o
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,10 +6,9 @@
 | 
			
		|||
 * published by the Free Software Foundation.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/gpio.h>
 | 
			
		||||
#include <linux/gpio/driver.h>
 | 
			
		||||
#include <linux/i2c.h>
 | 
			
		||||
#include <linux/interrupt.h>
 | 
			
		||||
#include <linux/irqdomain.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <linux/of_irq.h>
 | 
			
		||||
#include <linux/seq_file.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -27,8 +26,6 @@ struct adnp {
 | 
			
		|||
	unsigned int reg_shift;
 | 
			
		||||
 | 
			
		||||
	struct mutex i2c_lock;
 | 
			
		||||
 | 
			
		||||
	struct irq_domain *domain;
 | 
			
		||||
	struct mutex irq_lock;
 | 
			
		||||
 | 
			
		||||
	u8 *irq_enable;
 | 
			
		||||
| 
						 | 
				
			
			@ -253,6 +250,7 @@ static void adnp_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 | 
			
		|||
static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios)
 | 
			
		||||
{
 | 
			
		||||
	struct gpio_chip *chip = &adnp->gpio;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	adnp->reg_shift = get_count_order(num_gpios) - 3;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -272,6 +270,10 @@ static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios)
 | 
			
		|||
	chip->of_node = chip->dev->of_node;
 | 
			
		||||
	chip->owner = THIS_MODULE;
 | 
			
		||||
 | 
			
		||||
	err = gpiochip_add(chip);
 | 
			
		||||
	if (err)
 | 
			
		||||
		return err;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -326,7 +328,8 @@ static irqreturn_t adnp_irq(int irq, void *data)
 | 
			
		|||
 | 
			
		||||
		for_each_set_bit(bit, &pending, 8) {
 | 
			
		||||
			unsigned int child_irq;
 | 
			
		||||
			child_irq = irq_find_mapping(adnp->domain, base + bit);
 | 
			
		||||
			child_irq = irq_find_mapping(adnp->gpio.irqdomain,
 | 
			
		||||
						     base + bit);
 | 
			
		||||
			handle_nested_irq(child_irq);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -334,35 +337,32 @@ static irqreturn_t adnp_irq(int irq, void *data)
 | 
			
		|||
	return IRQ_HANDLED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int adnp_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 | 
			
		||||
static void adnp_irq_mask(struct irq_data *d)
 | 
			
		||||
{
 | 
			
		||||
	struct adnp *adnp = to_adnp(chip);
 | 
			
		||||
	return irq_create_mapping(adnp->domain, offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void adnp_irq_mask(struct irq_data *data)
 | 
			
		||||
{
 | 
			
		||||
	struct adnp *adnp = irq_data_get_irq_chip_data(data);
 | 
			
		||||
	unsigned int reg = data->hwirq >> adnp->reg_shift;
 | 
			
		||||
	unsigned int pos = data->hwirq & 7;
 | 
			
		||||
	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 | 
			
		||||
	struct adnp *adnp = to_adnp(gc);
 | 
			
		||||
	unsigned int reg = d->hwirq >> adnp->reg_shift;
 | 
			
		||||
	unsigned int pos = d->hwirq & 7;
 | 
			
		||||
 | 
			
		||||
	adnp->irq_enable[reg] &= ~BIT(pos);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void adnp_irq_unmask(struct irq_data *data)
 | 
			
		||||
static void adnp_irq_unmask(struct irq_data *d)
 | 
			
		||||
{
 | 
			
		||||
	struct adnp *adnp = irq_data_get_irq_chip_data(data);
 | 
			
		||||
	unsigned int reg = data->hwirq >> adnp->reg_shift;
 | 
			
		||||
	unsigned int pos = data->hwirq & 7;
 | 
			
		||||
	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 | 
			
		||||
	struct adnp *adnp = to_adnp(gc);
 | 
			
		||||
	unsigned int reg = d->hwirq >> adnp->reg_shift;
 | 
			
		||||
	unsigned int pos = d->hwirq & 7;
 | 
			
		||||
 | 
			
		||||
	adnp->irq_enable[reg] |= BIT(pos);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int adnp_irq_set_type(struct irq_data *data, unsigned int type)
 | 
			
		||||
static int adnp_irq_set_type(struct irq_data *d, unsigned int type)
 | 
			
		||||
{
 | 
			
		||||
	struct adnp *adnp = irq_data_get_irq_chip_data(data);
 | 
			
		||||
	unsigned int reg = data->hwirq >> adnp->reg_shift;
 | 
			
		||||
	unsigned int pos = data->hwirq & 7;
 | 
			
		||||
	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 | 
			
		||||
	struct adnp *adnp = to_adnp(gc);
 | 
			
		||||
	unsigned int reg = d->hwirq >> adnp->reg_shift;
 | 
			
		||||
	unsigned int pos = d->hwirq & 7;
 | 
			
		||||
 | 
			
		||||
	if (type & IRQ_TYPE_EDGE_RISING)
 | 
			
		||||
		adnp->irq_rise[reg] |= BIT(pos);
 | 
			
		||||
| 
						 | 
				
			
			@ -387,16 +387,18 @@ static int adnp_irq_set_type(struct irq_data *data, unsigned int type)
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void adnp_irq_bus_lock(struct irq_data *data)
 | 
			
		||||
static void adnp_irq_bus_lock(struct irq_data *d)
 | 
			
		||||
{
 | 
			
		||||
	struct adnp *adnp = irq_data_get_irq_chip_data(data);
 | 
			
		||||
	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 | 
			
		||||
	struct adnp *adnp = to_adnp(gc);
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&adnp->irq_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void adnp_irq_bus_unlock(struct irq_data *data)
 | 
			
		||||
static void adnp_irq_bus_unlock(struct irq_data *d)
 | 
			
		||||
{
 | 
			
		||||
	struct adnp *adnp = irq_data_get_irq_chip_data(data);
 | 
			
		||||
	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 | 
			
		||||
	struct adnp *adnp = to_adnp(gc);
 | 
			
		||||
	unsigned int num_regs = 1 << adnp->reg_shift, i;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&adnp->i2c_lock);
 | 
			
		||||
| 
						 | 
				
			
			@ -408,26 +410,6 @@ static void adnp_irq_bus_unlock(struct irq_data *data)
 | 
			
		|||
	mutex_unlock(&adnp->irq_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int adnp_irq_reqres(struct irq_data *data)
 | 
			
		||||
{
 | 
			
		||||
	struct adnp *adnp = irq_data_get_irq_chip_data(data);
 | 
			
		||||
 | 
			
		||||
	if (gpio_lock_as_irq(&adnp->gpio, data->hwirq)) {
 | 
			
		||||
		dev_err(adnp->gpio.dev,
 | 
			
		||||
			"unable to lock HW IRQ %lu for IRQ\n",
 | 
			
		||||
			data->hwirq);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void adnp_irq_relres(struct irq_data *data)
 | 
			
		||||
{
 | 
			
		||||
	struct adnp *adnp = irq_data_get_irq_chip_data(data);
 | 
			
		||||
 | 
			
		||||
	gpio_unlock_as_irq(&adnp->gpio, data->hwirq);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct irq_chip adnp_irq_chip = {
 | 
			
		||||
	.name = "gpio-adnp",
 | 
			
		||||
	.irq_mask = adnp_irq_mask,
 | 
			
		||||
| 
						 | 
				
			
			@ -435,29 +417,6 @@ static struct irq_chip adnp_irq_chip = {
 | 
			
		|||
	.irq_set_type = adnp_irq_set_type,
 | 
			
		||||
	.irq_bus_lock = adnp_irq_bus_lock,
 | 
			
		||||
	.irq_bus_sync_unlock = adnp_irq_bus_unlock,
 | 
			
		||||
	.irq_request_resources = adnp_irq_reqres,
 | 
			
		||||
	.irq_release_resources = adnp_irq_relres,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int adnp_irq_map(struct irq_domain *domain, unsigned int irq,
 | 
			
		||||
			irq_hw_number_t hwirq)
 | 
			
		||||
{
 | 
			
		||||
	irq_set_chip_data(irq, domain->host_data);
 | 
			
		||||
	irq_set_chip(irq, &adnp_irq_chip);
 | 
			
		||||
	irq_set_nested_thread(irq, true);
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_ARM
 | 
			
		||||
	set_irq_flags(irq, IRQF_VALID);
 | 
			
		||||
#else
 | 
			
		||||
	irq_set_noprobe(irq);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct irq_domain_ops adnp_irq_domain_ops = {
 | 
			
		||||
	.map = adnp_irq_map,
 | 
			
		||||
	.xlate = irq_domain_xlate_twocell,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int adnp_irq_setup(struct adnp *adnp)
 | 
			
		||||
| 
						 | 
				
			
			@ -503,10 +462,8 @@ static int adnp_irq_setup(struct adnp *adnp)
 | 
			
		|||
		adnp->irq_enable[i] = 0x00;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	adnp->domain = irq_domain_add_linear(chip->of_node, chip->ngpio,
 | 
			
		||||
					     &adnp_irq_domain_ops, adnp);
 | 
			
		||||
 | 
			
		||||
	err = request_threaded_irq(adnp->client->irq, NULL, adnp_irq,
 | 
			
		||||
	err = devm_request_threaded_irq(chip->dev, adnp->client->irq,
 | 
			
		||||
					NULL, adnp_irq,
 | 
			
		||||
					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
 | 
			
		||||
					dev_name(chip->dev), adnp);
 | 
			
		||||
	if (err != 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -515,25 +472,20 @@ static int adnp_irq_setup(struct adnp *adnp)
 | 
			
		|||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	chip->to_irq = adnp_gpio_to_irq;
 | 
			
		||||
	err = gpiochip_irqchip_add(chip,
 | 
			
		||||
				   &adnp_irq_chip,
 | 
			
		||||
				   0,
 | 
			
		||||
				   handle_simple_irq,
 | 
			
		||||
				   IRQ_TYPE_NONE);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		dev_err(chip->dev,
 | 
			
		||||
			"could not connect irqchip to gpiochip\n");
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void adnp_irq_teardown(struct adnp *adnp)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int irq, i;
 | 
			
		||||
 | 
			
		||||
	free_irq(adnp->client->irq, adnp);
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < adnp->gpio.ngpio; i++) {
 | 
			
		||||
		irq = irq_find_mapping(adnp->domain, i);
 | 
			
		||||
		if (irq > 0)
 | 
			
		||||
			irq_dispose_mapping(irq);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	irq_domain_remove(adnp->domain);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int adnp_i2c_probe(struct i2c_client *client,
 | 
			
		||||
				    const struct i2c_device_id *id)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -558,38 +510,25 @@ static int adnp_i2c_probe(struct i2c_client *client,
 | 
			
		|||
	adnp->client = client;
 | 
			
		||||
 | 
			
		||||
	err = adnp_gpio_setup(adnp, num_gpios);
 | 
			
		||||
	if (err < 0)
 | 
			
		||||
	if (err)
 | 
			
		||||
		return err;
 | 
			
		||||
 | 
			
		||||
	if (of_find_property(np, "interrupt-controller", NULL)) {
 | 
			
		||||
		err = adnp_irq_setup(adnp);
 | 
			
		||||
		if (err < 0)
 | 
			
		||||
			goto teardown;
 | 
			
		||||
		if (err)
 | 
			
		||||
			return err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = gpiochip_add(&adnp->gpio);
 | 
			
		||||
	if (err < 0)
 | 
			
		||||
		goto teardown;
 | 
			
		||||
 | 
			
		||||
	i2c_set_clientdata(client, adnp);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
teardown:
 | 
			
		||||
	if (of_find_property(np, "interrupt-controller", NULL))
 | 
			
		||||
		adnp_irq_teardown(adnp);
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int adnp_i2c_remove(struct i2c_client *client)
 | 
			
		||||
{
 | 
			
		||||
	struct adnp *adnp = i2c_get_clientdata(client);
 | 
			
		||||
	struct device_node *np = client->dev.of_node;
 | 
			
		||||
 | 
			
		||||
	gpiochip_remove(&adnp->gpio);
 | 
			
		||||
	if (of_find_property(np, "interrupt-controller", NULL))
 | 
			
		||||
		adnp_irq_teardown(adnp);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -496,7 +496,7 @@ static struct irq_chip bcm_gpio_irq_chip = {
 | 
			
		|||
	.irq_release_resources = bcm_kona_gpio_irq_relres,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct __initconst of_device_id bcm_kona_gpio_of_match[] = {
 | 
			
		||||
static struct of_device_id const bcm_kona_gpio_of_match[] = {
 | 
			
		||||
	{ .compatible = "brcm,kona-gpio" },
 | 
			
		||||
	{}
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,6 +24,7 @@
 | 
			
		|||
#include <linux/mfd/intel_soc_pmic.h>
 | 
			
		||||
 | 
			
		||||
#define CRYSTALCOVE_GPIO_NUM	16
 | 
			
		||||
#define CRYSTALCOVE_VGPIO_NUM	94
 | 
			
		||||
 | 
			
		||||
#define UPDATE_IRQ_TYPE		BIT(0)
 | 
			
		||||
#define UPDATE_IRQ_MASK		BIT(1)
 | 
			
		||||
| 
						 | 
				
			
			@ -130,6 +131,9 @@ static int crystalcove_gpio_dir_in(struct gpio_chip *chip, unsigned gpio)
 | 
			
		|||
{
 | 
			
		||||
	struct crystalcove_gpio *cg = to_cg(chip);
 | 
			
		||||
 | 
			
		||||
	if (gpio > CRYSTALCOVE_VGPIO_NUM)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	return regmap_write(cg->regmap, to_reg(gpio, CTRL_OUT),
 | 
			
		||||
			    CTLO_INPUT_SET);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -139,6 +143,9 @@ static int crystalcove_gpio_dir_out(struct gpio_chip *chip, unsigned gpio,
 | 
			
		|||
{
 | 
			
		||||
	struct crystalcove_gpio *cg = to_cg(chip);
 | 
			
		||||
 | 
			
		||||
	if (gpio > CRYSTALCOVE_VGPIO_NUM)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	return regmap_write(cg->regmap, to_reg(gpio, CTRL_OUT),
 | 
			
		||||
			    CTLO_OUTPUT_SET | value);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -149,6 +156,9 @@ static int crystalcove_gpio_get(struct gpio_chip *chip, unsigned gpio)
 | 
			
		|||
	int ret;
 | 
			
		||||
	unsigned int val;
 | 
			
		||||
 | 
			
		||||
	if (gpio > CRYSTALCOVE_VGPIO_NUM)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	ret = regmap_read(cg->regmap, to_reg(gpio, CTRL_IN), &val);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -161,6 +171,9 @@ static void crystalcove_gpio_set(struct gpio_chip *chip,
 | 
			
		|||
{
 | 
			
		||||
	struct crystalcove_gpio *cg = to_cg(chip);
 | 
			
		||||
 | 
			
		||||
	if (gpio > CRYSTALCOVE_VGPIO_NUM)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (value)
 | 
			
		||||
		regmap_update_bits(cg->regmap, to_reg(gpio, CTRL_OUT), 1, 1);
 | 
			
		||||
	else
 | 
			
		||||
| 
						 | 
				
			
			@ -256,7 +269,7 @@ static irqreturn_t crystalcove_gpio_irq_handler(int irq, void *data)
 | 
			
		|||
 | 
			
		||||
	pending = p0 | p1 << 8;
 | 
			
		||||
 | 
			
		||||
	for (gpio = 0; gpio < cg->chip.ngpio; gpio++) {
 | 
			
		||||
	for (gpio = 0; gpio < CRYSTALCOVE_GPIO_NUM; gpio++) {
 | 
			
		||||
		if (pending & BIT(gpio)) {
 | 
			
		||||
			virq = irq_find_mapping(cg->chip.irqdomain, gpio);
 | 
			
		||||
			generic_handle_irq(virq);
 | 
			
		||||
| 
						 | 
				
			
			@ -273,7 +286,7 @@ static void crystalcove_gpio_dbg_show(struct seq_file *s,
 | 
			
		|||
	int gpio, offset;
 | 
			
		||||
	unsigned int ctlo, ctli, mirqs0, mirqsx, irq;
 | 
			
		||||
 | 
			
		||||
	for (gpio = 0; gpio < cg->chip.ngpio; gpio++) {
 | 
			
		||||
	for (gpio = 0; gpio < CRYSTALCOVE_GPIO_NUM; gpio++) {
 | 
			
		||||
		regmap_read(cg->regmap, to_reg(gpio, CTRL_OUT), &ctlo);
 | 
			
		||||
		regmap_read(cg->regmap, to_reg(gpio, CTRL_IN), &ctli);
 | 
			
		||||
		regmap_read(cg->regmap, gpio < 8 ? MGPIO0IRQS0 : MGPIO1IRQS0,
 | 
			
		||||
| 
						 | 
				
			
			@ -320,7 +333,7 @@ static int crystalcove_gpio_probe(struct platform_device *pdev)
 | 
			
		|||
	cg->chip.get = crystalcove_gpio_get;
 | 
			
		||||
	cg->chip.set = crystalcove_gpio_set;
 | 
			
		||||
	cg->chip.base = -1;
 | 
			
		||||
	cg->chip.ngpio = CRYSTALCOVE_GPIO_NUM;
 | 
			
		||||
	cg->chip.ngpio = CRYSTALCOVE_VGPIO_NUM;
 | 
			
		||||
	cg->chip.can_sleep = true;
 | 
			
		||||
	cg->chip.dev = dev;
 | 
			
		||||
	cg->chip.dbg_show = crystalcove_gpio_dbg_show;
 | 
			
		||||
| 
						 | 
				
			
			@ -346,7 +359,7 @@ static int crystalcove_gpio_probe(struct platform_device *pdev)
 | 
			
		|||
	return 0;
 | 
			
		||||
 | 
			
		||||
out_remove_gpio:
 | 
			
		||||
	WARN_ON(gpiochip_remove(&cg->chip));
 | 
			
		||||
	gpiochip_remove(&cg->chip);
 | 
			
		||||
	return retval;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -354,14 +367,11 @@ static int crystalcove_gpio_remove(struct platform_device *pdev)
 | 
			
		|||
{
 | 
			
		||||
	struct crystalcove_gpio *cg = platform_get_drvdata(pdev);
 | 
			
		||||
	int irq = platform_get_irq(pdev, 0);
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	err = gpiochip_remove(&cg->chip);
 | 
			
		||||
 | 
			
		||||
	gpiochip_remove(&cg->chip);
 | 
			
		||||
	if (irq >= 0)
 | 
			
		||||
		free_irq(irq, cg);
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct platform_driver crystalcove_gpio_driver = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -201,7 +201,8 @@ EXPORT_SYMBOL_GPL(cs5535_gpio_setup_event);
 | 
			
		|||
 | 
			
		||||
static int chip_gpio_request(struct gpio_chip *c, unsigned offset)
 | 
			
		||||
{
 | 
			
		||||
	struct cs5535_gpio_chip *chip = (struct cs5535_gpio_chip *) c;
 | 
			
		||||
	struct cs5535_gpio_chip *chip =
 | 
			
		||||
		container_of(c, struct cs5535_gpio_chip, chip);
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&chip->lock, flags);
 | 
			
		||||
| 
						 | 
				
			
			@ -241,7 +242,8 @@ static void chip_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
 | 
			
		|||
 | 
			
		||||
static int chip_direction_input(struct gpio_chip *c, unsigned offset)
 | 
			
		||||
{
 | 
			
		||||
	struct cs5535_gpio_chip *chip = (struct cs5535_gpio_chip *) c;
 | 
			
		||||
	struct cs5535_gpio_chip *chip =
 | 
			
		||||
		container_of(c, struct cs5535_gpio_chip, chip);
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&chip->lock, flags);
 | 
			
		||||
| 
						 | 
				
			
			@ -254,7 +256,8 @@ static int chip_direction_input(struct gpio_chip *c, unsigned offset)
 | 
			
		|||
 | 
			
		||||
static int chip_direction_output(struct gpio_chip *c, unsigned offset, int val)
 | 
			
		||||
{
 | 
			
		||||
	struct cs5535_gpio_chip *chip = (struct cs5535_gpio_chip *) c;
 | 
			
		||||
	struct cs5535_gpio_chip *chip =
 | 
			
		||||
		container_of(c, struct cs5535_gpio_chip, chip);
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&chip->lock, flags);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,6 +21,8 @@
 | 
			
		|||
#include <linux/of_irq.h>
 | 
			
		||||
#include <linux/platform_device.h>
 | 
			
		||||
#include <linux/spinlock.h>
 | 
			
		||||
#include <linux/platform_data/gpio-dwapb.h>
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
 | 
			
		||||
#define GPIO_SWPORTA_DR		0x00
 | 
			
		||||
#define GPIO_SWPORTA_DDR	0x04
 | 
			
		||||
| 
						 | 
				
			
			@ -35,6 +37,7 @@
 | 
			
		|||
#define GPIO_INTTYPE_LEVEL	0x38
 | 
			
		||||
#define GPIO_INT_POLARITY	0x3c
 | 
			
		||||
#define GPIO_INTSTATUS		0x40
 | 
			
		||||
#define GPIO_PORTA_DEBOUNCE	0x48
 | 
			
		||||
#define GPIO_PORTA_EOI		0x4c
 | 
			
		||||
#define GPIO_EXT_PORTA		0x50
 | 
			
		||||
#define GPIO_EXT_PORTB		0x54
 | 
			
		||||
| 
						 | 
				
			
			@ -48,10 +51,28 @@
 | 
			
		|||
 | 
			
		||||
struct dwapb_gpio;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PM_SLEEP
 | 
			
		||||
/* Store GPIO context across system-wide suspend/resume transitions */
 | 
			
		||||
struct dwapb_context {
 | 
			
		||||
	u32 data;
 | 
			
		||||
	u32 dir;
 | 
			
		||||
	u32 ext;
 | 
			
		||||
	u32 int_en;
 | 
			
		||||
	u32 int_mask;
 | 
			
		||||
	u32 int_type;
 | 
			
		||||
	u32 int_pol;
 | 
			
		||||
	u32 int_deb;
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct dwapb_gpio_port {
 | 
			
		||||
	struct bgpio_chip	bgc;
 | 
			
		||||
	bool			is_registered;
 | 
			
		||||
	struct dwapb_gpio	*gpio;
 | 
			
		||||
#ifdef CONFIG_PM_SLEEP
 | 
			
		||||
	struct dwapb_context	*ctx;
 | 
			
		||||
#endif
 | 
			
		||||
	unsigned int		idx;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct dwapb_gpio {
 | 
			
		||||
| 
						 | 
				
			
			@ -62,11 +83,33 @@ struct dwapb_gpio {
 | 
			
		|||
	struct irq_domain	*domain;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline struct dwapb_gpio_port *
 | 
			
		||||
to_dwapb_gpio_port(struct bgpio_chip *bgc)
 | 
			
		||||
{
 | 
			
		||||
	return container_of(bgc, struct dwapb_gpio_port, bgc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 dwapb_read(struct dwapb_gpio *gpio, unsigned int offset)
 | 
			
		||||
{
 | 
			
		||||
	struct bgpio_chip *bgc	= &gpio->ports[0].bgc;
 | 
			
		||||
	void __iomem *reg_base	= gpio->regs;
 | 
			
		||||
 | 
			
		||||
	return bgc->read_reg(reg_base + offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void dwapb_write(struct dwapb_gpio *gpio, unsigned int offset,
 | 
			
		||||
			       u32 val)
 | 
			
		||||
{
 | 
			
		||||
	struct bgpio_chip *bgc	= &gpio->ports[0].bgc;
 | 
			
		||||
	void __iomem *reg_base	= gpio->regs;
 | 
			
		||||
 | 
			
		||||
	bgc->write_reg(reg_base + offset, val);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int dwapb_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
 | 
			
		||||
{
 | 
			
		||||
	struct bgpio_chip *bgc = to_bgpio_chip(gc);
 | 
			
		||||
	struct dwapb_gpio_port *port = container_of(bgc, struct
 | 
			
		||||
						    dwapb_gpio_port, bgc);
 | 
			
		||||
	struct dwapb_gpio_port *port = to_dwapb_gpio_port(bgc);
 | 
			
		||||
	struct dwapb_gpio *gpio = port->gpio;
 | 
			
		||||
 | 
			
		||||
	return irq_find_mapping(gpio->domain, offset);
 | 
			
		||||
| 
						 | 
				
			
			@ -74,21 +117,20 @@ static int dwapb_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
 | 
			
		|||
 | 
			
		||||
static void dwapb_toggle_trigger(struct dwapb_gpio *gpio, unsigned int offs)
 | 
			
		||||
{
 | 
			
		||||
	u32 v = readl(gpio->regs + GPIO_INT_POLARITY);
 | 
			
		||||
	u32 v = dwapb_read(gpio, GPIO_INT_POLARITY);
 | 
			
		||||
 | 
			
		||||
	if (gpio_get_value(gpio->ports[0].bgc.gc.base + offs))
 | 
			
		||||
		v &= ~BIT(offs);
 | 
			
		||||
	else
 | 
			
		||||
		v |= BIT(offs);
 | 
			
		||||
 | 
			
		||||
	writel(v, gpio->regs + GPIO_INT_POLARITY);
 | 
			
		||||
	dwapb_write(gpio, GPIO_INT_POLARITY, v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dwapb_irq_handler(u32 irq, struct irq_desc *desc)
 | 
			
		||||
static u32 dwapb_do_irq(struct dwapb_gpio *gpio)
 | 
			
		||||
{
 | 
			
		||||
	struct dwapb_gpio *gpio = irq_get_handler_data(irq);
 | 
			
		||||
	struct irq_chip *chip = irq_desc_get_chip(desc);
 | 
			
		||||
	u32 irq_status = readl_relaxed(gpio->regs + GPIO_INTSTATUS);
 | 
			
		||||
	u32 ret = irq_status;
 | 
			
		||||
 | 
			
		||||
	while (irq_status) {
 | 
			
		||||
		int hwirq = fls(irq_status) - 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -102,6 +144,16 @@ static void dwapb_irq_handler(u32 irq, struct irq_desc *desc)
 | 
			
		|||
			dwapb_toggle_trigger(gpio, hwirq);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dwapb_irq_handler(u32 irq, struct irq_desc *desc)
 | 
			
		||||
{
 | 
			
		||||
	struct dwapb_gpio *gpio = irq_get_handler_data(irq);
 | 
			
		||||
	struct irq_chip *chip = irq_desc_get_chip(desc);
 | 
			
		||||
 | 
			
		||||
	dwapb_do_irq(gpio);
 | 
			
		||||
 | 
			
		||||
	if (chip->irq_eoi)
 | 
			
		||||
		chip->irq_eoi(irq_desc_get_irq_data(desc));
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -115,9 +167,9 @@ static void dwapb_irq_enable(struct irq_data *d)
 | 
			
		|||
	u32 val;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&bgc->lock, flags);
 | 
			
		||||
	val = readl(gpio->regs + GPIO_INTEN);
 | 
			
		||||
	val = dwapb_read(gpio, GPIO_INTEN);
 | 
			
		||||
	val |= BIT(d->hwirq);
 | 
			
		||||
	writel(val, gpio->regs + GPIO_INTEN);
 | 
			
		||||
	dwapb_write(gpio, GPIO_INTEN, val);
 | 
			
		||||
	spin_unlock_irqrestore(&bgc->lock, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -130,9 +182,9 @@ static void dwapb_irq_disable(struct irq_data *d)
 | 
			
		|||
	u32 val;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&bgc->lock, flags);
 | 
			
		||||
	val = readl(gpio->regs + GPIO_INTEN);
 | 
			
		||||
	val = dwapb_read(gpio, GPIO_INTEN);
 | 
			
		||||
	val &= ~BIT(d->hwirq);
 | 
			
		||||
	writel(val, gpio->regs + GPIO_INTEN);
 | 
			
		||||
	dwapb_write(gpio, GPIO_INTEN, val);
 | 
			
		||||
	spin_unlock_irqrestore(&bgc->lock, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -172,8 +224,8 @@ static int dwapb_irq_set_type(struct irq_data *d, u32 type)
 | 
			
		|||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&bgc->lock, flags);
 | 
			
		||||
	level = readl(gpio->regs + GPIO_INTTYPE_LEVEL);
 | 
			
		||||
	polarity = readl(gpio->regs + GPIO_INT_POLARITY);
 | 
			
		||||
	level = dwapb_read(gpio, GPIO_INTTYPE_LEVEL);
 | 
			
		||||
	polarity = dwapb_read(gpio, GPIO_INT_POLARITY);
 | 
			
		||||
 | 
			
		||||
	switch (type) {
 | 
			
		||||
	case IRQ_TYPE_EDGE_BOTH:
 | 
			
		||||
| 
						 | 
				
			
			@ -200,29 +252,55 @@ static int dwapb_irq_set_type(struct irq_data *d, u32 type)
 | 
			
		|||
 | 
			
		||||
	irq_setup_alt_chip(d, type);
 | 
			
		||||
 | 
			
		||||
	writel(level, gpio->regs + GPIO_INTTYPE_LEVEL);
 | 
			
		||||
	writel(polarity, gpio->regs + GPIO_INT_POLARITY);
 | 
			
		||||
	dwapb_write(gpio, GPIO_INTTYPE_LEVEL, level);
 | 
			
		||||
	dwapb_write(gpio, GPIO_INT_POLARITY, polarity);
 | 
			
		||||
	spin_unlock_irqrestore(&bgc->lock, flags);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int dwapb_gpio_set_debounce(struct gpio_chip *gc,
 | 
			
		||||
				   unsigned offset, unsigned debounce)
 | 
			
		||||
{
 | 
			
		||||
	struct bgpio_chip *bgc = to_bgpio_chip(gc);
 | 
			
		||||
	struct dwapb_gpio_port *port = to_dwapb_gpio_port(bgc);
 | 
			
		||||
	struct dwapb_gpio *gpio = port->gpio;
 | 
			
		||||
	unsigned long flags, val_deb;
 | 
			
		||||
	unsigned long mask = bgc->pin2mask(bgc, offset);
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&bgc->lock, flags);
 | 
			
		||||
 | 
			
		||||
	val_deb = dwapb_read(gpio, GPIO_PORTA_DEBOUNCE);
 | 
			
		||||
	if (debounce)
 | 
			
		||||
		dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, val_deb | mask);
 | 
			
		||||
	else
 | 
			
		||||
		dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, val_deb & ~mask);
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irqrestore(&bgc->lock, flags);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static irqreturn_t dwapb_irq_handler_mfd(int irq, void *dev_id)
 | 
			
		||||
{
 | 
			
		||||
	u32 worked;
 | 
			
		||||
	struct dwapb_gpio *gpio = dev_id;
 | 
			
		||||
 | 
			
		||||
	worked = dwapb_do_irq(gpio);
 | 
			
		||||
 | 
			
		||||
	return worked ? IRQ_HANDLED : IRQ_NONE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
 | 
			
		||||
				 struct dwapb_gpio_port *port)
 | 
			
		||||
				 struct dwapb_gpio_port *port,
 | 
			
		||||
				 struct dwapb_port_property *pp)
 | 
			
		||||
{
 | 
			
		||||
	struct gpio_chip *gc = &port->bgc.gc;
 | 
			
		||||
	struct device_node *node =  gc->of_node;
 | 
			
		||||
	struct irq_chip_generic	*irq_gc;
 | 
			
		||||
	struct device_node *node = pp->node;
 | 
			
		||||
	struct irq_chip_generic	*irq_gc = NULL;
 | 
			
		||||
	unsigned int hwirq, ngpio = gc->ngpio;
 | 
			
		||||
	struct irq_chip_type *ct;
 | 
			
		||||
	int err, irq, i;
 | 
			
		||||
 | 
			
		||||
	irq = irq_of_parse_and_map(node, 0);
 | 
			
		||||
	if (!irq) {
 | 
			
		||||
		dev_warn(gpio->dev, "no irq for bank %s\n",
 | 
			
		||||
			port->bgc.gc.of_node->full_name);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	int err, i;
 | 
			
		||||
 | 
			
		||||
	gpio->domain = irq_domain_add_linear(node, ngpio,
 | 
			
		||||
					     &irq_generic_chip_ops, gpio);
 | 
			
		||||
| 
						 | 
				
			
			@ -269,8 +347,24 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
 | 
			
		|||
	irq_gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH;
 | 
			
		||||
	irq_gc->chip_types[1].handler = handle_edge_irq;
 | 
			
		||||
 | 
			
		||||
	irq_set_chained_handler(irq, dwapb_irq_handler);
 | 
			
		||||
	irq_set_handler_data(irq, gpio);
 | 
			
		||||
	if (!pp->irq_shared) {
 | 
			
		||||
		irq_set_chained_handler(pp->irq, dwapb_irq_handler);
 | 
			
		||||
		irq_set_handler_data(pp->irq, gpio);
 | 
			
		||||
	} else {
 | 
			
		||||
		/*
 | 
			
		||||
		 * Request a shared IRQ since where MFD would have devices
 | 
			
		||||
		 * using the same irq pin
 | 
			
		||||
		 */
 | 
			
		||||
		err = devm_request_irq(gpio->dev, pp->irq,
 | 
			
		||||
				       dwapb_irq_handler_mfd,
 | 
			
		||||
				       IRQF_SHARED, "gpio-dwapb-mfd", gpio);
 | 
			
		||||
		if (err) {
 | 
			
		||||
			dev_err(gpio->dev, "error requesting IRQ\n");
 | 
			
		||||
			irq_domain_remove(gpio->domain);
 | 
			
		||||
			gpio->domain = NULL;
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (hwirq = 0 ; hwirq < ngpio ; hwirq++)
 | 
			
		||||
		irq_create_mapping(gpio->domain, hwirq);
 | 
			
		||||
| 
						 | 
				
			
			@ -296,57 +390,53 @@ static void dwapb_irq_teardown(struct dwapb_gpio *gpio)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static int dwapb_gpio_add_port(struct dwapb_gpio *gpio,
 | 
			
		||||
			       struct device_node *port_np,
 | 
			
		||||
			       struct dwapb_port_property *pp,
 | 
			
		||||
			       unsigned int offs)
 | 
			
		||||
{
 | 
			
		||||
	struct dwapb_gpio_port *port;
 | 
			
		||||
	u32 port_idx, ngpio;
 | 
			
		||||
	void __iomem *dat, *set, *dirout;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	if (of_property_read_u32(port_np, "reg", &port_idx) ||
 | 
			
		||||
		port_idx >= DWAPB_MAX_PORTS) {
 | 
			
		||||
		dev_err(gpio->dev, "missing/invalid port index for %s\n",
 | 
			
		||||
			port_np->full_name);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	port = &gpio->ports[offs];
 | 
			
		||||
	port->gpio = gpio;
 | 
			
		||||
	port->idx = pp->idx;
 | 
			
		||||
 | 
			
		||||
	if (of_property_read_u32(port_np, "snps,nr-gpios", &ngpio)) {
 | 
			
		||||
		dev_info(gpio->dev, "failed to get number of gpios for %s\n",
 | 
			
		||||
			 port_np->full_name);
 | 
			
		||||
		ngpio = 32;
 | 
			
		||||
	}
 | 
			
		||||
#ifdef CONFIG_PM_SLEEP
 | 
			
		||||
	port->ctx = devm_kzalloc(gpio->dev, sizeof(*port->ctx), GFP_KERNEL);
 | 
			
		||||
	if (!port->ctx)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	dat = gpio->regs + GPIO_EXT_PORTA + (port_idx * GPIO_EXT_PORT_SIZE);
 | 
			
		||||
	set = gpio->regs + GPIO_SWPORTA_DR + (port_idx * GPIO_SWPORT_DR_SIZE);
 | 
			
		||||
	dat = gpio->regs + GPIO_EXT_PORTA + (pp->idx * GPIO_EXT_PORT_SIZE);
 | 
			
		||||
	set = gpio->regs + GPIO_SWPORTA_DR + (pp->idx * GPIO_SWPORT_DR_SIZE);
 | 
			
		||||
	dirout = gpio->regs + GPIO_SWPORTA_DDR +
 | 
			
		||||
		(port_idx * GPIO_SWPORT_DDR_SIZE);
 | 
			
		||||
		(pp->idx * GPIO_SWPORT_DDR_SIZE);
 | 
			
		||||
 | 
			
		||||
	err = bgpio_init(&port->bgc, gpio->dev, 4, dat, set, NULL, dirout,
 | 
			
		||||
			 NULL, false);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		dev_err(gpio->dev, "failed to init gpio chip for %s\n",
 | 
			
		||||
			port_np->full_name);
 | 
			
		||||
			pp->name);
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	port->bgc.gc.ngpio = ngpio;
 | 
			
		||||
	port->bgc.gc.of_node = port_np;
 | 
			
		||||
#ifdef CONFIG_OF_GPIO
 | 
			
		||||
	port->bgc.gc.of_node = pp->node;
 | 
			
		||||
#endif
 | 
			
		||||
	port->bgc.gc.ngpio = pp->ngpio;
 | 
			
		||||
	port->bgc.gc.base = pp->gpio_base;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Only port A can provide interrupts in all configurations of the IP.
 | 
			
		||||
	 */
 | 
			
		||||
	if (port_idx == 0 &&
 | 
			
		||||
	    of_property_read_bool(port_np, "interrupt-controller"))
 | 
			
		||||
		dwapb_configure_irqs(gpio, port);
 | 
			
		||||
	/* Only port A support debounce */
 | 
			
		||||
	if (pp->idx == 0)
 | 
			
		||||
		port->bgc.gc.set_debounce = dwapb_gpio_set_debounce;
 | 
			
		||||
 | 
			
		||||
	if (pp->irq)
 | 
			
		||||
		dwapb_configure_irqs(gpio, port, pp);
 | 
			
		||||
 | 
			
		||||
	err = gpiochip_add(&port->bgc.gc);
 | 
			
		||||
	if (err)
 | 
			
		||||
		dev_err(gpio->dev, "failed to register gpiochip for %s\n",
 | 
			
		||||
			port_np->full_name);
 | 
			
		||||
			pp->name);
 | 
			
		||||
	else
 | 
			
		||||
		port->is_registered = true;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -362,25 +452,116 @@ static void dwapb_gpio_unregister(struct dwapb_gpio *gpio)
 | 
			
		|||
			gpiochip_remove(&gpio->ports[m].bgc.gc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct dwapb_platform_data *
 | 
			
		||||
dwapb_gpio_get_pdata_of(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct device_node *node, *port_np;
 | 
			
		||||
	struct dwapb_platform_data *pdata;
 | 
			
		||||
	struct dwapb_port_property *pp;
 | 
			
		||||
	int nports;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	node = dev->of_node;
 | 
			
		||||
	if (!IS_ENABLED(CONFIG_OF_GPIO) || !node)
 | 
			
		||||
		return ERR_PTR(-ENODEV);
 | 
			
		||||
 | 
			
		||||
	nports = of_get_child_count(node);
 | 
			
		||||
	if (nports == 0)
 | 
			
		||||
		return ERR_PTR(-ENODEV);
 | 
			
		||||
 | 
			
		||||
	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
 | 
			
		||||
	if (!pdata)
 | 
			
		||||
		return ERR_PTR(-ENOMEM);
 | 
			
		||||
 | 
			
		||||
	pdata->properties = kcalloc(nports, sizeof(*pp), GFP_KERNEL);
 | 
			
		||||
	if (!pdata->properties) {
 | 
			
		||||
		kfree(pdata);
 | 
			
		||||
		return ERR_PTR(-ENOMEM);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pdata->nports = nports;
 | 
			
		||||
 | 
			
		||||
	i = 0;
 | 
			
		||||
	for_each_child_of_node(node, port_np) {
 | 
			
		||||
		pp = &pdata->properties[i++];
 | 
			
		||||
		pp->node = port_np;
 | 
			
		||||
 | 
			
		||||
		if (of_property_read_u32(port_np, "reg", &pp->idx) ||
 | 
			
		||||
		    pp->idx >= DWAPB_MAX_PORTS) {
 | 
			
		||||
			dev_err(dev, "missing/invalid port index for %s\n",
 | 
			
		||||
				port_np->full_name);
 | 
			
		||||
			kfree(pdata->properties);
 | 
			
		||||
			kfree(pdata);
 | 
			
		||||
			return ERR_PTR(-EINVAL);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (of_property_read_u32(port_np, "snps,nr-gpios",
 | 
			
		||||
					 &pp->ngpio)) {
 | 
			
		||||
			dev_info(dev, "failed to get number of gpios for %s\n",
 | 
			
		||||
				 port_np->full_name);
 | 
			
		||||
			pp->ngpio = 32;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Only port A can provide interrupts in all configurations of
 | 
			
		||||
		 * the IP.
 | 
			
		||||
		 */
 | 
			
		||||
		if (pp->idx == 0 &&
 | 
			
		||||
		    of_property_read_bool(port_np, "interrupt-controller")) {
 | 
			
		||||
			pp->irq = irq_of_parse_and_map(port_np, 0);
 | 
			
		||||
			if (!pp->irq) {
 | 
			
		||||
				dev_warn(dev, "no irq for bank %s\n",
 | 
			
		||||
					 port_np->full_name);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		pp->irq_shared	= false;
 | 
			
		||||
		pp->gpio_base	= -1;
 | 
			
		||||
		pp->name	= port_np->full_name;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return pdata;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void dwapb_free_pdata_of(struct dwapb_platform_data *pdata)
 | 
			
		||||
{
 | 
			
		||||
	if (!IS_ENABLED(CONFIG_OF_GPIO) || !pdata)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	kfree(pdata->properties);
 | 
			
		||||
	kfree(pdata);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int dwapb_gpio_probe(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
	struct resource *res;
 | 
			
		||||
	struct dwapb_gpio *gpio;
 | 
			
		||||
	struct device_node *np;
 | 
			
		||||
	int err;
 | 
			
		||||
	unsigned int offs = 0;
 | 
			
		||||
	struct device *dev = &pdev->dev;
 | 
			
		||||
	struct dwapb_platform_data *pdata = dev_get_platdata(dev);
 | 
			
		||||
	bool is_pdata_alloc = !pdata;
 | 
			
		||||
 | 
			
		||||
	gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
 | 
			
		||||
	if (!gpio)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	gpio->dev = &pdev->dev;
 | 
			
		||||
	if (is_pdata_alloc) {
 | 
			
		||||
		pdata = dwapb_gpio_get_pdata_of(dev);
 | 
			
		||||
		if (IS_ERR(pdata))
 | 
			
		||||
			return PTR_ERR(pdata);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gpio->nr_ports = of_get_child_count(pdev->dev.of_node);
 | 
			
		||||
	if (!gpio->nr_ports) {
 | 
			
		||||
		err = -EINVAL;
 | 
			
		||||
	if (!pdata->nports) {
 | 
			
		||||
		err = -ENODEV;
 | 
			
		||||
		goto out_err;
 | 
			
		||||
	}
 | 
			
		||||
	gpio->ports = devm_kzalloc(&pdev->dev, gpio->nr_ports *
 | 
			
		||||
 | 
			
		||||
	gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
 | 
			
		||||
	if (!gpio) {
 | 
			
		||||
		err = -ENOMEM;
 | 
			
		||||
		goto out_err;
 | 
			
		||||
	}
 | 
			
		||||
	gpio->dev = &pdev->dev;
 | 
			
		||||
	gpio->nr_ports = pdata->nports;
 | 
			
		||||
 | 
			
		||||
	gpio->ports = devm_kcalloc(&pdev->dev, gpio->nr_ports,
 | 
			
		||||
				   sizeof(*gpio->ports), GFP_KERNEL);
 | 
			
		||||
	if (!gpio->ports) {
 | 
			
		||||
		err = -ENOMEM;
 | 
			
		||||
| 
						 | 
				
			
			@ -394,20 +575,23 @@ static int dwapb_gpio_probe(struct platform_device *pdev)
 | 
			
		|||
		goto out_err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for_each_child_of_node(pdev->dev.of_node, np) {
 | 
			
		||||
		err = dwapb_gpio_add_port(gpio, np, offs++);
 | 
			
		||||
	for (i = 0; i < gpio->nr_ports; i++) {
 | 
			
		||||
		err = dwapb_gpio_add_port(gpio, &pdata->properties[i], i);
 | 
			
		||||
		if (err)
 | 
			
		||||
			goto out_unregister;
 | 
			
		||||
	}
 | 
			
		||||
	platform_set_drvdata(pdev, gpio);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
	goto out_err;
 | 
			
		||||
 | 
			
		||||
out_unregister:
 | 
			
		||||
	dwapb_gpio_unregister(gpio);
 | 
			
		||||
	dwapb_irq_teardown(gpio);
 | 
			
		||||
 | 
			
		||||
out_err:
 | 
			
		||||
	if (is_pdata_alloc)
 | 
			
		||||
		dwapb_free_pdata_of(pdata);
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -427,10 +611,100 @@ static const struct of_device_id dwapb_of_match[] = {
 | 
			
		|||
};
 | 
			
		||||
MODULE_DEVICE_TABLE(of, dwapb_of_match);
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PM_SLEEP
 | 
			
		||||
static int dwapb_gpio_suspend(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct platform_device *pdev = to_platform_device(dev);
 | 
			
		||||
	struct dwapb_gpio *gpio = platform_get_drvdata(pdev);
 | 
			
		||||
	struct bgpio_chip *bgc	= &gpio->ports[0].bgc;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&bgc->lock, flags);
 | 
			
		||||
	for (i = 0; i < gpio->nr_ports; i++) {
 | 
			
		||||
		unsigned int offset;
 | 
			
		||||
		unsigned int idx = gpio->ports[i].idx;
 | 
			
		||||
		struct dwapb_context *ctx = gpio->ports[i].ctx;
 | 
			
		||||
 | 
			
		||||
		BUG_ON(!ctx);
 | 
			
		||||
 | 
			
		||||
		offset = GPIO_SWPORTA_DDR + idx * GPIO_SWPORT_DDR_SIZE;
 | 
			
		||||
		ctx->dir = dwapb_read(gpio, offset);
 | 
			
		||||
 | 
			
		||||
		offset = GPIO_SWPORTA_DR + idx * GPIO_SWPORT_DR_SIZE;
 | 
			
		||||
		ctx->data = dwapb_read(gpio, offset);
 | 
			
		||||
 | 
			
		||||
		offset = GPIO_EXT_PORTA + idx * GPIO_EXT_PORT_SIZE;
 | 
			
		||||
		ctx->ext = dwapb_read(gpio, offset);
 | 
			
		||||
 | 
			
		||||
		/* Only port A can provide interrupts */
 | 
			
		||||
		if (idx == 0) {
 | 
			
		||||
			ctx->int_mask	= dwapb_read(gpio, GPIO_INTMASK);
 | 
			
		||||
			ctx->int_en	= dwapb_read(gpio, GPIO_INTEN);
 | 
			
		||||
			ctx->int_pol	= dwapb_read(gpio, GPIO_INT_POLARITY);
 | 
			
		||||
			ctx->int_type	= dwapb_read(gpio, GPIO_INTTYPE_LEVEL);
 | 
			
		||||
			ctx->int_deb	= dwapb_read(gpio, GPIO_PORTA_DEBOUNCE);
 | 
			
		||||
 | 
			
		||||
			/* Mask out interrupts */
 | 
			
		||||
			dwapb_write(gpio, GPIO_INTMASK, 0xffffffff);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	spin_unlock_irqrestore(&bgc->lock, flags);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int dwapb_gpio_resume(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct platform_device *pdev = to_platform_device(dev);
 | 
			
		||||
	struct dwapb_gpio *gpio = platform_get_drvdata(pdev);
 | 
			
		||||
	struct bgpio_chip *bgc	= &gpio->ports[0].bgc;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&bgc->lock, flags);
 | 
			
		||||
	for (i = 0; i < gpio->nr_ports; i++) {
 | 
			
		||||
		unsigned int offset;
 | 
			
		||||
		unsigned int idx = gpio->ports[i].idx;
 | 
			
		||||
		struct dwapb_context *ctx = gpio->ports[i].ctx;
 | 
			
		||||
 | 
			
		||||
		BUG_ON(!ctx);
 | 
			
		||||
 | 
			
		||||
		offset = GPIO_SWPORTA_DR + idx * GPIO_SWPORT_DR_SIZE;
 | 
			
		||||
		dwapb_write(gpio, offset, ctx->data);
 | 
			
		||||
 | 
			
		||||
		offset = GPIO_SWPORTA_DDR + idx * GPIO_SWPORT_DDR_SIZE;
 | 
			
		||||
		dwapb_write(gpio, offset, ctx->dir);
 | 
			
		||||
 | 
			
		||||
		offset = GPIO_EXT_PORTA + idx * GPIO_EXT_PORT_SIZE;
 | 
			
		||||
		dwapb_write(gpio, offset, ctx->ext);
 | 
			
		||||
 | 
			
		||||
		/* Only port A can provide interrupts */
 | 
			
		||||
		if (idx == 0) {
 | 
			
		||||
			dwapb_write(gpio, GPIO_INTTYPE_LEVEL, ctx->int_type);
 | 
			
		||||
			dwapb_write(gpio, GPIO_INT_POLARITY, ctx->int_pol);
 | 
			
		||||
			dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, ctx->int_deb);
 | 
			
		||||
			dwapb_write(gpio, GPIO_INTEN, ctx->int_en);
 | 
			
		||||
			dwapb_write(gpio, GPIO_INTMASK, ctx->int_mask);
 | 
			
		||||
 | 
			
		||||
			/* Clear out spurious interrupts */
 | 
			
		||||
			dwapb_write(gpio, GPIO_PORTA_EOI, 0xffffffff);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	spin_unlock_irqrestore(&bgc->lock, flags);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static SIMPLE_DEV_PM_OPS(dwapb_gpio_pm_ops, dwapb_gpio_suspend,
 | 
			
		||||
			 dwapb_gpio_resume);
 | 
			
		||||
 | 
			
		||||
static struct platform_driver dwapb_gpio_driver = {
 | 
			
		||||
	.driver		= {
 | 
			
		||||
		.name	= "gpio-dwapb",
 | 
			
		||||
		.owner	= THIS_MODULE,
 | 
			
		||||
		.pm	= &dwapb_gpio_pm_ops,
 | 
			
		||||
		.of_match_table = of_match_ptr(dwapb_of_match),
 | 
			
		||||
	},
 | 
			
		||||
	.probe		= dwapb_gpio_probe,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -276,18 +276,16 @@ static int ks8695_gpio_show(struct seq_file *s, void *unused)
 | 
			
		|||
				case IOPC_TM_EDGE:
 | 
			
		||||
					seq_printf(s, "(Edges)");	break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			} else
 | 
			
		||||
				seq_printf(s, "GPIO\t");
 | 
			
		||||
		}
 | 
			
		||||
		else if (i <= KS8695_GPIO_5) {
 | 
			
		||||
		} else if (i <= KS8695_GPIO_5) {
 | 
			
		||||
			if (ctrl & enable[i])
 | 
			
		||||
				seq_printf(s, "TOUT%i\t", i - KS8695_GPIO_4);
 | 
			
		||||
			else
 | 
			
		||||
				seq_printf(s, "GPIO\t");
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		} else {
 | 
			
		||||
			seq_printf(s, "GPIO\t");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		seq_printf(s, "\t");
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -479,7 +479,7 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp)
 | 
			
		|||
 | 
			
		||||
	mutex_init(&mcp->irq_lock);
 | 
			
		||||
 | 
			
		||||
	mcp->irq_domain = irq_domain_add_linear(chip->of_node, chip->ngpio,
 | 
			
		||||
	mcp->irq_domain = irq_domain_add_linear(chip->dev->of_node, chip->ngpio,
 | 
			
		||||
						&irq_domain_simple_ops, mcp);
 | 
			
		||||
	if (!mcp->irq_domain)
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
| 
						 | 
				
			
			@ -581,7 +581,7 @@ done:
 | 
			
		|||
 | 
			
		||||
static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
 | 
			
		||||
			      void *data, unsigned addr, unsigned type,
 | 
			
		||||
			      unsigned base, unsigned pullups)
 | 
			
		||||
			      struct mcp23s08_platform_data *pdata, int cs)
 | 
			
		||||
{
 | 
			
		||||
	int status;
 | 
			
		||||
	bool mirror = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -635,7 +635,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
 | 
			
		|||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mcp->chip.base = base;
 | 
			
		||||
	mcp->chip.base = pdata->base;
 | 
			
		||||
	mcp->chip.can_sleep = true;
 | 
			
		||||
	mcp->chip.dev = dev;
 | 
			
		||||
	mcp->chip.owner = THIS_MODULE;
 | 
			
		||||
| 
						 | 
				
			
			@ -648,11 +648,9 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
 | 
			
		|||
	if (status < 0)
 | 
			
		||||
		goto fail;
 | 
			
		||||
 | 
			
		||||
	mcp->irq_controller = of_property_read_bool(mcp->chip.of_node,
 | 
			
		||||
						"interrupt-controller");
 | 
			
		||||
	mcp->irq_controller = pdata->irq_controller;
 | 
			
		||||
	if (mcp->irq && mcp->irq_controller && (type == MCP_TYPE_017))
 | 
			
		||||
		mirror = of_property_read_bool(mcp->chip.of_node,
 | 
			
		||||
						"microchip,irq-mirror");
 | 
			
		||||
		mirror = pdata->mirror;
 | 
			
		||||
 | 
			
		||||
	if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN) || mirror) {
 | 
			
		||||
		/* mcp23s17 has IOCON twice, make sure they are in sync */
 | 
			
		||||
| 
						 | 
				
			
			@ -668,7 +666,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	/* configure ~100K pullups */
 | 
			
		||||
	status = mcp->ops->write(mcp, MCP_GPPU, pullups);
 | 
			
		||||
	status = mcp->ops->write(mcp, MCP_GPPU, pdata->chip[cs].pullups);
 | 
			
		||||
	if (status < 0)
 | 
			
		||||
		goto fail;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -768,25 +766,29 @@ MODULE_DEVICE_TABLE(of, mcp23s08_i2c_of_match);
 | 
			
		|||
static int mcp230xx_probe(struct i2c_client *client,
 | 
			
		||||
				    const struct i2c_device_id *id)
 | 
			
		||||
{
 | 
			
		||||
	struct mcp23s08_platform_data *pdata;
 | 
			
		||||
	struct mcp23s08_platform_data *pdata, local_pdata;
 | 
			
		||||
	struct mcp23s08 *mcp;
 | 
			
		||||
	int status, base, pullups;
 | 
			
		||||
	int status;
 | 
			
		||||
	const struct of_device_id *match;
 | 
			
		||||
 | 
			
		||||
	match = of_match_device(of_match_ptr(mcp23s08_i2c_of_match),
 | 
			
		||||
					&client->dev);
 | 
			
		||||
	pdata = dev_get_platdata(&client->dev);
 | 
			
		||||
	if (match || !pdata) {
 | 
			
		||||
		base = -1;
 | 
			
		||||
		pullups = 0;
 | 
			
		||||
	if (match) {
 | 
			
		||||
		pdata = &local_pdata;
 | 
			
		||||
		pdata->base = -1;
 | 
			
		||||
		pdata->chip[0].pullups = 0;
 | 
			
		||||
		pdata->irq_controller =	of_property_read_bool(
 | 
			
		||||
					client->dev.of_node,
 | 
			
		||||
					"interrupt-controller");
 | 
			
		||||
		pdata->mirror = of_property_read_bool(client->dev.of_node,
 | 
			
		||||
						      "microchip,irq-mirror");
 | 
			
		||||
		client->irq = irq_of_parse_and_map(client->dev.of_node, 0);
 | 
			
		||||
	} else {
 | 
			
		||||
		if (!gpio_is_valid(pdata->base)) {
 | 
			
		||||
		pdata = dev_get_platdata(&client->dev);
 | 
			
		||||
		if (!pdata || !gpio_is_valid(pdata->base)) {
 | 
			
		||||
			dev_dbg(&client->dev, "invalid platform data\n");
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
		}
 | 
			
		||||
		base = pdata->base;
 | 
			
		||||
		pullups = pdata->chip[0].pullups;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mcp = kzalloc(sizeof(*mcp), GFP_KERNEL);
 | 
			
		||||
| 
						 | 
				
			
			@ -795,7 +797,7 @@ static int mcp230xx_probe(struct i2c_client *client,
 | 
			
		|||
 | 
			
		||||
	mcp->irq = client->irq;
 | 
			
		||||
	status = mcp23s08_probe_one(mcp, &client->dev, client, client->addr,
 | 
			
		||||
				    id->driver_data, base, pullups);
 | 
			
		||||
				    id->driver_data, pdata, 0);
 | 
			
		||||
	if (status)
 | 
			
		||||
		goto fail;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -863,14 +865,12 @@ static void mcp23s08_i2c_exit(void) { }
 | 
			
		|||
 | 
			
		||||
static int mcp23s08_probe(struct spi_device *spi)
 | 
			
		||||
{
 | 
			
		||||
	struct mcp23s08_platform_data	*pdata;
 | 
			
		||||
	struct mcp23s08_platform_data	*pdata, local_pdata;
 | 
			
		||||
	unsigned			addr;
 | 
			
		||||
	int				chips = 0;
 | 
			
		||||
	struct mcp23s08_driver_data	*data;
 | 
			
		||||
	int				status, type;
 | 
			
		||||
	unsigned			base = -1,
 | 
			
		||||
					ngpio = 0,
 | 
			
		||||
					pullups[ARRAY_SIZE(pdata->chip)];
 | 
			
		||||
	unsigned			ngpio = 0;
 | 
			
		||||
	const struct			of_device_id *match;
 | 
			
		||||
	u32				spi_present_mask = 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -893,11 +893,18 @@ static int mcp23s08_probe(struct spi_device *spi)
 | 
			
		|||
			return -ENODEV;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		pdata = &local_pdata;
 | 
			
		||||
		pdata->base = -1;
 | 
			
		||||
		for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) {
 | 
			
		||||
			pullups[addr] = 0;
 | 
			
		||||
			pdata->chip[addr].pullups = 0;
 | 
			
		||||
			if (spi_present_mask & (1 << addr))
 | 
			
		||||
				chips++;
 | 
			
		||||
		}
 | 
			
		||||
		pdata->irq_controller =	of_property_read_bool(
 | 
			
		||||
					spi->dev.of_node,
 | 
			
		||||
					"interrupt-controller");
 | 
			
		||||
		pdata->mirror = of_property_read_bool(spi->dev.of_node,
 | 
			
		||||
						      "microchip,irq-mirror");
 | 
			
		||||
	} else {
 | 
			
		||||
		type = spi_get_device_id(spi)->driver_data;
 | 
			
		||||
		pdata = dev_get_platdata(&spi->dev);
 | 
			
		||||
| 
						 | 
				
			
			@ -917,10 +924,7 @@ static int mcp23s08_probe(struct spi_device *spi)
 | 
			
		|||
				return -EINVAL;
 | 
			
		||||
			}
 | 
			
		||||
			spi_present_mask |= 1 << addr;
 | 
			
		||||
			pullups[addr] = pdata->chip[addr].pullups;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		base = pdata->base;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!chips)
 | 
			
		||||
| 
						 | 
				
			
			@ -938,13 +942,13 @@ static int mcp23s08_probe(struct spi_device *spi)
 | 
			
		|||
		chips--;
 | 
			
		||||
		data->mcp[addr] = &data->chip[chips];
 | 
			
		||||
		status = mcp23s08_probe_one(data->mcp[addr], &spi->dev, spi,
 | 
			
		||||
					    0x40 | (addr << 1), type, base,
 | 
			
		||||
					    pullups[addr]);
 | 
			
		||||
					    0x40 | (addr << 1), type, pdata,
 | 
			
		||||
					    addr);
 | 
			
		||||
		if (status < 0)
 | 
			
		||||
			goto fail;
 | 
			
		||||
 | 
			
		||||
		if (base != -1)
 | 
			
		||||
			base += (type == MCP_TYPE_S17) ? 16 : 8;
 | 
			
		||||
		if (pdata->base != -1)
 | 
			
		||||
			pdata->base += (type == MCP_TYPE_S17) ? 16 : 8;
 | 
			
		||||
		ngpio += (type == MCP_TYPE_S17) ? 16 : 8;
 | 
			
		||||
	}
 | 
			
		||||
	data->ngpio = ngpio;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -857,16 +857,6 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
 | 
			
		|||
	spin_unlock_irqrestore(&bank->lock, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct irq_chip gpio_irq_chip = {
 | 
			
		||||
	.name		= "GPIO",
 | 
			
		||||
	.irq_shutdown	= omap_gpio_irq_shutdown,
 | 
			
		||||
	.irq_ack	= omap_gpio_ack_irq,
 | 
			
		||||
	.irq_mask	= omap_gpio_mask_irq,
 | 
			
		||||
	.irq_unmask	= omap_gpio_unmask_irq,
 | 
			
		||||
	.irq_set_type	= omap_gpio_irq_type,
 | 
			
		||||
	.irq_set_wake	= omap_gpio_wake_enable,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*---------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
static int omap_mpuio_suspend_noirq(struct device *dev)
 | 
			
		||||
| 
						 | 
				
			
			@ -1088,7 +1078,7 @@ omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start,
 | 
			
		|||
			       IRQ_NOREQUEST | IRQ_NOPROBE, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int omap_gpio_chip_init(struct gpio_bank *bank)
 | 
			
		||||
static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
 | 
			
		||||
{
 | 
			
		||||
	int j;
 | 
			
		||||
	static int gpio;
 | 
			
		||||
| 
						 | 
				
			
			@ -1137,17 +1127,17 @@ static int omap_gpio_chip_init(struct gpio_bank *bank)
 | 
			
		|||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	ret = gpiochip_irqchip_add(&bank->chip, &gpio_irq_chip,
 | 
			
		||||
	ret = gpiochip_irqchip_add(&bank->chip, irqc,
 | 
			
		||||
				   irq_base, omap_gpio_irq_handler,
 | 
			
		||||
				   IRQ_TYPE_NONE);
 | 
			
		||||
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		dev_err(bank->dev, "Couldn't add irqchip to gpiochip %d\n", ret);
 | 
			
		||||
		ret = gpiochip_remove(&bank->chip);
 | 
			
		||||
		gpiochip_remove(&bank->chip);
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gpiochip_set_chained_irqchip(&bank->chip, &gpio_irq_chip,
 | 
			
		||||
	gpiochip_set_chained_irqchip(&bank->chip, irqc,
 | 
			
		||||
				     bank->irq, omap_gpio_irq_handler);
 | 
			
		||||
 | 
			
		||||
	for (j = 0; j < bank->width; j++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1172,6 +1162,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
 | 
			
		|||
	const struct omap_gpio_platform_data *pdata;
 | 
			
		||||
	struct resource *res;
 | 
			
		||||
	struct gpio_bank *bank;
 | 
			
		||||
	struct irq_chip *irqc;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	match = of_match_device(of_match_ptr(omap_gpio_match), dev);
 | 
			
		||||
| 
						 | 
				
			
			@ -1186,6 +1177,18 @@ static int omap_gpio_probe(struct platform_device *pdev)
 | 
			
		|||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	irqc = devm_kzalloc(dev, sizeof(*irqc), GFP_KERNEL);
 | 
			
		||||
	if (!irqc)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	irqc->irq_shutdown = omap_gpio_irq_shutdown,
 | 
			
		||||
	irqc->irq_ack = omap_gpio_ack_irq,
 | 
			
		||||
	irqc->irq_mask = omap_gpio_mask_irq,
 | 
			
		||||
	irqc->irq_unmask = omap_gpio_unmask_irq,
 | 
			
		||||
	irqc->irq_set_type = omap_gpio_irq_type,
 | 
			
		||||
	irqc->irq_set_wake = omap_gpio_wake_enable,
 | 
			
		||||
	irqc->name = dev_name(&pdev->dev);
 | 
			
		||||
 | 
			
		||||
	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 | 
			
		||||
	if (unlikely(!res)) {
 | 
			
		||||
		dev_err(dev, "Invalid IRQ resource\n");
 | 
			
		||||
| 
						 | 
				
			
			@ -1241,7 +1244,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
 | 
			
		|||
 | 
			
		||||
	omap_gpio_mod_init(bank);
 | 
			
		||||
 | 
			
		||||
	ret = omap_gpio_chip_init(bank);
 | 
			
		||||
	ret = omap_gpio_chip_init(bank, irqc);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -520,7 +520,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
 | 
			
		|||
	struct i2c_client *client = chip->client;
 | 
			
		||||
	int ret, i, offset = 0;
 | 
			
		||||
 | 
			
		||||
	if (irq_base != -1
 | 
			
		||||
	if (client->irq && irq_base != -1
 | 
			
		||||
			&& (id->driver_data & PCA_INT)) {
 | 
			
		||||
 | 
			
		||||
		switch (chip->chip_type) {
 | 
			
		||||
| 
						 | 
				
			
			@ -586,50 +586,6 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
 | 
			
		|||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Handlers for alternative sources of platform_data
 | 
			
		||||
 */
 | 
			
		||||
#ifdef CONFIG_OF_GPIO
 | 
			
		||||
/*
 | 
			
		||||
 * Translate OpenFirmware node properties into platform_data
 | 
			
		||||
 * WARNING: This is DEPRECATED and will be removed eventually!
 | 
			
		||||
 */
 | 
			
		||||
static void
 | 
			
		||||
pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert)
 | 
			
		||||
{
 | 
			
		||||
	struct device_node *node;
 | 
			
		||||
	const __be32 *val;
 | 
			
		||||
	int size;
 | 
			
		||||
 | 
			
		||||
	*gpio_base = -1;
 | 
			
		||||
 | 
			
		||||
	node = client->dev.of_node;
 | 
			
		||||
	if (node == NULL)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	val = of_get_property(node, "linux,gpio-base", &size);
 | 
			
		||||
	WARN(val, "%s: device-tree property 'linux,gpio-base' is deprecated!", __func__);
 | 
			
		||||
	if (val) {
 | 
			
		||||
		if (size != sizeof(*val))
 | 
			
		||||
			dev_warn(&client->dev, "%s: wrong linux,gpio-base\n",
 | 
			
		||||
				 node->full_name);
 | 
			
		||||
		else
 | 
			
		||||
			*gpio_base = be32_to_cpup(val);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	val = of_get_property(node, "polarity", NULL);
 | 
			
		||||
	WARN(val, "%s: device-tree property 'polarity' is deprecated!", __func__);
 | 
			
		||||
	if (val)
 | 
			
		||||
		*invert = *val;
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
static void
 | 
			
		||||
pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert)
 | 
			
		||||
{
 | 
			
		||||
	*gpio_base = -1;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static int device_pca953x_init(struct pca953x_chip *chip, u32 invert)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -704,12 +660,8 @@ static int pca953x_probe(struct i2c_client *client,
 | 
			
		|||
		invert = pdata->invert;
 | 
			
		||||
		chip->names = pdata->names;
 | 
			
		||||
	} else {
 | 
			
		||||
		pca953x_get_alt_pdata(client, &chip->gpio_start, &invert);
 | 
			
		||||
#ifdef CONFIG_OF_GPIO
 | 
			
		||||
		/* If I2C node has no interrupts property, disable GPIO interrupts */
 | 
			
		||||
		if (of_find_property(client->dev.of_node, "interrupts", NULL) == NULL)
 | 
			
		||||
			irq_base = -1;
 | 
			
		||||
#endif
 | 
			
		||||
		chip->gpio_start = -1;
 | 
			
		||||
		irq_base = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	chip->client = client;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -171,6 +171,7 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PM
 | 
			
		||||
/*
 | 
			
		||||
 * Save register configuration and disable interrupts.
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -206,6 +207,7 @@ static void pch_gpio_restore_reg_conf(struct pch_gpio *chip)
 | 
			
		|||
		iowrite32(chip->pch_gpio_reg.gpio_use_sel_reg,
 | 
			
		||||
			  &chip->reg->gpio_use_sel);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static int pch_gpio_to_irq(struct gpio_chip *gpio, unsigned offset)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1309,56 +1309,6 @@ samsung_gpio_pull_t s3c_gpio_getpull(unsigned int pin)
 | 
			
		|||
}
 | 
			
		||||
EXPORT_SYMBOL(s3c_gpio_getpull);
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_S5P_GPIO_DRVSTR
 | 
			
		||||
s5p_gpio_drvstr_t s5p_gpio_get_drvstr(unsigned int pin)
 | 
			
		||||
{
 | 
			
		||||
	struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin);
 | 
			
		||||
	unsigned int off;
 | 
			
		||||
	void __iomem *reg;
 | 
			
		||||
	int shift;
 | 
			
		||||
	u32 drvstr;
 | 
			
		||||
 | 
			
		||||
	if (!chip)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	off = pin - chip->chip.base;
 | 
			
		||||
	shift = off * 2;
 | 
			
		||||
	reg = chip->base + 0x0C;
 | 
			
		||||
 | 
			
		||||
	drvstr = __raw_readl(reg);
 | 
			
		||||
	drvstr = drvstr >> shift;
 | 
			
		||||
	drvstr &= 0x3;
 | 
			
		||||
 | 
			
		||||
	return (__force s5p_gpio_drvstr_t)drvstr;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(s5p_gpio_get_drvstr);
 | 
			
		||||
 | 
			
		||||
int s5p_gpio_set_drvstr(unsigned int pin, s5p_gpio_drvstr_t drvstr)
 | 
			
		||||
{
 | 
			
		||||
	struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin);
 | 
			
		||||
	unsigned int off;
 | 
			
		||||
	void __iomem *reg;
 | 
			
		||||
	int shift;
 | 
			
		||||
	u32 tmp;
 | 
			
		||||
 | 
			
		||||
	if (!chip)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	off = pin - chip->chip.base;
 | 
			
		||||
	shift = off * 2;
 | 
			
		||||
	reg = chip->base + 0x0C;
 | 
			
		||||
 | 
			
		||||
	tmp = __raw_readl(reg);
 | 
			
		||||
	tmp &= ~(0x3 << shift);
 | 
			
		||||
	tmp |= drvstr << shift;
 | 
			
		||||
 | 
			
		||||
	__raw_writel(tmp, reg);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(s5p_gpio_set_drvstr);
 | 
			
		||||
#endif	/* CONFIG_S5P_GPIO_DRVSTR */
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PLAT_S3C24XX
 | 
			
		||||
unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,6 +13,7 @@
 | 
			
		|||
#include <linux/interrupt.h>
 | 
			
		||||
#include <linux/of.h>
 | 
			
		||||
#include <linux/mfd/stmpe.h>
 | 
			
		||||
#include <linux/seq_file.h>
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * These registers are modified under the irq bus lock and cached to avoid
 | 
			
		||||
| 
						 | 
				
			
			@ -127,19 +128,19 @@ static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type)
 | 
			
		|||
	int regoffset = offset / 8;
 | 
			
		||||
	int mask = 1 << (offset % 8);
 | 
			
		||||
 | 
			
		||||
	if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH)
 | 
			
		||||
	if (type & IRQ_TYPE_LEVEL_LOW || type & IRQ_TYPE_LEVEL_HIGH)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	/* STMPE801 doesn't have RE and FE registers */
 | 
			
		||||
	if (stmpe_gpio->stmpe->partnum == STMPE801)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (type == IRQ_TYPE_EDGE_RISING)
 | 
			
		||||
	if (type & IRQ_TYPE_EDGE_RISING)
 | 
			
		||||
		stmpe_gpio->regs[REG_RE][regoffset] |= mask;
 | 
			
		||||
	else
 | 
			
		||||
		stmpe_gpio->regs[REG_RE][regoffset] &= ~mask;
 | 
			
		||||
 | 
			
		||||
	if (type == IRQ_TYPE_EDGE_FALLING)
 | 
			
		||||
	if (type & IRQ_TYPE_EDGE_FALLING)
 | 
			
		||||
		stmpe_gpio->regs[REG_FE][regoffset] |= mask;
 | 
			
		||||
	else
 | 
			
		||||
		stmpe_gpio->regs[REG_FE][regoffset] &= ~mask;
 | 
			
		||||
| 
						 | 
				
			
			@ -211,6 +212,77 @@ static void stmpe_gpio_irq_unmask(struct irq_data *d)
 | 
			
		|||
	stmpe_gpio->regs[REG_IE][regoffset] |= mask;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void stmpe_dbg_show_one(struct seq_file *s,
 | 
			
		||||
			       struct gpio_chip *gc,
 | 
			
		||||
			       unsigned offset, unsigned gpio)
 | 
			
		||||
{
 | 
			
		||||
	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc);
 | 
			
		||||
	struct stmpe *stmpe = stmpe_gpio->stmpe;
 | 
			
		||||
	const char *label = gpiochip_is_requested(gc, offset);
 | 
			
		||||
	int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
 | 
			
		||||
	bool val = !!stmpe_gpio_get(gc, offset);
 | 
			
		||||
	u8 dir_reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
 | 
			
		||||
	u8 mask = 1 << (offset % 8);
 | 
			
		||||
	int ret;
 | 
			
		||||
	u8 dir;
 | 
			
		||||
 | 
			
		||||
	ret = stmpe_reg_read(stmpe, dir_reg);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return;
 | 
			
		||||
	dir = !!(ret & mask);
 | 
			
		||||
 | 
			
		||||
	if (dir) {
 | 
			
		||||
		seq_printf(s, " gpio-%-3d (%-20.20s) out %s",
 | 
			
		||||
			   gpio, label ?: "(none)",
 | 
			
		||||
			   val ? "hi" : "lo");
 | 
			
		||||
	} else {
 | 
			
		||||
		u8 edge_det_reg = stmpe->regs[STMPE_IDX_GPEDR_MSB] + num_banks - 1 - (offset / 8);
 | 
			
		||||
		u8 rise_reg = stmpe->regs[STMPE_IDX_GPRER_LSB] - (offset / 8);
 | 
			
		||||
		u8 fall_reg = stmpe->regs[STMPE_IDX_GPFER_LSB] - (offset / 8);
 | 
			
		||||
		u8 irqen_reg = stmpe->regs[STMPE_IDX_IEGPIOR_LSB] - (offset / 8);
 | 
			
		||||
		bool edge_det;
 | 
			
		||||
		bool rise;
 | 
			
		||||
		bool fall;
 | 
			
		||||
		bool irqen;
 | 
			
		||||
 | 
			
		||||
		ret = stmpe_reg_read(stmpe, edge_det_reg);
 | 
			
		||||
		if (ret < 0)
 | 
			
		||||
			return;
 | 
			
		||||
		edge_det = !!(ret & mask);
 | 
			
		||||
		ret = stmpe_reg_read(stmpe, rise_reg);
 | 
			
		||||
		if (ret < 0)
 | 
			
		||||
			return;
 | 
			
		||||
		rise = !!(ret & mask);
 | 
			
		||||
		ret = stmpe_reg_read(stmpe, fall_reg);
 | 
			
		||||
		if (ret < 0)
 | 
			
		||||
			return;
 | 
			
		||||
		fall = !!(ret & mask);
 | 
			
		||||
		ret = stmpe_reg_read(stmpe, irqen_reg);
 | 
			
		||||
		if (ret < 0)
 | 
			
		||||
			return;
 | 
			
		||||
		irqen = !!(ret & mask);
 | 
			
		||||
 | 
			
		||||
		seq_printf(s, " gpio-%-3d (%-20.20s) in  %s %s %s%s%s",
 | 
			
		||||
			   gpio, label ?: "(none)",
 | 
			
		||||
			   val ? "hi" : "lo",
 | 
			
		||||
			   edge_det ? "edge-asserted" : "edge-inactive",
 | 
			
		||||
			   irqen ? "IRQ-enabled" : "",
 | 
			
		||||
			   rise ? " rising-edge-detection" : "",
 | 
			
		||||
			   fall ? " falling-edge-detection" : "");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void stmpe_dbg_show(struct seq_file *s, struct gpio_chip *gc)
 | 
			
		||||
{
 | 
			
		||||
	unsigned i;
 | 
			
		||||
	unsigned gpio = gc->base;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < gc->ngpio; i++, gpio++) {
 | 
			
		||||
		stmpe_dbg_show_one(s, gc, i, gpio);
 | 
			
		||||
		seq_printf(s, "\n");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct irq_chip stmpe_gpio_irq_chip = {
 | 
			
		||||
	.name			= "stmpe-gpio",
 | 
			
		||||
	.irq_bus_lock		= stmpe_gpio_irq_lock,
 | 
			
		||||
| 
						 | 
				
			
			@ -293,6 +365,9 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
 | 
			
		|||
#endif
 | 
			
		||||
	stmpe_gpio->chip.base = -1;
 | 
			
		||||
 | 
			
		||||
	if (IS_ENABLED(CONFIG_DEBUG_FS))
 | 
			
		||||
                stmpe_gpio->chip.dbg_show = stmpe_dbg_show;
 | 
			
		||||
 | 
			
		||||
	if (pdata)
 | 
			
		||||
		stmpe_gpio->norequest_mask = pdata->norequest_mask;
 | 
			
		||||
	else if (np)
 | 
			
		||||
| 
						 | 
				
			
			@ -308,6 +383,12 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
 | 
			
		|||
	if (ret)
 | 
			
		||||
		goto out_free;
 | 
			
		||||
 | 
			
		||||
	ret = gpiochip_add(&stmpe_gpio->chip);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
 | 
			
		||||
		goto out_disable;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (irq > 0) {
 | 
			
		||||
		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
 | 
			
		||||
				stmpe_gpio_irq, IRQF_ONESHOT,
 | 
			
		||||
| 
						 | 
				
			
			@ -324,14 +405,13 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
 | 
			
		|||
		if (ret) {
 | 
			
		||||
			dev_err(&pdev->dev,
 | 
			
		||||
				"could not connect irqchip to gpiochip\n");
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
			goto out_disable;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	ret = gpiochip_add(&stmpe_gpio->chip);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
 | 
			
		||||
		goto out_disable;
 | 
			
		||||
		gpiochip_set_chained_irqchip(&stmpe_gpio->chip,
 | 
			
		||||
					     &stmpe_gpio_irq_chip,
 | 
			
		||||
					     irq,
 | 
			
		||||
					     NULL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (pdata && pdata->setup)
 | 
			
		||||
| 
						 | 
				
			
			@ -343,6 +423,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
 | 
			
		|||
 | 
			
		||||
out_disable:
 | 
			
		||||
	stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
 | 
			
		||||
	gpiochip_remove(&stmpe_gpio->chip);
 | 
			
		||||
out_free:
 | 
			
		||||
	kfree(stmpe_gpio);
 | 
			
		||||
	return ret;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -292,7 +292,7 @@ static struct platform_driver xway_stp_driver = {
 | 
			
		|||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int __init xway_stp_init(void)
 | 
			
		||||
static int __init xway_stp_init(void)
 | 
			
		||||
{
 | 
			
		||||
	return platform_driver_register(&xway_stp_driver);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,6 +37,8 @@
 | 
			
		|||
 * dat_bit_offset:	Offset (in bits) to the first GPIO bit.
 | 
			
		||||
 * dir_bit_offset:	Optional offset (in bits) to the first bit to switch
 | 
			
		||||
 *			GPIO direction (Used with GPIO_SYSCON_FEAT_DIR flag).
 | 
			
		||||
 * set:		HW specific callback to assigns output value
 | 
			
		||||
 *			for signal "offset"
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
struct syscon_gpio_data {
 | 
			
		||||
| 
						 | 
				
			
			@ -45,12 +47,16 @@ struct syscon_gpio_data {
 | 
			
		|||
	unsigned int	bit_count;
 | 
			
		||||
	unsigned int	dat_bit_offset;
 | 
			
		||||
	unsigned int	dir_bit_offset;
 | 
			
		||||
	void		(*set)(struct gpio_chip *chip,
 | 
			
		||||
			       unsigned offset, int value);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct syscon_gpio_priv {
 | 
			
		||||
	struct gpio_chip		chip;
 | 
			
		||||
	struct regmap			*syscon;
 | 
			
		||||
	const struct syscon_gpio_data	*data;
 | 
			
		||||
	u32				dreg_offset;
 | 
			
		||||
	u32				dir_reg_offset;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline struct syscon_gpio_priv *to_syscon_gpio(struct gpio_chip *chip)
 | 
			
		||||
| 
						 | 
				
			
			@ -61,9 +67,11 @@ static inline struct syscon_gpio_priv *to_syscon_gpio(struct gpio_chip *chip)
 | 
			
		|||
static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset)
 | 
			
		||||
{
 | 
			
		||||
	struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
 | 
			
		||||
	unsigned int val, offs = priv->data->dat_bit_offset + offset;
 | 
			
		||||
	unsigned int val, offs;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	offs = priv->dreg_offset + priv->data->dat_bit_offset + offset;
 | 
			
		||||
 | 
			
		||||
	ret = regmap_read(priv->syscon,
 | 
			
		||||
			  (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, &val);
 | 
			
		||||
	if (ret)
 | 
			
		||||
| 
						 | 
				
			
			@ -75,7 +83,9 @@ static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset)
 | 
			
		|||
static void syscon_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
 | 
			
		||||
{
 | 
			
		||||
	struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
 | 
			
		||||
	unsigned int offs = priv->data->dat_bit_offset + offset;
 | 
			
		||||
	unsigned int offs;
 | 
			
		||||
 | 
			
		||||
	offs = priv->dreg_offset + priv->data->dat_bit_offset + offset;
 | 
			
		||||
 | 
			
		||||
	regmap_update_bits(priv->syscon,
 | 
			
		||||
			   (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
 | 
			
		||||
| 
						 | 
				
			
			@ -88,7 +98,10 @@ static int syscon_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
 | 
			
		|||
	struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
 | 
			
		||||
 | 
			
		||||
	if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) {
 | 
			
		||||
		unsigned int offs = priv->data->dir_bit_offset + offset;
 | 
			
		||||
		unsigned int offs;
 | 
			
		||||
 | 
			
		||||
		offs = priv->dir_reg_offset +
 | 
			
		||||
		       priv->data->dir_bit_offset + offset;
 | 
			
		||||
 | 
			
		||||
		regmap_update_bits(priv->syscon,
 | 
			
		||||
				   (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
 | 
			
		||||
| 
						 | 
				
			
			@ -103,7 +116,10 @@ static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val)
 | 
			
		|||
	struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
 | 
			
		||||
 | 
			
		||||
	if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) {
 | 
			
		||||
		unsigned int offs = priv->data->dir_bit_offset + offset;
 | 
			
		||||
		unsigned int offs;
 | 
			
		||||
 | 
			
		||||
		offs = priv->dir_reg_offset +
 | 
			
		||||
		       priv->data->dir_bit_offset + offset;
 | 
			
		||||
 | 
			
		||||
		regmap_update_bits(priv->syscon,
 | 
			
		||||
				   (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
 | 
			
		||||
| 
						 | 
				
			
			@ -111,7 +127,7 @@ static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val)
 | 
			
		|||
				   BIT(offs % SYSCON_REG_BITS));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	syscon_gpio_set(chip, offset, val);
 | 
			
		||||
	priv->data->set(chip, offset, val);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -124,11 +140,46 @@ static const struct syscon_gpio_data clps711x_mctrl_gpio = {
 | 
			
		|||
	.dat_bit_offset	= 0x40 * 8 + 8,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define KEYSTONE_LOCK_BIT BIT(0)
 | 
			
		||||
 | 
			
		||||
static void keystone_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
 | 
			
		||||
{
 | 
			
		||||
	struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
 | 
			
		||||
	unsigned int offs;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	offs = priv->dreg_offset + priv->data->dat_bit_offset + offset;
 | 
			
		||||
 | 
			
		||||
	if (!val)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	ret = regmap_update_bits(
 | 
			
		||||
			priv->syscon,
 | 
			
		||||
			(offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
 | 
			
		||||
			BIT(offs % SYSCON_REG_BITS) | KEYSTONE_LOCK_BIT,
 | 
			
		||||
			BIT(offs % SYSCON_REG_BITS) | KEYSTONE_LOCK_BIT);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		dev_err(chip->dev, "gpio write failed ret(%d)\n", ret);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct syscon_gpio_data keystone_dsp_gpio = {
 | 
			
		||||
	/* ARM Keystone 2 */
 | 
			
		||||
	.compatible	= NULL,
 | 
			
		||||
	.flags		= GPIO_SYSCON_FEAT_OUT,
 | 
			
		||||
	.bit_count	= 28,
 | 
			
		||||
	.dat_bit_offset	= 4,
 | 
			
		||||
	.set		= keystone_gpio_set,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct of_device_id syscon_gpio_ids[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.compatible	= "cirrus,clps711x-mctrl-gpio",
 | 
			
		||||
		.data		= &clps711x_mctrl_gpio,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.compatible	= "ti,keystone-dsp-gpio",
 | 
			
		||||
		.data		= &keystone_dsp_gpio,
 | 
			
		||||
	},
 | 
			
		||||
	{ }
 | 
			
		||||
};
 | 
			
		||||
MODULE_DEVICE_TABLE(of, syscon_gpio_ids);
 | 
			
		||||
| 
						 | 
				
			
			@ -138,6 +189,8 @@ static int syscon_gpio_probe(struct platform_device *pdev)
 | 
			
		|||
	struct device *dev = &pdev->dev;
 | 
			
		||||
	const struct of_device_id *of_id = of_match_device(syscon_gpio_ids, dev);
 | 
			
		||||
	struct syscon_gpio_priv *priv;
 | 
			
		||||
	struct device_node *np = dev->of_node;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 | 
			
		||||
	if (!priv)
 | 
			
		||||
| 
						 | 
				
			
			@ -145,10 +198,31 @@ static int syscon_gpio_probe(struct platform_device *pdev)
 | 
			
		|||
 | 
			
		||||
	priv->data = of_id->data;
 | 
			
		||||
 | 
			
		||||
	priv->syscon =
 | 
			
		||||
		syscon_regmap_lookup_by_compatible(priv->data->compatible);
 | 
			
		||||
	if (priv->data->compatible) {
 | 
			
		||||
		priv->syscon = syscon_regmap_lookup_by_compatible(
 | 
			
		||||
					priv->data->compatible);
 | 
			
		||||
		if (IS_ERR(priv->syscon))
 | 
			
		||||
			return PTR_ERR(priv->syscon);
 | 
			
		||||
	} else {
 | 
			
		||||
		priv->syscon =
 | 
			
		||||
			syscon_regmap_lookup_by_phandle(np, "gpio,syscon-dev");
 | 
			
		||||
		if (IS_ERR(priv->syscon))
 | 
			
		||||
			return PTR_ERR(priv->syscon);
 | 
			
		||||
 | 
			
		||||
		ret = of_property_read_u32_index(np, "gpio,syscon-dev", 1,
 | 
			
		||||
						 &priv->dreg_offset);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			dev_err(dev, "can't read the data register offset!\n");
 | 
			
		||||
 | 
			
		||||
		priv->dreg_offset <<= 3;
 | 
			
		||||
 | 
			
		||||
		ret = of_property_read_u32_index(np, "gpio,syscon-dev", 2,
 | 
			
		||||
						 &priv->dir_reg_offset);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			dev_err(dev, "can't read the dir register offset!\n");
 | 
			
		||||
 | 
			
		||||
		priv->dir_reg_offset <<= 3;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	priv->chip.dev = dev;
 | 
			
		||||
	priv->chip.owner = THIS_MODULE;
 | 
			
		||||
| 
						 | 
				
			
			@ -159,7 +233,7 @@ static int syscon_gpio_probe(struct platform_device *pdev)
 | 
			
		|||
	if (priv->data->flags & GPIO_SYSCON_FEAT_IN)
 | 
			
		||||
		priv->chip.direction_input = syscon_gpio_dir_in;
 | 
			
		||||
	if (priv->data->flags & GPIO_SYSCON_FEAT_OUT) {
 | 
			
		||||
		priv->chip.set = syscon_gpio_set;
 | 
			
		||||
		priv->chip.set = priv->data->set ? : syscon_gpio_set;
 | 
			
		||||
		priv->chip.direction_output = syscon_gpio_dir_out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -300,6 +300,11 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
 | 
			
		|||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gpiochip_set_chained_irqchip(&tc3589x_gpio->chip,
 | 
			
		||||
				     &tc3589x_gpio_irq_chip,
 | 
			
		||||
				     irq,
 | 
			
		||||
				     NULL);
 | 
			
		||||
 | 
			
		||||
	if (pdata && pdata->setup)
 | 
			
		||||
		pdata->setup(tc3589x, tc3589x_gpio->chip.base);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										244
									
								
								drivers/gpio/gpio-xgene.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								drivers/gpio/gpio-xgene.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,244 @@
 | 
			
		|||
/*
 | 
			
		||||
 * AppliedMicro X-Gene SoC GPIO Driver
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2014, Applied Micro Circuits Corporation
 | 
			
		||||
 * Author: Feng Kan <fkan@apm.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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <linux/kernel.h>
 | 
			
		||||
#include <linux/init.h>
 | 
			
		||||
#include <linux/io.h>
 | 
			
		||||
#include <linux/spinlock.h>
 | 
			
		||||
#include <linux/platform_device.h>
 | 
			
		||||
#include <linux/gpio/driver.h>
 | 
			
		||||
#include <linux/types.h>
 | 
			
		||||
#include <linux/bitops.h>
 | 
			
		||||
 | 
			
		||||
#define GPIO_SET_DR_OFFSET	0x0C
 | 
			
		||||
#define GPIO_DATA_OFFSET	0x14
 | 
			
		||||
#define GPIO_BANK_STRIDE	0x0C
 | 
			
		||||
 | 
			
		||||
#define XGENE_GPIOS_PER_BANK	16
 | 
			
		||||
#define XGENE_MAX_GPIO_BANKS	3
 | 
			
		||||
#define XGENE_MAX_GPIOS		(XGENE_GPIOS_PER_BANK * XGENE_MAX_GPIO_BANKS)
 | 
			
		||||
 | 
			
		||||
#define GPIO_BIT_OFFSET(x)	(x % XGENE_GPIOS_PER_BANK)
 | 
			
		||||
#define GPIO_BANK_OFFSET(x)	((x / XGENE_GPIOS_PER_BANK) * GPIO_BANK_STRIDE)
 | 
			
		||||
 | 
			
		||||
struct xgene_gpio {
 | 
			
		||||
	struct gpio_chip	chip;
 | 
			
		||||
	void __iomem		*base;
 | 
			
		||||
	spinlock_t		lock;
 | 
			
		||||
#ifdef CONFIG_PM
 | 
			
		||||
	u32			set_dr_val[XGENE_MAX_GPIO_BANKS];
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline struct xgene_gpio *to_xgene_gpio(struct gpio_chip *chip)
 | 
			
		||||
{
 | 
			
		||||
	return container_of(chip, struct xgene_gpio, chip);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int xgene_gpio_get(struct gpio_chip *gc, unsigned int offset)
 | 
			
		||||
{
 | 
			
		||||
	struct xgene_gpio *chip = to_xgene_gpio(gc);
 | 
			
		||||
	unsigned long bank_offset;
 | 
			
		||||
	u32 bit_offset;
 | 
			
		||||
 | 
			
		||||
	bank_offset = GPIO_DATA_OFFSET + GPIO_BANK_OFFSET(offset);
 | 
			
		||||
	bit_offset = GPIO_BIT_OFFSET(offset);
 | 
			
		||||
	return !!(ioread32(chip->base + bank_offset) & BIT(bit_offset));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
 | 
			
		||||
{
 | 
			
		||||
	struct xgene_gpio *chip = to_xgene_gpio(gc);
 | 
			
		||||
	unsigned long bank_offset;
 | 
			
		||||
	u32 setval, bit_offset;
 | 
			
		||||
 | 
			
		||||
	bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset);
 | 
			
		||||
	bit_offset = GPIO_BIT_OFFSET(offset) + XGENE_GPIOS_PER_BANK;
 | 
			
		||||
 | 
			
		||||
	setval = ioread32(chip->base + bank_offset);
 | 
			
		||||
	if (val)
 | 
			
		||||
		setval |= BIT(bit_offset);
 | 
			
		||||
	else
 | 
			
		||||
		setval &= ~BIT(bit_offset);
 | 
			
		||||
	iowrite32(setval, chip->base + bank_offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
 | 
			
		||||
{
 | 
			
		||||
	struct xgene_gpio *chip = to_xgene_gpio(gc);
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&chip->lock, flags);
 | 
			
		||||
	__xgene_gpio_set(gc, offset, val);
 | 
			
		||||
	spin_unlock_irqrestore(&chip->lock, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int xgene_gpio_dir_in(struct gpio_chip *gc, unsigned int offset)
 | 
			
		||||
{
 | 
			
		||||
	struct xgene_gpio *chip = to_xgene_gpio(gc);
 | 
			
		||||
	unsigned long flags, bank_offset;
 | 
			
		||||
	u32 dirval, bit_offset;
 | 
			
		||||
 | 
			
		||||
	bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset);
 | 
			
		||||
	bit_offset = GPIO_BIT_OFFSET(offset);
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&chip->lock, flags);
 | 
			
		||||
 | 
			
		||||
	dirval = ioread32(chip->base + bank_offset);
 | 
			
		||||
	dirval |= BIT(bit_offset);
 | 
			
		||||
	iowrite32(dirval, chip->base + bank_offset);
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irqrestore(&chip->lock, flags);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int xgene_gpio_dir_out(struct gpio_chip *gc,
 | 
			
		||||
					unsigned int offset, int val)
 | 
			
		||||
{
 | 
			
		||||
	struct xgene_gpio *chip = to_xgene_gpio(gc);
 | 
			
		||||
	unsigned long flags, bank_offset;
 | 
			
		||||
	u32 dirval, bit_offset;
 | 
			
		||||
 | 
			
		||||
	bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset);
 | 
			
		||||
	bit_offset = GPIO_BIT_OFFSET(offset);
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&chip->lock, flags);
 | 
			
		||||
 | 
			
		||||
	dirval = ioread32(chip->base + bank_offset);
 | 
			
		||||
	dirval &= ~BIT(bit_offset);
 | 
			
		||||
	iowrite32(dirval, chip->base + bank_offset);
 | 
			
		||||
	__xgene_gpio_set(gc, offset, val);
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irqrestore(&chip->lock, flags);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PM
 | 
			
		||||
static int xgene_gpio_suspend(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct xgene_gpio *gpio = dev_get_drvdata(dev);
 | 
			
		||||
	unsigned long bank_offset;
 | 
			
		||||
	unsigned int bank;
 | 
			
		||||
 | 
			
		||||
	for (bank = 0; bank < XGENE_MAX_GPIO_BANKS; bank++) {
 | 
			
		||||
		bank_offset = GPIO_SET_DR_OFFSET + bank * GPIO_BANK_STRIDE;
 | 
			
		||||
		gpio->set_dr_val[bank] = ioread32(gpio->base + bank_offset);
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int xgene_gpio_resume(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct xgene_gpio *gpio = dev_get_drvdata(dev);
 | 
			
		||||
	unsigned long bank_offset;
 | 
			
		||||
	unsigned int bank;
 | 
			
		||||
 | 
			
		||||
	for (bank = 0; bank < XGENE_MAX_GPIO_BANKS; bank++) {
 | 
			
		||||
		bank_offset = GPIO_SET_DR_OFFSET + bank * GPIO_BANK_STRIDE;
 | 
			
		||||
		iowrite32(gpio->set_dr_val[bank], gpio->base + bank_offset);
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static SIMPLE_DEV_PM_OPS(xgene_gpio_pm, xgene_gpio_suspend, xgene_gpio_resume);
 | 
			
		||||
#define XGENE_GPIO_PM_OPS	(&xgene_gpio_pm)
 | 
			
		||||
#else
 | 
			
		||||
#define XGENE_GPIO_PM_OPS	NULL
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static int xgene_gpio_probe(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct resource *res;
 | 
			
		||||
	struct xgene_gpio *gpio;
 | 
			
		||||
	int err = 0;
 | 
			
		||||
 | 
			
		||||
	gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
 | 
			
		||||
	if (!gpio) {
 | 
			
		||||
		err = -ENOMEM;
 | 
			
		||||
		goto err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 | 
			
		||||
	gpio->base = devm_ioremap_nocache(&pdev->dev, res->start,
 | 
			
		||||
							resource_size(res));
 | 
			
		||||
	if (!gpio->base) {
 | 
			
		||||
		err = -ENOMEM;
 | 
			
		||||
		goto err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gpio->chip.ngpio = XGENE_MAX_GPIOS;
 | 
			
		||||
 | 
			
		||||
	spin_lock_init(&gpio->lock);
 | 
			
		||||
	gpio->chip.dev = &pdev->dev;
 | 
			
		||||
	gpio->chip.direction_input = xgene_gpio_dir_in;
 | 
			
		||||
	gpio->chip.direction_output = xgene_gpio_dir_out;
 | 
			
		||||
	gpio->chip.get = xgene_gpio_get;
 | 
			
		||||
	gpio->chip.set = xgene_gpio_set;
 | 
			
		||||
	gpio->chip.label = dev_name(&pdev->dev);
 | 
			
		||||
	gpio->chip.base = -1;
 | 
			
		||||
 | 
			
		||||
	platform_set_drvdata(pdev, gpio);
 | 
			
		||||
 | 
			
		||||
	err = gpiochip_add(&gpio->chip);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		dev_err(&pdev->dev,
 | 
			
		||||
			"failed to register gpiochip.\n");
 | 
			
		||||
		goto err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dev_info(&pdev->dev, "X-Gene GPIO driver registered.\n");
 | 
			
		||||
	return 0;
 | 
			
		||||
err:
 | 
			
		||||
	dev_err(&pdev->dev, "X-Gene GPIO driver registration failed.\n");
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int xgene_gpio_remove(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct xgene_gpio *gpio = platform_get_drvdata(pdev);
 | 
			
		||||
 | 
			
		||||
	gpiochip_remove(&gpio->chip);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct of_device_id xgene_gpio_of_match[] = {
 | 
			
		||||
	{ .compatible = "apm,xgene-gpio", },
 | 
			
		||||
	{},
 | 
			
		||||
};
 | 
			
		||||
MODULE_DEVICE_TABLE(of, xgene_gpio_of_match);
 | 
			
		||||
 | 
			
		||||
static struct platform_driver xgene_gpio_driver = {
 | 
			
		||||
	.driver = {
 | 
			
		||||
		.name = "xgene-gpio",
 | 
			
		||||
		.owner = THIS_MODULE,
 | 
			
		||||
		.of_match_table = xgene_gpio_of_match,
 | 
			
		||||
		.pm     = XGENE_GPIO_PM_OPS,
 | 
			
		||||
	},
 | 
			
		||||
	.probe = xgene_gpio_probe,
 | 
			
		||||
	.remove = xgene_gpio_remove,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module_platform_driver(xgene_gpio_driver);
 | 
			
		||||
 | 
			
		||||
MODULE_AUTHOR("Feng Kan <fkan@apm.com>");
 | 
			
		||||
MODULE_DESCRIPTION("APM X-Gene GPIO driver");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
| 
						 | 
				
			
			@ -197,6 +197,7 @@ static int xgpio_of_probe(struct device_node *np)
 | 
			
		|||
	struct xgpio_instance *chip;
 | 
			
		||||
	int status = 0;
 | 
			
		||||
	const u32 *tree_info;
 | 
			
		||||
	u32 ngpio;
 | 
			
		||||
 | 
			
		||||
	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
 | 
			
		||||
	if (!chip)
 | 
			
		||||
| 
						 | 
				
			
			@ -211,12 +212,13 @@ static int xgpio_of_probe(struct device_node *np)
 | 
			
		|||
	/* Update GPIO direction shadow register with default value */
 | 
			
		||||
	of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir);
 | 
			
		||||
 | 
			
		||||
	/* By default assume full GPIO controller */
 | 
			
		||||
	chip->mmchip.gc.ngpio = 32;
 | 
			
		||||
 | 
			
		||||
	/* Check device node and parent device node for device width */
 | 
			
		||||
	of_property_read_u32(np, "xlnx,gpio-width",
 | 
			
		||||
			      (u32 *)&chip->mmchip.gc.ngpio);
 | 
			
		||||
	/*
 | 
			
		||||
	 * Check device node and parent device node for device width
 | 
			
		||||
	 * and assume default width of 32
 | 
			
		||||
	 */
 | 
			
		||||
	if (of_property_read_u32(np, "xlnx,gpio-width", &ngpio))
 | 
			
		||||
		ngpio = 32;
 | 
			
		||||
	chip->mmchip.gc.ngpio = (u16)ngpio;
 | 
			
		||||
 | 
			
		||||
	spin_lock_init(&chip->gpio_lock);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -258,12 +260,13 @@ static int xgpio_of_probe(struct device_node *np)
 | 
			
		|||
		/* Update GPIO direction shadow register with default value */
 | 
			
		||||
		of_property_read_u32(np, "xlnx,tri-default-2", &chip->gpio_dir);
 | 
			
		||||
 | 
			
		||||
		/* By default assume full GPIO controller */
 | 
			
		||||
		chip->mmchip.gc.ngpio = 32;
 | 
			
		||||
 | 
			
		||||
		/* Check device node and parent device node for device width */
 | 
			
		||||
		of_property_read_u32(np, "xlnx,gpio2-width",
 | 
			
		||||
				     (u32 *)&chip->mmchip.gc.ngpio);
 | 
			
		||||
		/*
 | 
			
		||||
		 * Check device node and parent device node for device width
 | 
			
		||||
		 * and assume default width of 32
 | 
			
		||||
		 */
 | 
			
		||||
		if (of_property_read_u32(np, "xlnx,gpio2-width", &ngpio))
 | 
			
		||||
			ngpio = 32;
 | 
			
		||||
		chip->mmchip.gc.ngpio = (u16)ngpio;
 | 
			
		||||
 | 
			
		||||
		spin_lock_init(&chip->gpio_lock);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -88,16 +88,17 @@
 | 
			
		|||
 * @chip:	instance of the gpio_chip
 | 
			
		||||
 * @base_addr:	base address of the GPIO device
 | 
			
		||||
 * @clk:	clock resource for this controller
 | 
			
		||||
 * @irq:	interrupt for the GPIO device
 | 
			
		||||
 */
 | 
			
		||||
struct zynq_gpio {
 | 
			
		||||
	struct gpio_chip chip;
 | 
			
		||||
	void __iomem *base_addr;
 | 
			
		||||
	struct clk *clk;
 | 
			
		||||
	int irq;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct irq_chip zynq_gpio_level_irqchip;
 | 
			
		||||
static struct irq_chip zynq_gpio_edge_irqchip;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * zynq_gpio_get_bank_pin - Get the bank number and pin number within that bank
 | 
			
		||||
 * for a given pin in the GPIO device
 | 
			
		||||
| 
						 | 
				
			
			@ -138,6 +139,13 @@ static inline void zynq_gpio_get_bank_pin(unsigned int pin_num,
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const unsigned int zynq_gpio_bank_offset[] = {
 | 
			
		||||
	ZYNQ_GPIO_BANK0_PIN_MIN,
 | 
			
		||||
	ZYNQ_GPIO_BANK1_PIN_MIN,
 | 
			
		||||
	ZYNQ_GPIO_BANK2_PIN_MIN,
 | 
			
		||||
	ZYNQ_GPIO_BANK3_PIN_MIN,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * zynq_gpio_get_value - Get the state of the specified pin of GPIO device
 | 
			
		||||
 * @chip:	gpio_chip instance to be worked on
 | 
			
		||||
| 
						 | 
				
			
			@ -427,10 +435,9 @@ static int zynq_gpio_set_irq_type(struct irq_data *irq_data, unsigned int type)
 | 
			
		|||
 | 
			
		||||
static int zynq_gpio_set_wake(struct irq_data *data, unsigned int on)
 | 
			
		||||
{
 | 
			
		||||
	if (on)
 | 
			
		||||
		zynq_gpio_irq_unmask(data);
 | 
			
		||||
	else
 | 
			
		||||
		zynq_gpio_irq_mask(data);
 | 
			
		||||
	struct zynq_gpio *gpio = irq_data_get_irq_chip_data(data);
 | 
			
		||||
 | 
			
		||||
	irq_set_irq_wake(gpio->irq, on);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -444,7 +451,8 @@ static struct irq_chip zynq_gpio_level_irqchip = {
 | 
			
		|||
	.irq_unmask	= zynq_gpio_irq_unmask,
 | 
			
		||||
	.irq_set_type	= zynq_gpio_set_irq_type,
 | 
			
		||||
	.irq_set_wake	= zynq_gpio_set_wake,
 | 
			
		||||
	.flags		= IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED,
 | 
			
		||||
	.flags		= IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED |
 | 
			
		||||
			  IRQCHIP_MASK_ON_SUSPEND,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct irq_chip zynq_gpio_edge_irqchip = {
 | 
			
		||||
| 
						 | 
				
			
			@ -455,8 +463,28 @@ static struct irq_chip zynq_gpio_edge_irqchip = {
 | 
			
		|||
	.irq_unmask	= zynq_gpio_irq_unmask,
 | 
			
		||||
	.irq_set_type	= zynq_gpio_set_irq_type,
 | 
			
		||||
	.irq_set_wake	= zynq_gpio_set_wake,
 | 
			
		||||
	.flags		= IRQCHIP_MASK_ON_SUSPEND,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void zynq_gpio_handle_bank_irq(struct zynq_gpio *gpio,
 | 
			
		||||
				      unsigned int bank_num,
 | 
			
		||||
				      unsigned long pending)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int bank_offset = zynq_gpio_bank_offset[bank_num];
 | 
			
		||||
	struct irq_domain *irqdomain = gpio->chip.irqdomain;
 | 
			
		||||
	int offset;
 | 
			
		||||
 | 
			
		||||
	if (!pending)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	for_each_set_bit(offset, &pending, 32) {
 | 
			
		||||
		unsigned int gpio_irq;
 | 
			
		||||
 | 
			
		||||
		gpio_irq = irq_find_mapping(irqdomain, offset + bank_offset);
 | 
			
		||||
		generic_handle_irq(gpio_irq);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * zynq_gpio_irqhandler - IRQ handler for the gpio banks of a gpio device
 | 
			
		||||
 * @irq:	irq number of the gpio bank where interrupt has occurred
 | 
			
		||||
| 
						 | 
				
			
			@ -482,18 +510,7 @@ static void zynq_gpio_irqhandler(unsigned int irq, struct irq_desc *desc)
 | 
			
		|||
					ZYNQ_GPIO_INTSTS_OFFSET(bank_num));
 | 
			
		||||
		int_enb = readl_relaxed(gpio->base_addr +
 | 
			
		||||
					ZYNQ_GPIO_INTMASK_OFFSET(bank_num));
 | 
			
		||||
		int_sts &= ~int_enb;
 | 
			
		||||
		if (int_sts) {
 | 
			
		||||
			int offset;
 | 
			
		||||
			unsigned long pending = int_sts;
 | 
			
		||||
 | 
			
		||||
			for_each_set_bit(offset, &pending, 32) {
 | 
			
		||||
				unsigned int gpio_irq =
 | 
			
		||||
					irq_find_mapping(gpio->chip.irqdomain,
 | 
			
		||||
							offset);
 | 
			
		||||
				generic_handle_irq(gpio_irq);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		zynq_gpio_handle_bank_irq(gpio, bank_num, int_sts & ~int_enb);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	chained_irq_exit(irqchip, desc);
 | 
			
		||||
| 
						 | 
				
			
			@ -501,7 +518,11 @@ static void zynq_gpio_irqhandler(unsigned int irq, struct irq_desc *desc)
 | 
			
		|||
 | 
			
		||||
static int __maybe_unused zynq_gpio_suspend(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	if (!device_may_wakeup(dev))
 | 
			
		||||
	struct platform_device *pdev = to_platform_device(dev);
 | 
			
		||||
	int irq = platform_get_irq(pdev, 0);
 | 
			
		||||
	struct irq_data *data = irq_get_irq_data(irq);
 | 
			
		||||
 | 
			
		||||
	if (!irqd_is_wakeup_set(data))
 | 
			
		||||
		return pm_runtime_force_suspend(dev);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -509,7 +530,11 @@ static int __maybe_unused zynq_gpio_suspend(struct device *dev)
 | 
			
		|||
 | 
			
		||||
static int __maybe_unused zynq_gpio_resume(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	if (!device_may_wakeup(dev))
 | 
			
		||||
	struct platform_device *pdev = to_platform_device(dev);
 | 
			
		||||
	int irq = platform_get_irq(pdev, 0);
 | 
			
		||||
	struct irq_data *data = irq_get_irq_data(irq);
 | 
			
		||||
 | 
			
		||||
	if (!irqd_is_wakeup_set(data))
 | 
			
		||||
		return pm_runtime_force_resume(dev);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -570,7 +595,7 @@ static const struct dev_pm_ops zynq_gpio_dev_pm_ops = {
 | 
			
		|||
 */
 | 
			
		||||
static int zynq_gpio_probe(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	int ret, bank_num, irq;
 | 
			
		||||
	int ret, bank_num;
 | 
			
		||||
	struct zynq_gpio *gpio;
 | 
			
		||||
	struct gpio_chip *chip;
 | 
			
		||||
	struct resource *res;
 | 
			
		||||
| 
						 | 
				
			
			@ -586,10 +611,10 @@ static int zynq_gpio_probe(struct platform_device *pdev)
 | 
			
		|||
	if (IS_ERR(gpio->base_addr))
 | 
			
		||||
		return PTR_ERR(gpio->base_addr);
 | 
			
		||||
 | 
			
		||||
	irq = platform_get_irq(pdev, 0);
 | 
			
		||||
	if (irq < 0) {
 | 
			
		||||
	gpio->irq = platform_get_irq(pdev, 0);
 | 
			
		||||
	if (gpio->irq < 0) {
 | 
			
		||||
		dev_err(&pdev->dev, "invalid IRQ\n");
 | 
			
		||||
		return irq;
 | 
			
		||||
		return gpio->irq;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* configure the gpio chip */
 | 
			
		||||
| 
						 | 
				
			
			@ -637,19 +662,16 @@ static int zynq_gpio_probe(struct platform_device *pdev)
 | 
			
		|||
		goto err_rm_gpiochip;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gpiochip_set_chained_irqchip(chip, &zynq_gpio_edge_irqchip, irq,
 | 
			
		||||
	gpiochip_set_chained_irqchip(chip, &zynq_gpio_edge_irqchip, gpio->irq,
 | 
			
		||||
				     zynq_gpio_irqhandler);
 | 
			
		||||
 | 
			
		||||
	pm_runtime_set_active(&pdev->dev);
 | 
			
		||||
	pm_runtime_enable(&pdev->dev);
 | 
			
		||||
 | 
			
		||||
	device_set_wakeup_capable(&pdev->dev, 1);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_rm_gpiochip:
 | 
			
		||||
	if (gpiochip_remove(chip))
 | 
			
		||||
		dev_err(&pdev->dev, "Failed to remove gpio chip\n");
 | 
			
		||||
	gpiochip_remove(chip);
 | 
			
		||||
err_disable_clk:
 | 
			
		||||
	clk_disable_unprepare(gpio->clk);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -664,16 +686,10 @@ err_disable_clk:
 | 
			
		|||
 */
 | 
			
		||||
static int zynq_gpio_remove(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	struct zynq_gpio *gpio = platform_get_drvdata(pdev);
 | 
			
		||||
 | 
			
		||||
	pm_runtime_get_sync(&pdev->dev);
 | 
			
		||||
 | 
			
		||||
	ret = gpiochip_remove(&gpio->chip);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		dev_err(&pdev->dev, "Failed to remove gpio chip\n");
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	gpiochip_remove(&gpio->chip);
 | 
			
		||||
	clk_disable_unprepare(gpio->clk);
 | 
			
		||||
	device_set_wakeup_capable(&pdev->dev, 0);
 | 
			
		||||
	return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -688,7 +704,6 @@ MODULE_DEVICE_TABLE(of, zynq_gpio_of_match);
 | 
			
		|||
static struct platform_driver zynq_gpio_driver = {
 | 
			
		||||
	.driver	= {
 | 
			
		||||
		.name = DRIVER_NAME,
 | 
			
		||||
		.owner = THIS_MODULE,
 | 
			
		||||
		.pm = &zynq_gpio_dev_pm_ops,
 | 
			
		||||
		.of_match_table = zynq_gpio_of_match,
 | 
			
		||||
	},
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,10 +25,12 @@ struct acpi_gpio_event {
 | 
			
		|||
	acpi_handle handle;
 | 
			
		||||
	unsigned int pin;
 | 
			
		||||
	unsigned int irq;
 | 
			
		||||
	struct gpio_desc *desc;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct acpi_gpio_connection {
 | 
			
		||||
	struct list_head node;
 | 
			
		||||
	unsigned int pin;
 | 
			
		||||
	struct gpio_desc *desc;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -143,14 +145,8 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
 | 
			
		|||
	if (!handler)
 | 
			
		||||
		return AE_BAD_PARAMETER;
 | 
			
		||||
 | 
			
		||||
	desc = gpiochip_get_desc(chip, pin);
 | 
			
		||||
	desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event");
 | 
			
		||||
	if (IS_ERR(desc)) {
 | 
			
		||||
		dev_err(chip->dev, "Failed to get GPIO descriptor\n");
 | 
			
		||||
		return AE_ERROR;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = gpiochip_request_own_desc(desc, "ACPI:Event");
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		dev_err(chip->dev, "Failed to request GPIO\n");
 | 
			
		||||
		return AE_ERROR;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -197,6 +193,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
 | 
			
		|||
	event->handle = evt_handle;
 | 
			
		||||
	event->irq = irq;
 | 
			
		||||
	event->pin = pin;
 | 
			
		||||
	event->desc = desc;
 | 
			
		||||
 | 
			
		||||
	ret = request_threaded_irq(event->irq, NULL, handler, irqflags,
 | 
			
		||||
				   "ACPI:Event", event);
 | 
			
		||||
| 
						 | 
				
			
			@ -280,7 +277,7 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
 | 
			
		|||
		struct gpio_desc *desc;
 | 
			
		||||
 | 
			
		||||
		free_irq(event->irq, event);
 | 
			
		||||
		desc = gpiochip_get_desc(chip, event->pin);
 | 
			
		||||
		desc = event->desc;
 | 
			
		||||
		if (WARN_ON(IS_ERR(desc)))
 | 
			
		||||
			continue;
 | 
			
		||||
		gpio_unlock_as_irq(chip, event->pin);
 | 
			
		||||
| 
						 | 
				
			
			@ -409,26 +406,20 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
 | 
			
		|||
		struct gpio_desc *desc;
 | 
			
		||||
		bool found;
 | 
			
		||||
 | 
			
		||||
		desc = gpiochip_get_desc(chip, pin);
 | 
			
		||||
		if (IS_ERR(desc)) {
 | 
			
		||||
			status = AE_ERROR;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		mutex_lock(&achip->conn_lock);
 | 
			
		||||
 | 
			
		||||
		found = false;
 | 
			
		||||
		list_for_each_entry(conn, &achip->conns, node) {
 | 
			
		||||
			if (conn->desc == desc) {
 | 
			
		||||
			if (conn->pin == pin) {
 | 
			
		||||
				found = true;
 | 
			
		||||
				desc = conn->desc;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (!found) {
 | 
			
		||||
			int ret;
 | 
			
		||||
 | 
			
		||||
			ret = gpiochip_request_own_desc(desc, "ACPI:OpRegion");
 | 
			
		||||
			if (ret) {
 | 
			
		||||
			desc = gpiochip_request_own_desc(chip, pin,
 | 
			
		||||
							 "ACPI:OpRegion");
 | 
			
		||||
			if (IS_ERR(desc)) {
 | 
			
		||||
				status = AE_ERROR;
 | 
			
		||||
				mutex_unlock(&achip->conn_lock);
 | 
			
		||||
				goto out;
 | 
			
		||||
| 
						 | 
				
			
			@ -465,6 +456,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
 | 
			
		|||
				goto out;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			conn->pin = pin;
 | 
			
		||||
			conn->desc = desc;
 | 
			
		||||
			list_add_tail(&conn->node, &achip->conns);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -308,10 +308,9 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);
 | 
			
		|||
 *
 | 
			
		||||
 * A gpio_chip with any GPIOs still requested may not be removed.
 | 
			
		||||
 */
 | 
			
		||||
int gpiochip_remove(struct gpio_chip *chip)
 | 
			
		||||
void gpiochip_remove(struct gpio_chip *chip)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long	flags;
 | 
			
		||||
	int		status = 0;
 | 
			
		||||
	unsigned	id;
 | 
			
		||||
 | 
			
		||||
	acpi_gpiochip_remove(chip);
 | 
			
		||||
| 
						 | 
				
			
			@ -323,24 +322,15 @@ int gpiochip_remove(struct gpio_chip *chip)
 | 
			
		|||
	of_gpiochip_remove(chip);
 | 
			
		||||
 | 
			
		||||
	for (id = 0; id < chip->ngpio; id++) {
 | 
			
		||||
		if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) {
 | 
			
		||||
			status = -EBUSY;
 | 
			
		||||
			break;
 | 
			
		||||
		if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags))
 | 
			
		||||
			dev_crit(chip->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");
 | 
			
		||||
	}
 | 
			
		||||
	}
 | 
			
		||||
	if (status == 0) {
 | 
			
		||||
	for (id = 0; id < chip->ngpio; id++)
 | 
			
		||||
		chip->desc[id].chip = NULL;
 | 
			
		||||
 | 
			
		||||
	list_del(&chip->list);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irqrestore(&gpio_lock, flags);
 | 
			
		||||
 | 
			
		||||
	if (status == 0)
 | 
			
		||||
	gpiochip_unexport(chip);
 | 
			
		||||
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(gpiochip_remove);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -395,24 +385,35 @@ static struct gpio_chip *find_chip_by_name(const char *name)
 | 
			
		|||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * gpiochip_add_chained_irqchip() - adds a chained irqchip to a gpiochip
 | 
			
		||||
 * @gpiochip: the gpiochip to add the irqchip to
 | 
			
		||||
 * @irqchip: the irqchip to add to the gpiochip
 | 
			
		||||
 * gpiochip_set_chained_irqchip() - sets a chained irqchip to a gpiochip
 | 
			
		||||
 * @gpiochip: the gpiochip to set the irqchip chain to
 | 
			
		||||
 * @irqchip: the irqchip to chain to the gpiochip
 | 
			
		||||
 * @parent_irq: the irq number corresponding to the parent IRQ for this
 | 
			
		||||
 * chained irqchip
 | 
			
		||||
 * @parent_handler: the parent interrupt handler for the accumulated IRQ
 | 
			
		||||
 * coming out of the gpiochip
 | 
			
		||||
 * coming out of the gpiochip. If the interrupt is nested rather than
 | 
			
		||||
 * cascaded, pass NULL in this handler argument
 | 
			
		||||
 */
 | 
			
		||||
void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
 | 
			
		||||
				  struct irq_chip *irqchip,
 | 
			
		||||
				  int parent_irq,
 | 
			
		||||
				  irq_flow_handler_t parent_handler)
 | 
			
		||||
{
 | 
			
		||||
	if (gpiochip->can_sleep) {
 | 
			
		||||
		chip_err(gpiochip, "you cannot have chained interrupts on a chip that may sleep\n");
 | 
			
		||||
	unsigned int offset;
 | 
			
		||||
 | 
			
		||||
	if (!gpiochip->irqdomain) {
 | 
			
		||||
		chip_err(gpiochip, "called %s before setting up irqchip\n",
 | 
			
		||||
			 __func__);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (parent_handler) {
 | 
			
		||||
		if (gpiochip->can_sleep) {
 | 
			
		||||
			chip_err(gpiochip,
 | 
			
		||||
				 "you cannot have chained interrupts on a "
 | 
			
		||||
				 "chip that may sleep\n");
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		/*
 | 
			
		||||
		 * The parent irqchip is already using the chip_data for this
 | 
			
		||||
		 * irqchip, so our callbacks simply use the handler_data.
 | 
			
		||||
| 
						 | 
				
			
			@ -420,6 +421,12 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
 | 
			
		|||
		irq_set_handler_data(parent_irq, gpiochip);
 | 
			
		||||
		irq_set_chained_handler(parent_irq, parent_handler);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Set the parent IRQ for all affected IRQs */
 | 
			
		||||
	for (offset = 0; offset < gpiochip->ngpio; offset++)
 | 
			
		||||
		irq_set_parent(irq_find_mapping(gpiochip->irqdomain, offset),
 | 
			
		||||
			       parent_irq);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			@ -447,7 +454,7 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
 | 
			
		|||
	irq_set_lockdep_class(irq, &gpiochip_irq_lock_class);
 | 
			
		||||
	irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler);
 | 
			
		||||
	/* Chips that can sleep need nested thread handlers */
 | 
			
		||||
	if (chip->can_sleep)
 | 
			
		||||
	if (chip->can_sleep && !chip->irq_not_threaded)
 | 
			
		||||
		irq_set_nested_thread(irq, 1);
 | 
			
		||||
#ifdef CONFIG_ARM
 | 
			
		||||
	set_irq_flags(irq, IRQF_VALID);
 | 
			
		||||
| 
						 | 
				
			
			@ -524,7 +531,8 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
 | 
			
		|||
	/* Remove all IRQ mappings and delete the domain */
 | 
			
		||||
	if (gpiochip->irqdomain) {
 | 
			
		||||
		for (offset = 0; offset < gpiochip->ngpio; offset++)
 | 
			
		||||
			irq_dispose_mapping(gpiochip->irq_base + offset);
 | 
			
		||||
			irq_dispose_mapping(
 | 
			
		||||
				irq_find_mapping(gpiochip->irqdomain, offset));
 | 
			
		||||
		irq_domain_remove(gpiochip->irqdomain);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -895,12 +903,22 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested);
 | 
			
		|||
 * allows the GPIO chip module to be unloaded as needed (we assume that the
 | 
			
		||||
 * GPIO chip driver handles freeing the GPIOs it has requested).
 | 
			
		||||
 */
 | 
			
		||||
int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label)
 | 
			
		||||
struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum,
 | 
			
		||||
					    const char *label)
 | 
			
		||||
{
 | 
			
		||||
	if (!desc || !desc->chip)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	struct gpio_desc *desc = gpiochip_get_desc(chip, hwnum);
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	return __gpiod_request(desc, label);
 | 
			
		||||
	if (IS_ERR(desc)) {
 | 
			
		||||
		chip_err(chip, "failed to get GPIO descriptor\n");
 | 
			
		||||
		return desc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = __gpiod_request(desc, label);
 | 
			
		||||
	if (err < 0)
 | 
			
		||||
		return ERR_PTR(err);
 | 
			
		||||
 | 
			
		||||
	return desc;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(gpiochip_request_own_desc);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1652,7 +1670,7 @@ struct gpio_desc *__must_check __gpiod_get_index(struct device *dev,
 | 
			
		|||
	 * a result. In that case, use platform lookup as a fallback.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!desc || desc == ERR_PTR(-ENOENT)) {
 | 
			
		||||
		dev_dbg(dev, "using lookup tables for GPIO lookup");
 | 
			
		||||
		dev_dbg(dev, "using lookup tables for GPIO lookup\n");
 | 
			
		||||
		desc = gpiod_find(dev, con_id, idx, &lookupflags);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1069,8 +1069,7 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
 | 
			
		|||
	return ret;
 | 
			
		||||
 | 
			
		||||
err_gpiochip_remove:
 | 
			
		||||
	if (gpiochip_remove(&dev->gc) < 0)
 | 
			
		||||
		hid_err(hdev, "error removing gpio chip\n");
 | 
			
		||||
	gpiochip_remove(&dev->gc);
 | 
			
		||||
err_free_i2c:
 | 
			
		||||
	i2c_del_adapter(&dev->adap);
 | 
			
		||||
err_free_dev:
 | 
			
		||||
| 
						 | 
				
			
			@ -1089,8 +1088,7 @@ static void cp2112_remove(struct hid_device *hdev)
 | 
			
		|||
	struct cp2112_device *dev = hid_get_drvdata(hdev);
 | 
			
		||||
 | 
			
		||||
	sysfs_remove_group(&hdev->dev.kobj, &cp2112_attr_group);
 | 
			
		||||
	if (gpiochip_remove(&dev->gc))
 | 
			
		||||
		hid_err(hdev, "unable to remove gpio chip\n");
 | 
			
		||||
	gpiochip_remove(&dev->gc);
 | 
			
		||||
	i2c_del_adapter(&dev->adap);
 | 
			
		||||
	/* i2c_del_adapter has finished removing all i2c devices from our
 | 
			
		||||
	 * adapter. Well behaved devices should no longer call our cp2112_xfer
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -251,9 +251,7 @@ static void adp5588_gpio_remove(struct adp5588_kpad *kpad)
 | 
			
		|||
			dev_warn(dev, "teardown failed %d\n", error);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	error = gpiochip_remove(&kpad->gc);
 | 
			
		||||
	if (error)
 | 
			
		||||
		dev_warn(dev, "gpiochip_remove failed %d\n", error);
 | 
			
		||||
	gpiochip_remove(&kpad->gc);
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
static inline int adp5588_gpio_add(struct adp5588_kpad *kpad)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -567,9 +567,7 @@ static void adp5589_gpio_remove(struct adp5589_kpad *kpad)
 | 
			
		|||
			dev_warn(dev, "teardown failed %d\n", error);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	error = gpiochip_remove(&kpad->gc);
 | 
			
		||||
	if (error)
 | 
			
		||||
		dev_warn(dev, "gpiochip_remove failed %d\n", error);
 | 
			
		||||
	gpiochip_remove(&kpad->gc);
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
static inline int adp5589_gpio_add(struct adp5589_kpad *kpad)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -470,14 +470,10 @@ static int ad7879_gpio_add(struct ad7879 *ts,
 | 
			
		|||
static void ad7879_gpio_remove(struct ad7879 *ts)
 | 
			
		||||
{
 | 
			
		||||
	const struct ad7879_platform_data *pdata = dev_get_platdata(ts->dev);
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (pdata->gpio_export) {
 | 
			
		||||
		ret = gpiochip_remove(&ts->gc);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			dev_err(ts->dev, "failed to remove gpio %d\n",
 | 
			
		||||
				ts->gc.base);
 | 
			
		||||
	}
 | 
			
		||||
	if (pdata->gpio_export)
 | 
			
		||||
		gpiochip_remove(&ts->gc);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
static inline int ad7879_gpio_add(struct ad7879 *ts,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -319,14 +319,8 @@ static int pca9532_destroy_devices(struct pca9532_data *data, int n_devs)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_LEDS_PCA9532_GPIO
 | 
			
		||||
	if (data->gpio.dev) {
 | 
			
		||||
		int err = gpiochip_remove(&data->gpio);
 | 
			
		||||
		if (err) {
 | 
			
		||||
			dev_err(&data->client->dev, "%s failed, %d\n",
 | 
			
		||||
						"gpiochip_remove()", err);
 | 
			
		||||
			return err;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (data->gpio.dev)
 | 
			
		||||
		gpiochip_remove(&data->gpio);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -667,11 +667,8 @@ static int tca6507_probe_gpios(struct i2c_client *client,
 | 
			
		|||
 | 
			
		||||
static void tca6507_remove_gpio(struct tca6507_chip *tca)
 | 
			
		||||
{
 | 
			
		||||
	if (tca->gpio.ngpio) {
 | 
			
		||||
		int err = gpiochip_remove(&tca->gpio);
 | 
			
		||||
		dev_err(&tca->client->dev, "%s failed, %d\n",
 | 
			
		||||
			"gpiochip_remove()", err);
 | 
			
		||||
	}
 | 
			
		||||
	if (tca->gpio.ngpio)
 | 
			
		||||
		gpiochip_remove(&tca->gpio);
 | 
			
		||||
}
 | 
			
		||||
#else /* CONFIG_GPIOLIB */
 | 
			
		||||
static int tca6507_probe_gpios(struct i2c_client *client,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -584,18 +584,14 @@ static int cxd2820r_get_frontend_algo(struct dvb_frontend *fe)
 | 
			
		|||
static void cxd2820r_release(struct dvb_frontend *fe)
 | 
			
		||||
{
 | 
			
		||||
	struct cxd2820r_priv *priv = fe->demodulator_priv;
 | 
			
		||||
	int uninitialized_var(ret); /* silence compiler warning */
 | 
			
		||||
 | 
			
		||||
	dev_dbg(&priv->i2c->dev, "%s\n", __func__);
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_GPIOLIB
 | 
			
		||||
	/* remove GPIOs */
 | 
			
		||||
	if (priv->gpio_chip.label) {
 | 
			
		||||
		ret = gpiochip_remove(&priv->gpio_chip);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			dev_err(&priv->i2c->dev, "%s: gpiochip_remove() " \
 | 
			
		||||
					"failed=%d\n", KBUILD_MODNAME, ret);
 | 
			
		||||
	}
 | 
			
		||||
	if (priv->gpio_chip.label)
 | 
			
		||||
		gpiochip_remove(&priv->gpio_chip);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
	kfree(priv);
 | 
			
		||||
	return;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -605,7 +605,8 @@ static int asic3_gpio_remove(struct platform_device *pdev)
 | 
			
		|||
{
 | 
			
		||||
	struct asic3 *asic = platform_get_drvdata(pdev);
 | 
			
		||||
 | 
			
		||||
	return gpiochip_remove(&asic->gpio);
 | 
			
		||||
	gpiochip_remove(&asic->gpio);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void asic3_clk_enable(struct asic3 *asic, struct asic3_clk *clk)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -481,15 +481,9 @@ static int htcpld_register_chip_gpio(
 | 
			
		|||
 | 
			
		||||
	ret = gpiochip_add(&(chip->chip_in));
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		int error;
 | 
			
		||||
 | 
			
		||||
		dev_warn(dev, "Unable to register input GPIOs for 0x%x: %d\n",
 | 
			
		||||
			 plat_chip_data->addr, ret);
 | 
			
		||||
 | 
			
		||||
		error = gpiochip_remove(&(chip->chip_out));
 | 
			
		||||
		if (error)
 | 
			
		||||
			dev_warn(dev, "Error while trying to unregister gpio chip: %d\n", error);
 | 
			
		||||
 | 
			
		||||
		gpiochip_remove(&(chip->chip_out));
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1047,7 +1047,6 @@ static int sm501_register_gpio(struct sm501_devdata *sm)
 | 
			
		|||
	struct sm501_gpio *gpio = &sm->gpio;
 | 
			
		||||
	resource_size_t iobase = sm->io_res->start + SM501_GPIO;
 | 
			
		||||
	int ret;
 | 
			
		||||
	int tmp;
 | 
			
		||||
 | 
			
		||||
	dev_dbg(sm->dev, "registering gpio block %08llx\n",
 | 
			
		||||
		(unsigned long long)iobase);
 | 
			
		||||
| 
						 | 
				
			
			@ -1086,11 +1085,7 @@ static int sm501_register_gpio(struct sm501_devdata *sm)
 | 
			
		|||
	return 0;
 | 
			
		||||
 | 
			
		||||
 err_low_chip:
 | 
			
		||||
	tmp = gpiochip_remove(&gpio->low.gpio);
 | 
			
		||||
	if (tmp) {
 | 
			
		||||
		dev_err(sm->dev, "cannot remove low chip, cannot tidy up\n");
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	gpiochip_remove(&gpio->low.gpio);
 | 
			
		||||
 | 
			
		||||
 err_mapped:
 | 
			
		||||
	iounmap(gpio->regs);
 | 
			
		||||
| 
						 | 
				
			
			@ -1105,18 +1100,12 @@ static int sm501_register_gpio(struct sm501_devdata *sm)
 | 
			
		|||
static void sm501_gpio_remove(struct sm501_devdata *sm)
 | 
			
		||||
{
 | 
			
		||||
	struct sm501_gpio *gpio = &sm->gpio;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (!sm->gpio.registered)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	ret = gpiochip_remove(&gpio->low.gpio);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		dev_err(sm->dev, "cannot remove low chip, cannot tidy up\n");
 | 
			
		||||
 | 
			
		||||
	ret = gpiochip_remove(&gpio->high.gpio);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		dev_err(sm->dev, "cannot remove high chip, cannot tidy up\n");
 | 
			
		||||
	gpiochip_remove(&gpio->low.gpio);
 | 
			
		||||
	gpiochip_remove(&gpio->high.gpio);
 | 
			
		||||
 | 
			
		||||
	iounmap(gpio->regs);
 | 
			
		||||
	release_resource(gpio->regs_res);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -607,7 +607,7 @@ static int tc6393xb_probe(struct platform_device *dev)
 | 
			
		|||
	struct tc6393xb_platform_data *tcpd = dev_get_platdata(&dev->dev);
 | 
			
		||||
	struct tc6393xb *tc6393xb;
 | 
			
		||||
	struct resource *iomem, *rscr;
 | 
			
		||||
	int ret, temp;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
 | 
			
		||||
	if (!iomem)
 | 
			
		||||
| 
						 | 
				
			
			@ -714,7 +714,7 @@ err_setup:
 | 
			
		|||
 | 
			
		||||
err_gpio_add:
 | 
			
		||||
	if (tc6393xb->gpio.base != -1)
 | 
			
		||||
		temp = gpiochip_remove(&tc6393xb->gpio);
 | 
			
		||||
		gpiochip_remove(&tc6393xb->gpio);
 | 
			
		||||
	tcpd->disable(dev);
 | 
			
		||||
err_enable:
 | 
			
		||||
	clk_disable(tc6393xb->clk);
 | 
			
		||||
| 
						 | 
				
			
			@ -744,13 +744,8 @@ static int tc6393xb_remove(struct platform_device *dev)
 | 
			
		|||
 | 
			
		||||
	tc6393xb_detach_irq(dev);
 | 
			
		||||
 | 
			
		||||
	if (tc6393xb->gpio.base != -1) {
 | 
			
		||||
		ret = gpiochip_remove(&tc6393xb->gpio);
 | 
			
		||||
		if (ret) {
 | 
			
		||||
			dev_err(&dev->dev, "Can't remove gpio chip: %d\n", ret);
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (tc6393xb->gpio.base != -1)
 | 
			
		||||
		gpiochip_remove(&tc6393xb->gpio);
 | 
			
		||||
 | 
			
		||||
	ret = tcpd->disable(dev);
 | 
			
		||||
	clk_disable(tc6393xb->clk);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -621,7 +621,6 @@ static void ucb1x00_remove(struct mcp *mcp)
 | 
			
		|||
	struct ucb1x00_plat_data *pdata = mcp->attached_device.platform_data;
 | 
			
		||||
	struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
 | 
			
		||||
	struct list_head *l, *n;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&ucb1x00_mutex);
 | 
			
		||||
	list_del(&ucb->node);
 | 
			
		||||
| 
						 | 
				
			
			@ -631,11 +630,8 @@ static void ucb1x00_remove(struct mcp *mcp)
 | 
			
		|||
	}
 | 
			
		||||
	mutex_unlock(&ucb1x00_mutex);
 | 
			
		||||
 | 
			
		||||
	if (ucb->gpio.base != -1) {
 | 
			
		||||
		ret = gpiochip_remove(&ucb->gpio);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			dev_err(&ucb->dev, "Can't remove gpio chip: %d\n", ret);
 | 
			
		||||
	}
 | 
			
		||||
	if (ucb->gpio.base != -1)
 | 
			
		||||
		gpiochip_remove(&ucb->gpio);
 | 
			
		||||
 | 
			
		||||
	irq_set_chained_handler(ucb->irq, NULL);
 | 
			
		||||
	irq_free_descs(ucb->irq_base, 16);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -86,7 +86,7 @@ config PINCTRL_BCM2835
 | 
			
		|||
 | 
			
		||||
config PINCTRL_BCM281XX
 | 
			
		||||
	bool "Broadcom BCM281xx pinctrl driver"
 | 
			
		||||
	depends on OF
 | 
			
		||||
	depends on OF && (ARCH_BCM_MOBILE || COMPILE_TEST)
 | 
			
		||||
	select PINMUX
 | 
			
		||||
	select PINCONF
 | 
			
		||||
	select GENERIC_PINCONF
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1174,7 +1174,7 @@ static int abx500_gpio_probe(struct platform_device *pdev)
 | 
			
		|||
	const struct of_device_id *match;
 | 
			
		||||
	struct abx500_pinctrl *pct;
 | 
			
		||||
	unsigned int id = -1;
 | 
			
		||||
	int ret, err;
 | 
			
		||||
	int ret;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (!np) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1266,10 +1266,7 @@ static int abx500_gpio_probe(struct platform_device *pdev)
 | 
			
		|||
	return 0;
 | 
			
		||||
 | 
			
		||||
out_rem_chip:
 | 
			
		||||
	err = gpiochip_remove(&pct->chip);
 | 
			
		||||
	if (err)
 | 
			
		||||
		dev_info(&pdev->dev, "failed to remove gpiochip\n");
 | 
			
		||||
 | 
			
		||||
	gpiochip_remove(&pct->chip);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1280,15 +1277,8 @@ out_rem_chip:
 | 
			
		|||
static int abx500_gpio_remove(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct abx500_pinctrl *pct = platform_get_drvdata(pdev);
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = gpiochip_remove(&pct->chip);
 | 
			
		||||
	if (ret < 0) {
 | 
			
		||||
		dev_err(pct->dev, "unable to remove gpiochip: %d\n",
 | 
			
		||||
			ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gpiochip_remove(&pct->chip);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1276,7 +1276,7 @@ static int nmk_gpio_probe(struct platform_device *dev)
 | 
			
		|||
				   IRQ_TYPE_EDGE_FALLING);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		dev_err(&dev->dev, "could not add irqchip\n");
 | 
			
		||||
		ret = gpiochip_remove(&nmk_chip->chip);
 | 
			
		||||
		gpiochip_remove(&nmk_chip->chip);
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
	}
 | 
			
		||||
	/* Then register the chain on the parent IRQ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -936,14 +936,8 @@ EXPORT_SYMBOL(msm_pinctrl_probe);
 | 
			
		|||
int msm_pinctrl_remove(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct msm_pinctrl *pctrl = platform_get_drvdata(pdev);
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = gpiochip_remove(&pctrl->chip);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		dev_err(&pdev->dev, "Failed to remove gpiochip\n");
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gpiochip_remove(&pctrl->chip);
 | 
			
		||||
	pinctrl_unregister(pctrl->pctrl);
 | 
			
		||||
 | 
			
		||||
	unregister_restart_handler(&pctrl->restart_nb);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -874,11 +874,7 @@ static int exynos5440_gpiolib_register(struct platform_device *pdev,
 | 
			
		|||
static int exynos5440_gpiolib_unregister(struct platform_device *pdev,
 | 
			
		||||
				struct exynos5440_pinctrl_priv_data *priv)
 | 
			
		||||
{
 | 
			
		||||
	int ret = gpiochip_remove(priv->gc);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		dev_err(&pdev->dev, "gpio chip remove failed\n");
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	gpiochip_remove(priv->gc);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -946,9 +946,7 @@ static int samsung_gpiolib_register(struct platform_device *pdev,
 | 
			
		|||
 | 
			
		||||
fail:
 | 
			
		||||
	for (--i, --bank; i >= 0; --i, --bank)
 | 
			
		||||
		if (gpiochip_remove(&bank->gpio_chip))
 | 
			
		||||
			dev_err(&pdev->dev, "gpio chip %s remove failed\n",
 | 
			
		||||
							bank->gpio_chip.label);
 | 
			
		||||
		gpiochip_remove(&bank->gpio_chip);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -958,16 +956,11 @@ static int samsung_gpiolib_unregister(struct platform_device *pdev,
 | 
			
		|||
{
 | 
			
		||||
	struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
 | 
			
		||||
	struct samsung_pin_bank *bank = ctrl->pin_banks;
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; !ret && i < ctrl->nr_banks; ++i, ++bank)
 | 
			
		||||
		ret = gpiochip_remove(&bank->gpio_chip);
 | 
			
		||||
 | 
			
		||||
	if (ret)
 | 
			
		||||
		dev_err(&pdev->dev, "gpio chip remove failed\n");
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
	for (i = 0; i < ctrl->nr_banks; ++i, ++bank)
 | 
			
		||||
		gpiochip_remove(&bank->gpio_chip);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct of_device_id samsung_pinctrl_dt_match[];
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -891,8 +891,7 @@ static int sirfsoc_gpio_probe(struct device_node *np)
 | 
			
		|||
 | 
			
		||||
out_no_range:
 | 
			
		||||
out_banks:
 | 
			
		||||
	if (gpiochip_remove(&sgpio->chip.gc))
 | 
			
		||||
		dev_err(&pdev->dev, "could not remove gpio chip\n");
 | 
			
		||||
	gpiochip_remove(&sgpio->chip.gc);
 | 
			
		||||
out:
 | 
			
		||||
	iounmap(regs);
 | 
			
		||||
	return err;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -301,8 +301,7 @@ static int platform_pmic_gpio_probe(struct platform_device *pdev)
 | 
			
		|||
	return 0;
 | 
			
		||||
 | 
			
		||||
fail_request_irq:
 | 
			
		||||
	if (gpiochip_remove(&pg->chip))
 | 
			
		||||
		pr_err("gpiochip_remove failed\n");
 | 
			
		||||
	gpiochip_remove(&pg->chip);
 | 
			
		||||
err:
 | 
			
		||||
	iounmap(pg->gpiointr);
 | 
			
		||||
err2:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -475,7 +475,8 @@ int ssb_gpio_unregister(struct ssb_bus *bus)
 | 
			
		|||
{
 | 
			
		||||
	if (ssb_chipco_available(&bus->chipco) ||
 | 
			
		||||
	    ssb_extif_available(&bus->extif)) {
 | 
			
		||||
		return gpiochip_remove(&bus->gpio);
 | 
			
		||||
		gpiochip_remove(&bus->gpio);
 | 
			
		||||
		return 0;
 | 
			
		||||
	} else {
 | 
			
		||||
		SSB_WARN_ON(1);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -221,9 +221,7 @@ void pio2_gpio_exit(struct pio2_card *card)
 | 
			
		|||
{
 | 
			
		||||
	const char *label = card->gc.label;
 | 
			
		||||
 | 
			
		||||
	if (gpiochip_remove(&(card->gc)))
 | 
			
		||||
		dev_err(&card->vdev->dev, "Failed to remove GPIO\n");
 | 
			
		||||
 | 
			
		||||
	gpiochip_remove(&(card->gc));
 | 
			
		||||
	kfree(label);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1248,7 +1248,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
 | 
			
		|||
	mutex_destroy(&s->mutex);
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_GPIOLIB
 | 
			
		||||
	WARN_ON(gpiochip_remove(&s->gpio));
 | 
			
		||||
	gpiochip_remove(&s->gpio);
 | 
			
		||||
 | 
			
		||||
out_uart:
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -1263,12 +1263,10 @@ out_clk:
 | 
			
		|||
static int max310x_remove(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct max310x_port *s = dev_get_drvdata(dev);
 | 
			
		||||
	int i, ret = 0;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_GPIOLIB
 | 
			
		||||
	ret = gpiochip_remove(&s->gpio);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
	gpiochip_remove(&s->gpio);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < s->uart.nr; i++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1282,7 +1280,7 @@ static int max310x_remove(struct device *dev)
 | 
			
		|||
	uart_unregister_driver(&s->uart);
 | 
			
		||||
	clk_disable_unprepare(s->clk);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct of_device_id __maybe_unused max310x_dt_ids[] = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1157,7 +1157,7 @@ static int sc16is7xx_probe(struct device *dev,
 | 
			
		|||
 | 
			
		||||
#ifdef CONFIG_GPIOLIB
 | 
			
		||||
	if (devtype->nr_gpio)
 | 
			
		||||
		WARN_ON(gpiochip_remove(&s->gpio));
 | 
			
		||||
		gpiochip_remove(&s->gpio);
 | 
			
		||||
 | 
			
		||||
out_uart:
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -1173,14 +1173,11 @@ out_clk:
 | 
			
		|||
static int sc16is7xx_remove(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct sc16is7xx_port *s = dev_get_drvdata(dev);
 | 
			
		||||
	int i, ret = 0;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_GPIOLIB
 | 
			
		||||
	if (s->devtype->nr_gpio) {
 | 
			
		||||
		ret = gpiochip_remove(&s->gpio);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
	}
 | 
			
		||||
	if (s->devtype->nr_gpio)
 | 
			
		||||
		gpiochip_remove(&s->gpio);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < s->uart.nr; i++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1195,7 +1192,7 @@ static int sc16is7xx_remove(struct device *dev)
 | 
			
		|||
	if (!IS_ERR(s->clk))
 | 
			
		||||
		clk_disable_unprepare(s->clk);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -270,7 +270,7 @@ static int viafb_gpio_probe(struct platform_device *platdev)
 | 
			
		|||
static int viafb_gpio_remove(struct platform_device *platdev)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	int ret = 0, i;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PM
 | 
			
		||||
	viafb_pm_unregister(&viafb_gpio_pm_hooks);
 | 
			
		||||
| 
						 | 
				
			
			@ -280,11 +280,7 @@ static int viafb_gpio_remove(struct platform_device *platdev)
 | 
			
		|||
	 * Get unregistered.
 | 
			
		||||
	 */
 | 
			
		||||
	if (viafb_gpio_config.gpio_chip.ngpio > 0) {
 | 
			
		||||
		ret = gpiochip_remove(&viafb_gpio_config.gpio_chip);
 | 
			
		||||
		if (ret) { /* Somebody still using it? */
 | 
			
		||||
			printk(KERN_ERR "Viafb: GPIO remove failed\n");
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		gpiochip_remove(&viafb_gpio_config.gpio_chip);
 | 
			
		||||
	}
 | 
			
		||||
	/*
 | 
			
		||||
	 * Disable the ports.
 | 
			
		||||
| 
						 | 
				
			
			@ -294,7 +290,7 @@ static int viafb_gpio_remove(struct platform_device *platdev)
 | 
			
		|||
		viafb_gpio_disable(viafb_gpio_config.active_gpios[i]);
 | 
			
		||||
	viafb_gpio_config.gpio_chip.ngpio = 0;
 | 
			
		||||
	spin_unlock_irqrestore(&viafb_gpio_config.vdev->reg_lock, flags);
 | 
			
		||||
	return ret;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct platform_driver via_gpio_driver = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,7 +27,7 @@
 | 
			
		|||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef ARCH_NR_GPIOS
 | 
			
		||||
#define ARCH_NR_GPIOS		256
 | 
			
		||||
#define ARCH_NR_GPIOS		512
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,6 +56,8 @@ struct seq_file;
 | 
			
		|||
 *	as the chip access may sleep when e.g. reading out the IRQ status
 | 
			
		||||
 *	registers.
 | 
			
		||||
 * @exported: flags if the gpiochip is exported for use from sysfs. Private.
 | 
			
		||||
 * @irq_not_threaded: flag must be set if @can_sleep is set but the
 | 
			
		||||
 *	IRQs don't need to be threaded
 | 
			
		||||
 *
 | 
			
		||||
 * A gpio_chip can help platforms abstract various sources of GPIOs so
 | 
			
		||||
 * they can all be accessed through a common programing interface.
 | 
			
		||||
| 
						 | 
				
			
			@ -101,6 +103,7 @@ struct gpio_chip {
 | 
			
		|||
	struct gpio_desc	*desc;
 | 
			
		||||
	const char		*const *names;
 | 
			
		||||
	bool			can_sleep;
 | 
			
		||||
	bool			irq_not_threaded;
 | 
			
		||||
	bool			exported;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_GPIOLIB_IRQCHIP
 | 
			
		||||
| 
						 | 
				
			
			@ -141,7 +144,7 @@ extern const char *gpiochip_is_requested(struct gpio_chip *chip,
 | 
			
		|||
 | 
			
		||||
/* add/remove chips */
 | 
			
		||||
extern int gpiochip_add(struct gpio_chip *chip);
 | 
			
		||||
extern int gpiochip_remove(struct gpio_chip *chip);
 | 
			
		||||
extern void gpiochip_remove(struct gpio_chip *chip);
 | 
			
		||||
extern struct gpio_chip *gpiochip_find(void *data,
 | 
			
		||||
			      int (*match)(struct gpio_chip *chip, void *data));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -166,7 +169,8 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
 | 
			
		|||
 | 
			
		||||
#endif /* CONFIG_GPIOLIB_IRQCHIP */
 | 
			
		||||
 | 
			
		||||
int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label);
 | 
			
		||||
struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum,
 | 
			
		||||
					    const char *label);
 | 
			
		||||
void gpiochip_free_own_desc(struct gpio_desc *desc);
 | 
			
		||||
 | 
			
		||||
#else /* CONFIG_GPIOLIB */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										32
									
								
								include/linux/platform_data/gpio-dwapb.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								include/linux/platform_data/gpio-dwapb.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,32 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright(c) 2014 Intel Corporation.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify it
 | 
			
		||||
 * under the terms and conditions of the GNU General Public License,
 | 
			
		||||
 * version 2, as published by the Free Software Foundation.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef GPIO_DW_APB_H
 | 
			
		||||
#define GPIO_DW_APB_H
 | 
			
		||||
 | 
			
		||||
struct dwapb_port_property {
 | 
			
		||||
	struct device_node *node;
 | 
			
		||||
	const char	*name;
 | 
			
		||||
	unsigned int	idx;
 | 
			
		||||
	unsigned int	ngpio;
 | 
			
		||||
	unsigned int	gpio_base;
 | 
			
		||||
	unsigned int	irq;
 | 
			
		||||
	bool		irq_shared;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct dwapb_platform_data {
 | 
			
		||||
	struct dwapb_port_property *properties;
 | 
			
		||||
	unsigned int nports;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -22,4 +22,22 @@ struct mcp23s08_platform_data {
 | 
			
		|||
	 * base to base+15 (or base+31 for s17 variant).
 | 
			
		||||
	 */
 | 
			
		||||
	unsigned	base;
 | 
			
		||||
	/* Marks the device as a interrupt controller.
 | 
			
		||||
	 * NOTE: The interrupt functionality is only supported for i2c
 | 
			
		||||
	 * versions of the chips. The spi chips can also do the interrupts,
 | 
			
		||||
	 * but this is not supported by the linux driver yet.
 | 
			
		||||
	 */
 | 
			
		||||
	bool		irq_controller;
 | 
			
		||||
 | 
			
		||||
	/* Sets the mirror flag in the IOCON register. Devices
 | 
			
		||||
	 * with two interrupt outputs (these are the devices ending with 17 and
 | 
			
		||||
	 * those that have 16 IOs) have two IO banks: IO 0-7 form bank 1 and
 | 
			
		||||
	 * IO 8-15 are bank 2. These chips have two different interrupt outputs:
 | 
			
		||||
	 * One for bank 1 and another for bank 2. If irq-mirror is set, both
 | 
			
		||||
	 * interrupts are generated regardless of the bank that an input change
 | 
			
		||||
	 * occurred on. If it is not set, the interrupt are only generated for
 | 
			
		||||
	 * the bank they belong to.
 | 
			
		||||
	 * On devices with only one interrupt output this property is useless.
 | 
			
		||||
	 */
 | 
			
		||||
	bool		mirror;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2319,11 +2319,8 @@ static void wm5100_init_gpio(struct i2c_client *i2c)
 | 
			
		|||
static void wm5100_free_gpio(struct i2c_client *i2c)
 | 
			
		||||
{
 | 
			
		||||
	struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c);
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = gpiochip_remove(&wm5100->gpio_chip);
 | 
			
		||||
	if (ret != 0)
 | 
			
		||||
		dev_err(&i2c->dev, "Failed to remove GPIOs: %d\n", ret);
 | 
			
		||||
	gpiochip_remove(&wm5100->gpio_chip);
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
static void wm5100_init_gpio(struct i2c_client *i2c)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1877,11 +1877,7 @@ static void wm8903_init_gpio(struct wm8903_priv *wm8903)
 | 
			
		|||
 | 
			
		||||
static void wm8903_free_gpio(struct wm8903_priv *wm8903)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = gpiochip_remove(&wm8903->gpio_chip);
 | 
			
		||||
	if (ret != 0)
 | 
			
		||||
		dev_err(wm8903->dev, "Failed to remove GPIOs: %d\n", ret);
 | 
			
		||||
	gpiochip_remove(&wm8903->gpio_chip);
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
static void wm8903_init_gpio(struct wm8903_priv *wm8903)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3398,11 +3398,8 @@ static void wm8962_init_gpio(struct snd_soc_codec *codec)
 | 
			
		|||
static void wm8962_free_gpio(struct snd_soc_codec *codec)
 | 
			
		||||
{
 | 
			
		||||
	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = gpiochip_remove(&wm8962->gpio_chip);
 | 
			
		||||
	if (ret != 0)
 | 
			
		||||
		dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret);
 | 
			
		||||
	gpiochip_remove(&wm8962->gpio_chip);
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
static void wm8962_init_gpio(struct snd_soc_codec *codec)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2216,11 +2216,7 @@ static void wm8996_init_gpio(struct wm8996_priv *wm8996)
 | 
			
		|||
 | 
			
		||||
static void wm8996_free_gpio(struct wm8996_priv *wm8996)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = gpiochip_remove(&wm8996->gpio_chip);
 | 
			
		||||
	if (ret != 0)
 | 
			
		||||
		dev_err(wm8996->dev, "Failed to remove GPIOs: %d\n", ret);
 | 
			
		||||
	gpiochip_remove(&wm8996->gpio_chip);
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
static void wm8996_init_gpio(struct wm8996_priv *wm8996)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue