Commit 1cd04d29 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull GPIO updates from Linus Walleij:
 "This is the bulk of GPIO changes for the v4.8 kernel cycle.  The big
  news is the completion of the chardev ABI which I'm very happy about
  and apart from that it's an ordinary, quite busy cycle.  The details
  are below.

  The patches are tested in linux-next for some time, patches to other
  subsystem mostly have ACKs.

  I got overly ambitious with configureing lines as input for IRQ lines
  but it turns out that some controllers have their interrupt-enable and
  input-enabling in orthogonal settings so the assumption that all IRQ
  lines are input lines does not hold.  Oh well, revert and back to the
  drawing board with that.

  Core changes:

   - The big item is of course the completion of the character device
     ABI.  It has now replaced and surpassed the former unmaintainable
     sysfs ABI: we can now hammer (bitbang) individual lines or sets of
     lines and read individual lines or sets of lines from userspace,
     and we can also register to listen to GPIO events from userspace.

     As a tie-in we have two new tools in tools/gpio: gpio-hammer and
     gpio-event-mon that illustrate the proper use of the new ABI.  As
     someone said: the wild west days of GPIO are now over.

   - Continued to remove the pointless ARCH_[WANT_OPTIONAL|REQUIRE]_GPIOLIB
     Kconfig symbols.  I'm patching hexagon, openrisc, powerpc, sh,
     unicore, ia64 and microblaze.  These are either ACKed by their
     maintainers or patched anyways after a grace period and no response
     from maintainers.

     Some archs (ARM) come in from their trees, and others (x86) are
     still not fixed, so I might send a second pull request to root it
     out later in this merge window, or just defer to v4.9.

   - The GPIO tools are moved to the tools build system.

  New drivers:

   - New driver for the MAX77620/MAX20024.

   - New driver for the Intel Merrifield.

   - Enabled PCA953x for the TI PCA9536.

   - Enabled PCA953x for the Intel Edison.

   - Enabled R8A7792 in the RCAR driver.

  Driver improvements:

   - The STMPE and F7188x now supports the .get_direction() callback.

   - The Xilinx driver supports setting multiple lines at once.

   - ACPI support for the Vulcan GPIO controller.

   - The MMIO GPIO driver supports device tree probing.

   - The Acer One 10 is supported through the _DEP ACPI attribute.

  Cleanups:

   - A major cleanup of the OF/DT support code.  It is way easier to
     read and understand now, probably this improves performance too.

   - Drop a few redundant .owner assignments.

   - Remove CLPS711x boardfile support: we are 100% DT"

* tag 'gpio-v4.8-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (67 commits)
  MAINTAINERS: Add INTEL MERRIFIELD GPIO entry
  gpio: dwapb: add missing fwnode_handle_put() in dwapb_gpio_get_pdata()
  gpio: merrifield: Protect irq_ack() and gpio_set() by lock
  gpio: merrifield: Introduce GPIO driver to support Merrifield
  gpio: intel-mid: Make it depend to X86_INTEL_MID
  gpio: intel-mid: Sort header block alphabetically
  gpio: intel-mid: Remove potentially harmful code
  gpio: rcar: add R8A7792 support
  gpiolib: remove duplicated include from gpiolib.c
  Revert "gpio: convince line to become input in irq helper"
  gpiolib: of_find_gpio(): Don't discard errors
  gpio: of: Allow overriding the device node
  gpio: free handles in fringe cases
  gpio: tps65218: Add platform_device_id table
  gpio: max77620: get gpio value based on direction
  gpio: lynxpoint: avoid potential warning on error path
  tools/gpio: add install section
  tools/gpio: move to tools buildsystem
  gpio: intel-mid: switch to devm_gpiochip_add_data()
  gpio: 74x164: Use spi_write() helper instead of open coding
  ...
parents 9c1958fc 224f9e6d
* ARM Cirrus Logic CLPS711X SYSFLG1 MCTRL GPIOs * ARM Cirrus Logic CLPS711X SYSFLG1 MCTRL GPIOs
Required properties: Required properties:
- compatible: Should contain "cirrus,clps711x-mctrl-gpio". - compatible: Should contain "cirrus,ep7209-mctrl-gpio".
- gpio-controller: Marks the device node as a gpio controller. - gpio-controller: Marks the device node as a gpio controller.
- #gpio-cells: Should be two. The first cell is the pin number and - #gpio-cells: Should be two. The first cell is the pin number and
the second cell is used to specify the gpio polarity: the second cell is used to specify the gpio polarity:
...@@ -11,7 +11,7 @@ Required properties: ...@@ -11,7 +11,7 @@ Required properties:
Example: Example:
sysgpio: sysgpio { sysgpio: sysgpio {
compatible = "cirrus,ep7312-mctrl-gpio", compatible = "cirrus,ep7312-mctrl-gpio",
"cirrus,clps711x-mctrl-gpio"; "cirrus,ep7209-mctrl-gpio";
gpio-controller; gpio-controller;
#gpio-cells = <2>; #gpio-cells = <2>;
}; };
Cirrus Logic CLPS711X GPIO controller Cirrus Logic CLPS711X GPIO controller
Required properties: Required properties:
- compatible: Should be "cirrus,clps711x-gpio" - compatible: Should be "cirrus,ep7209-gpio"
- reg: Physical base GPIO controller registers location and length. - reg: Physical base GPIO controller registers location and length.
There should be two registers, first is DATA register, the second There should be two registers, first is DATA register, the second
is DIRECTION. is DIRECTION.
...@@ -21,7 +21,7 @@ aliases { ...@@ -21,7 +21,7 @@ aliases {
}; };
porta: gpio@80000000 { porta: gpio@80000000 {
compatible = "cirrus,clps711x-gpio"; compatible = "cirrus,ep7312-gpio","cirrus,ep7209-gpio";
reg = <0x80000000 0x1>, <0x80000040 0x1>; reg = <0x80000000 0x1>, <0x80000040 0x1>;
gpio-controller; gpio-controller;
#gpio-cells = <2>; #gpio-cells = <2>;
......
GPIO driver for MAX77620 Power management IC from Maxim Semiconductor.
Device has 8 GPIO pins which can be configured as GPIO as well as the
special IO functions.
Required properties:
-------------------
- gpio-controller : Marks the device node as a gpio controller.
- #gpio-cells : Should be two. The first cell is the pin number and
the second cell is used to specify the gpio polarity:
0 = active high
1 = active low
For more details, please refer generic GPIO DT binding document
<devicetree/bindings/gpio/gpio.txt>.
Example:
--------
#include <dt-bindings/mfd/max77620.h>
...
max77620@3c {
compatible = "maxim,max77620";
gpio-controller;
#gpio-cells = <2>;
};
...@@ -21,6 +21,7 @@ Required properties: ...@@ -21,6 +21,7 @@ Required properties:
maxim,max7313 maxim,max7313
maxim,max7315 maxim,max7315
ti,pca6107 ti,pca6107
ti,pca9536
ti,tca6408 ti,tca6408
ti,tca6416 ti,tca6416
ti,tca6424 ti,tca6424
......
...@@ -7,6 +7,7 @@ Required Properties: ...@@ -7,6 +7,7 @@ Required Properties:
- "renesas,gpio-r8a7779": for R8A7779 (R-Car H1) compatible GPIO controller. - "renesas,gpio-r8a7779": for R8A7779 (R-Car H1) compatible GPIO controller.
- "renesas,gpio-r8a7790": for R8A7790 (R-Car H2) compatible GPIO controller. - "renesas,gpio-r8a7790": for R8A7790 (R-Car H2) compatible GPIO controller.
- "renesas,gpio-r8a7791": for R8A7791 (R-Car M2-W) compatible GPIO controller. - "renesas,gpio-r8a7791": for R8A7791 (R-Car M2-W) compatible GPIO controller.
- "renesas,gpio-r8a7792": for R8A7792 (R-Car V2H) compatible GPIO controller.
- "renesas,gpio-r8a7793": for R8A7793 (R-Car M2-N) compatible GPIO controller. - "renesas,gpio-r8a7793": for R8A7793 (R-Car M2-N) compatible GPIO controller.
- "renesas,gpio-r8a7794": for R8A7794 (R-Car E2) compatible GPIO controller. - "renesas,gpio-r8a7794": for R8A7794 (R-Car E2) compatible GPIO controller.
- "renesas,gpio-r8a7795": for R8A7795 (R-Car H3) compatible GPIO controller. - "renesas,gpio-r8a7795": for R8A7795 (R-Car H3) compatible GPIO controller.
......
...@@ -37,15 +37,16 @@ hardware descriptions such as device tree or ACPI: ...@@ -37,15 +37,16 @@ hardware descriptions such as device tree or ACPI:
external connector status, such as a headset line for an audio driver or an external connector status, such as a headset line for an audio driver or an
HDMI connector. It will provide a better userspace sysfs interface than GPIO. HDMI connector. It will provide a better userspace sysfs interface than GPIO.
- restart-gpio: drivers/power/gpio-restart.c is used to restart/reboot the - restart-gpio: drivers/power/reset/gpio-restart.c is used to restart/reboot
system by pulling a GPIO line and will register a restart handler so the system by pulling a GPIO line and will register a restart handler so
userspace can issue the right system call to restart the system. userspace can issue the right system call to restart the system.
- poweroff-gpio: drivers/power/gpio-poweroff.c is used to power the system down - poweroff-gpio: drivers/power/reset/gpio-poweroff.c is used to power the
by pulling a GPIO line and will register a pm_power_off() callback so that system down by pulling a GPIO line and will register a pm_power_off()
userspace can issue the right system call to power down the system. callback so that userspace can issue the right system call to power down the
system.
- gpio-gate-clock: drivers/clk/clk-gpio-gate.c is used to control a gated clock - gpio-gate-clock: drivers/clk/clk-gpio.c is used to control a gated clock
(off/on) that uses a GPIO, and integrated with the clock subsystem. (off/on) that uses a GPIO, and integrated with the clock subsystem.
- i2c-gpio: drivers/i2c/busses/i2c-gpio.c is used to drive an I2C bus - i2c-gpio: drivers/i2c/busses/i2c-gpio.c is used to drive an I2C bus
......
...@@ -6060,6 +6060,12 @@ L: linux-rdma@vger.kernel.org ...@@ -6060,6 +6060,12 @@ L: linux-rdma@vger.kernel.org
S: Supported S: Supported
F: drivers/infiniband/hw/i40iw/ F: drivers/infiniband/hw/i40iw/
INTEL MERRIFIELD GPIO DRIVER
M: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
L: linux-gpio@vger.kernel.org
S: Maintained
F: drivers/gpio/gpio-merrifield.c
INTEL-MID GPIO DRIVER INTEL-MID GPIO DRIVER
M: David Cohen <david.a.cohen@linux.intel.com> M: David Cohen <david.a.cohen@linux.intel.com>
L: linux-gpio@vger.kernel.org L: linux-gpio@vger.kernel.org
......
...@@ -8,8 +8,7 @@ config HEXAGON ...@@ -8,8 +8,7 @@ config HEXAGON
# select HAVE_REGS_AND_STACK_ACCESS_API # select HAVE_REGS_AND_STACK_ACCESS_API
# select HAVE_HW_BREAKPOINT if PERF_EVENTS # select HAVE_HW_BREAKPOINT if PERF_EVENTS
# select ARCH_HAS_CPU_IDLE_WAIT # select ARCH_HAS_CPU_IDLE_WAIT
# select ARCH_WANT_OPTIONAL_GPIOLIB # select GPIOLIB
# select ARCH_REQUIRE_GPIOLIB
# select HAVE_CLK # select HAVE_CLK
# select GENERIC_PENDING_IRQ if SMP # select GENERIC_PENDING_IRQ if SMP
select GENERIC_ATOMIC64 select GENERIC_ATOMIC64
......
...@@ -39,7 +39,6 @@ config IA64 ...@@ -39,7 +39,6 @@ config IA64
select GENERIC_PENDING_IRQ if SMP select GENERIC_PENDING_IRQ if SMP
select GENERIC_IRQ_SHOW select GENERIC_IRQ_SHOW
select GENERIC_IRQ_LEGACY select GENERIC_IRQ_LEGACY
select ARCH_WANT_OPTIONAL_GPIOLIB
select ARCH_HAVE_NMI_SAFE_CMPXCHG select ARCH_HAVE_NMI_SAFE_CMPXCHG
select GENERIC_IOMAP select GENERIC_IOMAP
select GENERIC_SMP_IDLE_THREAD select GENERIC_SMP_IDLE_THREAD
......
...@@ -3,7 +3,6 @@ config MICROBLAZE ...@@ -3,7 +3,6 @@ config MICROBLAZE
select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_HAS_GCOV_PROFILE_ALL
select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_MIGHT_HAVE_PC_PARPORT
select ARCH_WANT_IPC_PARSE_VERSION select ARCH_WANT_IPC_PARSE_VERSION
select ARCH_WANT_OPTIONAL_GPIOLIB
select BUILDTIME_EXTABLE_SORT select BUILDTIME_EXTABLE_SORT
select CLKSRC_OF select CLKSRC_OF
select CLONE_BACKWARDS3 select CLONE_BACKWARDS3
......
...@@ -10,7 +10,7 @@ config OPENRISC ...@@ -10,7 +10,7 @@ config OPENRISC
select IRQ_DOMAIN select IRQ_DOMAIN
select HANDLE_DOMAIN_IRQ select HANDLE_DOMAIN_IRQ
select HAVE_MEMBLOCK select HAVE_MEMBLOCK
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
select HAVE_ARCH_TRACEHOOK select HAVE_ARCH_TRACEHOOK
select GENERIC_IRQ_CHIP select GENERIC_IRQ_CHIP
select GENERIC_IRQ_PROBE select GENERIC_IRQ_PROBE
......
...@@ -98,7 +98,6 @@ config PPC ...@@ -98,7 +98,6 @@ config PPC
select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_TRACER
select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FUNCTION_GRAPH_TRACER
select SYSCTL_EXCEPTION_TRACE select SYSCTL_EXCEPTION_TRACE
select ARCH_WANT_OPTIONAL_GPIOLIB
select VIRT_TO_BUS if !PPC64 select VIRT_TO_BUS if !PPC64
select HAVE_IDE select HAVE_IDE
select HAVE_IOREMAP_PROT select HAVE_IOREMAP_PROT
......
...@@ -137,7 +137,7 @@ config STB03xxx ...@@ -137,7 +137,7 @@ config STB03xxx
config PPC4xx_GPIO config PPC4xx_GPIO
bool "PPC4xx GPIO support" bool "PPC4xx GPIO support"
depends on 40x depends on 40x
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
help help
Enable gpiolib support for ppc40x based boards Enable gpiolib support for ppc40x based boards
......
...@@ -273,7 +273,7 @@ config PPC44x_SIMPLE ...@@ -273,7 +273,7 @@ config PPC44x_SIMPLE
config PPC4xx_GPIO config PPC4xx_GPIO
bool "PPC4xx GPIO support" bool "PPC4xx GPIO support"
depends on 44x depends on 44x
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
help help
Enable gpiolib support for ppc440 based boards Enable gpiolib support for ppc440 based boards
......
...@@ -6,7 +6,6 @@ config PPC_MPC512x ...@@ -6,7 +6,6 @@ config PPC_MPC512x
select IPIC select IPIC
select PPC_PCI_CHOICE select PPC_PCI_CHOICE
select FSL_PCI if PCI select FSL_PCI if PCI
select ARCH_WANT_OPTIONAL_GPIOLIB
select USB_EHCI_BIG_ENDIAN_MMIO if USB_EHCI_HCD select USB_EHCI_BIG_ENDIAN_MMIO if USB_EHCI_HCD
select USB_EHCI_BIG_ENDIAN_DESC if USB_EHCI_HCD select USB_EHCI_BIG_ENDIAN_DESC if USB_EHCI_HCD
......
...@@ -116,7 +116,6 @@ endif ...@@ -116,7 +116,6 @@ endif
# used for usb & gpio # used for usb & gpio
config PPC_MPC831x config PPC_MPC831x
bool bool
select ARCH_WANT_OPTIONAL_GPIOLIB
# used for math-emu # used for math-emu
config PPC_MPC832x config PPC_MPC832x
...@@ -125,9 +124,7 @@ config PPC_MPC832x ...@@ -125,9 +124,7 @@ config PPC_MPC832x
# used for usb & gpio # used for usb & gpio
config PPC_MPC834x config PPC_MPC834x
bool bool
select ARCH_WANT_OPTIONAL_GPIOLIB
# used for usb & gpio # used for usb & gpio
config PPC_MPC837x config PPC_MPC837x
bool bool
select ARCH_WANT_OPTIONAL_GPIOLIB
...@@ -225,7 +225,7 @@ config GE_IMP3A ...@@ -225,7 +225,7 @@ config GE_IMP3A
select DEFAULT_UIMAGE select DEFAULT_UIMAGE
select SWIOTLB select SWIOTLB
select MMIO_NVRAM select MMIO_NVRAM
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
select GE_FPGA select GE_FPGA
help help
This option enables support for the GE Intelligent Platforms IMP3A This option enables support for the GE Intelligent Platforms IMP3A
...@@ -272,7 +272,7 @@ config CORENET_GENERIC ...@@ -272,7 +272,7 @@ config CORENET_GENERIC
select PPC_E500MC select PPC_E500MC
select PHYS_64BIT select PHYS_64BIT
select SWIOTLB select SWIOTLB
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
select GPIO_MPC8XXX select GPIO_MPC8XXX
select HAS_RAPIDIO select HAS_RAPIDIO
select PPC_EPAPR_HV_PIC select PPC_EPAPR_HV_PIC
......
...@@ -4,7 +4,6 @@ menuconfig PPC_86xx ...@@ -4,7 +4,6 @@ menuconfig PPC_86xx
depends on 6xx depends on 6xx
select FSL_SOC select FSL_SOC
select ALTIVEC select ALTIVEC
select ARCH_WANT_OPTIONAL_GPIOLIB
help help
The Freescale E600 SoCs have 74xx cores. The Freescale E600 SoCs have 74xx cores.
...@@ -37,7 +36,7 @@ config GEF_PPC9A ...@@ -37,7 +36,7 @@ config GEF_PPC9A
bool "GE PPC9A" bool "GE PPC9A"
select DEFAULT_UIMAGE select DEFAULT_UIMAGE
select MMIO_NVRAM select MMIO_NVRAM
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
select GE_FPGA select GE_FPGA
help help
This option enables support for the GE PPC9A. This option enables support for the GE PPC9A.
...@@ -46,7 +45,7 @@ config GEF_SBC310 ...@@ -46,7 +45,7 @@ config GEF_SBC310
bool "GE SBC310" bool "GE SBC310"
select DEFAULT_UIMAGE select DEFAULT_UIMAGE
select MMIO_NVRAM select MMIO_NVRAM
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
select GE_FPGA select GE_FPGA
help help
This option enables support for the GE SBC310. This option enables support for the GE SBC310.
...@@ -55,7 +54,7 @@ config GEF_SBC610 ...@@ -55,7 +54,7 @@ config GEF_SBC610
bool "GE SBC610" bool "GE SBC610"
select DEFAULT_UIMAGE select DEFAULT_UIMAGE
select MMIO_NVRAM select MMIO_NVRAM
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
select GE_FPGA select GE_FPGA
select HAS_RAPIDIO select HAS_RAPIDIO
help help
......
...@@ -109,7 +109,7 @@ config 8xx_COPYBACK ...@@ -109,7 +109,7 @@ config 8xx_COPYBACK
config 8xx_GPIO config 8xx_GPIO
bool "GPIO API Support" bool "GPIO API Support"
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
help help
Saying Y here will cause the ports on an MPC8xx processor to be used Saying Y here will cause the ports on an MPC8xx processor to be used
with the GPIO API. If you say N here, the kernel needs less memory. with the GPIO API. If you say N here, the kernel needs less memory.
......
...@@ -275,7 +275,7 @@ config TAU_AVERAGE ...@@ -275,7 +275,7 @@ config TAU_AVERAGE
config QE_GPIO config QE_GPIO
bool "QE GPIO support" bool "QE GPIO support"
depends on QUICC_ENGINE depends on QUICC_ENGINE
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
help help
Say Y here if you're going to use hardware that connects to the Say Y here if you're going to use hardware that connects to the
QE GPIOs. QE GPIOs.
...@@ -285,7 +285,7 @@ config CPM2 ...@@ -285,7 +285,7 @@ config CPM2
depends on (FSL_SOC_BOOKE && PPC32) || 8260 depends on (FSL_SOC_BOOKE && PPC32) || 8260
select CPM select CPM
select PPC_PCI_CHOICE select PPC_PCI_CHOICE
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
help help
The CPM2 (Communications Processor Module) is a coprocessor on The CPM2 (Communications Processor Module) is a coprocessor on
embedded CPUs made by Freescale. Selecting this option means that embedded CPUs made by Freescale. Selecting this option means that
...@@ -324,7 +324,7 @@ config OF_RTC ...@@ -324,7 +324,7 @@ config OF_RTC
config SIMPLE_GPIO config SIMPLE_GPIO
bool "Support for simple, memory-mapped GPIO controllers" bool "Support for simple, memory-mapped GPIO controllers"
depends on PPC depends on PPC
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
help help
Say Y here to support simple, memory-mapped GPIO controllers. Say Y here to support simple, memory-mapped GPIO controllers.
These are usually BCSRs used to control board's switches, LEDs, These are usually BCSRs used to control board's switches, LEDs,
...@@ -334,7 +334,7 @@ config SIMPLE_GPIO ...@@ -334,7 +334,7 @@ config SIMPLE_GPIO
config MCU_MPC8349EMITX config MCU_MPC8349EMITX
bool "MPC8349E-mITX MCU driver" bool "MPC8349E-mITX MCU driver"
depends on I2C=y && PPC_83xx depends on I2C=y && PPC_83xx
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
help help
Say Y here to enable soft power-off functionality on the Freescale Say Y here to enable soft power-off functionality on the Freescale
boards with the MPC8349E-mITX-compatible MCU chips. This driver will boards with the MPC8349E-mITX-compatible MCU chips. This driver will
......
...@@ -264,7 +264,6 @@ config CPU_SUBTYPE_SH7203 ...@@ -264,7 +264,6 @@ config CPU_SUBTYPE_SH7203
select CPU_HAS_FPU select CPU_HAS_FPU
select SYS_SUPPORTS_SH_CMT select SYS_SUPPORTS_SH_CMT
select SYS_SUPPORTS_SH_MTU2 select SYS_SUPPORTS_SH_MTU2
select ARCH_WANT_OPTIONAL_GPIOLIB
select PINCTRL select PINCTRL
config CPU_SUBTYPE_SH7206 config CPU_SUBTYPE_SH7206
...@@ -353,7 +352,6 @@ config CPU_SUBTYPE_SH7720 ...@@ -353,7 +352,6 @@ config CPU_SUBTYPE_SH7720
select CPU_SH3 select CPU_SH3
select CPU_HAS_DSP select CPU_HAS_DSP
select SYS_SUPPORTS_SH_CMT select SYS_SUPPORTS_SH_CMT
select ARCH_WANT_OPTIONAL_GPIOLIB
select USB_OHCI_SH if USB_OHCI_HCD select USB_OHCI_SH if USB_OHCI_HCD
select PINCTRL select PINCTRL
help help
...@@ -419,7 +417,6 @@ config CPU_SUBTYPE_SH7723 ...@@ -419,7 +417,6 @@ config CPU_SUBTYPE_SH7723
select ARCH_SHMOBILE select ARCH_SHMOBILE
select ARCH_SPARSEMEM_ENABLE select ARCH_SPARSEMEM_ENABLE
select SYS_SUPPORTS_SH_CMT select SYS_SUPPORTS_SH_CMT
select ARCH_WANT_OPTIONAL_GPIOLIB
select PINCTRL select PINCTRL
help help
Select SH7723 if you have an SH-MobileR2 CPU. Select SH7723 if you have an SH-MobileR2 CPU.
...@@ -431,7 +428,6 @@ config CPU_SUBTYPE_SH7724 ...@@ -431,7 +428,6 @@ config CPU_SUBTYPE_SH7724
select ARCH_SHMOBILE select ARCH_SHMOBILE
select ARCH_SPARSEMEM_ENABLE select ARCH_SPARSEMEM_ENABLE
select SYS_SUPPORTS_SH_CMT select SYS_SUPPORTS_SH_CMT
select ARCH_WANT_OPTIONAL_GPIOLIB
select PINCTRL select PINCTRL
help help
Select SH7724 if you have an SH-MobileR2R CPU. Select SH7724 if you have an SH-MobileR2R CPU.
...@@ -440,7 +436,6 @@ config CPU_SUBTYPE_SH7734 ...@@ -440,7 +436,6 @@ config CPU_SUBTYPE_SH7734
bool "Support SH7734 processor" bool "Support SH7734 processor"
select CPU_SH4A select CPU_SH4A
select CPU_SHX2 select CPU_SHX2
select ARCH_WANT_OPTIONAL_GPIOLIB
select PINCTRL select PINCTRL
help help
Select SH7734 if you have a SH4A SH7734 CPU. Select SH7734 if you have a SH4A SH7734 CPU.
...@@ -449,7 +444,6 @@ config CPU_SUBTYPE_SH7757 ...@@ -449,7 +444,6 @@ config CPU_SUBTYPE_SH7757
bool "Support SH7757 processor" bool "Support SH7757 processor"
select CPU_SH4A select CPU_SH4A
select CPU_SHX2 select CPU_SHX2
select ARCH_WANT_OPTIONAL_GPIOLIB
select PINCTRL select PINCTRL
help help
Select SH7757 if you have a SH4A SH7757 CPU. Select SH7757 if you have a SH4A SH7757 CPU.
...@@ -475,7 +469,6 @@ config CPU_SUBTYPE_SH7785 ...@@ -475,7 +469,6 @@ config CPU_SUBTYPE_SH7785
select CPU_SHX2 select CPU_SHX2
select ARCH_SPARSEMEM_ENABLE select ARCH_SPARSEMEM_ENABLE
select SYS_SUPPORTS_NUMA select SYS_SUPPORTS_NUMA
select ARCH_WANT_OPTIONAL_GPIOLIB
select PINCTRL select PINCTRL
config CPU_SUBTYPE_SH7786 config CPU_SUBTYPE_SH7786
...@@ -484,7 +477,6 @@ config CPU_SUBTYPE_SH7786 ...@@ -484,7 +477,6 @@ config CPU_SUBTYPE_SH7786
select CPU_SHX3 select CPU_SHX3
select CPU_HAS_PTEAEX select CPU_HAS_PTEAEX
select GENERIC_CLOCKEVENTS_BROADCAST if SMP select GENERIC_CLOCKEVENTS_BROADCAST if SMP
select ARCH_WANT_OPTIONAL_GPIOLIB
select USB_OHCI_SH if USB_OHCI_HCD select USB_OHCI_SH if USB_OHCI_HCD
select USB_EHCI_SH if USB_EHCI_HCD select USB_EHCI_SH if USB_EHCI_HCD
select PINCTRL select PINCTRL
...@@ -494,7 +486,7 @@ config CPU_SUBTYPE_SHX3 ...@@ -494,7 +486,7 @@ config CPU_SUBTYPE_SHX3
select CPU_SH4A select CPU_SH4A
select CPU_SHX3 select CPU_SHX3
select GENERIC_CLOCKEVENTS_BROADCAST if SMP select GENERIC_CLOCKEVENTS_BROADCAST if SMP
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
select PINCTRL select PINCTRL
# SH4AL-DSP Processor Support # SH4AL-DSP Processor Support
...@@ -513,7 +505,6 @@ config CPU_SUBTYPE_SH7722 ...@@ -513,7 +505,6 @@ config CPU_SUBTYPE_SH7722
select ARCH_SPARSEMEM_ENABLE select ARCH_SPARSEMEM_ENABLE
select SYS_SUPPORTS_NUMA select SYS_SUPPORTS_NUMA
select SYS_SUPPORTS_SH_CMT select SYS_SUPPORTS_SH_CMT
select ARCH_WANT_OPTIONAL_GPIOLIB
select PINCTRL select PINCTRL
config CPU_SUBTYPE_SH7366 config CPU_SUBTYPE_SH7366
......
...@@ -70,7 +70,7 @@ config SH_7724_SOLUTION_ENGINE ...@@ -70,7 +70,7 @@ config SH_7724_SOLUTION_ENGINE
bool "SolutionEngine7724" bool "SolutionEngine7724"
select SOLUTION_ENGINE select SOLUTION_ENGINE
depends on CPU_SUBTYPE_SH7724 depends on CPU_SUBTYPE_SH7724
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
select SND_SOC_AK4642 if SND_SIMPLE_CARD select SND_SOC_AK4642 if SND_SIMPLE_CARD
select REGULATOR_FIXED_VOLTAGE if REGULATOR select REGULATOR_FIXED_VOLTAGE if REGULATOR
help help
...@@ -174,7 +174,6 @@ config SH_SDK7786 ...@@ -174,7 +174,6 @@ config SH_SDK7786
depends on CPU_SUBTYPE_SH7786 depends on CPU_SUBTYPE_SH7786
select SYS_SUPPORTS_PCI select SYS_SUPPORTS_PCI
select NO_IOPORT_MAP if !PCI select NO_IOPORT_MAP if !PCI
select ARCH_WANT_OPTIONAL_GPIOLIB
select HAVE_SRAM_POOL select HAVE_SRAM_POOL
select REGULATOR_FIXED_VOLTAGE if REGULATOR select REGULATOR_FIXED_VOLTAGE if REGULATOR
help help
...@@ -190,7 +189,7 @@ config SH_HIGHLANDER ...@@ -190,7 +189,7 @@ config SH_HIGHLANDER
config SH_SH7757LCR config SH_SH7757LCR
bool "SH7757LCR" bool "SH7757LCR"
depends on CPU_SUBTYPE_SH7757 depends on CPU_SUBTYPE_SH7757
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
select REGULATOR_FIXED_VOLTAGE if REGULATOR select REGULATOR_FIXED_VOLTAGE if REGULATOR
config SH_SH7785LCR config SH_SH7785LCR
...@@ -217,14 +216,14 @@ config SH_SH7785LCR_PT ...@@ -217,14 +216,14 @@ config SH_SH7785LCR_PT
config SH_URQUELL config SH_URQUELL
bool "Urquell" bool "Urquell"
depends on CPU_SUBTYPE_SH7786 depends on CPU_SUBTYPE_SH7786
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
select SYS_SUPPORTS_PCI select SYS_SUPPORTS_PCI
select NO_IOPORT_MAP if !PCI select NO_IOPORT_MAP if !PCI
config SH_MIGOR config SH_MIGOR
bool "Migo-R" bool "Migo-R"
depends on CPU_SUBTYPE_SH7722 depends on CPU_SUBTYPE_SH7722
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
select REGULATOR_FIXED_VOLTAGE if REGULATOR select REGULATOR_FIXED_VOLTAGE if REGULATOR
help help
Select Migo-R if configuring for the SH7722 Migo-R platform Select Migo-R if configuring for the SH7722 Migo-R platform
...@@ -233,7 +232,7 @@ config SH_MIGOR ...@@ -233,7 +232,7 @@ config SH_MIGOR
config SH_AP325RXA config SH_AP325RXA
bool "AP-325RXA" bool "AP-325RXA"
depends on CPU_SUBTYPE_SH7723 depends on CPU_SUBTYPE_SH7723
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
select REGULATOR_FIXED_VOLTAGE if REGULATOR select REGULATOR_FIXED_VOLTAGE if REGULATOR
help help
Renesas "AP-325RXA" support. Renesas "AP-325RXA" support.
...@@ -242,7 +241,7 @@ config SH_AP325RXA ...@@ -242,7 +241,7 @@ config SH_AP325RXA
config SH_KFR2R09 config SH_KFR2R09
bool "KFR2R09" bool "KFR2R09"
depends on CPU_SUBTYPE_SH7724 depends on CPU_SUBTYPE_SH7724
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
select REGULATOR_FIXED_VOLTAGE if REGULATOR select REGULATOR_FIXED_VOLTAGE if REGULATOR
help help
"Kit For R2R for 2009" support. "Kit For R2R for 2009" support.
...@@ -250,7 +249,7 @@ config SH_KFR2R09 ...@@ -250,7 +249,7 @@ config SH_KFR2R09
config SH_ECOVEC config SH_ECOVEC
bool "EcoVec" bool "EcoVec"
depends on CPU_SUBTYPE_SH7724 depends on CPU_SUBTYPE_SH7724
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
select SND_SOC_DA7210 if SND_SIMPLE_CARD select SND_SOC_DA7210 if SND_SIMPLE_CARD
select REGULATOR_FIXED_VOLTAGE if REGULATOR select REGULATOR_FIXED_VOLTAGE if REGULATOR
help help
...@@ -327,7 +326,7 @@ config SH_X3PROTO ...@@ -327,7 +326,7 @@ config SH_X3PROTO
config SH_MAGIC_PANEL_R2 config SH_MAGIC_PANEL_R2
bool "Magic Panel R2" bool "Magic Panel R2"
depends on CPU_SUBTYPE_SH7720 depends on CPU_SUBTYPE_SH7720
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
select REGULATOR_FIXED_VOLTAGE if REGULATOR select REGULATOR_FIXED_VOLTAGE if REGULATOR
help help
Select Magic Panel R2 if configuring for Magic Panel R2. Select Magic Panel R2 if configuring for Magic Panel R2.
......
...@@ -18,7 +18,7 @@ config SH_R7780MP ...@@ -18,7 +18,7 @@ config SH_R7780MP
config SH_R7785RP config SH_R7785RP
bool "R7785RP board support" bool "R7785RP board support"
depends on CPU_SUBTYPE_SH7785 depends on CPU_SUBTYPE_SH7785
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
endchoice endchoice
......
...@@ -10,17 +10,17 @@ config SH_RSK7201 ...@@ -10,17 +10,17 @@ config SH_RSK7201
config SH_RSK7203 config SH_RSK7203
bool "RSK7203" bool "RSK7203"
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
depends on CPU_SUBTYPE_SH7203 depends on CPU_SUBTYPE_SH7203
config SH_RSK7264 config SH_RSK7264
bool "RSK2+SH7264" bool "RSK2+SH7264"
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
depends on CPU_SUBTYPE_SH7264 depends on CPU_SUBTYPE_SH7264
config SH_RSK7269 config SH_RSK7269
bool "RSK2+SH7269" bool "RSK2+SH7269"
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
depends on CPU_SUBTYPE_SH7269 depends on CPU_SUBTYPE_SH7269
endchoice endchoice
......
...@@ -80,7 +80,7 @@ config ARCH_PUV3 ...@@ -80,7 +80,7 @@ config ARCH_PUV3
select CPU_UCV2 select CPU_UCV2
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select HAVE_CLK select HAVE_CLK
select ARCH_REQUIRE_GPIOLIB select GPIOLIB
# CONFIGs for ARCH_PUV3 # CONFIGs for ARCH_PUV3
......
...@@ -12,7 +12,7 @@ obj-$(CONFIG_GENERIC_PHY) += phy/ ...@@ -12,7 +12,7 @@ obj-$(CONFIG_GENERIC_PHY) += phy/
# GPIO must come after pinctrl as gpios may need to mux pins etc # GPIO must come after pinctrl as gpios may need to mux pins etc
obj-$(CONFIG_PINCTRL) += pinctrl/ obj-$(CONFIG_PINCTRL) += pinctrl/
obj-y += gpio/ obj-$(CONFIG_GPIOLIB) += gpio/
obj-y += pwm/ obj-y += pwm/
obj-$(CONFIG_PCI) += pci/ obj-$(CONFIG_PCI) += pci/
obj-$(CONFIG_PARISC) += parisc/ obj-$(CONFIG_PARISC) += parisc/
......
...@@ -250,7 +250,7 @@ config GPIO_LOONGSON ...@@ -250,7 +250,7 @@ config GPIO_LOONGSON
driver for GPIO functionality on Loongson-2F/3A/3B processors. driver for GPIO functionality on Loongson-2F/3A/3B processors.
config GPIO_LPC18XX config GPIO_LPC18XX
bool "NXP LPC18XX/43XX GPIO support" tristate "NXP LPC18XX/43XX GPIO support"
default y if ARCH_LPC18XX default y if ARCH_LPC18XX
depends on OF_GPIO && (ARCH_LPC18XX || COMPILE_TEST) depends on OF_GPIO && (ARCH_LPC18XX || COMPILE_TEST)
help help
...@@ -874,6 +874,15 @@ config GPIO_LP3943 ...@@ -874,6 +874,15 @@ config GPIO_LP3943
LP3943 can be used as a GPIO expander which provides up to 16 GPIOs. LP3943 can be used as a GPIO expander which provides up to 16 GPIOs.
Open drain outputs are required for this usage. Open drain outputs are required for this usage.
config GPIO_MAX77620
tristate "GPIO support for PMIC MAX77620 and MAX20024"
depends on MFD_MAX77620
help
GPIO driver for MAX77620 and MAX20024 PMIC from Maxim Semiconductor.
MAX77620 PMIC has 8 pins that can be configured as GPIOs. The
driver also provides interrupt support for each of the gpios.
Say yes here to enable the max77620 to be used as gpio controller.
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 MFD_INTEL_MSIC
...@@ -1029,11 +1038,18 @@ config GPIO_BT8XX ...@@ -1029,11 +1038,18 @@ config GPIO_BT8XX
If unsure, say N. If unsure, say N.
config GPIO_INTEL_MID config GPIO_INTEL_MID
bool "Intel Mid GPIO support" bool "Intel MID GPIO support"
depends on X86 depends on X86_INTEL_MID
select GPIOLIB_IRQCHIP
help
Say Y here to support Intel MID GPIO.
config GPIO_MERRIFIELD
tristate "Intel Merrifield GPIO support"
depends on X86_INTEL_MID
select GPIOLIB_IRQCHIP select GPIOLIB_IRQCHIP
help help
Say Y here to support Intel Mid GPIO. Say Y here to support Intel Merrifield GPIO.
config GPIO_ML_IOH config GPIO_ML_IOH
tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support" tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support"
......
...@@ -61,8 +61,10 @@ obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o ...@@ -61,8 +61,10 @@ obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o
obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o
obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o
obj-$(CONFIG_GPIO_MAX732X) += gpio-max732x.o obj-$(CONFIG_GPIO_MAX732X) += gpio-max732x.o
obj-$(CONFIG_GPIO_MAX77620) += gpio-max77620.o
obj-$(CONFIG_GPIO_MB86S7X) += gpio-mb86s7x.o obj-$(CONFIG_GPIO_MB86S7X) += gpio-mb86s7x.o
obj-$(CONFIG_GPIO_MENZ127) += gpio-menz127.o obj-$(CONFIG_GPIO_MENZ127) += gpio-menz127.o
obj-$(CONFIG_GPIO_MERRIFIELD) += gpio-merrifield.o
obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o
obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o
obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o
......
...@@ -35,13 +35,8 @@ struct gen_74x164_chip { ...@@ -35,13 +35,8 @@ struct gen_74x164_chip {
static int __gen_74x164_write_config(struct gen_74x164_chip *chip) static int __gen_74x164_write_config(struct gen_74x164_chip *chip)
{ {
struct spi_transfer xfer = { return spi_write(to_spi_device(chip->gpio_chip.parent), chip->buffer,
.tx_buf = chip->buffer, chip->registers);
.len = chip->registers,
};
return spi_sync_transfer(to_spi_device(chip->gpio_chip.parent),
&xfer, 1);
} }
static int gen_74x164_get_value(struct gpio_chip *gc, unsigned offset) static int gen_74x164_get_value(struct gpio_chip *gc, unsigned offset)
......
...@@ -20,8 +20,12 @@ static int clps711x_gpio_probe(struct platform_device *pdev) ...@@ -20,8 +20,12 @@ static int clps711x_gpio_probe(struct platform_device *pdev)
void __iomem *dat, *dir; void __iomem *dat, *dir;
struct gpio_chip *gc; struct gpio_chip *gc;
struct resource *res; struct resource *res;
int err, id = np ? of_alias_get_id(np, "gpio") : pdev->id; int err, id;
if (!np)
return -ENODEV;
id = of_alias_get_id(np, "gpio");
if ((id < 0) || (id > 4)) if ((id < 0) || (id > 4))
return -ENODEV; return -ENODEV;
...@@ -63,7 +67,7 @@ static int clps711x_gpio_probe(struct platform_device *pdev) ...@@ -63,7 +67,7 @@ static int clps711x_gpio_probe(struct platform_device *pdev)
break; break;
} }
gc->base = id * 8; gc->base = -1;
gc->owner = THIS_MODULE; gc->owner = THIS_MODULE;
platform_set_drvdata(pdev, gc); platform_set_drvdata(pdev, gc);
...@@ -71,7 +75,7 @@ static int clps711x_gpio_probe(struct platform_device *pdev) ...@@ -71,7 +75,7 @@ static int clps711x_gpio_probe(struct platform_device *pdev)
} }
static const struct of_device_id __maybe_unused clps711x_gpio_ids[] = { static const struct of_device_id __maybe_unused clps711x_gpio_ids[] = {
{ .compatible = "cirrus,clps711x-gpio" }, { .compatible = "cirrus,ep7209-gpio" },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, clps711x_gpio_ids); MODULE_DEVICE_TABLE(of, clps711x_gpio_ids);
......
...@@ -486,6 +486,7 @@ dwapb_gpio_get_pdata(struct device *dev) ...@@ -486,6 +486,7 @@ dwapb_gpio_get_pdata(struct device *dev)
pp->idx >= DWAPB_MAX_PORTS) { pp->idx >= DWAPB_MAX_PORTS) {
dev_err(dev, dev_err(dev,
"missing/invalid port index for port%d\n", i); "missing/invalid port index for port%d\n", i);
fwnode_handle_put(fwnode);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
......
...@@ -125,6 +125,7 @@ static inline void superio_exit(int base) ...@@ -125,6 +125,7 @@ static inline void superio_exit(int base)
* GPIO chip. * GPIO chip.
*/ */
static int f7188x_gpio_get_direction(struct gpio_chip *chip, unsigned offset);
static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset); static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset);
static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset); static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset);
static int f7188x_gpio_direction_out(struct gpio_chip *chip, static int f7188x_gpio_direction_out(struct gpio_chip *chip,
...@@ -139,6 +140,7 @@ static int f7188x_gpio_set_single_ended(struct gpio_chip *gc, ...@@ -139,6 +140,7 @@ static int f7188x_gpio_set_single_ended(struct gpio_chip *gc,
.chip = { \ .chip = { \
.label = DRVNAME, \ .label = DRVNAME, \
.owner = THIS_MODULE, \ .owner = THIS_MODULE, \
.get_direction = f7188x_gpio_get_direction, \
.direction_input = f7188x_gpio_direction_in, \ .direction_input = f7188x_gpio_direction_in, \
.get = f7188x_gpio_get, \ .get = f7188x_gpio_get, \
.direction_output = f7188x_gpio_direction_out, \ .direction_output = f7188x_gpio_direction_out, \
...@@ -209,6 +211,26 @@ static struct f7188x_gpio_bank f81866_gpio_bank[] = { ...@@ -209,6 +211,26 @@ static struct f7188x_gpio_bank f81866_gpio_bank[] = {
F7188X_GPIO_BANK(80, 8, 0x88), F7188X_GPIO_BANK(80, 8, 0x88),
}; };
static int f7188x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
{
int err;
struct f7188x_gpio_bank *bank =
container_of(chip, struct f7188x_gpio_bank, chip);
struct f7188x_sio *sio = bank->data->sio;
u8 dir;
err = superio_enter(sio->addr);
if (err)
return err;
superio_select(sio->addr, SIO_LD_GPIO);
dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
superio_exit(sio->addr);
return !(dir & 1 << offset);
}
static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset) static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
{ {
int err; int err;
......
/* /*
* Intel MID GPIO driver * Intel MID GPIO driver
* *
* Copyright (c) 2008-2014 Intel Corporation. * Copyright (c) 2008-2014,2016 Intel Corporation.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
...@@ -17,21 +17,20 @@ ...@@ -17,21 +17,20 @@
* Moorestown platform Langwell chip. * Moorestown platform Langwell chip.
* Medfield platform Penwell chip. * Medfield platform Penwell chip.
* Clovertrail platform Cloverview chip. * Clovertrail platform Cloverview chip.
* Merrifield platform Tangier chip.
*/ */
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/stddef.h>
#include <linux/interrupt.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/slab.h> #include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/stddef.h>
#define INTEL_MID_IRQ_TYPE_EDGE (1 << 0) #define INTEL_MID_IRQ_TYPE_EDGE (1 << 0)
#define INTEL_MID_IRQ_TYPE_LEVEL (1 << 1) #define INTEL_MID_IRQ_TYPE_LEVEL (1 << 1)
...@@ -64,10 +63,6 @@ enum GPIO_REG { ...@@ -64,10 +63,6 @@ enum GPIO_REG {
/* intel_mid gpio driver data */ /* intel_mid gpio driver data */
struct intel_mid_gpio_ddata { struct intel_mid_gpio_ddata {
u16 ngpio; /* number of gpio pins */ u16 ngpio; /* number of gpio pins */
u32 gplr_offset; /* offset of first GPLR register from base */
u32 flis_base; /* base address of FLIS registers */
u32 flis_len; /* length of FLIS registers */
u32 (*get_flis_offset)(int gpio);
u32 chip_irq_type; /* chip interrupt type */ u32 chip_irq_type; /* chip interrupt type */
}; };
...@@ -252,15 +247,6 @@ static const struct intel_mid_gpio_ddata gpio_cloverview_core = { ...@@ -252,15 +247,6 @@ static const struct intel_mid_gpio_ddata gpio_cloverview_core = {
.chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE, .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE,
}; };
static const struct intel_mid_gpio_ddata gpio_tangier = {
.ngpio = 192,
.gplr_offset = 4,
.flis_base = 0xff0c0000,
.flis_len = 0x8000,
.get_flis_offset = NULL,
.chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE,
};
static const struct pci_device_id intel_gpio_ids[] = { static const struct pci_device_id intel_gpio_ids[] = {
{ {
/* Lincroft */ /* Lincroft */
...@@ -287,11 +273,6 @@ static const struct pci_device_id intel_gpio_ids[] = { ...@@ -287,11 +273,6 @@ static const struct pci_device_id intel_gpio_ids[] = {
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08f7), PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08f7),
.driver_data = (kernel_ulong_t)&gpio_cloverview_core, .driver_data = (kernel_ulong_t)&gpio_cloverview_core,
}, },
{
/* Tangier */
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x1199),
.driver_data = (kernel_ulong_t)&gpio_tangier,
},
{ 0 } { 0 }
}; };
MODULE_DEVICE_TABLE(pci, intel_gpio_ids); MODULE_DEVICE_TABLE(pci, intel_gpio_ids);
...@@ -401,7 +382,7 @@ static int intel_gpio_probe(struct pci_dev *pdev, ...@@ -401,7 +382,7 @@ static int intel_gpio_probe(struct pci_dev *pdev,
spin_lock_init(&priv->lock); spin_lock_init(&priv->lock);
pci_set_drvdata(pdev, priv); pci_set_drvdata(pdev, priv);
retval = gpiochip_add_data(&priv->chip, priv); retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv);
if (retval) { if (retval) {
dev_err(&pdev->dev, "gpiochip_add error %d\n", retval); dev_err(&pdev->dev, "gpiochip_add error %d\n", retval);
return retval; return retval;
......
...@@ -383,7 +383,6 @@ static int lp_gpio_probe(struct platform_device *pdev) ...@@ -383,7 +383,6 @@ static int lp_gpio_probe(struct platform_device *pdev)
handle_simple_irq, IRQ_TYPE_NONE); handle_simple_irq, IRQ_TYPE_NONE);
if (ret) { if (ret) {
dev_err(dev, "failed to add irqchip\n"); dev_err(dev, "failed to add irqchip\n");
gpiochip_remove(gc);
return ret; return ret;
} }
......
/*
* MAXIM MAX77620 GPIO driver
*
* Copyright (c) 2016, NVIDIA CORPORATION. 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.
*/
#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/mfd/max77620.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#define GPIO_REG_ADDR(offset) (MAX77620_REG_GPIO0 + offset)
struct max77620_gpio {
struct gpio_chip gpio_chip;
struct regmap *rmap;
struct device *dev;
int gpio_irq;
int irq_base;
int gpio_base;
};
static const struct regmap_irq max77620_gpio_irqs[] = {
[0] = {
.mask = MAX77620_IRQ_LVL2_GPIO_EDGE0,
.type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING,
.type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING,
.reg_offset = 0,
.type_reg_offset = 0,
},
[1] = {
.mask = MAX77620_IRQ_LVL2_GPIO_EDGE1,
.type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING,
.type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING,
.reg_offset = 0,
.type_reg_offset = 1,
},
[2] = {
.mask = MAX77620_IRQ_LVL2_GPIO_EDGE2,
.type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING,
.type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING,
.reg_offset = 0,
.type_reg_offset = 2,
},
[3] = {
.mask = MAX77620_IRQ_LVL2_GPIO_EDGE3,
.type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING,
.type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING,
.reg_offset = 0,
.type_reg_offset = 3,
},
[4] = {
.mask = MAX77620_IRQ_LVL2_GPIO_EDGE4,
.type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING,
.type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING,
.reg_offset = 0,
.type_reg_offset = 4,
},
[5] = {
.mask = MAX77620_IRQ_LVL2_GPIO_EDGE5,
.type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING,
.type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING,
.reg_offset = 0,
.type_reg_offset = 5,
},
[6] = {
.mask = MAX77620_IRQ_LVL2_GPIO_EDGE6,
.type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING,
.type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING,
.reg_offset = 0,
.type_reg_offset = 6,
},
[7] = {
.mask = MAX77620_IRQ_LVL2_GPIO_EDGE7,
.type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING,
.type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING,
.reg_offset = 0,
.type_reg_offset = 7,
},
};
static struct regmap_irq_chip max77620_gpio_irq_chip = {
.name = "max77620-gpio",
.irqs = max77620_gpio_irqs,
.num_irqs = ARRAY_SIZE(max77620_gpio_irqs),
.num_regs = 1,
.num_type_reg = 8,
.irq_reg_stride = 1,
.type_reg_stride = 1,
.status_base = MAX77620_REG_IRQ_LVL2_GPIO,
.type_base = MAX77620_REG_GPIO0,
};
static int max77620_gpio_dir_input(struct gpio_chip *gc, unsigned int offset)
{
struct max77620_gpio *mgpio = gpiochip_get_data(gc);
int ret;
ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),
MAX77620_CNFG_GPIO_DIR_MASK,
MAX77620_CNFG_GPIO_DIR_INPUT);
if (ret < 0)
dev_err(mgpio->dev, "CNFG_GPIOx dir update failed: %d\n", ret);
return ret;
}
static int max77620_gpio_get(struct gpio_chip *gc, unsigned int offset)
{
struct max77620_gpio *mgpio = gpiochip_get_data(gc);
unsigned int val;
int ret;
ret = regmap_read(mgpio->rmap, GPIO_REG_ADDR(offset), &val);
if (ret < 0) {
dev_err(mgpio->dev, "CNFG_GPIOx read failed: %d\n", ret);
return ret;
}
if (val & MAX77620_CNFG_GPIO_DIR_MASK)
return !!(val & MAX77620_CNFG_GPIO_INPUT_VAL_MASK);
else
return !!(val & MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK);
}
static int max77620_gpio_dir_output(struct gpio_chip *gc, unsigned int offset,
int value)
{
struct max77620_gpio *mgpio = gpiochip_get_data(gc);
u8 val;
int ret;
val = (value) ? MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH :
MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW;
ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),
MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK, val);
if (ret < 0) {
dev_err(mgpio->dev, "CNFG_GPIOx val update failed: %d\n", ret);
return ret;
}
ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),
MAX77620_CNFG_GPIO_DIR_MASK,
MAX77620_CNFG_GPIO_DIR_OUTPUT);
if (ret < 0)
dev_err(mgpio->dev, "CNFG_GPIOx dir update failed: %d\n", ret);
return ret;
}
static int max77620_gpio_set_debounce(struct gpio_chip *gc,
unsigned int offset,
unsigned int debounce)
{
struct max77620_gpio *mgpio = gpiochip_get_data(gc);
u8 val;
int ret;
switch (debounce) {
case 0:
val = MAX77620_CNFG_GPIO_DBNC_None;
break;
case 1 ... 8:
val = MAX77620_CNFG_GPIO_DBNC_8ms;
break;
case 9 ... 16:
val = MAX77620_CNFG_GPIO_DBNC_16ms;
break;
case 17 ... 32:
val = MAX77620_CNFG_GPIO_DBNC_32ms;
break;
default:
dev_err(mgpio->dev, "Illegal value %u\n", debounce);
return -EINVAL;
}
ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),
MAX77620_CNFG_GPIO_DBNC_MASK, val);
if (ret < 0)
dev_err(mgpio->dev, "CNFG_GPIOx_DBNC update failed: %d\n", ret);
return ret;
}
static void max77620_gpio_set(struct gpio_chip *gc, unsigned int offset,
int value)
{
struct max77620_gpio *mgpio = gpiochip_get_data(gc);
u8 val;
int ret;
val = (value) ? MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH :
MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW;
ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),
MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK, val);
if (ret < 0)
dev_err(mgpio->dev, "CNFG_GPIO_OUT update failed: %d\n", ret);
}
static int max77620_gpio_set_single_ended(struct gpio_chip *gc,
unsigned int offset,
enum single_ended_mode mode)
{
struct max77620_gpio *mgpio = gpiochip_get_data(gc);
switch (mode) {
case LINE_MODE_OPEN_DRAIN:
return regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),
MAX77620_CNFG_GPIO_DRV_MASK,
MAX77620_CNFG_GPIO_DRV_OPENDRAIN);
case LINE_MODE_PUSH_PULL:
return regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),
MAX77620_CNFG_GPIO_DRV_MASK,
MAX77620_CNFG_GPIO_DRV_PUSHPULL);
default:
break;
}
return -ENOTSUPP;
}
static int max77620_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
{
struct max77620_gpio *mgpio = gpiochip_get_data(gc);
struct max77620_chip *chip = dev_get_drvdata(mgpio->dev->parent);
return regmap_irq_get_virq(chip->gpio_irq_data, offset);
}
static int max77620_gpio_probe(struct platform_device *pdev)
{
struct max77620_chip *chip = dev_get_drvdata(pdev->dev.parent);
struct max77620_gpio *mgpio;
int gpio_irq;
int ret;
gpio_irq = platform_get_irq(pdev, 0);
if (gpio_irq <= 0) {
dev_err(&pdev->dev, "GPIO irq not available %d\n", gpio_irq);
return -ENODEV;
}
mgpio = devm_kzalloc(&pdev->dev, sizeof(*mgpio), GFP_KERNEL);
if (!mgpio)
return -ENOMEM;
mgpio->rmap = chip->rmap;
mgpio->dev = &pdev->dev;
mgpio->gpio_irq = gpio_irq;
mgpio->gpio_chip.label = pdev->name;
mgpio->gpio_chip.parent = &pdev->dev;
mgpio->gpio_chip.direction_input = max77620_gpio_dir_input;
mgpio->gpio_chip.get = max77620_gpio_get;
mgpio->gpio_chip.direction_output = max77620_gpio_dir_output;
mgpio->gpio_chip.set_debounce = max77620_gpio_set_debounce;
mgpio->gpio_chip.set = max77620_gpio_set;
mgpio->gpio_chip.set_single_ended = max77620_gpio_set_single_ended;
mgpio->gpio_chip.to_irq = max77620_gpio_to_irq;
mgpio->gpio_chip.ngpio = MAX77620_GPIO_NR;
mgpio->gpio_chip.can_sleep = 1;
mgpio->gpio_chip.base = -1;
mgpio->irq_base = -1;
#ifdef CONFIG_OF_GPIO
mgpio->gpio_chip.of_node = pdev->dev.parent->of_node;
#endif
platform_set_drvdata(pdev, mgpio);
ret = devm_gpiochip_add_data(&pdev->dev, &mgpio->gpio_chip, mgpio);
if (ret < 0) {
dev_err(&pdev->dev, "gpio_init: Failed to add max77620_gpio\n");
return ret;
}
mgpio->gpio_base = mgpio->gpio_chip.base;
ret = devm_regmap_add_irq_chip(&pdev->dev, chip->rmap, mgpio->gpio_irq,
IRQF_ONESHOT, mgpio->irq_base,
&max77620_gpio_irq_chip,
&chip->gpio_irq_data);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to add gpio irq_chip %d\n", ret);
return ret;
}
return 0;
}
static const struct platform_device_id max77620_gpio_devtype[] = {
{ .name = "max77620-gpio", },
{},
};
MODULE_DEVICE_TABLE(platform, max77620_gpio_devtype);
static struct platform_driver max77620_gpio_driver = {
.driver.name = "max77620-gpio",
.probe = max77620_gpio_probe,
.id_table = max77620_gpio_devtype,
};
module_platform_driver(max77620_gpio_driver);
MODULE_DESCRIPTION("GPIO interface for MAX77620 and MAX20024 PMIC");
MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
MODULE_AUTHOR("Chaitanya Bandi <bandik@nvidia.com>");
MODULE_ALIAS("platform:max77620-gpio");
MODULE_LICENSE("GPL v2");
...@@ -187,7 +187,6 @@ MODULE_DEVICE_TABLE(mcb, men_z127_ids); ...@@ -187,7 +187,6 @@ MODULE_DEVICE_TABLE(mcb, men_z127_ids);
static struct mcb_driver men_z127_driver = { static struct mcb_driver men_z127_driver = {
.driver = { .driver = {
.name = "z127-gpio", .name = "z127-gpio",
.owner = THIS_MODULE,
}, },
.probe = men_z127_probe, .probe = men_z127_probe,
.remove = men_z127_remove, .remove = men_z127_remove,
......
This diff is collapsed.
...@@ -61,6 +61,8 @@ o ` ~~~~\___/~~~~ ` controller in FPGA is ,.` ...@@ -61,6 +61,8 @@ o ` ~~~~\___/~~~~ ` controller in FPGA is ,.`
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/mod_devicetable.h> #include <linux/mod_devicetable.h>
#include <linux/of.h>
#include <linux/of_device.h>
static void bgpio_write8(void __iomem *reg, unsigned long data) static void bgpio_write8(void __iomem *reg, unsigned long data)
{ {
...@@ -569,6 +571,41 @@ static void __iomem *bgpio_map(struct platform_device *pdev, ...@@ -569,6 +571,41 @@ static void __iomem *bgpio_map(struct platform_device *pdev,
return devm_ioremap_resource(&pdev->dev, r); return devm_ioremap_resource(&pdev->dev, r);
} }
#ifdef CONFIG_OF
static const struct of_device_id bgpio_of_match[] = {
{ .compatible = "wd,mbl-gpio" },
{ }
};
MODULE_DEVICE_TABLE(of, bgpio_of_match);
static struct bgpio_pdata *bgpio_parse_dt(struct platform_device *pdev,
unsigned long *flags)
{
struct bgpio_pdata *pdata;
if (!of_match_device(bgpio_of_match, &pdev->dev))
return NULL;
pdata = devm_kzalloc(&pdev->dev, sizeof(struct bgpio_pdata),
GFP_KERNEL);
if (!pdata)
return ERR_PTR(-ENOMEM);
pdata->base = -1;
if (of_property_read_bool(pdev->dev.of_node, "no-output"))
*flags |= BGPIOF_NO_OUTPUT;
return pdata;
}
#else
static struct bgpio_pdata *bgpio_parse_dt(struct platform_device *pdev,
unsigned long *flags)
{
return NULL;
}
#endif /* CONFIG_OF */
static int bgpio_pdev_probe(struct platform_device *pdev) static int bgpio_pdev_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -579,10 +616,19 @@ static int bgpio_pdev_probe(struct platform_device *pdev) ...@@ -579,10 +616,19 @@ static int bgpio_pdev_probe(struct platform_device *pdev)
void __iomem *dirout; void __iomem *dirout;
void __iomem *dirin; void __iomem *dirin;
unsigned long sz; unsigned long sz;
unsigned long flags = pdev->id_entry->driver_data; unsigned long flags = 0;
int err; int err;
struct gpio_chip *gc; struct gpio_chip *gc;
struct bgpio_pdata *pdata = dev_get_platdata(dev); struct bgpio_pdata *pdata;
pdata = bgpio_parse_dt(pdev, &flags);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
if (!pdata) {
pdata = dev_get_platdata(dev);
flags = pdev->id_entry->driver_data;
}
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat"); r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
if (!r) if (!r)
...@@ -646,6 +692,7 @@ MODULE_DEVICE_TABLE(platform, bgpio_id_table); ...@@ -646,6 +692,7 @@ MODULE_DEVICE_TABLE(platform, bgpio_id_table);
static struct platform_driver bgpio_driver = { static struct platform_driver bgpio_driver = {
.driver = { .driver = {
.name = "basic-mmio-gpio", .name = "basic-mmio-gpio",
.of_match_table = of_match_ptr(bgpio_of_match),
}, },
.id_table = bgpio_id_table, .id_table = bgpio_id_table,
.probe = bgpio_pdev_probe, .probe = bgpio_pdev_probe,
......
...@@ -208,7 +208,6 @@ static int palmas_gpio_probe(struct platform_device *pdev) ...@@ -208,7 +208,6 @@ static int palmas_gpio_probe(struct platform_device *pdev)
static struct platform_driver palmas_gpio_driver = { static struct platform_driver palmas_gpio_driver = {
.driver.name = "palmas-gpio", .driver.name = "palmas-gpio",
.driver.owner = THIS_MODULE,
.driver.of_match_table = of_palmas_gpio_match, .driver.of_match_table = of_palmas_gpio_match,
.probe = palmas_gpio_probe, .probe = palmas_gpio_probe,
}; };
......
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
#define PCA_GPIO_MASK 0x00FF #define PCA_GPIO_MASK 0x00FF
#define PCA_INT 0x0100 #define PCA_INT 0x0100
#define PCA_PCAL 0x0200 #define PCA_PCAL 0x0200
#define PCA953X_TYPE 0x1000 #define PCA953X_TYPE 0x1000
#define PCA957X_TYPE 0x2000 #define PCA957X_TYPE 0x2000
#define PCA_TYPE_MASK 0xF000 #define PCA_TYPE_MASK 0xF000
...@@ -67,6 +67,8 @@ static const struct i2c_device_id pca953x_id[] = { ...@@ -67,6 +67,8 @@ static const struct i2c_device_id pca953x_id[] = {
{ "pca9575", 16 | PCA957X_TYPE | PCA_INT, }, { "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
{ "pca9698", 40 | PCA953X_TYPE, }, { "pca9698", 40 | PCA953X_TYPE, },
{ "pcal9555a", 16 | PCA953X_TYPE | PCA_INT | PCA_PCAL, },
{ "max7310", 8 | PCA953X_TYPE, }, { "max7310", 8 | PCA953X_TYPE, },
{ "max7312", 16 | PCA953X_TYPE | PCA_INT, }, { "max7312", 16 | PCA953X_TYPE | PCA_INT, },
{ "max7313", 16 | PCA953X_TYPE | PCA_INT, }, { "max7313", 16 | PCA953X_TYPE | PCA_INT, },
...@@ -90,7 +92,7 @@ MODULE_DEVICE_TABLE(acpi, pca953x_acpi_ids); ...@@ -90,7 +92,7 @@ MODULE_DEVICE_TABLE(acpi, pca953x_acpi_ids);
#define MAX_BANK 5 #define MAX_BANK 5
#define BANK_SZ 8 #define BANK_SZ 8
#define NBANK(chip) (chip->gpio_chip.ngpio / BANK_SZ) #define NBANK(chip) DIV_ROUND_UP(chip->gpio_chip.ngpio, BANK_SZ)
struct pca953x_chip { struct pca953x_chip {
unsigned gpio_start; unsigned gpio_start;
...@@ -135,7 +137,7 @@ static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val, ...@@ -135,7 +137,7 @@ static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val,
static int pca953x_write_single(struct pca953x_chip *chip, int reg, u32 val, static int pca953x_write_single(struct pca953x_chip *chip, int reg, u32 val,
int off) int off)
{ {
int ret = 0; int ret;
int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ); int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
int offset = off / BANK_SZ; int offset = off / BANK_SZ;
...@@ -163,10 +165,13 @@ static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val) ...@@ -163,10 +165,13 @@ static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val)
NBANK(chip), val); NBANK(chip), val);
} else { } else {
switch (chip->chip_type) { switch (chip->chip_type) {
case PCA953X_TYPE: case PCA953X_TYPE: {
ret = i2c_smbus_write_word_data(chip->client, __le16 word = cpu_to_le16(get_unaligned((u16 *)val));
reg << 1, cpu_to_le16(get_unaligned((u16 *)val)));
ret = i2c_smbus_write_word_data(chip->client, reg << 1,
(__force u16)word);
break; break;
}
case PCA957X_TYPE: case PCA957X_TYPE:
ret = i2c_smbus_write_byte_data(chip->client, reg << 1, ret = i2c_smbus_write_byte_data(chip->client, reg << 1,
val[0]); val[0]);
...@@ -235,7 +240,6 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) ...@@ -235,7 +240,6 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
goto exit; goto exit;
chip->reg_direction[off / BANK_SZ] = reg_val; chip->reg_direction[off / BANK_SZ] = reg_val;
ret = 0;
exit: exit:
mutex_unlock(&chip->i2c_lock); mutex_unlock(&chip->i2c_lock);
return ret; return ret;
...@@ -286,7 +290,6 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, ...@@ -286,7 +290,6 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
goto exit; goto exit;
chip->reg_direction[off / BANK_SZ] = reg_val; chip->reg_direction[off / BANK_SZ] = reg_val;
ret = 0;
exit: exit:
mutex_unlock(&chip->i2c_lock); mutex_unlock(&chip->i2c_lock);
return ret; return ret;
...@@ -351,7 +354,6 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) ...@@ -351,7 +354,6 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
mutex_unlock(&chip->i2c_lock); mutex_unlock(&chip->i2c_lock);
} }
static void pca953x_gpio_set_multiple(struct gpio_chip *gc, static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
unsigned long *mask, unsigned long *bits) unsigned long *mask, unsigned long *bits)
{ {
...@@ -820,7 +822,7 @@ static int pca953x_remove(struct i2c_client *client) ...@@ -820,7 +822,7 @@ static int pca953x_remove(struct i2c_client *client)
{ {
struct pca953x_platform_data *pdata = dev_get_platdata(&client->dev); struct pca953x_platform_data *pdata = dev_get_platdata(&client->dev);
struct pca953x_chip *chip = i2c_get_clientdata(client); struct pca953x_chip *chip = i2c_get_clientdata(client);
int ret = 0; int ret;
if (pdata && pdata->teardown) { if (pdata && pdata->teardown) {
ret = pdata->teardown(client, chip->gpio_chip.base, ret = pdata->teardown(client, chip->gpio_chip.base,
...@@ -861,6 +863,7 @@ static const struct of_device_id pca953x_dt_ids[] = { ...@@ -861,6 +863,7 @@ static const struct of_device_id pca953x_dt_ids[] = {
{ .compatible = "maxim,max7315", .data = OF_953X( 8, PCA_INT), }, { .compatible = "maxim,max7315", .data = OF_953X( 8, 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,tca6408", .data = OF_953X( 8, PCA_INT), }, { .compatible = "ti,tca6408", .data = OF_953X( 8, PCA_INT), },
{ .compatible = "ti,tca6416", .data = OF_953X(16, PCA_INT), }, { .compatible = "ti,tca6416", .data = OF_953X(16, PCA_INT), },
{ .compatible = "ti,tca6424", .data = OF_953X(24, PCA_INT), }, { .compatible = "ti,tca6424", .data = OF_953X(24, PCA_INT), },
......
...@@ -440,6 +440,14 @@ static int pcf857x_remove(struct i2c_client *client) ...@@ -440,6 +440,14 @@ static int pcf857x_remove(struct i2c_client *client)
return status; return status;
} }
static void pcf857x_shutdown(struct i2c_client *client)
{
struct pcf857x *gpio = i2c_get_clientdata(client);
/* Drive all the I/O lines high */
gpio->write(gpio->client, BIT(gpio->chip.ngpio) - 1);
}
static struct i2c_driver pcf857x_driver = { static struct i2c_driver pcf857x_driver = {
.driver = { .driver = {
.name = "pcf857x", .name = "pcf857x",
...@@ -447,6 +455,7 @@ static struct i2c_driver pcf857x_driver = { ...@@ -447,6 +455,7 @@ static struct i2c_driver pcf857x_driver = {
}, },
.probe = pcf857x_probe, .probe = pcf857x_probe,
.remove = pcf857x_remove, .remove = pcf857x_remove,
.shutdown = pcf857x_shutdown,
.id_table = pcf857x_id, .id_table = pcf857x_id,
}; };
......
...@@ -334,6 +334,9 @@ static const struct of_device_id gpio_rcar_of_table[] = { ...@@ -334,6 +334,9 @@ static const struct of_device_id gpio_rcar_of_table[] = {
}, { }, {
.compatible = "renesas,gpio-r8a7791", .compatible = "renesas,gpio-r8a7791",
.data = &gpio_rcar_info_gen2, .data = &gpio_rcar_info_gen2,
}, {
.compatible = "renesas,gpio-r8a7792",
.data = &gpio_rcar_info_gen2,
}, { }, {
.compatible = "renesas,gpio-r8a7793", .compatible = "renesas,gpio-r8a7793",
.data = &gpio_rcar_info_gen2, .data = &gpio_rcar_info_gen2,
......
...@@ -200,7 +200,6 @@ static int rdc321x_gpio_probe(struct platform_device *pdev) ...@@ -200,7 +200,6 @@ static int rdc321x_gpio_probe(struct platform_device *pdev)
static struct platform_driver rdc321x_gpio_driver = { static struct platform_driver rdc321x_gpio_driver = {
.driver.name = "rdc321x-gpio", .driver.name = "rdc321x-gpio",
.driver.owner = THIS_MODULE,
.probe = rdc321x_gpio_probe, .probe = rdc321x_gpio_probe,
}; };
......
...@@ -296,7 +296,6 @@ static int sch311x_gpio_remove(struct platform_device *pdev) ...@@ -296,7 +296,6 @@ static int sch311x_gpio_remove(struct platform_device *pdev)
static struct platform_driver sch311x_gpio_driver = { static struct platform_driver sch311x_gpio_driver = {
.driver.name = DRV_NAME, .driver.name = DRV_NAME,
.driver.owner = THIS_MODULE,
.probe = sch311x_gpio_probe, .probe = sch311x_gpio_probe,
.remove = sch311x_gpio_remove, .remove = sch311x_gpio_remove,
}; };
......
...@@ -68,6 +68,22 @@ static void stmpe_gpio_set(struct gpio_chip *chip, unsigned offset, int val) ...@@ -68,6 +68,22 @@ static void stmpe_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
stmpe_reg_write(stmpe, reg, mask); stmpe_reg_write(stmpe, reg, mask);
} }
static int stmpe_gpio_get_direction(struct gpio_chip *chip,
unsigned offset)
{
struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip);
struct stmpe *stmpe = stmpe_gpio->stmpe;
u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
u8 mask = 1 << (offset % 8);
int ret;
ret = stmpe_reg_read(stmpe, reg);
if (ret < 0)
return ret;
return !(ret & mask);
}
static int stmpe_gpio_direction_output(struct gpio_chip *chip, static int stmpe_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int val) unsigned offset, int val)
{ {
...@@ -106,6 +122,7 @@ static int stmpe_gpio_request(struct gpio_chip *chip, unsigned offset) ...@@ -106,6 +122,7 @@ static int stmpe_gpio_request(struct gpio_chip *chip, unsigned offset)
static struct gpio_chip template_chip = { static struct gpio_chip template_chip = {
.label = "stmpe", .label = "stmpe",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.get_direction = stmpe_gpio_get_direction,
.direction_input = stmpe_gpio_direction_input, .direction_input = stmpe_gpio_direction_input,
.get = stmpe_gpio_get, .get = stmpe_gpio_get,
.direction_output = stmpe_gpio_direction_output, .direction_output = stmpe_gpio_direction_output,
...@@ -416,7 +433,6 @@ static struct platform_driver stmpe_gpio_driver = { ...@@ -416,7 +433,6 @@ static struct platform_driver stmpe_gpio_driver = {
.driver = { .driver = {
.suppress_bind_attrs = true, .suppress_bind_attrs = true,
.name = "stmpe-gpio", .name = "stmpe-gpio",
.owner = THIS_MODULE,
}, },
.probe = stmpe_gpio_probe, .probe = stmpe_gpio_probe,
}; };
......
...@@ -129,7 +129,7 @@ static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val) ...@@ -129,7 +129,7 @@ static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val)
static const struct syscon_gpio_data clps711x_mctrl_gpio = { static const struct syscon_gpio_data clps711x_mctrl_gpio = {
/* ARM CLPS711X SYSFLG1 Bits 8-10 */ /* ARM CLPS711X SYSFLG1 Bits 8-10 */
.compatible = "cirrus,clps711x-syscon1", .compatible = "cirrus,ep7209-syscon1",
.flags = GPIO_SYSCON_FEAT_IN, .flags = GPIO_SYSCON_FEAT_IN,
.bit_count = 3, .bit_count = 3,
.dat_bit_offset = 0x40 * 8 + 8, .dat_bit_offset = 0x40 * 8 + 8,
...@@ -168,7 +168,7 @@ static const struct syscon_gpio_data keystone_dsp_gpio = { ...@@ -168,7 +168,7 @@ static const struct syscon_gpio_data keystone_dsp_gpio = {
static const struct of_device_id syscon_gpio_ids[] = { static const struct of_device_id syscon_gpio_ids[] = {
{ {
.compatible = "cirrus,clps711x-mctrl-gpio", .compatible = "cirrus,ep7209-mctrl-gpio",
.data = &clps711x_mctrl_gpio, .data = &clps711x_mctrl_gpio,
}, },
{ {
......
...@@ -343,7 +343,6 @@ static int tc3589x_gpio_probe(struct platform_device *pdev) ...@@ -343,7 +343,6 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
static struct platform_driver tc3589x_gpio_driver = { static struct platform_driver tc3589x_gpio_driver = {
.driver.name = "tc3589x-gpio", .driver.name = "tc3589x-gpio",
.driver.owner = THIS_MODULE,
.probe = tc3589x_gpio_probe, .probe = tc3589x_gpio_probe,
}; };
......
...@@ -230,6 +230,12 @@ static const struct of_device_id tps65218_dt_match[] = { ...@@ -230,6 +230,12 @@ static const struct of_device_id tps65218_dt_match[] = {
}; };
MODULE_DEVICE_TABLE(of, tps65218_dt_match); MODULE_DEVICE_TABLE(of, tps65218_dt_match);
static const struct platform_device_id tps65218_gpio_id_table[] = {
{ "tps65218-gpio", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, tps65218_gpio_id_table);
static struct platform_driver tps65218_gpio_driver = { static struct platform_driver tps65218_gpio_driver = {
.driver = { .driver = {
.name = "tps65218-gpio", .name = "tps65218-gpio",
...@@ -237,6 +243,7 @@ static struct platform_driver tps65218_gpio_driver = { ...@@ -237,6 +243,7 @@ static struct platform_driver tps65218_gpio_driver = {
}, },
.probe = tps65218_gpio_probe, .probe = tps65218_gpio_probe,
.remove = tps65218_gpio_remove, .remove = tps65218_gpio_remove,
.id_table = tps65218_gpio_id_table,
}; };
module_platform_driver(tps65218_gpio_driver); module_platform_driver(tps65218_gpio_driver);
......
...@@ -131,7 +131,6 @@ static int tps6586x_gpio_probe(struct platform_device *pdev) ...@@ -131,7 +131,6 @@ static int tps6586x_gpio_probe(struct platform_device *pdev)
static struct platform_driver tps6586x_gpio_driver = { static struct platform_driver tps6586x_gpio_driver = {
.driver.name = "tps6586x-gpio", .driver.name = "tps6586x-gpio",
.driver.owner = THIS_MODULE,
.probe = tps6586x_gpio_probe, .probe = tps6586x_gpio_probe,
}; };
......
...@@ -184,7 +184,6 @@ static int tps65910_gpio_probe(struct platform_device *pdev) ...@@ -184,7 +184,6 @@ static int tps65910_gpio_probe(struct platform_device *pdev)
static struct platform_driver tps65910_gpio_driver = { static struct platform_driver tps65910_gpio_driver = {
.driver.name = "tps65910-gpio", .driver.name = "tps65910-gpio",
.driver.owner = THIS_MODULE,
.probe = tps65910_gpio_probe, .probe = tps65910_gpio_probe,
}; };
......
...@@ -440,7 +440,6 @@ static int vprbrd_gpio_probe(struct platform_device *pdev) ...@@ -440,7 +440,6 @@ static int vprbrd_gpio_probe(struct platform_device *pdev)
static struct platform_driver vprbrd_gpio_driver = { static struct platform_driver vprbrd_gpio_driver = {
.driver.name = "viperboard-gpio", .driver.name = "viperboard-gpio",
.driver.owner = THIS_MODULE,
.probe = vprbrd_gpio_probe, .probe = vprbrd_gpio_probe,
}; };
......
...@@ -296,7 +296,6 @@ static int wm831x_gpio_probe(struct platform_device *pdev) ...@@ -296,7 +296,6 @@ static int wm831x_gpio_probe(struct platform_device *pdev)
static struct platform_driver wm831x_gpio_driver = { static struct platform_driver wm831x_gpio_driver = {
.driver.name = "wm831x-gpio", .driver.name = "wm831x-gpio",
.driver.owner = THIS_MODULE,
.probe = wm831x_gpio_probe, .probe = wm831x_gpio_probe,
}; };
......
...@@ -139,7 +139,6 @@ static int wm8350_gpio_probe(struct platform_device *pdev) ...@@ -139,7 +139,6 @@ static int wm8350_gpio_probe(struct platform_device *pdev)
static struct platform_driver wm8350_gpio_driver = { static struct platform_driver wm8350_gpio_driver = {
.driver.name = "wm8350-gpio", .driver.name = "wm8350-gpio",
.driver.owner = THIS_MODULE,
.probe = wm8350_gpio_probe, .probe = wm8350_gpio_probe,
}; };
......
...@@ -299,7 +299,6 @@ static int wm8994_gpio_probe(struct platform_device *pdev) ...@@ -299,7 +299,6 @@ static int wm8994_gpio_probe(struct platform_device *pdev)
static struct platform_driver wm8994_gpio_driver = { static struct platform_driver wm8994_gpio_driver = {
.driver.name = "wm8994-gpio", .driver.name = "wm8994-gpio",
.driver.owner = THIS_MODULE,
.probe = wm8994_gpio_probe, .probe = wm8994_gpio_probe,
}; };
......
...@@ -132,6 +132,53 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) ...@@ -132,6 +132,53 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
spin_unlock_irqrestore(&chip->gpio_lock[index], flags); spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
} }
/**
* xgpio_set_multiple - Write the specified signals of the GPIO device.
* @gc: Pointer to gpio_chip device structure.
* @mask: Mask of the GPIOS to modify.
* @bits: Value to be wrote on each GPIO
*
* This function writes the specified values into the specified signals of the
* GPIO devices.
*/
static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
unsigned long *bits)
{
unsigned long flags;
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip = gpiochip_get_data(gc);
int index = xgpio_index(chip, 0);
int offset, i;
spin_lock_irqsave(&chip->gpio_lock[index], flags);
/* Write to GPIO signals */
for (i = 0; i < gc->ngpio; i++) {
if (*mask == 0)
break;
if (index != xgpio_index(chip, i)) {
xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET +
xgpio_regoffset(chip, i),
chip->gpio_state[index]);
spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
index = xgpio_index(chip, i);
spin_lock_irqsave(&chip->gpio_lock[index], flags);
}
if (__test_and_clear_bit(i, mask)) {
offset = xgpio_offset(chip, i);
if (test_bit(i, bits))
chip->gpio_state[index] |= BIT(offset);
else
chip->gpio_state[index] &= ~BIT(offset);
}
}
xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET +
xgpio_regoffset(chip, i), chip->gpio_state[index]);
spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
}
/** /**
* xgpio_dir_in - Set the direction of the specified GPIO signal as input. * xgpio_dir_in - Set the direction of the specified GPIO signal as input.
* @gc: Pointer to gpio_chip device structure. * @gc: Pointer to gpio_chip device structure.
...@@ -306,6 +353,7 @@ static int xgpio_probe(struct platform_device *pdev) ...@@ -306,6 +353,7 @@ static int xgpio_probe(struct platform_device *pdev)
chip->mmchip.gc.direction_output = xgpio_dir_out; chip->mmchip.gc.direction_output = xgpio_dir_out;
chip->mmchip.gc.get = xgpio_get; chip->mmchip.gc.get = xgpio_get;
chip->mmchip.gc.set = xgpio_set; chip->mmchip.gc.set = xgpio_set;
chip->mmchip.gc.set_multiple = xgpio_set_multiple;
chip->mmchip.save_regs = xgpio_save_regs; chip->mmchip.save_regs = xgpio_save_regs;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irqchip/chained_irq.h> #include <linux/irqchip/chained_irq.h>
#include <linux/acpi.h>
/* /*
* XLP GPIO has multiple 32 bit registers for each feature where each register * XLP GPIO has multiple 32 bit registers for each feature where each register
...@@ -299,7 +300,6 @@ static int xlp_gpio_probe(struct platform_device *pdev) ...@@ -299,7 +300,6 @@ static int xlp_gpio_probe(struct platform_device *pdev)
struct gpio_chip *gc; struct gpio_chip *gc;
struct resource *iores; struct resource *iores;
struct xlp_gpio_priv *priv; struct xlp_gpio_priv *priv;
const struct of_device_id *of_id;
void __iomem *gpio_base; void __iomem *gpio_base;
int irq_base, irq, err; int irq_base, irq, err;
int ngpio; int ngpio;
...@@ -321,13 +321,26 @@ static int xlp_gpio_probe(struct platform_device *pdev) ...@@ -321,13 +321,26 @@ static int xlp_gpio_probe(struct platform_device *pdev)
if (irq < 0) if (irq < 0)
return irq; return irq;
of_id = of_match_device(xlp_gpio_of_ids, &pdev->dev); if (pdev->dev.of_node) {
if (!of_id) { const struct of_device_id *of_id;
dev_err(&pdev->dev, "Failed to get soc type!\n");
return -ENODEV;
}
soc_type = (uintptr_t) of_id->data; of_id = of_match_device(xlp_gpio_of_ids, &pdev->dev);
if (!of_id) {
dev_err(&pdev->dev, "Unable to match OF ID\n");
return -ENODEV;
}
soc_type = (uintptr_t) of_id->data;
} else {
const struct acpi_device_id *acpi_id;
acpi_id = acpi_match_device(pdev->dev.driver->acpi_match_table,
&pdev->dev);
if (!acpi_id || !acpi_id->driver_data) {
dev_err(&pdev->dev, "Unable to match ACPI ID\n");
return -ENODEV;
}
soc_type = (uintptr_t) acpi_id->driver_data;
}
switch (soc_type) { switch (soc_type) {
case XLP_GPIO_VARIANT_XLP832: case XLP_GPIO_VARIANT_XLP832:
...@@ -388,14 +401,16 @@ static int xlp_gpio_probe(struct platform_device *pdev) ...@@ -388,14 +401,16 @@ static int xlp_gpio_probe(struct platform_device *pdev)
gc->get = xlp_gpio_get; gc->get = xlp_gpio_get;
spin_lock_init(&priv->lock); spin_lock_init(&priv->lock);
/* XLP has fixed IRQ range for GPIO interrupts */
if (soc_type == GPIO_VARIANT_VULCAN) /* XLP(MIPS) has fixed range for GPIO IRQs, Vulcan(ARM64) does not */
irq_base = irq_alloc_descs(-1, 0, gc->ngpio, 0); if (soc_type != GPIO_VARIANT_VULCAN) {
else
irq_base = irq_alloc_descs(-1, XLP_GPIO_IRQ_BASE, gc->ngpio, 0); irq_base = irq_alloc_descs(-1, XLP_GPIO_IRQ_BASE, gc->ngpio, 0);
if (irq_base < 0) { if (irq_base < 0) {
dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n"); dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n");
return irq_base; return irq_base;
}
} else {
irq_base = 0;
} }
err = gpiochip_add_data(gc, priv); err = gpiochip_add_data(gc, priv);
...@@ -423,10 +438,19 @@ static int xlp_gpio_probe(struct platform_device *pdev) ...@@ -423,10 +438,19 @@ static int xlp_gpio_probe(struct platform_device *pdev)
return err; return err;
} }
#ifdef CONFIG_ACPI
static const struct acpi_device_id xlp_gpio_acpi_match[] = {
{ "BRCM9006", GPIO_VARIANT_VULCAN },
{},
};
MODULE_DEVICE_TABLE(acpi, xlp_gpio_acpi_match);
#endif
static struct platform_driver xlp_gpio_driver = { static struct platform_driver xlp_gpio_driver = {
.driver = { .driver = {
.name = "xlp-gpio", .name = "xlp-gpio",
.of_match_table = xlp_gpio_of_ids, .of_match_table = xlp_gpio_of_ids,
.acpi_match_table = ACPI_PTR(xlp_gpio_acpi_match),
}, },
.probe = xlp_gpio_probe, .probe = xlp_gpio_probe,
}; };
......
...@@ -836,6 +836,7 @@ void acpi_gpiochip_add(struct gpio_chip *chip) ...@@ -836,6 +836,7 @@ void acpi_gpiochip_add(struct gpio_chip *chip)
} }
acpi_gpiochip_request_regions(acpi_gpio); acpi_gpiochip_request_regions(acpi_gpio);
acpi_walk_dep_device_list(handle);
} }
void acpi_gpiochip_remove(struct gpio_chip *chip) void acpi_gpiochip_remove(struct gpio_chip *chip)
......
...@@ -27,38 +27,30 @@ ...@@ -27,38 +27,30 @@
#include "gpiolib.h" #include "gpiolib.h"
/* Private data structure for of_gpiochip_find_and_xlate */ static int of_gpiochip_match_node(struct gpio_chip *chip, void *data)
struct gg_data { {
enum of_gpio_flags *flags; return chip->gpiodev->dev.of_node == data;
struct of_phandle_args gpiospec; }
struct gpio_desc *out_gpio; static struct gpio_chip *of_find_gpiochip_by_node(struct device_node *np)
}; {
return gpiochip_find(np, of_gpiochip_match_node);
}
/* Private function for resolving node pointer to gpio_chip */ static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip,
static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data) struct of_phandle_args *gpiospec,
enum of_gpio_flags *flags)
{ {
struct gg_data *gg_data = data;
int ret; int ret;
if ((gc->of_node != gg_data->gpiospec.np) || if (chip->of_gpio_n_cells != gpiospec->args_count)
(gc->of_gpio_n_cells != gg_data->gpiospec.args_count) || return ERR_PTR(-EINVAL);
(!gc->of_xlate))
return false; ret = chip->of_xlate(chip, gpiospec, flags);
if (ret < 0)
ret = gc->of_xlate(gc, &gg_data->gpiospec, gg_data->flags); return ERR_PTR(ret);
if (ret < 0) {
/* We've found a gpio chip, but the translation failed. return gpiochip_get_desc(chip, ret);
* Store translation error in out_gpio.
* Return false to keep looking, as more than one gpio chip
* could be registered per of-node.
*/
gg_data->out_gpio = ERR_PTR(ret);
return false;
}
gg_data->out_gpio = gpiochip_get_desc(gc, ret);
return true;
} }
/** /**
...@@ -75,34 +67,37 @@ static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data) ...@@ -75,34 +67,37 @@ static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data)
struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
const char *propname, int index, enum of_gpio_flags *flags) const char *propname, int index, enum of_gpio_flags *flags)
{ {
/* Return -EPROBE_DEFER to support probe() functions to be called struct of_phandle_args gpiospec;
* later when the GPIO actually becomes available struct gpio_chip *chip;
*/ struct gpio_desc *desc;
struct gg_data gg_data = {
.flags = flags,
.out_gpio = ERR_PTR(-EPROBE_DEFER)
};
int ret; int ret;
/* .of_xlate might decide to not fill in the flags, so clear it. */
if (flags)
*flags = 0;
ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index, ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index,
&gg_data.gpiospec); &gpiospec);
if (ret) { if (ret) {
pr_debug("%s: can't parse '%s' property of node '%s[%d]'\n", pr_debug("%s: can't parse '%s' property of node '%s[%d]'\n",
__func__, propname, np->full_name, index); __func__, propname, np->full_name, index);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
gpiochip_find(&gg_data, of_gpiochip_find_and_xlate); chip = of_find_gpiochip_by_node(gpiospec.np);
if (!chip) {
desc = ERR_PTR(-EPROBE_DEFER);
goto out;
}
desc = of_xlate_and_get_gpiod_flags(chip, &gpiospec, flags);
if (IS_ERR(desc))
goto out;
of_node_put(gg_data.gpiospec.np);
pr_debug("%s: parsed '%s' property of node '%s[%d]' - status (%d)\n", pr_debug("%s: parsed '%s' property of node '%s[%d]' - status (%d)\n",
__func__, propname, np->full_name, index, __func__, propname, np->full_name, index,
PTR_ERR_OR_ZERO(gg_data.out_gpio)); PTR_ERR_OR_ZERO(desc));
return gg_data.out_gpio;
out:
of_node_put(gpiospec.np);
return desc;
} }
int of_get_named_gpio_flags(struct device_node *np, const char *list_name, int of_get_named_gpio_flags(struct device_node *np, const char *list_name,
...@@ -122,6 +117,7 @@ EXPORT_SYMBOL(of_get_named_gpio_flags); ...@@ -122,6 +117,7 @@ EXPORT_SYMBOL(of_get_named_gpio_flags);
/** /**
* of_parse_own_gpio() - Get a GPIO hog descriptor, names and flags for GPIO API * of_parse_own_gpio() - Get a GPIO hog descriptor, names and flags for GPIO API
* @np: device node to get GPIO from * @np: device node to get GPIO from
* @chip: GPIO chip whose hog is parsed
* @name: GPIO line name * @name: GPIO line name
* @lflags: gpio_lookup_flags - returned from of_find_gpio() or * @lflags: gpio_lookup_flags - returned from of_find_gpio() or
* of_parse_own_gpio() * of_parse_own_gpio()
...@@ -131,19 +127,19 @@ EXPORT_SYMBOL(of_get_named_gpio_flags); ...@@ -131,19 +127,19 @@ EXPORT_SYMBOL(of_get_named_gpio_flags);
* value on the error condition. * value on the error condition.
*/ */
static struct gpio_desc *of_parse_own_gpio(struct device_node *np, static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
struct gpio_chip *chip,
const char **name, const char **name,
enum gpio_lookup_flags *lflags, enum gpio_lookup_flags *lflags,
enum gpiod_flags *dflags) enum gpiod_flags *dflags)
{ {
struct device_node *chip_np; struct device_node *chip_np;
enum of_gpio_flags xlate_flags; enum of_gpio_flags xlate_flags;
struct gg_data gg_data = { struct of_phandle_args gpiospec;
.flags = &xlate_flags, struct gpio_desc *desc;
};
u32 tmp; u32 tmp;
int i, ret; int ret;
chip_np = np->parent; chip_np = chip->of_node;
if (!chip_np) if (!chip_np)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
...@@ -155,25 +151,16 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np, ...@@ -155,25 +151,16 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
if (ret) if (ret)
return ERR_PTR(ret); return ERR_PTR(ret);
if (tmp > MAX_PHANDLE_ARGS) gpiospec.np = chip_np;
return ERR_PTR(-EINVAL); gpiospec.args_count = tmp;
gg_data.gpiospec.args_count = tmp; ret = of_property_read_u32_array(np, "gpios", gpiospec.args, tmp);
gg_data.gpiospec.np = chip_np; if (ret)
for (i = 0; i < tmp; i++) { return ERR_PTR(ret);
ret = of_property_read_u32_index(np, "gpios", i,
&gg_data.gpiospec.args[i]);
if (ret)
return ERR_PTR(ret);
}
gpiochip_find(&gg_data, of_gpiochip_find_and_xlate); desc = of_xlate_and_get_gpiod_flags(chip, &gpiospec, &xlate_flags);
if (!gg_data.out_gpio) { if (IS_ERR(desc))
if (np->parent == np) return desc;
return ERR_PTR(-ENXIO);
else
return ERR_PTR(-EINVAL);
}
if (xlate_flags & OF_GPIO_ACTIVE_LOW) if (xlate_flags & OF_GPIO_ACTIVE_LOW)
*lflags |= GPIO_ACTIVE_LOW; *lflags |= GPIO_ACTIVE_LOW;
...@@ -186,14 +173,14 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np, ...@@ -186,14 +173,14 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
*dflags |= GPIOD_OUT_HIGH; *dflags |= GPIOD_OUT_HIGH;
else { else {
pr_warn("GPIO line %d (%s): no hogging state specified, bailing out\n", pr_warn("GPIO line %d (%s): no hogging state specified, bailing out\n",
desc_to_gpio(gg_data.out_gpio), np->name); desc_to_gpio(desc), np->name);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
if (name && of_property_read_string(np, "line-name", name)) if (name && of_property_read_string(np, "line-name", name))
*name = np->name; *name = np->name;
return gg_data.out_gpio; return desc;
} }
/** /**
...@@ -262,7 +249,7 @@ static int of_gpiochip_scan_gpios(struct gpio_chip *chip) ...@@ -262,7 +249,7 @@ static int of_gpiochip_scan_gpios(struct gpio_chip *chip)
if (!of_property_read_bool(np, "gpio-hog")) if (!of_property_read_bool(np, "gpio-hog"))
continue; continue;
desc = of_parse_own_gpio(np, &name, &lflags, &dflags); desc = of_parse_own_gpio(np, chip, &name, &lflags, &dflags);
if (IS_ERR(desc)) if (IS_ERR(desc))
continue; continue;
...@@ -410,6 +397,7 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip) ...@@ -410,6 +397,7 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip)
break; break;
pctldev = of_pinctrl_get(pinspec.np); pctldev = of_pinctrl_get(pinspec.np);
of_node_put(pinspec.np);
if (!pctldev) if (!pctldev)
return -EPROBE_DEFER; return -EPROBE_DEFER;
...@@ -487,6 +475,9 @@ int of_gpiochip_add(struct gpio_chip *chip) ...@@ -487,6 +475,9 @@ int of_gpiochip_add(struct gpio_chip *chip)
chip->of_xlate = of_gpio_simple_xlate; chip->of_xlate = of_gpio_simple_xlate;
} }
if (chip->of_gpio_n_cells > MAX_PHANDLE_ARGS)
return -EINVAL;
status = of_gpiochip_add_pin_range(chip); status = of_gpiochip_add_pin_range(chip);
if (status) if (status)
return status; return status;
......
This diff is collapsed.
...@@ -1724,9 +1724,9 @@ static int pinmux_xway_probe(struct platform_device *pdev) ...@@ -1724,9 +1724,9 @@ static int pinmux_xway_probe(struct platform_device *pdev)
} }
xway_pctrl_desc.pins = xway_info.pads; xway_pctrl_desc.pins = xway_info.pads;
/* load the gpio chip */ /* register the gpio chip */
xway_chip.parent = &pdev->dev; xway_chip.parent = &pdev->dev;
ret = gpiochip_add(&xway_chip); ret = devm_gpiochip_add_data(&pdev->dev, &xway_chip, NULL);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Failed to register gpio chip\n"); dev_err(&pdev->dev, "Failed to register gpio chip\n");
return ret; return ret;
...@@ -1749,7 +1749,6 @@ static int pinmux_xway_probe(struct platform_device *pdev) ...@@ -1749,7 +1749,6 @@ static int pinmux_xway_probe(struct platform_device *pdev)
/* register with the generic lantiq layer */ /* register with the generic lantiq layer */
ret = ltq_pinctrl_register(pdev, &xway_info); ret = ltq_pinctrl_register(pdev, &xway_info);
if (ret) { if (ret) {
gpiochip_remove(&xway_chip);
dev_err(&pdev->dev, "Failed to register pinctrl driver\n"); dev_err(&pdev->dev, "Failed to register pinctrl driver\n");
return ret; return ret;
} }
......
/* /*
* <linux/gpio.h> - userspace ABI for the GPIO character devices * <linux/gpio.h> - userspace ABI for the GPIO character devices
* *
* Copyright (C) 2015 Linus Walleij * Copyright (C) 2016 Linus Walleij
* *
* 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
...@@ -26,8 +26,8 @@ struct gpiochip_info { ...@@ -26,8 +26,8 @@ struct gpiochip_info {
__u32 lines; __u32 lines;
}; };
/* Line is in use by the kernel */ /* Informational flags */
#define GPIOLINE_FLAG_KERNEL (1UL << 0) #define GPIOLINE_FLAG_KERNEL (1UL << 0) /* Line used by the kernel */
#define GPIOLINE_FLAG_IS_OUT (1UL << 1) #define GPIOLINE_FLAG_IS_OUT (1UL << 1)
#define GPIOLINE_FLAG_ACTIVE_LOW (1UL << 2) #define GPIOLINE_FLAG_ACTIVE_LOW (1UL << 2)
#define GPIOLINE_FLAG_OPEN_DRAIN (1UL << 3) #define GPIOLINE_FLAG_OPEN_DRAIN (1UL << 3)
...@@ -52,7 +52,106 @@ struct gpioline_info { ...@@ -52,7 +52,106 @@ struct gpioline_info {
char consumer[32]; char consumer[32];
}; };
/* Maximum number of requested handles */
#define GPIOHANDLES_MAX 64
/* Linerequest flags */
#define GPIOHANDLE_REQUEST_INPUT (1UL << 0)
#define GPIOHANDLE_REQUEST_OUTPUT (1UL << 1)
#define GPIOHANDLE_REQUEST_ACTIVE_LOW (1UL << 2)
#define GPIOHANDLE_REQUEST_OPEN_DRAIN (1UL << 3)
#define GPIOHANDLE_REQUEST_OPEN_SOURCE (1UL << 4)
/**
* struct gpiohandle_request - Information about a GPIO handle request
* @lineoffsets: an array desired lines, specified by offset index for the
* associated GPIO device
* @flags: desired flags for the desired GPIO lines, such as
* GPIOHANDLE_REQUEST_OUTPUT, GPIOHANDLE_REQUEST_ACTIVE_LOW etc, OR:ed
* together. Note that even if multiple lines are requested, the same flags
* must be applicable to all of them, if you want lines with individual
* flags set, request them one by one. It is possible to select
* a batch of input or output lines, but they must all have the same
* characteristics, i.e. all inputs or all outputs, all active low etc
* @default_values: if the GPIOHANDLE_REQUEST_OUTPUT is set for a requested
* line, this specifies the default output value, should be 0 (low) or
* 1 (high), anything else than 0 or 1 will be interpreted as 1 (high)
* @consumer_label: a desired consumer label for the selected GPIO line(s)
* such as "my-bitbanged-relay"
* @lines: number of lines requested in this request, i.e. the number of
* valid fields in the above arrays, set to 1 to request a single line
* @fd: if successful this field will contain a valid anonymous file handle
* after a GPIO_GET_LINEHANDLE_IOCTL operation, zero or negative value
* means error
*/
struct gpiohandle_request {
__u32 lineoffsets[GPIOHANDLES_MAX];
__u32 flags;
__u8 default_values[GPIOHANDLES_MAX];
char consumer_label[32];
__u32 lines;
int fd;
};
/**
* struct gpiohandle_data - Information of values on a GPIO handle
* @values: when getting the state of lines this contains the current
* state of a line, when setting the state of lines these should contain
* the desired target state
*/
struct gpiohandle_data {
__u8 values[GPIOHANDLES_MAX];
};
#define GPIOHANDLE_GET_LINE_VALUES_IOCTL _IOWR(0xB4, 0x08, struct gpiohandle_data)
#define GPIOHANDLE_SET_LINE_VALUES_IOCTL _IOWR(0xB4, 0x09, struct gpiohandle_data)
/* Eventrequest flags */
#define GPIOEVENT_REQUEST_RISING_EDGE (1UL << 0)
#define GPIOEVENT_REQUEST_FALLING_EDGE (1UL << 1)
#define GPIOEVENT_REQUEST_BOTH_EDGES ((1UL << 0) | (1UL << 1))
/**
* struct gpioevent_request - Information about a GPIO event request
* @lineoffset: the desired line to subscribe to events from, specified by
* offset index for the associated GPIO device
* @handleflags: desired handle flags for the desired GPIO line, such as
* GPIOHANDLE_REQUEST_ACTIVE_LOW or GPIOHANDLE_REQUEST_OPEN_DRAIN
* @eventflags: desired flags for the desired GPIO event line, such as
* GPIOEVENT_REQUEST_RISING_EDGE or GPIOEVENT_REQUEST_FALLING_EDGE
* @consumer_label: a desired consumer label for the selected GPIO line(s)
* such as "my-listener"
* @fd: if successful this field will contain a valid anonymous file handle
* after a GPIO_GET_LINEEVENT_IOCTL operation, zero or negative value
* means error
*/
struct gpioevent_request {
__u32 lineoffset;
__u32 handleflags;
__u32 eventflags;
char consumer_label[32];
int fd;
};
/**
* GPIO event types
*/
#define GPIOEVENT_EVENT_RISING_EDGE 0x01
#define GPIOEVENT_EVENT_FALLING_EDGE 0x02
/**
* struct gpioevent_data - The actual event being pushed to userspace
* @timestamp: best estimate of time of event occurrence, in nanoseconds
* @id: event identifier
*/
struct gpioevent_data {
__u64 timestamp;
__u32 id;
};
#define GPIO_GET_CHIPINFO_IOCTL _IOR(0xB4, 0x01, struct gpiochip_info) #define GPIO_GET_CHIPINFO_IOCTL _IOR(0xB4, 0x01, struct gpiochip_info)
#define GPIO_GET_LINEINFO_IOCTL _IOWR(0xB4, 0x02, struct gpioline_info) #define GPIO_GET_LINEINFO_IOCTL _IOWR(0xB4, 0x02, struct gpioline_info)
#define GPIO_GET_LINEHANDLE_IOCTL _IOWR(0xB4, 0x03, struct gpiohandle_request)
#define GPIO_GET_LINEEVENT_IOCTL _IOWR(0xB4, 0x04, struct gpioevent_request)
#endif /* _UAPI_GPIO_H_ */ #endif /* _UAPI_GPIO_H_ */
...@@ -85,7 +85,7 @@ tmon: FORCE ...@@ -85,7 +85,7 @@ tmon: FORCE
freefall: FORCE freefall: FORCE
$(call descend,laptop/$@) $(call descend,laptop/$@)
all: acpi cgroup cpupower hv firewire lguest \ all: acpi cgroup cpupower gpio hv firewire lguest \
perf selftests turbostat usb \ perf selftests turbostat usb \
virtio vm net x86_energy_perf_policy \ virtio vm net x86_energy_perf_policy \
tmon freefall objtool tmon freefall objtool
...@@ -96,7 +96,7 @@ acpi_install: ...@@ -96,7 +96,7 @@ acpi_install:
cpupower_install: cpupower_install:
$(call descend,power/$(@:_install=),install) $(call descend,power/$(@:_install=),install)
cgroup_install firewire_install hv_install lguest_install perf_install usb_install virtio_install vm_install net_install objtool_install: cgroup_install firewire_install gpio_install hv_install lguest_install perf_install usb_install virtio_install vm_install net_install objtool_install:
$(call descend,$(@:_install=),install) $(call descend,$(@:_install=),install)
selftests_install: selftests_install:
...@@ -114,7 +114,8 @@ freefall_install: ...@@ -114,7 +114,8 @@ freefall_install:
kvm_stat_install: kvm_stat_install:
$(call descend,kvm/$(@:_install=),install) $(call descend,kvm/$(@:_install=),install)
install: acpi_install cgroup_install cpupower_install hv_install firewire_install lguest_install \ install: acpi_install cgroup_install cpupower_install gpio_install \
hv_install firewire_install lguest_install \
perf_install selftests_install turbostat_install usb_install \ perf_install selftests_install turbostat_install usb_install \
virtio_install vm_install net_install x86_energy_perf_policy_install \ virtio_install vm_install net_install x86_energy_perf_policy_install \
tmon_install freefall_install objtool_install kvm_stat_install tmon_install freefall_install objtool_install kvm_stat_install
......
lsgpio-y += lsgpio.o gpio-utils.o
gpio-hammer-y += gpio-hammer.o gpio-utils.o
gpio-event-mon-y += gpio-event-mon.o gpio-utils.o
include ../scripts/Makefile.include
bindir ?= /usr/bin
ifeq ($(srctree),)
srctree := $(patsubst %/,%,$(dir $(shell pwd)))
srctree := $(patsubst %/,%,$(dir $(srctree)))
endif
# Do not use make's built-in rules
# (this improves performance and avoids hard-to-debug behaviour);
MAKEFLAGS += -r
CC = $(CROSS_COMPILE)gcc CC = $(CROSS_COMPILE)gcc
CFLAGS += -O2 -Wall -g -D_GNU_SOURCE LD = $(CROSS_COMPILE)ld
CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include
ALL_TARGETS := lsgpio gpio-hammer gpio-event-mon
ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS))
all: $(ALL_PROGRAMS)
all: lsgpio export srctree OUTPUT CC LD CFLAGS
include $(srctree)/tools/build/Makefile.include
lsgpio: lsgpio.o gpio-utils.o #
# We need the following to be outside of kernel tree
#
$(OUTPUT)include/linux/gpio.h: ../../include/uapi/linux/gpio.h
mkdir -p $(OUTPUT)include/linux 2>&1 || true
ln -sf $(CURDIR)/../../include/uapi/linux/gpio.h $@
%.o: %.c gpio-utils.h prepare: $(OUTPUT)include/linux/gpio.h
#
# lsgpio
#
LSGPIO_IN := $(OUTPUT)lsgpio-in.o
$(LSGPIO_IN): prepare FORCE
$(Q)$(MAKE) $(build)=lsgpio
$(OUTPUT)lsgpio: $(LSGPIO_IN)
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
#
# gpio-hammer
#
GPIO_HAMMER_IN := $(OUTPUT)gpio-hammer-in.o
$(GPIO_HAMMER_IN): prepare FORCE
$(Q)$(MAKE) $(build)=gpio-hammer
$(OUTPUT)gpio-hammer: $(GPIO_HAMMER_IN)
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
#
# gpio-event-mon
#
GPIO_EVENT_MON_IN := $(OUTPUT)gpio-event-mon-in.o
$(GPIO_EVENT_MON_IN): prepare FORCE
$(Q)$(MAKE) $(build)=gpio-event-mon
$(OUTPUT)gpio-event-mon: $(GPIO_EVENT_MON_IN)
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
.PHONY: clean
clean: clean:
rm -f *.o lsgpio rm -f $(ALL_PROGRAMS)
rm -f $(OUTPUT)include/linux/gpio.h
find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.d' -delete
install: $(ALL_PROGRAMS)
install -d -m 755 $(DESTDIR)$(bindir); \
for program in $(ALL_PROGRAMS); do \
install $$program $(DESTDIR)$(bindir); \
done
FORCE:
.PHONY: all install clean FORCE prepare
/*
* gpio-hammer - example swiss army knife to shake GPIO lines on a system
*
* Copyright (C) 2016 Linus Walleij
*
* 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.
*
* Usage:
* gpio-event-mon -n <device-name> -o <offset>
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include <poll.h>
#include <fcntl.h>
#include <getopt.h>
#include <inttypes.h>
#include <sys/ioctl.h>
#include <linux/gpio.h>
int monitor_device(const char *device_name,
unsigned int line,
u_int32_t handleflags,
u_int32_t eventflags,
unsigned int loops)
{
struct gpioevent_request req;
struct gpiohandle_data data;
char *chrdev_name;
int fd;
int ret;
int i = 0;
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;
}
req.lineoffset = line;
req.handleflags = handleflags;
req.eventflags = eventflags;
strcpy(req.consumer_label, "gpio-event-mon");
ret = ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &req);
if (ret == -1) {
ret = -errno;
fprintf(stderr, "Failed to issue GET EVENT "
"IOCTL (%d)\n",
ret);
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, "Monitoring line %d on %s\n", line, device_name);
fprintf(stdout, "Initial line value: %d\n", data.values[0]);
while (1) {
struct gpioevent_data event;
ret = read(req.fd, &event, sizeof(event));
if (ret == -1) {
if (errno == -EAGAIN) {
fprintf(stderr, "nothing available\n");
continue;
} else {
ret = -errno;
fprintf(stderr, "Failed to read event (%d)\n",
ret);
break;
}
}
if (ret != sizeof(event)) {
fprintf(stderr, "Reading event failed\n");
ret = -EIO;
break;
}
fprintf(stdout, "GPIO EVENT %" PRIu64 ": ", event.timestamp);
switch (event.id) {
case GPIOEVENT_EVENT_RISING_EDGE:
fprintf(stdout, "rising edge");
break;
case GPIOEVENT_EVENT_FALLING_EDGE:
fprintf(stdout, "falling edge");
break;
default:
fprintf(stdout, "unknown event");
}
fprintf(stdout, "\n");
i++;
if (i == loops)
break;
}
exit_close_error:
if (close(fd) == -1)
perror("Failed to close GPIO character device file");
free(chrdev_name);
return ret;
}
void print_usage(void)
{
fprintf(stderr, "Usage: gpio-event-mon [options]...\n"
"Listen to events on GPIO lines, 0->1 1->0\n"
" -n <name> Listen on GPIOs on a named device (must be stated)\n"
" -o <n> Offset to monitor\n"
" -d Set line as open drain\n"
" -s Set line as open source\n"
" -r Listen for rising edges\n"
" -f Listen for falling edges\n"
" [-c <n>] Do <n> loops (optional, infinite loop if not stated)\n"
" -? This helptext\n"
"\n"
"Example:\n"
"gpio-event-mon -n gpiochip0 -o 4 -r -f\n"
);
}
int main(int argc, char **argv)
{
const char *device_name = NULL;
unsigned int line = -1;
unsigned int loops = 0;
u_int32_t handleflags = GPIOHANDLE_REQUEST_INPUT;
u_int32_t eventflags = 0;
int c;
while ((c = getopt(argc, argv, "c:n:o:dsrf?")) != -1) {
switch (c) {
case 'c':
loops = strtoul(optarg, NULL, 10);
break;
case 'n':
device_name = optarg;
break;
case 'o':
line = strtoul(optarg, NULL, 10);
break;
case 'd':
handleflags |= GPIOHANDLE_REQUEST_OPEN_DRAIN;
break;
case 's':
handleflags |= GPIOHANDLE_REQUEST_OPEN_SOURCE;
break;
case 'r':
eventflags |= GPIOEVENT_REQUEST_RISING_EDGE;
break;
case 'f':
eventflags |= GPIOEVENT_REQUEST_FALLING_EDGE;
break;
case '?':
print_usage();
return -1;
}
}
if (!device_name || line == -1) {
print_usage();
return -1;
}
if (!eventflags) {
printf("No flags specified, listening on both rising and "
"falling edges\n");
eventflags = GPIOEVENT_REQUEST_BOTH_EDGES;
}
return monitor_device(device_name, line, handleflags,
eventflags, loops);
}
/*
* gpio-hammer - example swiss army knife to shake GPIO lines on a system
*
* Copyright (C) 2016 Linus Walleij
*
* 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.
*
* Usage:
* gpio-hammer -n <device-name> -o <offset1> -o <offset2>
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include <poll.h>
#include <fcntl.h>
#include <getopt.h>
#include <sys/ioctl.h>
#include <linux/gpio.h>
int hammer_device(const char *device_name, unsigned int *lines, int nlines,
unsigned int loops)
{
struct gpiohandle_request req;
struct gpiohandle_data data;
char *chrdev_name;
char swirr[] = "-\\|/";
int fd;
int ret;
int i, j;
unsigned int iteration = 0;
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;
}
/* 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;
}
/* 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 [");
for (i = 0; i < nlines; i++) {
fprintf(stdout, "%d", lines[i]);
if (i != (nlines - 1))
fprintf(stdout, ", ");
}
fprintf(stdout, "] on %s, initial states: [", device_name);
for (i = 0; i < nlines; i++) {
fprintf(stdout, "%d", data.values[i]);
if (i != (nlines - 1))
fprintf(stdout, ", ");
}
fprintf(stdout, "]\n");
/* Hammertime! */
j = 0;
while (1) {
/* Invert all lines so we blink */
for (i = 0; i < nlines; i++)
data.values[i] = !data.values[i];
ret = ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data);
if (ret == -1) {
ret = -errno;
fprintf(stderr, "Failed to issue GPIOHANDLE SET LINE "
"VALUES IOCTL (%d)\n",
ret);
goto exit_close_error;
}
/* Re-read values to get status */
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, "[%c] ", swirr[j]);
j++;
if (j == sizeof(swirr)-1)
j = 0;
fprintf(stdout, "[");
for (i = 0; i < nlines; i++) {
fprintf(stdout, "%d: %d", lines[i], data.values[i]);
if (i != (nlines - 1))
fprintf(stdout, ", ");
}
fprintf(stdout, "]\r");
fflush(stdout);
sleep(1);
iteration++;
if (loops && iteration == loops)
break;
}
fprintf(stdout, "\n");
ret = 0;
exit_close_error:
if (close(fd) == -1)
perror("Failed to close GPIO character device file");
free(chrdev_name);
return ret;
}
void print_usage(void)
{
fprintf(stderr, "Usage: gpio-hammer [options]...\n"
"Hammer GPIO lines, 0->1->0->1...\n"
" -n <name> Hammer GPIOs on a named device (must be stated)\n"
" -o <n> Offset[s] to hammer, at least one, several can be stated\n"
" [-c <n>] Do <n> loops (optional, infinite loop if not stated)\n"
" -? This helptext\n"
"\n"
"Example:\n"
"gpio-hammer -n gpiochip0 -o 4\n"
);
}
int main(int argc, char **argv)
{
const char *device_name = NULL;
unsigned int lines[GPIOHANDLES_MAX];
unsigned int loops = 0;
int nlines;
int c;
int i;
i = 0;
while ((c = getopt(argc, argv, "c:n:o:?")) != -1) {
switch (c) {
case 'c':
loops = strtoul(optarg, NULL, 10);
break;
case 'n':
device_name = optarg;
break;
case 'o':
lines[i] = strtoul(optarg, NULL, 10);
i++;
break;
case '?':
print_usage();
return -1;
}
}
nlines = i;
if (!device_name || !nlines) {
print_usage();
return -1;
}
return hammer_device(device_name, lines, nlines, loops);
}
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