This is the bulk of GPIO changes for the v4.12 kernel cycle:
Core changes - Return NULL from gpiod_get_optional() when GPIOLIB is disabled. This was a much discussed change. It affects use cases where people write drivers that might or might not be using GPIO resources. I have decided that this is the lesser evil right now. - Make gpiod_count() behave consistently across different hardware descriptions. - Fix the syntax around open drain/open source to not infer active high/low semantics. New drivers - A new single-register fixed-direction framework driver for hardware that have lines controlled by a single register that just work in one direction (out or in), including IRQ support. - Support the Fintek F71889A GPIO SuperIO controller. - Support the National NI 169445 MMIO GPIO. - Support for the X-Gene derivative of the DWC GPIO controller - Support for the Rohm BD9571MWV-M PMIC GPIO controller. - Refactor the Gemini GPIO driver to a generic Faraday FTGPIO driver and replace both the Gemini and the Moxa ART custom drivers with this driver. Driver improvements - A whole slew of drivers have their spinlocks chaned to raw spinlocks as they provide irqchips, and thus we are progressing on realtime compliance. - Use devm_irq_alloc_descs() in a slew of drivers, getting managed resources. - Support for the embedded PWM controller inside the MVEBU driver. - Debounce, open source and open drain support for the Aspeed driver. - Misc smaller fixes like spelling and syntax and whatnot. -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJZCusBAAoJEEEQszewGV1zengP/i3YgmSXJdaf26t/NxG3klU3 qx3akdQ3gEQ6BOlIY7Ew+b6qgMJynYNZa1trZgqTgLxPEKWjidyCgz+LHQ0OY+ir a7x6wr+gBj5WlgV+nBjVs4l6W8pVKCfnap/04OPEQDpxZOHs2LU5pqxxUZ9AxkKS urDFMDX55baFviQ+xAuHgamok87YoGP36A/e/fHIBepZmnochf0mCcPfIh0t8lRh s2x29PN5ZFRkl403RzjZfVCEMr9bMnSqmDquvPO++Kq0bL+3rOhuMErocd1Bg8ao LxBktkryujTaw699xK7Rq5SwcnOAPpaBY4NTmwsIJvAJuCh7qLy9JxQSBsSOT2bx 61NWUt5T/Xsi0ECYZM4YvsNpUP6XrpSTyG3c8T3fY9vXYLNKZBv1ht6OODpLeuke DxULAWP+DdzUS8a3qfKQvIJzSTloU31a1MBG58DWNJ072EQfa2YNaVE75VQk/z5/ 0xZbSHdPY/0Xgx8ltpKu37bSO676JiVQZZ1HEAuti4h21+USYueYD2L8/Bx4k9e/ 4UaOcw3MaCDHP/sf5hg17kQBjhhS0lV9Zv6H9QbHZUocJTJlIU+vXtgkQlrfi3n8 8j5m+ywVarmLtPqg1j2rqcw7LBCPe0qRXH3e5X/YmNMc3rH9bQz4cTo8ZSN9r8zS c17zGbbAqlGsBkpFAbQz =DGPb -----END PGP SIGNATURE----- Merge tag 'gpio-v4.12-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio Pull GPIO updates from Linus Walleij: "This is the bulk of GPIO changes for the v4.12 kernel cycle. Core changes: - Return NULL from gpiod_get_optional() when GPIOLIB is disabled. This was a much discussed change. It affects use cases where people write drivers that might or might not be using GPIO resources. I have decided that this is the lesser evil right now. - Make gpiod_count() behave consistently across different hardware descriptions. - Fix the syntax around open drain/open source to not infer active high/low semantics. New drivers: - A new single-register fixed-direction framework driver for hardware that have lines controlled by a single register that just work in one direction (out or in), including IRQ support. - Support the Fintek F71889A GPIO SuperIO controller. - Support the National NI 169445 MMIO GPIO. - Support for the X-Gene derivative of the DWC GPIO controller - Support for the Rohm BD9571MWV-M PMIC GPIO controller. - Refactor the Gemini GPIO driver to a generic Faraday FTGPIO driver and replace both the Gemini and the Moxa ART custom drivers with this driver. Driver improvements: - A whole slew of drivers have their spinlocks chaned to raw spinlocks as they provide irqchips, and thus we are progressing on realtime compliance. - Use devm_irq_alloc_descs() in a slew of drivers, getting managed resources. - Support for the embedded PWM controller inside the MVEBU driver. - Debounce, open source and open drain support for the Aspeed driver. - Misc smaller fixes like spelling and syntax and whatnot" * tag 'gpio-v4.12-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (77 commits) gpio: f7188x: Add a missing break gpio: omap: return error if requested debounce time is not possible gpio: Add ROHM BD9571MWV-M PMIC GPIO driver gpio: gpio-wcove: fix GPIO IRQ status mask gpio: DT bindings, move tca9554 from pcf857x to pca953x gpio: move tca9554 from pcf857x to pca953x gpio: arizona: Correct check whether the pin is an input gpio: Add XRA1403 DTS binding documentation dt-bindings: add exar to vendor prefixes list gpio: gpio-wcove: fix irq pending status bit width gpio: dwapb: use dwapb_read instead of readl_relaxed gpio: aspeed: Add open-source and open-drain support gpio: aspeed: Add debounce support gpio: aspeed: dt: Add optional clocks property gpio: aspeed: dt: Fix description alignment in bindings document gpio: mvebu: Add limited PWM support gpio: Use unsigned int for interrupt numbers gpio: f7188x: Add F71889A GPIO support. gpio: core: Decouple open drain/source flag with active low/high gpio: arizona: Correct handling for reading input GPIOs ...
This commit is contained in:
Коммит
2bd8040174
|
@ -1,8 +1,11 @@
|
|||
Cortina Systems Gemini GPIO Controller
|
||||
Faraday Technology FTGPIO010 GPIO Controller
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : Must be "cortina,gemini-gpio"
|
||||
- compatible : Should be one of
|
||||
"cortina,gemini-gpio", "faraday,ftgpio010"
|
||||
"moxa,moxart-gpio", "faraday,ftgpio010"
|
||||
"faraday,ftgpio010"
|
||||
- reg : Should contain registers location and length
|
||||
- interrupts : Should contain the interrupt line for the GPIO block
|
||||
- gpio-controller : marks this as a GPIO controller
|
||||
|
@ -14,7 +17,7 @@ Required properties:
|
|||
Example:
|
||||
|
||||
gpio@4d000000 {
|
||||
compatible = "cortina,gemini-gpio";
|
||||
compatible = "cortina,gemini-gpio", "faraday,ftgpio010";
|
||||
reg = <0x4d000000 0x100>;
|
||||
interrupts = <22 IRQ_TYPE_LEVEL_HIGH>;
|
||||
gpio-controller;
|
|
@ -17,7 +17,8 @@ Required properties:
|
|||
|
||||
Optional properties:
|
||||
|
||||
- interrupt-parent : The parent interrupt controller, optional if inherited
|
||||
- interrupt-parent : The parent interrupt controller, optional if inherited
|
||||
- clocks : A phandle to the HPLL clock node for debounce timings
|
||||
|
||||
The gpio and interrupt properties are further described in their respective
|
||||
bindings documentation:
|
||||
|
|
|
@ -38,6 +38,24 @@ Required properties:
|
|||
- #gpio-cells: Should be two. The first cell is the pin number. The
|
||||
second cell is reserved for flags, unused at the moment.
|
||||
|
||||
Optional properties:
|
||||
|
||||
In order to use the GPIO lines in PWM mode, some additional optional
|
||||
properties are required. Only Armada 370 and XP support these properties.
|
||||
|
||||
- compatible: Must contain "marvell,armada-370-xp-gpio"
|
||||
|
||||
- reg: an additional register set is needed, for the GPIO Blink
|
||||
Counter on/off registers.
|
||||
|
||||
- reg-names: Must contain an entry "pwm" corresponding to the
|
||||
additional register range needed for PWM operation.
|
||||
|
||||
- #pwm-cells: Should be two. The first cell is the GPIO line number. The
|
||||
second cell is the period in nanoseconds.
|
||||
|
||||
- clocks: Must be a phandle to the clock for the GPIO controller.
|
||||
|
||||
Example:
|
||||
|
||||
gpio0: gpio@d0018100 {
|
||||
|
@ -51,3 +69,17 @@ Example:
|
|||
#interrupt-cells = <2>;
|
||||
interrupts = <16>, <17>, <18>, <19>;
|
||||
};
|
||||
|
||||
gpio1: gpio@18140 {
|
||||
compatible = "marvell,armada-370-xp-gpio";
|
||||
reg = <0x18140 0x40>, <0x181c8 0x08>;
|
||||
reg-names = "gpio", "pwm";
|
||||
ngpios = <17>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
#pwm-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupts = <87>, <88>, <89>;
|
||||
clocks = <&coreclk 0>;
|
||||
};
|
||||
|
|
|
@ -26,6 +26,7 @@ Required properties:
|
|||
ti,tca6416
|
||||
ti,tca6424
|
||||
ti,tca9539
|
||||
ti,tca9554
|
||||
onsemi,pca9654
|
||||
exar,xra1202
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@ Required Properties:
|
|||
- "nxp,pcf8574": For the NXP PCF8574
|
||||
- "nxp,pcf8574a": For the NXP PCF8574A
|
||||
- "nxp,pcf8575": For the NXP PCF8575
|
||||
- "ti,tca9554": For the TI TCA9554
|
||||
|
||||
- reg: I2C slave address.
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
Cavium ThunderX/OCTEON-TX GPIO controller bindings
|
||||
|
||||
Required Properties:
|
||||
- reg: The controller bus address.
|
||||
- gpio-controller: Marks the device node as a GPIO controller.
|
||||
- #gpio-cells: Must be 2.
|
||||
- First cell is the GPIO pin number relative to the controller.
|
||||
- Second cell is a standard generic flag bitfield as described in gpio.txt.
|
||||
|
||||
Optional Properties:
|
||||
- compatible: "cavium,thunder-8890-gpio", unused as PCI driver binding is used.
|
||||
- interrupt-controller: Marks the device node as an interrupt controller.
|
||||
- #interrupt-cells: Must be present and have value of 2 if
|
||||
"interrupt-controller" is present.
|
||||
- First cell is the GPIO pin number relative to the controller.
|
||||
- Second cell is triggering flags as defined in interrupts.txt.
|
||||
|
||||
Example:
|
||||
|
||||
gpio_6_0: gpio@6,0 {
|
||||
compatible = "cavium,thunder-8890-gpio";
|
||||
reg = <0x3000 0 0 0 0>; /* DEVFN = 0x30 (6:0) */
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
};
|
|
@ -0,0 +1,46 @@
|
|||
GPIO Driver for XRA1403 16-BIT GPIO Expander With Reset Input from EXAR
|
||||
|
||||
The XRA1403 is an 16-bit GPIO expander with an SPI interface. Features available:
|
||||
- Individually programmable inputs:
|
||||
- Internal pull-up resistors
|
||||
- Polarity inversion
|
||||
- Individual interrupt enable
|
||||
- Rising edge and/or Falling edge interrupt
|
||||
- Input filter
|
||||
- Individually programmable outputs
|
||||
- Output Level Control
|
||||
- Output Three-State Control
|
||||
|
||||
Properties
|
||||
----------
|
||||
Check documentation for SPI and GPIO controllers regarding properties needed to configure the node.
|
||||
|
||||
- compatible = "exar,xra1403".
|
||||
- reg - SPI id of the device.
|
||||
- gpio-controller - marks the node as gpio.
|
||||
- #gpio-cells - should be two where the first cell is the pin number
|
||||
and the second one is used for optional parameters.
|
||||
|
||||
Optional properties:
|
||||
-------------------
|
||||
- reset-gpios: in case available used to control the device reset line.
|
||||
- interrupt-controller - marks the node as interrupt controller.
|
||||
- #interrupt-cells - should be two and represents the number of cells
|
||||
needed to encode interrupt source.
|
||||
|
||||
Example
|
||||
--------
|
||||
|
||||
gpioxra0: gpio@2 {
|
||||
compatible = "exar,xra1403";
|
||||
reg = <2>;
|
||||
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
|
||||
reset-gpios = <&gpio3 6 GPIO_ACTIVE_LOW>;
|
||||
spi-max-frequency = <1000000>;
|
||||
};
|
|
@ -1,19 +0,0 @@
|
|||
MOXA ART GPIO Controller
|
||||
|
||||
Required properties:
|
||||
|
||||
- #gpio-cells : Should be 2, The first cell is the pin number,
|
||||
the second cell is used to specify polarity:
|
||||
0 = active high
|
||||
1 = active low
|
||||
- compatible : Must be "moxa,moxart-gpio"
|
||||
- reg : Should contain registers location and length
|
||||
|
||||
Example:
|
||||
|
||||
gpio: gpio@98700000 {
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
compatible = "moxa,moxart-gpio";
|
||||
reg = <0x98700000 0xC>;
|
||||
};
|
|
@ -0,0 +1,38 @@
|
|||
Bindings for the National Instruments 169445 GPIO NAND controller
|
||||
|
||||
The 169445 GPIO NAND controller has two memory mapped GPIO registers, one
|
||||
for input (the ready signal) and one for output (control signals). It is
|
||||
intended to be used with the GPIO NAND driver.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "ni,169445-nand-gpio"
|
||||
- reg-names: must contain
|
||||
"dat" - data register
|
||||
- reg: address + size pairs describing the GPIO register sets;
|
||||
order must correspond with the order of entries in reg-names
|
||||
- #gpio-cells: must be set to 2. The first cell is the pin number and
|
||||
the 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.
|
||||
|
||||
Optional properties:
|
||||
- no-output: disables driving output on the pins
|
||||
|
||||
Examples:
|
||||
gpio1: nand-gpio-out@1f300010 {
|
||||
compatible = "ni,169445-nand-gpio";
|
||||
reg = <0x1f300010 0x4>;
|
||||
reg-names = "dat";
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
|
||||
gpio2: nand-gpio-in@1f300014 {
|
||||
compatible = "ni,169445-nand-gpio";
|
||||
reg = <0x1f300014 0x4>;
|
||||
reg-names = "dat";
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
no-output;
|
||||
};
|
|
@ -103,6 +103,7 @@ ettus NI Ettus Research
|
|||
eukrea Eukréa Electromatique
|
||||
everest Everest Semiconductor Co. Ltd.
|
||||
everspin Everspin Technologies, Inc.
|
||||
exar Exar Corporation
|
||||
excito Excito
|
||||
ezchip EZchip Semiconductor
|
||||
faraday Faraday Technology Corporation
|
||||
|
|
|
@ -70,6 +70,12 @@ instead of -ENOENT if no GPIO has been assigned to the requested function:
|
|||
unsigned int index,
|
||||
enum gpiod_flags flags)
|
||||
|
||||
Note that gpio_get*_optional() functions (and their managed variants), unlike
|
||||
the rest of gpiolib API, also return NULL when gpiolib support is disabled.
|
||||
This is helpful to driver authors, since they do not need to special case
|
||||
-ENOSYS return codes. System integrators should however be careful to enable
|
||||
gpiolib on systems that need it.
|
||||
|
||||
For a function using multiple GPIOs all of those can be obtained with one call:
|
||||
|
||||
struct gpio_descs *gpiod_get_array(struct device *dev,
|
||||
|
|
|
@ -10315,6 +10315,8 @@ F: include/linux/pwm.h
|
|||
F: drivers/pwm/
|
||||
F: drivers/video/backlight/pwm_bl.c
|
||||
F: include/linux/pwm_backlight.h
|
||||
F: drivers/gpio/gpio-mvebu.c
|
||||
F: Documentation/devicetree/bindings/gpio/gpio-mvebu.txt
|
||||
|
||||
PXA2xx/PXA3xx SUPPORT
|
||||
M: Daniel Mack <daniel@zonque.org>
|
||||
|
|
|
@ -204,14 +204,15 @@ config GPIO_GE_FPGA
|
|||
and write pin state) for GPIO implemented in a number of GE single
|
||||
board computers.
|
||||
|
||||
config GPIO_GEMINI
|
||||
bool "Gemini GPIO"
|
||||
depends on ARCH_GEMINI
|
||||
config GPIO_FTGPIO010
|
||||
bool "Faraday FTGPIO010 GPIO"
|
||||
depends on OF_GPIO
|
||||
select GPIO_GENERIC
|
||||
select GPIOLIB_IRQCHIP
|
||||
default (ARCH_GEMINI || ARCH_MOXART)
|
||||
help
|
||||
Support for common GPIOs found in Cortina systems Gemini platforms.
|
||||
Support for common GPIOs from the Faraday FTGPIO010 IP core, found in
|
||||
Cortina systems Gemini platforms, Moxa ART and others.
|
||||
|
||||
config GPIO_GENERIC_PLATFORM
|
||||
tristate "Generic memory-mapped GPIO controller support (MMIO platform device)"
|
||||
|
@ -308,14 +309,6 @@ config GPIO_MOCKUP
|
|||
tools/testing/selftests/gpio/gpio-mockup.sh. Reference the usage in
|
||||
it.
|
||||
|
||||
config GPIO_MOXART
|
||||
bool "MOXART GPIO support"
|
||||
depends on ARCH_MOXART || COMPILE_TEST
|
||||
select GPIO_GENERIC
|
||||
help
|
||||
Select this option to enable GPIO driver for
|
||||
MOXA ART SoC devices.
|
||||
|
||||
config GPIO_MPC5200
|
||||
def_bool y
|
||||
depends on PPC_MPC52xx
|
||||
|
@ -387,6 +380,12 @@ config GPIO_RCAR
|
|||
help
|
||||
Say yes here to support GPIO on Renesas R-Car SoCs.
|
||||
|
||||
config GPIO_REG
|
||||
bool
|
||||
help
|
||||
A 32-bit single register GPIO fixed in/out implementation. This
|
||||
can be used to represent any register as a set of GPIO signals.
|
||||
|
||||
config GPIO_SPEAR_SPICS
|
||||
bool "ST SPEAr13xx SPI Chip Select as GPIO support"
|
||||
depends on PLAT_SPEAR
|
||||
|
@ -505,7 +504,7 @@ config GPIO_XILINX
|
|||
|
||||
config GPIO_XLP
|
||||
tristate "Netlogic XLP GPIO support"
|
||||
depends on OF_GPIO && (CPU_XLP || ARCH_VULCAN || COMPILE_TEST)
|
||||
depends on OF_GPIO && (CPU_XLP || ARCH_VULCAN || ARCH_THUNDER2 || COMPILE_TEST)
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
This driver provides support for GPIO interface on Netlogic XLP MIPS64
|
||||
|
@ -557,7 +556,7 @@ menu "Port-mapped I/O GPIO drivers"
|
|||
|
||||
config GPIO_104_DIO_48E
|
||||
tristate "ACCES 104-DIO-48E GPIO support"
|
||||
depends on ISA_BUS_API
|
||||
depends on PC104 && ISA_BUS_API
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
Enables GPIO support for the ACCES 104-DIO-48E series (104-DIO-48E,
|
||||
|
@ -567,7 +566,7 @@ config GPIO_104_DIO_48E
|
|||
|
||||
config GPIO_104_IDIO_16
|
||||
tristate "ACCES 104-IDIO-16 GPIO support"
|
||||
depends on ISA_BUS_API
|
||||
depends on PC104 && ISA_BUS_API
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
Enables GPIO support for the ACCES 104-IDIO-16 family (104-IDIO-16,
|
||||
|
@ -578,7 +577,7 @@ config GPIO_104_IDIO_16
|
|||
|
||||
config GPIO_104_IDI_48
|
||||
tristate "ACCES 104-IDI-48 GPIO support"
|
||||
depends on ISA_BUS_API
|
||||
depends on PC104 && ISA_BUS_API
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
Enables GPIO support for the ACCES 104-IDI-48 family (104-IDI-48A,
|
||||
|
@ -598,7 +597,7 @@ config GPIO_F7188X
|
|||
|
||||
config GPIO_GPIO_MM
|
||||
tristate "Diamond Systems GPIO-MM GPIO support"
|
||||
depends on ISA_BUS_API
|
||||
depends on PC104 && ISA_BUS_API
|
||||
help
|
||||
Enables GPIO support for the Diamond Systems GPIO-MM and GPIO-MM-12.
|
||||
|
||||
|
@ -753,7 +752,7 @@ config GPIO_PCA953X
|
|||
4 bits: pca9536, pca9537
|
||||
|
||||
8 bits: max7310, max7315, pca6107, pca9534, pca9538, pca9554,
|
||||
pca9556, pca9557, pca9574, tca6408, xra1202
|
||||
pca9556, pca9557, pca9574, tca6408, tca9554, xra1202
|
||||
|
||||
16 bits: max7312, max7313, pca9535, pca9539, pca9555, pca9575,
|
||||
tca6416
|
||||
|
@ -845,6 +844,17 @@ config GPIO_ARIZONA
|
|||
help
|
||||
Support for GPIOs on Wolfson Arizona class devices.
|
||||
|
||||
config GPIO_BD9571MWV
|
||||
tristate "ROHM BD9571 GPIO support"
|
||||
depends on MFD_BD9571MWV
|
||||
help
|
||||
Support for GPIOs on ROHM BD9571 PMIC. There are two GPIOs
|
||||
available on the ROHM PMIC in total, both of which can also
|
||||
generate interrupts.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called gpio-bd9571mwv.
|
||||
|
||||
config GPIO_CRYSTAL_COVE
|
||||
tristate "GPIO support for Crystal Cove PMIC"
|
||||
depends on (X86 || COMPILE_TEST) && INTEL_SOC_PMIC
|
||||
|
|
|
@ -33,6 +33,7 @@ obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o
|
|||
obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o
|
||||
obj-$(CONFIG_GPIO_AXP209) += gpio-axp209.o
|
||||
obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
|
||||
obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
|
||||
obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
|
||||
obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
|
||||
obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
|
||||
|
@ -48,8 +49,8 @@ obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
|
|||
obj-$(CONFIG_GPIO_ETRAXFS) += gpio-etraxfs.o
|
||||
obj-$(CONFIG_GPIO_EXAR) += gpio-exar.o
|
||||
obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
|
||||
obj-$(CONFIG_GPIO_FTGPIO010) += gpio-ftgpio010.o
|
||||
obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
|
||||
obj-$(CONFIG_GPIO_GEMINI) += gpio-gemini.o
|
||||
obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o
|
||||
obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o
|
||||
obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o
|
||||
|
@ -80,7 +81,6 @@ obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o
|
|||
obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o
|
||||
obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o
|
||||
obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o
|
||||
obj-$(CONFIG_GPIO_MOXART) += gpio-moxart.o
|
||||
obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o
|
||||
obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o
|
||||
obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o
|
||||
|
@ -99,6 +99,7 @@ obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o
|
|||
obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
|
||||
obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o
|
||||
obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o
|
||||
obj-$(CONFIG_GPIO_REG) += gpio-reg.o
|
||||
obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
|
||||
obj-$(CONFIG_GPIO_SCH) += gpio-sch.o
|
||||
obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o
|
||||
|
|
|
@ -136,7 +136,7 @@ EXPORT_SYMBOL(devm_gpiod_get_index);
|
|||
* GPIO descriptors returned from this function are automatically disposed on
|
||||
* driver detach.
|
||||
*
|
||||
* On successfull request the GPIO pin is configured in accordance with
|
||||
* On successful request the GPIO pin is configured in accordance with
|
||||
* provided @flags.
|
||||
*/
|
||||
struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev,
|
||||
|
|
|
@ -55,7 +55,7 @@ struct dio48e_gpio {
|
|||
unsigned char io_state[6];
|
||||
unsigned char out_state[6];
|
||||
unsigned char control[2];
|
||||
spinlock_t lock;
|
||||
raw_spinlock_t lock;
|
||||
unsigned base;
|
||||
unsigned char irq_mask;
|
||||
};
|
||||
|
@ -78,7 +78,7 @@ static int dio48e_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
|||
unsigned long flags;
|
||||
unsigned control;
|
||||
|
||||
spin_lock_irqsave(&dio48egpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&dio48egpio->lock, flags);
|
||||
|
||||
/* Check if configuring Port C */
|
||||
if (io_port == 2 || io_port == 5) {
|
||||
|
@ -103,7 +103,7 @@ static int dio48e_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
|||
control &= ~BIT(7);
|
||||
outb(control, control_addr);
|
||||
|
||||
spin_unlock_irqrestore(&dio48egpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ static int dio48e_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
|
|||
unsigned long flags;
|
||||
unsigned control;
|
||||
|
||||
spin_lock_irqsave(&dio48egpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&dio48egpio->lock, flags);
|
||||
|
||||
/* Check if configuring Port C */
|
||||
if (io_port == 2 || io_port == 5) {
|
||||
|
@ -153,7 +153,7 @@ static int dio48e_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
|
|||
control &= ~BIT(7);
|
||||
outb(control, control_addr);
|
||||
|
||||
spin_unlock_irqrestore(&dio48egpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -167,17 +167,17 @@ static int dio48e_gpio_get(struct gpio_chip *chip, unsigned offset)
|
|||
unsigned long flags;
|
||||
unsigned port_state;
|
||||
|
||||
spin_lock_irqsave(&dio48egpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&dio48egpio->lock, flags);
|
||||
|
||||
/* ensure that GPIO is set for input */
|
||||
if (!(dio48egpio->io_state[port] & mask)) {
|
||||
spin_unlock_irqrestore(&dio48egpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
port_state = inb(dio48egpio->base + in_port);
|
||||
|
||||
spin_unlock_irqrestore(&dio48egpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
|
||||
|
||||
return !!(port_state & mask);
|
||||
}
|
||||
|
@ -190,7 +190,7 @@ static void dio48e_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
|||
const unsigned out_port = (port > 2) ? port + 1 : port;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dio48egpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&dio48egpio->lock, flags);
|
||||
|
||||
if (value)
|
||||
dio48egpio->out_state[port] |= mask;
|
||||
|
@ -199,7 +199,7 @@ static void dio48e_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
|||
|
||||
outb(dio48egpio->out_state[port], dio48egpio->base + out_port);
|
||||
|
||||
spin_unlock_irqrestore(&dio48egpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
|
||||
}
|
||||
|
||||
static void dio48e_gpio_set_multiple(struct gpio_chip *chip,
|
||||
|
@ -225,14 +225,14 @@ static void dio48e_gpio_set_multiple(struct gpio_chip *chip,
|
|||
out_port = (port > 2) ? port + 1 : port;
|
||||
bitmask = mask[BIT_WORD(i)] & bits[BIT_WORD(i)];
|
||||
|
||||
spin_lock_irqsave(&dio48egpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&dio48egpio->lock, flags);
|
||||
|
||||
/* update output state data and set device gpio register */
|
||||
dio48egpio->out_state[port] &= ~mask[BIT_WORD(i)];
|
||||
dio48egpio->out_state[port] |= bitmask;
|
||||
outb(dio48egpio->out_state[port], dio48egpio->base + out_port);
|
||||
|
||||
spin_unlock_irqrestore(&dio48egpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
|
||||
|
||||
/* prepare for next gpio register set */
|
||||
mask[BIT_WORD(i)] >>= gpio_reg_size;
|
||||
|
@ -255,7 +255,7 @@ static void dio48e_irq_mask(struct irq_data *data)
|
|||
if (offset != 19 && offset != 43)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&dio48egpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&dio48egpio->lock, flags);
|
||||
|
||||
if (offset == 19)
|
||||
dio48egpio->irq_mask &= ~BIT(0);
|
||||
|
@ -266,7 +266,7 @@ static void dio48e_irq_mask(struct irq_data *data)
|
|||
/* disable interrupts */
|
||||
inb(dio48egpio->base + 0xB);
|
||||
|
||||
spin_unlock_irqrestore(&dio48egpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
|
||||
}
|
||||
|
||||
static void dio48e_irq_unmask(struct irq_data *data)
|
||||
|
@ -280,7 +280,7 @@ static void dio48e_irq_unmask(struct irq_data *data)
|
|||
if (offset != 19 && offset != 43)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&dio48egpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&dio48egpio->lock, flags);
|
||||
|
||||
if (!dio48egpio->irq_mask) {
|
||||
/* enable interrupts */
|
||||
|
@ -293,7 +293,7 @@ static void dio48e_irq_unmask(struct irq_data *data)
|
|||
else
|
||||
dio48egpio->irq_mask |= BIT(1);
|
||||
|
||||
spin_unlock_irqrestore(&dio48egpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
|
||||
}
|
||||
|
||||
static int dio48e_irq_set_type(struct irq_data *data, unsigned flow_type)
|
||||
|
@ -329,11 +329,11 @@ static irqreturn_t dio48e_irq_handler(int irq, void *dev_id)
|
|||
generic_handle_irq(irq_find_mapping(chip->irqdomain,
|
||||
19 + gpio*24));
|
||||
|
||||
spin_lock(&dio48egpio->lock);
|
||||
raw_spin_lock(&dio48egpio->lock);
|
||||
|
||||
outb(0x00, dio48egpio->base + 0xF);
|
||||
|
||||
spin_unlock(&dio48egpio->lock);
|
||||
raw_spin_unlock(&dio48egpio->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -388,7 +388,7 @@ static int dio48e_probe(struct device *dev, unsigned int id)
|
|||
dio48egpio->chip.set_multiple = dio48e_gpio_set_multiple;
|
||||
dio48egpio->base = base[id];
|
||||
|
||||
spin_lock_init(&dio48egpio->lock);
|
||||
raw_spin_lock_init(&dio48egpio->lock);
|
||||
|
||||
err = devm_gpiochip_add_data(dev, &dio48egpio->chip, dio48egpio);
|
||||
if (err) {
|
||||
|
|
|
@ -51,7 +51,7 @@ MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line numbers");
|
|||
*/
|
||||
struct idi_48_gpio {
|
||||
struct gpio_chip chip;
|
||||
spinlock_t lock;
|
||||
raw_spinlock_t lock;
|
||||
spinlock_t ack_lock;
|
||||
unsigned char irq_mask[6];
|
||||
unsigned base;
|
||||
|
@ -112,11 +112,12 @@ static void idi_48_irq_mask(struct irq_data *data)
|
|||
if (!idi48gpio->irq_mask[boundary]) {
|
||||
idi48gpio->cos_enb &= ~BIT(boundary);
|
||||
|
||||
spin_lock_irqsave(&idi48gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&idi48gpio->lock, flags);
|
||||
|
||||
outb(idi48gpio->cos_enb, idi48gpio->base + 7);
|
||||
|
||||
spin_unlock_irqrestore(&idi48gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&idi48gpio->lock,
|
||||
flags);
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -145,11 +146,12 @@ static void idi_48_irq_unmask(struct irq_data *data)
|
|||
if (!prev_irq_mask) {
|
||||
idi48gpio->cos_enb |= BIT(boundary);
|
||||
|
||||
spin_lock_irqsave(&idi48gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&idi48gpio->lock, flags);
|
||||
|
||||
outb(idi48gpio->cos_enb, idi48gpio->base + 7);
|
||||
|
||||
spin_unlock_irqrestore(&idi48gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&idi48gpio->lock,
|
||||
flags);
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -186,11 +188,11 @@ static irqreturn_t idi_48_irq_handler(int irq, void *dev_id)
|
|||
|
||||
spin_lock(&idi48gpio->ack_lock);
|
||||
|
||||
spin_lock(&idi48gpio->lock);
|
||||
raw_spin_lock(&idi48gpio->lock);
|
||||
|
||||
cos_status = inb(idi48gpio->base + 7);
|
||||
|
||||
spin_unlock(&idi48gpio->lock);
|
||||
raw_spin_unlock(&idi48gpio->lock);
|
||||
|
||||
/* IRQ Status (bit 6) is active low (0 = IRQ generated by device) */
|
||||
if (cos_status & BIT(6)) {
|
||||
|
@ -256,7 +258,7 @@ static int idi_48_probe(struct device *dev, unsigned int id)
|
|||
idi48gpio->chip.get = idi_48_gpio_get;
|
||||
idi48gpio->base = base[id];
|
||||
|
||||
spin_lock_init(&idi48gpio->lock);
|
||||
raw_spin_lock_init(&idi48gpio->lock);
|
||||
spin_lock_init(&idi48gpio->ack_lock);
|
||||
|
||||
err = devm_gpiochip_add_data(dev, &idi48gpio->chip, idi48gpio);
|
||||
|
|
|
@ -50,7 +50,7 @@ MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers");
|
|||
*/
|
||||
struct idio_16_gpio {
|
||||
struct gpio_chip chip;
|
||||
spinlock_t lock;
|
||||
raw_spinlock_t lock;
|
||||
unsigned long irq_mask;
|
||||
unsigned base;
|
||||
unsigned out_state;
|
||||
|
@ -99,7 +99,7 @@ static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
|||
if (offset > 15)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&idio16gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&idio16gpio->lock, flags);
|
||||
|
||||
if (value)
|
||||
idio16gpio->out_state |= mask;
|
||||
|
@ -111,7 +111,7 @@ static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
|||
else
|
||||
outb(idio16gpio->out_state, idio16gpio->base);
|
||||
|
||||
spin_unlock_irqrestore(&idio16gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
|
||||
}
|
||||
|
||||
static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
|
||||
|
@ -120,7 +120,7 @@ static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
|
|||
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&idio16gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&idio16gpio->lock, flags);
|
||||
|
||||
idio16gpio->out_state &= ~*mask;
|
||||
idio16gpio->out_state |= *mask & *bits;
|
||||
|
@ -130,7 +130,7 @@ static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
|
|||
if ((*mask >> 8) & 0xFF)
|
||||
outb(idio16gpio->out_state >> 8, idio16gpio->base + 4);
|
||||
|
||||
spin_unlock_irqrestore(&idio16gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
|
||||
}
|
||||
|
||||
static void idio_16_irq_ack(struct irq_data *data)
|
||||
|
@ -147,11 +147,11 @@ static void idio_16_irq_mask(struct irq_data *data)
|
|||
idio16gpio->irq_mask &= ~mask;
|
||||
|
||||
if (!idio16gpio->irq_mask) {
|
||||
spin_lock_irqsave(&idio16gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&idio16gpio->lock, flags);
|
||||
|
||||
outb(0, idio16gpio->base + 2);
|
||||
|
||||
spin_unlock_irqrestore(&idio16gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -166,11 +166,11 @@ static void idio_16_irq_unmask(struct irq_data *data)
|
|||
idio16gpio->irq_mask |= mask;
|
||||
|
||||
if (!prev_irq_mask) {
|
||||
spin_lock_irqsave(&idio16gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&idio16gpio->lock, flags);
|
||||
|
||||
inb(idio16gpio->base + 2);
|
||||
|
||||
spin_unlock_irqrestore(&idio16gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,11 +201,11 @@ static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
|
|||
for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
|
||||
generic_handle_irq(irq_find_mapping(chip->irqdomain, gpio));
|
||||
|
||||
spin_lock(&idio16gpio->lock);
|
||||
raw_spin_lock(&idio16gpio->lock);
|
||||
|
||||
outb(0, idio16gpio->base + 1);
|
||||
|
||||
spin_unlock(&idio16gpio->lock);
|
||||
raw_spin_unlock(&idio16gpio->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -249,7 +249,7 @@ static int idio_16_probe(struct device *dev, unsigned int id)
|
|||
idio16gpio->base = base[id];
|
||||
idio16gpio->out_state = 0xFFFF;
|
||||
|
||||
spin_lock_init(&idio16gpio->lock);
|
||||
raw_spin_lock_init(&idio16gpio->lock);
|
||||
|
||||
err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
|
||||
if (err) {
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
*/
|
||||
struct altera_gpio_chip {
|
||||
struct of_mm_gpio_chip mmchip;
|
||||
spinlock_t gpio_lock;
|
||||
raw_spinlock_t gpio_lock;
|
||||
int interrupt_trigger;
|
||||
int mapped_irq;
|
||||
};
|
||||
|
@ -53,12 +53,12 @@ static void altera_gpio_irq_unmask(struct irq_data *d)
|
|||
altera_gc = gpiochip_get_data(irq_data_get_irq_chip_data(d));
|
||||
mm_gc = &altera_gc->mmchip;
|
||||
|
||||
spin_lock_irqsave(&altera_gc->gpio_lock, flags);
|
||||
raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags);
|
||||
intmask = readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK);
|
||||
/* Set ALTERA_GPIO_IRQ_MASK bit to unmask */
|
||||
intmask |= BIT(irqd_to_hwirq(d));
|
||||
writel(intmask, mm_gc->regs + ALTERA_GPIO_IRQ_MASK);
|
||||
spin_unlock_irqrestore(&altera_gc->gpio_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags);
|
||||
}
|
||||
|
||||
static void altera_gpio_irq_mask(struct irq_data *d)
|
||||
|
@ -71,12 +71,12 @@ static void altera_gpio_irq_mask(struct irq_data *d)
|
|||
altera_gc = gpiochip_get_data(irq_data_get_irq_chip_data(d));
|
||||
mm_gc = &altera_gc->mmchip;
|
||||
|
||||
spin_lock_irqsave(&altera_gc->gpio_lock, flags);
|
||||
raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags);
|
||||
intmask = readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK);
|
||||
/* Clear ALTERA_GPIO_IRQ_MASK bit to mask */
|
||||
intmask &= ~BIT(irqd_to_hwirq(d));
|
||||
writel(intmask, mm_gc->regs + ALTERA_GPIO_IRQ_MASK);
|
||||
spin_unlock_irqrestore(&altera_gc->gpio_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -140,14 +140,14 @@ static void altera_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
|
|||
mm_gc = to_of_mm_gpio_chip(gc);
|
||||
chip = gpiochip_get_data(gc);
|
||||
|
||||
spin_lock_irqsave(&chip->gpio_lock, flags);
|
||||
raw_spin_lock_irqsave(&chip->gpio_lock, flags);
|
||||
data_reg = readl(mm_gc->regs + ALTERA_GPIO_DATA);
|
||||
if (value)
|
||||
data_reg |= BIT(offset);
|
||||
else
|
||||
data_reg &= ~BIT(offset);
|
||||
writel(data_reg, mm_gc->regs + ALTERA_GPIO_DATA);
|
||||
spin_unlock_irqrestore(&chip->gpio_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&chip->gpio_lock, flags);
|
||||
}
|
||||
|
||||
static int altera_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
|
||||
|
@ -160,12 +160,12 @@ static int altera_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
|
|||
mm_gc = to_of_mm_gpio_chip(gc);
|
||||
chip = gpiochip_get_data(gc);
|
||||
|
||||
spin_lock_irqsave(&chip->gpio_lock, flags);
|
||||
raw_spin_lock_irqsave(&chip->gpio_lock, flags);
|
||||
/* Set pin as input, assumes software controlled IP */
|
||||
gpio_ddr = readl(mm_gc->regs + ALTERA_GPIO_DIR);
|
||||
gpio_ddr &= ~BIT(offset);
|
||||
writel(gpio_ddr, mm_gc->regs + ALTERA_GPIO_DIR);
|
||||
spin_unlock_irqrestore(&chip->gpio_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&chip->gpio_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ static int altera_gpio_direction_output(struct gpio_chip *gc,
|
|||
mm_gc = to_of_mm_gpio_chip(gc);
|
||||
chip = gpiochip_get_data(gc);
|
||||
|
||||
spin_lock_irqsave(&chip->gpio_lock, flags);
|
||||
raw_spin_lock_irqsave(&chip->gpio_lock, flags);
|
||||
/* Sets the GPIO value */
|
||||
data_reg = readl(mm_gc->regs + ALTERA_GPIO_DATA);
|
||||
if (value)
|
||||
|
@ -194,7 +194,7 @@ static int altera_gpio_direction_output(struct gpio_chip *gc,
|
|||
gpio_ddr = readl(mm_gc->regs + ALTERA_GPIO_DIR);
|
||||
gpio_ddr |= BIT(offset);
|
||||
writel(gpio_ddr, mm_gc->regs + ALTERA_GPIO_DIR);
|
||||
spin_unlock_irqrestore(&chip->gpio_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&chip->gpio_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -262,7 +262,7 @@ static int altera_gpio_probe(struct platform_device *pdev)
|
|||
if (!altera_gc)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&altera_gc->gpio_lock);
|
||||
raw_spin_lock_init(&altera_gc->gpio_lock);
|
||||
|
||||
if (of_property_read_u32(node, "altr,ngpio", ®))
|
||||
/* By default assume maximum ngpio */
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
#include <linux/mfd/arizona/core.h>
|
||||
|
@ -41,13 +42,38 @@ static int arizona_gpio_get(struct gpio_chip *chip, unsigned offset)
|
|||
{
|
||||
struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
|
||||
struct arizona *arizona = arizona_gpio->arizona;
|
||||
unsigned int val;
|
||||
unsigned int reg, val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(arizona->regmap, ARIZONA_GPIO1_CTRL + offset, &val);
|
||||
reg = ARIZONA_GPIO1_CTRL + offset;
|
||||
ret = regmap_read(arizona->regmap, reg, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Resume to read actual registers for input pins */
|
||||
if (val & ARIZONA_GPN_DIR) {
|
||||
ret = pm_runtime_get_sync(chip->parent);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->parent, "Failed to resume: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Register is cached, drop it to ensure a physical read */
|
||||
ret = regcache_drop_region(arizona->regmap, reg, reg);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->parent, "Failed to drop cache: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_read(arizona->regmap, reg, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
pm_runtime_mark_last_busy(chip->parent);
|
||||
pm_runtime_put_autosuspend(chip->parent);
|
||||
}
|
||||
|
||||
if (val & ARIZONA_GPN_LVL)
|
||||
return 1;
|
||||
else
|
||||
|
|
|
@ -9,14 +9,18 @@
|
|||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/div64.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/hashtable.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/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
struct aspeed_bank_props {
|
||||
unsigned int bank;
|
||||
|
@ -29,59 +33,85 @@ struct aspeed_gpio_config {
|
|||
const struct aspeed_bank_props *props;
|
||||
};
|
||||
|
||||
/*
|
||||
* @offset_timer: Maps an offset to an @timer_users index, or zero if disabled
|
||||
* @timer_users: Tracks the number of users for each timer
|
||||
*
|
||||
* The @timer_users has four elements but the first element is unused. This is
|
||||
* to simplify accounting and indexing, as a zero value in @offset_timer
|
||||
* represents disabled debouncing for the GPIO. Any other value for an element
|
||||
* of @offset_timer is used as an index into @timer_users. This behaviour of
|
||||
* the zero value aligns with the behaviour of zero built from the timer
|
||||
* configuration registers (i.e. debouncing is disabled).
|
||||
*/
|
||||
struct aspeed_gpio {
|
||||
struct gpio_chip chip;
|
||||
spinlock_t lock;
|
||||
void __iomem *base;
|
||||
int irq;
|
||||
const struct aspeed_gpio_config *config;
|
||||
|
||||
u8 *offset_timer;
|
||||
unsigned int timer_users[4];
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
struct aspeed_gpio_bank {
|
||||
uint16_t val_regs;
|
||||
uint16_t irq_regs;
|
||||
uint16_t debounce_regs;
|
||||
const char names[4][3];
|
||||
};
|
||||
|
||||
static const int debounce_timers[4] = { 0x00, 0x50, 0x54, 0x58 };
|
||||
|
||||
static const struct aspeed_gpio_bank aspeed_gpio_banks[] = {
|
||||
{
|
||||
.val_regs = 0x0000,
|
||||
.irq_regs = 0x0008,
|
||||
.debounce_regs = 0x0040,
|
||||
.names = { "A", "B", "C", "D" },
|
||||
},
|
||||
{
|
||||
.val_regs = 0x0020,
|
||||
.irq_regs = 0x0028,
|
||||
.debounce_regs = 0x0048,
|
||||
.names = { "E", "F", "G", "H" },
|
||||
},
|
||||
{
|
||||
.val_regs = 0x0070,
|
||||
.irq_regs = 0x0098,
|
||||
.debounce_regs = 0x00b0,
|
||||
.names = { "I", "J", "K", "L" },
|
||||
},
|
||||
{
|
||||
.val_regs = 0x0078,
|
||||
.irq_regs = 0x00e8,
|
||||
.debounce_regs = 0x0100,
|
||||
.names = { "M", "N", "O", "P" },
|
||||
},
|
||||
{
|
||||
.val_regs = 0x0080,
|
||||
.irq_regs = 0x0118,
|
||||
.debounce_regs = 0x0130,
|
||||
.names = { "Q", "R", "S", "T" },
|
||||
},
|
||||
{
|
||||
.val_regs = 0x0088,
|
||||
.irq_regs = 0x0148,
|
||||
.debounce_regs = 0x0160,
|
||||
.names = { "U", "V", "W", "X" },
|
||||
},
|
||||
{
|
||||
.val_regs = 0x01E0,
|
||||
.irq_regs = 0x0178,
|
||||
.debounce_regs = 0x0190,
|
||||
.names = { "Y", "Z", "AA", "AB" },
|
||||
},
|
||||
{
|
||||
.val_regs = 0x01E8,
|
||||
.irq_regs = 0x01A8,
|
||||
.debounce_regs = 0x01c0,
|
||||
.names = { "AC", "", "", "" },
|
||||
},
|
||||
};
|
||||
|
@ -99,6 +129,13 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = {
|
|||
#define GPIO_IRQ_TYPE2 0x0c
|
||||
#define GPIO_IRQ_STATUS 0x10
|
||||
|
||||
#define GPIO_DEBOUNCE_SEL1 0x00
|
||||
#define GPIO_DEBOUNCE_SEL2 0x04
|
||||
|
||||
#define _GPIO_SET_DEBOUNCE(t, o, i) ((!!((t) & BIT(i))) << GPIO_OFFSET(o))
|
||||
#define GPIO_SET_DEBOUNCE1(t, o) _GPIO_SET_DEBOUNCE(t, o, 1)
|
||||
#define GPIO_SET_DEBOUNCE2(t, o) _GPIO_SET_DEBOUNCE(t, o, 0)
|
||||
|
||||
static const struct aspeed_gpio_bank *to_bank(unsigned int offset)
|
||||
{
|
||||
unsigned int bank = GPIO_BANK(offset);
|
||||
|
@ -144,6 +181,7 @@ static inline bool have_input(struct aspeed_gpio *gpio, unsigned int offset)
|
|||
}
|
||||
|
||||
#define have_irq(g, o) have_input((g), (o))
|
||||
#define have_debounce(g, o) have_input((g), (o))
|
||||
|
||||
static inline bool have_output(struct aspeed_gpio *gpio, unsigned int offset)
|
||||
{
|
||||
|
@ -506,6 +544,231 @@ static void aspeed_gpio_free(struct gpio_chip *chip, unsigned int offset)
|
|||
pinctrl_free_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static inline void __iomem *bank_debounce_reg(struct aspeed_gpio *gpio,
|
||||
const struct aspeed_gpio_bank *bank,
|
||||
unsigned int reg)
|
||||
{
|
||||
return gpio->base + bank->debounce_regs + reg;
|
||||
}
|
||||
|
||||
static int usecs_to_cycles(struct aspeed_gpio *gpio, unsigned long usecs,
|
||||
u32 *cycles)
|
||||
{
|
||||
u64 rate;
|
||||
u64 n;
|
||||
u32 r;
|
||||
|
||||
rate = clk_get_rate(gpio->clk);
|
||||
if (!rate)
|
||||
return -ENOTSUPP;
|
||||
|
||||
n = rate * usecs;
|
||||
r = do_div(n, 1000000);
|
||||
|
||||
if (n >= U32_MAX)
|
||||
return -ERANGE;
|
||||
|
||||
/* At least as long as the requested time */
|
||||
*cycles = n + (!!r);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Call under gpio->lock */
|
||||
static int register_allocated_timer(struct aspeed_gpio *gpio,
|
||||
unsigned int offset, unsigned int timer)
|
||||
{
|
||||
if (WARN(gpio->offset_timer[offset] != 0,
|
||||
"Offset %d already allocated timer %d\n",
|
||||
offset, gpio->offset_timer[offset]))
|
||||
return -EINVAL;
|
||||
|
||||
if (WARN(gpio->timer_users[timer] == UINT_MAX,
|
||||
"Timer user count would overflow\n"))
|
||||
return -EPERM;
|
||||
|
||||
gpio->offset_timer[offset] = timer;
|
||||
gpio->timer_users[timer]++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Call under gpio->lock */
|
||||
static int unregister_allocated_timer(struct aspeed_gpio *gpio,
|
||||
unsigned int offset)
|
||||
{
|
||||
if (WARN(gpio->offset_timer[offset] == 0,
|
||||
"No timer allocated to offset %d\n", offset))
|
||||
return -EINVAL;
|
||||
|
||||
if (WARN(gpio->timer_users[gpio->offset_timer[offset]] == 0,
|
||||
"No users recorded for timer %d\n",
|
||||
gpio->offset_timer[offset]))
|
||||
return -EINVAL;
|
||||
|
||||
gpio->timer_users[gpio->offset_timer[offset]]--;
|
||||
gpio->offset_timer[offset] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Call under gpio->lock */
|
||||
static inline bool timer_allocation_registered(struct aspeed_gpio *gpio,
|
||||
unsigned int offset)
|
||||
{
|
||||
return gpio->offset_timer[offset] > 0;
|
||||
}
|
||||
|
||||
/* Call under gpio->lock */
|
||||
static void configure_timer(struct aspeed_gpio *gpio, unsigned int offset,
|
||||
unsigned int timer)
|
||||
{
|
||||
const struct aspeed_gpio_bank *bank = to_bank(offset);
|
||||
const u32 mask = GPIO_BIT(offset);
|
||||
void __iomem *addr;
|
||||
u32 val;
|
||||
|
||||
addr = bank_debounce_reg(gpio, bank, GPIO_DEBOUNCE_SEL1);
|
||||
val = ioread32(addr);
|
||||
iowrite32((val & ~mask) | GPIO_SET_DEBOUNCE1(timer, offset), addr);
|
||||
|
||||
addr = bank_debounce_reg(gpio, bank, GPIO_DEBOUNCE_SEL2);
|
||||
val = ioread32(addr);
|
||||
iowrite32((val & ~mask) | GPIO_SET_DEBOUNCE2(timer, offset), addr);
|
||||
}
|
||||
|
||||
static int enable_debounce(struct gpio_chip *chip, unsigned int offset,
|
||||
unsigned long usecs)
|
||||
{
|
||||
struct aspeed_gpio *gpio = gpiochip_get_data(chip);
|
||||
u32 requested_cycles;
|
||||
unsigned long flags;
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
rc = usecs_to_cycles(gpio, usecs, &requested_cycles);
|
||||
if (rc < 0) {
|
||||
dev_warn(chip->parent, "Failed to convert %luus to cycles at %luHz: %d\n",
|
||||
usecs, clk_get_rate(gpio->clk), rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&gpio->lock, flags);
|
||||
|
||||
if (timer_allocation_registered(gpio, offset)) {
|
||||
rc = unregister_allocated_timer(gpio, offset);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Try to find a timer already configured for the debounce period */
|
||||
for (i = 1; i < ARRAY_SIZE(debounce_timers); i++) {
|
||||
u32 cycles;
|
||||
|
||||
cycles = ioread32(gpio->base + debounce_timers[i]);
|
||||
if (requested_cycles == cycles)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(debounce_timers)) {
|
||||
int j;
|
||||
|
||||
/*
|
||||
* As there are no timers configured for the requested debounce
|
||||
* period, find an unused timer instead
|
||||
*/
|
||||
for (j = 1; j < ARRAY_SIZE(gpio->timer_users); j++) {
|
||||
if (gpio->timer_users[j] == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (j == ARRAY_SIZE(gpio->timer_users)) {
|
||||
dev_warn(chip->parent,
|
||||
"Debounce timers exhausted, cannot debounce for period %luus\n",
|
||||
usecs);
|
||||
|
||||
rc = -EPERM;
|
||||
|
||||
/*
|
||||
* We already adjusted the accounting to remove @offset
|
||||
* as a user of its previous timer, so also configure
|
||||
* the hardware so @offset has timers disabled for
|
||||
* consistency.
|
||||
*/
|
||||
configure_timer(gpio, offset, 0);
|
||||
goto out;
|
||||
}
|
||||
|
||||
i = j;
|
||||
|
||||
iowrite32(requested_cycles, gpio->base + debounce_timers[i]);
|
||||
}
|
||||
|
||||
if (WARN(i == 0, "Cannot register index of disabled timer\n")) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
register_allocated_timer(gpio, offset, i);
|
||||
configure_timer(gpio, offset, i);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&gpio->lock, flags);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int disable_debounce(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct aspeed_gpio *gpio = gpiochip_get_data(chip);
|
||||
unsigned long flags;
|
||||
int rc;
|
||||
|
||||
spin_lock_irqsave(&gpio->lock, flags);
|
||||
|
||||
rc = unregister_allocated_timer(gpio, offset);
|
||||
if (!rc)
|
||||
configure_timer(gpio, offset, 0);
|
||||
|
||||
spin_unlock_irqrestore(&gpio->lock, flags);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int set_debounce(struct gpio_chip *chip, unsigned int offset,
|
||||
unsigned long usecs)
|
||||
{
|
||||
struct aspeed_gpio *gpio = gpiochip_get_data(chip);
|
||||
|
||||
if (!have_debounce(gpio, offset))
|
||||
return -ENOTSUPP;
|
||||
|
||||
if (usecs)
|
||||
return enable_debounce(chip, offset, usecs);
|
||||
|
||||
return disable_debounce(chip, offset);
|
||||
}
|
||||
|
||||
static int aspeed_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
|
||||
unsigned long config)
|
||||
{
|
||||
unsigned long param = pinconf_to_config_param(config);
|
||||
u32 arg = pinconf_to_config_argument(config);
|
||||
|
||||
if (param == PIN_CONFIG_INPUT_DEBOUNCE)
|
||||
return set_debounce(chip, offset, arg);
|
||||
else if (param == PIN_CONFIG_BIAS_DISABLE ||
|
||||
param == PIN_CONFIG_BIAS_PULL_DOWN ||
|
||||
param == PIN_CONFIG_DRIVE_STRENGTH)
|
||||
return pinctrl_gpio_set_config(offset, config);
|
||||
else if (param == PIN_CONFIG_DRIVE_OPEN_DRAIN ||
|
||||
param == PIN_CONFIG_DRIVE_OPEN_SOURCE)
|
||||
/* Return -ENOTSUPP to trigger emulation, as per datasheet */
|
||||
return -ENOTSUPP;
|
||||
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
/*
|
||||
* Any banks not specified in a struct aspeed_bank_props array are assumed to
|
||||
* have the properties:
|
||||
|
@ -565,8 +828,16 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
|
|||
if (!gpio_id)
|
||||
return -EINVAL;
|
||||
|
||||
gpio->clk = of_clk_get(pdev->dev.of_node, 0);
|
||||
if (IS_ERR(gpio->clk)) {
|
||||
dev_warn(&pdev->dev,
|
||||
"No HPLL clock phandle provided, debouncing disabled\n");
|
||||
gpio->clk = NULL;
|
||||
}
|
||||
|
||||
gpio->config = gpio_id->data;
|
||||
|
||||
gpio->chip.parent = &pdev->dev;
|
||||
gpio->chip.ngpio = gpio->config->nr_gpios;
|
||||
gpio->chip.parent = &pdev->dev;
|
||||
gpio->chip.direction_input = aspeed_gpio_dir_in;
|
||||
|
@ -576,6 +847,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
|
|||
gpio->chip.free = aspeed_gpio_free;
|
||||
gpio->chip.get = aspeed_gpio_get;
|
||||
gpio->chip.set = aspeed_gpio_set;
|
||||
gpio->chip.set_config = aspeed_gpio_set_config;
|
||||
gpio->chip.label = dev_name(&pdev->dev);
|
||||
gpio->chip.base = -1;
|
||||
gpio->chip.irq_need_valid_mask = true;
|
||||
|
@ -584,6 +856,9 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
|
|||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
gpio->offset_timer =
|
||||
devm_kzalloc(&pdev->dev, gpio->chip.ngpio, GFP_KERNEL);
|
||||
|
||||
return aspeed_gpio_setup_irqs(gpio, pdev);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
struct ath79_gpio_ctrl {
|
||||
struct gpio_chip gc;
|
||||
void __iomem *base;
|
||||
spinlock_t lock;
|
||||
raw_spinlock_t lock;
|
||||
unsigned long both_edges;
|
||||
};
|
||||
|
||||
|
@ -74,9 +74,9 @@ static void ath79_gpio_irq_unmask(struct irq_data *data)
|
|||
u32 mask = BIT(irqd_to_hwirq(data));
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ctrl->lock, flags);
|
||||
raw_spin_lock_irqsave(&ctrl->lock, flags);
|
||||
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_MASK, mask, mask);
|
||||
spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
}
|
||||
|
||||
static void ath79_gpio_irq_mask(struct irq_data *data)
|
||||
|
@ -85,9 +85,9 @@ static void ath79_gpio_irq_mask(struct irq_data *data)
|
|||
u32 mask = BIT(irqd_to_hwirq(data));
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ctrl->lock, flags);
|
||||
raw_spin_lock_irqsave(&ctrl->lock, flags);
|
||||
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_MASK, mask, 0);
|
||||
spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
}
|
||||
|
||||
static void ath79_gpio_irq_enable(struct irq_data *data)
|
||||
|
@ -96,10 +96,10 @@ static void ath79_gpio_irq_enable(struct irq_data *data)
|
|||
u32 mask = BIT(irqd_to_hwirq(data));
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ctrl->lock, flags);
|
||||
raw_spin_lock_irqsave(&ctrl->lock, flags);
|
||||
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_ENABLE, mask, mask);
|
||||
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_MASK, mask, mask);
|
||||
spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
}
|
||||
|
||||
static void ath79_gpio_irq_disable(struct irq_data *data)
|
||||
|
@ -108,10 +108,10 @@ static void ath79_gpio_irq_disable(struct irq_data *data)
|
|||
u32 mask = BIT(irqd_to_hwirq(data));
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ctrl->lock, flags);
|
||||
raw_spin_lock_irqsave(&ctrl->lock, flags);
|
||||
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_MASK, mask, 0);
|
||||
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_ENABLE, mask, 0);
|
||||
spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
}
|
||||
|
||||
static int ath79_gpio_irq_set_type(struct irq_data *data,
|
||||
|
@ -140,7 +140,7 @@ static int ath79_gpio_irq_set_type(struct irq_data *data,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&ctrl->lock, flags);
|
||||
raw_spin_lock_irqsave(&ctrl->lock, flags);
|
||||
|
||||
if (flow_type == IRQ_TYPE_EDGE_BOTH) {
|
||||
ctrl->both_edges |= mask;
|
||||
|
@ -165,7 +165,7 @@ static int ath79_gpio_irq_set_type(struct irq_data *data,
|
|||
ath79_gpio_update_bits(
|
||||
ctrl, AR71XX_GPIO_REG_INT_ENABLE, mask, mask);
|
||||
|
||||
spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -191,7 +191,7 @@ static void ath79_gpio_irq_handler(struct irq_desc *desc)
|
|||
|
||||
chained_irq_enter(irqchip, desc);
|
||||
|
||||
spin_lock_irqsave(&ctrl->lock, flags);
|
||||
raw_spin_lock_irqsave(&ctrl->lock, flags);
|
||||
|
||||
pending = ath79_gpio_read(ctrl, AR71XX_GPIO_REG_INT_PENDING);
|
||||
|
||||
|
@ -203,7 +203,7 @@ static void ath79_gpio_irq_handler(struct irq_desc *desc)
|
|||
both_edges, ~state);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
|
||||
if (pending) {
|
||||
for_each_set_bit(irq, &pending, gc->ngpio)
|
||||
|
@ -262,7 +262,7 @@ static int ath79_gpio_probe(struct platform_device *pdev)
|
|||
if (!ctrl->base)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&ctrl->lock);
|
||||
raw_spin_lock_init(&ctrl->lock);
|
||||
err = bgpio_init(&ctrl->gc, &pdev->dev, 4,
|
||||
ctrl->base + AR71XX_GPIO_REG_IN,
|
||||
ctrl->base + AR71XX_GPIO_REG_SET,
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
struct bcm_kona_gpio {
|
||||
void __iomem *reg_base;
|
||||
int num_bank;
|
||||
spinlock_t lock;
|
||||
raw_spinlock_t lock;
|
||||
struct gpio_chip gpio_chip;
|
||||
struct irq_domain *irq_domain;
|
||||
struct bcm_kona_gpio_bank *banks;
|
||||
|
@ -95,13 +95,13 @@ static void bcm_kona_gpio_lock_gpio(struct bcm_kona_gpio *kona_gpio,
|
|||
unsigned long flags;
|
||||
int bank_id = GPIO_BANK(gpio);
|
||||
|
||||
spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
|
||||
val = readl(kona_gpio->reg_base + GPIO_PWD_STATUS(bank_id));
|
||||
val |= BIT(gpio);
|
||||
bcm_kona_gpio_write_lock_regs(kona_gpio->reg_base, bank_id, val);
|
||||
|
||||
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||
}
|
||||
|
||||
static void bcm_kona_gpio_unlock_gpio(struct bcm_kona_gpio *kona_gpio,
|
||||
|
@ -111,13 +111,13 @@ static void bcm_kona_gpio_unlock_gpio(struct bcm_kona_gpio *kona_gpio,
|
|||
unsigned long flags;
|
||||
int bank_id = GPIO_BANK(gpio);
|
||||
|
||||
spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
|
||||
val = readl(kona_gpio->reg_base + GPIO_PWD_STATUS(bank_id));
|
||||
val &= ~BIT(gpio);
|
||||
bcm_kona_gpio_write_lock_regs(kona_gpio->reg_base, bank_id, val);
|
||||
|
||||
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||
}
|
||||
|
||||
static int bcm_kona_gpio_get_dir(struct gpio_chip *chip, unsigned gpio)
|
||||
|
@ -141,7 +141,7 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
|
|||
|
||||
kona_gpio = gpiochip_get_data(chip);
|
||||
reg_base = kona_gpio->reg_base;
|
||||
spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
|
||||
/* this function only applies to output pin */
|
||||
if (bcm_kona_gpio_get_dir(chip, gpio) == GPIOF_DIR_IN)
|
||||
|
@ -154,7 +154,7 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
|
|||
writel(val, reg_base + reg_offset);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||
}
|
||||
|
||||
static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio)
|
||||
|
@ -168,7 +168,7 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio)
|
|||
|
||||
kona_gpio = gpiochip_get_data(chip);
|
||||
reg_base = kona_gpio->reg_base;
|
||||
spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
|
||||
if (bcm_kona_gpio_get_dir(chip, gpio) == GPIOF_DIR_IN)
|
||||
reg_offset = GPIO_IN_STATUS(bank_id);
|
||||
|
@ -178,7 +178,7 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio)
|
|||
/* read the GPIO bank status */
|
||||
val = readl(reg_base + reg_offset);
|
||||
|
||||
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||
|
||||
/* return the specified bit status */
|
||||
return !!(val & BIT(bit));
|
||||
|
@ -208,14 +208,14 @@ static int bcm_kona_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
|
|||
|
||||
kona_gpio = gpiochip_get_data(chip);
|
||||
reg_base = kona_gpio->reg_base;
|
||||
spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
|
||||
val = readl(reg_base + GPIO_CONTROL(gpio));
|
||||
val &= ~GPIO_GPCTR0_IOTR_MASK;
|
||||
val |= GPIO_GPCTR0_IOTR_CMD_INPUT;
|
||||
writel(val, reg_base + GPIO_CONTROL(gpio));
|
||||
|
||||
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -232,7 +232,7 @@ static int bcm_kona_gpio_direction_output(struct gpio_chip *chip,
|
|||
|
||||
kona_gpio = gpiochip_get_data(chip);
|
||||
reg_base = kona_gpio->reg_base;
|
||||
spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
|
||||
val = readl(reg_base + GPIO_CONTROL(gpio));
|
||||
val &= ~GPIO_GPCTR0_IOTR_MASK;
|
||||
|
@ -244,7 +244,7 @@ static int bcm_kona_gpio_direction_output(struct gpio_chip *chip,
|
|||
val |= BIT(bit);
|
||||
writel(val, reg_base + reg_offset);
|
||||
|
||||
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -288,7 +288,7 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio,
|
|||
}
|
||||
|
||||
/* spin lock for read-modify-write of the GPIO register */
|
||||
spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
|
||||
val = readl(reg_base + GPIO_CONTROL(gpio));
|
||||
val &= ~GPIO_GPCTR0_DBR_MASK;
|
||||
|
@ -303,7 +303,7 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio,
|
|||
|
||||
writel(val, reg_base + GPIO_CONTROL(gpio));
|
||||
|
||||
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -347,13 +347,13 @@ static void bcm_kona_gpio_irq_ack(struct irq_data *d)
|
|||
|
||||
kona_gpio = irq_data_get_irq_chip_data(d);
|
||||
reg_base = kona_gpio->reg_base;
|
||||
spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
|
||||
val = readl(reg_base + GPIO_INT_STATUS(bank_id));
|
||||
val |= BIT(bit);
|
||||
writel(val, reg_base + GPIO_INT_STATUS(bank_id));
|
||||
|
||||
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||
}
|
||||
|
||||
static void bcm_kona_gpio_irq_mask(struct irq_data *d)
|
||||
|
@ -368,13 +368,13 @@ static void bcm_kona_gpio_irq_mask(struct irq_data *d)
|
|||
|
||||
kona_gpio = irq_data_get_irq_chip_data(d);
|
||||
reg_base = kona_gpio->reg_base;
|
||||
spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
|
||||
val = readl(reg_base + GPIO_INT_MASK(bank_id));
|
||||
val |= BIT(bit);
|
||||
writel(val, reg_base + GPIO_INT_MASK(bank_id));
|
||||
|
||||
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||
}
|
||||
|
||||
static void bcm_kona_gpio_irq_unmask(struct irq_data *d)
|
||||
|
@ -389,13 +389,13 @@ static void bcm_kona_gpio_irq_unmask(struct irq_data *d)
|
|||
|
||||
kona_gpio = irq_data_get_irq_chip_data(d);
|
||||
reg_base = kona_gpio->reg_base;
|
||||
spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
|
||||
val = readl(reg_base + GPIO_INT_MSKCLR(bank_id));
|
||||
val |= BIT(bit);
|
||||
writel(val, reg_base + GPIO_INT_MSKCLR(bank_id));
|
||||
|
||||
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||
}
|
||||
|
||||
static int bcm_kona_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
|
@ -431,14 +431,14 @@ static int bcm_kona_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
|
||||
val = readl(reg_base + GPIO_CONTROL(gpio));
|
||||
val &= ~GPIO_GPCTR0_ITR_MASK;
|
||||
val |= lvl_type << GPIO_GPCTR0_ITR_SHIFT;
|
||||
writel(val, reg_base + GPIO_CONTROL(gpio));
|
||||
|
||||
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -655,7 +655,7 @@ static int bcm_kona_gpio_probe(struct platform_device *pdev)
|
|||
bank);
|
||||
}
|
||||
|
||||
spin_lock_init(&kona_gpio->lock);
|
||||
raw_spin_lock_init(&kona_gpio->lock);
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* ROHM BD9571MWV-M GPIO driver
|
||||
*
|
||||
* Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.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 "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether expressed or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License version 2 for more details.
|
||||
*
|
||||
* Based on the TPS65086 driver
|
||||
*
|
||||
* NOTE: Interrupts are not supported yet.
|
||||
*/
|
||||
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <linux/mfd/bd9571mwv.h>
|
||||
|
||||
struct bd9571mwv_gpio {
|
||||
struct gpio_chip chip;
|
||||
struct bd9571mwv *bd;
|
||||
};
|
||||
|
||||
static int bd9571mwv_gpio_get_direction(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip);
|
||||
int ret, val;
|
||||
|
||||
ret = regmap_read(gpio->bd->regmap, BD9571MWV_GPIO_DIR, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return val & BIT(offset);
|
||||
}
|
||||
|
||||
static int bd9571mwv_gpio_direction_input(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip);
|
||||
|
||||
regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_DIR,
|
||||
BIT(offset), 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bd9571mwv_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip);
|
||||
|
||||
/* Set the initial value */
|
||||
regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_OUT,
|
||||
BIT(offset), value ? BIT(offset) : 0);
|
||||
regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_DIR,
|
||||
BIT(offset), BIT(offset));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bd9571mwv_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip);
|
||||
int ret, val;
|
||||
|
||||
ret = regmap_read(gpio->bd->regmap, BD9571MWV_GPIO_IN, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return val & BIT(offset);
|
||||
}
|
||||
|
||||
static void bd9571mwv_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip);
|
||||
|
||||
regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_OUT,
|
||||
BIT(offset), value ? BIT(offset) : 0);
|
||||
}
|
||||
|
||||
static const struct gpio_chip template_chip = {
|
||||
.label = "bd9571mwv-gpio",
|
||||
.owner = THIS_MODULE,
|
||||
.get_direction = bd9571mwv_gpio_get_direction,
|
||||
.direction_input = bd9571mwv_gpio_direction_input,
|
||||
.direction_output = bd9571mwv_gpio_direction_output,
|
||||
.get = bd9571mwv_gpio_get,
|
||||
.set = bd9571mwv_gpio_set,
|
||||
.base = -1,
|
||||
.ngpio = 2,
|
||||
.can_sleep = true,
|
||||
};
|
||||
|
||||
static int bd9571mwv_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct bd9571mwv_gpio *gpio;
|
||||
int ret;
|
||||
|
||||
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
|
||||
if (!gpio)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, gpio);
|
||||
|
||||
gpio->bd = dev_get_drvdata(pdev->dev.parent);
|
||||
gpio->chip = template_chip;
|
||||
gpio->chip.parent = gpio->bd->dev;
|
||||
|
||||
ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id bd9571mwv_gpio_id_table[] = {
|
||||
{ "bd9571mwv-gpio", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, bd9571mwv_gpio_id_table);
|
||||
|
||||
static struct platform_driver bd9571mwv_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "bd9571mwv-gpio",
|
||||
},
|
||||
.probe = bd9571mwv_gpio_probe,
|
||||
.id_table = bd9571mwv_gpio_id_table,
|
||||
};
|
||||
module_platform_driver(bd9571mwv_gpio_driver);
|
||||
|
||||
MODULE_AUTHOR("Marek Vasut <marek.vasut+renesas@gmail.com>");
|
||||
MODULE_DESCRIPTION("BD9571MWV GPIO driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -483,7 +483,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
|
|||
clk_prepare_enable(clk);
|
||||
|
||||
if (!pdata->gpio_unbanked) {
|
||||
irq = irq_alloc_descs(-1, 0, ngpio, 0);
|
||||
irq = devm_irq_alloc_descs(dev, -1, 0, ngpio, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "Couldn't allocate IRQ numbers\n");
|
||||
return irq;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
|
@ -55,6 +56,14 @@
|
|||
#define GPIO_SWPORT_DR_SIZE (GPIO_SWPORTB_DR - GPIO_SWPORTA_DR)
|
||||
#define GPIO_SWPORT_DDR_SIZE (GPIO_SWPORTB_DDR - GPIO_SWPORTA_DDR)
|
||||
|
||||
#define GPIO_REG_OFFSET_V2 1
|
||||
|
||||
#define GPIO_INTMASK_V2 0x44
|
||||
#define GPIO_INTTYPE_LEVEL_V2 0x34
|
||||
#define GPIO_INT_POLARITY_V2 0x38
|
||||
#define GPIO_INTSTATUS_V2 0x3c
|
||||
#define GPIO_PORTA_EOI_V2 0x40
|
||||
|
||||
struct dwapb_gpio;
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
@ -87,14 +96,41 @@ struct dwapb_gpio {
|
|||
struct dwapb_gpio_port *ports;
|
||||
unsigned int nr_ports;
|
||||
struct irq_domain *domain;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
static inline u32 gpio_reg_v2_convert(unsigned int offset)
|
||||
{
|
||||
switch (offset) {
|
||||
case GPIO_INTMASK:
|
||||
return GPIO_INTMASK_V2;
|
||||
case GPIO_INTTYPE_LEVEL:
|
||||
return GPIO_INTTYPE_LEVEL_V2;
|
||||
case GPIO_INT_POLARITY:
|
||||
return GPIO_INT_POLARITY_V2;
|
||||
case GPIO_INTSTATUS:
|
||||
return GPIO_INTSTATUS_V2;
|
||||
case GPIO_PORTA_EOI:
|
||||
return GPIO_PORTA_EOI_V2;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static inline u32 gpio_reg_convert(struct dwapb_gpio *gpio, unsigned int offset)
|
||||
{
|
||||
if (gpio->flags & GPIO_REG_OFFSET_V2)
|
||||
return gpio_reg_v2_convert(offset);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static inline u32 dwapb_read(struct dwapb_gpio *gpio, unsigned int offset)
|
||||
{
|
||||
struct gpio_chip *gc = &gpio->ports[0].gc;
|
||||
void __iomem *reg_base = gpio->regs;
|
||||
|
||||
return gc->read_reg(reg_base + offset);
|
||||
return gc->read_reg(reg_base + gpio_reg_convert(gpio, offset));
|
||||
}
|
||||
|
||||
static inline void dwapb_write(struct dwapb_gpio *gpio, unsigned int offset,
|
||||
|
@ -103,7 +139,7 @@ static inline void dwapb_write(struct dwapb_gpio *gpio, unsigned int offset,
|
|||
struct gpio_chip *gc = &gpio->ports[0].gc;
|
||||
void __iomem *reg_base = gpio->regs;
|
||||
|
||||
gc->write_reg(reg_base + offset, val);
|
||||
gc->write_reg(reg_base + gpio_reg_convert(gpio, offset), val);
|
||||
}
|
||||
|
||||
static int dwapb_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
|
||||
|
@ -128,7 +164,7 @@ static void dwapb_toggle_trigger(struct dwapb_gpio *gpio, unsigned int offs)
|
|||
|
||||
static u32 dwapb_do_irq(struct dwapb_gpio *gpio)
|
||||
{
|
||||
u32 irq_status = readl_relaxed(gpio->regs + GPIO_INTSTATUS);
|
||||
u32 irq_status = dwapb_read(gpio, GPIO_INTSTATUS);
|
||||
u32 ret = irq_status;
|
||||
|
||||
while (irq_status) {
|
||||
|
@ -348,8 +384,8 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
|
|||
ct->chip.irq_disable = dwapb_irq_disable;
|
||||
ct->chip.irq_request_resources = dwapb_irq_reqres;
|
||||
ct->chip.irq_release_resources = dwapb_irq_relres;
|
||||
ct->regs.ack = GPIO_PORTA_EOI;
|
||||
ct->regs.mask = GPIO_INTMASK;
|
||||
ct->regs.ack = gpio_reg_convert(gpio, GPIO_PORTA_EOI);
|
||||
ct->regs.mask = gpio_reg_convert(gpio, GPIO_INTMASK);
|
||||
ct->type = IRQ_TYPE_LEVEL_MASK;
|
||||
}
|
||||
|
||||
|
@ -532,6 +568,21 @@ dwapb_gpio_get_pdata(struct device *dev)
|
|||
return pdata;
|
||||
}
|
||||
|
||||
static const struct of_device_id dwapb_of_match[] = {
|
||||
{ .compatible = "snps,dw-apb-gpio", .data = (void *)0},
|
||||
{ .compatible = "apm,xgene-gpio-v2", .data = (void *)GPIO_REG_OFFSET_V2},
|
||||
{ /* Sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dwapb_of_match);
|
||||
|
||||
static const struct acpi_device_id dwapb_acpi_match[] = {
|
||||
{"HISI0181", 0},
|
||||
{"APMC0D07", 0},
|
||||
{"APMC0D81", GPIO_REG_OFFSET_V2},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, dwapb_acpi_match);
|
||||
|
||||
static int dwapb_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
unsigned int i;
|
||||
|
@ -567,6 +618,25 @@ static int dwapb_gpio_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(gpio->regs))
|
||||
return PTR_ERR(gpio->regs);
|
||||
|
||||
gpio->flags = 0;
|
||||
if (dev->of_node) {
|
||||
const struct of_device_id *of_devid;
|
||||
|
||||
of_devid = of_match_device(dwapb_of_match, dev);
|
||||
if (of_devid) {
|
||||
if (of_devid->data)
|
||||
gpio->flags = (uintptr_t)of_devid->data;
|
||||
}
|
||||
} else if (has_acpi_companion(dev)) {
|
||||
const struct acpi_device_id *acpi_id;
|
||||
|
||||
acpi_id = acpi_match_device(dwapb_acpi_match, dev);
|
||||
if (acpi_id) {
|
||||
if (acpi_id->driver_data)
|
||||
gpio->flags = acpi_id->driver_data;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < gpio->nr_ports; i++) {
|
||||
err = dwapb_gpio_add_port(gpio, &pdata->properties[i], i);
|
||||
if (err)
|
||||
|
@ -593,19 +663,6 @@ static int dwapb_gpio_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id dwapb_of_match[] = {
|
||||
{ .compatible = "snps,dw-apb-gpio" },
|
||||
{ /* Sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dwapb_of_match);
|
||||
|
||||
static const struct acpi_device_id dwapb_acpi_match[] = {
|
||||
{"HISI0181", 0},
|
||||
{"APMC0D07", 0},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, dwapb_acpi_match);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int dwapb_gpio_suspend(struct device *dev)
|
||||
{
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
struct etraxfs_gpio_info;
|
||||
|
||||
struct etraxfs_gpio_block {
|
||||
spinlock_t lock;
|
||||
raw_spinlock_t lock;
|
||||
u32 mask;
|
||||
u32 cfg;
|
||||
u32 pins;
|
||||
|
@ -233,10 +233,10 @@ static void etraxfs_gpio_irq_mask(struct irq_data *d)
|
|||
struct etraxfs_gpio_block *block = chip->block;
|
||||
unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
|
||||
|
||||
spin_lock(&block->lock);
|
||||
raw_spin_lock(&block->lock);
|
||||
block->mask &= ~BIT(grpirq);
|
||||
writel(block->mask, block->regs + block->info->rw_intr_mask);
|
||||
spin_unlock(&block->lock);
|
||||
raw_spin_unlock(&block->lock);
|
||||
}
|
||||
|
||||
static void etraxfs_gpio_irq_unmask(struct irq_data *d)
|
||||
|
@ -246,10 +246,10 @@ static void etraxfs_gpio_irq_unmask(struct irq_data *d)
|
|||
struct etraxfs_gpio_block *block = chip->block;
|
||||
unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
|
||||
|
||||
spin_lock(&block->lock);
|
||||
raw_spin_lock(&block->lock);
|
||||
block->mask |= BIT(grpirq);
|
||||
writel(block->mask, block->regs + block->info->rw_intr_mask);
|
||||
spin_unlock(&block->lock);
|
||||
raw_spin_unlock(&block->lock);
|
||||
}
|
||||
|
||||
static int etraxfs_gpio_irq_set_type(struct irq_data *d, u32 type)
|
||||
|
@ -280,11 +280,11 @@ static int etraxfs_gpio_irq_set_type(struct irq_data *d, u32 type)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock(&block->lock);
|
||||
raw_spin_lock(&block->lock);
|
||||
block->cfg &= ~(0x7 << (grpirq * 3));
|
||||
block->cfg |= (cfg << (grpirq * 3));
|
||||
writel(block->cfg, block->regs + block->info->rw_intr_cfg);
|
||||
spin_unlock(&block->lock);
|
||||
raw_spin_unlock(&block->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -297,7 +297,7 @@ static int etraxfs_gpio_irq_request_resources(struct irq_data *d)
|
|||
unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
|
||||
int ret = -EBUSY;
|
||||
|
||||
spin_lock(&block->lock);
|
||||
raw_spin_lock(&block->lock);
|
||||
if (block->group[grpirq])
|
||||
goto out;
|
||||
|
||||
|
@ -316,7 +316,7 @@ static int etraxfs_gpio_irq_request_resources(struct irq_data *d)
|
|||
}
|
||||
|
||||
out:
|
||||
spin_unlock(&block->lock);
|
||||
raw_spin_unlock(&block->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -327,10 +327,10 @@ static void etraxfs_gpio_irq_release_resources(struct irq_data *d)
|
|||
struct etraxfs_gpio_block *block = chip->block;
|
||||
unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
|
||||
|
||||
spin_lock(&block->lock);
|
||||
raw_spin_lock(&block->lock);
|
||||
block->group[grpirq] = 0;
|
||||
gpiochip_unlock_as_irq(&chip->gc, d->hwirq);
|
||||
spin_unlock(&block->lock);
|
||||
raw_spin_unlock(&block->lock);
|
||||
}
|
||||
|
||||
static struct irq_chip etraxfs_gpio_irq_chip = {
|
||||
|
@ -391,7 +391,7 @@ static int etraxfs_gpio_probe(struct platform_device *pdev)
|
|||
if (!block)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&block->lock);
|
||||
raw_spin_lock_init(&block->lock);
|
||||
|
||||
block->regs = regs;
|
||||
block->info = info;
|
||||
|
|
|
@ -59,17 +59,6 @@ static int exar_set_direction(struct gpio_chip *chip, int direction,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int exar_direction_output(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
return exar_set_direction(chip, 0, offset);
|
||||
}
|
||||
|
||||
static int exar_direction_input(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
return exar_set_direction(chip, 1, offset);
|
||||
}
|
||||
|
||||
static int exar_get(struct gpio_chip *chip, unsigned int reg)
|
||||
{
|
||||
struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
|
||||
|
@ -116,6 +105,18 @@ static void exar_set_value(struct gpio_chip *chip, unsigned int offset,
|
|||
exar_update(chip, addr, value, offset % 8);
|
||||
}
|
||||
|
||||
static int exar_direction_output(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
exar_set_value(chip, offset, value);
|
||||
return exar_set_direction(chip, 0, offset);
|
||||
}
|
||||
|
||||
static int exar_direction_input(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
return exar_set_direction(chip, 1, offset);
|
||||
}
|
||||
|
||||
static int gpio_exar_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pci_dev *pcidev = platform_get_drvdata(pdev);
|
||||
|
|
|
@ -37,14 +37,16 @@
|
|||
#define SIO_F71869A_ID 0x1007 /* F71869A chipset ID */
|
||||
#define SIO_F71882_ID 0x0541 /* F71882 chipset ID */
|
||||
#define SIO_F71889_ID 0x0909 /* F71889 chipset ID */
|
||||
#define SIO_F71889A_ID 0x1005 /* F71889A chipset ID */
|
||||
#define SIO_F81866_ID 0x1010 /* F81866 chipset ID */
|
||||
|
||||
enum chips { f71869, f71869a, f71882fg, f71889f, f81866 };
|
||||
enum chips { f71869, f71869a, f71882fg, f71889a, f71889f, f81866 };
|
||||
|
||||
static const char * const f7188x_names[] = {
|
||||
"f71869",
|
||||
"f71869a",
|
||||
"f71882fg",
|
||||
"f71889a",
|
||||
"f71889f",
|
||||
"f81866",
|
||||
};
|
||||
|
@ -187,6 +189,17 @@ static struct f7188x_gpio_bank f71882_gpio_bank[] = {
|
|||
F7188X_GPIO_BANK(40, 4, 0xB0),
|
||||
};
|
||||
|
||||
static struct f7188x_gpio_bank f71889a_gpio_bank[] = {
|
||||
F7188X_GPIO_BANK(0, 7, 0xF0),
|
||||
F7188X_GPIO_BANK(10, 7, 0xE0),
|
||||
F7188X_GPIO_BANK(20, 8, 0xD0),
|
||||
F7188X_GPIO_BANK(30, 8, 0xC0),
|
||||
F7188X_GPIO_BANK(40, 8, 0xB0),
|
||||
F7188X_GPIO_BANK(50, 5, 0xA0),
|
||||
F7188X_GPIO_BANK(60, 8, 0x90),
|
||||
F7188X_GPIO_BANK(70, 8, 0x80),
|
||||
};
|
||||
|
||||
static struct f7188x_gpio_bank f71889_gpio_bank[] = {
|
||||
F7188X_GPIO_BANK(0, 7, 0xF0),
|
||||
F7188X_GPIO_BANK(10, 7, 0xE0),
|
||||
|
@ -382,6 +395,10 @@ static int f7188x_gpio_probe(struct platform_device *pdev)
|
|||
data->nr_bank = ARRAY_SIZE(f71882_gpio_bank);
|
||||
data->bank = f71882_gpio_bank;
|
||||
break;
|
||||
case f71889a:
|
||||
data->nr_bank = ARRAY_SIZE(f71889a_gpio_bank);
|
||||
data->bank = f71889a_gpio_bank;
|
||||
break;
|
||||
case f71889f:
|
||||
data->nr_bank = ARRAY_SIZE(f71889_gpio_bank);
|
||||
data->bank = f71889_gpio_bank;
|
||||
|
@ -443,6 +460,9 @@ static int __init f7188x_find(int addr, struct f7188x_sio *sio)
|
|||
case SIO_F71882_ID:
|
||||
sio->type = f71882fg;
|
||||
break;
|
||||
case SIO_F71889A_ID:
|
||||
sio->type = f71889a;
|
||||
break;
|
||||
case SIO_F71889_ID:
|
||||
sio->type = f71889f;
|
||||
break;
|
||||
|
@ -538,6 +558,6 @@ static void __exit f7188x_gpio_exit(void)
|
|||
}
|
||||
module_exit(f7188x_gpio_exit);
|
||||
|
||||
MODULE_DESCRIPTION("GPIO driver for Super-I/O chips F71869, F71869A, F71882FG, F71889F and F81866");
|
||||
MODULE_DESCRIPTION("GPIO driver for Super-I/O chips F71869, F71869A, F71882FG, F71889A, F71889F and F81866");
|
||||
MODULE_AUTHOR("Simon Guinot <simon.guinot@sequanux.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Gemini gpiochip and interrupt routines
|
||||
* Faraday Technolog FTGPIO010 gpiochip and interrupt routines
|
||||
* Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
|
||||
*
|
||||
* Based on arch/arm/mach-gemini/gpio.c:
|
||||
|
@ -35,28 +35,28 @@
|
|||
#define GPIO_DEBOUNCE_PRESCALE 0x44
|
||||
|
||||
/**
|
||||
* struct gemini_gpio - Gemini GPIO state container
|
||||
* struct ftgpio_gpio - Gemini GPIO state container
|
||||
* @dev: containing device for this instance
|
||||
* @gc: gpiochip for this instance
|
||||
*/
|
||||
struct gemini_gpio {
|
||||
struct ftgpio_gpio {
|
||||
struct device *dev;
|
||||
struct gpio_chip gc;
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
static void gemini_gpio_ack_irq(struct irq_data *d)
|
||||
static void ftgpio_gpio_ack_irq(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct gemini_gpio *g = gpiochip_get_data(gc);
|
||||
struct ftgpio_gpio *g = gpiochip_get_data(gc);
|
||||
|
||||
writel(BIT(irqd_to_hwirq(d)), g->base + GPIO_INT_CLR);
|
||||
}
|
||||
|
||||
static void gemini_gpio_mask_irq(struct irq_data *d)
|
||||
static void ftgpio_gpio_mask_irq(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct gemini_gpio *g = gpiochip_get_data(gc);
|
||||
struct ftgpio_gpio *g = gpiochip_get_data(gc);
|
||||
u32 val;
|
||||
|
||||
val = readl(g->base + GPIO_INT_EN);
|
||||
|
@ -64,10 +64,10 @@ static void gemini_gpio_mask_irq(struct irq_data *d)
|
|||
writel(val, g->base + GPIO_INT_EN);
|
||||
}
|
||||
|
||||
static void gemini_gpio_unmask_irq(struct irq_data *d)
|
||||
static void ftgpio_gpio_unmask_irq(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct gemini_gpio *g = gpiochip_get_data(gc);
|
||||
struct ftgpio_gpio *g = gpiochip_get_data(gc);
|
||||
u32 val;
|
||||
|
||||
val = readl(g->base + GPIO_INT_EN);
|
||||
|
@ -75,10 +75,10 @@ static void gemini_gpio_unmask_irq(struct irq_data *d)
|
|||
writel(val, g->base + GPIO_INT_EN);
|
||||
}
|
||||
|
||||
static int gemini_gpio_set_irq_type(struct irq_data *d, unsigned int type)
|
||||
static int ftgpio_gpio_set_irq_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct gemini_gpio *g = gpiochip_get_data(gc);
|
||||
struct ftgpio_gpio *g = gpiochip_get_data(gc);
|
||||
u32 mask = BIT(irqd_to_hwirq(d));
|
||||
u32 reg_both, reg_level, reg_type;
|
||||
|
||||
|
@ -123,23 +123,23 @@ static int gemini_gpio_set_irq_type(struct irq_data *d, unsigned int type)
|
|||
writel(reg_level, g->base + GPIO_INT_LEVEL);
|
||||
writel(reg_both, g->base + GPIO_INT_BOTH_EDGE);
|
||||
|
||||
gemini_gpio_ack_irq(d);
|
||||
ftgpio_gpio_ack_irq(d);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_chip gemini_gpio_irqchip = {
|
||||
.name = "GPIO",
|
||||
.irq_ack = gemini_gpio_ack_irq,
|
||||
.irq_mask = gemini_gpio_mask_irq,
|
||||
.irq_unmask = gemini_gpio_unmask_irq,
|
||||
.irq_set_type = gemini_gpio_set_irq_type,
|
||||
static struct irq_chip ftgpio_gpio_irqchip = {
|
||||
.name = "FTGPIO010",
|
||||
.irq_ack = ftgpio_gpio_ack_irq,
|
||||
.irq_mask = ftgpio_gpio_mask_irq,
|
||||
.irq_unmask = ftgpio_gpio_unmask_irq,
|
||||
.irq_set_type = ftgpio_gpio_set_irq_type,
|
||||
};
|
||||
|
||||
static void gemini_gpio_irq_handler(struct irq_desc *desc)
|
||||
static void ftgpio_gpio_irq_handler(struct irq_desc *desc)
|
||||
{
|
||||
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
|
||||
struct gemini_gpio *g = gpiochip_get_data(gc);
|
||||
struct ftgpio_gpio *g = gpiochip_get_data(gc);
|
||||
struct irq_chip *irqchip = irq_desc_get_chip(desc);
|
||||
int offset;
|
||||
unsigned long stat;
|
||||
|
@ -155,11 +155,11 @@ static void gemini_gpio_irq_handler(struct irq_desc *desc)
|
|||
chained_irq_exit(irqchip, desc);
|
||||
}
|
||||
|
||||
static int gemini_gpio_probe(struct platform_device *pdev)
|
||||
static int ftgpio_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
struct gemini_gpio *g;
|
||||
struct ftgpio_gpio *g;
|
||||
int irq;
|
||||
int ret;
|
||||
|
||||
|
@ -189,7 +189,7 @@ static int gemini_gpio_probe(struct platform_device *pdev)
|
|||
dev_err(dev, "unable to init generic GPIO\n");
|
||||
return ret;
|
||||
}
|
||||
g->gc.label = "Gemini";
|
||||
g->gc.label = "FTGPIO010";
|
||||
g->gc.base = -1;
|
||||
g->gc.parent = dev;
|
||||
g->gc.owner = THIS_MODULE;
|
||||
|
@ -204,33 +204,39 @@ static int gemini_gpio_probe(struct platform_device *pdev)
|
|||
writel(0x0, g->base + GPIO_INT_MASK);
|
||||
writel(~0x0, g->base + GPIO_INT_CLR);
|
||||
|
||||
ret = gpiochip_irqchip_add(&g->gc, &gemini_gpio_irqchip,
|
||||
ret = gpiochip_irqchip_add(&g->gc, &ftgpio_gpio_irqchip,
|
||||
0, handle_bad_irq,
|
||||
IRQ_TYPE_NONE);
|
||||
if (ret) {
|
||||
dev_info(dev, "could not add irqchip\n");
|
||||
return ret;
|
||||
}
|
||||
gpiochip_set_chained_irqchip(&g->gc, &gemini_gpio_irqchip,
|
||||
irq, gemini_gpio_irq_handler);
|
||||
gpiochip_set_chained_irqchip(&g->gc, &ftgpio_gpio_irqchip,
|
||||
irq, ftgpio_gpio_irq_handler);
|
||||
|
||||
dev_info(dev, "Gemini GPIO @%p registered\n", g->base);
|
||||
dev_info(dev, "FTGPIO010 @%p registered\n", g->base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id gemini_gpio_of_match[] = {
|
||||
static const struct of_device_id ftgpio_gpio_of_match[] = {
|
||||
{
|
||||
.compatible = "cortina,gemini-gpio",
|
||||
},
|
||||
{
|
||||
.compatible = "moxa,moxart-gpio",
|
||||
},
|
||||
{
|
||||
.compatible = "faraday,ftgpio010",
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver gemini_gpio_driver = {
|
||||
static struct platform_driver ftgpio_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "gemini-gpio",
|
||||
.of_match_table = of_match_ptr(gemini_gpio_of_match),
|
||||
.name = "ftgpio010-gpio",
|
||||
.of_match_table = of_match_ptr(ftgpio_gpio_of_match),
|
||||
},
|
||||
.probe = gemini_gpio_probe,
|
||||
.probe = ftgpio_gpio_probe,
|
||||
};
|
||||
builtin_platform_driver(gemini_gpio_driver);
|
||||
builtin_platform_driver(ftgpio_gpio_driver);
|
|
@ -166,7 +166,7 @@ static int mrfld_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
|
|||
{
|
||||
void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
|
||||
|
||||
return (readl(gpdr) & BIT(offset % 32)) ? GPIOF_DIR_OUT : GPIOF_DIR_IN;
|
||||
return !(readl(gpdr) & BIT(offset % 32));
|
||||
}
|
||||
|
||||
static int mrfld_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset,
|
||||
|
|
|
@ -459,41 +459,31 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
|
|||
|
||||
chip = chip_save;
|
||||
for (j = 0; j < 8; j++, chip++) {
|
||||
irq_base = irq_alloc_descs(-1, IOH_IRQ_BASE, num_ports[j],
|
||||
NUMA_NO_NODE);
|
||||
irq_base = devm_irq_alloc_descs(&pdev->dev, -1, IOH_IRQ_BASE,
|
||||
num_ports[j], NUMA_NO_NODE);
|
||||
if (irq_base < 0) {
|
||||
dev_warn(&pdev->dev,
|
||||
"ml_ioh_gpio: Failed to get IRQ base num\n");
|
||||
chip->irq_base = -1;
|
||||
ret = irq_base;
|
||||
goto err_irq_alloc_descs;
|
||||
goto err_gpiochip_add;
|
||||
}
|
||||
chip->irq_base = irq_base;
|
||||
ioh_gpio_alloc_generic_chip(chip, irq_base, num_ports[j]);
|
||||
}
|
||||
|
||||
chip = chip_save;
|
||||
ret = request_irq(pdev->irq, ioh_gpio_handler,
|
||||
IRQF_SHARED, KBUILD_MODNAME, chip);
|
||||
ret = devm_request_irq(&pdev->dev, pdev->irq, ioh_gpio_handler,
|
||||
IRQF_SHARED, KBUILD_MODNAME, chip);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"%s request_irq failed\n", __func__);
|
||||
goto err_request_irq;
|
||||
goto err_gpiochip_add;
|
||||
}
|
||||
|
||||
pci_set_drvdata(pdev, chip);
|
||||
|
||||
return 0;
|
||||
|
||||
err_request_irq:
|
||||
chip = chip_save;
|
||||
err_irq_alloc_descs:
|
||||
while (--j >= 0) {
|
||||
chip--;
|
||||
irq_free_descs(chip->irq_base, num_ports[j]);
|
||||
}
|
||||
|
||||
chip = chip_save;
|
||||
err_gpiochip_add:
|
||||
while (--i >= 0) {
|
||||
chip--;
|
||||
|
@ -524,12 +514,8 @@ static void ioh_gpio_remove(struct pci_dev *pdev)
|
|||
|
||||
chip_save = chip;
|
||||
|
||||
free_irq(pdev->irq, chip);
|
||||
|
||||
for (i = 0; i < 8; i++, chip++) {
|
||||
irq_free_descs(chip->irq_base, num_ports[i]);
|
||||
for (i = 0; i < 8; i++, chip++)
|
||||
gpiochip_remove(&chip->gpio);
|
||||
}
|
||||
|
||||
chip = chip_save;
|
||||
pci_iounmap(pdev, chip->base);
|
||||
|
|
|
@ -575,6 +575,7 @@ static void __iomem *bgpio_map(struct platform_device *pdev,
|
|||
static const struct of_device_id bgpio_of_match[] = {
|
||||
{ .compatible = "brcm,bcm6345-gpio" },
|
||||
{ .compatible = "wd,mbl-gpio" },
|
||||
{ .compatible = "ni,169445-nand-gpio" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bgpio_of_match);
|
||||
|
|
|
@ -169,7 +169,7 @@ static int gpio_mockup_irqchip_setup(struct device *dev,
|
|||
struct gpio_chip *gc = &chip->gc;
|
||||
int irq_base, i;
|
||||
|
||||
irq_base = irq_alloc_descs(-1, 0, gc->ngpio, 0);
|
||||
irq_base = devm_irq_alloc_descs(dev, -1, 0, gc->ngpio, 0);
|
||||
if (irq_base < 0)
|
||||
return irq_base;
|
||||
|
||||
|
@ -372,25 +372,11 @@ static int gpio_mockup_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_mockup_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_mockup_chip *chips;
|
||||
int i;
|
||||
|
||||
chips = platform_get_drvdata(pdev);
|
||||
|
||||
for (i = 0; i < gpio_mockup_params_nr >> 1; i++)
|
||||
irq_free_descs(chips[i].gc.irq_base, chips[i].gc.ngpio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver gpio_mockup_driver = {
|
||||
.driver = {
|
||||
.name = GPIO_MOCKUP_NAME,
|
||||
},
|
||||
.probe = gpio_mockup_probe,
|
||||
.remove = gpio_mockup_remove,
|
||||
};
|
||||
|
||||
static struct platform_device *pdev;
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* MOXA ART SoCs GPIO driver.
|
||||
*
|
||||
* Copyright (C) 2013 Jonas Jensen
|
||||
*
|
||||
* Jonas Jensen <jonas.jensen@gmail.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
|
||||
#define GPIO_DATA_OUT 0x00
|
||||
#define GPIO_DATA_IN 0x04
|
||||
#define GPIO_PIN_DIRECTION 0x08
|
||||
|
||||
static int moxart_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
struct gpio_chip *gc;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
|
||||
gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
|
||||
if (!gc)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
ret = bgpio_init(gc, dev, 4, base + GPIO_DATA_IN,
|
||||
base + GPIO_DATA_OUT, NULL,
|
||||
base + GPIO_PIN_DIRECTION, NULL,
|
||||
BGPIOF_READ_OUTPUT_REG_SET);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "bgpio_init failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
gc->label = "moxart-gpio";
|
||||
gc->request = gpiochip_generic_request;
|
||||
gc->free = gpiochip_generic_free;
|
||||
gc->base = 0;
|
||||
gc->owner = THIS_MODULE;
|
||||
|
||||
ret = devm_gpiochip_add_data(dev, gc, NULL);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: gpiochip_add failed\n",
|
||||
dev->of_node->full_name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id moxart_gpio_match[] = {
|
||||
{ .compatible = "moxa,moxart-gpio" },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct platform_driver moxart_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "moxart-gpio",
|
||||
.of_match_table = moxart_gpio_match,
|
||||
},
|
||||
.probe = moxart_gpio_probe,
|
||||
};
|
||||
builtin_platform_driver(moxart_gpio_driver);
|
|
@ -42,29 +42,44 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include "gpiolib.h"
|
||||
|
||||
/*
|
||||
* GPIO unit register offsets.
|
||||
*/
|
||||
#define GPIO_OUT_OFF 0x0000
|
||||
#define GPIO_IO_CONF_OFF 0x0004
|
||||
#define GPIO_BLINK_EN_OFF 0x0008
|
||||
#define GPIO_IN_POL_OFF 0x000c
|
||||
#define GPIO_DATA_IN_OFF 0x0010
|
||||
#define GPIO_EDGE_CAUSE_OFF 0x0014
|
||||
#define GPIO_EDGE_MASK_OFF 0x0018
|
||||
#define GPIO_LEVEL_MASK_OFF 0x001c
|
||||
#define GPIO_OUT_OFF 0x0000
|
||||
#define GPIO_IO_CONF_OFF 0x0004
|
||||
#define GPIO_BLINK_EN_OFF 0x0008
|
||||
#define GPIO_IN_POL_OFF 0x000c
|
||||
#define GPIO_DATA_IN_OFF 0x0010
|
||||
#define GPIO_EDGE_CAUSE_OFF 0x0014
|
||||
#define GPIO_EDGE_MASK_OFF 0x0018
|
||||
#define GPIO_LEVEL_MASK_OFF 0x001c
|
||||
#define GPIO_BLINK_CNT_SELECT_OFF 0x0020
|
||||
|
||||
/*
|
||||
* PWM register offsets.
|
||||
*/
|
||||
#define PWM_BLINK_ON_DURATION_OFF 0x0
|
||||
#define PWM_BLINK_OFF_DURATION_OFF 0x4
|
||||
|
||||
|
||||
/* The MV78200 has per-CPU registers for edge mask and level mask */
|
||||
#define GPIO_EDGE_MASK_MV78200_OFF(cpu) ((cpu) ? 0x30 : 0x18)
|
||||
#define GPIO_LEVEL_MASK_MV78200_OFF(cpu) ((cpu) ? 0x34 : 0x1C)
|
||||
|
||||
/* The Armada XP has per-CPU registers for interrupt cause, interrupt
|
||||
/*
|
||||
* The Armada XP has per-CPU registers for interrupt cause, interrupt
|
||||
* mask and interrupt level mask. Those are relative to the
|
||||
* percpu_membase. */
|
||||
* percpu_membase.
|
||||
*/
|
||||
#define GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu) ((cpu) * 0x4)
|
||||
#define GPIO_EDGE_MASK_ARMADAXP_OFF(cpu) (0x10 + (cpu) * 0x4)
|
||||
#define GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu) (0x20 + (cpu) * 0x4)
|
||||
|
@ -75,6 +90,20 @@
|
|||
|
||||
#define MVEBU_MAX_GPIO_PER_BANK 32
|
||||
|
||||
struct mvebu_pwm {
|
||||
void __iomem *membase;
|
||||
unsigned long clk_rate;
|
||||
struct gpio_desc *gpiod;
|
||||
struct pwm_chip chip;
|
||||
spinlock_t lock;
|
||||
struct mvebu_gpio_chip *mvchip;
|
||||
|
||||
/* Used to preserve GPIO/PWM registers across suspend/resume */
|
||||
u32 blink_select;
|
||||
u32 blink_on_duration;
|
||||
u32 blink_off_duration;
|
||||
};
|
||||
|
||||
struct mvebu_gpio_chip {
|
||||
struct gpio_chip chip;
|
||||
spinlock_t lock;
|
||||
|
@ -84,48 +113,55 @@ struct mvebu_gpio_chip {
|
|||
struct irq_domain *domain;
|
||||
int soc_variant;
|
||||
|
||||
/* Used for PWM support */
|
||||
struct clk *clk;
|
||||
struct mvebu_pwm *mvpwm;
|
||||
|
||||
/* Used to preserve GPIO registers across suspend/resume */
|
||||
u32 out_reg;
|
||||
u32 io_conf_reg;
|
||||
u32 blink_en_reg;
|
||||
u32 in_pol_reg;
|
||||
u32 edge_mask_regs[4];
|
||||
u32 level_mask_regs[4];
|
||||
u32 out_reg;
|
||||
u32 io_conf_reg;
|
||||
u32 blink_en_reg;
|
||||
u32 in_pol_reg;
|
||||
u32 edge_mask_regs[4];
|
||||
u32 level_mask_regs[4];
|
||||
};
|
||||
|
||||
/*
|
||||
* Functions returning addresses of individual registers for a given
|
||||
* GPIO controller.
|
||||
*/
|
||||
static inline void __iomem *mvebu_gpioreg_out(struct mvebu_gpio_chip *mvchip)
|
||||
static void __iomem *mvebu_gpioreg_out(struct mvebu_gpio_chip *mvchip)
|
||||
{
|
||||
return mvchip->membase + GPIO_OUT_OFF;
|
||||
}
|
||||
|
||||
static inline void __iomem *mvebu_gpioreg_blink(struct mvebu_gpio_chip *mvchip)
|
||||
static void __iomem *mvebu_gpioreg_blink(struct mvebu_gpio_chip *mvchip)
|
||||
{
|
||||
return mvchip->membase + GPIO_BLINK_EN_OFF;
|
||||
}
|
||||
|
||||
static inline void __iomem *
|
||||
mvebu_gpioreg_io_conf(struct mvebu_gpio_chip *mvchip)
|
||||
static void __iomem *mvebu_gpioreg_blink_counter_select(struct mvebu_gpio_chip
|
||||
*mvchip)
|
||||
{
|
||||
return mvchip->membase + GPIO_BLINK_CNT_SELECT_OFF;
|
||||
}
|
||||
|
||||
static void __iomem *mvebu_gpioreg_io_conf(struct mvebu_gpio_chip *mvchip)
|
||||
{
|
||||
return mvchip->membase + GPIO_IO_CONF_OFF;
|
||||
}
|
||||
|
||||
static inline void __iomem *mvebu_gpioreg_in_pol(struct mvebu_gpio_chip *mvchip)
|
||||
static void __iomem *mvebu_gpioreg_in_pol(struct mvebu_gpio_chip *mvchip)
|
||||
{
|
||||
return mvchip->membase + GPIO_IN_POL_OFF;
|
||||
}
|
||||
|
||||
static inline void __iomem *
|
||||
mvebu_gpioreg_data_in(struct mvebu_gpio_chip *mvchip)
|
||||
static void __iomem *mvebu_gpioreg_data_in(struct mvebu_gpio_chip *mvchip)
|
||||
{
|
||||
return mvchip->membase + GPIO_DATA_IN_OFF;
|
||||
}
|
||||
|
||||
static inline void __iomem *
|
||||
mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvchip)
|
||||
static void __iomem *mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvchip)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
|
@ -142,8 +178,7 @@ mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvchip)
|
|||
}
|
||||
}
|
||||
|
||||
static inline void __iomem *
|
||||
mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvchip)
|
||||
static void __iomem *mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvchip)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
|
@ -181,11 +216,24 @@ static void __iomem *mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Functions returning addresses of individual registers for a given
|
||||
* PWM controller.
|
||||
*/
|
||||
static void __iomem *mvebu_pwmreg_blink_on_duration(struct mvebu_pwm *mvpwm)
|
||||
{
|
||||
return mvpwm->membase + PWM_BLINK_ON_DURATION_OFF;
|
||||
}
|
||||
|
||||
static void __iomem *mvebu_pwmreg_blink_off_duration(struct mvebu_pwm *mvpwm)
|
||||
{
|
||||
return mvpwm->membase + PWM_BLINK_OFF_DURATION_OFF;
|
||||
}
|
||||
|
||||
/*
|
||||
* Functions implementing the gpio_chip methods
|
||||
*/
|
||||
|
||||
static void mvebu_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
|
||||
static void mvebu_gpio_set(struct gpio_chip *chip, unsigned int pin, int value)
|
||||
{
|
||||
struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
|
||||
unsigned long flags;
|
||||
|
@ -194,19 +242,19 @@ static void mvebu_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
|
|||
spin_lock_irqsave(&mvchip->lock, flags);
|
||||
u = readl_relaxed(mvebu_gpioreg_out(mvchip));
|
||||
if (value)
|
||||
u |= 1 << pin;
|
||||
u |= BIT(pin);
|
||||
else
|
||||
u &= ~(1 << pin);
|
||||
u &= ~BIT(pin);
|
||||
writel_relaxed(u, mvebu_gpioreg_out(mvchip));
|
||||
spin_unlock_irqrestore(&mvchip->lock, flags);
|
||||
}
|
||||
|
||||
static int mvebu_gpio_get(struct gpio_chip *chip, unsigned pin)
|
||||
static int mvebu_gpio_get(struct gpio_chip *chip, unsigned int pin)
|
||||
{
|
||||
struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
|
||||
u32 u;
|
||||
|
||||
if (readl_relaxed(mvebu_gpioreg_io_conf(mvchip)) & (1 << pin)) {
|
||||
if (readl_relaxed(mvebu_gpioreg_io_conf(mvchip)) & BIT(pin)) {
|
||||
u = readl_relaxed(mvebu_gpioreg_data_in(mvchip)) ^
|
||||
readl_relaxed(mvebu_gpioreg_in_pol(mvchip));
|
||||
} else {
|
||||
|
@ -216,7 +264,8 @@ static int mvebu_gpio_get(struct gpio_chip *chip, unsigned pin)
|
|||
return (u >> pin) & 1;
|
||||
}
|
||||
|
||||
static void mvebu_gpio_blink(struct gpio_chip *chip, unsigned pin, int value)
|
||||
static void mvebu_gpio_blink(struct gpio_chip *chip, unsigned int pin,
|
||||
int value)
|
||||
{
|
||||
struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
|
||||
unsigned long flags;
|
||||
|
@ -225,36 +274,38 @@ static void mvebu_gpio_blink(struct gpio_chip *chip, unsigned pin, int value)
|
|||
spin_lock_irqsave(&mvchip->lock, flags);
|
||||
u = readl_relaxed(mvebu_gpioreg_blink(mvchip));
|
||||
if (value)
|
||||
u |= 1 << pin;
|
||||
u |= BIT(pin);
|
||||
else
|
||||
u &= ~(1 << pin);
|
||||
u &= ~BIT(pin);
|
||||
writel_relaxed(u, mvebu_gpioreg_blink(mvchip));
|
||||
spin_unlock_irqrestore(&mvchip->lock, flags);
|
||||
}
|
||||
|
||||
static int mvebu_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
|
||||
static int mvebu_gpio_direction_input(struct gpio_chip *chip, unsigned int pin)
|
||||
{
|
||||
struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
u32 u;
|
||||
|
||||
/* Check with the pinctrl driver whether this pin is usable as
|
||||
* an input GPIO */
|
||||
/*
|
||||
* Check with the pinctrl driver whether this pin is usable as
|
||||
* an input GPIO
|
||||
*/
|
||||
ret = pinctrl_gpio_direction_input(chip->base + pin);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spin_lock_irqsave(&mvchip->lock, flags);
|
||||
u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip));
|
||||
u |= 1 << pin;
|
||||
u |= BIT(pin);
|
||||
writel_relaxed(u, mvebu_gpioreg_io_conf(mvchip));
|
||||
spin_unlock_irqrestore(&mvchip->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned pin,
|
||||
static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned int pin,
|
||||
int value)
|
||||
{
|
||||
struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
|
||||
|
@ -262,8 +313,10 @@ static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned pin,
|
|||
int ret;
|
||||
u32 u;
|
||||
|
||||
/* Check with the pinctrl driver whether this pin is usable as
|
||||
* an output GPIO */
|
||||
/*
|
||||
* Check with the pinctrl driver whether this pin is usable as
|
||||
* an output GPIO
|
||||
*/
|
||||
ret = pinctrl_gpio_direction_output(chip->base + pin);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -273,16 +326,17 @@ static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned pin,
|
|||
|
||||
spin_lock_irqsave(&mvchip->lock, flags);
|
||||
u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip));
|
||||
u &= ~(1 << pin);
|
||||
u &= ~BIT(pin);
|
||||
writel_relaxed(u, mvebu_gpioreg_io_conf(mvchip));
|
||||
spin_unlock_irqrestore(&mvchip->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mvebu_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
|
||||
static int mvebu_gpio_to_irq(struct gpio_chip *chip, unsigned int pin)
|
||||
{
|
||||
struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
|
||||
|
||||
return irq_create_mapping(mvchip->domain, pin);
|
||||
}
|
||||
|
||||
|
@ -389,7 +443,7 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
|||
|
||||
pin = d->hwirq;
|
||||
|
||||
u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip)) & (1 << pin);
|
||||
u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip)) & BIT(pin);
|
||||
if (!u)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -409,13 +463,13 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
|||
case IRQ_TYPE_EDGE_RISING:
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
u = readl_relaxed(mvebu_gpioreg_in_pol(mvchip));
|
||||
u &= ~(1 << pin);
|
||||
u &= ~BIT(pin);
|
||||
writel_relaxed(u, mvebu_gpioreg_in_pol(mvchip));
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
u = readl_relaxed(mvebu_gpioreg_in_pol(mvchip));
|
||||
u |= 1 << pin;
|
||||
u |= BIT(pin);
|
||||
writel_relaxed(u, mvebu_gpioreg_in_pol(mvchip));
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_BOTH: {
|
||||
|
@ -428,10 +482,10 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
|||
* set initial polarity based on current input level
|
||||
*/
|
||||
u = readl_relaxed(mvebu_gpioreg_in_pol(mvchip));
|
||||
if (v & (1 << pin))
|
||||
u |= 1 << pin; /* falling */
|
||||
if (v & BIT(pin))
|
||||
u |= BIT(pin); /* falling */
|
||||
else
|
||||
u &= ~(1 << pin); /* rising */
|
||||
u &= ~BIT(pin); /* rising */
|
||||
writel_relaxed(u, mvebu_gpioreg_in_pol(mvchip));
|
||||
break;
|
||||
}
|
||||
|
@ -461,7 +515,7 @@ static void mvebu_gpio_irq_handler(struct irq_desc *desc)
|
|||
|
||||
irq = irq_find_mapping(mvchip->domain, i);
|
||||
|
||||
if (!(cause & (1 << i)))
|
||||
if (!(cause & BIT(i)))
|
||||
continue;
|
||||
|
||||
type = irq_get_trigger_type(irq);
|
||||
|
@ -470,7 +524,7 @@ static void mvebu_gpio_irq_handler(struct irq_desc *desc)
|
|||
u32 polarity;
|
||||
|
||||
polarity = readl_relaxed(mvebu_gpioreg_in_pol(mvchip));
|
||||
polarity ^= 1 << i;
|
||||
polarity ^= BIT(i);
|
||||
writel_relaxed(polarity, mvebu_gpioreg_in_pol(mvchip));
|
||||
}
|
||||
|
||||
|
@ -480,6 +534,246 @@ static void mvebu_gpio_irq_handler(struct irq_desc *desc)
|
|||
chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Functions implementing the pwm_chip methods
|
||||
*/
|
||||
static struct mvebu_pwm *to_mvebu_pwm(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct mvebu_pwm, chip);
|
||||
}
|
||||
|
||||
static int mvebu_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip);
|
||||
struct mvebu_gpio_chip *mvchip = mvpwm->mvchip;
|
||||
struct gpio_desc *desc;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_irqsave(&mvpwm->lock, flags);
|
||||
|
||||
if (mvpwm->gpiod) {
|
||||
ret = -EBUSY;
|
||||
} else {
|
||||
desc = gpio_to_desc(mvchip->chip.base + pwm->hwpwm);
|
||||
if (!desc) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = gpiod_request(desc, "mvebu-pwm");
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = gpiod_direction_output(desc, 0);
|
||||
if (ret) {
|
||||
gpiod_free(desc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
mvpwm->gpiod = desc;
|
||||
}
|
||||
out:
|
||||
spin_unlock_irqrestore(&mvpwm->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mvebu_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&mvpwm->lock, flags);
|
||||
gpiod_free(mvpwm->gpiod);
|
||||
mvpwm->gpiod = NULL;
|
||||
spin_unlock_irqrestore(&mvpwm->lock, flags);
|
||||
}
|
||||
|
||||
static void mvebu_pwm_get_state(struct pwm_chip *chip,
|
||||
struct pwm_device *pwm,
|
||||
struct pwm_state *state) {
|
||||
|
||||
struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip);
|
||||
struct mvebu_gpio_chip *mvchip = mvpwm->mvchip;
|
||||
unsigned long long val;
|
||||
unsigned long flags;
|
||||
u32 u;
|
||||
|
||||
spin_lock_irqsave(&mvpwm->lock, flags);
|
||||
|
||||
val = (unsigned long long)
|
||||
readl_relaxed(mvebu_pwmreg_blink_on_duration(mvpwm));
|
||||
val *= NSEC_PER_SEC;
|
||||
do_div(val, mvpwm->clk_rate);
|
||||
if (val > UINT_MAX)
|
||||
state->duty_cycle = UINT_MAX;
|
||||
else if (val)
|
||||
state->duty_cycle = val;
|
||||
else
|
||||
state->duty_cycle = 1;
|
||||
|
||||
val = (unsigned long long)
|
||||
readl_relaxed(mvebu_pwmreg_blink_off_duration(mvpwm));
|
||||
val *= NSEC_PER_SEC;
|
||||
do_div(val, mvpwm->clk_rate);
|
||||
if (val < state->duty_cycle) {
|
||||
state->period = 1;
|
||||
} else {
|
||||
val -= state->duty_cycle;
|
||||
if (val > UINT_MAX)
|
||||
state->period = UINT_MAX;
|
||||
else if (val)
|
||||
state->period = val;
|
||||
else
|
||||
state->period = 1;
|
||||
}
|
||||
|
||||
u = readl_relaxed(mvebu_gpioreg_blink(mvchip));
|
||||
if (u)
|
||||
state->enabled = true;
|
||||
else
|
||||
state->enabled = false;
|
||||
|
||||
spin_unlock_irqrestore(&mvpwm->lock, flags);
|
||||
}
|
||||
|
||||
static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
struct pwm_state *state)
|
||||
{
|
||||
struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip);
|
||||
struct mvebu_gpio_chip *mvchip = mvpwm->mvchip;
|
||||
unsigned long long val;
|
||||
unsigned long flags;
|
||||
unsigned int on, off;
|
||||
|
||||
val = (unsigned long long) mvpwm->clk_rate * state->duty_cycle;
|
||||
do_div(val, NSEC_PER_SEC);
|
||||
if (val > UINT_MAX)
|
||||
return -EINVAL;
|
||||
if (val)
|
||||
on = val;
|
||||
else
|
||||
on = 1;
|
||||
|
||||
val = (unsigned long long) mvpwm->clk_rate *
|
||||
(state->period - state->duty_cycle);
|
||||
do_div(val, NSEC_PER_SEC);
|
||||
if (val > UINT_MAX)
|
||||
return -EINVAL;
|
||||
if (val)
|
||||
off = val;
|
||||
else
|
||||
off = 1;
|
||||
|
||||
spin_lock_irqsave(&mvpwm->lock, flags);
|
||||
|
||||
writel_relaxed(on, mvebu_pwmreg_blink_on_duration(mvpwm));
|
||||
writel_relaxed(off, mvebu_pwmreg_blink_off_duration(mvpwm));
|
||||
if (state->enabled)
|
||||
mvebu_gpio_blink(&mvchip->chip, pwm->hwpwm, 1);
|
||||
else
|
||||
mvebu_gpio_blink(&mvchip->chip, pwm->hwpwm, 0);
|
||||
|
||||
spin_unlock_irqrestore(&mvpwm->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pwm_ops mvebu_pwm_ops = {
|
||||
.request = mvebu_pwm_request,
|
||||
.free = mvebu_pwm_free,
|
||||
.get_state = mvebu_pwm_get_state,
|
||||
.apply = mvebu_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static void __maybe_unused mvebu_pwm_suspend(struct mvebu_gpio_chip *mvchip)
|
||||
{
|
||||
struct mvebu_pwm *mvpwm = mvchip->mvpwm;
|
||||
|
||||
mvpwm->blink_select =
|
||||
readl_relaxed(mvebu_gpioreg_blink_counter_select(mvchip));
|
||||
mvpwm->blink_on_duration =
|
||||
readl_relaxed(mvebu_pwmreg_blink_on_duration(mvpwm));
|
||||
mvpwm->blink_off_duration =
|
||||
readl_relaxed(mvebu_pwmreg_blink_off_duration(mvpwm));
|
||||
}
|
||||
|
||||
static void __maybe_unused mvebu_pwm_resume(struct mvebu_gpio_chip *mvchip)
|
||||
{
|
||||
struct mvebu_pwm *mvpwm = mvchip->mvpwm;
|
||||
|
||||
writel_relaxed(mvpwm->blink_select,
|
||||
mvebu_gpioreg_blink_counter_select(mvchip));
|
||||
writel_relaxed(mvpwm->blink_on_duration,
|
||||
mvebu_pwmreg_blink_on_duration(mvpwm));
|
||||
writel_relaxed(mvpwm->blink_off_duration,
|
||||
mvebu_pwmreg_blink_off_duration(mvpwm));
|
||||
}
|
||||
|
||||
static int mvebu_pwm_probe(struct platform_device *pdev,
|
||||
struct mvebu_gpio_chip *mvchip,
|
||||
int id)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct mvebu_pwm *mvpwm;
|
||||
struct resource *res;
|
||||
u32 set;
|
||||
|
||||
if (!of_device_is_compatible(mvchip->chip.of_node,
|
||||
"marvell,armada-370-xp-gpio"))
|
||||
return 0;
|
||||
|
||||
if (IS_ERR(mvchip->clk))
|
||||
return PTR_ERR(mvchip->clk);
|
||||
|
||||
/*
|
||||
* There are only two sets of PWM configuration registers for
|
||||
* all the GPIO lines on those SoCs which this driver reserves
|
||||
* for the first two GPIO chips. So if the resource is missing
|
||||
* we can't treat it as an error.
|
||||
*/
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwm");
|
||||
if (!res)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Use set A for lines of GPIO chip with id 0, B for GPIO chip
|
||||
* with id 1. Don't allow further GPIO chips to be used for PWM.
|
||||
*/
|
||||
if (id == 0)
|
||||
set = 0;
|
||||
else if (id == 1)
|
||||
set = U32_MAX;
|
||||
else
|
||||
return -EINVAL;
|
||||
writel_relaxed(0, mvebu_gpioreg_blink_counter_select(mvchip));
|
||||
|
||||
mvpwm = devm_kzalloc(dev, sizeof(struct mvebu_pwm), GFP_KERNEL);
|
||||
if (!mvpwm)
|
||||
return -ENOMEM;
|
||||
mvchip->mvpwm = mvpwm;
|
||||
mvpwm->mvchip = mvchip;
|
||||
|
||||
mvpwm->membase = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(mvpwm->membase))
|
||||
return PTR_ERR(mvpwm->membase);
|
||||
|
||||
mvpwm->clk_rate = clk_get_rate(mvchip->clk);
|
||||
if (!mvpwm->clk_rate) {
|
||||
dev_err(dev, "failed to get clock rate\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mvpwm->chip.dev = dev;
|
||||
mvpwm->chip.ops = &mvebu_pwm_ops;
|
||||
mvpwm->chip.npwm = mvchip->chip.ngpio;
|
||||
|
||||
spin_lock_init(&mvpwm->lock);
|
||||
|
||||
return pwmchip_add(&mvpwm->chip);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
|
@ -507,7 +801,7 @@ static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
|||
if (!label)
|
||||
continue;
|
||||
|
||||
msk = 1 << i;
|
||||
msk = BIT(i);
|
||||
is_out = !(io_conf & msk);
|
||||
|
||||
seq_printf(s, " gpio-%-3d (%-20.20s)", chip->base + i, label);
|
||||
|
@ -550,6 +844,10 @@ static const struct of_device_id mvebu_gpio_of_match[] = {
|
|||
.compatible = "marvell,armadaxp-gpio",
|
||||
.data = (void *) MVEBU_GPIO_SOC_VARIANT_ARMADAXP,
|
||||
},
|
||||
{
|
||||
.compatible = "marvell,armada-370-xp-gpio",
|
||||
.data = (void *) MVEBU_GPIO_SOC_VARIANT_ORION,
|
||||
},
|
||||
{
|
||||
/* sentinel */
|
||||
},
|
||||
|
@ -596,6 +894,9 @@ static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state)
|
|||
BUG();
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_PWM))
|
||||
mvebu_pwm_suspend(mvchip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -639,6 +940,9 @@ static int mvebu_gpio_resume(struct platform_device *pdev)
|
|||
BUG();
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_PWM))
|
||||
mvebu_pwm_resume(mvchip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -650,7 +954,6 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
|
|||
struct resource *res;
|
||||
struct irq_chip_generic *gc;
|
||||
struct irq_chip_type *ct;
|
||||
struct clk *clk;
|
||||
unsigned int ngpios;
|
||||
bool have_irqs;
|
||||
int soc_variant;
|
||||
|
@ -684,10 +987,10 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
|
|||
return id;
|
||||
}
|
||||
|
||||
clk = devm_clk_get(&pdev->dev, NULL);
|
||||
mvchip->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
/* Not all SoCs require a clock.*/
|
||||
if (!IS_ERR(clk))
|
||||
clk_prepare_enable(clk);
|
||||
if (!IS_ERR(mvchip->clk))
|
||||
clk_prepare_enable(mvchip->clk);
|
||||
|
||||
mvchip->soc_variant = soc_variant;
|
||||
mvchip->chip.label = dev_name(&pdev->dev);
|
||||
|
@ -712,8 +1015,10 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(mvchip->membase))
|
||||
return PTR_ERR(mvchip->membase);
|
||||
|
||||
/* The Armada XP has a second range of registers for the
|
||||
* per-CPU registers */
|
||||
/*
|
||||
* The Armada XP has a second range of registers for the
|
||||
* per-CPU registers
|
||||
*/
|
||||
if (soc_variant == MVEBU_GPIO_SOC_VARIANT_ARMADAXP) {
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
mvchip->percpu_membase = devm_ioremap_resource(&pdev->dev,
|
||||
|
@ -780,7 +1085,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
|
|||
goto err_domain;
|
||||
}
|
||||
|
||||
/* NOTE: The common accessors cannot be used because of the percpu
|
||||
/*
|
||||
* NOTE: The common accessors cannot be used because of the percpu
|
||||
* access to the mask registers
|
||||
*/
|
||||
gc = irq_get_domain_generic_chip(mvchip->domain, 0);
|
||||
|
@ -801,7 +1107,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
|
|||
ct->handler = handle_edge_irq;
|
||||
ct->chip.name = mvchip->chip.label;
|
||||
|
||||
/* Setup the interrupt handlers. Each chip can have up to 4
|
||||
/*
|
||||
* Setup the interrupt handlers. Each chip can have up to 4
|
||||
* interrupt handlers, with each handler dealing with 8 GPIO
|
||||
* pins.
|
||||
*/
|
||||
|
@ -814,6 +1121,10 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
|
|||
mvchip);
|
||||
}
|
||||
|
||||
/* Armada 370/XP has simple PWM support for GPIO lines */
|
||||
if (IS_ENABLED(CONFIG_PWM))
|
||||
return mvebu_pwm_probe(pdev, mvchip, id);
|
||||
|
||||
return 0;
|
||||
|
||||
err_domain:
|
||||
|
|
|
@ -471,7 +471,7 @@ static int mxc_gpio_probe(struct platform_device *pdev)
|
|||
if (err)
|
||||
goto out_bgio;
|
||||
|
||||
irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id());
|
||||
irq_base = devm_irq_alloc_descs(&pdev->dev, -1, 0, 32, numa_node_id());
|
||||
if (irq_base < 0) {
|
||||
err = irq_base;
|
||||
goto out_bgio;
|
||||
|
@ -481,7 +481,7 @@ static int mxc_gpio_probe(struct platform_device *pdev)
|
|||
&irq_domain_simple_ops, NULL);
|
||||
if (!port->domain) {
|
||||
err = -ENODEV;
|
||||
goto out_irqdesc_free;
|
||||
goto out_bgio;
|
||||
}
|
||||
|
||||
/* gpio-mxc can be a generic irq chip */
|
||||
|
@ -495,8 +495,6 @@ static int mxc_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
out_irqdomain_remove:
|
||||
irq_domain_remove(port->domain);
|
||||
out_irqdesc_free:
|
||||
irq_free_descs(irq_base, 32);
|
||||
out_bgio:
|
||||
dev_info(&pdev->dev, "%s failed with errno %d\n", __func__, err);
|
||||
return err;
|
||||
|
|
|
@ -328,7 +328,7 @@ static int mxs_gpio_probe(struct platform_device *pdev)
|
|||
/* clear address has to be used to clear IRQSTAT bits */
|
||||
writel(~0U, port->base + PINCTRL_IRQSTAT(port) + MXS_CLR);
|
||||
|
||||
irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id());
|
||||
irq_base = devm_irq_alloc_descs(&pdev->dev, -1, 0, 32, numa_node_id());
|
||||
if (irq_base < 0) {
|
||||
err = irq_base;
|
||||
goto out_iounmap;
|
||||
|
@ -338,7 +338,7 @@ static int mxs_gpio_probe(struct platform_device *pdev)
|
|||
&irq_domain_simple_ops, NULL);
|
||||
if (!port->domain) {
|
||||
err = -ENODEV;
|
||||
goto out_irqdesc_free;
|
||||
goto out_iounmap;
|
||||
}
|
||||
|
||||
/* gpio-mxs can be a generic irq chip */
|
||||
|
@ -370,8 +370,6 @@ static int mxs_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
out_irqdomain_remove:
|
||||
irq_domain_remove(port->domain);
|
||||
out_irqdesc_free:
|
||||
irq_free_descs(irq_base, 32);
|
||||
out_iounmap:
|
||||
iounmap(port->base);
|
||||
return err;
|
||||
|
|
|
@ -208,9 +208,11 @@ static inline void omap_gpio_dbck_disable(struct gpio_bank *bank)
|
|||
* OMAP's debounce time is in 31us steps
|
||||
* <debounce time> = (GPIO_DEBOUNCINGTIME[7:0].DEBOUNCETIME + 1) x 31
|
||||
* so we need to convert and round up to the closest unit.
|
||||
*
|
||||
* Return: 0 on success, negative error otherwise.
|
||||
*/
|
||||
static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset,
|
||||
unsigned debounce)
|
||||
static int omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset,
|
||||
unsigned debounce)
|
||||
{
|
||||
void __iomem *reg;
|
||||
u32 val;
|
||||
|
@ -218,11 +220,12 @@ static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset,
|
|||
bool enable = !!debounce;
|
||||
|
||||
if (!bank->dbck_flag)
|
||||
return;
|
||||
return -ENOTSUPP;
|
||||
|
||||
if (enable) {
|
||||
debounce = DIV_ROUND_UP(debounce, 31) - 1;
|
||||
debounce &= OMAP4_GPIO_DEBOUNCINGTIME_MASK;
|
||||
if ((debounce & OMAP4_GPIO_DEBOUNCINGTIME_MASK) != debounce)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
l = BIT(offset);
|
||||
|
@ -255,6 +258,8 @@ static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset,
|
|||
bank->context.debounce = debounce;
|
||||
bank->context.debounce_en = val;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -964,14 +969,20 @@ static int omap_gpio_debounce(struct gpio_chip *chip, unsigned offset,
|
|||
{
|
||||
struct gpio_bank *bank;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
bank = gpiochip_get_data(chip);
|
||||
|
||||
raw_spin_lock_irqsave(&bank->lock, flags);
|
||||
omap2_set_gpio_debounce(bank, offset, debounce);
|
||||
ret = omap2_set_gpio_debounce(bank, offset, debounce);
|
||||
raw_spin_unlock_irqrestore(&bank->lock, flags);
|
||||
|
||||
return 0;
|
||||
if (ret)
|
||||
dev_info(chip->parent,
|
||||
"Could not set line %u debounce to %u microseconds (%d)",
|
||||
offset, debounce, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int omap_gpio_set_config(struct gpio_chip *chip, unsigned offset,
|
||||
|
@ -1085,7 +1096,8 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
|
|||
* REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop
|
||||
* irq_alloc_descs() since a base IRQ offset will no longer be needed.
|
||||
*/
|
||||
irq_base = irq_alloc_descs(-1, 0, bank->width, 0);
|
||||
irq_base = devm_irq_alloc_descs(bank->chip.parent,
|
||||
-1, 0, bank->width, 0);
|
||||
if (irq_base < 0) {
|
||||
dev_err(bank->chip.parent, "Couldn't allocate IRQ numbers\n");
|
||||
return -ENODEV;
|
||||
|
|
|
@ -11,18 +11,19 @@
|
|||
* the Free Software Foundation; version 2 of the License.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_data/pca953x.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/platform_data/pca953x.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#define PCA953X_INPUT 0
|
||||
#define PCA953X_OUTPUT 1
|
||||
|
@ -81,6 +82,7 @@ static const struct i2c_device_id pca953x_id[] = {
|
|||
{ "tca6416", 16 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "tca6424", 24 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "tca9539", 16 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "tca9554", 8 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "xra1202", 8 | PCA953X_TYPE },
|
||||
{ }
|
||||
};
|
||||
|
@ -363,6 +365,21 @@ exit:
|
|||
mutex_unlock(&chip->i2c_lock);
|
||||
}
|
||||
|
||||
static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off)
|
||||
{
|
||||
struct pca953x_chip *chip = gpiochip_get_data(gc);
|
||||
u32 reg_val;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&chip->i2c_lock);
|
||||
ret = pca953x_read_single(chip, chip->regs->direction, ®_val, off);
|
||||
mutex_unlock(&chip->i2c_lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return !!(reg_val & (1u << (off % BANK_SZ)));
|
||||
}
|
||||
|
||||
static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
|
||||
unsigned long *mask, unsigned long *bits)
|
||||
{
|
||||
|
@ -408,6 +425,7 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
|
|||
gc->direction_output = pca953x_gpio_direction_output;
|
||||
gc->get = pca953x_gpio_get_value;
|
||||
gc->set = pca953x_gpio_set_value;
|
||||
gc->get_direction = pca953x_gpio_get_direction;
|
||||
gc->set_multiple = pca953x_gpio_set_multiple;
|
||||
gc->can_sleep = true;
|
||||
|
||||
|
@ -760,7 +778,13 @@ static int pca953x_probe(struct i2c_client *client,
|
|||
chip->gpio_start = -1;
|
||||
irq_base = 0;
|
||||
|
||||
/* See if we need to de-assert a reset pin */
|
||||
/*
|
||||
* See if we need to de-assert a reset pin.
|
||||
*
|
||||
* There is no known ACPI-enabled platforms that are
|
||||
* using "reset" GPIO. Otherwise any of those platform
|
||||
* must use _DSD method with corresponding property.
|
||||
*/
|
||||
reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(reset_gpio))
|
||||
|
|
|
@ -46,7 +46,6 @@ static const struct i2c_device_id pcf857x_id[] = {
|
|||
{ "pca9675", 16 },
|
||||
{ "max7328", 8 },
|
||||
{ "max7329", 8 },
|
||||
{ "tca9554", 8 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pcf857x_id);
|
||||
|
@ -66,7 +65,6 @@ static const struct of_device_id pcf857x_of_table[] = {
|
|||
{ .compatible = "nxp,pca9675" },
|
||||
{ .compatible = "maxim,max7328" },
|
||||
{ .compatible = "maxim,max7329" },
|
||||
{ .compatible = "ti,tca9554" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pcf857x_of_table);
|
||||
|
|
|
@ -403,7 +403,8 @@ static int pch_gpio_probe(struct pci_dev *pdev,
|
|||
goto err_gpiochip_add;
|
||||
}
|
||||
|
||||
irq_base = irq_alloc_descs(-1, 0, gpio_pins[chip->ioh], NUMA_NO_NODE);
|
||||
irq_base = devm_irq_alloc_descs(&pdev->dev, -1, 0,
|
||||
gpio_pins[chip->ioh], NUMA_NO_NODE);
|
||||
if (irq_base < 0) {
|
||||
dev_warn(&pdev->dev, "PCH gpio: Failed to get IRQ base num\n");
|
||||
chip->irq_base = -1;
|
||||
|
@ -416,8 +417,8 @@ static int pch_gpio_probe(struct pci_dev *pdev,
|
|||
iowrite32(msk, &chip->reg->imask);
|
||||
iowrite32(msk, &chip->reg->ien);
|
||||
|
||||
ret = request_irq(pdev->irq, pch_gpio_handler,
|
||||
IRQF_SHARED, KBUILD_MODNAME, chip);
|
||||
ret = devm_request_irq(&pdev->dev, pdev->irq, pch_gpio_handler,
|
||||
IRQF_SHARED, KBUILD_MODNAME, chip);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"%s request_irq failed\n", __func__);
|
||||
|
@ -430,7 +431,6 @@ end:
|
|||
return 0;
|
||||
|
||||
err_request_irq:
|
||||
irq_free_descs(irq_base, gpio_pins[chip->ioh]);
|
||||
gpiochip_remove(&chip->gpio);
|
||||
|
||||
err_gpiochip_add:
|
||||
|
@ -452,12 +452,6 @@ static void pch_gpio_remove(struct pci_dev *pdev)
|
|||
{
|
||||
struct pch_gpio *chip = pci_get_drvdata(pdev);
|
||||
|
||||
if (chip->irq_base != -1) {
|
||||
free_irq(pdev->irq, chip);
|
||||
|
||||
irq_free_descs(chip->irq_base, gpio_pins[chip->ioh]);
|
||||
}
|
||||
|
||||
gpiochip_remove(&chip->gpio);
|
||||
pci_iounmap(pdev, chip->base);
|
||||
pci_release_regions(pdev);
|
||||
|
|
|
@ -59,7 +59,7 @@ struct idio_16_gpio_reg {
|
|||
*/
|
||||
struct idio_16_gpio {
|
||||
struct gpio_chip chip;
|
||||
spinlock_t lock;
|
||||
raw_spinlock_t lock;
|
||||
struct idio_16_gpio_reg __iomem *reg;
|
||||
unsigned long irq_mask;
|
||||
};
|
||||
|
@ -121,7 +121,7 @@ static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
|||
} else
|
||||
base = &idio16gpio->reg->out0_7;
|
||||
|
||||
spin_lock_irqsave(&idio16gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&idio16gpio->lock, flags);
|
||||
|
||||
if (value)
|
||||
out_state = ioread8(base) | mask;
|
||||
|
@ -130,7 +130,7 @@ static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
|||
|
||||
iowrite8(out_state, base);
|
||||
|
||||
spin_unlock_irqrestore(&idio16gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
|
||||
}
|
||||
|
||||
static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
|
||||
|
@ -140,7 +140,7 @@ static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
|
|||
unsigned long flags;
|
||||
unsigned int out_state;
|
||||
|
||||
spin_lock_irqsave(&idio16gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&idio16gpio->lock, flags);
|
||||
|
||||
/* process output lines 0-7 */
|
||||
if (*mask & 0xFF) {
|
||||
|
@ -160,7 +160,7 @@ static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
|
|||
iowrite8(out_state, &idio16gpio->reg->out8_15);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&idio16gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
|
||||
}
|
||||
|
||||
static void idio_16_irq_ack(struct irq_data *data)
|
||||
|
@ -177,11 +177,11 @@ static void idio_16_irq_mask(struct irq_data *data)
|
|||
idio16gpio->irq_mask &= ~mask;
|
||||
|
||||
if (!idio16gpio->irq_mask) {
|
||||
spin_lock_irqsave(&idio16gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&idio16gpio->lock, flags);
|
||||
|
||||
iowrite8(0, &idio16gpio->reg->irq_ctl);
|
||||
|
||||
spin_unlock_irqrestore(&idio16gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,11 +196,11 @@ static void idio_16_irq_unmask(struct irq_data *data)
|
|||
idio16gpio->irq_mask |= mask;
|
||||
|
||||
if (!prev_irq_mask) {
|
||||
spin_lock_irqsave(&idio16gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&idio16gpio->lock, flags);
|
||||
|
||||
ioread8(&idio16gpio->reg->irq_ctl);
|
||||
|
||||
spin_unlock_irqrestore(&idio16gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -229,11 +229,11 @@ static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
|
|||
struct gpio_chip *const chip = &idio16gpio->chip;
|
||||
int gpio;
|
||||
|
||||
spin_lock(&idio16gpio->lock);
|
||||
raw_spin_lock(&idio16gpio->lock);
|
||||
|
||||
irq_status = ioread8(&idio16gpio->reg->irq_status);
|
||||
|
||||
spin_unlock(&idio16gpio->lock);
|
||||
raw_spin_unlock(&idio16gpio->lock);
|
||||
|
||||
/* Make sure our device generated IRQ */
|
||||
if (!(irq_status & 0x3) || !(irq_status & 0x4))
|
||||
|
@ -242,12 +242,12 @@ static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
|
|||
for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
|
||||
generic_handle_irq(irq_find_mapping(chip->irqdomain, gpio));
|
||||
|
||||
spin_lock(&idio16gpio->lock);
|
||||
raw_spin_lock(&idio16gpio->lock);
|
||||
|
||||
/* Clear interrupt */
|
||||
iowrite8(0, &idio16gpio->reg->in0_7);
|
||||
|
||||
spin_unlock(&idio16gpio->lock);
|
||||
raw_spin_unlock(&idio16gpio->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -302,7 +302,7 @@ static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
idio16gpio->chip.set = idio_16_gpio_set;
|
||||
idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
|
||||
|
||||
spin_lock_init(&idio16gpio->lock);
|
||||
raw_spin_lock_init(&idio16gpio->lock);
|
||||
|
||||
err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
|
||||
if (err) {
|
||||
|
|
|
@ -50,7 +50,7 @@ struct pl061_context_save_regs {
|
|||
#endif
|
||||
|
||||
struct pl061 {
|
||||
spinlock_t lock;
|
||||
raw_spinlock_t lock;
|
||||
|
||||
void __iomem *base;
|
||||
struct gpio_chip gc;
|
||||
|
@ -74,11 +74,11 @@ static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
|
|||
unsigned long flags;
|
||||
unsigned char gpiodir;
|
||||
|
||||
spin_lock_irqsave(&pl061->lock, flags);
|
||||
raw_spin_lock_irqsave(&pl061->lock, flags);
|
||||
gpiodir = readb(pl061->base + GPIODIR);
|
||||
gpiodir &= ~(BIT(offset));
|
||||
writeb(gpiodir, pl061->base + GPIODIR);
|
||||
spin_unlock_irqrestore(&pl061->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&pl061->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ static int pl061_direction_output(struct gpio_chip *gc, unsigned offset,
|
|||
unsigned long flags;
|
||||
unsigned char gpiodir;
|
||||
|
||||
spin_lock_irqsave(&pl061->lock, flags);
|
||||
raw_spin_lock_irqsave(&pl061->lock, flags);
|
||||
writeb(!!value << offset, pl061->base + (BIT(offset + 2)));
|
||||
gpiodir = readb(pl061->base + GPIODIR);
|
||||
gpiodir |= BIT(offset);
|
||||
|
@ -101,7 +101,7 @@ static int pl061_direction_output(struct gpio_chip *gc, unsigned offset,
|
|||
* a gpio pin before configuring it in OUT mode.
|
||||
*/
|
||||
writeb(!!value << offset, pl061->base + (BIT(offset + 2)));
|
||||
spin_unlock_irqrestore(&pl061->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&pl061->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
|
|||
}
|
||||
|
||||
|
||||
spin_lock_irqsave(&pl061->lock, flags);
|
||||
raw_spin_lock_irqsave(&pl061->lock, flags);
|
||||
|
||||
gpioiev = readb(pl061->base + GPIOIEV);
|
||||
gpiois = readb(pl061->base + GPIOIS);
|
||||
|
@ -203,7 +203,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
|
|||
writeb(gpioibe, pl061->base + GPIOIBE);
|
||||
writeb(gpioiev, pl061->base + GPIOIEV);
|
||||
|
||||
spin_unlock_irqrestore(&pl061->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&pl061->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -235,10 +235,10 @@ static void pl061_irq_mask(struct irq_data *d)
|
|||
u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
|
||||
u8 gpioie;
|
||||
|
||||
spin_lock(&pl061->lock);
|
||||
raw_spin_lock(&pl061->lock);
|
||||
gpioie = readb(pl061->base + GPIOIE) & ~mask;
|
||||
writeb(gpioie, pl061->base + GPIOIE);
|
||||
spin_unlock(&pl061->lock);
|
||||
raw_spin_unlock(&pl061->lock);
|
||||
}
|
||||
|
||||
static void pl061_irq_unmask(struct irq_data *d)
|
||||
|
@ -248,10 +248,10 @@ static void pl061_irq_unmask(struct irq_data *d)
|
|||
u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
|
||||
u8 gpioie;
|
||||
|
||||
spin_lock(&pl061->lock);
|
||||
raw_spin_lock(&pl061->lock);
|
||||
gpioie = readb(pl061->base + GPIOIE) | mask;
|
||||
writeb(gpioie, pl061->base + GPIOIE);
|
||||
spin_unlock(&pl061->lock);
|
||||
raw_spin_unlock(&pl061->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -268,9 +268,9 @@ static void pl061_irq_ack(struct irq_data *d)
|
|||
struct pl061 *pl061 = gpiochip_get_data(gc);
|
||||
u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
|
||||
|
||||
spin_lock(&pl061->lock);
|
||||
raw_spin_lock(&pl061->lock);
|
||||
writeb(mask, pl061->base + GPIOIC);
|
||||
spin_unlock(&pl061->lock);
|
||||
raw_spin_unlock(&pl061->lock);
|
||||
}
|
||||
|
||||
static int pl061_irq_set_wake(struct irq_data *d, unsigned int state)
|
||||
|
@ -304,7 +304,7 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
|
|||
if (IS_ERR(pl061->base))
|
||||
return PTR_ERR(pl061->base);
|
||||
|
||||
spin_lock_init(&pl061->lock);
|
||||
raw_spin_lock_init(&pl061->lock);
|
||||
if (of_property_read_bool(dev->of_node, "gpio-ranges")) {
|
||||
pl061->gc.request = gpiochip_generic_request;
|
||||
pl061->gc.free = gpiochip_generic_free;
|
||||
|
|
|
@ -601,7 +601,7 @@ static int pxa_gpio_probe_dt(struct platform_device *pdev,
|
|||
nr_gpios = gpio_id->gpio_nums;
|
||||
pxa_last_gpio = nr_gpios - 1;
|
||||
|
||||
irq_base = irq_alloc_descs(-1, 0, nr_gpios, 0);
|
||||
irq_base = devm_irq_alloc_descs(&pdev->dev, -1, 0, nr_gpios, 0);
|
||||
if (irq_base < 0) {
|
||||
dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n");
|
||||
return irq_base;
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* gpio-reg: single register individually fixed-direction GPIOs
|
||||
*
|
||||
* Copyright (C) 2016 Russell King
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*/
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/gpio-reg.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
struct gpio_reg {
|
||||
struct gpio_chip gc;
|
||||
spinlock_t lock;
|
||||
u32 direction;
|
||||
u32 out;
|
||||
void __iomem *reg;
|
||||
struct irq_domain *irqdomain;
|
||||
const int *irqs;
|
||||
};
|
||||
|
||||
#define to_gpio_reg(x) container_of(x, struct gpio_reg, gc)
|
||||
|
||||
static int gpio_reg_get_direction(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct gpio_reg *r = to_gpio_reg(gc);
|
||||
|
||||
return r->direction & BIT(offset) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int gpio_reg_direction_output(struct gpio_chip *gc, unsigned offset,
|
||||
int value)
|
||||
{
|
||||
struct gpio_reg *r = to_gpio_reg(gc);
|
||||
|
||||
if (r->direction & BIT(offset))
|
||||
return -ENOTSUPP;
|
||||
|
||||
gc->set(gc, offset, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_reg_direction_input(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct gpio_reg *r = to_gpio_reg(gc);
|
||||
|
||||
return r->direction & BIT(offset) ? 0 : -ENOTSUPP;
|
||||
}
|
||||
|
||||
static void gpio_reg_set(struct gpio_chip *gc, unsigned offset, int value)
|
||||
{
|
||||
struct gpio_reg *r = to_gpio_reg(gc);
|
||||
unsigned long flags;
|
||||
u32 val, mask = BIT(offset);
|
||||
|
||||
spin_lock_irqsave(&r->lock, flags);
|
||||
val = r->out;
|
||||
if (value)
|
||||
val |= mask;
|
||||
else
|
||||
val &= ~mask;
|
||||
r->out = val;
|
||||
writel_relaxed(val, r->reg);
|
||||
spin_unlock_irqrestore(&r->lock, flags);
|
||||
}
|
||||
|
||||
static int gpio_reg_get(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct gpio_reg *r = to_gpio_reg(gc);
|
||||
u32 val, mask = BIT(offset);
|
||||
|
||||
if (r->direction & mask) {
|
||||
/*
|
||||
* double-read the value, some registers latch after the
|
||||
* first read.
|
||||
*/
|
||||
readl_relaxed(r->reg);
|
||||
val = readl_relaxed(r->reg);
|
||||
} else {
|
||||
val = r->out;
|
||||
}
|
||||
return !!(val & mask);
|
||||
}
|
||||
|
||||
static void gpio_reg_set_multiple(struct gpio_chip *gc, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
struct gpio_reg *r = to_gpio_reg(gc);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&r->lock, flags);
|
||||
r->out = (r->out & ~*mask) | (*bits & *mask);
|
||||
writel_relaxed(r->out, r->reg);
|
||||
spin_unlock_irqrestore(&r->lock, flags);
|
||||
}
|
||||
|
||||
static int gpio_reg_to_irq(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct gpio_reg *r = to_gpio_reg(gc);
|
||||
int irq = r->irqs[offset];
|
||||
|
||||
if (irq >= 0 && r->irqdomain)
|
||||
irq = irq_find_mapping(r->irqdomain, irq);
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
/**
|
||||
* gpio_reg_init - add a fixed in/out register as gpio
|
||||
* @dev: optional struct device associated with this register
|
||||
* @base: start gpio number, or -1 to allocate
|
||||
* @num: number of GPIOs, maximum 32
|
||||
* @label: GPIO chip label
|
||||
* @direction: bitmask of fixed direction, one per GPIO signal, 1 = in
|
||||
* @def_out: initial GPIO output value
|
||||
* @names: array of %num strings describing each GPIO signal or %NULL
|
||||
* @irqdom: irq domain or %NULL
|
||||
* @irqs: array of %num ints describing the interrupt mapping for each
|
||||
* GPIO signal, or %NULL. If @irqdom is %NULL, then this
|
||||
* describes the Linux interrupt number, otherwise it describes
|
||||
* the hardware interrupt number in the specified irq domain.
|
||||
*
|
||||
* Add a single-register GPIO device containing up to 32 GPIO signals,
|
||||
* where each GPIO has a fixed input or output configuration. Only
|
||||
* input GPIOs are assumed to be readable from the register, and only
|
||||
* then after a double-read. Output values are assumed not to be
|
||||
* readable.
|
||||
*/
|
||||
struct gpio_chip *gpio_reg_init(struct device *dev, void __iomem *reg,
|
||||
int base, int num, const char *label, u32 direction, u32 def_out,
|
||||
const char *const *names, struct irq_domain *irqdom, const int *irqs)
|
||||
{
|
||||
struct gpio_reg *r;
|
||||
int ret;
|
||||
|
||||
if (dev)
|
||||
r = devm_kzalloc(dev, sizeof(*r), GFP_KERNEL);
|
||||
else
|
||||
r = kzalloc(sizeof(*r), GFP_KERNEL);
|
||||
|
||||
if (!r)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
spin_lock_init(&r->lock);
|
||||
|
||||
r->gc.label = label;
|
||||
r->gc.get_direction = gpio_reg_get_direction;
|
||||
r->gc.direction_input = gpio_reg_direction_input;
|
||||
r->gc.direction_output = gpio_reg_direction_output;
|
||||
r->gc.set = gpio_reg_set;
|
||||
r->gc.get = gpio_reg_get;
|
||||
r->gc.set_multiple = gpio_reg_set_multiple;
|
||||
if (irqs)
|
||||
r->gc.to_irq = gpio_reg_to_irq;
|
||||
r->gc.base = base;
|
||||
r->gc.ngpio = num;
|
||||
r->gc.names = names;
|
||||
r->direction = direction;
|
||||
r->out = def_out;
|
||||
r->reg = reg;
|
||||
r->irqs = irqs;
|
||||
|
||||
if (dev)
|
||||
ret = devm_gpiochip_add_data(dev, &r->gc, r);
|
||||
else
|
||||
ret = gpiochip_add_data(&r->gc, r);
|
||||
|
||||
return ret ? ERR_PTR(ret) : &r->gc;
|
||||
}
|
||||
|
||||
int gpio_reg_resume(struct gpio_chip *gc)
|
||||
{
|
||||
struct gpio_reg *r = to_gpio_reg(gc);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&r->lock, flags);
|
||||
writel_relaxed(r->out, r->reg);
|
||||
spin_unlock_irqrestore(&r->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -12,57 +12,97 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <soc/sa1100/pwer.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/irqs.h>
|
||||
|
||||
struct sa1100_gpio_chip {
|
||||
struct gpio_chip chip;
|
||||
void __iomem *membase;
|
||||
int irqbase;
|
||||
u32 irqmask;
|
||||
u32 irqrising;
|
||||
u32 irqfalling;
|
||||
u32 irqwake;
|
||||
};
|
||||
|
||||
#define sa1100_gpio_chip(x) container_of(x, struct sa1100_gpio_chip, chip)
|
||||
|
||||
enum {
|
||||
R_GPLR = 0x00,
|
||||
R_GPDR = 0x04,
|
||||
R_GPSR = 0x08,
|
||||
R_GPCR = 0x0c,
|
||||
R_GRER = 0x10,
|
||||
R_GFER = 0x14,
|
||||
R_GEDR = 0x18,
|
||||
R_GAFR = 0x1c,
|
||||
};
|
||||
|
||||
static int sa1100_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return !!(GPLR & GPIO_GPIO(offset));
|
||||
return readl_relaxed(sa1100_gpio_chip(chip)->membase + R_GPLR) &
|
||||
BIT(offset);
|
||||
}
|
||||
|
||||
static void sa1100_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
{
|
||||
if (value)
|
||||
GPSR = GPIO_GPIO(offset);
|
||||
else
|
||||
GPCR = GPIO_GPIO(offset);
|
||||
int reg = value ? R_GPSR : R_GPCR;
|
||||
|
||||
writel_relaxed(BIT(offset), sa1100_gpio_chip(chip)->membase + reg);
|
||||
}
|
||||
|
||||
static int sa1100_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
void __iomem *gpdr = sa1100_gpio_chip(chip)->membase + R_GPDR;
|
||||
|
||||
return !(readl_relaxed(gpdr) & BIT(offset));
|
||||
}
|
||||
|
||||
static int sa1100_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
void __iomem *gpdr = sa1100_gpio_chip(chip)->membase + R_GPDR;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
GPDR &= ~GPIO_GPIO(offset);
|
||||
writel_relaxed(readl_relaxed(gpdr) & ~BIT(offset), gpdr);
|
||||
local_irq_restore(flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sa1100_direction_output(struct gpio_chip *chip, unsigned offset, int value)
|
||||
{
|
||||
void __iomem *gpdr = sa1100_gpio_chip(chip)->membase + R_GPDR;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
sa1100_gpio_set(chip, offset, value);
|
||||
GPDR |= GPIO_GPIO(offset);
|
||||
writel_relaxed(readl_relaxed(gpdr) | BIT(offset), gpdr);
|
||||
local_irq_restore(flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sa1100_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return IRQ_GPIO0 + offset;
|
||||
return sa1100_gpio_chip(chip)->irqbase + offset;
|
||||
}
|
||||
|
||||
static struct gpio_chip sa1100_gpio_chip = {
|
||||
.label = "gpio",
|
||||
.direction_input = sa1100_direction_input,
|
||||
.direction_output = sa1100_direction_output,
|
||||
.set = sa1100_gpio_set,
|
||||
.get = sa1100_gpio_get,
|
||||
.to_irq = sa1100_to_irq,
|
||||
.base = 0,
|
||||
.ngpio = GPIO_MAX + 1,
|
||||
static struct sa1100_gpio_chip sa1100_gpio_chip = {
|
||||
.chip = {
|
||||
.label = "gpio",
|
||||
.get_direction = sa1100_get_direction,
|
||||
.direction_input = sa1100_direction_input,
|
||||
.direction_output = sa1100_direction_output,
|
||||
.set = sa1100_gpio_set,
|
||||
.get = sa1100_gpio_get,
|
||||
.to_irq = sa1100_to_irq,
|
||||
.base = 0,
|
||||
.ngpio = GPIO_MAX + 1,
|
||||
},
|
||||
.membase = (void *)&GPLR,
|
||||
.irqbase = IRQ_GPIO0,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -70,33 +110,39 @@ static struct gpio_chip sa1100_gpio_chip = {
|
|||
* IRQs are generated on Falling-Edge, Rising-Edge, or both.
|
||||
* Use this instead of directly setting GRER/GFER.
|
||||
*/
|
||||
static int GPIO_IRQ_rising_edge;
|
||||
static int GPIO_IRQ_falling_edge;
|
||||
static int GPIO_IRQ_mask;
|
||||
static void sa1100_update_edge_regs(struct sa1100_gpio_chip *sgc)
|
||||
{
|
||||
void *base = sgc->membase;
|
||||
u32 grer, gfer;
|
||||
|
||||
grer = sgc->irqrising & sgc->irqmask;
|
||||
gfer = sgc->irqfalling & sgc->irqmask;
|
||||
|
||||
writel_relaxed(grer, base + R_GRER);
|
||||
writel_relaxed(gfer, base + R_GFER);
|
||||
}
|
||||
|
||||
static int sa1100_gpio_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
unsigned int mask;
|
||||
|
||||
mask = BIT(d->hwirq);
|
||||
struct sa1100_gpio_chip *sgc = irq_data_get_irq_chip_data(d);
|
||||
unsigned int mask = BIT(d->hwirq);
|
||||
|
||||
if (type == IRQ_TYPE_PROBE) {
|
||||
if ((GPIO_IRQ_rising_edge | GPIO_IRQ_falling_edge) & mask)
|
||||
if ((sgc->irqrising | sgc->irqfalling) & mask)
|
||||
return 0;
|
||||
type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
|
||||
}
|
||||
|
||||
if (type & IRQ_TYPE_EDGE_RISING)
|
||||
GPIO_IRQ_rising_edge |= mask;
|
||||
sgc->irqrising |= mask;
|
||||
else
|
||||
GPIO_IRQ_rising_edge &= ~mask;
|
||||
sgc->irqrising &= ~mask;
|
||||
if (type & IRQ_TYPE_EDGE_FALLING)
|
||||
GPIO_IRQ_falling_edge |= mask;
|
||||
sgc->irqfalling |= mask;
|
||||
else
|
||||
GPIO_IRQ_falling_edge &= ~mask;
|
||||
sgc->irqfalling &= ~mask;
|
||||
|
||||
GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask;
|
||||
GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask;
|
||||
sa1100_update_edge_regs(sgc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -106,36 +152,42 @@ static int sa1100_gpio_type(struct irq_data *d, unsigned int type)
|
|||
*/
|
||||
static void sa1100_gpio_ack(struct irq_data *d)
|
||||
{
|
||||
GEDR = BIT(d->hwirq);
|
||||
struct sa1100_gpio_chip *sgc = irq_data_get_irq_chip_data(d);
|
||||
|
||||
writel_relaxed(BIT(d->hwirq), sgc->membase + R_GEDR);
|
||||
}
|
||||
|
||||
static void sa1100_gpio_mask(struct irq_data *d)
|
||||
{
|
||||
struct sa1100_gpio_chip *sgc = irq_data_get_irq_chip_data(d);
|
||||
unsigned int mask = BIT(d->hwirq);
|
||||
|
||||
GPIO_IRQ_mask &= ~mask;
|
||||
sgc->irqmask &= ~mask;
|
||||
|
||||
GRER &= ~mask;
|
||||
GFER &= ~mask;
|
||||
sa1100_update_edge_regs(sgc);
|
||||
}
|
||||
|
||||
static void sa1100_gpio_unmask(struct irq_data *d)
|
||||
{
|
||||
struct sa1100_gpio_chip *sgc = irq_data_get_irq_chip_data(d);
|
||||
unsigned int mask = BIT(d->hwirq);
|
||||
|
||||
GPIO_IRQ_mask |= mask;
|
||||
sgc->irqmask |= mask;
|
||||
|
||||
GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask;
|
||||
GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask;
|
||||
sa1100_update_edge_regs(sgc);
|
||||
}
|
||||
|
||||
static int sa1100_gpio_wake(struct irq_data *d, unsigned int on)
|
||||
{
|
||||
if (on)
|
||||
PWER |= BIT(d->hwirq);
|
||||
else
|
||||
PWER &= ~BIT(d->hwirq);
|
||||
return 0;
|
||||
struct sa1100_gpio_chip *sgc = irq_data_get_irq_chip_data(d);
|
||||
int ret = sa11x0_gpio_set_wake(d->hwirq, on);
|
||||
if (!ret) {
|
||||
if (on)
|
||||
sgc->irqwake |= BIT(d->hwirq);
|
||||
else
|
||||
sgc->irqwake &= ~BIT(d->hwirq);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -153,8 +205,10 @@ static struct irq_chip sa1100_gpio_irq_chip = {
|
|||
static int sa1100_gpio_irqdomain_map(struct irq_domain *d,
|
||||
unsigned int irq, irq_hw_number_t hwirq)
|
||||
{
|
||||
irq_set_chip_and_handler(irq, &sa1100_gpio_irq_chip,
|
||||
handle_edge_irq);
|
||||
struct sa1100_gpio_chip *sgc = d->host_data;
|
||||
|
||||
irq_set_chip_data(irq, sgc);
|
||||
irq_set_chip_and_handler(irq, &sa1100_gpio_irq_chip, handle_edge_irq);
|
||||
irq_set_probe(irq);
|
||||
|
||||
return 0;
|
||||
|
@ -174,17 +228,19 @@ static struct irq_domain *sa1100_gpio_irqdomain;
|
|||
*/
|
||||
static void sa1100_gpio_handler(struct irq_desc *desc)
|
||||
{
|
||||
struct sa1100_gpio_chip *sgc = irq_desc_get_handler_data(desc);
|
||||
unsigned int irq, mask;
|
||||
void __iomem *gedr = sgc->membase + R_GEDR;
|
||||
|
||||
mask = GEDR;
|
||||
mask = readl_relaxed(gedr);
|
||||
do {
|
||||
/*
|
||||
* clear down all currently active IRQ sources.
|
||||
* We will be processing them all.
|
||||
*/
|
||||
GEDR = mask;
|
||||
writel_relaxed(mask, gedr);
|
||||
|
||||
irq = IRQ_GPIO0;
|
||||
irq = sgc->irqbase;
|
||||
do {
|
||||
if (mask & 1)
|
||||
generic_handle_irq(irq);
|
||||
|
@ -192,30 +248,32 @@ static void sa1100_gpio_handler(struct irq_desc *desc)
|
|||
irq++;
|
||||
} while (mask);
|
||||
|
||||
mask = GEDR;
|
||||
mask = readl_relaxed(gedr);
|
||||
} while (mask);
|
||||
}
|
||||
|
||||
static int sa1100_gpio_suspend(void)
|
||||
{
|
||||
struct sa1100_gpio_chip *sgc = &sa1100_gpio_chip;
|
||||
|
||||
/*
|
||||
* Set the appropriate edges for wakeup.
|
||||
*/
|
||||
GRER = PWER & GPIO_IRQ_rising_edge;
|
||||
GFER = PWER & GPIO_IRQ_falling_edge;
|
||||
writel_relaxed(sgc->irqwake & sgc->irqrising, sgc->membase + R_GRER);
|
||||
writel_relaxed(sgc->irqwake & sgc->irqfalling, sgc->membase + R_GFER);
|
||||
|
||||
/*
|
||||
* Clear any pending GPIO interrupts.
|
||||
*/
|
||||
GEDR = GEDR;
|
||||
writel_relaxed(readl_relaxed(sgc->membase + R_GEDR),
|
||||
sgc->membase + R_GEDR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sa1100_gpio_resume(void)
|
||||
{
|
||||
GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask;
|
||||
GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask;
|
||||
sa1100_update_edge_regs(&sa1100_gpio_chip);
|
||||
}
|
||||
|
||||
static struct syscore_ops sa1100_gpio_syscore_ops = {
|
||||
|
@ -231,36 +289,40 @@ static int __init sa1100_gpio_init_devicefs(void)
|
|||
|
||||
device_initcall(sa1100_gpio_init_devicefs);
|
||||
|
||||
static const int sa1100_gpio_irqs[] __initconst = {
|
||||
/* Install handlers for GPIO 0-10 edge detect interrupts */
|
||||
IRQ_GPIO0_SC,
|
||||
IRQ_GPIO1_SC,
|
||||
IRQ_GPIO2_SC,
|
||||
IRQ_GPIO3_SC,
|
||||
IRQ_GPIO4_SC,
|
||||
IRQ_GPIO5_SC,
|
||||
IRQ_GPIO6_SC,
|
||||
IRQ_GPIO7_SC,
|
||||
IRQ_GPIO8_SC,
|
||||
IRQ_GPIO9_SC,
|
||||
IRQ_GPIO10_SC,
|
||||
/* Install handler for GPIO 11-27 edge detect interrupts */
|
||||
IRQ_GPIO11_27,
|
||||
};
|
||||
|
||||
void __init sa1100_init_gpio(void)
|
||||
{
|
||||
/* clear all GPIO edge detects */
|
||||
GFER = 0;
|
||||
GRER = 0;
|
||||
GEDR = -1;
|
||||
struct sa1100_gpio_chip *sgc = &sa1100_gpio_chip;
|
||||
int i;
|
||||
|
||||
gpiochip_add_data(&sa1100_gpio_chip, NULL);
|
||||
/* clear all GPIO edge detects */
|
||||
writel_relaxed(0, sgc->membase + R_GFER);
|
||||
writel_relaxed(0, sgc->membase + R_GRER);
|
||||
writel_relaxed(-1, sgc->membase + R_GEDR);
|
||||
|
||||
gpiochip_add_data(&sa1100_gpio_chip.chip, NULL);
|
||||
|
||||
sa1100_gpio_irqdomain = irq_domain_add_simple(NULL,
|
||||
28, IRQ_GPIO0,
|
||||
&sa1100_gpio_irqdomain_ops, NULL);
|
||||
|
||||
/*
|
||||
* Install handlers for GPIO 0-10 edge detect interrupts
|
||||
*/
|
||||
irq_set_chained_handler(IRQ_GPIO0_SC, sa1100_gpio_handler);
|
||||
irq_set_chained_handler(IRQ_GPIO1_SC, sa1100_gpio_handler);
|
||||
irq_set_chained_handler(IRQ_GPIO2_SC, sa1100_gpio_handler);
|
||||
irq_set_chained_handler(IRQ_GPIO3_SC, sa1100_gpio_handler);
|
||||
irq_set_chained_handler(IRQ_GPIO4_SC, sa1100_gpio_handler);
|
||||
irq_set_chained_handler(IRQ_GPIO5_SC, sa1100_gpio_handler);
|
||||
irq_set_chained_handler(IRQ_GPIO6_SC, sa1100_gpio_handler);
|
||||
irq_set_chained_handler(IRQ_GPIO7_SC, sa1100_gpio_handler);
|
||||
irq_set_chained_handler(IRQ_GPIO8_SC, sa1100_gpio_handler);
|
||||
irq_set_chained_handler(IRQ_GPIO9_SC, sa1100_gpio_handler);
|
||||
irq_set_chained_handler(IRQ_GPIO10_SC, sa1100_gpio_handler);
|
||||
/*
|
||||
* Install handler for GPIO 11-27 edge detect interrupts
|
||||
*/
|
||||
irq_set_chained_handler(IRQ_GPIO11_27, sa1100_gpio_handler);
|
||||
&sa1100_gpio_irqdomain_ops, sgc);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sa1100_gpio_irqs); i++)
|
||||
irq_set_chained_handler_and_data(sa1100_gpio_irqs[i],
|
||||
sa1100_gpio_handler, sgc);
|
||||
}
|
||||
|
|
|
@ -135,7 +135,8 @@ static int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd,
|
|||
struct irq_chip_type *ct;
|
||||
int ret;
|
||||
|
||||
sd->irq_base = irq_alloc_descs(-1, 0, SDV_NUM_PUB_GPIOS, -1);
|
||||
sd->irq_base = devm_irq_alloc_descs(&pdev->dev, -1, 0,
|
||||
SDV_NUM_PUB_GPIOS, -1);
|
||||
if (sd->irq_base < 0)
|
||||
return sd->irq_base;
|
||||
|
||||
|
@ -143,10 +144,11 @@ static int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd,
|
|||
writel(0, sd->gpio_pub_base + GPIO_INT);
|
||||
writel((1 << 11) - 1, sd->gpio_pub_base + GPSTR);
|
||||
|
||||
ret = request_irq(pdev->irq, sdv_gpio_pub_irq_handler, IRQF_SHARED,
|
||||
"sdv_gpio", sd);
|
||||
ret = devm_request_irq(&pdev->dev, pdev->irq,
|
||||
sdv_gpio_pub_irq_handler, IRQF_SHARED,
|
||||
"sdv_gpio", sd);
|
||||
if (ret)
|
||||
goto out_free_desc;
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* This gpio irq controller latches level irqs. Testing shows that if
|
||||
|
@ -155,10 +157,8 @@ static int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd,
|
|||
*/
|
||||
sd->gc = irq_alloc_generic_chip("sdv-gpio", 1, sd->irq_base,
|
||||
sd->gpio_pub_base, handle_fasteoi_irq);
|
||||
if (!sd->gc) {
|
||||
ret = -ENOMEM;
|
||||
goto out_free_irq;
|
||||
}
|
||||
if (!sd->gc)
|
||||
return -ENOMEM;
|
||||
|
||||
sd->gc->private = sd;
|
||||
ct = sd->gc->chip_types;
|
||||
|
@ -176,16 +176,10 @@ static int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd,
|
|||
|
||||
sd->id = irq_domain_add_legacy(pdev->dev.of_node, SDV_NUM_PUB_GPIOS,
|
||||
sd->irq_base, 0, &irq_domain_sdv_ops, sd);
|
||||
if (!sd->id) {
|
||||
ret = -ENODEV;
|
||||
goto out_free_irq;
|
||||
}
|
||||
if (!sd->id)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
out_free_irq:
|
||||
free_irq(pdev->irq, sd);
|
||||
out_free_desc:
|
||||
irq_free_descs(sd->irq_base, SDV_NUM_PUB_GPIOS);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sdv_gpio_probe(struct pci_dev *pdev,
|
||||
|
|
|
@ -392,7 +392,8 @@ static int gsta_probe(struct platform_device *dev)
|
|||
gsta_set_config(chip, i, gpio_pdata->pinconfig[i]);
|
||||
|
||||
/* 384 was used in previous code: be compatible for other drivers */
|
||||
err = irq_alloc_descs(-1, 384, GSTA_NR_GPIO, NUMA_NO_NODE);
|
||||
err = devm_irq_alloc_descs(&dev->dev, -1, 384,
|
||||
GSTA_NR_GPIO, NUMA_NO_NODE);
|
||||
if (err < 0) {
|
||||
dev_warn(&dev->dev, "sta2x11 gpio: Can't get irq base (%i)\n",
|
||||
-err);
|
||||
|
@ -401,29 +402,23 @@ static int gsta_probe(struct platform_device *dev)
|
|||
chip->irq_base = err;
|
||||
gsta_alloc_irq_chip(chip);
|
||||
|
||||
err = request_irq(pdev->irq, gsta_gpio_handler,
|
||||
IRQF_SHARED, KBUILD_MODNAME, chip);
|
||||
err = devm_request_irq(&dev->dev, pdev->irq, gsta_gpio_handler,
|
||||
IRQF_SHARED, KBUILD_MODNAME, chip);
|
||||
if (err < 0) {
|
||||
dev_err(&dev->dev, "sta2x11 gpio: Can't request irq (%i)\n",
|
||||
-err);
|
||||
goto err_free_descs;
|
||||
return err;
|
||||
}
|
||||
|
||||
err = devm_gpiochip_add_data(&dev->dev, &chip->gpio, chip);
|
||||
if (err < 0) {
|
||||
dev_err(&dev->dev, "sta2x11 gpio: Can't register (%i)\n",
|
||||
-err);
|
||||
goto err_free_irq;
|
||||
return err;
|
||||
}
|
||||
|
||||
platform_set_drvdata(dev, chip);
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
free_irq(pdev->irq, chip);
|
||||
err_free_descs:
|
||||
irq_free_descs(chip->irq_base, GSTA_NR_GPIO);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct platform_driver sta2x11_gpio_platform_driver = {
|
||||
|
|
|
@ -485,7 +485,8 @@ static int gpio_twl4030_probe(struct platform_device *pdev)
|
|||
goto no_irqs;
|
||||
}
|
||||
|
||||
irq_base = irq_alloc_descs(-1, 0, TWL4030_GPIO_MAX, 0);
|
||||
irq_base = devm_irq_alloc_descs(&pdev->dev, -1,
|
||||
0, TWL4030_GPIO_MAX, 0);
|
||||
if (irq_base < 0) {
|
||||
dev_err(&pdev->dev, "Failed to alloc irq_descs\n");
|
||||
return irq_base;
|
||||
|
|
|
@ -51,6 +51,8 @@
|
|||
#define GROUP1_NR_IRQS 6
|
||||
#define IRQ_MASK_BASE 0x4e19
|
||||
#define IRQ_STATUS_BASE 0x4e0b
|
||||
#define GPIO_IRQ0_MASK GENMASK(6, 0)
|
||||
#define GPIO_IRQ1_MASK GENMASK(5, 0)
|
||||
#define UPDATE_IRQ_TYPE BIT(0)
|
||||
#define UPDATE_IRQ_MASK BIT(1)
|
||||
|
||||
|
@ -309,7 +311,7 @@ static irqreturn_t wcove_gpio_irq_handler(int irq, void *data)
|
|||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
pending = p[0] | (p[1] << 8);
|
||||
pending = (p[0] & GPIO_IRQ0_MASK) | ((p[1] & GPIO_IRQ1_MASK) << 7);
|
||||
if (!pending)
|
||||
return IRQ_NONE;
|
||||
|
||||
|
@ -317,7 +319,7 @@ static irqreturn_t wcove_gpio_irq_handler(int irq, void *data)
|
|||
while (pending) {
|
||||
/* One iteration is for all pending bits */
|
||||
for_each_set_bit(gpio, (const unsigned long *)&pending,
|
||||
GROUP0_NR_IRQS) {
|
||||
WCOVE_GPIO_NUM) {
|
||||
offset = (gpio > GROUP0_NR_IRQS) ? 1 : 0;
|
||||
mask = (offset == 1) ? BIT(gpio - GROUP0_NR_IRQS) :
|
||||
BIT(gpio);
|
||||
|
@ -333,7 +335,7 @@ static irqreturn_t wcove_gpio_irq_handler(int irq, void *data)
|
|||
break;
|
||||
}
|
||||
|
||||
pending = p[0] | (p[1] << 8);
|
||||
pending = (p[0] & GPIO_IRQ0_MASK) | ((p[1] & GPIO_IRQ1_MASK) << 7);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
|
|
@ -51,7 +51,7 @@ struct ws16c48_gpio {
|
|||
struct gpio_chip chip;
|
||||
unsigned char io_state[6];
|
||||
unsigned char out_state[6];
|
||||
spinlock_t lock;
|
||||
raw_spinlock_t lock;
|
||||
unsigned long irq_mask;
|
||||
unsigned long flow_mask;
|
||||
unsigned base;
|
||||
|
@ -73,13 +73,13 @@ static int ws16c48_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
|||
const unsigned mask = BIT(offset % 8);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ws16c48gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
|
||||
|
||||
ws16c48gpio->io_state[port] |= mask;
|
||||
ws16c48gpio->out_state[port] &= ~mask;
|
||||
outb(ws16c48gpio->out_state[port], ws16c48gpio->base + port);
|
||||
|
||||
spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ static int ws16c48_gpio_direction_output(struct gpio_chip *chip,
|
|||
const unsigned mask = BIT(offset % 8);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ws16c48gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
|
||||
|
||||
ws16c48gpio->io_state[port] &= ~mask;
|
||||
if (value)
|
||||
|
@ -101,7 +101,7 @@ static int ws16c48_gpio_direction_output(struct gpio_chip *chip,
|
|||
ws16c48gpio->out_state[port] &= ~mask;
|
||||
outb(ws16c48gpio->out_state[port], ws16c48gpio->base + port);
|
||||
|
||||
spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -114,17 +114,17 @@ static int ws16c48_gpio_get(struct gpio_chip *chip, unsigned offset)
|
|||
unsigned long flags;
|
||||
unsigned port_state;
|
||||
|
||||
spin_lock_irqsave(&ws16c48gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
|
||||
|
||||
/* ensure that GPIO is set for input */
|
||||
if (!(ws16c48gpio->io_state[port] & mask)) {
|
||||
spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
port_state = inb(ws16c48gpio->base + port);
|
||||
|
||||
spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
|
||||
|
||||
return !!(port_state & mask);
|
||||
}
|
||||
|
@ -136,11 +136,11 @@ static void ws16c48_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
|||
const unsigned mask = BIT(offset % 8);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ws16c48gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
|
||||
|
||||
/* ensure that GPIO is set for output */
|
||||
if (ws16c48gpio->io_state[port] & mask) {
|
||||
spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -150,7 +150,7 @@ static void ws16c48_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
|||
ws16c48gpio->out_state[port] &= ~mask;
|
||||
outb(ws16c48gpio->out_state[port], ws16c48gpio->base + port);
|
||||
|
||||
spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
|
||||
}
|
||||
|
||||
static void ws16c48_gpio_set_multiple(struct gpio_chip *chip,
|
||||
|
@ -178,14 +178,14 @@ static void ws16c48_gpio_set_multiple(struct gpio_chip *chip,
|
|||
iomask = mask[BIT_WORD(i)] & ~ws16c48gpio->io_state[port];
|
||||
bitmask = iomask & bits[BIT_WORD(i)];
|
||||
|
||||
spin_lock_irqsave(&ws16c48gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
|
||||
|
||||
/* update output state data and set device gpio register */
|
||||
ws16c48gpio->out_state[port] &= ~iomask;
|
||||
ws16c48gpio->out_state[port] |= bitmask;
|
||||
outb(ws16c48gpio->out_state[port], ws16c48gpio->base + port);
|
||||
|
||||
spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
|
||||
|
||||
/* prepare for next gpio register set */
|
||||
mask[BIT_WORD(i)] >>= gpio_reg_size;
|
||||
|
@ -207,7 +207,7 @@ static void ws16c48_irq_ack(struct irq_data *data)
|
|||
if (port > 2)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&ws16c48gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
|
||||
|
||||
port_state = ws16c48gpio->irq_mask >> (8*port);
|
||||
|
||||
|
@ -216,7 +216,7 @@ static void ws16c48_irq_ack(struct irq_data *data)
|
|||
outb(port_state | mask, ws16c48gpio->base + 8 + port);
|
||||
outb(0xC0, ws16c48gpio->base + 7);
|
||||
|
||||
spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
|
||||
}
|
||||
|
||||
static void ws16c48_irq_mask(struct irq_data *data)
|
||||
|
@ -232,7 +232,7 @@ static void ws16c48_irq_mask(struct irq_data *data)
|
|||
if (port > 2)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&ws16c48gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
|
||||
|
||||
ws16c48gpio->irq_mask &= ~mask;
|
||||
|
||||
|
@ -240,7 +240,7 @@ static void ws16c48_irq_mask(struct irq_data *data)
|
|||
outb(ws16c48gpio->irq_mask >> (8*port), ws16c48gpio->base + 8 + port);
|
||||
outb(0xC0, ws16c48gpio->base + 7);
|
||||
|
||||
spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
|
||||
}
|
||||
|
||||
static void ws16c48_irq_unmask(struct irq_data *data)
|
||||
|
@ -256,7 +256,7 @@ static void ws16c48_irq_unmask(struct irq_data *data)
|
|||
if (port > 2)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&ws16c48gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
|
||||
|
||||
ws16c48gpio->irq_mask |= mask;
|
||||
|
||||
|
@ -264,7 +264,7 @@ static void ws16c48_irq_unmask(struct irq_data *data)
|
|||
outb(ws16c48gpio->irq_mask >> (8*port), ws16c48gpio->base + 8 + port);
|
||||
outb(0xC0, ws16c48gpio->base + 7);
|
||||
|
||||
spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
|
||||
}
|
||||
|
||||
static int ws16c48_irq_set_type(struct irq_data *data, unsigned flow_type)
|
||||
|
@ -280,7 +280,7 @@ static int ws16c48_irq_set_type(struct irq_data *data, unsigned flow_type)
|
|||
if (port > 2)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&ws16c48gpio->lock, flags);
|
||||
raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
|
||||
|
||||
switch (flow_type) {
|
||||
case IRQ_TYPE_NONE:
|
||||
|
@ -292,7 +292,7 @@ static int ws16c48_irq_set_type(struct irq_data *data, unsigned flow_type)
|
|||
ws16c48gpio->flow_mask &= ~mask;
|
||||
break;
|
||||
default:
|
||||
spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -300,7 +300,7 @@ static int ws16c48_irq_set_type(struct irq_data *data, unsigned flow_type)
|
|||
outb(ws16c48gpio->flow_mask >> (8*port), ws16c48gpio->base + 8 + port);
|
||||
outb(0xC0, ws16c48gpio->base + 7);
|
||||
|
||||
spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -387,7 +387,7 @@ static int ws16c48_probe(struct device *dev, unsigned int id)
|
|||
ws16c48gpio->chip.set_multiple = ws16c48_gpio_set_multiple;
|
||||
ws16c48gpio->base = base[id];
|
||||
|
||||
spin_lock_init(&ws16c48gpio->lock);
|
||||
raw_spin_lock_init(&ws16c48gpio->lock);
|
||||
|
||||
err = devm_gpiochip_add_data(dev, &ws16c48gpio->chip, ws16c48gpio);
|
||||
if (err) {
|
||||
|
|
|
@ -404,7 +404,9 @@ static int xlp_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
/* XLP(MIPS) has fixed range for GPIO IRQs, Vulcan(ARM64) does not */
|
||||
if (soc_type != GPIO_VARIANT_VULCAN) {
|
||||
irq_base = irq_alloc_descs(-1, XLP_GPIO_IRQ_BASE, gc->ngpio, 0);
|
||||
irq_base = devm_irq_alloc_descs(&pdev->dev, -1,
|
||||
XLP_GPIO_IRQ_BASE,
|
||||
gc->ngpio, 0);
|
||||
if (irq_base < 0) {
|
||||
dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n");
|
||||
return irq_base;
|
||||
|
@ -415,7 +417,7 @@ static int xlp_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
err = gpiochip_add_data(gc, priv);
|
||||
if (err < 0)
|
||||
goto out_free_desc;
|
||||
return err;
|
||||
|
||||
err = gpiochip_irqchip_add(gc, &xlp_gpio_irq_chip, irq_base,
|
||||
handle_level_irq, IRQ_TYPE_NONE);
|
||||
|
@ -433,14 +435,13 @@ static int xlp_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
out_gpio_remove:
|
||||
gpiochip_remove(gc);
|
||||
out_free_desc:
|
||||
irq_free_descs(irq_base, gc->ngpio);
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id xlp_gpio_acpi_match[] = {
|
||||
{ "BRCM9006", GPIO_VARIANT_VULCAN },
|
||||
{ "CAV9006", GPIO_VARIANT_VULCAN },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, xlp_gpio_acpi_match);
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
#define ZX_GPIO_NR 16
|
||||
|
||||
struct zx_gpio {
|
||||
spinlock_t lock;
|
||||
raw_spinlock_t lock;
|
||||
|
||||
void __iomem *base;
|
||||
struct gpio_chip gc;
|
||||
|
@ -56,11 +56,11 @@ static int zx_direction_input(struct gpio_chip *gc, unsigned offset)
|
|||
if (offset >= gc->ngpio)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&chip->lock, flags);
|
||||
raw_spin_lock_irqsave(&chip->lock, flags);
|
||||
gpiodir = readw_relaxed(chip->base + ZX_GPIO_DIR);
|
||||
gpiodir &= ~BIT(offset);
|
||||
writew_relaxed(gpiodir, chip->base + ZX_GPIO_DIR);
|
||||
spin_unlock_irqrestore(&chip->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&chip->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ static int zx_direction_output(struct gpio_chip *gc, unsigned offset,
|
|||
if (offset >= gc->ngpio)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&chip->lock, flags);
|
||||
raw_spin_lock_irqsave(&chip->lock, flags);
|
||||
gpiodir = readw_relaxed(chip->base + ZX_GPIO_DIR);
|
||||
gpiodir |= BIT(offset);
|
||||
writew_relaxed(gpiodir, chip->base + ZX_GPIO_DIR);
|
||||
|
@ -84,7 +84,7 @@ static int zx_direction_output(struct gpio_chip *gc, unsigned offset,
|
|||
writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO1);
|
||||
else
|
||||
writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO0);
|
||||
spin_unlock_irqrestore(&chip->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&chip->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -118,7 +118,7 @@ static int zx_irq_type(struct irq_data *d, unsigned trigger)
|
|||
if (offset < 0 || offset >= ZX_GPIO_NR)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&chip->lock, flags);
|
||||
raw_spin_lock_irqsave(&chip->lock, flags);
|
||||
|
||||
gpioiev = readw_relaxed(chip->base + ZX_GPIO_IV);
|
||||
gpiois = readw_relaxed(chip->base + ZX_GPIO_IVE);
|
||||
|
@ -151,7 +151,7 @@ static int zx_irq_type(struct irq_data *d, unsigned trigger)
|
|||
writew_relaxed(gpioi_epos, chip->base + ZX_GPIO_IEP);
|
||||
writew_relaxed(gpioi_eneg, chip->base + ZX_GPIO_IEN);
|
||||
writew_relaxed(gpioiev, chip->base + ZX_GPIO_IV);
|
||||
spin_unlock_irqrestore(&chip->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&chip->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -184,12 +184,12 @@ static void zx_irq_mask(struct irq_data *d)
|
|||
u16 mask = BIT(irqd_to_hwirq(d) % ZX_GPIO_NR);
|
||||
u16 gpioie;
|
||||
|
||||
spin_lock(&chip->lock);
|
||||
raw_spin_lock(&chip->lock);
|
||||
gpioie = readw_relaxed(chip->base + ZX_GPIO_IM) | mask;
|
||||
writew_relaxed(gpioie, chip->base + ZX_GPIO_IM);
|
||||
gpioie = readw_relaxed(chip->base + ZX_GPIO_IE) & ~mask;
|
||||
writew_relaxed(gpioie, chip->base + ZX_GPIO_IE);
|
||||
spin_unlock(&chip->lock);
|
||||
raw_spin_unlock(&chip->lock);
|
||||
}
|
||||
|
||||
static void zx_irq_unmask(struct irq_data *d)
|
||||
|
@ -199,12 +199,12 @@ static void zx_irq_unmask(struct irq_data *d)
|
|||
u16 mask = BIT(irqd_to_hwirq(d) % ZX_GPIO_NR);
|
||||
u16 gpioie;
|
||||
|
||||
spin_lock(&chip->lock);
|
||||
raw_spin_lock(&chip->lock);
|
||||
gpioie = readw_relaxed(chip->base + ZX_GPIO_IM) & ~mask;
|
||||
writew_relaxed(gpioie, chip->base + ZX_GPIO_IM);
|
||||
gpioie = readw_relaxed(chip->base + ZX_GPIO_IE) | mask;
|
||||
writew_relaxed(gpioie, chip->base + ZX_GPIO_IE);
|
||||
spin_unlock(&chip->lock);
|
||||
raw_spin_unlock(&chip->lock);
|
||||
}
|
||||
|
||||
static struct irq_chip zx_irqchip = {
|
||||
|
@ -230,7 +230,7 @@ static int zx_gpio_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(chip->base))
|
||||
return PTR_ERR(chip->base);
|
||||
|
||||
spin_lock_init(&chip->lock);
|
||||
raw_spin_lock_init(&chip->lock);
|
||||
if (of_property_read_bool(dev->of_node, "gpio-ranges")) {
|
||||
chip->gc.request = gpiochip_generic_request;
|
||||
chip->gc.free = gpiochip_generic_free;
|
||||
|
|
|
@ -368,6 +368,37 @@ int acpi_dev_add_driver_gpios(struct acpi_device *adev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_dev_add_driver_gpios);
|
||||
|
||||
static void devm_acpi_dev_release_driver_gpios(struct device *dev, void *res)
|
||||
{
|
||||
acpi_dev_remove_driver_gpios(ACPI_COMPANION(dev));
|
||||
}
|
||||
|
||||
int devm_acpi_dev_add_driver_gpios(struct device *dev,
|
||||
const struct acpi_gpio_mapping *gpios)
|
||||
{
|
||||
void *res;
|
||||
int ret;
|
||||
|
||||
res = devres_alloc(devm_acpi_dev_release_driver_gpios, 0, GFP_KERNEL);
|
||||
if (!res)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(dev), gpios);
|
||||
if (ret) {
|
||||
devres_free(res);
|
||||
return ret;
|
||||
}
|
||||
devres_add(dev, res);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_acpi_dev_add_driver_gpios);
|
||||
|
||||
void devm_acpi_dev_remove_driver_gpios(struct device *dev)
|
||||
{
|
||||
WARN_ON(devres_release(dev, devm_acpi_dev_release_driver_gpios, NULL, NULL));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_acpi_dev_remove_driver_gpios);
|
||||
|
||||
static bool acpi_get_driver_gpio_data(struct acpi_device *adev,
|
||||
const char *name, int index,
|
||||
struct acpi_reference_args *args)
|
||||
|
@ -661,20 +692,24 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
|
|||
{
|
||||
int idx, i;
|
||||
unsigned int irq_flags;
|
||||
int ret = -ENOENT;
|
||||
|
||||
for (i = 0, idx = 0; idx <= index; i++) {
|
||||
struct acpi_gpio_info info;
|
||||
struct gpio_desc *desc;
|
||||
|
||||
desc = acpi_get_gpiod_by_index(adev, NULL, i, &info);
|
||||
if (IS_ERR(desc)) {
|
||||
ret = PTR_ERR(desc);
|
||||
break;
|
||||
}
|
||||
if (info.gpioint && idx++ == index) {
|
||||
int irq = gpiod_to_irq(desc);
|
||||
|
||||
/* Ignore -EPROBE_DEFER, it only matters if idx matches */
|
||||
if (IS_ERR(desc) && PTR_ERR(desc) != -EPROBE_DEFER)
|
||||
return PTR_ERR(desc);
|
||||
|
||||
if (info.gpioint && idx++ == index) {
|
||||
int irq;
|
||||
|
||||
if (IS_ERR(desc))
|
||||
return PTR_ERR(desc);
|
||||
|
||||
irq = gpiod_to_irq(desc);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
|
@ -690,7 +725,7 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
|
|||
}
|
||||
|
||||
}
|
||||
return ret;
|
||||
return -ENOENT;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_dev_gpio_irq_get);
|
||||
|
||||
|
@ -1075,7 +1110,7 @@ int acpi_gpio_count(struct device *dev, const char *con_id)
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (count >= 0)
|
||||
if (count > 0)
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1091,7 +1126,7 @@ int acpi_gpio_count(struct device *dev, const char *con_id)
|
|||
if (crs_count > 0)
|
||||
count = crs_count;
|
||||
}
|
||||
return count;
|
||||
return count ? count : -ENOENT;
|
||||
}
|
||||
|
||||
struct acpi_crs_lookup {
|
||||
|
|
|
@ -147,7 +147,7 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
|
|||
*flags |= GPIO_ACTIVE_LOW;
|
||||
|
||||
if (of_flags & OF_GPIO_SINGLE_ENDED) {
|
||||
if (of_flags & OF_GPIO_ACTIVE_LOW)
|
||||
if (of_flags & OF_GPIO_OPEN_DRAIN)
|
||||
*flags |= GPIO_OPEN_DRAIN;
|
||||
else
|
||||
*flags |= GPIO_OPEN_SOURCE;
|
||||
|
|
|
@ -1522,7 +1522,7 @@ static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
|
|||
*/
|
||||
static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip,
|
||||
struct irq_chip *irqchip,
|
||||
int parent_irq,
|
||||
unsigned int parent_irq,
|
||||
irq_flow_handler_t parent_handler)
|
||||
{
|
||||
unsigned int offset;
|
||||
|
@ -1571,7 +1571,7 @@ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip,
|
|||
*/
|
||||
void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
|
||||
struct irq_chip *irqchip,
|
||||
int parent_irq,
|
||||
unsigned int parent_irq,
|
||||
irq_flow_handler_t parent_handler)
|
||||
{
|
||||
gpiochip_set_cascaded_irqchip(gpiochip, irqchip, parent_irq,
|
||||
|
@ -1588,7 +1588,7 @@ EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip);
|
|||
*/
|
||||
void gpiochip_set_nested_irqchip(struct gpio_chip *gpiochip,
|
||||
struct irq_chip *irqchip,
|
||||
int parent_irq)
|
||||
unsigned int parent_irq)
|
||||
{
|
||||
if (!gpiochip->irq_nested) {
|
||||
chip_err(gpiochip, "tried to nest a chained gpiochip\n");
|
||||
|
@ -3122,10 +3122,10 @@ static int dt_gpio_count(struct device *dev, const char *con_id)
|
|||
gpio_suffixes[i]);
|
||||
|
||||
ret = of_gpio_named_count(dev->of_node, propname);
|
||||
if (ret >= 0)
|
||||
if (ret > 0)
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
return ret ? ret : -ENOENT;
|
||||
}
|
||||
|
||||
static int platform_gpio_count(struct device *dev, const char *con_id)
|
||||
|
@ -3326,7 +3326,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_index);
|
|||
* underlying firmware interface and then makes sure that the GPIO
|
||||
* descriptor is requested before it is returned to the caller.
|
||||
*
|
||||
* On successfull request the GPIO pin is configured in accordance with
|
||||
* On successful request the GPIO pin is configured in accordance with
|
||||
* provided @dflags.
|
||||
*
|
||||
* In case of error an ERR_PTR() is returned.
|
||||
|
@ -3340,6 +3340,7 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
|
|||
unsigned long lflags = 0;
|
||||
bool active_low = false;
|
||||
bool single_ended = false;
|
||||
bool open_drain = false;
|
||||
int ret;
|
||||
|
||||
if (!fwnode)
|
||||
|
@ -3353,6 +3354,7 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
|
|||
if (!IS_ERR(desc)) {
|
||||
active_low = flags & OF_GPIO_ACTIVE_LOW;
|
||||
single_ended = flags & OF_GPIO_SINGLE_ENDED;
|
||||
open_drain = flags & OF_GPIO_OPEN_DRAIN;
|
||||
}
|
||||
} else if (is_acpi_node(fwnode)) {
|
||||
struct acpi_gpio_info info;
|
||||
|
@ -3373,7 +3375,7 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
|
|||
lflags |= GPIO_ACTIVE_LOW;
|
||||
|
||||
if (single_ended) {
|
||||
if (active_low)
|
||||
if (open_drain)
|
||||
lflags |= GPIO_OPEN_DRAIN;
|
||||
else
|
||||
lflags |= GPIO_OPEN_SOURCE;
|
||||
|
|
|
@ -320,9 +320,10 @@ static int soc_button_probe(struct platform_device *pdev)
|
|||
button_info = (struct soc_button_info *)id->driver_data;
|
||||
}
|
||||
|
||||
if (gpiod_count(dev, NULL) <= 0) {
|
||||
error = gpiod_count(dev, NULL);
|
||||
if (error < 0) {
|
||||
dev_dbg(dev, "no GPIO attached, ignoring...\n");
|
||||
return -ENODEV;
|
||||
return error;
|
||||
}
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
|
|
|
@ -196,9 +196,10 @@ static int surface3_button_probe(struct i2c_client *client,
|
|||
strlen(SURFACE_BUTTON_OBJ_NAME)))
|
||||
return -ENODEV;
|
||||
|
||||
if (gpiod_count(dev, KBUILD_MODNAME) <= 0) {
|
||||
error = gpiod_count(dev, NULL);
|
||||
if (error < 0) {
|
||||
dev_dbg(dev, "no GPIO attached, ignoring...\n");
|
||||
return -ENODEV;
|
||||
return error;
|
||||
}
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
|
|
|
@ -125,8 +125,10 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc)
|
|||
if (pdev->device == PCI_DEVICE_ID_INTEL_BYT) {
|
||||
struct gpio_desc *gpio;
|
||||
|
||||
acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev),
|
||||
ret = devm_acpi_dev_add_driver_gpios(&pdev->dev,
|
||||
acpi_dwc3_byt_gpios);
|
||||
if (ret)
|
||||
dev_dbg(&pdev->dev, "failed to add mapping table\n");
|
||||
|
||||
/*
|
||||
* These GPIOs will turn on the USB2 PHY. Note that we have to
|
||||
|
@ -242,7 +244,6 @@ static void dwc3_pci_remove(struct pci_dev *pci)
|
|||
|
||||
device_init_wakeup(&pci->dev, false);
|
||||
pm_runtime_get(&pci->dev);
|
||||
acpi_dev_remove_driver_gpios(ACPI_COMPANION(&pci->dev));
|
||||
platform_device_unregister(dwc->dwc3);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,11 +17,15 @@
|
|||
#define GPIO_PUSH_PULL 0
|
||||
#define GPIO_SINGLE_ENDED 2
|
||||
|
||||
/* Bit 2 express Open drain or open source */
|
||||
#define GPIO_LINE_OPEN_SOURCE 0
|
||||
#define GPIO_LINE_OPEN_DRAIN 4
|
||||
|
||||
/*
|
||||
* Open Drain/Collector is the combination of single-ended active low,
|
||||
* Open Source/Emitter is the combination of single-ended active high.
|
||||
* Open Drain/Collector is the combination of single-ended open drain interface.
|
||||
* Open Source/Emitter is the combination of single-ended open source interface.
|
||||
*/
|
||||
#define GPIO_OPEN_DRAIN (GPIO_SINGLE_ENDED | GPIO_ACTIVE_LOW)
|
||||
#define GPIO_OPEN_SOURCE (GPIO_SINGLE_ENDED | GPIO_ACTIVE_HIGH)
|
||||
#define GPIO_OPEN_DRAIN (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_DRAIN)
|
||||
#define GPIO_OPEN_SOURCE (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_SOURCE)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -957,6 +957,10 @@ static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev)
|
|||
adev->driver_gpios = NULL;
|
||||
}
|
||||
|
||||
int devm_acpi_dev_add_driver_gpios(struct device *dev,
|
||||
const struct acpi_gpio_mapping *gpios);
|
||||
void devm_acpi_dev_remove_driver_gpios(struct device *dev);
|
||||
|
||||
int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index);
|
||||
#else
|
||||
static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev,
|
||||
|
@ -966,6 +970,13 @@ static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev,
|
|||
}
|
||||
static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev) {}
|
||||
|
||||
static inline int devm_acpi_dev_add_driver_gpios(struct device *dev,
|
||||
const struct acpi_gpio_mapping *gpios)
|
||||
{
|
||||
return -ENXIO;
|
||||
}
|
||||
static inline void devm_acpi_dev_remove_driver_gpios(struct device *dev) {}
|
||||
|
||||
static inline int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
|
||||
{
|
||||
return -ENXIO;
|
||||
|
|
|
@ -170,14 +170,14 @@ static inline struct gpio_desc *__must_check
|
|||
gpiod_get_optional(struct device *dev, const char *con_id,
|
||||
enum gpiod_flags flags)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct gpio_desc *__must_check
|
||||
gpiod_get_index_optional(struct device *dev, const char *con_id,
|
||||
unsigned int index, enum gpiod_flags flags)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct gpio_descs *__must_check
|
||||
|
@ -191,7 +191,7 @@ static inline struct gpio_descs *__must_check
|
|||
gpiod_get_array_optional(struct device *dev, const char *con_id,
|
||||
enum gpiod_flags flags)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void gpiod_put(struct gpio_desc *desc)
|
||||
|
@ -231,14 +231,14 @@ static inline struct gpio_desc *__must_check
|
|||
devm_gpiod_get_optional(struct device *dev, const char *con_id,
|
||||
enum gpiod_flags flags)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct gpio_desc *__must_check
|
||||
devm_gpiod_get_index_optional(struct device *dev, const char *con_id,
|
||||
unsigned int index, enum gpiod_flags flags)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct gpio_descs *__must_check
|
||||
|
@ -252,7 +252,7 @@ static inline struct gpio_descs *__must_check
|
|||
devm_gpiod_get_array_optional(struct device *dev, const char *con_id,
|
||||
enum gpiod_flags flags)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void devm_gpiod_put(struct device *dev, struct gpio_desc *desc)
|
||||
|
|
|
@ -168,7 +168,7 @@ struct gpio_chip {
|
|||
unsigned int irq_base;
|
||||
irq_flow_handler_t irq_handler;
|
||||
unsigned int irq_default_type;
|
||||
int irq_chained_parent;
|
||||
unsigned int irq_chained_parent;
|
||||
bool irq_nested;
|
||||
bool irq_need_valid_mask;
|
||||
unsigned long *irq_valid_mask;
|
||||
|
@ -244,12 +244,12 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev,
|
|||
|
||||
void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
|
||||
struct irq_chip *irqchip,
|
||||
int parent_irq,
|
||||
unsigned int parent_irq,
|
||||
irq_flow_handler_t parent_handler);
|
||||
|
||||
void gpiochip_set_nested_irqchip(struct gpio_chip *gpiochip,
|
||||
struct irq_chip *irqchip,
|
||||
int parent_irq);
|
||||
unsigned int parent_irq);
|
||||
|
||||
int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
|
||||
struct irq_chip *irqchip,
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef GPIO_REG_H
|
||||
#define GPIO_REG_H
|
||||
|
||||
struct device;
|
||||
struct irq_domain;
|
||||
|
||||
struct gpio_chip *gpio_reg_init(struct device *dev, void __iomem *reg,
|
||||
int base, int num, const char *label, u32 direction, u32 def_out,
|
||||
const char *const *names, struct irq_domain *irqdom, const int *irqs);
|
||||
|
||||
int gpio_reg_resume(struct gpio_chip *gc);
|
||||
|
||||
#endif
|
|
@ -30,6 +30,7 @@ struct device_node;
|
|||
enum of_gpio_flags {
|
||||
OF_GPIO_ACTIVE_LOW = 0x1,
|
||||
OF_GPIO_SINGLE_ENDED = 0x2,
|
||||
OF_GPIO_OPEN_DRAIN = 0x4,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF_GPIO
|
||||
|
|
Загрузка…
Ссылка в новой задаче