Commit 061ad503 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'gpio-v4.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio

Pull GPIO updates from Luinus Walleij:
 "Bulk GPIO changes for the v4.10 kernel cycle:

  Core changes:

   - Simplify threaded interrupt handling: instead of passing numbed
     parameters to gpiochip_irqchip_add_chained() we create a new call:
     gpiochip_irqchip_add_nested() so the two types are clearly
     semantically different. Also make sure that all nested chips call
     gpiochip_set_nested_irqchip() which is necessary for IRQ resend to
     work properly if it happens.

   - Return error on seek operations for the chardev.

   - Clamp values set as part of gpio[d]_direction_output() so that
     anything != 0 will be send down to the driver as "1" not the value
     passed in.

   - ACPI can now support naming of GPIO lines, hogs and holes in the
     GPIO lists.

  New drivers:

   - The SX150x driver was deemed unfit for the GPIO subsystem and was
     moved over to a combined GPIO+pinctrl driver in the pinctrl
     subsystem.

  New features:

   - Various cleanups to various drivers"

* tag 'gpio-v4.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (49 commits)
  gpio: merrifield: Implement gpio_get_direction callback
  gpio: merrifield: Add support for hardware debouncer
  gpio: chardev: Return error for seek operations
  gpio: arizona: Tidy up probe error path
  gpio: arizona: Remove pointless set of platform drvdata
  gpio: pl061: delete platform data handling
  gpio: pl061: move platform data into driver
  gpio: pl061: rename variable from chip to pl061
  gpio: pl061: rename state container struct
  gpio: pl061: use local state for parent IRQ storage
  gpio: set explicit nesting on drivers
  gpio: simplify adding threaded interrupts
  gpio: vf610: use builtin_platform_driver
  gpio: axp209: use correct register for GPIO input status
  gpio: stmpe: fix interrupt handling bug
  gpio: em: depnd on ARCH_SHMOBILE
  gpio: zx: depend on ARCH_ZX
  gpio: x86: update config dependencies for x86 specific hardware
  gpio: mb86s7x: use builtin_platform_driver
  gpio: etraxfs: use builtin_platform_driver
  ...
parents e7aa8c2e acf1fcf7
...@@ -51,6 +51,68 @@ it to 1 marks the GPIO as active low. ...@@ -51,6 +51,68 @@ it to 1 marks the GPIO as active low.
In our Bluetooth example the "reset-gpios" refers to the second GpioIo() In our Bluetooth example the "reset-gpios" refers to the second GpioIo()
resource, second pin in that resource with the GPIO number of 31. resource, second pin in that resource with the GPIO number of 31.
It is possible to leave holes in the array of GPIOs. This is useful in
cases like with SPI host controllers where some chip selects may be
implemented as GPIOs and some as native signals. For example a SPI host
controller can have chip selects 0 and 2 implemented as GPIOs and 1 as
native:
Package () {
"cs-gpios",
Package () {
^GPIO, 19, 0, 0, // chip select 0: GPIO
0, // chip select 1: native signal
^GPIO, 20, 0, 0, // chip select 2: GPIO
}
}
Other supported properties
--------------------------
Following Device Tree compatible device properties are also supported by
_DSD device properties for GPIO controllers:
- gpio-hog
- output-high
- output-low
- input
- line-name
Example:
Name (_DSD, Package () {
// _DSD Hierarchical Properties Extension UUID
ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
Package () {
Package () {"hog-gpio8", "G8PU"}
}
})
Name (G8PU, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () {"gpio-hog", 1},
Package () {"gpios", Package () {8, 0}},
Package () {"output-high", 1},
Package () {"line-name", "gpio8-pullup"},
}
})
- gpio-line-names
Example:
Package () {
"gpio-line-names",
Package () {
"SPI0_CS_N", "EXP2_INT", "MUX6_IO", "UART0_RXD", "MUX7_IO",
"LVL_C_A1", "MUX0_IO", "SPI1_MISO"
}
}
See Documentation/devicetree/bindings/gpio/gpio.txt for more information
about these properties.
ACPI GPIO Mappings Provided by Drivers ACPI GPIO Mappings Provided by Drivers
-------------------------------------- --------------------------------------
......
SEMTECH SX150x GPIO expander bindings SEMTECH SX150x GPIO expander bindings
Please refer to pinctrl-bindings.txt, ../gpio/gpio.txt, and
../interrupt-controller/interrupts.txt for generic information regarding
pin controller, GPIO, and interrupt bindings.
Required properties: Required properties:
- compatible: should be one of :
- compatible: should be "semtech,sx1506q", "semtech,sx1506q",
"semtech,sx1508q", "semtech,sx1508q",
"semtech,sx1509q", "semtech,sx1509q",
"semtech,sx1502q". "semtech,sx1502q".
- reg: The I2C slave address for this device. - reg: The I2C slave address for this device.
- interrupt-parent: phandle of the parent interrupt controller.
- interrupts: Interrupt specifier for the controllers interrupt.
- #gpio-cells: Should be 2. The first cell is the GPIO number and the - #gpio-cells: Should be 2. The first cell is the GPIO number and the
second cell is used to specify optional parameters: second cell is used to specify optional parameters:
bit 0: polarity (0: normal, 1: inverted) bit 0: polarity (0: normal, 1: inverted)
- gpio-controller: Marks the device as a GPIO controller. - gpio-controller: Marks the device as a GPIO controller.
Optional properties :
- interrupt-parent: phandle of the parent interrupt controller.
- interrupts: Interrupt specifier for the controllers interrupt.
- interrupt-controller: Marks the device as a interrupt controller. - interrupt-controller: Marks the device as a interrupt controller.
- semtech,probe-reset: Will trigger a reset of the GPIO expander on probe,
only for sx1508q and sx1509q
The GPIO expander can optionally be used as an interrupt controller, in The GPIO expander can optionally be used as an interrupt controller, in
which case it uses the default two cell specifier as described in which case it uses the default two cell specifier.
Documentation/devicetree/bindings/interrupt-controller/interrupts.txt.
Required properties for pin configuration sub-nodes:
- pins: List of pins to which the configuration applies.
Optional properties for pin configuration sub-nodes:
----------------------------------------------------
- bias-disable: disable any pin bias, except the OSCIO pin
- bias-pull-up: pull up the pin, except the OSCIO pin
- bias-pull-down: pull down the pin, except the OSCIO pin
- bias-pull-pin-default: use pin-default pull state, except the OSCIO pin
- drive-push-pull: drive actively high and low
- drive-open-drain: drive with open drain only for sx1508q and sx1509q and except the OSCIO pin
- output-low: set the pin to output mode with low level
- output-high: set the pin to output mode with high level
Example: Example:
i2c_gpio_expander@20{ i2c0gpio-expander@20{
#gpio-cells = <2>; #gpio-cells = <2>;
#interrupt-cells = <2>; #interrupt-cells = <2>;
compatible = "semtech,sx1506q"; compatible = "semtech,sx1506q";
...@@ -38,4 +58,12 @@ Example: ...@@ -38,4 +58,12 @@ Example:
gpio-controller; gpio-controller;
interrupt-controller; interrupt-controller;
pinctrl-names = "default";
pinctrl-0 = <&gpio1_cfg_pins>;
gpio1_cfg_pins: gpio1-cfg {
pins = "gpio1";
bias-pull-up;
};
}; };
...@@ -175,8 +175,8 @@ The IRQ portions of the GPIO block are implemented using an irqchip, using ...@@ -175,8 +175,8 @@ The IRQ portions of the GPIO block are implemented using an irqchip, using
the header <linux/irq.h>. So basically such a driver is utilizing two sub- the header <linux/irq.h>. So basically such a driver is utilizing two sub-
systems simultaneously: gpio and irq. systems simultaneously: gpio and irq.
RT_FULL: GPIO driver should not use spinlock_t or any sleepable APIs RT_FULL: a realtime compliant GPIO driver should not use spinlock_t or any
(like PM runtime) as part of its irq_chip implementation on -RT. sleepable APIs (like PM runtime) as part of its irq_chip implementation.
- spinlock_t should be replaced with raw_spinlock_t [1]. - spinlock_t should be replaced with raw_spinlock_t [1].
- If sleepable APIs have to be used, these can be done from the .irq_bus_lock() - If sleepable APIs have to be used, these can be done from the .irq_bus_lock()
and .irq_bus_unlock() callbacks, as these are the only slowpath callbacks and .irq_bus_unlock() callbacks, as these are the only slowpath callbacks
...@@ -185,33 +185,32 @@ RT_FULL: GPIO driver should not use spinlock_t or any sleepable APIs ...@@ -185,33 +185,32 @@ RT_FULL: GPIO driver should not use spinlock_t or any sleepable APIs
GPIO irqchips usually fall in one of two categories: GPIO irqchips usually fall in one of two categories:
* CHAINED GPIO irqchips: these are usually the type that is embedded on * CHAINED GPIO irqchips: these are usually the type that is embedded on
an SoC. This means that there is a fast IRQ handler for the GPIOs that an SoC. This means that there is a fast IRQ flow handler for the GPIOs that
gets called in a chain from the parent IRQ handler, most typically the gets called in a chain from the parent IRQ handler, most typically the
system interrupt controller. This means the GPIO irqchip is registered system interrupt controller. This means that the GPIO irqchip handler will
using irq_set_chained_handler() or the corresponding be called immediately from the parent irqchip, while holding the IRQs
gpiochip_set_chained_irqchip() helper function, and the GPIO irqchip disabled. The GPIO irqchip will then end up calling something like this
handler will be called immediately from the parent irqchip, while sequence in its interrupt handler:
holding the IRQs disabled. The GPIO irqchip will then end up calling
something like this sequence in its interrupt handler: static irqreturn_t foo_gpio_irq(int irq, void *data)
static irqreturn_t tc3589x_gpio_irq(int irq, void *data)
chained_irq_enter(...); chained_irq_enter(...);
generic_handle_irq(...); generic_handle_irq(...);
chained_irq_exit(...); chained_irq_exit(...);
Chained GPIO irqchips typically can NOT set the .can_sleep flag on Chained GPIO irqchips typically can NOT set the .can_sleep flag on
struct gpio_chip, as everything happens directly in the callbacks. struct gpio_chip, as everything happens directly in the callbacks: no
slow bus traffic like I2C can be used.
RT_FULL: Note, chained IRQ handlers will not be forced threaded on -RT. RT_FULL: Note, chained IRQ handlers will not be forced threaded on -RT.
As result, spinlock_t or any sleepable APIs (like PM runtime) can't be used As result, spinlock_t or any sleepable APIs (like PM runtime) can't be used
in chained IRQ handler. in chained IRQ handler.
if required (and if it can't be converted to the nested threaded GPIO irqchip) If required (and if it can't be converted to the nested threaded GPIO irqchip)
- chained IRQ handler can be converted to generic irq handler and this way a chained IRQ handler can be converted to generic irq handler and this way
it will be threaded IRQ handler on -RT and hard IRQ handler on non-RT it will be a threaded IRQ handler on -RT and a hard IRQ handler on non-RT
(for example, see [3]). (for example, see [3]).
Know W/A: The generic_handle_irq() is expected to be called with IRQ disabled, Know W/A: The generic_handle_irq() is expected to be called with IRQ disabled,
so IRQ core will complain if it will be called from IRQ handler which is so the IRQ core will complain if it is called from an IRQ handler which is
forced thread. The "fake?" raw lock can be used to W/A this problem: forced to a thread. The "fake?" raw lock can be used to W/A this problem:
raw_spinlock_t wa_lock; raw_spinlock_t wa_lock;
static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank) static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
...@@ -243,7 +242,7 @@ GPIO irqchips usually fall in one of two categories: ...@@ -243,7 +242,7 @@ GPIO irqchips usually fall in one of two categories:
by the driver. The hallmark of this driver is to call something like by the driver. The hallmark of this driver is to call something like
this in its interrupt handler: this in its interrupt handler:
static irqreturn_t tc3589x_gpio_irq(int irq, void *data) static irqreturn_t foo_gpio_irq(int irq, void *data)
... ...
handle_nested_irq(irq); handle_nested_irq(irq);
...@@ -256,23 +255,31 @@ associated irqdomain and resource allocation callbacks, the gpiolib has ...@@ -256,23 +255,31 @@ associated irqdomain and resource allocation callbacks, the gpiolib has
some helpers that can be enabled by selecting the GPIOLIB_IRQCHIP Kconfig some helpers that can be enabled by selecting the GPIOLIB_IRQCHIP Kconfig
symbol: symbol:
* gpiochip_irqchip_add(): adds an irqchip to a gpiochip. It will pass * gpiochip_irqchip_add(): adds a chained irqchip to a gpiochip. It will pass
the struct gpio_chip* for the chip to all IRQ callbacks, so the callbacks the struct gpio_chip* for the chip to all IRQ callbacks, so the callbacks
need to embed the gpio_chip in its state container and obtain a pointer need to embed the gpio_chip in its state container and obtain a pointer
to the container using container_of(). to the container using container_of().
(See Documentation/driver-model/design-patterns.txt) (See Documentation/driver-model/design-patterns.txt)
If there is a need to exclude certain GPIOs from the IRQ domain, one can * gpiochip_irqchip_add_nested(): adds a nested irqchip to a gpiochip.
set .irq_need_valid_mask of the gpiochip before gpiochip_add_data() is Apart from that it works exactly like the chained irqchip.
called. This allocates .irq_valid_mask with as many bits set as there are
GPIOs in the chip. Drivers can exclude GPIOs by clearing bits from this
mask. The mask must be filled in before gpiochip_irqchip_add() is called.
* gpiochip_set_chained_irqchip(): sets up a chained irq handler for a * gpiochip_set_chained_irqchip(): sets up a chained irq handler for a
gpio_chip from a parent IRQ and passes the struct gpio_chip* as handler gpio_chip from a parent IRQ and passes the struct gpio_chip* as handler
data. (Notice handler data, since the irqchip data is likely used by the data. (Notice handler data, since the irqchip data is likely used by the
parent irqchip!) This is for the chained type of chip. This is also used parent irqchip!).
to set up a nested irqchip if NULL is passed as handler.
* gpiochip_set_nested_irqchip(): sets up a nested irq handler for a
gpio_chip from a parent IRQ. As the parent IRQ has usually been
explicitly requested by the driver, this does very little more than
mark all the child IRQs as having the other IRQ as parent.
If there is a need to exclude certain GPIOs from the IRQ domain, you can
set .irq_need_valid_mask of the gpiochip before gpiochip_add_data() is
called. This allocates an .irq_valid_mask with as many bits set as there
are GPIOs in the chip. Drivers can exclude GPIOs by clearing bits from this
mask. The mask must be filled in before gpiochip_irqchip_add() or
gpiochip_irqchip_add_nested() is called.
To use the helpers please keep the following in mind: To use the helpers please keep the following in mind:
...@@ -323,6 +330,9 @@ When implementing an irqchip inside a GPIO driver, these two functions should ...@@ -323,6 +330,9 @@ When implementing an irqchip inside a GPIO driver, these two functions should
typically be called in the .startup() and .shutdown() callbacks from the typically be called in the .startup() and .shutdown() callbacks from the
irqchip. irqchip.
When using the gpiolib irqchip helpers, these callback are automatically
assigned.
Real-Time compliance for GPIO IRQ chips Real-Time compliance for GPIO IRQ chips
--------------------------------------- ---------------------------------------
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
#include <linux/amba/bus.h> #include <linux/amba/bus.h>
#include <linux/amba/clcd.h> #include <linux/amba/clcd.h>
#include <linux/amba/mmci.h> #include <linux/amba/mmci.h>
#include <linux/amba/pl061.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/platform_data/clk-integrator.h> #include <linux/platform_data/clk-integrator.h>
#include <linux/slab.h> #include <linux/slab.h>
......
...@@ -167,7 +167,7 @@ config GPIO_DWAPB ...@@ -167,7 +167,7 @@ config GPIO_DWAPB
config GPIO_EM config GPIO_EM
tristate "Emma Mobile GPIO" tristate "Emma Mobile GPIO"
depends on ARM && OF_GPIO depends on (ARCH_EMEV2 || COMPILE_TEST) && OF_GPIO
help help
Say yes here to support GPIO on Renesas Emma Mobile SoCs. Say yes here to support GPIO on Renesas Emma Mobile SoCs.
...@@ -451,7 +451,7 @@ config GPIO_VR41XX ...@@ -451,7 +451,7 @@ config GPIO_VR41XX
config GPIO_VX855 config GPIO_VX855
tristate "VIA VX855/VX875 GPIO" tristate "VIA VX855/VX875 GPIO"
depends on PCI depends on (X86 || COMPILE_TEST) && PCI
select MFD_CORE select MFD_CORE
select MFD_VX855 select MFD_VX855
help help
...@@ -520,6 +520,7 @@ config GPIO_ZYNQ ...@@ -520,6 +520,7 @@ config GPIO_ZYNQ
config GPIO_ZX config GPIO_ZX
bool "ZTE ZX GPIO support" bool "ZTE ZX GPIO support"
depends on ARCH_ZX || COMPILE_TEST
select GPIOLIB_IRQCHIP select GPIOLIB_IRQCHIP
help help
Say yes here to support the GPIO device on ZTE ZX SoCs. Say yes here to support the GPIO device on ZTE ZX SoCs.
...@@ -603,7 +604,7 @@ config GPIO_IT87 ...@@ -603,7 +604,7 @@ config GPIO_IT87
config GPIO_SCH config GPIO_SCH
tristate "Intel SCH/TunnelCreek/Centerton/Quark X1000 GPIO" tristate "Intel SCH/TunnelCreek/Centerton/Quark X1000 GPIO"
depends on PCI depends on (X86 || COMPILE_TEST) && PCI
select MFD_CORE select MFD_CORE
select LPC_SCH select LPC_SCH
help help
...@@ -777,16 +778,13 @@ config GPIO_PCF857X ...@@ -777,16 +778,13 @@ config GPIO_PCF857X
platform-neutral GPIO calls. platform-neutral GPIO calls.
config GPIO_SX150X config GPIO_SX150X
bool "Semtech SX150x I2C GPIO expander" bool "Semtech SX150x I2C GPIO expander (deprecated)"
depends on I2C=y depends on PINCTRL && I2C=y
select GPIOLIB_IRQCHIP select PINCTRL_SX150X
default n default n
help help
Say yes here to provide support for Semtech SX150-series I2C Say yes here to provide support for Semtech SX150x-series I2C
GPIO expanders. Compatible models include: GPIO expanders. The GPIO driver was replaced by a Pinctrl version.
8 bits: sx1508q
16 bits: sx1509q
config GPIO_TPIC2810 config GPIO_TPIC2810
tristate "TPIC2810 8-Bit I2C GPO expander" tristate "TPIC2810 8-Bit I2C GPO expander"
...@@ -798,6 +796,7 @@ config GPIO_TPIC2810 ...@@ -798,6 +796,7 @@ config GPIO_TPIC2810
config GPIO_TS4900 config GPIO_TS4900
tristate "Technologic Systems FPGA I2C GPIO" tristate "Technologic Systems FPGA I2C GPIO"
depends on SOC_IMX6 || COMPILE_TEST
select REGMAP_I2C select REGMAP_I2C
help help
Say yes here to enabled the GPIO driver for Technologic's FPGA core. Say yes here to enabled the GPIO driver for Technologic's FPGA core.
...@@ -814,6 +813,14 @@ config GPIO_ADP5520 ...@@ -814,6 +813,14 @@ config GPIO_ADP5520
This option enables support for on-chip GPIO found This option enables support for on-chip GPIO found
on Analog Devices ADP5520 PMICs. on Analog Devices ADP5520 PMICs.
config GPIO_ALTERA_A10SR
tristate "Altera Arria10 System Resource GPIO"
depends on MFD_ALTERA_A10SR
help
Driver for Arria10 Development Kit GPIO expansion which
includes reads of pushbuttons and DIP switches as well
as writes to LEDs.
config GPIO_ARIZONA config GPIO_ARIZONA
tristate "Wolfson Microelectronics Arizona class devices" tristate "Wolfson Microelectronics Arizona class devices"
depends on MFD_ARIZONA depends on MFD_ARIZONA
...@@ -822,7 +829,7 @@ config GPIO_ARIZONA ...@@ -822,7 +829,7 @@ config GPIO_ARIZONA
config GPIO_CRYSTAL_COVE config GPIO_CRYSTAL_COVE
tristate "GPIO support for Crystal Cove PMIC" tristate "GPIO support for Crystal Cove PMIC"
depends on INTEL_SOC_PMIC depends on (X86 || COMPILE_TEST) && INTEL_SOC_PMIC
select GPIOLIB_IRQCHIP select GPIOLIB_IRQCHIP
help help
Support for GPIO pins on Crystal Cove PMIC. Support for GPIO pins on Crystal Cove PMIC.
...@@ -835,6 +842,7 @@ config GPIO_CRYSTAL_COVE ...@@ -835,6 +842,7 @@ config GPIO_CRYSTAL_COVE
config GPIO_CS5535 config GPIO_CS5535
tristate "AMD CS5535/CS5536 GPIO support" tristate "AMD CS5535/CS5536 GPIO support"
depends on X86 || MIPS || COMPILE_TEST
depends on MFD_CS5535 depends on MFD_CS5535
help help
The AMD CS5535 and CS5536 southbridges support 28 GPIO pins that The AMD CS5535 and CS5536 southbridges support 28 GPIO pins that
...@@ -927,7 +935,7 @@ config GPIO_MAX77620 ...@@ -927,7 +935,7 @@ config GPIO_MAX77620
config GPIO_MSIC config GPIO_MSIC
bool "Intel MSIC mixed signal gpio support" bool "Intel MSIC mixed signal gpio support"
depends on MFD_INTEL_MSIC depends on (X86 || COMPILE_TEST) && MFD_INTEL_MSIC
help help
Enable support for GPIO on intel MSIC controllers found in Enable support for GPIO on intel MSIC controllers found in
intel MID devices intel MID devices
...@@ -1028,7 +1036,7 @@ config GPIO_UCB1400 ...@@ -1028,7 +1036,7 @@ config GPIO_UCB1400
config GPIO_WHISKEY_COVE config GPIO_WHISKEY_COVE
tristate "GPIO support for Whiskey Cove PMIC" tristate "GPIO support for Whiskey Cove PMIC"
depends on INTEL_SOC_PMIC depends on (X86 || COMPILE_TEST) && INTEL_SOC_PMIC
select GPIOLIB_IRQCHIP select GPIOLIB_IRQCHIP
help help
Support for GPIO pins on Whiskey Cove PMIC. Support for GPIO pins on Whiskey Cove PMIC.
...@@ -1067,6 +1075,7 @@ menu "PCI GPIO expanders" ...@@ -1067,6 +1075,7 @@ menu "PCI GPIO expanders"
config GPIO_AMD8111 config GPIO_AMD8111
tristate "AMD 8111 GPIO driver" tristate "AMD 8111 GPIO driver"
depends on X86 || COMPILE_TEST
help help
The AMD 8111 south bridge contains 32 GPIO pins which can be used. The AMD 8111 south bridge contains 32 GPIO pins which can be used.
...@@ -1108,6 +1117,7 @@ config GPIO_MERRIFIELD ...@@ -1108,6 +1117,7 @@ config GPIO_MERRIFIELD
config GPIO_ML_IOH config GPIO_ML_IOH
tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support" tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support"
depends on X86 || COMPILE_TEST
select GENERIC_IRQ_CHIP select GENERIC_IRQ_CHIP
help help
ML7213 is companion chip for Intel Atom E6xx series. ML7213 is companion chip for Intel Atom E6xx series.
......
...@@ -5,6 +5,7 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG ...@@ -5,6 +5,7 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG
obj-$(CONFIG_GPIOLIB) += devres.o obj-$(CONFIG_GPIOLIB) += devres.o
obj-$(CONFIG_GPIOLIB) += gpiolib.o obj-$(CONFIG_GPIOLIB) += gpiolib.o
obj-$(CONFIG_GPIOLIB) += gpiolib-legacy.o obj-$(CONFIG_GPIOLIB) += gpiolib-legacy.o
obj-$(CONFIG_GPIOLIB) += gpiolib-devprop.o
obj-$(CONFIG_OF_GPIO) += gpiolib-of.o obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
obj-$(CONFIG_GPIO_SYSFS) += gpiolib-sysfs.o obj-$(CONFIG_GPIO_SYSFS) += gpiolib-sysfs.o
obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
...@@ -24,6 +25,7 @@ obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o ...@@ -24,6 +25,7 @@ obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o
obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o
obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o
obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o
obj-$(CONFIG_GPIO_ALTERA_A10SR) += gpio-altera-a10sr.o
obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o
obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o
obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
...@@ -102,7 +104,6 @@ obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.o ...@@ -102,7 +104,6 @@ obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.o
obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o
obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o
obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o
obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o
obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o
obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o
......
...@@ -468,7 +468,7 @@ static int adnp_irq_setup(struct adnp *adnp) ...@@ -468,7 +468,7 @@ static int adnp_irq_setup(struct adnp *adnp)
return err; return err;
} }
err = gpiochip_irqchip_add(chip, err = gpiochip_irqchip_add_nested(chip,
&adnp_irq_chip, &adnp_irq_chip,
0, 0,
handle_simple_irq, handle_simple_irq,
...@@ -479,6 +479,8 @@ static int adnp_irq_setup(struct adnp *adnp) ...@@ -479,6 +479,8 @@ static int adnp_irq_setup(struct adnp *adnp)
return err; return err;
} }
gpiochip_set_nested_irqchip(chip, &adnp_irq_chip, adnp->client->irq);
return 0; return 0;
} }
......
/*
* Copyright Intel Corporation (C) 2014-2016. All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* GPIO driver for Altera Arria10 MAX5 System Resource Chip
*
* Adapted from gpio-tps65910.c
*/
#include <linux/gpio/driver.h>
#include <linux/mfd/altera-a10sr.h>
#include <linux/module.h>
/**
* struct altr_a10sr_gpio - Altera Max5 GPIO device private data structure
* @gp: : instance of the gpio_chip
* @regmap: the regmap from the parent device.
*/
struct altr_a10sr_gpio {
struct gpio_chip gp;
struct regmap *regmap;
};
static int altr_a10sr_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct altr_a10sr_gpio *gpio = gpiochip_get_data(chip);
int ret, val;
ret = regmap_read(gpio->regmap, ALTR_A10SR_PBDSW_REG, &val);
if (ret < 0)
return ret;
return !!(val & BIT(offset - ALTR_A10SR_LED_VALID_SHIFT));
}
static void altr_a10sr_gpio_set(struct gpio_chip *chip, unsigned int offset,
int value)
{
struct altr_a10sr_gpio *gpio = gpiochip_get_data(chip);
regmap_update_bits(gpio->regmap, ALTR_A10SR_LED_REG,
BIT(ALTR_A10SR_LED_VALID_SHIFT + offset),
value ? BIT(ALTR_A10SR_LED_VALID_SHIFT + offset)
: 0);
}
static int altr_a10sr_gpio_direction_input(struct gpio_chip *gc,
unsigned int nr)
{
if (nr >= (ALTR_A10SR_IN_VALID_RANGE_LO - ALTR_A10SR_LED_VALID_SHIFT))
return 0;
return -EINVAL;
}
static int altr_a10sr_gpio_direction_output(struct gpio_chip *gc,
unsigned int nr, int value)
{
if (nr <= (ALTR_A10SR_OUT_VALID_RANGE_HI - ALTR_A10SR_LED_VALID_SHIFT))
return 0;
return -EINVAL;
}
static struct gpio_chip altr_a10sr_gc = {
.label = "altr_a10sr_gpio",
.owner = THIS_MODULE,
.get = altr_a10sr_gpio_get,
.set = altr_a10sr_gpio_set,
.direction_input = altr_a10sr_gpio_direction_input,
.direction_output = altr_a10sr_gpio_direction_output,
.can_sleep = true,
.ngpio = 12,
.base = -1,
};
static int altr_a10sr_gpio_probe(struct platform_device *pdev)
{
struct altr_a10sr_gpio *gpio;
int ret;
struct altr_a10sr *a10sr = dev_get_drvdata(pdev->dev.parent);
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
if (!gpio)
return -ENOMEM;
gpio->regmap = a10sr->regmap;
gpio->gp = altr_a10sr_gc;
gpio->gp.of_node = pdev->dev.of_node;
ret = devm_gpiochip_add_data(&pdev->dev, &gpio->gp, gpio);
if (ret < 0) {
dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
return ret;
}
platform_set_drvdata(pdev, gpio);
return 0;
}
static const struct of_device_id altr_a10sr_gpio_of_match[] = {
{ .compatible = "altr,a10sr-gpio" },
{ },
};
MODULE_DEVICE_TABLE(of, altr_a10sr_gpio_of_match);
static struct platform_driver altr_a10sr_gpio_driver = {
.probe = altr_a10sr_gpio_probe,
.driver = {
.name = "altr_a10sr_gpio",
.of_match_table = of_match_ptr(altr_a10sr_gpio_of_match),
},
};
module_platform_driver(altr_a10sr_gpio_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Thor Thayer <tthayer@opensource.altera.com>");
MODULE_DESCRIPTION("Altera Arria10 System Resource Chip GPIO");
...@@ -137,15 +137,10 @@ static int arizona_gpio_probe(struct platform_device *pdev) ...@@ -137,15 +137,10 @@ static int arizona_gpio_probe(struct platform_device *pdev)
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "Could not register gpiochip, %d\n", dev_err(&pdev->dev, "Could not register gpiochip, %d\n",
ret); ret);
goto err;
}
platform_set_drvdata(pdev, arizona_gpio);
return ret; return ret;
}
err: return 0;
return ret;
} }
static struct platform_driver arizona_gpio_driver = { static struct platform_driver arizona_gpio_driver = {
......
...@@ -64,13 +64,9 @@ static int axp20x_gpio_get(struct gpio_chip *chip, unsigned offset) ...@@ -64,13 +64,9 @@ static int axp20x_gpio_get(struct gpio_chip *chip, unsigned offset)
{ {
struct axp20x_gpio *gpio = gpiochip_get_data(chip); struct axp20x_gpio *gpio = gpiochip_get_data(chip);
unsigned int val; unsigned int val;
int reg, ret; int ret;
reg = axp20x_gpio_get_reg(offset);
if (reg < 0)
return reg;
ret = regmap_read(gpio->regmap, reg, &val); ret = regmap_read(gpio->regmap, AXP20X_GPIO20_SS, &val);
if (ret) if (ret)
return ret; return ret;
......
...@@ -351,7 +351,7 @@ static int crystalcove_gpio_probe(struct platform_device *pdev) ...@@ -351,7 +351,7 @@ static int crystalcove_gpio_probe(struct platform_device *pdev)
return retval; return retval;
} }
gpiochip_irqchip_add(&cg->chip, &crystalcove_irqchip, 0, gpiochip_irqchip_add_nested(&cg->chip, &crystalcove_irqchip, 0,
handle_simple_irq, IRQ_TYPE_NONE); handle_simple_irq, IRQ_TYPE_NONE);
retval = request_threaded_irq(irq, NULL, crystalcove_gpio_irq_handler, retval = request_threaded_irq(irq, NULL, crystalcove_gpio_irq_handler,
...@@ -362,6 +362,8 @@ static int crystalcove_gpio_probe(struct platform_device *pdev) ...@@ -362,6 +362,8 @@ static int crystalcove_gpio_probe(struct platform_device *pdev)
return retval; return retval;
} }
gpiochip_set_nested_irqchip(&cg->chip, &crystalcove_irqchip, irq);
return 0; return 0;
} }
......
...@@ -40,6 +40,7 @@ struct davinci_gpio_regs { ...@@ -40,6 +40,7 @@ struct davinci_gpio_regs {
typedef struct irq_chip *(*gpio_get_irq_chip_cb_t)(unsigned int irq); typedef struct irq_chip *(*gpio_get_irq_chip_cb_t)(unsigned int irq);
#define BINTEN 0x8 /* GPIO Interrupt Per-Bank Enable Register */ #define BINTEN 0x8 /* GPIO Interrupt Per-Bank Enable Register */
#define MAX_LABEL_SIZE 20
static void __iomem *gpio_base; static void __iomem *gpio_base;
...@@ -201,6 +202,7 @@ static int davinci_gpio_probe(struct platform_device *pdev) ...@@ -201,6 +202,7 @@ static int davinci_gpio_probe(struct platform_device *pdev)
struct davinci_gpio_regs __iomem *regs; struct davinci_gpio_regs __iomem *regs;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct resource *res; struct resource *res;
char label[MAX_LABEL_SIZE];
pdata = davinci_gpio_get_pdata(pdev); pdata = davinci_gpio_get_pdata(pdev);
if (!pdata) { if (!pdata) {
...@@ -237,7 +239,10 @@ static int davinci_gpio_probe(struct platform_device *pdev) ...@@ -237,7 +239,10 @@ static int davinci_gpio_probe(struct platform_device *pdev)
return PTR_ERR(gpio_base); return PTR_ERR(gpio_base);
for (i = 0, base = 0; base < ngpio; i++, base += 32) { for (i = 0, base = 0; base < ngpio; i++, base += 32) {
chips[i].chip.label = "DaVinci"; snprintf(label, MAX_LABEL_SIZE, "davinci_gpio.%d", i);
chips[i].chip.label = devm_kstrdup(dev, label, GFP_KERNEL);
if (!chips[i].chip.label)
return -ENOMEM;
chips[i].chip.direction_input = davinci_direction_in; chips[i].chip.direction_input = davinci_direction_in;
chips[i].chip.get = davinci_gpio_get; chips[i].chip.get = davinci_gpio_get;
......
...@@ -467,7 +467,6 @@ static int dln2_gpio_probe(struct platform_device *pdev) ...@@ -467,7 +467,6 @@ static int dln2_gpio_probe(struct platform_device *pdev)
dln2->gpio.base = -1; dln2->gpio.base = -1;
dln2->gpio.ngpio = pins; dln2->gpio.ngpio = pins;
dln2->gpio.can_sleep = true; dln2->gpio.can_sleep = true;
dln2->gpio.irq_not_threaded = true;
dln2->gpio.set = dln2_gpio_set; dln2->gpio.set = dln2_gpio_set;
dln2->gpio.get = dln2_gpio_get; dln2->gpio.get = dln2_gpio_get;
dln2->gpio.request = dln2_gpio_request; dln2->gpio.request = dln2_gpio_request;
......
...@@ -471,9 +471,4 @@ static struct platform_driver etraxfs_gpio_driver = { ...@@ -471,9 +471,4 @@ static struct platform_driver etraxfs_gpio_driver = {
.probe = etraxfs_gpio_probe, .probe = etraxfs_gpio_probe,
}; };
static int __init etraxfs_gpio_init(void) builtin_platform_driver(etraxfs_gpio_driver);
{
return platform_driver_register(&etraxfs_gpio_driver);
}
device_initcall(etraxfs_gpio_init);
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#include <linux/platform_data/gpio-htc-egpio.h> #include <linux/platform_data/gpio-htc-egpio.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/init.h>
struct egpio_chip { struct egpio_chip {
int reg_start; int reg_start;
...@@ -160,10 +160,14 @@ static int egpio_get(struct gpio_chip *chip, unsigned offset) ...@@ -160,10 +160,14 @@ static int egpio_get(struct gpio_chip *chip, unsigned offset)
bit = egpio_bit(ei, offset); bit = egpio_bit(ei, offset);
reg = egpio->reg_start + egpio_pos(ei, offset); reg = egpio->reg_start + egpio_pos(ei, offset);
if (test_bit(offset, &egpio->is_out)) {
return !!(egpio->cached_values & (1 << offset));
} else {
value = egpio_readw(ei, reg); value = egpio_readw(ei, reg);
pr_debug("readw(%p + %x) = %x\n", pr_debug("readw(%p + %x) = %x\n",
ei->base_addr, reg << ei->bus_shift, value); ei->base_addr, reg << ei->bus_shift, value);
return !!(value & bit); return !!(value & bit);
}
} }
static int egpio_direction_input(struct gpio_chip *chip, unsigned offset) static int egpio_direction_input(struct gpio_chip *chip, unsigned offset)
...@@ -225,6 +229,15 @@ static int egpio_direction_output(struct gpio_chip *chip, ...@@ -225,6 +229,15 @@ static int egpio_direction_output(struct gpio_chip *chip,
} }
} }
static int egpio_get_direction(struct gpio_chip *chip, unsigned offset)
{
struct egpio_chip *egpio;
egpio = gpiochip_get_data(chip);
return !test_bit(offset, &egpio->is_out);
}
static void egpio_write_cache(struct egpio_info *ei) static void egpio_write_cache(struct egpio_info *ei)
{ {
int i; int i;
...@@ -327,6 +340,7 @@ static int __init egpio_probe(struct platform_device *pdev) ...@@ -327,6 +340,7 @@ static int __init egpio_probe(struct platform_device *pdev)
chip->set = egpio_set; chip->set = egpio_set;
chip->direction_input = egpio_direction_input; chip->direction_input = egpio_direction_input;
chip->direction_output = egpio_direction_output; chip->direction_output = egpio_direction_output;
chip->get_direction = egpio_get_direction;
chip->base = pdata->chip[i].gpio_base; chip->base = pdata->chip[i].gpio_base;
chip->ngpio = pdata->chip[i].num_gpios; chip->ngpio = pdata->chip[i].num_gpios;
...@@ -367,24 +381,6 @@ static int __init egpio_probe(struct platform_device *pdev) ...@@ -367,24 +381,6 @@ static int __init egpio_probe(struct platform_device *pdev)
return ret; return ret;
} }
static int __exit egpio_remove(struct platform_device *pdev)
{
struct egpio_info *ei = platform_get_drvdata(pdev);
unsigned int irq, irq_end;
if (ei->chained_irq) {
irq_end = ei->irq_start + ei->nirqs;
for (irq = ei->irq_start; irq < irq_end; irq++) {
irq_set_chip_and_handler(irq, NULL, NULL);
irq_set_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE);
}
irq_set_chained_handler(ei->chained_irq, NULL);
device_init_wakeup(&pdev->dev, 0);
}
return 0;
}
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int egpio_suspend(struct platform_device *pdev, pm_message_t state) static int egpio_suspend(struct platform_device *pdev, pm_message_t state)
{ {
...@@ -416,8 +412,8 @@ static int egpio_resume(struct platform_device *pdev) ...@@ -416,8 +412,8 @@ static int egpio_resume(struct platform_device *pdev)
static struct platform_driver egpio_driver = { static struct platform_driver egpio_driver = {
.driver = { .driver = {
.name = "htc-egpio", .name = "htc-egpio",
.suppress_bind_attrs = true,
}, },
.remove = __exit_p(egpio_remove),
.suspend = egpio_suspend, .suspend = egpio_suspend,
.resume = egpio_resume, .resume = egpio_resume,
}; };
...@@ -426,15 +422,5 @@ static int __init egpio_init(void) ...@@ -426,15 +422,5 @@ static int __init egpio_init(void)
{ {
return platform_driver_probe(&egpio_driver, egpio_probe); return platform_driver_probe(&egpio_driver, egpio_probe);
} }
static void __exit egpio_exit(void)
{
platform_driver_unregister(&egpio_driver);
}
/* start early for dependencies */ /* start early for dependencies */
subsys_initcall(egpio_init); subsys_initcall(egpio_init);
module_exit(egpio_exit)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kevin O'Connor <kevin@koconnor.net>");
...@@ -421,9 +421,4 @@ static struct pci_driver intel_gpio_driver = { ...@@ -421,9 +421,4 @@ static struct pci_driver intel_gpio_driver = {
}, },
}; };
static int __init intel_gpio_init(void) builtin_pci_driver(intel_gpio_driver);
{
return pci_register_driver(&intel_gpio_driver);
}
device_initcall(intel_gpio_init);
...@@ -520,7 +520,7 @@ static int max732x_irq_setup(struct max732x_chip *chip, ...@@ -520,7 +520,7 @@ static int max732x_irq_setup(struct max732x_chip *chip,
client->irq); client->irq);
return ret; return ret;
} }
ret = gpiochip_irqchip_add(&chip->gpio_chip, ret = gpiochip_irqchip_add_nested(&chip->gpio_chip,
&max732x_irq_chip, &max732x_irq_chip,
irq_base, irq_base,
handle_simple_irq, handle_simple_irq,
...@@ -530,10 +530,9 @@ static int max732x_irq_setup(struct max732x_chip *chip, ...@@ -530,10 +530,9 @@ static int max732x_irq_setup(struct max732x_chip *chip,
"could not connect irqchip to gpiochip\n"); "could not connect irqchip to gpiochip\n");
return ret; return ret;
} }
gpiochip_set_chained_irqchip(&chip->gpio_chip, gpiochip_set_nested_irqchip(&chip->gpio_chip,
&max732x_irq_chip, &max732x_irq_chip,
client->irq, client->irq);
NULL);
} }
return 0; return 0;
......
...@@ -21,9 +21,6 @@ struct max77620_gpio { ...@@ -21,9 +21,6 @@ struct max77620_gpio {
struct gpio_chip gpio_chip; struct gpio_chip gpio_chip;
struct regmap *rmap; struct regmap *rmap;
struct device *dev; struct device *dev;
int gpio_irq;
int irq_base;
int gpio_base;
}; };
static const struct regmap_irq max77620_gpio_irqs[] = { static const struct regmap_irq max77620_gpio_irqs[] = {
...@@ -254,7 +251,6 @@ static int max77620_gpio_probe(struct platform_device *pdev) ...@@ -254,7 +251,6 @@ static int max77620_gpio_probe(struct platform_device *pdev)
mgpio->rmap = chip->rmap; mgpio->rmap = chip->rmap;
mgpio->dev = &pdev->dev; mgpio->dev = &pdev->dev;
mgpio->gpio_irq = gpio_irq;
mgpio->gpio_chip.label = pdev->name; mgpio->gpio_chip.label = pdev->name;
mgpio->gpio_chip.parent = &pdev->dev; mgpio->gpio_chip.parent = &pdev->dev;
...@@ -268,7 +264,6 @@ static int max77620_gpio_probe(struct platform_device *pdev) ...@@ -268,7 +264,6 @@ static int max77620_gpio_probe(struct platform_device *pdev)
mgpio->gpio_chip.ngpio = MAX77620_GPIO_NR; mgpio->gpio_chip.ngpio = MAX77620_GPIO_NR;
mgpio->gpio_chip.can_sleep = 1; mgpio->gpio_chip.can_sleep = 1;
mgpio->gpio_chip.base = -1; mgpio->gpio_chip.base = -1;
mgpio->irq_base = -1;
#ifdef CONFIG_OF_GPIO #ifdef CONFIG_OF_GPIO
mgpio->gpio_chip.of_node = pdev->dev.parent->of_node; mgpio->gpio_chip.of_node = pdev->dev.parent->of_node;
#endif #endif
...@@ -281,9 +276,8 @@ static int max77620_gpio_probe(struct platform_device *pdev) ...@@ -281,9 +276,8 @@ static int max77620_gpio_probe(struct platform_device *pdev)
return ret; return ret;
} }
mgpio->gpio_base = mgpio->gpio_chip.base; ret = devm_regmap_add_irq_chip(&pdev->dev, chip->rmap, gpio_irq,
ret = devm_regmap_add_irq_chip(&pdev->dev, chip->rmap, mgpio->gpio_irq, IRQF_ONESHOT, -1,
IRQF_ONESHOT, mgpio->irq_base,
&max77620_gpio_irq_chip, &max77620_gpio_irq_chip,
&chip->gpio_irq_data); &chip->gpio_irq_data);
if (ret < 0) { if (ret < 0) {
...@@ -296,6 +290,7 @@ static int max77620_gpio_probe(struct platform_device *pdev) ...@@ -296,6 +290,7 @@ static int max77620_gpio_probe(struct platform_device *pdev)
static const struct platform_device_id max77620_gpio_devtype[] = { static const struct platform_device_id max77620_gpio_devtype[] = {
{ .name = "max77620-gpio", }, { .name = "max77620-gpio", },
{ .name = "max20024-gpio", },
{}, {},
}; };
MODULE_DEVICE_TABLE(platform, max77620_gpio_devtype); MODULE_DEVICE_TABLE(platform, max77620_gpio_devtype);
......
...@@ -217,8 +217,4 @@ static struct platform_driver mb86s70_gpio_driver = { ...@@ -217,8 +217,4 @@ static struct platform_driver mb86s70_gpio_driver = {
.remove = mb86s70_gpio_remove, .remove = mb86s70_gpio_remove,
}; };
static int __init mb86s70_gpio_init(void) builtin_platform_driver(mb86s70_gpio_driver);
{
return platform_driver_register(&mb86s70_gpio_driver);
}
device_initcall(mb86s70_gpio_init);
...@@ -473,7 +473,7 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp) ...@@ -473,7 +473,7 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp)
return err; return err;
} }
err = gpiochip_irqchip_add(chip, err = gpiochip_irqchip_add_nested(chip,
&mcp23s08_irq_chip, &mcp23s08_irq_chip,
0, 0,
handle_simple_irq, handle_simple_irq,
...@@ -484,10 +484,9 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp) ...@@ -484,10 +484,9 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp)
return err; return err;
} }
gpiochip_set_chained_irqchip(chip, gpiochip_set_nested_irqchip(chip,
&mcp23s08_irq_chip, &mcp23s08_irq_chip,
mcp->irq, mcp->irq);
NULL);
return 0; return 0;
} }
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/gpio.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -161,6 +162,34 @@ static int mrfld_gpio_direction_output(struct gpio_chip *chip, ...@@ -161,6 +162,34 @@ static int mrfld_gpio_direction_output(struct gpio_chip *chip,
return 0; return 0;
} }
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;
}
static int mrfld_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset,
unsigned int debounce)
{
struct mrfld_gpio *priv = gpiochip_get_data(chip);
void __iomem *gfbr = gpio_reg(chip, offset, GFBR);
unsigned long flags;
u32 value;
raw_spin_lock_irqsave(&priv->lock, flags);
if (debounce)
value = readl(gfbr) & ~BIT(offset % 32);
else
value = readl(gfbr) | BIT(offset % 32);
writel(value, gfbr);
raw_spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
static void mrfld_irq_ack(struct irq_data *d) static void mrfld_irq_ack(struct irq_data *d)
{ {
struct mrfld_gpio *priv = irq_data_get_irq_chip_data(d); struct mrfld_gpio *priv = irq_data_get_irq_chip_data(d);
...@@ -384,6 +413,8 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id ...@@ -384,6 +413,8 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id
priv->chip.direction_output = mrfld_gpio_direction_output; priv->chip.direction_output = mrfld_gpio_direction_output;
priv->chip.get = mrfld_gpio_get; priv->chip.get = mrfld_gpio_get;
priv->chip.set = mrfld_gpio_set; priv->chip.set = mrfld_gpio_set;
priv->chip.get_direction = mrfld_gpio_get_direction;
priv->chip.set_debounce = mrfld_gpio_set_debounce;
priv->chip.base = gpio_base; priv->chip.base = gpio_base;
priv->chip.ngpio = MRFLD_NGPIO; priv->chip.ngpio = MRFLD_NGPIO;
priv->chip.can_sleep = false; priv->chip.can_sleep = false;
...@@ -411,7 +442,7 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id ...@@ -411,7 +442,7 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id
} }
retval = gpiochip_irqchip_add(&priv->chip, &mrfld_irqchip, irq_base, retval = gpiochip_irqchip_add(&priv->chip, &mrfld_irqchip, irq_base,
handle_simple_irq, IRQ_TYPE_NONE); handle_bad_irq, IRQ_TYPE_NONE);
if (retval) { if (retval) {
dev_err(&pdev->dev, "could not connect irqchip to gpiochip\n"); dev_err(&pdev->dev, "could not connect irqchip to gpiochip\n");
return retval; return retval;
......
...@@ -87,10 +87,15 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type) ...@@ -87,10 +87,15 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
u32 val; u32 val;
u32 pin_mask = 1 << d->hwirq; u32 pin_mask = 1 << d->hwirq;
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct irq_chip_type *ct = irq_data_get_chip_type(d);
struct mxs_gpio_port *port = gc->private; struct mxs_gpio_port *port = gc->private;
void __iomem *pin_addr; void __iomem *pin_addr;
int edge; int edge;
if (!(ct->type & type))
if (irq_setup_alt_chip(d, type))
return -EINVAL;
port->both_edges &= ~pin_mask; port->both_edges &= ~pin_mask;
switch (type) { switch (type) {
case IRQ_TYPE_EDGE_BOTH: case IRQ_TYPE_EDGE_BOTH:
...@@ -119,10 +124,13 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type) ...@@ -119,10 +124,13 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
/* set level or edge */ /* set level or edge */
pin_addr = port->base + PINCTRL_IRQLEV(port); pin_addr = port->base + PINCTRL_IRQLEV(port);
if (edge & GPIO_INT_LEV_MASK) if (edge & GPIO_INT_LEV_MASK) {
writel(pin_mask, pin_addr + MXS_SET); writel(pin_mask, pin_addr + MXS_SET);
else writel(pin_mask, port->base + PINCTRL_IRQEN(port) + MXS_SET);
} else {
writel(pin_mask, pin_addr + MXS_CLR); writel(pin_mask, pin_addr + MXS_CLR);
writel(pin_mask, port->base + PINCTRL_PIN2IRQ(port) + MXS_SET);
}
/* set polarity */ /* set polarity */
pin_addr = port->base + PINCTRL_IRQPOL(port); pin_addr = port->base + PINCTRL_IRQPOL(port);
...@@ -202,21 +210,37 @@ static int __init mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base) ...@@ -202,21 +210,37 @@ static int __init mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base)
struct irq_chip_generic *gc; struct irq_chip_generic *gc;
struct irq_chip_type *ct; struct irq_chip_type *ct;
gc = irq_alloc_generic_chip("gpio-mxs", 1, irq_base, gc = irq_alloc_generic_chip("gpio-mxs", 2, irq_base,
port->base, handle_level_irq); port->base, handle_level_irq);
if (!gc) if (!gc)
return -ENOMEM; return -ENOMEM;
gc->private = port; gc->private = port;
ct = gc->chip_types; ct = &gc->chip_types[0];
ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW;
ct->chip.irq_ack = irq_gc_ack_set_bit; ct->chip.irq_ack = irq_gc_ack_set_bit;
ct->chip.irq_mask = irq_gc_mask_clr_bit; ct->chip.irq_mask = irq_gc_mask_disable_reg;
ct->chip.irq_unmask = irq_gc_mask_set_bit; ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
ct->chip.irq_set_type = mxs_gpio_set_irq_type; ct->chip.irq_set_type = mxs_gpio_set_irq_type;
ct->chip.irq_set_wake = mxs_gpio_set_wake_irq; ct->chip.irq_set_wake = mxs_gpio_set_wake_irq;
ct->chip.flags = IRQCHIP_SET_TYPE_MASKED;
ct->regs.ack = PINCTRL_IRQSTAT(port) + MXS_CLR; ct->regs.ack = PINCTRL_IRQSTAT(port) + MXS_CLR;
ct->regs.mask = PINCTRL_IRQEN(port); ct->regs.enable = PINCTRL_PIN2IRQ(port) + MXS_SET;
ct->regs.disable = PINCTRL_PIN2IRQ(port) + MXS_CLR;
ct = &gc->chip_types[1];
ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
ct->chip.irq_ack = irq_gc_ack_set_bit;
ct->chip.irq_mask = irq_gc_mask_disable_reg;
ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
ct->chip.irq_set_type = mxs_gpio_set_irq_type;
ct->chip.irq_set_wake = mxs_gpio_set_wake_irq;
ct->chip.flags = IRQCHIP_SET_TYPE_MASKED;
ct->regs.ack = PINCTRL_IRQSTAT(port) + MXS_CLR;
ct->regs.enable = PINCTRL_IRQEN(port) + MXS_SET;
ct->regs.disable = PINCTRL_IRQEN(port) + MXS_CLR;
ct->handler = handle_level_irq;
irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_NESTED_LOCK, irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_NESTED_LOCK,
IRQ_NOREQUEST, 0); IRQ_NOREQUEST, 0);
...@@ -297,11 +321,8 @@ static int mxs_gpio_probe(struct platform_device *pdev) ...@@ -297,11 +321,8 @@ static int mxs_gpio_probe(struct platform_device *pdev)
} }
port->base = base; port->base = base;
/* /* initially disable the interrupts */
* select the pin interrupt functionality but initially writel(0, port->base + PINCTRL_PIN2IRQ(port));
* disable the interrupts
*/
writel(~0U, port->base + PINCTRL_PIN2IRQ(port));
writel(0, port->base + PINCTRL_IRQEN(port)); writel(0, port->base + PINCTRL_IRQEN(port));
/* clear address has to be used to clear IRQSTAT bits */ /* clear address has to be used to clear IRQSTAT bits */
......
...@@ -74,6 +74,7 @@ static const struct i2c_device_id pca953x_id[] = { ...@@ -74,6 +74,7 @@ static const struct i2c_device_id pca953x_id[] = {
{ "max7312", 16 | PCA953X_TYPE | PCA_INT, }, { "max7312", 16 | PCA953X_TYPE | PCA_INT, },
{ "max7313", 16 | PCA953X_TYPE | PCA_INT, }, { "max7313", 16 | PCA953X_TYPE | PCA_INT, },
{ "max7315", 8 | PCA953X_TYPE | PCA_INT, }, { "max7315", 8 | PCA953X_TYPE | PCA_INT, },
{ "max7318", 16 | PCA953X_TYPE | PCA_INT, },
{ "pca6107", 8 | PCA953X_TYPE | PCA_INT, }, { "pca6107", 8 | PCA953X_TYPE | PCA_INT, },
{ "tca6408", 8 | PCA953X_TYPE | PCA_INT, }, { "tca6408", 8 | PCA953X_TYPE | PCA_INT, },
{ "tca6416", 16 | PCA953X_TYPE | PCA_INT, }, { "tca6416", 16 | PCA953X_TYPE | PCA_INT, },
...@@ -635,7 +636,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, ...@@ -635,7 +636,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
return ret; return ret;
} }
ret = gpiochip_irqchip_add(&chip->gpio_chip, ret = gpiochip_irqchip_add_nested(&chip->gpio_chip,
&pca953x_irq_chip, &pca953x_irq_chip,
irq_base, irq_base,
handle_simple_irq, handle_simple_irq,
...@@ -646,9 +647,9 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, ...@@ -646,9 +647,9 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
return ret; return ret;
} }
gpiochip_set_chained_irqchip(&chip->gpio_chip, gpiochip_set_nested_irqchip(&chip->gpio_chip,
&pca953x_irq_chip, &pca953x_irq_chip,
client->irq, NULL); client->irq);
} }
return 0; return 0;
...@@ -907,6 +908,7 @@ static const struct of_device_id pca953x_dt_ids[] = { ...@@ -907,6 +908,7 @@ static const struct of_device_id pca953x_dt_ids[] = {
{ .compatible = "maxim,max7312", .data = OF_953X(16, PCA_INT), }, { .compatible = "maxim,max7312", .data = OF_953X(16, PCA_INT), },
{ .compatible = "maxim,max7313", .data = OF_953X(16, PCA_INT), }, { .compatible = "maxim,max7313", .data = OF_953X(16, PCA_INT), },
{ .compatible = "maxim,max7315", .data = OF_953X( 8, PCA_INT), }, { .compatible = "maxim,max7315", .data = OF_953X( 8, PCA_INT), },
{ .compatible = "maxim,max7318", .data = OF_953X(16, PCA_INT), },
{ .compatible = "ti,pca6107", .data = OF_953X( 8, PCA_INT), }, { .compatible = "ti,pca6107", .data = OF_953X( 8, PCA_INT), },
{ .compatible = "ti,pca9536", .data = OF_953X( 4, 0), }, { .compatible = "ti,pca9536", .data = OF_953X( 4, 0), },
......
...@@ -378,7 +378,8 @@ static int pcf857x_probe(struct i2c_client *client, ...@@ -378,7 +378,8 @@ static int pcf857x_probe(struct i2c_client *client,
/* Enable irqchip if we have an interrupt */ /* Enable irqchip if we have an interrupt */
if (client->irq) { if (client->irq) {
status = gpiochip_irqchip_add(&gpio->chip, &pcf857x_irq_chip, status = gpiochip_irqchip_add_nested(&gpio->chip,
&pcf857x_irq_chip,
0, handle_level_irq, 0, handle_level_irq,
IRQ_TYPE_NONE); IRQ_TYPE_NONE);
if (status) { if (status) {
...@@ -393,8 +394,8 @@ static int pcf857x_probe(struct i2c_client *client, ...@@ -393,8 +394,8 @@ static int pcf857x_probe(struct i2c_client *client,
if (status) if (status)
goto fail; goto fail;
gpiochip_set_chained_irqchip(&gpio->chip, &pcf857x_irq_chip, gpiochip_set_nested_irqchip(&gpio->chip, &pcf857x_irq_chip,
client->irq, NULL); client->irq);
gpio->irq_parent = client->irq; gpio->irq_parent = client->irq;
} }
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/amba/bus.h> #include <linux/amba/bus.h>
#include <linux/amba/pl061.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
#include <linux/pm.h> #include <linux/pm.h>
...@@ -50,11 +49,12 @@ struct pl061_context_save_regs { ...@@ -50,11 +49,12 @@ struct pl061_context_save_regs {
}; };
#endif #endif
struct pl061_gpio { struct pl061 {
spinlock_t lock; spinlock_t lock;
void __iomem *base; void __iomem *base;
struct gpio_chip gc; struct gpio_chip gc;
int parent_irq;
#ifdef CONFIG_PM #ifdef CONFIG_PM
struct pl061_context_save_regs csave_regs; struct pl061_context_save_regs csave_regs;
...@@ -63,22 +63,22 @@ struct pl061_gpio { ...@@ -63,22 +63,22 @@ struct pl061_gpio {
static int pl061_get_direction(struct gpio_chip *gc, unsigned offset) static int pl061_get_direction(struct gpio_chip *gc, unsigned offset)
{ {
struct pl061_gpio *chip = gpiochip_get_data(gc); struct pl061 *pl061 = gpiochip_get_data(gc);
return !(readb(chip->base + GPIODIR) & BIT(offset)); return !(readb(pl061->base + GPIODIR) & BIT(offset));
} }
static int pl061_direction_input(struct gpio_chip *gc, unsigned offset) static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
{ {
struct pl061_gpio *chip = gpiochip_get_data(gc); struct pl061 *pl061 = gpiochip_get_data(gc);
unsigned long flags; unsigned long flags;
unsigned char gpiodir; unsigned char gpiodir;
spin_lock_irqsave(&chip->lock, flags); spin_lock_irqsave(&pl061->lock, flags);
gpiodir = readb(chip->base + GPIODIR); gpiodir = readb(pl061->base + GPIODIR);
gpiodir &= ~(BIT(offset)); gpiodir &= ~(BIT(offset));
writeb(gpiodir, chip->base + GPIODIR); writeb(gpiodir, pl061->base + GPIODIR);
spin_unlock_irqrestore(&chip->lock, flags); spin_unlock_irqrestore(&pl061->lock, flags);
return 0; return 0;
} }
...@@ -86,44 +86,44 @@ static int pl061_direction_input(struct gpio_chip *gc, unsigned offset) ...@@ -86,44 +86,44 @@ static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
static int pl061_direction_output(struct gpio_chip *gc, unsigned offset, static int pl061_direction_output(struct gpio_chip *gc, unsigned offset,
int value) int value)
{ {
struct pl061_gpio *chip = gpiochip_get_data(gc); struct pl061 *pl061 = gpiochip_get_data(gc);
unsigned long flags; unsigned long flags;
unsigned char gpiodir; unsigned char gpiodir;
spin_lock_irqsave(&chip->lock, flags); spin_lock_irqsave(&pl061->lock, flags);
writeb(!!value << offset, chip->base + (BIT(offset + 2))); writeb(!!value << offset, pl061->base + (BIT(offset + 2)));
gpiodir = readb(chip->base + GPIODIR); gpiodir = readb(pl061->base + GPIODIR);
gpiodir |= BIT(offset); gpiodir |= BIT(offset);
writeb(gpiodir, chip->base + GPIODIR); writeb(gpiodir, pl061->base + GPIODIR);
/* /*
* gpio value is set again, because pl061 doesn't allow to set value of * gpio value is set again, because pl061 doesn't allow to set value of
* a gpio pin before configuring it in OUT mode. * a gpio pin before configuring it in OUT mode.
*/ */
writeb(!!value << offset, chip->base + (BIT(offset + 2))); writeb(!!value << offset, pl061->base + (BIT(offset + 2)));
spin_unlock_irqrestore(&chip->lock, flags); spin_unlock_irqrestore(&pl061->lock, flags);
return 0; return 0;
} }
static int pl061_get_value(struct gpio_chip *gc, unsigned offset) static int pl061_get_value(struct gpio_chip *gc, unsigned offset)
{ {
struct pl061_gpio *chip = gpiochip_get_data(gc); struct pl061 *pl061 = gpiochip_get_data(gc);
return !!readb(chip->base + (BIT(offset + 2))); return !!readb(pl061->base + (BIT(offset + 2)));
} }
static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value) static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value)
{ {
struct pl061_gpio *chip = gpiochip_get_data(gc); struct pl061 *pl061 = gpiochip_get_data(gc);
writeb(!!value << offset, chip->base + (BIT(offset + 2))); writeb(!!value << offset, pl061->base + (BIT(offset + 2)));
} }
static int pl061_irq_type(struct irq_data *d, unsigned trigger) static int pl061_irq_type(struct irq_data *d, unsigned trigger)
{ {
struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct pl061_gpio *chip = gpiochip_get_data(gc); struct pl061 *pl061 = gpiochip_get_data(gc);
int offset = irqd_to_hwirq(d); int offset = irqd_to_hwirq(d);
unsigned long flags; unsigned long flags;
u8 gpiois, gpioibe, gpioiev; u8 gpiois, gpioibe, gpioiev;
...@@ -143,11 +143,11 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger) ...@@ -143,11 +143,11 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
} }
spin_lock_irqsave(&chip->lock, flags); spin_lock_irqsave(&pl061->lock, flags);
gpioiev = readb(chip->base + GPIOIEV); gpioiev = readb(pl061->base + GPIOIEV);
gpiois = readb(chip->base + GPIOIS); gpiois = readb(pl061->base + GPIOIS);
gpioibe = readb(chip->base + GPIOIBE); gpioibe = readb(pl061->base + GPIOIBE);
if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
bool polarity = trigger & IRQ_TYPE_LEVEL_HIGH; bool polarity = trigger & IRQ_TYPE_LEVEL_HIGH;
...@@ -199,11 +199,11 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger) ...@@ -199,11 +199,11 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
offset); offset);
} }
writeb(gpiois, chip->base + GPIOIS); writeb(gpiois, pl061->base + GPIOIS);
writeb(gpioibe, chip->base + GPIOIBE); writeb(gpioibe, pl061->base + GPIOIBE);
writeb(gpioiev, chip->base + GPIOIEV); writeb(gpioiev, pl061->base + GPIOIEV);
spin_unlock_irqrestore(&chip->lock, flags); spin_unlock_irqrestore(&pl061->lock, flags);
return 0; return 0;
} }
...@@ -213,12 +213,12 @@ static void pl061_irq_handler(struct irq_desc *desc) ...@@ -213,12 +213,12 @@ static void pl061_irq_handler(struct irq_desc *desc)
unsigned long pending; unsigned long pending;
int offset; int offset;
struct gpio_chip *gc = irq_desc_get_handler_data(desc); struct gpio_chip *gc = irq_desc_get_handler_data(desc);
struct pl061_gpio *chip = gpiochip_get_data(gc); struct pl061 *pl061 = gpiochip_get_data(gc);
struct irq_chip *irqchip = irq_desc_get_chip(desc); struct irq_chip *irqchip = irq_desc_get_chip(desc);
chained_irq_enter(irqchip, desc); chained_irq_enter(irqchip, desc);
pending = readb(chip->base + GPIOMIS); pending = readb(pl061->base + GPIOMIS);
if (pending) { if (pending) {
for_each_set_bit(offset, &pending, PL061_GPIO_NR) for_each_set_bit(offset, &pending, PL061_GPIO_NR)
generic_handle_irq(irq_find_mapping(gc->irqdomain, generic_handle_irq(irq_find_mapping(gc->irqdomain,
...@@ -231,27 +231,27 @@ static void pl061_irq_handler(struct irq_desc *desc) ...@@ -231,27 +231,27 @@ static void pl061_irq_handler(struct irq_desc *desc)
static void pl061_irq_mask(struct irq_data *d) static void pl061_irq_mask(struct irq_data *d)
{ {
struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct pl061_gpio *chip = gpiochip_get_data(gc); struct pl061 *pl061 = gpiochip_get_data(gc);
u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
u8 gpioie; u8 gpioie;
spin_lock(&chip->lock); spin_lock(&pl061->lock);
gpioie = readb(chip->base + GPIOIE) & ~mask; gpioie = readb(pl061->base + GPIOIE) & ~mask;
writeb(gpioie, chip->base + GPIOIE); writeb(gpioie, pl061->base + GPIOIE);
spin_unlock(&chip->lock); spin_unlock(&pl061->lock);
} }
static void pl061_irq_unmask(struct irq_data *d) static void pl061_irq_unmask(struct irq_data *d)
{ {
struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct pl061_gpio *chip = gpiochip_get_data(gc); struct pl061 *pl061 = gpiochip_get_data(gc);
u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
u8 gpioie; u8 gpioie;
spin_lock(&chip->lock); spin_lock(&pl061->lock);
gpioie = readb(chip->base + GPIOIE) | mask; gpioie = readb(pl061->base + GPIOIE) | mask;
writeb(gpioie, chip->base + GPIOIE); writeb(gpioie, pl061->base + GPIOIE);
spin_unlock(&chip->lock); spin_unlock(&pl061->lock);
} }
/** /**
...@@ -265,19 +265,20 @@ static void pl061_irq_unmask(struct irq_data *d) ...@@ -265,19 +265,20 @@ static void pl061_irq_unmask(struct irq_data *d)
static void pl061_irq_ack(struct irq_data *d) static void pl061_irq_ack(struct irq_data *d)
{ {
struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct pl061_gpio *chip = gpiochip_get_data(gc); struct pl061 *pl061 = gpiochip_get_data(gc);
u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
spin_lock(&chip->lock); spin_lock(&pl061->lock);
writeb(mask, chip->base + GPIOIC); writeb(mask, pl061->base + GPIOIC);
spin_unlock(&chip->lock); spin_unlock(&pl061->lock);
} }
static int pl061_irq_set_wake(struct irq_data *d, unsigned int state) static int pl061_irq_set_wake(struct irq_data *d, unsigned int state)
{ {
struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct pl061 *pl061 = gpiochip_get_data(gc);
return irq_set_irq_wake(gc->irq_parent, state); return irq_set_irq_wake(pl061->parent_irq, state);
} }
static struct irq_chip pl061_irqchip = { static struct irq_chip pl061_irqchip = {
...@@ -292,81 +293,60 @@ static struct irq_chip pl061_irqchip = { ...@@ -292,81 +293,60 @@ static struct irq_chip pl061_irqchip = {
static int pl061_probe(struct amba_device *adev, const struct amba_id *id) static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
{ {
struct device *dev = &adev->dev; struct device *dev = &adev->dev;
struct pl061_platform_data *pdata = dev_get_platdata(dev); struct pl061 *pl061;
struct pl061_gpio *chip; int ret, irq;
int ret, irq, i, irq_base;
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); pl061 = devm_kzalloc(dev, sizeof(*pl061), GFP_KERNEL);
if (chip == NULL) if (pl061 == NULL)
return -ENOMEM; return -ENOMEM;
if (pdata) { pl061->base = devm_ioremap_resource(dev, &adev->res);
chip->gc.base = pdata->gpio_base; if (IS_ERR(pl061->base))
irq_base = pdata->irq_base; return PTR_ERR(pl061->base);
if (irq_base <= 0) {
dev_err(&adev->dev, "invalid IRQ base in pdata\n");
return -ENODEV;
}
} else {
chip->gc.base = -1;
irq_base = 0;
}
chip->base = devm_ioremap_resource(dev, &adev->res);
if (IS_ERR(chip->base))
return PTR_ERR(chip->base);
spin_lock_init(&chip->lock); spin_lock_init(&pl061->lock);
if (of_property_read_bool(dev->of_node, "gpio-ranges")) { if (of_property_read_bool(dev->of_node, "gpio-ranges")) {
chip->gc.request = gpiochip_generic_request; pl061->gc.request = gpiochip_generic_request;
chip->gc.free = gpiochip_generic_free; pl061->gc.free = gpiochip_generic_free;
} }
chip->gc.get_direction = pl061_get_direction; pl061->gc.base = -1;
chip->gc.direction_input = pl061_direction_input; pl061->gc.get_direction = pl061_get_direction;
chip->gc.direction_output = pl061_direction_output; pl061->gc.direction_input = pl061_direction_input;
chip->gc.get = pl061_get_value; pl061->gc.direction_output = pl061_direction_output;
chip->gc.set = pl061_set_value; pl061->gc.get = pl061_get_value;
chip->gc.ngpio = PL061_GPIO_NR; pl061->gc.set = pl061_set_value;
chip->gc.label = dev_name(dev); pl061->gc.ngpio = PL061_GPIO_NR;
chip->gc.parent = dev; pl061->gc.label = dev_name(dev);
chip->gc.owner = THIS_MODULE; pl061->gc.parent = dev;
pl061->gc.owner = THIS_MODULE;
ret = gpiochip_add_data(&chip->gc, chip);
ret = gpiochip_add_data(&pl061->gc, pl061);
if (ret) if (ret)
return ret; return ret;
/* /*
* irq_chip support * irq_chip support
*/ */
writeb(0, chip->base + GPIOIE); /* disable irqs */ writeb(0, pl061->base + GPIOIE); /* disable irqs */
irq = adev->irq[0]; irq = adev->irq[0];
if (irq < 0) { if (irq < 0) {
dev_err(&adev->dev, "invalid IRQ\n"); dev_err(&adev->dev, "invalid IRQ\n");
return -ENODEV; return -ENODEV;
} }
pl061->parent_irq = irq;
ret = gpiochip_irqchip_add(&chip->gc, &pl061_irqchip, ret = gpiochip_irqchip_add(&pl061->gc, &pl061_irqchip,
irq_base, handle_bad_irq, 0, handle_bad_irq,
IRQ_TYPE_NONE); IRQ_TYPE_NONE);
if (ret) { if (ret) {
dev_info(&adev->dev, "could not add irqchip\n"); dev_info(&adev->dev, "could not add irqchip\n");
return ret; return ret;
} }
gpiochip_set_chained_irqchip(&chip->gc, &pl061_irqchip, gpiochip_set_chained_irqchip(&pl061->gc, &pl061_irqchip,
irq, pl061_irq_handler); irq, pl061_irq_handler);
for (i = 0; i < PL061_GPIO_NR; i++) { amba_set_drvdata(adev, pl061);
if (pdata) {
if (pdata->directions & (BIT(i)))
pl061_direction_output(&chip->gc, i,
pdata->values & (BIT(i)));
else
pl061_direction_input(&chip->gc, i);
}
}
amba_set_drvdata(adev, chip);
dev_info(&adev->dev, "PL061 GPIO chip @%pa registered\n", dev_info(&adev->dev, "PL061 GPIO chip @%pa registered\n",
&adev->res.start); &adev->res.start);
...@@ -376,20 +356,20 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) ...@@ -376,20 +356,20 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int pl061_suspend(struct device *dev) static int pl061_suspend(struct device *dev)
{ {
struct pl061_gpio *chip = dev_get_drvdata(dev); struct pl061 *pl061 = dev_get_drvdata(dev);
int offset; int offset;
chip->csave_regs.gpio_data = 0; pl061->csave_regs.gpio_data = 0;
chip->csave_regs.gpio_dir = readb(chip->base + GPIODIR); pl061->csave_regs.gpio_dir = readb(pl061->base + GPIODIR);
chip->csave_regs.gpio_is = readb(chip->base + GPIOIS); pl061->csave_regs.gpio_is = readb(pl061->base + GPIOIS);
chip->csave_regs.gpio_ibe = readb(chip->base + GPIOIBE); pl061->csave_regs.gpio_ibe = readb(pl061->base + GPIOIBE);
chip->csave_regs.gpio_iev = readb(chip->base + GPIOIEV); pl061->csave_regs.gpio_iev = readb(pl061->base + GPIOIEV);
chip->csave_regs.gpio_ie = readb(chip->base + GPIOIE); pl061->csave_regs.gpio_ie = readb(pl061->base + GPIOIE);
for (offset = 0; offset < PL061_GPIO_NR; offset++) { for (offset = 0; offset < PL061_GPIO_NR; offset++) {
if (chip->csave_regs.gpio_dir & (BIT(offset))) if (pl061->csave_regs.gpio_dir & (BIT(offset)))
chip->csave_regs.gpio_data |= pl061->csave_regs.gpio_data |=
pl061_get_value(&chip->gc, offset) << offset; pl061_get_value(&pl061->gc, offset) << offset;
} }
return 0; return 0;
...@@ -397,22 +377,22 @@ static int pl061_suspend(struct device *dev) ...@@ -397,22 +377,22 @@ static int pl061_suspend(struct device *dev)
static int pl061_resume(struct device *dev) static int pl061_resume(struct device *dev)
{ {
struct pl061_gpio *chip = dev_get_drvdata(dev); struct pl061 *pl061 = dev_get_drvdata(dev);
int offset; int offset;
for (offset = 0; offset < PL061_GPIO_NR; offset++) { for (offset = 0; offset < PL061_GPIO_NR; offset++) {
if (chip->csave_regs.gpio_dir & (BIT(offset))) if (pl061->csave_regs.gpio_dir & (BIT(offset)))
pl061_direction_output(&chip->gc, offset, pl061_direction_output(&pl061->gc, offset,
chip->csave_regs.gpio_data & pl061->csave_regs.gpio_data &
(BIT(offset))); (BIT(offset)));
else else
pl061_direction_input(&chip->gc, offset); pl061_direction_input(&pl061->gc, offset);
} }
writeb(chip->csave_regs.gpio_is, chip->base + GPIOIS); writeb(pl061->csave_regs.gpio_is, pl061->base + GPIOIS);
writeb(chip->csave_regs.gpio_ibe, chip->base + GPIOIBE); writeb(pl061->csave_regs.gpio_ibe, pl061->base + GPIOIBE);
writeb(chip->csave_regs.gpio_iev, chip->base + GPIOIEV); writeb(pl061->csave_regs.gpio_iev, pl061->base + GPIOIEV);
writeb(chip->csave_regs.gpio_ie, chip->base + GPIOIE); writeb(pl061->csave_regs.gpio_ie, pl061->base + GPIOIE);
return 0; return 0;
} }
......
...@@ -413,7 +413,7 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev) ...@@ -413,7 +413,7 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
stmpe->partnum != STMPE1801) { stmpe->partnum != STMPE1801) {
stmpe_reg_write(stmpe, statmsbreg + i, status[i]); stmpe_reg_write(stmpe, statmsbreg + i, status[i]);
stmpe_reg_write(stmpe, stmpe_reg_write(stmpe,
stmpe->regs[STMPE_IDX_GPEDR_LSB + i], stmpe->regs[STMPE_IDX_GPEDR_MSB] + i,
status[i]); status[i]);
} }
} }
...@@ -484,7 +484,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev) ...@@ -484,7 +484,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
if (stmpe_gpio->norequest_mask & BIT(i)) if (stmpe_gpio->norequest_mask & BIT(i))
clear_bit(i, stmpe_gpio->chip.irq_valid_mask); clear_bit(i, stmpe_gpio->chip.irq_valid_mask);
} }
ret = gpiochip_irqchip_add(&stmpe_gpio->chip, ret = gpiochip_irqchip_add_nested(&stmpe_gpio->chip,
&stmpe_gpio_irq_chip, &stmpe_gpio_irq_chip,
0, 0,
handle_simple_irq, handle_simple_irq,
...@@ -495,10 +495,9 @@ static int stmpe_gpio_probe(struct platform_device *pdev) ...@@ -495,10 +495,9 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
goto out_disable; goto out_disable;
} }
gpiochip_set_chained_irqchip(&stmpe_gpio->chip, gpiochip_set_nested_irqchip(&stmpe_gpio->chip,
&stmpe_gpio_irq_chip, &stmpe_gpio_irq_chip,
irq, irq);
NULL);
} }
platform_set_drvdata(pdev, stmpe_gpio); platform_set_drvdata(pdev, stmpe_gpio);
......
/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* Driver for Semtech SX150X I2C GPIO Expanders
*
* Author: Gregory Bean <gbean@codeaurora.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/of_device.h>
#define NO_UPDATE_PENDING -1
/* The chip models of sx150x */
#define SX150X_123 0
#define SX150X_456 1
#define SX150X_789 2
struct sx150x_123_pri {
u8 reg_pld_mode;
u8 reg_pld_table0;
u8 reg_pld_table1;
u8 reg_pld_table2;
u8 reg_pld_table3;
u8 reg_pld_table4;
u8 reg_advance;
};
struct sx150x_456_pri {
u8 reg_pld_mode;
u8 reg_pld_table0;
u8 reg_pld_table1;
u8 reg_pld_table2;
u8 reg_pld_table3;
u8 reg_pld_table4;
u8 reg_advance;
};
struct sx150x_789_pri {
u8 reg_drain;
u8 reg_polarity;
u8 reg_clock;
u8 reg_misc;
u8 reg_reset;
u8 ngpios;
};
struct sx150x_device_data {
u8 model;
u8 reg_pullup;
u8 reg_pulldn;
u8 reg_dir;
u8 reg_data;
u8 reg_irq_mask;
u8 reg_irq_src;
u8 reg_sense;
u8 ngpios;
union {
struct sx150x_123_pri x123;
struct sx150x_456_pri x456;
struct sx150x_789_pri x789;
} pri;
};
/**
* struct sx150x_platform_data - config data for SX150x driver
* @gpio_base: The index number of the first GPIO assigned to this
* GPIO expander. The expander will create a block of
* consecutively numbered gpios beginning at the given base,
* with the size of the block depending on the model of the
* expander chip.
* @oscio_is_gpo: If set to true, the driver will configure OSCIO as a GPO
* instead of as an oscillator, increasing the size of the
* GP(I)O pool created by this expander by one. The
* output-only GPO pin will be added at the end of the block.
* @io_pullup_ena: A bit-mask which enables or disables the pull-up resistor
* for each IO line in the expander. Setting the bit at
* position n will enable the pull-up for the IO at
* the corresponding offset. For chips with fewer than
* 16 IO pins, high-end bits are ignored.
* @io_pulldn_ena: A bit-mask which enables-or disables the pull-down
* resistor for each IO line in the expander. Setting the
* bit at position n will enable the pull-down for the IO at
* the corresponding offset. For chips with fewer than
* 16 IO pins, high-end bits are ignored.
* @io_polarity: A bit-mask which enables polarity inversion for each IO line
* in the expander. Setting the bit at position n inverts
* the polarity of that IO line, while clearing it results
* in normal polarity. For chips with fewer than 16 IO pins,
* high-end bits are ignored.
* @irq_summary: The 'summary IRQ' line to which the GPIO expander's INT line
* is connected, via which it reports interrupt events
* across all GPIO lines. This must be a real,
* pre-existing IRQ line.
* Setting this value < 0 disables the irq_chip functionality
* of the driver.
* @irq_base: The first 'virtual IRQ' line at which our block of GPIO-based
* IRQ lines will appear. Similarly to gpio_base, the expander
* will create a block of irqs beginning at this number.
* This value is ignored if irq_summary is < 0.
* @reset_during_probe: If set to true, the driver will trigger a full
* reset of the chip at the beginning of the probe
* in order to place it in a known state.
*/
struct sx150x_platform_data {
unsigned gpio_base;
bool oscio_is_gpo;
u16 io_pullup_ena;
u16 io_pulldn_ena;
u16 io_polarity;
int irq_summary;
unsigned irq_base;
bool reset_during_probe;
};
struct sx150x_chip {
struct gpio_chip gpio_chip;
struct i2c_client *client;
const struct sx150x_device_data *dev_cfg;
int irq_summary;
int irq_base;
int irq_update;
u32 irq_sense;
u32 irq_masked;
u32 dev_sense;
u32 dev_masked;
struct irq_chip irq_chip;
struct mutex lock;
};
static const struct sx150x_device_data sx150x_devices[] = {
[0] = { /* sx1508q */
.model = SX150X_789,
.reg_pullup = 0x03,
.reg_pulldn = 0x04,
.reg_dir = 0x07,
.reg_data = 0x08,
.reg_irq_mask = 0x09,
.reg_irq_src = 0x0c,
.reg_sense = 0x0b,
.pri.x789 = {
.reg_drain = 0x05,
.reg_polarity = 0x06,
.reg_clock = 0x0f,
.reg_misc = 0x10,
.reg_reset = 0x7d,
},
.ngpios = 8,
},
[1] = { /* sx1509q */
.model = SX150X_789,
.reg_pullup = 0x07,
.reg_pulldn = 0x09,
.reg_dir = 0x0f,
.reg_data = 0x11,
.reg_irq_mask = 0x13,
.reg_irq_src = 0x19,
.reg_sense = 0x17,
.pri.x789 = {
.reg_drain = 0x0b,
.reg_polarity = 0x0d,
.reg_clock = 0x1e,
.reg_misc = 0x1f,
.reg_reset = 0x7d,
},
.ngpios = 16
},
[2] = { /* sx1506q */
.model = SX150X_456,
.reg_pullup = 0x05,
.reg_pulldn = 0x07,
.reg_dir = 0x03,
.reg_data = 0x01,
.reg_irq_mask = 0x09,
.reg_irq_src = 0x0f,
.reg_sense = 0x0d,
.pri.x456 = {
.reg_pld_mode = 0x21,
.reg_pld_table0 = 0x23,
.reg_pld_table1 = 0x25,
.reg_pld_table2 = 0x27,
.reg_pld_table3 = 0x29,
.reg_pld_table4 = 0x2b,
.reg_advance = 0xad,
},
.ngpios = 16
},
[3] = { /* sx1502q */
.model = SX150X_123,
.reg_pullup = 0x02,
.reg_pulldn = 0x03,
.reg_dir = 0x01,
.reg_data = 0x00,
.reg_irq_mask = 0x05,
.reg_irq_src = 0x08,
.reg_sense = 0x07,
.pri.x123 = {
.reg_pld_mode = 0x10,
.reg_pld_table0 = 0x11,
.reg_pld_table1 = 0x12,
.reg_pld_table2 = 0x13,
.reg_pld_table3 = 0x14,
.reg_pld_table4 = 0x15,
.reg_advance = 0xad,
},
.ngpios = 8,
},
};
static const struct i2c_device_id sx150x_id[] = {
{"sx1508q", 0},
{"sx1509q", 1},
{"sx1506q", 2},
{"sx1502q", 3},
{}
};
static const struct of_device_id sx150x_of_match[] = {
{ .compatible = "semtech,sx1508q" },
{ .compatible = "semtech,sx1509q" },
{ .compatible = "semtech,sx1506q" },
{ .compatible = "semtech,sx1502q" },
{},
};
static s32 sx150x_i2c_write(struct i2c_client *client, u8 reg, u8 val)
{
s32 err = i2c_smbus_write_byte_data(client, reg, val);
if (err < 0)
dev_warn(&client->dev,
"i2c write fail: can't write %02x to %02x: %d\n",
val, reg, err);
return err;
}
static s32 sx150x_i2c_read(struct i2c_client *client, u8 reg, u8 *val)
{
s32 err = i2c_smbus_read_byte_data(client, reg);
if (err >= 0)
*val = err;
else
dev_warn(&client->dev,
"i2c read fail: can't read from %02x: %d\n",
reg, err);
return err;
}
static inline bool offset_is_oscio(struct sx150x_chip *chip, unsigned offset)
{
return (chip->dev_cfg->ngpios == offset);
}
/*
* These utility functions solve the common problem of locating and setting
* configuration bits. Configuration bits are grouped into registers
* whose indexes increase downwards. For example, with eight-bit registers,
* sixteen gpios would have their config bits grouped in the following order:
* REGISTER N-1 [ f e d c b a 9 8 ]
* N [ 7 6 5 4 3 2 1 0 ]
*
* For multi-bit configurations, the pattern gets wider:
* REGISTER N-3 [ f f e e d d c c ]
* N-2 [ b b a a 9 9 8 8 ]
* N-1 [ 7 7 6 6 5 5 4 4 ]
* N [ 3 3 2 2 1 1 0 0 ]
*
* Given the address of the starting register 'N', the index of the gpio
* whose configuration we seek to change, and the width in bits of that
* configuration, these functions allow us to locate the correct
* register and mask the correct bits.
*/
static inline void sx150x_find_cfg(u8 offset, u8 width,
u8 *reg, u8 *mask, u8 *shift)
{
*reg -= offset * width / 8;
*mask = (1 << width) - 1;
*shift = (offset * width) % 8;
*mask <<= *shift;
}
static s32 sx150x_write_cfg(struct sx150x_chip *chip,
u8 offset, u8 width, u8 reg, u8 val)
{
u8 mask;
u8 data;
u8 shift;
s32 err;
sx150x_find_cfg(offset, width, &reg, &mask, &shift);
err = sx150x_i2c_read(chip->client, reg, &data);
if (err < 0)
return err;
data &= ~mask;
data |= (val << shift) & mask;
return sx150x_i2c_write(chip->client, reg, data);
}
static int sx150x_get_io(struct sx150x_chip *chip, unsigned offset)
{
u8 reg = chip->dev_cfg->reg_data;
u8 mask;
u8 data;
u8 shift;
s32 err;
sx150x_find_cfg(offset, 1, &reg, &mask, &shift);
err = sx150x_i2c_read(chip->client, reg, &data);
if (err >= 0)
err = (data & mask) != 0 ? 1 : 0;
return err;
}
static void sx150x_set_oscio(struct sx150x_chip *chip, int val)
{
sx150x_i2c_write(chip->client,
chip->dev_cfg->pri.x789.reg_clock,
(val ? 0x1f : 0x10));
}
static void sx150x_set_io(struct sx150x_chip *chip, unsigned offset, int val)
{
sx150x_write_cfg(chip,
offset,
1,
chip->dev_cfg->reg_data,
(val ? 1 : 0));
}
static int sx150x_io_input(struct sx150x_chip *chip, unsigned offset)
{
return sx150x_write_cfg(chip,
offset,
1,
chip->dev_cfg->reg_dir,
1);
}
static int sx150x_io_output(struct sx150x_chip *chip, unsigned offset, int val)
{
int err;
err = sx150x_write_cfg(chip,
offset,
1,
chip->dev_cfg->reg_data,
(val ? 1 : 0));
if (err >= 0)
err = sx150x_write_cfg(chip,
offset,
1,
chip->dev_cfg->reg_dir,
0);
return err;
}
static int sx150x_gpio_get(struct gpio_chip *gc, unsigned offset)
{
struct sx150x_chip *chip = gpiochip_get_data(gc);
int status = -EINVAL;
if (!offset_is_oscio(chip, offset)) {
mutex_lock(&chip->lock);
status = sx150x_get_io(chip, offset);
mutex_unlock(&chip->lock);
}
return (status < 0) ? status : !!status;
}
static void sx150x_gpio_set(struct gpio_chip *gc, unsigned offset, int val)
{
struct sx150x_chip *chip = gpiochip_get_data(gc);
mutex_lock(&chip->lock);
if (offset_is_oscio(chip, offset))
sx150x_set_oscio(chip, val);
else
sx150x_set_io(chip, offset, val);
mutex_unlock(&chip->lock);
}
static int sx150x_gpio_set_single_ended(struct gpio_chip *gc,
unsigned offset,
enum single_ended_mode mode)
{
struct sx150x_chip *chip = gpiochip_get_data(gc);
/* On the SX160X 789 we can set open drain */
if (chip->dev_cfg->model != SX150X_789)
return -ENOTSUPP;
if (mode == LINE_MODE_PUSH_PULL)
return sx150x_write_cfg(chip,
offset,
1,
chip->dev_cfg->pri.x789.reg_drain,
0);
if (mode == LINE_MODE_OPEN_DRAIN)
return sx150x_write_cfg(chip,
offset,
1,
chip->dev_cfg->pri.x789.reg_drain,
1);
return -ENOTSUPP;
}
static int sx150x_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
{
struct sx150x_chip *chip = gpiochip_get_data(gc);
int status = -EINVAL;
if (!offset_is_oscio(chip, offset)) {
mutex_lock(&chip->lock);
status = sx150x_io_input(chip, offset);
mutex_unlock(&chip->lock);
}
return status;
}
static int sx150x_gpio_direction_output(struct gpio_chip *gc,
unsigned offset,
int val)
{
struct sx150x_chip *chip = gpiochip_get_data(gc);
int status = 0;
if (!offset_is_oscio(chip, offset)) {
mutex_lock(&chip->lock);
status = sx150x_io_output(chip, offset, val);
mutex_unlock(&chip->lock);
}
return status;
}
static void sx150x_irq_mask(struct irq_data *d)
{
struct sx150x_chip *chip = gpiochip_get_data(irq_data_get_irq_chip_data(d));
unsigned n = d->hwirq;
chip->irq_masked |= (1 << n);
chip->irq_update = n;
}
static void sx150x_irq_unmask(struct irq_data *d)
{
struct sx150x_chip *chip = gpiochip_get_data(irq_data_get_irq_chip_data(d));
unsigned n = d->hwirq;
chip->irq_masked &= ~(1 << n);
chip->irq_update = n;
}
static int sx150x_irq_set_type(struct irq_data *d, unsigned int flow_type)
{
struct sx150x_chip *chip = gpiochip_get_data(irq_data_get_irq_chip_data(d));
unsigned n, val = 0;
if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
return -EINVAL;
n = d->hwirq;
if (flow_type & IRQ_TYPE_EDGE_RISING)
val |= 0x1;
if (flow_type & IRQ_TYPE_EDGE_FALLING)
val |= 0x2;
chip->irq_sense &= ~(3UL << (n * 2));
chip->irq_sense |= val << (n * 2);
chip->irq_update = n;
return 0;
}
static irqreturn_t sx150x_irq_thread_fn(int irq, void *dev_id)
{
struct sx150x_chip *chip = (struct sx150x_chip *)dev_id;
unsigned nhandled = 0;
unsigned sub_irq;
unsigned n;
s32 err;
u8 val;
int i;
for (i = (chip->dev_cfg->ngpios / 8) - 1; i >= 0; --i) {
err = sx150x_i2c_read(chip->client,
chip->dev_cfg->reg_irq_src - i,
&val);
if (err < 0)
continue;
sx150x_i2c_write(chip->client,
chip->dev_cfg->reg_irq_src - i,
val);
for (n = 0; n < 8; ++n) {
if (val & (1 << n)) {
sub_irq = irq_find_mapping(
chip->gpio_chip.irqdomain,
(i * 8) + n);
handle_nested_irq(sub_irq);
++nhandled;
}
}
}
return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
}
static void sx150x_irq_bus_lock(struct irq_data *d)
{
struct sx150x_chip *chip = gpiochip_get_data(irq_data_get_irq_chip_data(d));
mutex_lock(&chip->lock);
}
static void sx150x_irq_bus_sync_unlock(struct irq_data *d)
{
struct sx150x_chip *chip = gpiochip_get_data(irq_data_get_irq_chip_data(d));
unsigned n;
if (chip->irq_update == NO_UPDATE_PENDING)
goto out;
n = chip->irq_update;
chip->irq_update = NO_UPDATE_PENDING;
/* Avoid updates if nothing changed */
if (chip->dev_sense == chip->irq_sense &&
chip->dev_masked == chip->irq_masked)
goto out;
chip->dev_sense = chip->irq_sense;
chip->dev_masked = chip->irq_masked;
if (chip->irq_masked & (1 << n)) {
sx150x_write_cfg(chip, n, 1, chip->dev_cfg->reg_irq_mask, 1);
sx150x_write_cfg(chip, n, 2, chip->dev_cfg->reg_sense, 0);
} else {
sx150x_write_cfg(chip, n, 1, chip->dev_cfg->reg_irq_mask, 0);
sx150x_write_cfg(chip, n, 2, chip->dev_cfg->reg_sense,
chip->irq_sense >> (n * 2));
}
out:
mutex_unlock(&chip->lock);
}
static void sx150x_init_chip(struct sx150x_chip *chip,
struct i2c_client *client,
kernel_ulong_t driver_data,
struct sx150x_platform_data *pdata)
{
mutex_init(&chip->lock);
chip->client = client;
chip->dev_cfg = &sx150x_devices[driver_data];
chip->gpio_chip.parent = &client->dev;
chip->gpio_chip.label = client->name;
chip->gpio_chip.direction_input = sx150x_gpio_direction_input;
chip->gpio_chip.direction_output = sx150x_gpio_direction_output;
chip->gpio_chip.get = sx150x_gpio_get;
chip->gpio_chip.set = sx150x_gpio_set;
chip->gpio_chip.set_single_ended = sx150x_gpio_set_single_ended;
chip->gpio_chip.base = pdata->gpio_base;
chip->gpio_chip.can_sleep = true;
chip->gpio_chip.ngpio = chip->dev_cfg->ngpios;
#ifdef CONFIG_OF_GPIO
chip->gpio_chip.of_node = client->dev.of_node;
chip->gpio_chip.of_gpio_n_cells = 2;
#endif
if (pdata->oscio_is_gpo)
++chip->gpio_chip.ngpio;
chip->irq_chip.name = client->name;
chip->irq_chip.irq_mask = sx150x_irq_mask;
chip->irq_chip.irq_unmask = sx150x_irq_unmask;
chip->irq_chip.irq_set_type = sx150x_irq_set_type;
chip->irq_chip.irq_bus_lock = sx150x_irq_bus_lock;
chip->irq_chip.irq_bus_sync_unlock = sx150x_irq_bus_sync_unlock;
chip->irq_summary = -1;
chip->irq_base = -1;
chip->irq_masked = ~0;
chip->irq_sense = 0;
chip->dev_masked = ~0;
chip->dev_sense = 0;
chip->irq_update = NO_UPDATE_PENDING;
}
static int sx150x_init_io(struct sx150x_chip *chip, u8 base, u16 cfg)
{
int err = 0;
unsigned n;
for (n = 0; err >= 0 && n < (chip->dev_cfg->ngpios / 8); ++n)
err = sx150x_i2c_write(chip->client, base - n, cfg >> (n * 8));
return err;
}
static int sx150x_reset(struct sx150x_chip *chip)
{
int err;
err = i2c_smbus_write_byte_data(chip->client,
chip->dev_cfg->pri.x789.reg_reset,
0x12);
if (err < 0)
return err;
err = i2c_smbus_write_byte_data(chip->client,
chip->dev_cfg->pri.x789.reg_reset,
0x34);
return err;
}
static int sx150x_init_hw(struct sx150x_chip *chip,
struct sx150x_platform_data *pdata)
{
int err = 0;
if (pdata->reset_during_probe) {
err = sx150x_reset(chip);
if (err < 0)
return err;
}
if (chip->dev_cfg->model == SX150X_789)
err = sx150x_i2c_write(chip->client,
chip->dev_cfg->pri.x789.reg_misc,
0x01);
else if (chip->dev_cfg->model == SX150X_456)
err = sx150x_i2c_write(chip->client,
chip->dev_cfg->pri.x456.reg_advance,
0x04);
else
err = sx150x_i2c_write(chip->client,
chip->dev_cfg->pri.x123.reg_advance,
0x00);
if (err < 0)
return err;
err = sx150x_init_io(chip, chip->dev_cfg->reg_pullup,
pdata->io_pullup_ena);
if (err < 0)
return err;
err = sx150x_init_io(chip, chip->dev_cfg->reg_pulldn,
pdata->io_pulldn_ena);
if (err < 0)
return err;
if (chip->dev_cfg->model == SX150X_789) {
err = sx150x_init_io(chip,
chip->dev_cfg->pri.x789.reg_polarity,
pdata->io_polarity);
if (err < 0)
return err;
} else if (chip->dev_cfg->model == SX150X_456) {
/* Set all pins to work in normal mode */
err = sx150x_init_io(chip,
chip->dev_cfg->pri.x456.reg_pld_mode,
0);
if (err < 0)
return err;
} else {
/* Set all pins to work in normal mode */
err = sx150x_init_io(chip,
chip->dev_cfg->pri.x123.reg_pld_mode,
0);
if (err < 0)
return err;
}
if (pdata->oscio_is_gpo)
sx150x_set_oscio(chip, 0);
return err;
}
static int sx150x_install_irq_chip(struct sx150x_chip *chip,
int irq_summary,
int irq_base)
{
int err;
chip->irq_summary = irq_summary;
chip->irq_base = irq_base;
/* Add gpio chip to irq subsystem */
err = gpiochip_irqchip_add(&chip->gpio_chip,
&chip->irq_chip, chip->irq_base,
handle_edge_irq, IRQ_TYPE_EDGE_BOTH);
if (err) {
dev_err(&chip->client->dev,
"could not connect irqchip to gpiochip\n");
return err;
}
err = devm_request_threaded_irq(&chip->client->dev,
irq_summary, NULL, sx150x_irq_thread_fn,
IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_FALLING,
chip->irq_chip.name, chip);
if (err < 0) {
chip->irq_summary = -1;
chip->irq_base = -1;
}
return err;
}
static int sx150x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
static const u32 i2c_funcs = I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WRITE_WORD_DATA;
struct sx150x_platform_data *pdata;
struct sx150x_chip *chip;
int rc;
pdata = dev_get_platdata(&client->dev);
if (!pdata)
return -EINVAL;
if (!i2c_check_functionality(client->adapter, i2c_funcs))
return -ENOSYS;
chip = devm_kzalloc(&client->dev,
sizeof(struct sx150x_chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
sx150x_init_chip(chip, client, id->driver_data, pdata);
rc = sx150x_init_hw(chip, pdata);
if (rc < 0)
return rc;
rc = devm_gpiochip_add_data(&client->dev, &chip->gpio_chip, chip);
if (rc)
return rc;
if (pdata->irq_summary >= 0) {
rc = sx150x_install_irq_chip(chip,
pdata->irq_summary,
pdata->irq_base);
if (rc < 0)
return rc;
}
i2c_set_clientdata(client, chip);
return 0;
}
static struct i2c_driver sx150x_driver = {
.driver = {
.name = "sx150x",
.of_match_table = of_match_ptr(sx150x_of_match),
},
.probe = sx150x_probe,
.id_table = sx150x_id,
};
static int __init sx150x_init(void)
{
return i2c_add_driver(&sx150x_driver);
}
subsys_initcall(sx150x_init);
...@@ -337,7 +337,7 @@ static int tc3589x_gpio_probe(struct platform_device *pdev) ...@@ -337,7 +337,7 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
return ret; return ret;
} }
ret = gpiochip_irqchip_add(&tc3589x_gpio->chip, ret = gpiochip_irqchip_add_nested(&tc3589x_gpio->chip,
&tc3589x_gpio_irq_chip, &tc3589x_gpio_irq_chip,
0, 0,
handle_simple_irq, handle_simple_irq,
...@@ -348,10 +348,9 @@ static int tc3589x_gpio_probe(struct platform_device *pdev) ...@@ -348,10 +348,9 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
return ret; return ret;
} }
gpiochip_set_chained_irqchip(&tc3589x_gpio->chip, gpiochip_set_nested_irqchip(&tc3589x_gpio->chip,
&tc3589x_gpio_irq_chip, &tc3589x_gpio_irq_chip,
irq, irq);
NULL);
platform_set_drvdata(pdev, tc3589x_gpio); platform_set_drvdata(pdev, tc3589x_gpio);
......
...@@ -283,8 +283,4 @@ static struct platform_driver vf610_gpio_driver = { ...@@ -283,8 +283,4 @@ static struct platform_driver vf610_gpio_driver = {
.probe = vf610_gpio_probe, .probe = vf610_gpio_probe,
}; };
static int __init gpio_vf610_init(void) builtin_platform_driver(vf610_gpio_driver);
{
return platform_driver_register(&vf610_gpio_driver);
}
device_initcall(gpio_vf610_init);
...@@ -426,7 +426,7 @@ static int wcove_gpio_probe(struct platform_device *pdev) ...@@ -426,7 +426,7 @@ static int wcove_gpio_probe(struct platform_device *pdev)
return ret; return ret;
} }
ret = gpiochip_irqchip_add(&wg->chip, &wcove_irqchip, 0, ret = gpiochip_irqchip_add_nested(&wg->chip, &wcove_irqchip, 0,
handle_simple_irq, IRQ_TYPE_NONE); handle_simple_irq, IRQ_TYPE_NONE);
if (ret) { if (ret) {
dev_err(dev, "Failed to add irqchip: %d\n", ret); dev_err(dev, "Failed to add irqchip: %d\n", ret);
...@@ -446,6 +446,8 @@ static int wcove_gpio_probe(struct platform_device *pdev) ...@@ -446,6 +446,8 @@ static int wcove_gpio_probe(struct platform_device *pdev)
return ret; return ret;
} }
gpiochip_set_nested_irqchip(&wg->chip, &wcove_irqchip, virq);
return 0; return 0;
} }
......
...@@ -468,7 +468,8 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode, ...@@ -468,7 +468,8 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode,
int ret; int ret;
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
ret = acpi_node_get_property_reference(fwnode, propname, index, &args); ret = __acpi_node_get_property_reference(fwnode, propname, index, 3,
&args);
if (ret) { if (ret) {
struct acpi_device *adev = to_acpi_device_node(fwnode); struct acpi_device *adev = to_acpi_device_node(fwnode);
...@@ -483,13 +484,13 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode, ...@@ -483,13 +484,13 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode,
* on returned args. * on returned args.
*/ */
lookup->adev = args.adev; lookup->adev = args.adev;
if (args.nargs >= 2) { if (args.nargs != 3)
return -EPROTO;
lookup->index = args.args[0]; lookup->index = args.args[0];
lookup->pin_index = args.args[1]; lookup->pin_index = args.args[1];
/* 3rd argument, if present is used to specify active_low. */
if (args.nargs >= 3)
lookup->active_low = !!args.args[2]; lookup->active_low = !!args.args[2];
}
return 0; return 0;
} }
...@@ -859,6 +860,77 @@ static void acpi_gpiochip_free_regions(struct acpi_gpio_chip *achip) ...@@ -859,6 +860,77 @@ static void acpi_gpiochip_free_regions(struct acpi_gpio_chip *achip)
} }
} }
static struct gpio_desc *acpi_gpiochip_parse_own_gpio(
struct acpi_gpio_chip *achip, struct fwnode_handle *fwnode,
const char **name, unsigned int *lflags, unsigned int *dflags)
{
struct gpio_chip *chip = achip->chip;
struct gpio_desc *desc;
u32 gpios[2];
int ret;
*lflags = 0;
*dflags = 0;
*name = NULL;
ret = fwnode_property_read_u32_array(fwnode, "gpios", gpios,
ARRAY_SIZE(gpios));
if (ret < 0)
return ERR_PTR(ret);
ret = acpi_gpiochip_pin_to_gpio_offset(chip->gpiodev, gpios[0]);
if (ret < 0)
return ERR_PTR(ret);
desc = gpiochip_get_desc(chip, ret);
if (IS_ERR(desc))
return desc;
if (gpios[1])
*lflags |= GPIO_ACTIVE_LOW;
if (fwnode_property_present(fwnode, "input"))
*dflags |= GPIOD_IN;
else if (fwnode_property_present(fwnode, "output-low"))
*dflags |= GPIOD_OUT_LOW;
else if (fwnode_property_present(fwnode, "output-high"))
*dflags |= GPIOD_OUT_HIGH;
else
return ERR_PTR(-EINVAL);
fwnode_property_read_string(fwnode, "line-name", name);
return desc;
}
static void acpi_gpiochip_scan_gpios(struct acpi_gpio_chip *achip)
{
struct gpio_chip *chip = achip->chip;
struct fwnode_handle *fwnode;
device_for_each_child_node(chip->parent, fwnode) {
unsigned int lflags, dflags;
struct gpio_desc *desc;
const char *name;
int ret;
if (!fwnode_property_present(fwnode, "gpio-hog"))
continue;
desc = acpi_gpiochip_parse_own_gpio(achip, fwnode, &name,
&lflags, &dflags);
if (IS_ERR(desc))
continue;
ret = gpiod_hog(desc, name, lflags, dflags);
if (ret) {
dev_err(chip->parent, "Failed to hog GPIO\n");
fwnode_handle_put(fwnode);
return;
}
}
}
void acpi_gpiochip_add(struct gpio_chip *chip) void acpi_gpiochip_add(struct gpio_chip *chip)
{ {
struct acpi_gpio_chip *acpi_gpio; struct acpi_gpio_chip *acpi_gpio;
...@@ -889,7 +961,11 @@ void acpi_gpiochip_add(struct gpio_chip *chip) ...@@ -889,7 +961,11 @@ void acpi_gpiochip_add(struct gpio_chip *chip)
return; return;
} }
if (!chip->names)
devprop_gpiochip_set_names(chip);
acpi_gpiochip_request_regions(acpi_gpio); acpi_gpiochip_request_regions(acpi_gpio);
acpi_gpiochip_scan_gpios(acpi_gpio);
acpi_walk_dep_device_list(handle); acpi_walk_dep_device_list(handle);
} }
...@@ -918,18 +994,27 @@ void acpi_gpiochip_remove(struct gpio_chip *chip) ...@@ -918,18 +994,27 @@ void acpi_gpiochip_remove(struct gpio_chip *chip)
kfree(acpi_gpio); kfree(acpi_gpio);
} }
static unsigned int acpi_gpio_package_count(const union acpi_object *obj) static int acpi_gpio_package_count(const union acpi_object *obj)
{ {
const union acpi_object *element = obj->package.elements; const union acpi_object *element = obj->package.elements;
const union acpi_object *end = element + obj->package.count; const union acpi_object *end = element + obj->package.count;
unsigned int count = 0; unsigned int count = 0;
while (element < end) { while (element < end) {
if (element->type == ACPI_TYPE_LOCAL_REFERENCE) switch (element->type) {
case ACPI_TYPE_LOCAL_REFERENCE:
element += 3;
/* Fallthrough */
case ACPI_TYPE_INTEGER:
element++;
count++; count++;
break;
element++; default:
return -EPROTO;
}
} }
return count; return count;
} }
......
/*
* Device property helpers for GPIO chips.
*
* Copyright (C) 2016, Intel Corporation
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/property.h>
#include <linux/slab.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include "gpiolib.h"
/**
* devprop_gpiochip_set_names - Set GPIO line names using device properties
* @chip: GPIO chip whose lines should be named, if possible
*
* Looks for device property "gpio-line-names" and if it exists assigns
* GPIO line names for the chip. The memory allocated for the assigned
* names belong to the underlying firmware node and should not be released
* by the caller.
*/
void devprop_gpiochip_set_names(struct gpio_chip *chip)
{
struct gpio_device *gdev = chip->gpiodev;
const char **names;
int ret, i;
if (!chip->parent) {
dev_warn(&gdev->dev, "GPIO chip parent is NULL\n");
return;
}
ret = device_property_read_string_array(chip->parent, "gpio-line-names",
NULL, 0);
if (ret < 0)
return;
if (ret != gdev->ngpio) {
dev_warn(chip->parent,
"names %d do not match number of GPIOs %d\n", ret,
gdev->ngpio);
return;
}
names = kcalloc(gdev->ngpio, sizeof(*names), GFP_KERNEL);
if (!names)
return;
ret = device_property_read_string_array(chip->parent, "gpio-line-names",
names, gdev->ngpio);
if (ret < 0) {
dev_warn(chip->parent, "failed to read GPIO line names\n");
kfree(names);
return;
}
for (i = 0; i < gdev->ngpio; i++)
gdev->descs[i].name = names[i];
kfree(names);
}
...@@ -225,51 +225,6 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np, ...@@ -225,51 +225,6 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
return desc; return desc;
} }
/**
* of_gpiochip_set_names() - set up the names of the lines
* @chip: GPIO chip whose lines should be named, if possible
*/
static void of_gpiochip_set_names(struct gpio_chip *gc)
{
struct gpio_device *gdev = gc->gpiodev;
struct device_node *np = gc->of_node;
int i;
int nstrings;
nstrings = of_property_count_strings(np, "gpio-line-names");
if (nstrings <= 0)
/* Lines names not present */
return;
/* This is normally not what you want */
if (gdev->ngpio != nstrings)
dev_info(&gdev->dev, "gpio-line-names specifies %d line "
"names but there are %d lines on the chip\n",
nstrings, gdev->ngpio);
/*
* Make sure to not index beyond the end of the number of descriptors
* of the GPIO device.
*/
for (i = 0; i < gdev->ngpio; i++) {
const char *name;
int ret;
ret = of_property_read_string_index(np,
"gpio-line-names",
i,
&name);
if (ret) {
if (ret != -ENODATA)
dev_err(&gdev->dev,
"unable to name line %d: %d\n",
i, ret);
break;
}
gdev->descs[i].name = name;
}
}
/** /**
* of_gpiochip_scan_gpios - Scan gpio-controller for gpio definitions * of_gpiochip_scan_gpios - Scan gpio-controller for gpio definitions
* @chip: gpio chip to act on * @chip: gpio chip to act on
...@@ -296,9 +251,11 @@ static int of_gpiochip_scan_gpios(struct gpio_chip *chip) ...@@ -296,9 +251,11 @@ static int of_gpiochip_scan_gpios(struct gpio_chip *chip)
continue; continue;
ret = gpiod_hog(desc, name, lflags, dflags); ret = gpiod_hog(desc, name, lflags, dflags);
if (ret < 0) if (ret < 0) {
of_node_put(np);
return ret; return ret;
} }
}
return 0; return 0;
} }
...@@ -526,7 +483,7 @@ int of_gpiochip_add(struct gpio_chip *chip) ...@@ -526,7 +483,7 @@ int of_gpiochip_add(struct gpio_chip *chip)
/* If the chip defines names itself, these take precedence */ /* If the chip defines names itself, these take precedence */
if (!chip->names) if (!chip->names)
of_gpiochip_set_names(chip); devprop_gpiochip_set_names(chip);
of_node_get(chip->of_node); of_node_get(chip->of_node);
......
...@@ -986,7 +986,8 @@ static int gpio_chrdev_open(struct inode *inode, struct file *filp) ...@@ -986,7 +986,8 @@ static int gpio_chrdev_open(struct inode *inode, struct file *filp)
return -ENODEV; return -ENODEV;
get_device(&gdev->dev); get_device(&gdev->dev);
filp->private_data = gdev; filp->private_data = gdev;
return 0;
return nonseekable_open(inode, filp);
} }
/** /**
...@@ -1011,7 +1012,7 @@ static const struct file_operations gpio_fileops = { ...@@ -1011,7 +1012,7 @@ static const struct file_operations gpio_fileops = {
.release = gpio_chrdev_release, .release = gpio_chrdev_release,
.open = gpio_chrdev_open, .open = gpio_chrdev_open,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = noop_llseek, .llseek = no_llseek,
.unlocked_ioctl = gpio_ioctl, .unlocked_ioctl = gpio_ioctl,
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.compat_ioctl = gpio_ioctl_compat, .compat_ioctl = gpio_ioctl_compat,
...@@ -1512,7 +1513,7 @@ static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip, ...@@ -1512,7 +1513,7 @@ static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
} }
/** /**
* gpiochip_set_chained_irqchip() - sets a chained irqchip to a gpiochip * gpiochip_set_cascaded_irqchip() - connects a cascaded irqchip to a gpiochip
* @gpiochip: the gpiochip to set the irqchip chain to * @gpiochip: the gpiochip to set the irqchip chain to
* @irqchip: the irqchip to chain to the gpiochip * @irqchip: the irqchip to chain to the gpiochip
* @parent_irq: the irq number corresponding to the parent IRQ for this * @parent_irq: the irq number corresponding to the parent IRQ for this
...@@ -1521,7 +1522,7 @@ static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip, ...@@ -1521,7 +1522,7 @@ static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
* coming out of the gpiochip. If the interrupt is nested rather than * coming out of the gpiochip. If the interrupt is nested rather than
* cascaded, pass NULL in this handler argument * cascaded, pass NULL in this handler argument
*/ */
void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip,
struct irq_chip *irqchip, struct irq_chip *irqchip,
int parent_irq, int parent_irq,
irq_flow_handler_t parent_handler) irq_flow_handler_t parent_handler)
...@@ -1548,7 +1549,7 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, ...@@ -1548,7 +1549,7 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
irq_set_chained_handler_and_data(parent_irq, parent_handler, irq_set_chained_handler_and_data(parent_irq, parent_handler,
gpiochip); gpiochip);
gpiochip->irq_parent = parent_irq; gpiochip->irq_chained_parent = parent_irq;
} }
/* Set the parent IRQ for all affected IRQs */ /* Set the parent IRQ for all affected IRQs */
...@@ -1559,8 +1560,47 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, ...@@ -1559,8 +1560,47 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
parent_irq); parent_irq);
} }
} }
/**
* gpiochip_set_chained_irqchip() - connects a chained irqchip to a gpiochip
* @gpiochip: the gpiochip to set the irqchip chain to
* @irqchip: the irqchip to chain to the gpiochip
* @parent_irq: the irq number corresponding to the parent IRQ for this
* chained irqchip
* @parent_handler: the parent interrupt handler for the accumulated IRQ
* coming out of the gpiochip. If the interrupt is nested rather than
* cascaded, pass NULL in this handler argument
*/
void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
struct irq_chip *irqchip,
int parent_irq,
irq_flow_handler_t parent_handler)
{
gpiochip_set_cascaded_irqchip(gpiochip, irqchip, parent_irq,
parent_handler);
}
EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip); EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip);
/**
* gpiochip_set_nested_irqchip() - connects a nested irqchip to a gpiochip
* @gpiochip: the gpiochip to set the irqchip nested handler to
* @irqchip: the irqchip to nest to the gpiochip
* @parent_irq: the irq number corresponding to the parent IRQ for this
* nested irqchip
*/
void gpiochip_set_nested_irqchip(struct gpio_chip *gpiochip,
struct irq_chip *irqchip,
int parent_irq)
{
if (!gpiochip->irq_nested) {
chip_err(gpiochip, "tried to nest a chained gpiochip\n");
return;
}
gpiochip_set_cascaded_irqchip(gpiochip, irqchip, parent_irq,
NULL);
}
EXPORT_SYMBOL_GPL(gpiochip_set_nested_irqchip);
/** /**
* gpiochip_irq_map() - maps an IRQ into a GPIO irqchip * gpiochip_irq_map() - maps an IRQ into a GPIO irqchip
* @d: the irqdomain used by this irqchip * @d: the irqdomain used by this irqchip
...@@ -1583,8 +1623,8 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, ...@@ -1583,8 +1623,8 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
*/ */
irq_set_lockdep_class(irq, chip->lock_key); irq_set_lockdep_class(irq, chip->lock_key);
irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler); irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler);
/* Chips that can sleep need nested thread handlers */ /* Chips that use nested thread handlers have them marked */
if (chip->can_sleep && !chip->irq_not_threaded) if (chip->irq_nested)
irq_set_nested_thread(irq, 1); irq_set_nested_thread(irq, 1);
irq_set_noprobe(irq); irq_set_noprobe(irq);
...@@ -1602,7 +1642,7 @@ static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq) ...@@ -1602,7 +1642,7 @@ static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)
{ {
struct gpio_chip *chip = d->host_data; struct gpio_chip *chip = d->host_data;
if (chip->can_sleep) if (chip->irq_nested)
irq_set_nested_thread(irq, 0); irq_set_nested_thread(irq, 0);
irq_set_chip_and_handler(irq, NULL, NULL); irq_set_chip_and_handler(irq, NULL, NULL);
irq_set_chip_data(irq, NULL); irq_set_chip_data(irq, NULL);
...@@ -1657,9 +1697,9 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) ...@@ -1657,9 +1697,9 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
acpi_gpiochip_free_interrupts(gpiochip); acpi_gpiochip_free_interrupts(gpiochip);
if (gpiochip->irq_parent) { if (gpiochip->irq_chained_parent) {
irq_set_chained_handler(gpiochip->irq_parent, NULL); irq_set_chained_handler(gpiochip->irq_chained_parent, NULL);
irq_set_handler_data(gpiochip->irq_parent, NULL); irq_set_handler_data(gpiochip->irq_chained_parent, NULL);
} }
/* Remove all IRQ mappings and delete the domain */ /* Remove all IRQ mappings and delete the domain */
...@@ -1683,7 +1723,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) ...@@ -1683,7 +1723,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
} }
/** /**
* gpiochip_irqchip_add() - adds an irqchip to a gpiochip * _gpiochip_irqchip_add() - adds an irqchip to a gpiochip
* @gpiochip: the gpiochip to add the irqchip to * @gpiochip: the gpiochip to add the irqchip to
* @irqchip: the irqchip to add to the gpiochip * @irqchip: the irqchip to add to the gpiochip
* @first_irq: if not dynamically assigned, the base (first) IRQ to * @first_irq: if not dynamically assigned, the base (first) IRQ to
...@@ -1691,6 +1731,8 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) ...@@ -1691,6 +1731,8 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
* @handler: the irq handler to use (often a predefined irq core function) * @handler: the irq handler to use (often a predefined irq core function)
* @type: the default type for IRQs on this irqchip, pass IRQ_TYPE_NONE * @type: the default type for IRQs on this irqchip, pass IRQ_TYPE_NONE
* to have the core avoid setting up any default type in the hardware. * to have the core avoid setting up any default type in the hardware.
* @nested: whether this is a nested irqchip calling handle_nested_irq()
* in its IRQ handler
* @lock_key: lockdep class * @lock_key: lockdep class
* *
* This function closely associates a certain irqchip with a certain * This function closely associates a certain irqchip with a certain
...@@ -1712,6 +1754,7 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip, ...@@ -1712,6 +1754,7 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip,
unsigned int first_irq, unsigned int first_irq,
irq_flow_handler_t handler, irq_flow_handler_t handler,
unsigned int type, unsigned int type,
bool nested,
struct lock_class_key *lock_key) struct lock_class_key *lock_key)
{ {
struct device_node *of_node; struct device_node *of_node;
...@@ -1726,6 +1769,7 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip, ...@@ -1726,6 +1769,7 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip,
pr_err("missing gpiochip .dev parent pointer\n"); pr_err("missing gpiochip .dev parent pointer\n");
return -EINVAL; return -EINVAL;
} }
gpiochip->irq_nested = nested;
of_node = gpiochip->parent->of_node; of_node = gpiochip->parent->of_node;
#ifdef CONFIG_OF_GPIO #ifdef CONFIG_OF_GPIO
/* /*
...@@ -2223,6 +2267,7 @@ EXPORT_SYMBOL_GPL(gpiod_direction_input); ...@@ -2223,6 +2267,7 @@ EXPORT_SYMBOL_GPL(gpiod_direction_input);
static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value) static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value)
{ {
struct gpio_chip *gc = desc->gdev->chip; struct gpio_chip *gc = desc->gdev->chip;
int val = !!value;
int ret; int ret;
/* GPIOs used for IRQs shall not be set as output */ /* GPIOs used for IRQs shall not be set as output */
...@@ -2242,7 +2287,7 @@ static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value) ...@@ -2242,7 +2287,7 @@ static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value)
goto set_output_value; goto set_output_value;
} }
/* Emulate open drain by not actively driving the line high */ /* Emulate open drain by not actively driving the line high */
if (value) if (val)
return gpiod_direction_input(desc); return gpiod_direction_input(desc);
} }
else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) { else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) {
...@@ -2253,7 +2298,7 @@ static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value) ...@@ -2253,7 +2298,7 @@ static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value)
goto set_output_value; goto set_output_value;
} }
/* Emulate open source by not actively driving the line low */ /* Emulate open source by not actively driving the line low */
if (!value) if (!val)
return gpiod_direction_input(desc); return gpiod_direction_input(desc);
} else { } else {
/* Make sure to disable open drain/source hardware, if any */ /* Make sure to disable open drain/source hardware, if any */
...@@ -2271,10 +2316,10 @@ static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value) ...@@ -2271,10 +2316,10 @@ static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value)
return -EIO; return -EIO;
} }
ret = gc->direction_output(gc, gpio_chip_hwgpio(desc), value); ret = gc->direction_output(gc, gpio_chip_hwgpio(desc), val);
if (!ret) if (!ret)
set_bit(FLAG_IS_OUT, &desc->flags); set_bit(FLAG_IS_OUT, &desc->flags);
trace_gpio_value(desc_to_gpio(desc), 0, value); trace_gpio_value(desc_to_gpio(desc), 0, val);
trace_gpio_direction(desc_to_gpio(desc), 0, ret); trace_gpio_direction(desc_to_gpio(desc), 0, ret);
return ret; return ret;
} }
...@@ -2314,6 +2359,8 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) ...@@ -2314,6 +2359,8 @@ int gpiod_direction_output(struct gpio_desc *desc, int value)
VALIDATE_DESC(desc); VALIDATE_DESC(desc);
if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
value = !value; value = !value;
else
value = !!value;
return _gpiod_direction_output_raw(desc, value); return _gpiod_direction_output_raw(desc, value);
} }
EXPORT_SYMBOL_GPL(gpiod_direction_output); EXPORT_SYMBOL_GPL(gpiod_direction_output);
...@@ -2758,6 +2805,15 @@ int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset) ...@@ -2758,6 +2805,15 @@ int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
} }
set_bit(FLAG_USED_AS_IRQ, &desc->flags); set_bit(FLAG_USED_AS_IRQ, &desc->flags);
/*
* If the consumer has not set up a label (such as when the
* IRQ is referenced from .to_irq()) we set up a label here
* so it is clear this is used as an interrupt.
*/
if (!desc->label)
desc_set_label(desc, "interrupt");
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(gpiochip_lock_as_irq); EXPORT_SYMBOL_GPL(gpiochip_lock_as_irq);
...@@ -2772,10 +2828,17 @@ EXPORT_SYMBOL_GPL(gpiochip_lock_as_irq); ...@@ -2772,10 +2828,17 @@ EXPORT_SYMBOL_GPL(gpiochip_lock_as_irq);
*/ */
void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset) void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset)
{ {
if (offset >= chip->ngpio) struct gpio_desc *desc;
desc = gpiochip_get_desc(chip, offset);
if (IS_ERR(desc))
return; return;
clear_bit(FLAG_USED_AS_IRQ, &chip->gpiodev->descs[offset].flags); clear_bit(FLAG_USED_AS_IRQ, &desc->flags);
/* If we only had this marking, erase it */
if (desc->label && !strcmp(desc->label, "interrupt"))
desc_set_label(desc, NULL);
} }
EXPORT_SYMBOL_GPL(gpiochip_unlock_as_irq); EXPORT_SYMBOL_GPL(gpiochip_unlock_as_irq);
...@@ -3170,7 +3233,7 @@ static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, ...@@ -3170,7 +3233,7 @@ static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
/* Process flags */ /* Process flags */
if (dflags & GPIOD_FLAGS_BIT_DIR_OUT) if (dflags & GPIOD_FLAGS_BIT_DIR_OUT)
status = gpiod_direction_output(desc, status = gpiod_direction_output(desc,
dflags & GPIOD_FLAGS_BIT_DIR_VAL); !!(dflags & GPIOD_FLAGS_BIT_DIR_VAL));
else else
status = gpiod_direction_input(desc); status = gpiod_direction_input(desc);
......
...@@ -209,6 +209,8 @@ static int __maybe_unused gpio_chip_hwgpio(const struct gpio_desc *desc) ...@@ -209,6 +209,8 @@ static int __maybe_unused gpio_chip_hwgpio(const struct gpio_desc *desc)
return desc - &desc->gdev->descs[0]; return desc - &desc->gdev->descs[0];
} }
void devprop_gpiochip_set_names(struct gpio_chip *chip);
/* With descriptor prefix */ /* With descriptor prefix */
#define gpiod_emerg(desc, fmt, ...) \ #define gpiod_emerg(desc, fmt, ...) \
......
...@@ -164,6 +164,20 @@ config PINCTRL_SIRF ...@@ -164,6 +164,20 @@ config PINCTRL_SIRF
select GENERIC_PINCONF select GENERIC_PINCONF
select GPIOLIB_IRQCHIP select GPIOLIB_IRQCHIP
config PINCTRL_SX150X
bool "Semtech SX150x I2C GPIO expander pinctrl driver"
depends on GPIOLIB && I2C=y
select PINMUX
select PINCONF
select GENERIC_PINCONF
select GPIOLIB_IRQCHIP
help
Say yes here to provide support for Semtech SX150x-series I2C
GPIO expanders as pinctrl module.
Compatible models include:
- 8 bits: sx1508q, sx1502q
- 16 bits: sx1509q, sx1506q
config PINCTRL_PISTACHIO config PINCTRL_PISTACHIO
def_bool y if MACH_PISTACHIO def_bool y if MACH_PISTACHIO
depends on GPIOLIB depends on GPIOLIB
......
...@@ -25,6 +25,7 @@ obj-$(CONFIG_PINCTRL_PISTACHIO) += pinctrl-pistachio.o ...@@ -25,6 +25,7 @@ obj-$(CONFIG_PINCTRL_PISTACHIO) += pinctrl-pistachio.o
obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o
obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o
obj-$(CONFIG_PINCTRL_SIRF) += sirf/ obj-$(CONFIG_PINCTRL_SIRF) += sirf/
obj-$(CONFIG_PINCTRL_SX150X) += pinctrl-sx150x.o
obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_PINCTRL_TZ1090) += pinctrl-tz1090.o obj-$(CONFIG_PINCTRL_TZ1090) += pinctrl-tz1090.o
obj-$(CONFIG_PINCTRL_TZ1090_PDC) += pinctrl-tz1090-pdc.o obj-$(CONFIG_PINCTRL_TZ1090_PDC) += pinctrl-tz1090-pdc.o
......
/*
* Copyright (c) 2016, BayLibre, SAS. All rights reserved.
* Author: Neil Armstrong <narmstrong@baylibre.com>
*
* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* Driver for Semtech SX150X I2C GPIO Expanders
*
* Author: Gregory Bean <gbean@codeaurora.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/gpio.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf-generic.h>
#include "core.h"
#include "pinconf.h"
#include "pinctrl-utils.h"
/* The chip models of sx150x */
enum {
SX150X_123 = 0,
SX150X_456,
SX150X_789,
};
struct sx150x_123_pri {
u8 reg_pld_mode;
u8 reg_pld_table0;
u8 reg_pld_table1;
u8 reg_pld_table2;
u8 reg_pld_table3;
u8 reg_pld_table4;
u8 reg_advance;
};
struct sx150x_456_pri {
u8 reg_pld_mode;
u8 reg_pld_table0;
u8 reg_pld_table1;
u8 reg_pld_table2;
u8 reg_pld_table3;
u8 reg_pld_table4;
u8 reg_advance;
};
struct sx150x_789_pri {
u8 reg_drain;
u8 reg_polarity;
u8 reg_clock;
u8 reg_misc;
u8 reg_reset;
u8 ngpios;
};
struct sx150x_device_data {
u8 model;
u8 reg_pullup;
u8 reg_pulldn;
u8 reg_dir;
u8 reg_data;
u8 reg_irq_mask;
u8 reg_irq_src;
u8 reg_sense;
u8 ngpios;
union {
struct sx150x_123_pri x123;
struct sx150x_456_pri x456;
struct sx150x_789_pri x789;
} pri;
const struct pinctrl_pin_desc *pins;
unsigned int npins;
};
struct sx150x_pinctrl {
struct device *dev;
struct i2c_client *client;
struct pinctrl_dev *pctldev;
struct pinctrl_desc pinctrl_desc;
struct gpio_chip gpio;
struct irq_chip irq_chip;
struct {
int update;
u32 sense;
u32 masked;
u32 dev_sense;
u32 dev_masked;
} irq;
struct mutex lock;
const struct sx150x_device_data *data;
};
static const struct pinctrl_pin_desc sx150x_8_pins[] = {
PINCTRL_PIN(0, "gpio0"),
PINCTRL_PIN(1, "gpio1"),
PINCTRL_PIN(2, "gpio2"),
PINCTRL_PIN(3, "gpio3"),
PINCTRL_PIN(4, "gpio4"),
PINCTRL_PIN(5, "gpio5"),
PINCTRL_PIN(6, "gpio6"),
PINCTRL_PIN(7, "gpio7"),
PINCTRL_PIN(8, "oscio"),
};
static const struct pinctrl_pin_desc sx150x_16_pins[] = {
PINCTRL_PIN(0, "gpio0"),
PINCTRL_PIN(1, "gpio1"),
PINCTRL_PIN(2, "gpio2"),
PINCTRL_PIN(3, "gpio3"),
PINCTRL_PIN(4, "gpio4"),
PINCTRL_PIN(5, "gpio5"),
PINCTRL_PIN(6, "gpio6"),
PINCTRL_PIN(7, "gpio7"),
PINCTRL_PIN(8, "gpio8"),
PINCTRL_PIN(9, "gpio9"),
PINCTRL_PIN(10, "gpio10"),
PINCTRL_PIN(11, "gpio11"),
PINCTRL_PIN(12, "gpio12"),
PINCTRL_PIN(13, "gpio13"),
PINCTRL_PIN(14, "gpio14"),
PINCTRL_PIN(15, "gpio15"),
PINCTRL_PIN(16, "oscio"),
};
static const struct sx150x_device_data sx1508q_device_data = {
.model = SX150X_789,
.reg_pullup = 0x03,
.reg_pulldn = 0x04,
.reg_dir = 0x07,
.reg_data = 0x08,
.reg_irq_mask = 0x09,
.reg_irq_src = 0x0c,
.reg_sense = 0x0b,
.pri.x789 = {
.reg_drain = 0x05,
.reg_polarity = 0x06,
.reg_clock = 0x0f,
.reg_misc = 0x10,
.reg_reset = 0x7d,
},
.ngpios = 8,
.pins = sx150x_8_pins,
.npins = ARRAY_SIZE(sx150x_8_pins),
};
static const struct sx150x_device_data sx1509q_device_data = {
.model = SX150X_789,
.reg_pullup = 0x07,
.reg_pulldn = 0x09,
.reg_dir = 0x0f,
.reg_data = 0x11,
.reg_irq_mask = 0x13,
.reg_irq_src = 0x19,
.reg_sense = 0x17,
.pri.x789 = {
.reg_drain = 0x0b,
.reg_polarity = 0x0d,
.reg_clock = 0x1e,
.reg_misc = 0x1f,
.reg_reset = 0x7d,
},
.ngpios = 16,
.pins = sx150x_16_pins,
.npins = ARRAY_SIZE(sx150x_16_pins),
};
static const struct sx150x_device_data sx1506q_device_data = {
.model = SX150X_456,
.reg_pullup = 0x05,
.reg_pulldn = 0x07,
.reg_dir = 0x03,
.reg_data = 0x01,
.reg_irq_mask = 0x09,
.reg_irq_src = 0x0f,
.reg_sense = 0x0d,
.pri.x456 = {
.reg_pld_mode = 0x21,
.reg_pld_table0 = 0x23,
.reg_pld_table1 = 0x25,
.reg_pld_table2 = 0x27,
.reg_pld_table3 = 0x29,
.reg_pld_table4 = 0x2b,
.reg_advance = 0xad,
},
.ngpios = 16,
.pins = sx150x_16_pins,
.npins = 16, /* oscio not available */
};
static const struct sx150x_device_data sx1502q_device_data = {
.model = SX150X_123,
.reg_pullup = 0x02,
.reg_pulldn = 0x03,
.reg_dir = 0x01,
.reg_data = 0x00,
.reg_irq_mask = 0x05,
.reg_irq_src = 0x08,
.reg_sense = 0x07,
.pri.x123 = {
.reg_pld_mode = 0x10,
.reg_pld_table0 = 0x11,
.reg_pld_table1 = 0x12,
.reg_pld_table2 = 0x13,
.reg_pld_table3 = 0x14,
.reg_pld_table4 = 0x15,
.reg_advance = 0xad,
},
.ngpios = 8,
.pins = sx150x_8_pins,
.npins = 8, /* oscio not available */
};
static s32 sx150x_i2c_write(struct i2c_client *client, u8 reg, u8 val)
{
s32 err = i2c_smbus_write_byte_data(client, reg, val);
if (err < 0)
dev_warn(&client->dev,
"i2c write fail: can't write %02x to %02x: %d\n",
val, reg, err);
return err;
}
static s32 sx150x_i2c_read(struct i2c_client *client, u8 reg, u8 *val)
{
s32 err = i2c_smbus_read_byte_data(client, reg);
if (err >= 0)
*val = err;
else
dev_warn(&client->dev,
"i2c read fail: can't read from %02x: %d\n",
reg, err);
return err;
}
/*
* These utility functions solve the common problem of locating and setting
* configuration bits. Configuration bits are grouped into registers
* whose indexes increase downwards. For example, with eight-bit registers,
* sixteen gpios would have their config bits grouped in the following order:
* REGISTER N-1 [ f e d c b a 9 8 ]
* N [ 7 6 5 4 3 2 1 0 ]
*
* For multi-bit configurations, the pattern gets wider:
* REGISTER N-3 [ f f e e d d c c ]
* N-2 [ b b a a 9 9 8 8 ]
* N-1 [ 7 7 6 6 5 5 4 4 ]
* N [ 3 3 2 2 1 1 0 0 ]
*
* Given the address of the starting register 'N', the index of the gpio
* whose configuration we seek to change, and the width in bits of that
* configuration, these functions allow us to locate the correct
* register and mask the correct bits.
*/
static inline void sx150x_find_cfg(u8 offset, u8 width,
u8 *reg, u8 *mask, u8 *shift)
{
*reg -= offset * width / 8;
*mask = (1 << width) - 1;
*shift = (offset * width) % 8;
*mask <<= *shift;
}
static int sx150x_write_cfg(struct i2c_client *client,
u8 offset, u8 width, u8 reg, u8 val)
{
u8 mask;
u8 data;
u8 shift;
int err;
sx150x_find_cfg(offset, width, &reg, &mask, &shift);
err = sx150x_i2c_read(client, reg, &data);
if (err < 0)
return err;
data &= ~mask;
data |= (val << shift) & mask;
return sx150x_i2c_write(client, reg, data);
}
static int sx150x_read_cfg(struct i2c_client *client,
u8 offset, u8 width, u8 reg)
{
u8 mask;
u8 data;
u8 shift;
int err;
sx150x_find_cfg(offset, width, &reg, &mask, &shift);
err = sx150x_i2c_read(client, reg, &data);
if (err < 0)
return err;
return (data & mask);
}
static int sx150x_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
{
return 0;
}
static const char *sx150x_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
unsigned int group)
{
return NULL;
}
static int sx150x_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
unsigned int group,
const unsigned int **pins,
unsigned int *num_pins)
{
return -ENOTSUPP;
}
static const struct pinctrl_ops sx150x_pinctrl_ops = {
.get_groups_count = sx150x_pinctrl_get_groups_count,
.get_group_name = sx150x_pinctrl_get_group_name,
.get_group_pins = sx150x_pinctrl_get_group_pins,
#ifdef CONFIG_OF
.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
.dt_free_map = pinctrl_utils_free_map,
#endif
};
static bool sx150x_pin_is_oscio(struct sx150x_pinctrl *pctl, unsigned int pin)
{
if (pin >= pctl->data->npins)
return false;
/* OSCIO pin is only present in 789 devices */
if (pctl->data->model != SX150X_789)
return false;
return !strcmp(pctl->data->pins[pin].name, "oscio");
}
static int sx150x_gpio_get_direction(struct gpio_chip *chip,
unsigned int offset)
{
struct sx150x_pinctrl *pctl = gpiochip_get_data(chip);
int status;
if (sx150x_pin_is_oscio(pctl, offset))
return false;
status = sx150x_read_cfg(pctl->client, offset, 1, pctl->data->reg_dir);
if (status >= 0)
status = !!status;
return status;
}
static int sx150x_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct sx150x_pinctrl *pctl = gpiochip_get_data(chip);
int status;
if (sx150x_pin_is_oscio(pctl, offset))
return -EINVAL;
status = sx150x_read_cfg(pctl->client, offset, 1, pctl->data->reg_data);
if (status >= 0)
status = !!status;
return status;
}
static int sx150x_gpio_set_single_ended(struct gpio_chip *chip,
unsigned int offset,
enum single_ended_mode mode)
{
struct sx150x_pinctrl *pctl = gpiochip_get_data(chip);
int ret;
switch (mode) {
case LINE_MODE_PUSH_PULL:
if (pctl->data->model != SX150X_789 ||
sx150x_pin_is_oscio(pctl, offset))
return 0;
mutex_lock(&pctl->lock);
ret = sx150x_write_cfg(pctl->client, offset, 1,
pctl->data->pri.x789.reg_drain,
0);
mutex_unlock(&pctl->lock);
if (ret < 0)
return ret;
break;
case LINE_MODE_OPEN_DRAIN:
if (pctl->data->model != SX150X_789 ||
sx150x_pin_is_oscio(pctl, offset))
return -ENOTSUPP;
mutex_lock(&pctl->lock);
ret = sx150x_write_cfg(pctl->client, offset, 1,
pctl->data->pri.x789.reg_drain,
1);
mutex_unlock(&pctl->lock);
if (ret < 0)
return ret;
break;
default:
return -ENOTSUPP;
}
return 0;
}
static void sx150x_gpio_set(struct gpio_chip *chip, unsigned int offset,
int value)
{
struct sx150x_pinctrl *pctl = gpiochip_get_data(chip);
if (sx150x_pin_is_oscio(pctl, offset)) {
mutex_lock(&pctl->lock);
sx150x_i2c_write(pctl->client,
pctl->data->pri.x789.reg_clock,
(value ? 0x1f : 0x10));
mutex_unlock(&pctl->lock);
} else {
mutex_lock(&pctl->lock);
sx150x_write_cfg(pctl->client, offset, 1,
pctl->data->reg_data,
(value ? 1 : 0));
mutex_unlock(&pctl->lock);
}
}
static int sx150x_gpio_direction_input(struct gpio_chip *chip,
unsigned int offset)
{
struct sx150x_pinctrl *pctl = gpiochip_get_data(chip);
int ret;
if (sx150x_pin_is_oscio(pctl, offset))
return -EINVAL;
mutex_lock(&pctl->lock);
ret = sx150x_write_cfg(pctl->client, offset, 1,
pctl->data->reg_dir, 1);
mutex_unlock(&pctl->lock);
return ret;
}
static int sx150x_gpio_direction_output(struct gpio_chip *chip,
unsigned int offset, int value)
{
struct sx150x_pinctrl *pctl = gpiochip_get_data(chip);
int status;
if (sx150x_pin_is_oscio(pctl, offset)) {
sx150x_gpio_set(chip, offset, value);
return 0;
}
mutex_lock(&pctl->lock);
status = sx150x_write_cfg(pctl->client, offset, 1,
pctl->data->reg_data,
(value ? 1 : 0));
if (status >= 0)
status = sx150x_write_cfg(pctl->client, offset, 1,
pctl->data->reg_dir, 0);
mutex_unlock(&pctl->lock);
return status;
}
static void sx150x_irq_mask(struct irq_data *d)
{
struct sx150x_pinctrl *pctl =
gpiochip_get_data(irq_data_get_irq_chip_data(d));
unsigned int n = d->hwirq;
pctl->irq.masked |= (1 << n);
pctl->irq.update = n;
}
static void sx150x_irq_unmask(struct irq_data *d)
{
struct sx150x_pinctrl *pctl =
gpiochip_get_data(irq_data_get_irq_chip_data(d));
unsigned int n = d->hwirq;
pctl->irq.masked &= ~(1 << n);
pctl->irq.update = n;
}
static int sx150x_irq_set_type(struct irq_data *d, unsigned int flow_type)
{
struct sx150x_pinctrl *pctl =
gpiochip_get_data(irq_data_get_irq_chip_data(d));
unsigned int n, val = 0;
if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
return -EINVAL;
n = d->hwirq;
if (flow_type & IRQ_TYPE_EDGE_RISING)
val |= 0x1;
if (flow_type & IRQ_TYPE_EDGE_FALLING)
val |= 0x2;
pctl->irq.sense &= ~(3UL << (n * 2));
pctl->irq.sense |= val << (n * 2);
pctl->irq.update = n;
return 0;
}
static irqreturn_t sx150x_irq_thread_fn(int irq, void *dev_id)
{
struct sx150x_pinctrl *pctl = (struct sx150x_pinctrl *)dev_id;
unsigned int nhandled = 0;
unsigned int sub_irq;
unsigned int n;
s32 err;
u8 val;
int i;
for (i = (pctl->data->ngpios / 8) - 1; i >= 0; --i) {
err = sx150x_i2c_read(pctl->client,
pctl->data->reg_irq_src - i,
&val);
if (err < 0)
continue;
err = sx150x_i2c_write(pctl->client,
pctl->data->reg_irq_src - i,
val);
if (err < 0)
continue;
for (n = 0; n < 8; ++n) {
if (val & (1 << n)) {
sub_irq = irq_find_mapping(
pctl->gpio.irqdomain,
(i * 8) + n);
handle_nested_irq(sub_irq);
++nhandled;
}
}
}
return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
}
static void sx150x_irq_bus_lock(struct irq_data *d)
{
struct sx150x_pinctrl *pctl =
gpiochip_get_data(irq_data_get_irq_chip_data(d));
mutex_lock(&pctl->lock);
}
static void sx150x_irq_bus_sync_unlock(struct irq_data *d)
{
struct sx150x_pinctrl *pctl =
gpiochip_get_data(irq_data_get_irq_chip_data(d));
unsigned int n;
if (pctl->irq.update < 0)
goto out;
n = pctl->irq.update;
pctl->irq.update = -1;
/* Avoid updates if nothing changed */
if (pctl->irq.dev_sense == pctl->irq.sense &&
pctl->irq.dev_masked == pctl->irq.masked)
goto out;
pctl->irq.dev_sense = pctl->irq.sense;
pctl->irq.dev_masked = pctl->irq.masked;
if (pctl->irq.masked & (1 << n)) {
sx150x_write_cfg(pctl->client, n, 1,
pctl->data->reg_irq_mask, 1);
sx150x_write_cfg(pctl->client, n, 2,
pctl->data->reg_sense, 0);
} else {
sx150x_write_cfg(pctl->client, n, 1,
pctl->data->reg_irq_mask, 0);
sx150x_write_cfg(pctl->client, n, 2,
pctl->data->reg_sense,
pctl->irq.sense >> (n * 2));
}
out:
mutex_unlock(&pctl->lock);
}
static int sx150x_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long *config)
{
struct sx150x_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
unsigned int param = pinconf_to_config_param(*config);
int ret;
u32 arg;
if (sx150x_pin_is_oscio(pctl, pin)) {
u8 data;
switch (param) {
case PIN_CONFIG_DRIVE_PUSH_PULL:
case PIN_CONFIG_OUTPUT:
mutex_lock(&pctl->lock);
ret = sx150x_i2c_read(pctl->client,
pctl->data->pri.x789.reg_clock,
&data);
mutex_unlock(&pctl->lock);
if (ret < 0)
return ret;
if (param == PIN_CONFIG_DRIVE_PUSH_PULL)
arg = (data & 0x1f) ? 1 : 0;
else {
if ((data & 0x1f) == 0x1f)
arg = 1;
else if ((data & 0x1f) == 0x10)
arg = 0;
else
return -EINVAL;
}
break;
default:
return -ENOTSUPP;
}
goto out;
}
switch (param) {
case PIN_CONFIG_BIAS_PULL_DOWN:
mutex_lock(&pctl->lock);
ret = sx150x_read_cfg(pctl->client, pin, 1,
pctl->data->reg_pulldn);
mutex_unlock(&pctl->lock);
if (ret < 0)
return ret;
if (!ret)
return -EINVAL;
arg = 1;
break;
case PIN_CONFIG_BIAS_PULL_UP:
mutex_lock(&pctl->lock);
ret = sx150x_read_cfg(pctl->client, pin, 1,
pctl->data->reg_pullup);
mutex_unlock(&pctl->lock);
if (ret < 0)
return ret;
if (!ret)
return -EINVAL;
arg = 1;
break;
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
if (pctl->data->model != SX150X_789)
return -ENOTSUPP;
mutex_lock(&pctl->lock);
ret = sx150x_read_cfg(pctl->client, pin, 1,
pctl->data->pri.x789.reg_drain);
mutex_unlock(&pctl->lock);
if (ret < 0)
return ret;
if (!ret)
return -EINVAL;
arg = 1;
break;
case PIN_CONFIG_DRIVE_PUSH_PULL:
if (pctl->data->model != SX150X_789)
arg = true;
else {
mutex_lock(&pctl->lock);
ret = sx150x_read_cfg(pctl->client, pin, 1,
pctl->data->pri.x789.reg_drain);
mutex_unlock(&pctl->lock);
if (ret < 0)
return ret;
if (ret)
return -EINVAL;
arg = 1;
}
break;
case PIN_CONFIG_OUTPUT:
ret = sx150x_gpio_get_direction(&pctl->gpio, pin);
if (ret < 0)
return ret;
if (ret)
return -EINVAL;
ret = sx150x_gpio_get(&pctl->gpio, pin);
if (ret < 0)
return ret;
arg = ret;
break;
default:
return -ENOTSUPP;
}
out:
*config = pinconf_to_config_packed(param, arg);
return 0;
}
static int sx150x_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long *configs, unsigned int num_configs)
{
struct sx150x_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param;
u32 arg;
int i;
int ret;
for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]);
arg = pinconf_to_config_argument(configs[i]);
if (sx150x_pin_is_oscio(pctl, pin)) {
if (param == PIN_CONFIG_OUTPUT) {
ret = sx150x_gpio_direction_output(&pctl->gpio,
pin, arg);
if (ret < 0)
return ret;
continue;
} else
return -ENOTSUPP;
}
switch (param) {
case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
case PIN_CONFIG_BIAS_DISABLE:
mutex_lock(&pctl->lock);
ret = sx150x_write_cfg(pctl->client, pin, 1,
pctl->data->reg_pulldn, 0);
mutex_unlock(&pctl->lock);
if (ret < 0)
return ret;
mutex_lock(&pctl->lock);
ret = sx150x_write_cfg(pctl->client, pin, 1,
pctl->data->reg_pullup, 0);
mutex_unlock(&pctl->lock);
if (ret < 0)
return ret;
break;
case PIN_CONFIG_BIAS_PULL_UP:
mutex_lock(&pctl->lock);
ret = sx150x_write_cfg(pctl->client, pin, 1,
pctl->data->reg_pullup,
1);
mutex_unlock(&pctl->lock);
if (ret < 0)
return ret;
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
mutex_lock(&pctl->lock);
ret = sx150x_write_cfg(pctl->client, pin, 1,
pctl->data->reg_pulldn,
1);
mutex_unlock(&pctl->lock);
if (ret < 0)
return ret;
break;
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
ret = sx150x_gpio_set_single_ended(&pctl->gpio,
pin, LINE_MODE_OPEN_DRAIN);
if (ret < 0)
return ret;
break;
case PIN_CONFIG_DRIVE_PUSH_PULL:
ret = sx150x_gpio_set_single_ended(&pctl->gpio,
pin, LINE_MODE_PUSH_PULL);
if (ret < 0)
return ret;
break;
case PIN_CONFIG_OUTPUT:
ret = sx150x_gpio_direction_output(&pctl->gpio,
pin, arg);
if (ret < 0)
return ret;
break;
default:
return -ENOTSUPP;
}
} /* for each config */
return 0;
}
static const struct pinconf_ops sx150x_pinconf_ops = {
.pin_config_get = sx150x_pinconf_get,
.pin_config_set = sx150x_pinconf_set,
.is_generic = true,
};
static const struct i2c_device_id sx150x_id[] = {
{"sx1508q", (kernel_ulong_t) &sx1508q_device_data },
{"sx1509q", (kernel_ulong_t) &sx1509q_device_data },
{"sx1506q", (kernel_ulong_t) &sx1506q_device_data },
{"sx1502q", (kernel_ulong_t) &sx1502q_device_data },
{}
};
static const struct of_device_id sx150x_of_match[] = {
{ .compatible = "semtech,sx1508q" },
{ .compatible = "semtech,sx1509q" },
{ .compatible = "semtech,sx1506q" },
{ .compatible = "semtech,sx1502q" },
{},
};
static int sx150x_init_io(struct sx150x_pinctrl *pctl, u8 base, u16 cfg)
{
int err = 0;
unsigned int n;
for (n = 0; err >= 0 && n < (pctl->data->ngpios / 8); ++n)
err = sx150x_i2c_write(pctl->client, base - n, cfg >> (n * 8));
return err;
}
static int sx150x_reset(struct sx150x_pinctrl *pctl)
{
int err;
err = i2c_smbus_write_byte_data(pctl->client,
pctl->data->pri.x789.reg_reset,
0x12);
if (err < 0)
return err;
err = i2c_smbus_write_byte_data(pctl->client,
pctl->data->pri.x789.reg_reset,
0x34);
return err;
}
static int sx150x_init_hw(struct sx150x_pinctrl *pctl)
{
int err;
if (pctl->data->model == SX150X_789 &&
of_property_read_bool(pctl->dev->of_node, "semtech,probe-reset")) {
err = sx150x_reset(pctl);
if (err < 0)
return err;
}
if (pctl->data->model == SX150X_789)
err = sx150x_i2c_write(pctl->client,
pctl->data->pri.x789.reg_misc,
0x01);
else if (pctl->data->model == SX150X_456)
err = sx150x_i2c_write(pctl->client,
pctl->data->pri.x456.reg_advance,
0x04);
else
err = sx150x_i2c_write(pctl->client,
pctl->data->pri.x123.reg_advance,
0x00);
if (err < 0)
return err;
/* Set all pins to work in normal mode */
if (pctl->data->model == SX150X_789) {
err = sx150x_init_io(pctl,
pctl->data->pri.x789.reg_polarity,
0);
if (err < 0)
return err;
} else if (pctl->data->model == SX150X_456) {
/* Set all pins to work in normal mode */
err = sx150x_init_io(pctl,
pctl->data->pri.x456.reg_pld_mode,
0);
if (err < 0)
return err;
} else {
/* Set all pins to work in normal mode */
err = sx150x_init_io(pctl,
pctl->data->pri.x123.reg_pld_mode,
0);
if (err < 0)
return err;
}
return 0;
}
static int sx150x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
static const u32 i2c_funcs = I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WRITE_WORD_DATA;
struct device *dev = &client->dev;
struct sx150x_pinctrl *pctl;
int ret;
if (!id->driver_data)
return -EINVAL;
if (!i2c_check_functionality(client->adapter, i2c_funcs))
return -ENOSYS;
pctl = devm_kzalloc(dev, sizeof(*pctl), GFP_KERNEL);
if (!pctl)
return -ENOMEM;
pctl->dev = dev;
pctl->client = client;
pctl->data = (void *)id->driver_data;
mutex_init(&pctl->lock);
ret = sx150x_init_hw(pctl);
if (ret)
return ret;
/* Register GPIO controller */
pctl->gpio.label = devm_kstrdup(dev, client->name, GFP_KERNEL);
pctl->gpio.base = -1;
pctl->gpio.ngpio = pctl->data->npins;
pctl->gpio.get_direction = sx150x_gpio_get_direction;
pctl->gpio.direction_input = sx150x_gpio_direction_input;
pctl->gpio.direction_output = sx150x_gpio_direction_output;
pctl->gpio.get = sx150x_gpio_get;
pctl->gpio.set = sx150x_gpio_set;
pctl->gpio.set_single_ended = sx150x_gpio_set_single_ended;
pctl->gpio.parent = dev;
#ifdef CONFIG_OF_GPIO
pctl->gpio.of_node = dev->of_node;
#endif
pctl->gpio.can_sleep = true;
ret = devm_gpiochip_add_data(dev, &pctl->gpio, pctl);
if (ret)
return ret;
/* Add Interrupt support if an irq is specified */
if (client->irq > 0) {
pctl->irq_chip.name = devm_kstrdup(dev, client->name,
GFP_KERNEL);
pctl->irq_chip.irq_mask = sx150x_irq_mask;
pctl->irq_chip.irq_unmask = sx150x_irq_unmask;
pctl->irq_chip.irq_set_type = sx150x_irq_set_type;
pctl->irq_chip.irq_bus_lock = sx150x_irq_bus_lock;
pctl->irq_chip.irq_bus_sync_unlock = sx150x_irq_bus_sync_unlock;
pctl->irq.masked = ~0;
pctl->irq.sense = 0;
pctl->irq.dev_masked = ~0;
pctl->irq.dev_sense = 0;
pctl->irq.update = -1;
ret = gpiochip_irqchip_add(&pctl->gpio,
&pctl->irq_chip, 0,
handle_edge_irq, IRQ_TYPE_NONE);
if (ret) {
dev_err(dev, "could not connect irqchip to gpiochip\n");
return ret;
}
ret = devm_request_threaded_irq(dev, client->irq, NULL,
sx150x_irq_thread_fn,
IRQF_ONESHOT | IRQF_SHARED |
IRQF_TRIGGER_FALLING,
pctl->irq_chip.name, pctl);
if (ret < 0)
return ret;
}
/* Pinctrl_desc */
pctl->pinctrl_desc.name = "sx150x-pinctrl";
pctl->pinctrl_desc.pctlops = &sx150x_pinctrl_ops;
pctl->pinctrl_desc.confops = &sx150x_pinconf_ops;
pctl->pinctrl_desc.pins = pctl->data->pins;
pctl->pinctrl_desc.npins = pctl->data->npins;
pctl->pinctrl_desc.owner = THIS_MODULE;
pctl->pctldev = pinctrl_register(&pctl->pinctrl_desc, dev, pctl);
if (IS_ERR(pctl->pctldev)) {
dev_err(dev, "Failed to register pinctrl device\n");
return PTR_ERR(pctl->pctldev);
}
return 0;
}
static struct i2c_driver sx150x_driver = {
.driver = {
.name = "sx150x-pinctrl",
.of_match_table = of_match_ptr(sx150x_of_match),
},
.probe = sx150x_probe,
.id_table = sx150x_id,
};
static int __init sx150x_init(void)
{
return i2c_add_driver(&sx150x_driver);
}
subsys_initcall(sx150x_init);
#include <linux/types.h>
/* platform data for the PL061 GPIO driver */
struct pl061_platform_data {
/* number of the first GPIO */
unsigned gpio_base;
/* number of the first IRQ.
* If the IRQ functionality in not desired this must be set to 0.
*/
unsigned irq_base;
u8 directions; /* startup directions, 1: out, 0: in */
u8 values; /* startup values */
};
...@@ -82,8 +82,6 @@ enum single_ended_mode { ...@@ -82,8 +82,6 @@ enum single_ended_mode {
* implies that if the chip supports IRQs, these IRQs need to be threaded * implies that if the chip supports IRQs, these IRQs need to be threaded
* as the chip access may sleep when e.g. reading out the IRQ status * as the chip access may sleep when e.g. reading out the IRQ status
* registers. * registers.
* @irq_not_threaded: flag must be set if @can_sleep is set but the
* IRQs don't need to be threaded
* @read_reg: reader function for generic GPIO * @read_reg: reader function for generic GPIO
* @write_reg: writer function for generic GPIO * @write_reg: writer function for generic GPIO
* @pin2mask: some generic GPIO controllers work with the big-endian bits * @pin2mask: some generic GPIO controllers work with the big-endian bits
...@@ -91,7 +89,7 @@ enum single_ended_mode { ...@@ -91,7 +89,7 @@ enum single_ended_mode {
* bit. This callback assigns the right bit mask. * bit. This callback assigns the right bit mask.
* @reg_dat: data (in) register for generic GPIO * @reg_dat: data (in) register for generic GPIO
* @reg_set: output set register (out=high) for generic GPIO * @reg_set: output set register (out=high) for generic GPIO
* @reg_clk: output clear register (out=low) for generic GPIO * @reg_clr: output clear register (out=low) for generic GPIO
* @reg_dir: direction setting register for generic GPIO * @reg_dir: direction setting register for generic GPIO
* @bgpio_bits: number of register bits used for a generic GPIO i.e. * @bgpio_bits: number of register bits used for a generic GPIO i.e.
* <register width> * 8 * <register width> * 8
...@@ -109,8 +107,10 @@ enum single_ended_mode { ...@@ -109,8 +107,10 @@ enum single_ended_mode {
* for GPIO IRQs, provided by GPIO driver * for GPIO IRQs, provided by GPIO driver
* @irq_default_type: default IRQ triggering type applied during GPIO driver * @irq_default_type: default IRQ triggering type applied during GPIO driver
* initialization, provided by GPIO driver * initialization, provided by GPIO driver
* @irq_parent: GPIO IRQ chip parent/bank linux irq number, * @irq_chained_parent: GPIO IRQ chip parent/bank linux irq number,
* provided by GPIO driver * provided by GPIO driver for chained interrupt (not for nested
* interrupts).
* @irq_nested: True if set the interrupt handling is nested.
* @irq_need_valid_mask: If set core allocates @irq_valid_mask with all * @irq_need_valid_mask: If set core allocates @irq_valid_mask with all
* bits set to one * bits set to one
* @irq_valid_mask: If not %NULL holds bitmask of GPIOs which are valid to * @irq_valid_mask: If not %NULL holds bitmask of GPIOs which are valid to
...@@ -166,7 +166,6 @@ struct gpio_chip { ...@@ -166,7 +166,6 @@ struct gpio_chip {
u16 ngpio; u16 ngpio;
const char *const *names; const char *const *names;
bool can_sleep; bool can_sleep;
bool irq_not_threaded;
#if IS_ENABLED(CONFIG_GPIO_GENERIC) #if IS_ENABLED(CONFIG_GPIO_GENERIC)
unsigned long (*read_reg)(void __iomem *reg); unsigned long (*read_reg)(void __iomem *reg);
...@@ -192,7 +191,8 @@ struct gpio_chip { ...@@ -192,7 +191,8 @@ struct gpio_chip {
unsigned int irq_base; unsigned int irq_base;
irq_flow_handler_t irq_handler; irq_flow_handler_t irq_handler;
unsigned int irq_default_type; unsigned int irq_default_type;
int irq_parent; int irq_chained_parent;
bool irq_nested;
bool irq_need_valid_mask; bool irq_need_valid_mask;
unsigned long *irq_valid_mask; unsigned long *irq_valid_mask;
struct lock_class_key *lock_key; struct lock_class_key *lock_key;
...@@ -270,24 +270,40 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, ...@@ -270,24 +270,40 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
int parent_irq, int parent_irq,
irq_flow_handler_t parent_handler); irq_flow_handler_t parent_handler);
void gpiochip_set_nested_irqchip(struct gpio_chip *gpiochip,
struct irq_chip *irqchip,
int parent_irq);
int _gpiochip_irqchip_add(struct gpio_chip *gpiochip, int _gpiochip_irqchip_add(struct gpio_chip *gpiochip,
struct irq_chip *irqchip, struct irq_chip *irqchip,
unsigned int first_irq, unsigned int first_irq,
irq_flow_handler_t handler, irq_flow_handler_t handler,
unsigned int type, unsigned int type,
bool nested,
struct lock_class_key *lock_key); struct lock_class_key *lock_key);
/* FIXME: I assume threaded IRQchips do not have the lockdep problem */
static inline int gpiochip_irqchip_add_nested(struct gpio_chip *gpiochip,
struct irq_chip *irqchip,
unsigned int first_irq,
irq_flow_handler_t handler,
unsigned int type)
{
return _gpiochip_irqchip_add(gpiochip, irqchip, first_irq,
handler, type, true, NULL);
}
#ifdef CONFIG_LOCKDEP #ifdef CONFIG_LOCKDEP
#define gpiochip_irqchip_add(...) \ #define gpiochip_irqchip_add(...) \
( \ ( \
({ \ ({ \
static struct lock_class_key _key; \ static struct lock_class_key _key; \
_gpiochip_irqchip_add(__VA_ARGS__, &_key); \ _gpiochip_irqchip_add(__VA_ARGS__, false, &_key); \
}) \ }) \
) )
#else #else
#define gpiochip_irqchip_add(...) \ #define gpiochip_irqchip_add(...) \
_gpiochip_irqchip_add(__VA_ARGS__, NULL) _gpiochip_irqchip_add(__VA_ARGS__, false, NULL)
#endif #endif
#endif /* CONFIG_GPIOLIB_IRQCHIP */ #endif /* CONFIG_GPIOLIB_IRQCHIP */
......
...@@ -23,54 +23,31 @@ ...@@ -23,54 +23,31 @@
#include <getopt.h> #include <getopt.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include "gpio-utils.h"
int hammer_device(const char *device_name, unsigned int *lines, int nlines, int hammer_device(const char *device_name, unsigned int *lines, int nlines,
unsigned int loops) unsigned int loops)
{ {
struct gpiohandle_request req;
struct gpiohandle_data data; struct gpiohandle_data data;
char *chrdev_name;
char swirr[] = "-\\|/"; char swirr[] = "-\\|/";
int fd; int fd;
int ret; int ret;
int i, j; int i, j;
unsigned int iteration = 0; unsigned int iteration = 0;
ret = asprintf(&chrdev_name, "/dev/%s", device_name); memset(&data.values, 0, sizeof(data.values));
ret = gpiotools_request_linehandle(device_name, lines, nlines,
GPIOHANDLE_REQUEST_OUTPUT, &data,
"gpio-hammler");
if (ret < 0) if (ret < 0)
return -ENOMEM; goto exit_error;
else
fd = ret;
fd = open(chrdev_name, 0); ret = gpiotools_get_values(fd, &data);
if (fd == -1) { if (ret < 0)
ret = -errno;
fprintf(stderr, "Failed to open %s\n", chrdev_name);
goto exit_close_error;
}
/* Request lines as output */
for (i = 0; i < nlines; i++)
req.lineoffsets[i] = lines[i];
req.flags = GPIOHANDLE_REQUEST_OUTPUT; /* Request as output */
strcpy(req.consumer_label, "gpio-hammer");
req.lines = nlines;
ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
if (ret == -1) {
ret = -errno;
fprintf(stderr, "Failed to issue GET LINEHANDLE "
"IOCTL (%d)\n",
ret);
goto exit_close_error; goto exit_close_error;
}
/* Read initial states */
ret = ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data);
if (ret == -1) {
ret = -errno;
fprintf(stderr, "Failed to issue GPIOHANDLE GET LINE "
"VALUES IOCTL (%d)\n",
ret);
goto exit_close_error;
}
fprintf(stdout, "Hammer lines ["); fprintf(stdout, "Hammer lines [");
for (i = 0; i < nlines; i++) { for (i = 0; i < nlines; i++) {
fprintf(stdout, "%d", lines[i]); fprintf(stdout, "%d", lines[i]);
...@@ -92,23 +69,14 @@ int hammer_device(const char *device_name, unsigned int *lines, int nlines, ...@@ -92,23 +69,14 @@ int hammer_device(const char *device_name, unsigned int *lines, int nlines,
for (i = 0; i < nlines; i++) for (i = 0; i < nlines; i++)
data.values[i] = !data.values[i]; data.values[i] = !data.values[i];
ret = ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data); ret = gpiotools_set_values(fd, &data);
if (ret == -1) { if (ret < 0)
ret = -errno;
fprintf(stderr, "Failed to issue GPIOHANDLE SET LINE "
"VALUES IOCTL (%d)\n",
ret);
goto exit_close_error; goto exit_close_error;
}
/* Re-read values to get status */ /* Re-read values to get status */
ret = ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data); ret = gpiotools_get_values(fd, &data);
if (ret == -1) { if (ret < 0)
ret = -errno;
fprintf(stderr, "Failed to issue GPIOHANDLE GET LINE "
"VALUES IOCTL (%d)\n",
ret);
goto exit_close_error; goto exit_close_error;
}
fprintf(stdout, "[%c] ", swirr[j]); fprintf(stdout, "[%c] ", swirr[j]);
j++; j++;
...@@ -132,9 +100,8 @@ int hammer_device(const char *device_name, unsigned int *lines, int nlines, ...@@ -132,9 +100,8 @@ int hammer_device(const char *device_name, unsigned int *lines, int nlines,
ret = 0; ret = 0;
exit_close_error: exit_close_error:
if (close(fd) == -1) gpiotools_release_linehandle(fd);
perror("Failed to close GPIO character device file"); exit_error:
free(chrdev_name);
return ret; return ret;
} }
......
...@@ -2,10 +2,266 @@ ...@@ -2,10 +2,266 @@
* GPIO tools - helpers library for the GPIO tools * GPIO tools - helpers library for the GPIO tools
* *
* Copyright (C) 2015 Linus Walleij * Copyright (C) 2015 Linus Walleij
* Copyright (C) 2016 Bamvor Jian Zhang
* *
* This program is free software; you can redistribute it and/or modify it * 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 * under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation. * the Free Software Foundation.
*/ */
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <getopt.h>
#include <sys/ioctl.h>
#include <linux/gpio.h>
#include "gpio-utils.h" #include "gpio-utils.h"
#define COMSUMER "gpio-utils"
/**
* doc: Operation of gpio
*
* Provide the api of gpiochip for chardev interface. There are two
* types of api. The first one provide as same function as each
* ioctl, including request and release for lines of gpio, read/write
* the value of gpio. If the user want to do lots of read and write of
* lines of gpio, user should use this type of api.
*
* The second one provide the easy to use api for user. Each of the
* following api will request gpio lines, do the operation and then
* release these lines.
*/
/**
* gpiotools_request_linehandle() - request gpio lines in a gpiochip
* @device_name: The name of gpiochip without prefix "/dev/",
* such as "gpiochip0"
* @lines: An array desired lines, specified by offset
* index for the associated GPIO device.
* @nline: The number of lines to request.
* @flag: The new flag for requsted gpio. Reference
* "linux/gpio.h" for the meaning of flag.
* @data: Default value will be set to gpio when flag is
* GPIOHANDLE_REQUEST_OUTPUT.
* @consumer_label: The name of consumer, such as "sysfs",
* "powerkey". This is useful for other users to
* know who is using.
*
* Request gpio lines through the ioctl provided by chardev. User
* could call gpiotools_set_values() and gpiotools_get_values() to
* read and write respectively through the returned fd. Call
* gpiotools_release_linehandle() to release these lines after that.
*
* Return: On success return the fd;
* On failure return the errno.
*/
int gpiotools_request_linehandle(const char *device_name, unsigned int *lines,
unsigned int nlines, unsigned int flag,
struct gpiohandle_data *data,
const char *consumer_label)
{
struct gpiohandle_request req;
char *chrdev_name;
int fd;
int i;
int ret;
ret = asprintf(&chrdev_name, "/dev/%s", device_name);
if (ret < 0)
return -ENOMEM;
fd = open(chrdev_name, 0);
if (fd == -1) {
ret = -errno;
fprintf(stderr, "Failed to open %s\n", chrdev_name);
goto exit_close_error;
}
for (i = 0; i < nlines; i++)
req.lineoffsets[i] = lines[i];
req.flags = flag;
strcpy(req.consumer_label, consumer_label);
req.lines = nlines;
if (flag & GPIOHANDLE_REQUEST_OUTPUT)
memcpy(req.default_values, data, sizeof(req.default_values));
ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
if (ret == -1) {
ret = -errno;
fprintf(stderr, "Failed to issue GET LINEHANDLE IOCTL (%d)\n",
ret);
}
exit_close_error:
if (close(fd) == -1)
perror("Failed to close GPIO character device file");
free(chrdev_name);
return ret < 0 ? ret : req.fd;
}
/**
* gpiotools_set_values(): Set the value of gpio(s)
* @fd: The fd returned by
* gpiotools_request_linehandle().
* @data: The array of values want to set.
*
* Return: On success return 0;
* On failure return the errno.
*/
int gpiotools_set_values(const int fd, struct gpiohandle_data *data)
{
int ret;
ret = ioctl(fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, data);
if (ret == -1) {
ret = -errno;
fprintf(stderr, "Failed to issue %s (%d)\n",
"GPIOHANDLE_SET_LINE_VALUES_IOCTL", ret);
}
return ret;
}
/**
* gpiotools_get_values(): Get the value of gpio(s)
* @fd: The fd returned by
* gpiotools_request_linehandle().
* @data: The array of values get from hardware.
*
* Return: On success return 0;
* On failure return the errno.
*/
int gpiotools_get_values(const int fd, struct gpiohandle_data *data)
{
int ret;
ret = ioctl(fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, data);
if (ret == -1) {
ret = -errno;
fprintf(stderr, "Failed to issue %s (%d)\n",
"GPIOHANDLE_GET_LINE_VALUES_IOCTL", ret);
}
return ret;
}
/**
* gpiotools_release_linehandle(): Release the line(s) of gpiochip
* @fd: The fd returned by
* gpiotools_request_linehandle().
*
* Return: On success return 0;
* On failure return the errno.
*/
int gpiotools_release_linehandle(const int fd)
{
int ret;
ret = close(fd);
if (ret == -1) {
perror("Failed to close GPIO LINEHANDLE device file");
ret = -errno;
}
return ret;
}
/**
* gpiotools_get(): Get value from specific line
* @device_name: The name of gpiochip without prefix "/dev/",
* such as "gpiochip0"
* @line: number of line, such as 2.
*
* Return: On success return 0;
* On failure return the errno.
*/
int gpiotools_get(const char *device_name, unsigned int line)
{
struct gpiohandle_data data;
unsigned int lines[] = {line};
gpiotools_gets(device_name, lines, 1, &data);
return data.values[0];
}
/**
* gpiotools_gets(): Get values from specific lines.
* @device_name: The name of gpiochip without prefix "/dev/",
* such as "gpiochip0".
* @lines: An array desired lines, specified by offset
* index for the associated GPIO device.
* @nline: The number of lines to request.
* @data: The array of values get from gpiochip.
*
* Return: On success return 0;
* On failure return the errno.
*/
int gpiotools_gets(const char *device_name, unsigned int *lines,
unsigned int nlines, struct gpiohandle_data *data)
{
int fd;
int ret;
int ret_close;
ret = gpiotools_request_linehandle(device_name, lines, nlines,
GPIOHANDLE_REQUEST_INPUT, data,
COMSUMER);
if (ret < 0)
return ret;
fd = ret;
ret = gpiotools_get_values(fd, data);
ret_close = gpiotools_release_linehandle(fd);
return ret < 0 ? ret : ret_close;
}
/**
* gpiotools_set(): Set value to specific line
* @device_name: The name of gpiochip without prefix "/dev/",
* such as "gpiochip0"
* @line: number of line, such as 2.
* @value: The value of gpio, must be 0(low) or 1(high).
*
* Return: On success return 0;
* On failure return the errno.
*/
int gpiotools_set(const char *device_name, unsigned int line,
unsigned int value)
{
struct gpiohandle_data data;
unsigned int lines[] = {line};
data.values[0] = value;
return gpiotools_sets(device_name, lines, 1, &data);
}
/**
* gpiotools_sets(): Set values to specific lines.
* @device_name: The name of gpiochip without prefix "/dev/",
* such as "gpiochip0".
* @lines: An array desired lines, specified by offset
* index for the associated GPIO device.
* @nline: The number of lines to request.
* @data: The array of values set to gpiochip, must be
* 0(low) or 1(high).
*
* Return: On success return 0;
* On failure return the errno.
*/
int gpiotools_sets(const char *device_name, unsigned int *lines,
unsigned int nlines, struct gpiohandle_data *data)
{
int ret;
ret = gpiotools_request_linehandle(device_name, lines, nlines,
GPIOHANDLE_REQUEST_OUTPUT, data,
COMSUMER);
if (ret < 0)
return ret;
return gpiotools_release_linehandle(ret);
}
...@@ -24,4 +24,20 @@ static inline int check_prefix(const char *str, const char *prefix) ...@@ -24,4 +24,20 @@ static inline int check_prefix(const char *str, const char *prefix)
strncmp(str, prefix, strlen(prefix)) == 0; strncmp(str, prefix, strlen(prefix)) == 0;
} }
int gpiotools_request_linehandle(const char *device_name, unsigned int *lines,
unsigned int nlines, unsigned int flag,
struct gpiohandle_data *data,
const char *consumer_label);
int gpiotools_set_values(const int fd, struct gpiohandle_data *data);
int gpiotools_get_values(const int fd, struct gpiohandle_data *data);
int gpiotools_release_linehandle(const int fd);
int gpiotools_get(const char *device_name, unsigned int line);
int gpiotools_gets(const char *device_name, unsigned int *lines,
unsigned int nlines, struct gpiohandle_data *data);
int gpiotools_set(const char *device_name, unsigned int line,
unsigned int value);
int gpiotools_sets(const char *device_name, unsigned int *lines,
unsigned int nlines, struct gpiohandle_data *data);
#endif /* _GPIO_UTILS_H_ */ #endif /* _GPIO_UTILS_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment