diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-17 17:39:42 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-17 17:39:42 -0700 |
commit | 1eccc6e1529ec7ad1cebbd2c97ceb2a1a39f7d76 (patch) | |
tree | 725aff1150489e706b2b8b854b195a7a50dc6501 | |
parent | dcc4c2f61cdc7e0ab61b25b8d28205302497a8c4 (diff) | |
parent | d30a2b47d4c2b75573d93f60655d48ba8e3ed2b3 (diff) | |
download | op-kernel-dev-1eccc6e1529ec7ad1cebbd2c97ceb2a1a39f7d76.zip op-kernel-dev-1eccc6e1529ec7ad1cebbd2c97ceb2a1a39f7d76.tar.gz |
Merge tag 'gpio-v4.7-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 kernel cycle v4.7:
Core infrastructural changes:
- Support for natively single-ended GPIO driver stages.
This means that if the hardware has registers to configure open
drain or open source configuration, we use that rather than (as we
did before) try to emulate it by switching the line to an input to
get high impedance.
This is also documented throughly in Documentation/gpio/driver.txt
for those of you who did not understand one word of what I just
wrote.
- Start to do away with the unnecessarily complex and unitelligible
ARCH_REQUIRE_GPIOLIB and ARCH_WANT_OPTIONAL_GPIOLIB, another
evolutional artifact from the time when the GPIO subsystem was
unmaintained.
Archs can now just select GPIOLIB and be done with it, cleanups to
arches will trickle in for the next kernel. Some minor archs ACKed
the changes immediately so these are included in this pull request.
- Advancing the use of the data pointer inside the GPIO device for
storing driver data by switching the PowerPC, Super-H Unicore and
a few other subarches or subsystem drivers in ALSA SoC, Input,
serial, SSB, staging etc to use it.
- The initialization now reads the input/output state of the GPIO
lines, so that each GPIO descriptor knows - if this callback is
implemented - whether the line is input or output. This also
reflects nicely in userspace "lsgpio".
- It is now possible to name GPIO producer names, line names, from
the device tree. (Platform data has been supported for a while).
I bet we will get a similar mechanism for ACPI one of those days.
This makes is possible to get sensible producer names for e.g.
GPIO rails in "lsgpio" in userspace.
New drivers:
- New driver for the Loongson1.
- The XLP driver now supports Broadcom Vulcan ARM64.
- The IT87 driver now supports IT8620 and IT8628.
- The PCA953X driver now supports Galileo Gen2.
Driver improvements:
- MCP23S08 was switched to use the gpiolib irqchip helpers and now
also suppors level-triggered interrupts.
- 74x164 and RCAR now supports the .set_multiple() callback
- AMDPT was converted to use generic GPIO.
- TC3589x, TPS65218, SX150X, F7188X, MENZ127, VX855, WM831X, WM8994
support the new single ended callback for open drain and in some
cases open source.
- Implement the .get_direction() callback for a few more drivers like
PL061, Xgene.
Cleanups:
- Paul Gortmaker combed through the drivers and de-modularized those
who are not really modules.
- Move the GPIO poweroff DT bindings to the power subdir where they
belong.
- Rename gpio-generic.c to gpio-mmio.c, which is much more to the
point. That's what it is handling, nothing more, nothing less"
* tag 'gpio-v4.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (126 commits)
MIPS: do away with ARCH_[WANT_OPTIONAL|REQUIRE]_GPIOLIB
gpio: zevio: make it explicitly non-modular
gpio: timberdale: make it explicitly non-modular
gpio: stmpe: make it explicitly non-modular
gpio: sodaville: make it explicitly non-modular
pinctrl: sh-pfc: Let gpio_chip.to_irq() return zero on error
gpio: dwapb: Add ACPI device ID for DWAPB GPIO controller on X-Gene platforms
gpio: dt-bindings: add wd,mbl-gpio bindings
gpio: of: make it possible to name GPIO lines
gpio: make gpiod_to_irq() return negative for NO_IRQ
gpio: xgene: implement .get_direction()
gpio: xgene: Enable ACPI support for X-Gene GFC GPIO driver
gpio: tegra: Implement gpio_get_direction callback
gpio: set up initial state from .get_direction()
gpio: rename gpio-generic.c into gpio-mmio.c
gpio: generic: fix GPIO_GENERIC_PLATFORM is set to module case
gpio: dwapb: add gpio-signaled acpi event support
gpio: dwapb: convert device node to fwnode
gpio: dwapb: remove name from dwapb_port_property
gpio/qoriq: select IRQ_DOMAIN
...
101 files changed, 1566 insertions, 1169 deletions
diff --git a/Documentation/devicetree/bindings/gpio/gpio-74x164.txt b/Documentation/devicetree/bindings/gpio/gpio-74x164.txt index cc26080..ce1b223 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-74x164.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-74x164.txt @@ -1,7 +1,9 @@ * Generic 8-bits shift register GPIO driver Required properties: -- compatible : Should be "fairchild,74hc595" +- compatible: Should contain one of the following: + "fairchild,74hc595" + "nxp,74lvc594" - reg : chip select number - gpio-controller : Marks the device node as a gpio controller. - #gpio-cells : Should be two. The first cell is the pin number and diff --git a/Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt b/Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt index 120bc49..4b6cc63 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt @@ -1,9 +1,10 @@ -* Freescale MPC512x/MPC8xxx/Layerscape GPIO controller +* Freescale MPC512x/MPC8xxx/QorIQ/Layerscape GPIO controller Required properties: - compatible : Should be "fsl,<soc>-gpio" The following <soc>s are known to be supported: - mpc5121, mpc5125, mpc8349, mpc8572, mpc8610, pq3, qoriq. + mpc5121, mpc5125, mpc8349, mpc8572, mpc8610, pq3, qoriq, + ls1021a, ls1043a, ls2080a. - reg : Address and length of the register set for the device - interrupts : Should be the port interrupt shared by all 32 pins. - #gpio-cells : Should be two. The first cell is the pin number and @@ -15,7 +16,7 @@ Optional properties: - little-endian : GPIO registers are used as little endian. If not present registers are used as big endian by default. -Example: +Example of gpio-controller node for a mpc5125 SoC: gpio0: gpio@1100 { compatible = "fsl,mpc5125-gpio"; @@ -24,3 +25,16 @@ gpio0: gpio@1100 { interrupts = <78 0x8>; status = "okay"; }; + +Example of gpio-controller node for a ls2080a SoC: + +gpio0: gpio@2300000 { + compatible = "fsl,ls2080a-gpio", "fsl,qoriq-gpio"; + reg = <0x0 0x2300000 0x0 0x10000>; + interrupts = <0 36 0x4>; /* Level high type */ + gpio-controller; + little-endian; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; +}; diff --git a/Documentation/devicetree/bindings/gpio/gpio-xlp.txt b/Documentation/devicetree/bindings/gpio/gpio-xlp.txt index 262ee4d..28662d8 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-xlp.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-xlp.txt @@ -3,6 +3,8 @@ Netlogic XLP Family GPIO This GPIO driver is used for following Netlogic XLP SoCs: XLP832, XLP316, XLP208, XLP980, XLP532 +This GPIO driver is also compatible with GPIO controller found on +Broadcom Vulcan ARM64. Required properties: ------------------- @@ -13,6 +15,7 @@ Required properties: - "netlogic,xlp208-gpio": For Netlogic XLP208 - "netlogic,xlp980-gpio": For Netlogic XLP980 - "netlogic,xlp532-gpio": For Netlogic XLP532 + - "brcm,vulcan-gpio": For Broadcom Vulcan ARM64 - reg: Physical base address and length of the controller's registers. - #gpio-cells: Should be two. The first cell is the pin number and the second cell is used to specify optional parameters (currently unused). diff --git a/Documentation/devicetree/bindings/gpio/gpio.txt b/Documentation/devicetree/bindings/gpio/gpio.txt index 069cdf6..68d28f6 100644 --- a/Documentation/devicetree/bindings/gpio/gpio.txt +++ b/Documentation/devicetree/bindings/gpio/gpio.txt @@ -131,6 +131,13 @@ Every GPIO controller node must contain both an empty "gpio-controller" property, and a #gpio-cells integer property, which indicates the number of cells in a gpio-specifier. +Some system-on-chips (SoCs) use the concept of GPIO banks. A GPIO bank is an +instance of a hardware IP core on a silicon die, usually exposed to the +programmer as a coherent range of I/O addresses. Usually each such bank is +exposed in the device tree as an individual gpio-controller node, reflecting +the fact that the hardware was synthesized by reusing the same IP block a +few times over. + Optionally, a GPIO controller may have a "ngpios" property. This property indicates the number of in-use slots of available slots for GPIOs. The typical example is something like this: the hardware register is 32 bits @@ -145,6 +152,21 @@ additional bitmask is needed to specify which GPIOs are actually in use, and which are dummies. The bindings for this case has not yet been specified, but should be specified if/when such hardware appears. +Optionally, a GPIO controller may have a "gpio-line-names" property. This is +an array of strings defining the names of the GPIO lines going out of the +GPIO controller. This name should be the most meaningful producer name +for the system, such as a rail name indicating the usage. Package names +such as pin name are discouraged: such lines have opaque names (since they +are by definition generic purpose) and such names are usually not very +helpful. For example "MMC-CD", "Red LED Vdd" and "ethernet reset" are +reasonable line names as they describe what the line is used for. "GPIO0" +is not a good name to give to a GPIO line. Placeholders are discouraged: +rather use the "" (blank string) if the use of the GPIO line is undefined +in your design. The names are assigned starting from line offset 0 from +left to right from the passed array. An incomplete array (where the number +of passed named are less than ngpios) will still be used up until the last +provided valid line index. + Example: gpio-controller@00000000 { @@ -153,6 +175,10 @@ gpio-controller@00000000 { gpio-controller; #gpio-cells = <2>; ngpios = <18>; + gpio-line-names = "MMC-CD", "MMC-WP", "VDD eth", "RST eth", "LED R", + "LED G", "LED B", "Col A", "Col B", "Col C", "Col D", + "Row A", "Row B", "Row C", "Row D", "NMI button", + "poweroff", "reset"; } The GPIO chip may contain GPIO hog definitions. GPIO hogging is a mechanism diff --git a/Documentation/devicetree/bindings/gpio/wd,mbl-gpio.txt b/Documentation/devicetree/bindings/gpio/wd,mbl-gpio.txt new file mode 100644 index 0000000..038c3a6 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/wd,mbl-gpio.txt @@ -0,0 +1,38 @@ +Bindings for the Western Digital's MyBook Live memory-mapped GPIO controllers. + +The Western Digital MyBook Live has two memory-mapped GPIO controllers. +Both GPIO controller only have a single 8-bit data register, where GPIO +state can be read and/or written. + +Required properties: + - compatible: should be "wd,mbl-gpio" + - reg-names: must contain + "dat" - data register + - reg: address + size pairs describing the GPIO register sets; + order must correspond with the order of entries in reg-names + - #gpio-cells: must be set to 2. The first cell is the pin number and + the second cell is used to specify the gpio polarity: + 0 = active high + 1 = active low + - gpio-controller: Marks the device node as a gpio controller. + +Optional properties: + - no-output: GPIOs are read-only. + +Examples: + gpio0: gpio0@e0000000 { + compatible = "wd,mbl-gpio"; + reg-names = "dat"; + reg = <0xe0000000 0x1>; + #gpio-cells = <2>; + gpio-controller; + }; + + gpio1: gpio1@e0100000 { + compatible = "wd,mbl-gpio"; + reg-names = "dat"; + reg = <0xe0100000 0x1>; + #gpio-cells = <2>; + gpio-controller; + no-output; + }; diff --git a/Documentation/devicetree/bindings/gpio/gpio-poweroff.txt b/Documentation/devicetree/bindings/power/reset/gpio-poweroff.txt index d4eab92..d4eab92 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-poweroff.txt +++ b/Documentation/devicetree/bindings/power/reset/gpio-poweroff.txt diff --git a/Documentation/devicetree/bindings/gpio/gpio-restart.txt b/Documentation/devicetree/bindings/power/reset/gpio-restart.txt index af3701b..af3701b 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-restart.txt +++ b/Documentation/devicetree/bindings/power/reset/gpio-restart.txt diff --git a/Documentation/gpio/driver.txt b/Documentation/gpio/driver.txt index bbeec41..6cb35a7 100644 --- a/Documentation/gpio/driver.txt +++ b/Documentation/gpio/driver.txt @@ -68,6 +68,103 @@ control callbacks) if it is expected to call GPIO APIs from atomic context on -RT (inside hard IRQ handlers and similar contexts). Normally this should not be required. + +GPIOs with open drain/source support +------------------------------------ + +Open drain (CMOS) or open collector (TTL) means the line is not actively driven +high: instead you provide the drain/collector as output, so when the transistor +is not open, it will present a high-impedance (tristate) to the external rail. + + + CMOS CONFIGURATION TTL CONFIGURATION + + ||--- out +--- out + in ----|| |/ + ||--+ in ----| + | |\ + GND GND + +This configuration is normally used as a way to achieve one of two things: + +- Level-shifting: to reach a logical level higher than that of the silicon + where the output resides. + +- inverse wire-OR on an I/O line, for example a GPIO line, making it possible + for any driving stage on the line to drive it low even if any other output + to the same line is simultaneously driving it high. A special case of this + is driving the SCL and SCA lines of an I2C bus, which is by definition a + wire-OR bus. + +Both usecases require that the line be equipped with a pull-up resistor. This +resistor will make the line tend to high level unless one of the transistors on +the rail actively pulls it down. + +The level on the line will go as high as the VDD on the pull-up resistor, which +may be higher than the level supported by the transistor, achieveing a +level-shift to the higher VDD. + +Integrated electronics often have an output driver stage in the form of a CMOS +"totem-pole" with one N-MOS and one P-MOS transistor where one of them drives +the line high and one of them drives the line low. This is called a push-pull +output. The "totem-pole" looks like so: + + VDD + | + OD ||--+ + +--/ ---o|| P-MOS-FET + | ||--+ +IN --+ +----- out + | ||--+ + +--/ ----|| N-MOS-FET + OS ||--+ + | + GND + +The desired output signal (e.g. coming directly from some GPIO output register) +arrives at IN. The switches named "OD" and "OS" are normally closed, creating +a push-pull circuit. + +Consider the little "switches" named "OD" and "OS" that enable/disable the +P-MOS or N-MOS transistor right after the split of the input. As you can see, +either transistor will go totally numb if this switch is open. The totem-pole +is then halved and give high impedance instead of actively driving the line +high or low respectively. That is usually how software-controlled open +drain/source works. + +Some GPIO hardware come in open drain / open source configuration. Some are +hard-wired lines that will only support open drain or open source no matter +what: there is only one transistor there. Some are software-configurable: +by flipping a bit in a register the output can be configured as open drain +or open source, in practice by flicking open the switches labeled "OD" and "OS" +in the drawing above. + +By disabling the P-MOS transistor, the output can be driven between GND and +high impedance (open drain), and by disabling the N-MOS transistor, the output +can be driven between VDD and high impedance (open source). In the first case, +a pull-up resistor is needed on the outgoing rail to complete the circuit, and +in the second case, a pull-down resistor is needed on the rail. + +Hardware that supports open drain or open source or both, can implement a +special callback in the gpio_chip: .set_single_ended() that takes an enum flag +telling whether to configure the line as open drain, open source or push-pull. +This will happen in response to the GPIO_OPEN_DRAIN or GPIO_OPEN_SOURCE flag +set in the machine file, or coming from other hardware descriptions. + +If this state can not be configured in hardware, i.e. if the GPIO hardware does +not support open drain/open source in hardware, the GPIO library will instead +use a trick: when a line is set as output, if the line is flagged as open +drain, and the IN output value is low, it will be driven low as usual. But +if the IN output value is set to high, it will instead *NOT* be driven high, +instead it will be switched to input, as input mode is high impedance, thus +achieveing an "open drain emulation" of sorts: electrically the behaviour will +be identical, with the exception of possible hardware glitches when switching +the mode of the line. + +For open source configuration the same principle is used, just that instead +of actively driving the line low, it is set to input. + + GPIO drivers providing IRQs --------------------------- It is custom that GPIO drivers (GPIO chips) are also providing interrupts, diff --git a/MAINTAINERS b/MAINTAINERS index 1dd9335..8267754 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4902,6 +4902,7 @@ M: Alexandre Courbot <gnurou@gmail.com> L: linux-gpio@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git S: Maintained +F: Documentation/devicetree/bindings/gpio/ F: Documentation/gpio/ F: Documentation/ABI/testing/gpio-cdev F: Documentation/ABI/obsolete/sysfs-gpio diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index 9d8a858..fe99f89 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig @@ -13,7 +13,6 @@ config ALPHA select GENERIC_IRQ_PROBE select AUTO_IRQ_AFFINITY if SMP select GENERIC_IRQ_SHOW - select ARCH_WANT_OPTIONAL_GPIOLIB select ARCH_WANT_IPC_PARSE_VERSION select ARCH_HAVE_NMI_SAFE_CMPXCHG select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE diff --git a/arch/arc/plat-axs10x/Kconfig b/arch/arc/plat-axs10x/Kconfig index 426ac4b..c54d1ae 100644 --- a/arch/arc/plat-axs10x/Kconfig +++ b/arch/arc/plat-axs10x/Kconfig @@ -13,7 +13,7 @@ menuconfig ARC_PLAT_AXS10X select OF_GPIO select MIGHT_HAVE_PCI select GENERIC_IRQ_CHIP - select ARCH_REQUIRE_GPIOLIB + select GPIOLIB help Support for the ARC AXS10x Software Development Platforms. diff --git a/arch/arc/plat-tb10x/Kconfig b/arch/arc/plat-tb10x/Kconfig index d14b3d3..149e091 100644 --- a/arch/arc/plat-tb10x/Kconfig +++ b/arch/arc/plat-tb10x/Kconfig @@ -21,7 +21,7 @@ menuconfig ARC_PLAT_TB10X select PINCTRL select PINCTRL_TB10X select PINMUX - select ARCH_REQUIRE_GPIOLIB + select GPIOLIB select GPIO_TB10X select TB10X_IRQC help diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig index b6878eb..18b8877 100644 --- a/arch/avr32/Kconfig +++ b/arch/avr32/Kconfig @@ -74,7 +74,7 @@ config PLATFORM_AT32AP select SUBARCH_AVR32B select MMU select PERFORMANCE_COUNTERS - select ARCH_REQUIRE_GPIOLIB + select GPIOLIB select GENERIC_ALLOCATOR select HAVE_FB_ATMEL diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index e086f9e..99bda1b 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig @@ -61,7 +61,7 @@ config CRIS select CLONE_BACKWARDS2 select OLD_SIGSUSPEND select OLD_SIGACTION - select ARCH_REQUIRE_GPIOLIB + select GPIOLIB select IRQ_DOMAIN if ETRAX_ARCH_V32 select OF if ETRAX_ARCH_V32 select OF_EARLY_FLATTREE if ETRAX_ARCH_V32 diff --git a/arch/m68k/Kconfig.cpu b/arch/m68k/Kconfig.cpu index 0dfcf12..c1beb5a 100644 --- a/arch/m68k/Kconfig.cpu +++ b/arch/m68k/Kconfig.cpu @@ -22,11 +22,11 @@ config M68KCLASSIC config COLDFIRE bool "Coldfire CPU family support" - select ARCH_REQUIRE_GPIOLIB select ARCH_HAVE_CUSTOM_GPIO_H select CPU_HAS_NO_BITFIELDS select CPU_HAS_NO_MULDIV64 select GENERIC_CSUM + select GPIOLIB select HAVE_CLK endchoice diff --git a/arch/metag/Kconfig.soc b/arch/metag/Kconfig.soc index 973640f..50f979c 100644 --- a/arch/metag/Kconfig.soc +++ b/arch/metag/Kconfig.soc @@ -16,7 +16,6 @@ config META21_FPGA config SOC_TZ1090 bool "Toumaz Xenif TZ1090 SoC (Comet)" - select ARCH_WANT_OPTIONAL_GPIOLIB select IMGPDC_IRQ select METAG_LNKGET_AROUND_CACHE select METAG_META21 diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 3ee1ea6..d2ac117 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -79,7 +79,7 @@ config MIPS_ALCHEMY select SYS_HAS_CPU_MIPS32_R1 select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_APM_EMULATION - select ARCH_REQUIRE_GPIOLIB + select GPIOLIB select SYS_SUPPORTS_ZBOOT select COMMON_CLK @@ -98,7 +98,7 @@ config AR7 select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_SUPPORTS_MIPS16 select SYS_SUPPORTS_ZBOOT_UART16550 - select ARCH_REQUIRE_GPIOLIB + select GPIOLIB select VLYNQ select HAVE_CLK help @@ -122,11 +122,11 @@ config ATH25 config ATH79 bool "Atheros AR71XX/AR724X/AR913X based boards" select ARCH_HAS_RESET_CONTROLLER - select ARCH_REQUIRE_GPIOLIB select BOOT_RAW select CEVT_R4K select CSRC_R4K select DMA_NONCOHERENT + select GPIOLIB select HAVE_CLK select COMMON_CLK select CLKDEV_LOOKUP @@ -170,7 +170,6 @@ config BMIPS_GENERIC select USB_EHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN select USB_OHCI_BIG_ENDIAN_DESC if CPU_BIG_ENDIAN select USB_OHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN - select ARCH_WANT_OPTIONAL_GPIOLIB help Build a generic DT-based kernel image that boots on select BCM33xx cable modem chips, BCM63xx DSL chips, and BCM7xxx set-top @@ -179,7 +178,6 @@ config BMIPS_GENERIC config BCM47XX bool "Broadcom BCM47XX based boards" - select ARCH_WANT_OPTIONAL_GPIOLIB select BOOT_RAW select CEVT_R4K select CSRC_R4K @@ -211,7 +209,7 @@ config BCM63XX select SYS_SUPPORTS_BIG_ENDIAN select SYS_HAS_EARLY_PRINTK select SWAP_IO_SPACE - select ARCH_REQUIRE_GPIOLIB + select GPIOLIB select HAVE_CLK select MIPS_L1_CACHE_SHIFT_4 help @@ -305,7 +303,7 @@ config MACH_INGENIC select SYS_SUPPORTS_ZBOOT_UART16550 select DMA_NONCOHERENT select IRQ_MIPS_CPU - select ARCH_REQUIRE_GPIOLIB + select GPIOLIB select COMMON_CLK select GENERIC_IRQ_CHIP select BUILTIN_DTB @@ -325,7 +323,7 @@ config LANTIQ select SYS_SUPPORTS_MIPS16 select SYS_SUPPORTS_MULTITHREADING select SYS_HAS_EARLY_PRINTK - select ARCH_REQUIRE_GPIOLIB + select GPIOLIB select SWAP_IO_SPACE select BOOT_RAW select CLKDEV_LOOKUP @@ -377,7 +375,6 @@ config MACH_LOONGSON64 config MACH_PISTACHIO bool "IMG Pistachio SoC based boards" - select ARCH_REQUIRE_GPIOLIB select BOOT_ELF32 select BOOT_RAW select CEVT_R4K @@ -385,6 +382,7 @@ config MACH_PISTACHIO select COMMON_CLK select CSRC_R4K select DMA_MAYBE_COHERENT + select GPIOLIB select IRQ_MIPS_CPU select LIBFDT select MFD_SYSCON @@ -406,13 +404,13 @@ config MACH_PISTACHIO config MACH_XILFPGA bool "MIPSfpga Xilinx based boards" - select ARCH_REQUIRE_GPIOLIB select BOOT_ELF32 select BOOT_RAW select BUILTIN_DTB select CEVT_R4K select COMMON_CLK select CSRC_R4K + select GPIOLIB select IRQ_MIPS_CPU select LIBFDT select MIPS_CPU_SCACHE @@ -536,7 +534,7 @@ config MACH_VR41XX select CSRC_R4K select SYS_HAS_CPU_VR41XX select SYS_SUPPORTS_MIPS16 - select ARCH_REQUIRE_GPIOLIB + select GPIOLIB config NXP_STB220 bool "NXP STB220 board" @@ -856,7 +854,7 @@ config MIKROTIK_RB532 select SYS_SUPPORTS_LITTLE_ENDIAN select SWAP_IO_SPACE select BOOT_RAW - select ARCH_REQUIRE_GPIOLIB + select GPIOLIB select MIPS_L1_CACHE_SHIFT_4 help Support the Mikrotik(tm) RouterBoard 532 series, @@ -879,7 +877,7 @@ config CAVIUM_OCTEON_SOC select HW_HAS_PCI select ZONE_DMA32 select HOLES_IN_ZONE - select ARCH_REQUIRE_GPIOLIB + select GPIOLIB select LIBFDT select USE_OF select ARCH_SPARSEMEM_ENABLE @@ -937,7 +935,7 @@ config NLM_XLP_BOARD select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_64BIT_KERNEL select ARCH_PHYS_ADDR_T_64BIT - select ARCH_REQUIRE_GPIOLIB + select GPIOLIB select SYS_SUPPORTS_BIG_ENDIAN select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_SUPPORTS_HIGHMEM @@ -1077,7 +1075,7 @@ config MIPS_CLOCK_VSYSCALL def_bool CSRC_R4K || CLKSRC_MIPS_GIC config GPIO_TXX9 - select ARCH_REQUIRE_GPIOLIB + select GPIOLIB bool config FW_CFE @@ -1342,7 +1340,7 @@ config CPU_LOONGSON3 select CPU_SUPPORTS_HUGEPAGES select WEAK_ORDERING select WEAK_REORDERING_BEYOND_LLSC - select ARCH_REQUIRE_GPIOLIB + select GPIOLIB help The Loongson 3 processor implements the MIPS64R2 instruction set with many extensions. @@ -1362,7 +1360,7 @@ config CPU_LOONGSON2F bool "Loongson 2F" depends on SYS_HAS_CPU_LOONGSON2F select CPU_LOONGSON2 - select ARCH_REQUIRE_GPIOLIB + select GPIOLIB help The Loongson 2F processor implements the MIPS III instruction set with many extensions. diff --git a/arch/mips/alchemy/Kconfig b/arch/mips/alchemy/Kconfig index 7fa2488..88b4d6a 100644 --- a/arch/mips/alchemy/Kconfig +++ b/arch/mips/alchemy/Kconfig @@ -20,7 +20,7 @@ config MIPS_MTX1 config MIPS_DB1XXX bool "Alchemy DB1XXX / PB1XXX boards" - select ARCH_REQUIRE_GPIOLIB + select GPIOLIB select HW_HAS_PCI select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_HAS_EARLY_PRINTK diff --git a/arch/mips/pic32/Kconfig b/arch/mips/pic32/Kconfig index 1985971..527d37d 100644 --- a/arch/mips/pic32/Kconfig +++ b/arch/mips/pic32/Kconfig @@ -14,7 +14,7 @@ config PIC32MZDA select SYS_HAS_EARLY_PRINTK select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_LITTLE_ENDIAN - select ARCH_REQUIRE_GPIOLIB + select GPIOLIB select COMMON_CLK select CLKDEV_LOOKUP select LIBFDT diff --git a/arch/nios2/Kconfig b/arch/nios2/Kconfig index 4375554..87ca653 100644 --- a/arch/nios2/Kconfig +++ b/arch/nios2/Kconfig @@ -1,6 +1,5 @@ config NIOS2 def_bool y - select ARCH_WANT_OPTIONAL_GPIOLIB select CLKSRC_OF select GENERIC_ATOMIC64 select GENERIC_CLOCKEVENTS diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c index 3048e34..22645a7 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c @@ -278,14 +278,9 @@ mpc52xx_gpt_irq_setup(struct mpc52xx_gpt_priv *gpt, struct device_node *node) * GPIOLIB hooks */ #if defined(CONFIG_GPIOLIB) -static inline struct mpc52xx_gpt_priv *gc_to_mpc52xx_gpt(struct gpio_chip *gc) -{ - return container_of(gc, struct mpc52xx_gpt_priv, gc); -} - static int mpc52xx_gpt_gpio_get(struct gpio_chip *gc, unsigned int gpio) { - struct mpc52xx_gpt_priv *gpt = gc_to_mpc52xx_gpt(gc); + struct mpc52xx_gpt_priv *gpt = gpiochip_get_data(gc); return (in_be32(&gpt->regs->status) >> 8) & 1; } @@ -293,7 +288,7 @@ static int mpc52xx_gpt_gpio_get(struct gpio_chip *gc, unsigned int gpio) static void mpc52xx_gpt_gpio_set(struct gpio_chip *gc, unsigned int gpio, int v) { - struct mpc52xx_gpt_priv *gpt = gc_to_mpc52xx_gpt(gc); + struct mpc52xx_gpt_priv *gpt = gpiochip_get_data(gc); unsigned long flags; u32 r; @@ -307,7 +302,7 @@ mpc52xx_gpt_gpio_set(struct gpio_chip *gc, unsigned int gpio, int v) static int mpc52xx_gpt_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) { - struct mpc52xx_gpt_priv *gpt = gc_to_mpc52xx_gpt(gc); + struct mpc52xx_gpt_priv *gpt = gpiochip_get_data(gc); unsigned long flags; dev_dbg(gpt->dev, "%s: gpio:%d\n", __func__, gpio); @@ -354,9 +349,9 @@ mpc52xx_gpt_gpio_setup(struct mpc52xx_gpt_priv *gpt, struct device_node *node) clrsetbits_be32(&gpt->regs->mode, MPC52xx_GPT_MODE_MS_MASK, MPC52xx_GPT_MODE_MS_GPIO); - rc = gpiochip_add(&gpt->gc); + rc = gpiochip_add_data(&gpt->gc, gpt); if (rc) - dev_err(gpt->dev, "gpiochip_add() failed; rc=%i\n", rc); + dev_err(gpt->dev, "gpiochip_add_data() failed; rc=%i\n", rc); dev_dbg(gpt->dev, "%s() complete.\n", __func__); } diff --git a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c index 15e8021..dbcd030 100644 --- a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c +++ b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c @@ -16,7 +16,7 @@ #include <linux/device.h> #include <linux/mutex.h> #include <linux/i2c.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/of.h> #include <linux/of_gpio.h> #include <linux/slab.h> @@ -99,7 +99,7 @@ static void mcu_power_off(void) static void mcu_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) { - struct mcu *mcu = container_of(gc, struct mcu, gc); + struct mcu *mcu = gpiochip_get_data(gc); u8 bit = 1 << (4 + gpio); mutex_lock(&mcu->lock); @@ -136,7 +136,7 @@ static int mcu_gpiochip_add(struct mcu *mcu) gc->direction_output = mcu_gpio_dir_out; gc->of_node = np; - return gpiochip_add(gc); + return gpiochip_add_data(gc, mcu); } static int mcu_gpiochip_remove(struct mcu *mcu) diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c index 8ed6536..6c11099 100644 --- a/arch/powerpc/sysdev/cpm1.c +++ b/arch/powerpc/sysdev/cpm1.c @@ -532,15 +532,9 @@ struct cpm1_gpio16_chip { u16 cpdata; }; -static inline struct cpm1_gpio16_chip * -to_cpm1_gpio16_chip(struct of_mm_gpio_chip *mm_gc) -{ - return container_of(mm_gc, struct cpm1_gpio16_chip, mm_gc); -} - static void cpm1_gpio16_save_regs(struct of_mm_gpio_chip *mm_gc) { - struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc); + struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); struct cpm_ioport16 __iomem *iop = mm_gc->regs; cpm1_gc->cpdata = in_be16(&iop->dat); @@ -560,7 +554,7 @@ static int cpm1_gpio16_get(struct gpio_chip *gc, unsigned int gpio) static void __cpm1_gpio16_set(struct of_mm_gpio_chip *mm_gc, u16 pin_mask, int value) { - struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc); + struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); struct cpm_ioport16 __iomem *iop = mm_gc->regs; if (value) @@ -574,7 +568,7 @@ static void __cpm1_gpio16_set(struct of_mm_gpio_chip *mm_gc, u16 pin_mask, static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc); + struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); unsigned long flags; u16 pin_mask = 1 << (15 - gpio); @@ -588,7 +582,7 @@ static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value) static int cpm1_gpio16_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc); + struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); struct cpm_ioport16 __iomem *iop = mm_gc->regs; unsigned long flags; u16 pin_mask = 1 << (15 - gpio); @@ -606,7 +600,7 @@ static int cpm1_gpio16_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) static int cpm1_gpio16_dir_in(struct gpio_chip *gc, unsigned int gpio) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc); + struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); struct cpm_ioport16 __iomem *iop = mm_gc->regs; unsigned long flags; u16 pin_mask = 1 << (15 - gpio); @@ -642,7 +636,7 @@ int cpm1_gpiochip_add16(struct device_node *np) gc->get = cpm1_gpio16_get; gc->set = cpm1_gpio16_set; - return of_mm_gpiochip_add(np, mm_gc); + return of_mm_gpiochip_add_data(np, mm_gc, cpm1_gc); } struct cpm1_gpio32_chip { @@ -653,15 +647,9 @@ struct cpm1_gpio32_chip { u32 cpdata; }; -static inline struct cpm1_gpio32_chip * -to_cpm1_gpio32_chip(struct of_mm_gpio_chip *mm_gc) -{ - return container_of(mm_gc, struct cpm1_gpio32_chip, mm_gc); -} - static void cpm1_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc) { - struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc); + struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); struct cpm_ioport32b __iomem *iop = mm_gc->regs; cpm1_gc->cpdata = in_be32(&iop->dat); @@ -681,7 +669,7 @@ static int cpm1_gpio32_get(struct gpio_chip *gc, unsigned int gpio) static void __cpm1_gpio32_set(struct of_mm_gpio_chip *mm_gc, u32 pin_mask, int value) { - struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc); + struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); struct cpm_ioport32b __iomem *iop = mm_gc->regs; if (value) @@ -695,7 +683,7 @@ static void __cpm1_gpio32_set(struct of_mm_gpio_chip *mm_gc, u32 pin_mask, static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc); + struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); unsigned long flags; u32 pin_mask = 1 << (31 - gpio); @@ -709,7 +697,7 @@ static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value) static int cpm1_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc); + struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); struct cpm_ioport32b __iomem *iop = mm_gc->regs; unsigned long flags; u32 pin_mask = 1 << (31 - gpio); @@ -727,7 +715,7 @@ static int cpm1_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) static int cpm1_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc); + struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc); struct cpm_ioport32b __iomem *iop = mm_gc->regs; unsigned long flags; u32 pin_mask = 1 << (31 - gpio); @@ -763,7 +751,7 @@ int cpm1_gpiochip_add32(struct device_node *np) gc->get = cpm1_gpio32_get; gc->set = cpm1_gpio32_set; - return of_mm_gpiochip_add(np, mm_gc); + return of_mm_gpiochip_add_data(np, mm_gc, cpm1_gc); } static int cpm_init_par_io(void) diff --git a/arch/powerpc/sysdev/cpm_common.c b/arch/powerpc/sysdev/cpm_common.c index 9d32465..0ac12e5 100644 --- a/arch/powerpc/sysdev/cpm_common.c +++ b/arch/powerpc/sysdev/cpm_common.c @@ -80,15 +80,9 @@ struct cpm2_gpio32_chip { u32 cpdata; }; -static inline struct cpm2_gpio32_chip * -to_cpm2_gpio32_chip(struct of_mm_gpio_chip *mm_gc) -{ - return container_of(mm_gc, struct cpm2_gpio32_chip, mm_gc); -} - static void cpm2_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc) { - struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc); + struct cpm2_gpio32_chip *cpm2_gc = gpiochip_get_data(&mm_gc->gc); struct cpm2_ioports __iomem *iop = mm_gc->regs; cpm2_gc->cpdata = in_be32(&iop->dat); @@ -108,7 +102,7 @@ static int cpm2_gpio32_get(struct gpio_chip *gc, unsigned int gpio) static void __cpm2_gpio32_set(struct of_mm_gpio_chip *mm_gc, u32 pin_mask, int value) { - struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc); + struct cpm2_gpio32_chip *cpm2_gc = gpiochip_get_data(&mm_gc->gc); struct cpm2_ioports __iomem *iop = mm_gc->regs; if (value) @@ -122,7 +116,7 @@ static void __cpm2_gpio32_set(struct of_mm_gpio_chip *mm_gc, u32 pin_mask, static void cpm2_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc); + struct cpm2_gpio32_chip *cpm2_gc = gpiochip_get_data(gc); unsigned long flags; u32 pin_mask = 1 << (31 - gpio); @@ -136,7 +130,7 @@ static void cpm2_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value) static int cpm2_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc); + struct cpm2_gpio32_chip *cpm2_gc = gpiochip_get_data(gc); struct cpm2_ioports __iomem *iop = mm_gc->regs; unsigned long flags; u32 pin_mask = 1 << (31 - gpio); @@ -154,7 +148,7 @@ static int cpm2_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) static int cpm2_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc); + struct cpm2_gpio32_chip *cpm2_gc = gpiochip_get_data(gc); struct cpm2_ioports __iomem *iop = mm_gc->regs; unsigned long flags; u32 pin_mask = 1 << (31 - gpio); @@ -190,6 +184,6 @@ int cpm2_gpiochip_add32(struct device_node *np) gc->get = cpm2_gpio32_get; gc->set = cpm2_gpio32_set; - return of_mm_gpiochip_add(np, mm_gc); + return of_mm_gpiochip_add_data(np, mm_gc, cpm2_gc); } #endif /* CONFIG_CPM2 || CONFIG_8xx_GPIO */ diff --git a/arch/powerpc/sysdev/ppc4xx_gpio.c b/arch/powerpc/sysdev/ppc4xx_gpio.c index d7a7ef13..5382d04 100644 --- a/arch/powerpc/sysdev/ppc4xx_gpio.c +++ b/arch/powerpc/sysdev/ppc4xx_gpio.c @@ -27,7 +27,7 @@ #include <linux/io.h> #include <linux/of.h> #include <linux/of_gpio.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/types.h> #include <linux/slab.h> @@ -67,12 +67,6 @@ struct ppc4xx_gpio_chip { * There are a maximum of 32 gpios in each gpio controller. */ -static inline struct ppc4xx_gpio_chip * -to_ppc4xx_gpiochip(struct of_mm_gpio_chip *mm_gc) -{ - return container_of(mm_gc, struct ppc4xx_gpio_chip, mm_gc); -} - static int ppc4xx_gpio_get(struct gpio_chip *gc, unsigned int gpio) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); @@ -96,8 +90,7 @@ __ppc4xx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) static void ppc4xx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) { - struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct ppc4xx_gpio_chip *chip = to_ppc4xx_gpiochip(mm_gc); + struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc); unsigned long flags; spin_lock_irqsave(&chip->lock, flags); @@ -112,7 +105,7 @@ ppc4xx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) static int ppc4xx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct ppc4xx_gpio_chip *chip = to_ppc4xx_gpiochip(mm_gc); + struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc); struct ppc4xx_gpio __iomem *regs = mm_gc->regs; unsigned long flags; @@ -142,7 +135,7 @@ static int ppc4xx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct ppc4xx_gpio_chip *chip = to_ppc4xx_gpiochip(mm_gc); + struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc); struct ppc4xx_gpio __iomem *regs = mm_gc->regs; unsigned long flags; @@ -200,7 +193,7 @@ static int __init ppc4xx_add_gpiochips(void) gc->get = ppc4xx_gpio_get; gc->set = ppc4xx_gpio_set; - ret = of_mm_gpiochip_add(np, mm_gc); + ret = of_mm_gpiochip_add_data(np, mm_gc, ppc4xx_gc); if (ret) goto err; continue; diff --git a/arch/powerpc/sysdev/simple_gpio.c b/arch/powerpc/sysdev/simple_gpio.c index 56ce8ca..ef470b4 100644 --- a/arch/powerpc/sysdev/simple_gpio.c +++ b/arch/powerpc/sysdev/simple_gpio.c @@ -19,7 +19,7 @@ #include <linux/io.h> #include <linux/of.h> #include <linux/of_gpio.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/slab.h> #include <asm/prom.h> #include "simple_gpio.h" @@ -32,11 +32,6 @@ struct u8_gpio_chip { u8 data; }; -static struct u8_gpio_chip *to_u8_gpio_chip(struct of_mm_gpio_chip *mm_gc) -{ - return container_of(mm_gc, struct u8_gpio_chip, mm_gc); -} - static u8 u8_pin2mask(unsigned int pin) { return 1 << (8 - 1 - pin); @@ -52,7 +47,7 @@ static int u8_gpio_get(struct gpio_chip *gc, unsigned int gpio) static void u8_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct u8_gpio_chip *u8_gc = to_u8_gpio_chip(mm_gc); + struct u8_gpio_chip *u8_gc = gpiochip_get_data(gc); unsigned long flags; spin_lock_irqsave(&u8_gc->lock, flags); @@ -80,7 +75,7 @@ static int u8_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) static void u8_gpio_save_regs(struct of_mm_gpio_chip *mm_gc) { - struct u8_gpio_chip *u8_gc = to_u8_gpio_chip(mm_gc); + struct u8_gpio_chip *u8_gc = gpiochip_get_data(&mm_gc->gc); u8_gc->data = in_8(mm_gc->regs); } @@ -108,7 +103,7 @@ static int __init u8_simple_gpiochip_add(struct device_node *np) gc->get = u8_gpio_get; gc->set = u8_gpio_set; - ret = of_mm_gpiochip_add(np, mm_gc); + ret = of_mm_gpiochip_add_data(np, mm_gc, u8_gc); if (ret) goto err; return 0; diff --git a/arch/sh/boards/mach-sdk7786/gpio.c b/arch/sh/boards/mach-sdk7786/gpio.c index f71ce09..4799701 100644 --- a/arch/sh/boards/mach-sdk7786/gpio.c +++ b/arch/sh/boards/mach-sdk7786/gpio.c @@ -9,7 +9,7 @@ */ #include <linux/init.h> #include <linux/interrupt.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/irq.h> #include <linux/kernel.h> #include <linux/spinlock.h> @@ -44,6 +44,6 @@ static struct gpio_chip usrgpir_gpio_chip = { static int __init usrgpir_gpio_setup(void) { - return gpiochip_add(&usrgpir_gpio_chip); + return gpiochip_add_data(&usrgpir_gpio_chip, NULL); } device_initcall(usrgpir_gpio_setup); diff --git a/arch/sh/boards/mach-x3proto/gpio.c b/arch/sh/boards/mach-x3proto/gpio.c index 1fb2cbe..cea88b0 100644 --- a/arch/sh/boards/mach-x3proto/gpio.c +++ b/arch/sh/boards/mach-x3proto/gpio.c @@ -13,7 +13,7 @@ #include <linux/init.h> #include <linux/interrupt.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/irq.h> #include <linux/kernel.h> #include <linux/spinlock.h> @@ -107,7 +107,7 @@ int __init x3proto_gpio_setup(void) if (unlikely(ilsel < 0)) return ilsel; - ret = gpiochip_add(&x3proto_gpio_chip); + ret = gpiochip_add_data(&x3proto_gpio_chip, NULL); if (unlikely(ret)) goto err_gpio; diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index d500381..db0a26c 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -21,7 +21,6 @@ config SPARC select HAVE_ARCH_KGDB if !SMP || SPARC64 select HAVE_ARCH_TRACEHOOK select SYSCTL_EXCEPTION_TRACE - select ARCH_WANT_OPTIONAL_GPIOLIB select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE select RTC_CLASS select RTC_DRV_M48T59 diff --git a/arch/unicore32/kernel/gpio.c b/arch/unicore32/kernel/gpio.c index 5ab2379..49347a0 100644 --- a/arch/unicore32/kernel/gpio.c +++ b/arch/unicore32/kernel/gpio.c @@ -14,6 +14,8 @@ #include <linux/init.h> #include <linux/module.h> +#include <linux/gpio/driver.h> +/* FIXME: needed for gpio_set_value() - convert to use descriptors or hogs */ #include <linux/gpio.h> #include <mach/hardware.h> @@ -118,5 +120,5 @@ void __init puv3_init_gpio(void) * gpio_set_value(GPO_SET_V2, 1); */ #endif - gpiochip_add(&puv3_gpio_chip); + gpiochip_add_data(&puv3_gpio_chip, NULL); } diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index e832d3e..85257af 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -5,7 +5,6 @@ config XTENSA def_bool y select ARCH_WANT_FRAME_POINTERS select ARCH_WANT_IPC_PARSE_VERSION - select ARCH_WANT_OPTIONAL_GPIOLIB select BUILDTIME_EXTABLE_SORT select CLONE_BACKWARDS select COMMON_CLK diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 5f3429f..d00e7b6 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -33,7 +33,6 @@ config ARCH_REQUIRE_GPIOLIB menuconfig GPIOLIB bool "GPIO Support" - depends on ARCH_WANT_OPTIONAL_GPIOLIB || ARCH_REQUIRE_GPIOLIB help This enables GPIO support through the generic GPIO library. You only need to enable this, if you also want to enable @@ -49,7 +48,7 @@ config GPIO_DEVRES config OF_GPIO def_bool y - depends on OF + depends on OF || COMPILE_TEST config GPIO_ACPI def_bool y @@ -122,6 +121,7 @@ config GPIO_ALTERA config GPIO_AMDPT tristate "AMD Promontory GPIO support" depends on ACPI + select GPIO_GENERIC help driver for GPIO functionality on Promontory IOHub Require ACPI ASL code to enumerate as a platform device. @@ -303,6 +303,7 @@ config GPIO_MPC8XXX FSL_SOC_BOOKE || PPC_86xx || ARCH_LAYERSCAPE || ARM || \ COMPILE_TEST select GPIO_GENERIC + select IRQ_DOMAIN help Say Y here if you're going to use hardware that connects to the MPC512x/831x/834x/837x/8572/8610/QorIQ GPIOs. @@ -399,6 +400,11 @@ config GPIO_TB10X select GENERIC_IRQ_CHIP select OF_GPIO +config GPIO_TEGRA + bool + default y + depends on ARCH_TEGRA || COMPILE_TEST + config GPIO_TS4800 tristate "TS-4800 DIO blocks and compatibles" depends on OF_GPIO @@ -473,7 +479,7 @@ config GPIO_XILINX config GPIO_XLP tristate "Netlogic XLP GPIO support" - depends on CPU_XLP && OF_GPIO + depends on OF_GPIO && (CPU_XLP || ARCH_VULCAN || COMPILE_TEST) select GPIOLIB_IRQCHIP help This driver provides support for GPIO interface on Netlogic XLP MIPS64 @@ -510,6 +516,13 @@ config GPIO_ZX help Say yes here to support the GPIO device on ZTE ZX SoCs. +config GPIO_LOONGSON1 + tristate "Loongson1 GPIO support" + depends on MACH_LOONGSON32 + select GPIO_GENERIC + help + Say Y or M here to support GPIO on Loongson1 SoCs. + endmenu menu "Port-mapped I/O GPIO drivers" @@ -557,7 +570,7 @@ config GPIO_IT87 Say yes here to support GPIO functionality of IT87xx Super I/O chips. This driver is tested with ITE IT8728 and IT8732 Super I/O chips, and - supports the IT8761E Super I/O chip as well. + supports the IT8761E, IT8620E and IT8628E Super I/O chip as well. To compile this driver as a module, choose M here: the module will be called gpio_it87 @@ -1091,6 +1104,7 @@ menu "SPI or I2C GPIO expanders" config GPIO_MCP23S08 tristate "Microchip MCP23xxx I/O expander" + select GPIOLIB_IRQCHIP help SPI/I2C driver for Microchip MCP23S08/MCP23S17/MCP23008/MCP23017 I/O expanders. diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 1e0b74f..991598e 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -12,6 +12,9 @@ obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o # Device drivers. Generally keep list sorted alphabetically obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o +# directly supported by gpio-generic +gpio-generic-$(CONFIG_GPIO_GENERIC) += gpio-mmio.o + obj-$(CONFIG_GPIO_104_DIO_48E) += gpio-104-dio-48e.o obj-$(CONFIG_GPIO_104_IDIO_16) += gpio-104-idio-16.o obj-$(CONFIG_GPIO_104_IDI_48) += gpio-104-idi-48.o @@ -95,7 +98,7 @@ obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o -obj-$(CONFIG_ARCH_TEGRA) += gpio-tegra.o +obj-$(CONFIG_GPIO_TEGRA) += gpio-tegra.o obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o obj-$(CONFIG_GPIO_TPIC2810) += gpio-tpic2810.o @@ -127,3 +130,4 @@ obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o obj-$(CONFIG_GPIO_ZX) += gpio-zx.o +obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index c81224f..80f9ddf 100644 --- a/drivers/gpio/gpio-74x164.c +++ b/drivers/gpio/gpio-74x164.c @@ -75,6 +75,29 @@ static void gen_74x164_set_value(struct gpio_chip *gc, mutex_unlock(&chip->lock); } +static void gen_74x164_set_multiple(struct gpio_chip *gc, unsigned long *mask, + unsigned long *bits) +{ + struct gen_74x164_chip *chip = gpiochip_get_data(gc); + unsigned int i, idx, shift; + u8 bank, bankmask; + + mutex_lock(&chip->lock); + for (i = 0, bank = chip->registers - 1; i < chip->registers; + i++, bank--) { + idx = i / sizeof(*mask); + shift = i % sizeof(*mask) * BITS_PER_BYTE; + bankmask = mask[idx] >> shift; + if (!bankmask) + continue; + + chip->buffer[bank] &= ~bankmask; + chip->buffer[bank] |= bankmask & (bits[idx] >> shift); + } + __gen_74x164_write_config(chip); + mutex_unlock(&chip->lock); +} + static int gen_74x164_direction_output(struct gpio_chip *gc, unsigned offset, int val) { @@ -114,6 +137,7 @@ static int gen_74x164_probe(struct spi_device *spi) chip->gpio_chip.direction_output = gen_74x164_direction_output; chip->gpio_chip.get = gen_74x164_get_value; chip->gpio_chip.set = gen_74x164_set_value; + chip->gpio_chip.set_multiple = gen_74x164_set_multiple; chip->gpio_chip.base = -1; chip->registers = nregs; @@ -153,6 +177,7 @@ static int gen_74x164_remove(struct spi_device *spi) static const struct of_device_id gen_74x164_dt_ids[] = { { .compatible = "fairchild,74hc595" }, + { .compatible = "nxp,74lvc594" }, {}, }; MODULE_DEVICE_TABLE(of, gen_74x164_dt_ids); diff --git a/drivers/gpio/gpio-amdpt.c b/drivers/gpio/gpio-amdpt.c index c248404..9b78dc8 100644 --- a/drivers/gpio/gpio-amdpt.c +++ b/drivers/gpio/gpio-amdpt.c @@ -28,7 +28,6 @@ struct pt_gpio_chip { struct gpio_chip gc; void __iomem *reg_base; - spinlock_t lock; }; static int pt_gpio_request(struct gpio_chip *gc, unsigned offset) @@ -39,19 +38,19 @@ static int pt_gpio_request(struct gpio_chip *gc, unsigned offset) dev_dbg(gc->parent, "pt_gpio_request offset=%x\n", offset); - spin_lock_irqsave(&pt_gpio->lock, flags); + spin_lock_irqsave(&gc->bgpio_lock, flags); using_pins = readl(pt_gpio->reg_base + PT_SYNC_REG); if (using_pins & BIT(offset)) { dev_warn(gc->parent, "PT GPIO pin %x reconfigured\n", offset); - spin_unlock_irqrestore(&pt_gpio->lock, flags); + spin_unlock_irqrestore(&gc->bgpio_lock, flags); return -EINVAL; } writel(using_pins | BIT(offset), pt_gpio->reg_base + PT_SYNC_REG); - spin_unlock_irqrestore(&pt_gpio->lock, flags); + spin_unlock_irqrestore(&gc->bgpio_lock, flags); return 0; } @@ -62,111 +61,17 @@ static void pt_gpio_free(struct gpio_chip *gc, unsigned offset) unsigned long flags; u32 using_pins; - spin_lock_irqsave(&pt_gpio->lock, flags); + spin_lock_irqsave(&gc->bgpio_lock, flags); using_pins = readl(pt_gpio->reg_base + PT_SYNC_REG); using_pins &= ~BIT(offset); writel(using_pins, pt_gpio->reg_base + PT_SYNC_REG); - spin_unlock_irqrestore(&pt_gpio->lock, flags); + spin_unlock_irqrestore(&gc->bgpio_lock, flags); dev_dbg(gc->parent, "pt_gpio_free offset=%x\n", offset); } -static void pt_gpio_set_value(struct gpio_chip *gc, unsigned offset, int value) -{ - struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc); - unsigned long flags; - u32 data; - - dev_dbg(gc->parent, "pt_gpio_set_value offset=%x, value=%x\n", - offset, value); - - spin_lock_irqsave(&pt_gpio->lock, flags); - - data = readl(pt_gpio->reg_base + PT_OUTPUTDATA_REG); - data &= ~BIT(offset); - if (value) - data |= BIT(offset); - writel(data, pt_gpio->reg_base + PT_OUTPUTDATA_REG); - - spin_unlock_irqrestore(&pt_gpio->lock, flags); -} - -static int pt_gpio_get_value(struct gpio_chip *gc, unsigned offset) -{ - struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc); - unsigned long flags; - u32 data; - - spin_lock_irqsave(&pt_gpio->lock, flags); - - data = readl(pt_gpio->reg_base + PT_DIRECTION_REG); - - /* configure as output */ - if (data & BIT(offset)) - data = readl(pt_gpio->reg_base + PT_OUTPUTDATA_REG); - else /* configure as input */ - data = readl(pt_gpio->reg_base + PT_INPUTDATA_REG); - - spin_unlock_irqrestore(&pt_gpio->lock, flags); - - data >>= offset; - data &= 1; - - dev_dbg(gc->parent, "pt_gpio_get_value offset=%x, value=%x\n", - offset, data); - - return data; -} - -static int pt_gpio_direction_input(struct gpio_chip *gc, unsigned offset) -{ - struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc); - unsigned long flags; - u32 data; - - dev_dbg(gc->parent, "pt_gpio_dirction_input offset=%x\n", offset); - - spin_lock_irqsave(&pt_gpio->lock, flags); - - data = readl(pt_gpio->reg_base + PT_DIRECTION_REG); - data &= ~BIT(offset); - writel(data, pt_gpio->reg_base + PT_DIRECTION_REG); - - spin_unlock_irqrestore(&pt_gpio->lock, flags); - - return 0; -} - -static int pt_gpio_direction_output(struct gpio_chip *gc, - unsigned offset, int value) -{ - struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc); - unsigned long flags; - u32 data; - - dev_dbg(gc->parent, "pt_gpio_direction_output offset=%x, value=%x\n", - offset, value); - - spin_lock_irqsave(&pt_gpio->lock, flags); - - data = readl(pt_gpio->reg_base + PT_OUTPUTDATA_REG); - if (value) - data |= BIT(offset); - else - data &= ~BIT(offset); - writel(data, pt_gpio->reg_base + PT_OUTPUTDATA_REG); - - data = readl(pt_gpio->reg_base + PT_DIRECTION_REG); - data |= BIT(offset); - writel(data, pt_gpio->reg_base + PT_DIRECTION_REG); - - spin_unlock_irqrestore(&pt_gpio->lock, flags); - - return 0; -} - static int pt_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -196,18 +101,19 @@ static int pt_gpio_probe(struct platform_device *pdev) return PTR_ERR(pt_gpio->reg_base); } - spin_lock_init(&pt_gpio->lock); + ret = bgpio_init(&pt_gpio->gc, dev, 4, + pt_gpio->reg_base + PT_INPUTDATA_REG, + pt_gpio->reg_base + PT_OUTPUTDATA_REG, NULL, + pt_gpio->reg_base + PT_DIRECTION_REG, NULL, + BGPIOF_READ_OUTPUT_REG_SET); + if (ret) { + dev_err(&pdev->dev, "bgpio_init failed\n"); + return ret; + } - pt_gpio->gc.label = pdev->name; pt_gpio->gc.owner = THIS_MODULE; - pt_gpio->gc.parent = dev; pt_gpio->gc.request = pt_gpio_request; pt_gpio->gc.free = pt_gpio_free; - pt_gpio->gc.direction_input = pt_gpio_direction_input; - pt_gpio->gc.direction_output = pt_gpio_direction_output; - pt_gpio->gc.get = pt_gpio_get_value; - pt_gpio->gc.set = pt_gpio_set_value; - pt_gpio->gc.base = -1; pt_gpio->gc.ngpio = PT_TOTAL_GPIO; #if defined(CONFIG_OF_GPIO) pt_gpio->gc.of_node = pdev->dev.of_node; @@ -239,6 +145,7 @@ static int pt_gpio_remove(struct platform_device *pdev) static const struct acpi_device_id pt_gpio_acpi_match[] = { { "AMDF030", 0 }, + { "AMDIF030", 0 }, { }, }; MODULE_DEVICE_TABLE(acpi, pt_gpio_acpi_match); diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 2fd38d5..9aabc48 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -1,4 +1,7 @@ /* + * Broadcom Kona GPIO Driver + * + * Author: Broadcom Corporation <bcm-kernel-feedback-list@broadcom.com> * Copyright (C) 2012-2014 Broadcom Corporation * * This program is free software; you can redistribute it and/or @@ -17,7 +20,7 @@ #include <linux/gpio.h> #include <linux/of_device.h> #include <linux/of_irq.h> -#include <linux/module.h> +#include <linux/init.h> #include <linux/irqdomain.h> #include <linux/irqchip/chained_irq.h> @@ -502,8 +505,6 @@ static struct of_device_id const bcm_kona_gpio_of_match[] = { {} }; -MODULE_DEVICE_TABLE(of, bcm_kona_gpio_of_match); - /* * This lock class tells lockdep that GPIO irqs are in a different * category than their parents, so it won't report false recursion. @@ -659,9 +660,4 @@ static struct platform_driver bcm_kona_gpio_driver = { }, .probe = bcm_kona_gpio_probe, }; - -module_platform_driver(bcm_kona_gpio_driver); - -MODULE_AUTHOR("Broadcom Corporation <bcm-kernel-feedback-list@broadcom.com>"); -MODULE_DESCRIPTION("Broadcom Kona GPIO Driver"); -MODULE_LICENSE("GPL v2"); +builtin_platform_driver(bcm_kona_gpio_driver); diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c index 42d51c5..e648914 100644 --- a/drivers/gpio/gpio-brcmstb.c +++ b/drivers/gpio/gpio-brcmstb.c @@ -461,6 +461,7 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) bank->id = num_banks; if (bank_width <= 0 || bank_width > MAX_GPIO_PER_BANK) { dev_err(dev, "Invalid bank width %d\n", bank_width); + err = -EINVAL; goto fail; } else { bank->width = bank_width; diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 597de1e..34779bb 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -7,6 +7,7 @@ * * All enquiries to support@picochip.com */ +#include <linux/acpi.h> #include <linux/gpio/driver.h> /* FIXME: for gpio_get_value(), replace this with direct register read */ #include <linux/gpio.h> @@ -22,10 +23,13 @@ #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/platform_device.h> +#include <linux/property.h> #include <linux/spinlock.h> #include <linux/platform_data/gpio-dwapb.h> #include <linux/slab.h> +#include "gpiolib.h" + #define GPIO_SWPORTA_DR 0x00 #define GPIO_SWPORTA_DDR 0x04 #define GPIO_SWPORTB_DR 0x0c @@ -290,14 +294,14 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio, struct dwapb_port_property *pp) { struct gpio_chip *gc = &port->gc; - struct device_node *node = pp->node; + struct fwnode_handle *fwnode = pp->fwnode; struct irq_chip_generic *irq_gc = NULL; unsigned int hwirq, ngpio = gc->ngpio; struct irq_chip_type *ct; int err, i; - gpio->domain = irq_domain_add_linear(node, ngpio, - &irq_generic_chip_ops, gpio); + gpio->domain = irq_domain_create_linear(fwnode, ngpio, + &irq_generic_chip_ops, gpio); if (!gpio->domain) return; @@ -409,13 +413,13 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio, err = bgpio_init(&port->gc, gpio->dev, 4, dat, set, NULL, dirout, NULL, false); if (err) { - dev_err(gpio->dev, "failed to init gpio chip for %s\n", - pp->name); + dev_err(gpio->dev, "failed to init gpio chip for port%d\n", + port->idx); return err; } #ifdef CONFIG_OF_GPIO - port->gc.of_node = pp->node; + port->gc.of_node = to_of_node(pp->fwnode); #endif port->gc.ngpio = pp->ngpio; port->gc.base = pp->gpio_base; @@ -429,11 +433,15 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio, err = gpiochip_add_data(&port->gc, port); if (err) - dev_err(gpio->dev, "failed to register gpiochip for %s\n", - pp->name); + dev_err(gpio->dev, "failed to register gpiochip for port%d\n", + port->idx); else port->is_registered = true; + /* Add GPIO-signaled ACPI event support */ + if (pp->irq) + acpi_gpiochip_request_interrupts(&port->gc); + return err; } @@ -447,19 +455,15 @@ static void dwapb_gpio_unregister(struct dwapb_gpio *gpio) } static struct dwapb_platform_data * -dwapb_gpio_get_pdata_of(struct device *dev) +dwapb_gpio_get_pdata(struct device *dev) { - struct device_node *node, *port_np; + struct fwnode_handle *fwnode; struct dwapb_platform_data *pdata; struct dwapb_port_property *pp; int nports; int i; - node = dev->of_node; - if (!IS_ENABLED(CONFIG_OF_GPIO) || !node) - return ERR_PTR(-ENODEV); - - nports = of_get_child_count(node); + nports = device_get_child_node_count(dev); if (nports == 0) return ERR_PTR(-ENODEV); @@ -474,21 +478,22 @@ dwapb_gpio_get_pdata_of(struct device *dev) pdata->nports = nports; i = 0; - for_each_child_of_node(node, port_np) { + device_for_each_child_node(dev, fwnode) { pp = &pdata->properties[i++]; - pp->node = port_np; + pp->fwnode = fwnode; - if (of_property_read_u32(port_np, "reg", &pp->idx) || + if (fwnode_property_read_u32(fwnode, "reg", &pp->idx) || pp->idx >= DWAPB_MAX_PORTS) { - dev_err(dev, "missing/invalid port index for %s\n", - port_np->full_name); + dev_err(dev, + "missing/invalid port index for port%d\n", i); return ERR_PTR(-EINVAL); } - if (of_property_read_u32(port_np, "snps,nr-gpios", + if (fwnode_property_read_u32(fwnode, "snps,nr-gpios", &pp->ngpio)) { - dev_info(dev, "failed to get number of gpios for %s\n", - port_np->full_name); + dev_info(dev, + "failed to get number of gpios for port%d\n", + i); pp->ngpio = 32; } @@ -496,18 +501,19 @@ dwapb_gpio_get_pdata_of(struct device *dev) * Only port A can provide interrupts in all configurations of * the IP. */ - if (pp->idx == 0 && - of_property_read_bool(port_np, "interrupt-controller")) { - pp->irq = irq_of_parse_and_map(port_np, 0); - if (!pp->irq) { - dev_warn(dev, "no irq for bank %s\n", - port_np->full_name); - } + if (dev->of_node && pp->idx == 0 && + fwnode_property_read_bool(fwnode, + "interrupt-controller")) { + pp->irq = irq_of_parse_and_map(to_of_node(fwnode), 0); + if (!pp->irq) + dev_warn(dev, "no irq for port%d\n", pp->idx); } + if (has_acpi_companion(dev) && pp->idx == 0) + pp->irq = platform_get_irq(to_platform_device(dev), 0); + pp->irq_shared = false; pp->gpio_base = -1; - pp->name = port_np->full_name; } return pdata; @@ -523,7 +529,7 @@ static int dwapb_gpio_probe(struct platform_device *pdev) struct dwapb_platform_data *pdata = dev_get_platdata(dev); if (!pdata) { - pdata = dwapb_gpio_get_pdata_of(dev); + pdata = dwapb_gpio_get_pdata(dev); if (IS_ERR(pdata)) return PTR_ERR(pdata); } @@ -580,6 +586,13 @@ static const struct of_device_id dwapb_of_match[] = { }; MODULE_DEVICE_TABLE(of, dwapb_of_match); +static const struct acpi_device_id dwapb_acpi_match[] = { + {"HISI0181", 0}, + {"APMC0D07", 0}, + { } +}; +MODULE_DEVICE_TABLE(acpi, dwapb_acpi_match); + #ifdef CONFIG_PM_SLEEP static int dwapb_gpio_suspend(struct device *dev) { @@ -674,6 +687,7 @@ static struct platform_driver dwapb_gpio_driver = { .name = "gpio-dwapb", .pm = &dwapb_gpio_pm_ops, .of_match_table = of_match_ptr(dwapb_of_match), + .acpi_match_table = ACPI_PTR(dwapb_acpi_match), }, .probe = dwapb_gpio_probe, .remove = dwapb_gpio_remove, diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c index daac2d4..05aa538 100644 --- a/drivers/gpio/gpio-f7188x.c +++ b/drivers/gpio/gpio-f7188x.c @@ -15,7 +15,8 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/io.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> +#include <linux/bitops.h> #define DRVNAME "gpio-f7188x" @@ -129,6 +130,9 @@ static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset); static int f7188x_gpio_direction_out(struct gpio_chip *chip, unsigned offset, int value); static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value); +static int f7188x_gpio_set_single_ended(struct gpio_chip *gc, + unsigned offset, + enum single_ended_mode mode); #define F7188X_GPIO_BANK(_base, _ngpio, _regbase) \ { \ @@ -139,6 +143,7 @@ static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value); .get = f7188x_gpio_get, \ .direction_output = f7188x_gpio_direction_out, \ .set = f7188x_gpio_set, \ + .set_single_ended = f7188x_gpio_set_single_ended, \ .base = _base, \ .ngpio = _ngpio, \ .can_sleep = true, \ @@ -217,7 +222,7 @@ static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset) superio_select(sio->addr, SIO_LD_GPIO); dir = superio_inb(sio->addr, gpio_dir(bank->regbase)); - dir &= ~(1 << offset); + dir &= ~BIT(offset); superio_outb(sio->addr, gpio_dir(bank->regbase), dir); superio_exit(sio->addr); @@ -238,7 +243,7 @@ static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset) superio_select(sio->addr, SIO_LD_GPIO); dir = superio_inb(sio->addr, gpio_dir(bank->regbase)); - dir = !!(dir & (1 << offset)); + dir = !!(dir & BIT(offset)); if (dir) data = superio_inb(sio->addr, gpio_data_out(bank->regbase)); else @@ -246,7 +251,7 @@ static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset) superio_exit(sio->addr); - return !!(data & 1 << offset); + return !!(data & BIT(offset)); } static int f7188x_gpio_direction_out(struct gpio_chip *chip, @@ -264,13 +269,13 @@ static int f7188x_gpio_direction_out(struct gpio_chip *chip, data_out = superio_inb(sio->addr, gpio_data_out(bank->regbase)); if (value) - data_out |= (1 << offset); + data_out |= BIT(offset); else - data_out &= ~(1 << offset); + data_out &= ~BIT(offset); superio_outb(sio->addr, gpio_data_out(bank->regbase), data_out); dir = superio_inb(sio->addr, gpio_dir(bank->regbase)); - dir |= (1 << offset); + dir |= BIT(offset); superio_outb(sio->addr, gpio_dir(bank->regbase), dir); superio_exit(sio->addr); @@ -292,14 +297,43 @@ static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value) data_out = superio_inb(sio->addr, gpio_data_out(bank->regbase)); if (value) - data_out |= (1 << offset); + data_out |= BIT(offset); else - data_out &= ~(1 << offset); + data_out &= ~BIT(offset); superio_outb(sio->addr, gpio_data_out(bank->regbase), data_out); superio_exit(sio->addr); } +static int f7188x_gpio_set_single_ended(struct gpio_chip *chip, + unsigned offset, + enum single_ended_mode mode) +{ + int err; + struct f7188x_gpio_bank *bank = gpiochip_get_data(chip); + struct f7188x_sio *sio = bank->data->sio; + u8 data; + + if (mode != LINE_MODE_OPEN_DRAIN && + mode != LINE_MODE_PUSH_PULL) + return -ENOTSUPP; + + err = superio_enter(sio->addr); + if (err) + return err; + superio_select(sio->addr, SIO_LD_GPIO); + + data = superio_inb(sio->addr, gpio_out_mode(bank->regbase)); + if (mode == LINE_MODE_OPEN_DRAIN) + data &= ~BIT(offset); + else + data |= BIT(offset); + superio_outb(sio->addr, gpio_out_mode(bank->regbase), data); + + superio_exit(sio->addr); + return 0; +} + /* * Platform device and driver. */ diff --git a/drivers/gpio/gpio-it87.c b/drivers/gpio/gpio-it87.c index b219c82..63a962d 100644 --- a/drivers/gpio/gpio-it87.c +++ b/drivers/gpio/gpio-it87.c @@ -34,6 +34,8 @@ /* Chip Id numbers */ #define NO_DEV_ID 0xffff +#define IT8620_ID 0x8620 +#define IT8628_ID 0x8628 #define IT8728_ID 0x8728 #define IT8732_ID 0x8732 #define IT8761_ID 0x8761 @@ -302,6 +304,14 @@ static int __init it87_gpio_init(void) it87_gpio->chip = it87_template_chip; switch (chip_type) { + case IT8620_ID: + case IT8628_ID: + gpio_ba_reg = 0x62; + it87_gpio->io_size = 11; + it87_gpio->output_base = 0xc8; + it87_gpio->simple_size = 0; + it87_gpio->chip.ngpio = 64; + break; case IT8728_ID: case IT8732_ID: gpio_ba_reg = 0x62; diff --git a/drivers/gpio/gpio-loongson1.c b/drivers/gpio/gpio-loongson1.c new file mode 100644 index 0000000..10c09bd --- /dev/null +++ b/drivers/gpio/gpio-loongson1.c @@ -0,0 +1,102 @@ +/* + * GPIO Driver for Loongson 1 SoC + * + * Copyright (C) 2015-2016 Zhang, Keguang <keguang.zhang@gmail.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/gpio/driver.h> +#include <linux/platform_device.h> + +/* Loongson 1 GPIO Register Definitions */ +#define GPIO_CFG 0x0 +#define GPIO_DIR 0x10 +#define GPIO_DATA 0x20 +#define GPIO_OUTPUT 0x30 + +static void __iomem *gpio_reg_base; + +static int ls1x_gpio_request(struct gpio_chip *gc, unsigned int offset) +{ + unsigned long pinmask = gc->pin2mask(gc, offset); + unsigned long flags; + + spin_lock_irqsave(&gc->bgpio_lock, flags); + __raw_writel(__raw_readl(gpio_reg_base + GPIO_CFG) | pinmask, + gpio_reg_base + GPIO_CFG); + spin_unlock_irqrestore(&gc->bgpio_lock, flags); + + return 0; +} + +static void ls1x_gpio_free(struct gpio_chip *gc, unsigned int offset) +{ + unsigned long pinmask = gc->pin2mask(gc, offset); + unsigned long flags; + + spin_lock_irqsave(&gc->bgpio_lock, flags); + __raw_writel(__raw_readl(gpio_reg_base + GPIO_CFG) & ~pinmask, + gpio_reg_base + GPIO_CFG); + spin_unlock_irqrestore(&gc->bgpio_lock, flags); +} + +static int ls1x_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct gpio_chip *gc; + struct resource *res; + int ret; + + gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL); + if (!gc) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "failed to get I/O memory\n"); + return -EINVAL; + } + + gpio_reg_base = devm_ioremap_resource(dev, res); + if (IS_ERR(gpio_reg_base)) + return PTR_ERR(gpio_reg_base); + + ret = bgpio_init(gc, dev, 4, gpio_reg_base + GPIO_DATA, + gpio_reg_base + GPIO_OUTPUT, NULL, + NULL, gpio_reg_base + GPIO_DIR, 0); + if (ret) + goto err; + + gc->owner = THIS_MODULE; + gc->request = ls1x_gpio_request; + gc->free = ls1x_gpio_free; + gc->base = pdev->id * 32; + + ret = devm_gpiochip_add_data(dev, gc, NULL); + if (ret) + goto err; + + platform_set_drvdata(pdev, gc); + dev_info(dev, "Loongson1 GPIO driver registered\n"); + + return 0; +err: + dev_err(dev, "failed to register GPIO device\n"); + return ret; +} + +static struct platform_driver ls1x_gpio_driver = { + .probe = ls1x_gpio_probe, + .driver = { + .name = "ls1x-gpio", + }, +}; + +module_platform_driver(ls1x_gpio_driver); + +MODULE_AUTHOR("Kelvin Cheung <keguang.zhang@gmail.com>"); +MODULE_DESCRIPTION("Loongson1 GPIO driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-mb86s7x.c b/drivers/gpio/gpio-mb86s7x.c index 7fffc1d..d55af50 100644 --- a/drivers/gpio/gpio-mb86s7x.c +++ b/drivers/gpio/gpio-mb86s7x.c @@ -17,7 +17,6 @@ #include <linux/io.h> #include <linux/init.h> #include <linux/clk.h> -#include <linux/module.h> #include <linux/err.h> #include <linux/errno.h> #include <linux/ioport.h> @@ -185,8 +184,6 @@ static int mb86s70_gpio_probe(struct platform_device *pdev) gchip->gc.parent = &pdev->dev; gchip->gc.base = -1; - platform_set_drvdata(pdev, gchip); - ret = gpiochip_add_data(&gchip->gc, gchip); if (ret) { dev_err(&pdev->dev, "couldn't register gpio driver\n"); @@ -210,7 +207,6 @@ static const struct of_device_id mb86s70_gpio_dt_ids[] = { { .compatible = "fujitsu,mb86s70-gpio" }, { /* sentinel */ } }; -MODULE_DEVICE_TABLE(of, mb86s70_gpio_dt_ids); static struct platform_driver mb86s70_gpio_driver = { .driver = { @@ -225,8 +221,4 @@ static int __init mb86s70_gpio_init(void) { return platform_driver_register(&mb86s70_gpio_driver); } -module_init(mb86s70_gpio_init); - -MODULE_DESCRIPTION("MB86S7x GPIO Driver"); -MODULE_ALIAS("platform:mb86s70-gpio"); -MODULE_LICENSE("GPL"); +device_initcall(mb86s70_gpio_init); diff --git a/drivers/gpio/gpio-mc9s08dz60.c b/drivers/gpio/gpio-mc9s08dz60.c index 14f252f..2fcad5b 100644 --- a/drivers/gpio/gpio-mc9s08dz60.c +++ b/drivers/gpio/gpio-mc9s08dz60.c @@ -15,7 +15,7 @@ */ #include <linux/kernel.h> -#include <linux/module.h> +#include <linux/init.h> #include <linux/slab.h> #include <linux/i2c.h> #include <linux/gpio.h> @@ -111,8 +111,6 @@ static const struct i2c_device_id mc9s08dz60_id[] = { {}, }; -MODULE_DEVICE_TABLE(i2c, mc9s08dz60_id); - static struct i2c_driver mc9s08dz60_i2c_driver = { .driver = { .name = "mc9s08dz60", @@ -120,10 +118,4 @@ static struct i2c_driver mc9s08dz60_i2c_driver = { .probe = mc9s08dz60_probe, .id_table = mc9s08dz60_id, }; - -module_i2c_driver(mc9s08dz60_i2c_driver); - -MODULE_AUTHOR("Freescale Semiconductor, Inc. " - "Wu Guoxing <b39297@freescale.com>"); -MODULE_DESCRIPTION("mc9s08dz60 gpio function on mx35 3ds board"); -MODULE_LICENSE("GPL v2"); +builtin_i2c_driver(mc9s08dz60_i2c_driver); diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 47e4869..ac22efc 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -77,7 +77,6 @@ struct mcp23s08 { /* lock protects the cached values */ struct mutex lock; struct mutex irq_lock; - struct irq_domain *irq_domain; struct gpio_chip chip; @@ -96,11 +95,6 @@ struct mcp23s08_driver_data { struct mcp23s08 chip[]; }; -/* This lock class tells lockdep that GPIO irqs are in a different - * category than their parents, so it won't report false recursion. - */ -static struct lock_class_key gpio_lock_class; - /*----------------------------------------------------------------------*/ #if IS_ENABLED(CONFIG_I2C) @@ -368,8 +362,9 @@ static irqreturn_t mcp23s08_irq(int irq, void *data) for (i = 0; i < mcp->chip.ngpio; i++) { if ((BIT(i) & mcp->cache[MCP_INTF]) && ((BIT(i) & intcap & mcp->irq_rise) || - (mcp->irq_fall & ~intcap & BIT(i)))) { - child_irq = irq_find_mapping(mcp->irq_domain, i); + (mcp->irq_fall & ~intcap & BIT(i)) || + (BIT(i) & mcp->cache[MCP_INTCON]))) { + child_irq = irq_find_mapping(mcp->chip.irqdomain, i); handle_nested_irq(child_irq); } } @@ -377,16 +372,10 @@ static irqreturn_t mcp23s08_irq(int irq, void *data) return IRQ_HANDLED; } -static int mcp23s08_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct mcp23s08 *mcp = gpiochip_get_data(chip); - - return irq_find_mapping(mcp->irq_domain, offset); -} - static void mcp23s08_irq_mask(struct irq_data *data) { - struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); + struct gpio_chip *gc = irq_data_get_irq_chip_data(data); + struct mcp23s08 *mcp = gpiochip_get_data(gc); unsigned int pos = data->hwirq; mcp->cache[MCP_GPINTEN] &= ~BIT(pos); @@ -394,7 +383,8 @@ static void mcp23s08_irq_mask(struct irq_data *data) static void mcp23s08_irq_unmask(struct irq_data *data) { - struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); + struct gpio_chip *gc = irq_data_get_irq_chip_data(data); + struct mcp23s08 *mcp = gpiochip_get_data(gc); unsigned int pos = data->hwirq; mcp->cache[MCP_GPINTEN] |= BIT(pos); @@ -402,7 +392,8 @@ static void mcp23s08_irq_unmask(struct irq_data *data) static int mcp23s08_irq_set_type(struct irq_data *data, unsigned int type) { - struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); + struct gpio_chip *gc = irq_data_get_irq_chip_data(data); + struct mcp23s08 *mcp = gpiochip_get_data(gc); unsigned int pos = data->hwirq; int status = 0; @@ -418,6 +409,12 @@ static int mcp23s08_irq_set_type(struct irq_data *data, unsigned int type) mcp->cache[MCP_INTCON] &= ~BIT(pos); mcp->irq_rise &= ~BIT(pos); mcp->irq_fall |= BIT(pos); + } else if (type & IRQ_TYPE_LEVEL_HIGH) { + mcp->cache[MCP_INTCON] |= BIT(pos); + mcp->cache[MCP_DEFVAL] &= ~BIT(pos); + } else if (type & IRQ_TYPE_LEVEL_LOW) { + mcp->cache[MCP_INTCON] |= BIT(pos); + mcp->cache[MCP_DEFVAL] |= BIT(pos); } else return -EINVAL; @@ -426,14 +423,16 @@ static int mcp23s08_irq_set_type(struct irq_data *data, unsigned int type) static void mcp23s08_irq_bus_lock(struct irq_data *data) { - struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); + struct gpio_chip *gc = irq_data_get_irq_chip_data(data); + struct mcp23s08 *mcp = gpiochip_get_data(gc); mutex_lock(&mcp->irq_lock); } static void mcp23s08_irq_bus_unlock(struct irq_data *data) { - struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); + struct gpio_chip *gc = irq_data_get_irq_chip_data(data); + struct mcp23s08 *mcp = gpiochip_get_data(gc); mutex_lock(&mcp->lock); mcp->ops->write(mcp, MCP_GPINTEN, mcp->cache[MCP_GPINTEN]); @@ -443,27 +442,6 @@ static void mcp23s08_irq_bus_unlock(struct irq_data *data) mutex_unlock(&mcp->irq_lock); } -static int mcp23s08_irq_reqres(struct irq_data *data) -{ - struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); - - if (gpiochip_lock_as_irq(&mcp->chip, data->hwirq)) { - dev_err(mcp->chip.parent, - "unable to lock HW IRQ %lu for IRQ usage\n", - data->hwirq); - return -EINVAL; - } - - return 0; -} - -static void mcp23s08_irq_relres(struct irq_data *data) -{ - struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); - - gpiochip_unlock_as_irq(&mcp->chip, data->hwirq); -} - static struct irq_chip mcp23s08_irq_chip = { .name = "gpio-mcp23xxx", .irq_mask = mcp23s08_irq_mask, @@ -471,24 +449,16 @@ static struct irq_chip mcp23s08_irq_chip = { .irq_set_type = mcp23s08_irq_set_type, .irq_bus_lock = mcp23s08_irq_bus_lock, .irq_bus_sync_unlock = mcp23s08_irq_bus_unlock, - .irq_request_resources = mcp23s08_irq_reqres, - .irq_release_resources = mcp23s08_irq_relres, }; static int mcp23s08_irq_setup(struct mcp23s08 *mcp) { struct gpio_chip *chip = &mcp->chip; - int err, irq, j; + int err; unsigned long irqflags = IRQF_ONESHOT | IRQF_SHARED; mutex_init(&mcp->irq_lock); - mcp->irq_domain = irq_domain_add_linear(chip->parent->of_node, - chip->ngpio, - &irq_domain_simple_ops, mcp); - if (!mcp->irq_domain) - return -ENODEV; - if (mcp->irq_active_high) irqflags |= IRQF_TRIGGER_HIGH; else @@ -503,30 +473,23 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp) return err; } - chip->to_irq = mcp23s08_gpio_to_irq; - - for (j = 0; j < mcp->chip.ngpio; j++) { - irq = irq_create_mapping(mcp->irq_domain, j); - irq_set_lockdep_class(irq, &gpio_lock_class); - irq_set_chip_data(irq, mcp); - irq_set_chip(irq, &mcp23s08_irq_chip); - irq_set_nested_thread(irq, true); - irq_set_noprobe(irq); + err = gpiochip_irqchip_add(chip, + &mcp23s08_irq_chip, + 0, + handle_simple_irq, + IRQ_TYPE_NONE); + if (err) { + dev_err(chip->parent, + "could not connect irqchip to gpiochip: %d\n", err); + return err; } - return 0; -} -static void mcp23s08_irq_teardown(struct mcp23s08 *mcp) -{ - unsigned int irq, i; + gpiochip_set_chained_irqchip(chip, + &mcp23s08_irq_chip, + mcp->irq, + NULL); - for (i = 0; i < mcp->chip.ngpio; i++) { - irq = irq_find_mapping(mcp->irq_domain, i); - if (irq > 0) - irq_dispose_mapping(irq); - } - - irq_domain_remove(mcp->irq_domain); + return 0; } /*----------------------------------------------------------------------*/ @@ -721,7 +684,6 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, if (mcp->irq && mcp->irq_controller) { status = mcp23s08_irq_setup(mcp); if (status) { - mcp23s08_irq_teardown(mcp); goto fail; } } @@ -847,9 +809,6 @@ static int mcp230xx_remove(struct i2c_client *client) { struct mcp23s08 *mcp = i2c_get_clientdata(client); - if (client->irq && mcp->irq_controller) - mcp23s08_irq_teardown(mcp); - gpiochip_remove(&mcp->chip); kfree(mcp); @@ -1017,8 +976,6 @@ static int mcp23s08_remove(struct spi_device *spi) if (!data->mcp[addr]) continue; - if (spi->irq && data->mcp[addr]->irq_controller) - mcp23s08_irq_teardown(data->mcp[addr]); gpiochip_remove(&data->mcp[addr]->chip); } diff --git a/drivers/gpio/gpio-menz127.c b/drivers/gpio/gpio-menz127.c index c5c9599..cc103af 100644 --- a/drivers/gpio/gpio-menz127.c +++ b/drivers/gpio/gpio-menz127.c @@ -35,7 +35,6 @@ struct men_z127_gpio { struct gpio_chip gc; void __iomem *reg_base; - struct mcb_device *mdev; struct resource *mem; }; @@ -43,7 +42,7 @@ static int men_z127_debounce(struct gpio_chip *gc, unsigned gpio, unsigned debounce) { struct men_z127_gpio *priv = gpiochip_get_data(gc); - struct device *dev = &priv->mdev->dev; + struct device *dev = gc->parent; unsigned int rnd; u32 db_en, db_cnt; @@ -88,21 +87,25 @@ static int men_z127_debounce(struct gpio_chip *gc, unsigned gpio, return 0; } -static int men_z127_request(struct gpio_chip *gc, unsigned gpio_pin) +static int men_z127_set_single_ended(struct gpio_chip *gc, + unsigned offset, + enum single_ended_mode mode) { struct men_z127_gpio *priv = gpiochip_get_data(gc); u32 od_en; - if (gpio_pin >= gc->ngpio) - return -EINVAL; + if (mode != LINE_MODE_OPEN_DRAIN && + mode != LINE_MODE_PUSH_PULL) + return -ENOTSUPP; spin_lock(&gc->bgpio_lock); od_en = readl(priv->reg_base + MEN_Z127_ODER); - if (gpiochip_line_is_open_drain(gc, gpio_pin)) - od_en |= BIT(gpio_pin); + if (mode == LINE_MODE_OPEN_DRAIN) + od_en |= BIT(offset); else - od_en &= ~BIT(gpio_pin); + /* Implicitly LINE_MODE_PUSH_PULL */ + od_en &= ~BIT(offset); writel(od_en, priv->reg_base + MEN_Z127_ODER); spin_unlock(&gc->bgpio_lock); @@ -135,7 +138,6 @@ static int men_z127_probe(struct mcb_device *mdev, goto err_release; } - men_z127_gpio->mdev = mdev; mcb_set_drvdata(mdev, men_z127_gpio); ret = bgpio_init(&men_z127_gpio->gc, &mdev->dev, 4, @@ -148,7 +150,7 @@ static int men_z127_probe(struct mcb_device *mdev, goto err_unmap; men_z127_gpio->gc.set_debounce = men_z127_debounce; - men_z127_gpio->gc.request = men_z127_request; + men_z127_gpio->gc.set_single_ended = men_z127_set_single_ended; ret = gpiochip_add_data(&men_z127_gpio->gc, men_z127_gpio); if (ret) { diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-mmio.c index 54cddfa..6c1cb3b 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-mmio.c @@ -549,7 +549,7 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev, } EXPORT_SYMBOL_GPL(bgpio_init); -#ifdef CONFIG_GPIO_GENERIC_PLATFORM +#if IS_ENABLED(CONFIG_GPIO_GENERIC_PLATFORM) static void __iomem *bgpio_map(struct platform_device *pdev, const char *name, diff --git a/drivers/gpio/gpio-moxart.c b/drivers/gpio/gpio-moxart.c index f02d0b4..d58d389 100644 --- a/drivers/gpio/gpio-moxart.c +++ b/drivers/gpio/gpio-moxart.c @@ -15,7 +15,6 @@ #include <linux/irq.h> #include <linux/io.h> #include <linux/platform_device.h> -#include <linux/module.h> #include <linux/of_address.h> #include <linux/of_gpio.h> #include <linux/pinctrl/consumer.h> @@ -82,8 +81,4 @@ static struct platform_driver moxart_gpio_driver = { }, .probe = moxart_gpio_probe, }; -module_platform_driver(moxart_gpio_driver); - -MODULE_DESCRIPTION("MOXART GPIO chip driver"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>"); +builtin_platform_driver(moxart_gpio_driver); diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 11c6582..cd5dc27 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -34,7 +34,7 @@ */ #include <linux/err.h> -#include <linux/module.h> +#include <linux/init.h> #include <linux/gpio.h> #include <linux/irq.h> #include <linux/slab.h> @@ -557,7 +557,6 @@ static const struct of_device_id mvebu_gpio_of_match[] = { /* sentinel */ }, }; -MODULE_DEVICE_TABLE(of, mvebu_gpio_of_match); static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state) { @@ -838,4 +837,4 @@ static struct platform_driver mvebu_gpio_driver = { .suspend = mvebu_gpio_suspend, .resume = mvebu_gpio_resume, }; -module_platform_driver(mvebu_gpio_driver); +builtin_platform_driver(mvebu_gpio_driver); diff --git a/drivers/gpio/gpio-octeon.c b/drivers/gpio/gpio-octeon.c index 47aead1..96a8a8c 100644 --- a/drivers/gpio/gpio-octeon.c +++ b/drivers/gpio/gpio-octeon.c @@ -83,6 +83,7 @@ static int octeon_gpio_probe(struct platform_device *pdev) struct octeon_gpio *gpio; struct gpio_chip *chip; struct resource *res_mem; + void __iomem *reg_base; int err = 0; gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); @@ -91,21 +92,11 @@ static int octeon_gpio_probe(struct platform_device *pdev) chip = &gpio->chip; res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res_mem == NULL) { - dev_err(&pdev->dev, "found no memory resource\n"); - err = -ENXIO; - goto out; - } - if (!devm_request_mem_region(&pdev->dev, res_mem->start, - resource_size(res_mem), - res_mem->name)) { - dev_err(&pdev->dev, "request_mem_region failed\n"); - err = -ENXIO; - goto out; - } - gpio->register_base = (u64)devm_ioremap(&pdev->dev, res_mem->start, - resource_size(res_mem)); + reg_base = devm_ioremap_resource(&pdev->dev, res_mem); + if (IS_ERR(reg_base)) + return PTR_ERR(reg_base); + gpio->register_base = (u64)reg_base; pdev->dev.platform_data = chip; chip->label = "octeon-gpio"; chip->parent = &pdev->dev; @@ -119,14 +110,13 @@ static int octeon_gpio_probe(struct platform_device *pdev) chip->set = octeon_gpio_set; err = devm_gpiochip_add_data(&pdev->dev, chip, gpio); if (err) - goto out; + return err; dev_info(&pdev->dev, "OCTEON GPIO driver probed.\n"); -out: - return err; + return 0; } -static struct of_device_id octeon_gpio_match[] = { +static const struct of_device_id octeon_gpio_match[] = { { .compatible = "cavium,octeon-3860-gpio", }, diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 551dfa9..b98ede7 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -611,51 +611,12 @@ static inline void omap_set_gpio_irqenable(struct gpio_bank *bank, omap_disable_gpio_irqbank(bank, BIT(offset)); } -/* - * Note that ENAWAKEUP needs to be enabled in GPIO_SYSCONFIG register. - * 1510 does not seem to have a wake-up register. If JTAG is connected - * to the target, system will wake up always on GPIO events. While - * system is running all registered GPIO interrupts need to have wake-up - * enabled. When system is suspended, only selected GPIO interrupts need - * to have wake-up enabled. - */ -static int omap_set_gpio_wakeup(struct gpio_bank *bank, unsigned offset, - int enable) -{ - u32 gpio_bit = BIT(offset); - unsigned long flags; - - if (bank->non_wakeup_gpios & gpio_bit) { - dev_err(bank->chip.parent, - "Unable to modify wakeup on non-wakeup GPIO%d\n", - offset); - return -EINVAL; - } - - raw_spin_lock_irqsave(&bank->lock, flags); - if (enable) - bank->context.wake_en |= gpio_bit; - else - bank->context.wake_en &= ~gpio_bit; - - writel_relaxed(bank->context.wake_en, bank->base + bank->regs->wkup_en); - raw_spin_unlock_irqrestore(&bank->lock, flags); - - return 0; -} - /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */ static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable) { struct gpio_bank *bank = omap_irq_data_get_bank(d); - unsigned offset = d->hwirq; - int ret; - ret = omap_set_gpio_wakeup(bank, offset, enable); - if (!ret) - ret = irq_set_irq_wake(bank->irq, enable); - - return ret; + return irq_set_irq_wake(bank->irq, enable); } static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) @@ -1187,6 +1148,7 @@ static int omap_gpio_probe(struct platform_device *pdev) irqc->irq_bus_lock = omap_gpio_irq_bus_lock, irqc->irq_bus_sync_unlock = gpio_irq_bus_sync_unlock, irqc->name = dev_name(&pdev->dev); + irqc->flags = IRQCHIP_MASK_ON_SUSPEND; bank->irq = platform_get_irq(pdev, 0); if (bank->irq <= 0) { diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c index 6f27b3d..e248707 100644 --- a/drivers/gpio/gpio-palmas.c +++ b/drivers/gpio/gpio-palmas.c @@ -20,7 +20,7 @@ #include <linux/gpio.h> #include <linux/kernel.h> -#include <linux/module.h> +#include <linux/init.h> #include <linux/mfd/palmas.h> #include <linux/of.h> #include <linux/of_device.h> @@ -218,14 +218,3 @@ static int __init palmas_gpio_init(void) return platform_driver_register(&palmas_gpio_driver); } subsys_initcall(palmas_gpio_init); - -static void __exit palmas_gpio_exit(void) -{ - platform_driver_unregister(&palmas_gpio_driver); -} -module_exit(palmas_gpio_exit); - -MODULE_ALIAS("platform:palmas-gpio"); -MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); -MODULE_DESCRIPTION("GPIO driver for TI Palmas series PMICs"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index e66084c..5e3be32 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -38,8 +38,13 @@ #define PCA957X_MSK 6 #define PCA957X_INTS 7 +#define PCAL953X_IN_LATCH 34 +#define PCAL953X_INT_MASK 37 +#define PCAL953X_INT_STAT 38 + #define PCA_GPIO_MASK 0x00FF #define PCA_INT 0x0100 +#define PCA_PCAL 0x0200 #define PCA953X_TYPE 0x1000 #define PCA957X_TYPE 0x2000 #define PCA_TYPE_MASK 0xF000 @@ -77,7 +82,7 @@ static const struct i2c_device_id pca953x_id[] = { MODULE_DEVICE_TABLE(i2c, pca953x_id); static const struct acpi_device_id pca953x_acpi_ids[] = { - { "INT3491", 16 | PCA953X_TYPE | PCA_INT, }, + { "INT3491", 16 | PCA953X_TYPE | PCA_INT | PCA_PCAL, }, { } }; MODULE_DEVICE_TABLE(acpi, pca953x_acpi_ids); @@ -437,6 +442,18 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) struct pca953x_chip *chip = gpiochip_get_data(gc); u8 new_irqs; int level, i; + u8 invert_irq_mask[MAX_BANK]; + + if (chip->driver_data & PCA_PCAL) { + /* Enable latch on interrupt-enabled inputs */ + pca953x_write_regs(chip, PCAL953X_IN_LATCH, chip->irq_mask); + + for (i = 0; i < NBANK(chip); i++) + invert_irq_mask[i] = ~chip->irq_mask[i]; + + /* Unmask enabled interrupts */ + pca953x_write_regs(chip, PCAL953X_INT_MASK, invert_irq_mask); + } /* Look for any newly setup interrupt */ for (i = 0; i < NBANK(chip); i++) { @@ -498,6 +515,29 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending) u8 trigger[MAX_BANK]; int ret, i, offset = 0; + if (chip->driver_data & PCA_PCAL) { + /* Read the current interrupt status from the device */ + ret = pca953x_read_regs(chip, PCAL953X_INT_STAT, trigger); + if (ret) + return false; + + /* Check latched inputs and clear interrupt status */ + ret = pca953x_read_regs(chip, PCA953X_INPUT, cur_stat); + if (ret) + return false; + + for (i = 0; i < NBANK(chip); i++) { + /* Apply filter for rising/falling edge selection */ + pending[i] = (~cur_stat[i] & chip->irq_trig_fall[i]) | + (cur_stat[i] & chip->irq_trig_raise[i]); + pending[i] &= trigger[i]; + if (pending[i]) + pending_seen = true; + } + + return pending_seen; + } + switch (chip->chip_type) { case PCA953X_TYPE: offset = PCA953X_INPUT; diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 5cb3821..6e3c143 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -1,6 +1,8 @@ /* * Copyright (C) 2008, 2009 Provigent Ltd. * + * Author: Baruch Siach <baruch@tkos.co.il> + * * 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. @@ -11,7 +13,7 @@ */ #include <linux/spinlock.h> #include <linux/errno.h> -#include <linux/module.h> +#include <linux/init.h> #include <linux/io.h> #include <linux/ioport.h> #include <linux/interrupt.h> @@ -59,15 +61,19 @@ struct pl061_gpio { #endif }; +static int pl061_get_direction(struct gpio_chip *gc, unsigned offset) +{ + struct pl061_gpio *chip = gpiochip_get_data(gc); + + return !(readb(chip->base + GPIODIR) & BIT(offset)); +} + static int pl061_direction_input(struct gpio_chip *gc, unsigned offset) { struct pl061_gpio *chip = gpiochip_get_data(gc); unsigned long flags; unsigned char gpiodir; - if (offset >= gc->ngpio) - return -EINVAL; - spin_lock_irqsave(&chip->lock, flags); gpiodir = readb(chip->base + GPIODIR); gpiodir &= ~(BIT(offset)); @@ -84,9 +90,6 @@ static int pl061_direction_output(struct gpio_chip *gc, unsigned offset, unsigned long flags; unsigned char gpiodir; - if (offset >= gc->ngpio) - return -EINVAL; - spin_lock_irqsave(&chip->lock, flags); writeb(!!value << offset, chip->base + (BIT(offset + 2))); gpiodir = readb(chip->base + GPIODIR); @@ -319,6 +322,7 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) chip->gc.free = gpiochip_generic_free; } + chip->gc.get_direction = pl061_get_direction; chip->gc.direction_input = pl061_direction_input; chip->gc.direction_output = pl061_direction_output; chip->gc.get = pl061_get_value; @@ -429,8 +433,6 @@ static struct amba_id pl061_ids[] = { { 0, 0 }, }; -MODULE_DEVICE_TABLE(amba, pl061_ids); - static struct amba_driver pl061_gpio_driver = { .drv = { .name = "pl061_gpio", @@ -446,8 +448,4 @@ static int __init pl061_gpio_init(void) { return amba_driver_register(&pl061_gpio_driver); } -module_init(pl061_gpio_init); - -MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>"); -MODULE_DESCRIPTION("PL061 GPIO driver"); -MODULE_LICENSE("GPL"); +device_initcall(pl061_gpio_init); diff --git a/drivers/gpio/gpio-rc5t583.c b/drivers/gpio/gpio-rc5t583.c index 1d6100f..3b4dc1a 100644 --- a/drivers/gpio/gpio-rc5t583.c +++ b/drivers/gpio/gpio-rc5t583.c @@ -23,7 +23,6 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/slab.h> -#include <linux/module.h> #include <linux/platform_device.h> #include <linux/device.h> #include <linux/gpio.h> @@ -152,14 +151,3 @@ static int __init rc5t583_gpio_init(void) return platform_driver_register(&rc5t583_gpio_driver); } subsys_initcall(rc5t583_gpio_init); - -static void __exit rc5t583_gpio_exit(void) -{ - platform_driver_unregister(&rc5t583_gpio_driver); -} -module_exit(rc5t583_gpio_exit); - -MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); -MODULE_DESCRIPTION("GPIO interface for RC5T583"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:rc5t583-gpio"); diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 4d9a315..681c93f 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -284,6 +284,25 @@ static void gpio_rcar_set(struct gpio_chip *chip, unsigned offset, int value) spin_unlock_irqrestore(&p->lock, flags); } +static void gpio_rcar_set_multiple(struct gpio_chip *chip, unsigned long *mask, + unsigned long *bits) +{ + struct gpio_rcar_priv *p = gpiochip_get_data(chip); + unsigned long flags; + u32 val, bankmask; + + bankmask = mask[0] & GENMASK(chip->ngpio - 1, 0); + if (!bankmask) + return; + + spin_lock_irqsave(&p->lock, flags); + val = gpio_rcar_read(p, OUTDT); + val &= ~bankmask; + val |= (bankmask & bits[0]); + gpio_rcar_write(p, OUTDT, val); + spin_unlock_irqrestore(&p->lock, flags); +} + static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset, int value) { @@ -425,6 +444,7 @@ static int gpio_rcar_probe(struct platform_device *pdev) gpio_chip->get = gpio_rcar_get; gpio_chip->direction_output = gpio_rcar_direction_output; gpio_chip->set = gpio_rcar_set; + gpio_chip->set_multiple = gpio_rcar_set_multiple; gpio_chip->label = name; gpio_chip->parent = dev; gpio_chip->owner = THIS_MODULE; diff --git a/drivers/gpio/gpio-sodaville.c b/drivers/gpio/gpio-sodaville.c index e3cb677..7da9e6c 100644 --- a/drivers/gpio/gpio-sodaville.c +++ b/drivers/gpio/gpio-sodaville.c @@ -3,6 +3,8 @@ * * Copyright (c) 2010, 2011 Intel Corporation * + * Author: Hans J. Koch <hjk@linutronix.de> + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License 2 as published * by the Free Software Foundation. @@ -15,7 +17,6 @@ #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/kernel.h> -#include <linux/module.h> #include <linux/pci.h> #include <linux/platform_device.h> #include <linux/of_irq.h> @@ -257,34 +258,17 @@ done: return ret; } -static void sdv_gpio_remove(struct pci_dev *pdev) -{ - struct sdv_gpio_chip_data *sd = pci_get_drvdata(pdev); - - free_irq(pdev->irq, sd); - irq_free_descs(sd->irq_base, SDV_NUM_PUB_GPIOS); - - gpiochip_remove(&sd->chip); - pci_release_region(pdev, GPIO_BAR); - iounmap(sd->gpio_pub_base); - pci_disable_device(pdev); - kfree(sd); -} - static const struct pci_device_id sdv_gpio_pci_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_SDV_GPIO) }, { 0, }, }; static struct pci_driver sdv_gpio_driver = { + .driver = { + .suppress_bind_attrs = true, + }, .name = DRV_NAME, .id_table = sdv_gpio_pci_ids, .probe = sdv_gpio_probe, - .remove = sdv_gpio_remove, }; - -module_pci_driver(sdv_gpio_driver); - -MODULE_AUTHOR("Hans J. Koch <hjk@linutronix.de>"); -MODULE_DESCRIPTION("GPIO interface for Intel Sodaville SoCs"); -MODULE_LICENSE("GPL v2"); +builtin_pci_driver(sdv_gpio_driver); diff --git a/drivers/gpio/gpio-sta2x11.c b/drivers/gpio/gpio-sta2x11.c index 0d5b8c5..853ca23 100644 --- a/drivers/gpio/gpio-sta2x11.c +++ b/drivers/gpio/gpio-sta2x11.c @@ -20,7 +20,7 @@ * */ -#include <linux/module.h> +#include <linux/init.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/gpio.h> @@ -432,8 +432,4 @@ static struct platform_driver sta2x11_gpio_platform_driver = { }, .probe = gsta_probe, }; - -module_platform_driver(sta2x11_gpio_platform_driver); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("sta2x11_gpio GPIO driver"); +builtin_platform_driver(sta2x11_gpio_platform_driver); diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 5197edf..6f7af28 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -5,7 +5,6 @@ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson */ -#include <linux/module.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/slab.h> @@ -413,23 +412,13 @@ out_free: return ret; } -static int stmpe_gpio_remove(struct platform_device *pdev) -{ - struct stmpe_gpio *stmpe_gpio = platform_get_drvdata(pdev); - struct stmpe *stmpe = stmpe_gpio->stmpe; - - gpiochip_remove(&stmpe_gpio->chip); - stmpe_disable(stmpe, STMPE_BLOCK_GPIO); - kfree(stmpe_gpio); - - return 0; -} - static struct platform_driver stmpe_gpio_driver = { - .driver.name = "stmpe-gpio", - .driver.owner = THIS_MODULE, + .driver = { + .suppress_bind_attrs = true, + .name = "stmpe-gpio", + .owner = THIS_MODULE, + }, .probe = stmpe_gpio_probe, - .remove = stmpe_gpio_remove, }; static int __init stmpe_gpio_init(void) @@ -437,13 +426,3 @@ static int __init stmpe_gpio_init(void) return platform_driver_register(&stmpe_gpio_driver); } subsys_initcall(stmpe_gpio_init); - -static void __exit stmpe_gpio_exit(void) -{ - platform_driver_unregister(&stmpe_gpio_driver); -} -module_exit(stmpe_gpio_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("STMPExxxx GPIO driver"); -MODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>"); diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c index d387eb5..a177ebd 100644 --- a/drivers/gpio/gpio-sx150x.c +++ b/drivers/gpio/gpio-sx150x.c @@ -1,5 +1,9 @@ /* Copyright (c) 2010, Code Aurora Forum. All rights reserved. * + * Driver for Semtech SX150X I2C GPIO Expanders + * + * Author: Gregory Bean <gbean@codeaurora.org> + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. @@ -19,10 +23,8 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/irq.h> -#include <linux/module.h> #include <linux/mutex.h> #include <linux/slab.h> -#include <linux/i2c/sx150x.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> @@ -82,6 +84,57 @@ struct sx150x_device_data { } pri; }; +/** + * struct sx150x_platform_data - config data for SX150x driver + * @gpio_base: The index number of the first GPIO assigned to this + * GPIO expander. The expander will create a block of + * consecutively numbered gpios beginning at the given base, + * with the size of the block depending on the model of the + * expander chip. + * @oscio_is_gpo: If set to true, the driver will configure OSCIO as a GPO + * instead of as an oscillator, increasing the size of the + * GP(I)O pool created by this expander by one. The + * output-only GPO pin will be added at the end of the block. + * @io_pullup_ena: A bit-mask which enables or disables the pull-up resistor + * for each IO line in the expander. Setting the bit at + * position n will enable the pull-up for the IO at + * the corresponding offset. For chips with fewer than + * 16 IO pins, high-end bits are ignored. + * @io_pulldn_ena: A bit-mask which enables-or disables the pull-down + * resistor for each IO line in the expander. Setting the + * bit at position n will enable the pull-down for the IO at + * the corresponding offset. For chips with fewer than + * 16 IO pins, high-end bits are ignored. + * @io_polarity: A bit-mask which enables polarity inversion for each IO line + * in the expander. Setting the bit at position n inverts + * the polarity of that IO line, while clearing it results + * in normal polarity. For chips with fewer than 16 IO pins, + * high-end bits are ignored. + * @irq_summary: The 'summary IRQ' line to which the GPIO expander's INT line + * is connected, via which it reports interrupt events + * across all GPIO lines. This must be a real, + * pre-existing IRQ line. + * Setting this value < 0 disables the irq_chip functionality + * of the driver. + * @irq_base: The first 'virtual IRQ' line at which our block of GPIO-based + * IRQ lines will appear. Similarly to gpio_base, the expander + * will create a block of irqs beginning at this number. + * This value is ignored if irq_summary is < 0. + * @reset_during_probe: If set to true, the driver will trigger a full + * reset of the chip at the beginning of the probe + * in order to place it in a known state. + */ +struct sx150x_platform_data { + unsigned gpio_base; + bool oscio_is_gpo; + u16 io_pullup_ena; + u16 io_pulldn_ena; + u16 io_polarity; + int irq_summary; + unsigned irq_base; + bool reset_during_probe; +}; + struct sx150x_chip { struct gpio_chip gpio_chip; struct i2c_client *client; @@ -354,6 +407,32 @@ static void sx150x_gpio_set(struct gpio_chip *gc, unsigned offset, int val) mutex_unlock(&chip->lock); } +static int sx150x_gpio_set_single_ended(struct gpio_chip *gc, + unsigned offset, + enum single_ended_mode mode) +{ + struct sx150x_chip *chip = gpiochip_get_data(gc); + + /* On the SX160X 789 we can set open drain */ + if (chip->dev_cfg->model != SX150X_789) + return -ENOTSUPP; + + if (mode == LINE_MODE_PUSH_PULL) + return sx150x_write_cfg(chip, + offset, + 1, + chip->dev_cfg->pri.x789.reg_drain, + 0); + + if (mode == LINE_MODE_OPEN_DRAIN) + return sx150x_write_cfg(chip, + offset, + 1, + chip->dev_cfg->pri.x789.reg_drain, + 1); + return -ENOTSUPP; +} + static int sx150x_gpio_direction_input(struct gpio_chip *gc, unsigned offset) { struct sx150x_chip *chip = gpiochip_get_data(gc); @@ -508,6 +587,7 @@ static void sx150x_init_chip(struct sx150x_chip *chip, chip->gpio_chip.direction_output = sx150x_gpio_direction_output; chip->gpio_chip.get = sx150x_gpio_get; chip->gpio_chip.set = sx150x_gpio_set; + chip->gpio_chip.set_single_ended = sx150x_gpio_set_single_ended; chip->gpio_chip.base = pdata->gpio_base; chip->gpio_chip.can_sleep = true; chip->gpio_chip.ngpio = chip->dev_cfg->ngpios; @@ -597,12 +677,6 @@ static int sx150x_init_hw(struct sx150x_chip *chip, if (chip->dev_cfg->model == SX150X_789) { err = sx150x_init_io(chip, - chip->dev_cfg->pri.x789.reg_drain, - pdata->io_open_drain_ena); - if (err < 0) - return err; - - err = sx150x_init_io(chip, chip->dev_cfg->pri.x789.reg_polarity, pdata->io_polarity); if (err < 0) @@ -718,13 +792,3 @@ static int __init sx150x_init(void) return i2c_add_driver(&sx150x_driver); } subsys_initcall(sx150x_init); - -static void __exit sx150x_exit(void) -{ - return i2c_del_driver(&sx150x_driver); -} -module_exit(sx150x_exit); - -MODULE_AUTHOR("Gregory Bean <gbean@codeaurora.org>"); -MODULE_DESCRIPTION("Driver for Semtech SX150X I2C GPIO Expanders"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index 4f566e6..2e35ed3 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -6,14 +6,14 @@ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson */ -#include <linux/module.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/slab.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/of.h> #include <linux/interrupt.h> #include <linux/mfd/tc3589x.h> +#include <linux/bitops.h> /* * These registers are modified under the irq bus lock and cached to avoid @@ -39,7 +39,7 @@ static int tc3589x_gpio_get(struct gpio_chip *chip, unsigned offset) struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip); struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; u8 reg = TC3589x_GPIODATA0 + (offset / 8) * 2; - u8 mask = 1 << (offset % 8); + u8 mask = BIT(offset % 8); int ret; ret = tc3589x_reg_read(tc3589x, reg); @@ -55,7 +55,7 @@ static void tc3589x_gpio_set(struct gpio_chip *chip, unsigned offset, int val) struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; u8 reg = TC3589x_GPIODATA0 + (offset / 8) * 2; unsigned pos = offset % 8; - u8 data[] = {!!val << pos, 1 << pos}; + u8 data[] = {val ? BIT(pos) : 0, BIT(pos)}; tc3589x_block_write(tc3589x, reg, ARRAY_SIZE(data), data); } @@ -70,7 +70,7 @@ static int tc3589x_gpio_direction_output(struct gpio_chip *chip, tc3589x_gpio_set(chip, offset, val); - return tc3589x_set_bits(tc3589x, reg, 1 << pos, 1 << pos); + return tc3589x_set_bits(tc3589x, reg, BIT(pos), BIT(pos)); } static int tc3589x_gpio_direction_input(struct gpio_chip *chip, @@ -81,7 +81,47 @@ static int tc3589x_gpio_direction_input(struct gpio_chip *chip, u8 reg = TC3589x_GPIODIR0 + offset / 8; unsigned pos = offset % 8; - return tc3589x_set_bits(tc3589x, reg, 1 << pos, 0); + return tc3589x_set_bits(tc3589x, reg, BIT(pos), 0); +} + +static int tc3589x_gpio_single_ended(struct gpio_chip *chip, + unsigned offset, + enum single_ended_mode mode) +{ + struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip); + struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; + /* + * These registers are alterated at each second address + * ODM bit 0 = drive to GND or Hi-Z (open drain) + * ODM bit 1 = drive to VDD or Hi-Z (open source) + */ + u8 odmreg = TC3589x_GPIOODM0 + (offset / 8) * 2; + u8 odereg = TC3589x_GPIOODE0 + (offset / 8) * 2; + unsigned pos = offset % 8; + int ret; + + switch(mode) { + case LINE_MODE_OPEN_DRAIN: + /* Set open drain mode */ + ret = tc3589x_set_bits(tc3589x, odmreg, BIT(pos), 0); + if (ret) + return ret; + /* Enable open drain/source mode */ + return tc3589x_set_bits(tc3589x, odereg, BIT(pos), BIT(pos)); + case LINE_MODE_OPEN_SOURCE: + /* Set open source mode */ + ret = tc3589x_set_bits(tc3589x, odmreg, BIT(pos), BIT(pos)); + if (ret) + return ret; + /* Enable open drain/source mode */ + return tc3589x_set_bits(tc3589x, odereg, BIT(pos), BIT(pos)); + case LINE_MODE_PUSH_PULL: + /* Disable open drain/source mode */ + return tc3589x_set_bits(tc3589x, odereg, BIT(pos), 0); + default: + break; + } + return -ENOTSUPP; } static struct gpio_chip template_chip = { @@ -91,6 +131,7 @@ static struct gpio_chip template_chip = { .get = tc3589x_gpio_get, .direction_output = tc3589x_gpio_direction_output, .set = tc3589x_gpio_set, + .set_single_ended = tc3589x_gpio_single_ended, .can_sleep = true, }; @@ -100,7 +141,7 @@ static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type) struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc); int offset = d->hwirq; int regoffset = offset / 8; - int mask = 1 << (offset % 8); + int mask = BIT(offset % 8); if (type == IRQ_TYPE_EDGE_BOTH) { tc3589x_gpio->regs[REG_IBE][regoffset] |= mask; @@ -165,7 +206,7 @@ static void tc3589x_gpio_irq_mask(struct irq_data *d) struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc); int offset = d->hwirq; int regoffset = offset / 8; - int mask = 1 << (offset % 8); + int mask = BIT(offset % 8); tc3589x_gpio->regs[REG_IE][regoffset] &= ~mask; } @@ -176,7 +217,7 @@ static void tc3589x_gpio_irq_unmask(struct irq_data *d) struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc); int offset = d->hwirq; int regoffset = offset / 8; - int mask = 1 << (offset % 8); + int mask = BIT(offset % 8); tc3589x_gpio->regs[REG_IE][regoffset] |= mask; } @@ -311,13 +352,3 @@ static int __init tc3589x_gpio_init(void) return platform_driver_register(&tc3589x_gpio_driver); } subsys_initcall(tc3589x_gpio_init); - -static void __exit tc3589x_gpio_exit(void) -{ - platform_driver_unregister(&tc3589x_gpio_driver); -} -module_exit(tc3589x_gpio_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("TC3589x GPIO driver"); -MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent"); diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 790bb11..ec891a27 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -35,24 +35,27 @@ #define GPIO_PORT(x) (((x) >> 3) & 0x3) #define GPIO_BIT(x) ((x) & 0x7) -#define GPIO_REG(x) (GPIO_BANK(x) * tegra_gpio_bank_stride + \ +#define GPIO_REG(tgi, x) (GPIO_BANK(x) * tgi->soc->bank_stride + \ GPIO_PORT(x) * 4) -#define GPIO_CNF(x) (GPIO_REG(x) + 0x00) -#define GPIO_OE(x) (GPIO_REG(x) + 0x10) -#define GPIO_OUT(x) (GPIO_REG(x) + 0X20) -#define GPIO_IN(x) (GPIO_REG(x) + 0x30) -#define GPIO_INT_STA(x) (GPIO_REG(x) + 0x40) -#define GPIO_INT_ENB(x) (GPIO_REG(x) + 0x50) -#define GPIO_INT_LVL(x) (GPIO_REG(x) + 0x60) -#define GPIO_INT_CLR(x) (GPIO_REG(x) + 0x70) - -#define GPIO_MSK_CNF(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x00) -#define GPIO_MSK_OE(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x10) -#define GPIO_MSK_OUT(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0X20) -#define GPIO_MSK_INT_STA(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x40) -#define GPIO_MSK_INT_ENB(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x50) -#define GPIO_MSK_INT_LVL(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x60) +#define GPIO_CNF(t, x) (GPIO_REG(t, x) + 0x00) +#define GPIO_OE(t, x) (GPIO_REG(t, x) + 0x10) +#define GPIO_OUT(t, x) (GPIO_REG(t, x) + 0X20) +#define GPIO_IN(t, x) (GPIO_REG(t, x) + 0x30) +#define GPIO_INT_STA(t, x) (GPIO_REG(t, x) + 0x40) +#define GPIO_INT_ENB(t, x) (GPIO_REG(t, x) + 0x50) +#define GPIO_INT_LVL(t, x) (GPIO_REG(t, x) + 0x60) +#define GPIO_INT_CLR(t, x) (GPIO_REG(t, x) + 0x70) +#define GPIO_DBC_CNT(t, x) (GPIO_REG(t, x) + 0xF0) + + +#define GPIO_MSK_CNF(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0x00) +#define GPIO_MSK_OE(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0x10) +#define GPIO_MSK_OUT(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0X20) +#define GPIO_MSK_DBC_EN(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0x30) +#define GPIO_MSK_INT_STA(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0x40) +#define GPIO_MSK_INT_ENB(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0x50) +#define GPIO_MSK_INT_LVL(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0x60) #define GPIO_INT_LVL_MASK 0x010101 #define GPIO_INT_LVL_EDGE_RISING 0x000101 @@ -61,10 +64,13 @@ #define GPIO_INT_LVL_LEVEL_HIGH 0x000001 #define GPIO_INT_LVL_LEVEL_LOW 0x000000 +struct tegra_gpio_info; + struct tegra_gpio_bank { int bank; int irq; spinlock_t lvl_lock[4]; + spinlock_t dbc_lock[4]; /* Lock for updating debounce count register */ #ifdef CONFIG_PM_SLEEP u32 cnf[4]; u32 out[4]; @@ -72,25 +78,39 @@ struct tegra_gpio_bank { u32 int_enb[4]; u32 int_lvl[4]; u32 wake_enb[4]; + u32 dbc_enb[4]; #endif + u32 dbc_cnt[4]; + struct tegra_gpio_info *tgi; }; -static struct device *dev; -static struct irq_domain *irq_domain; -static void __iomem *regs; -static u32 tegra_gpio_bank_count; -static u32 tegra_gpio_bank_stride; -static u32 tegra_gpio_upper_offset; -static struct tegra_gpio_bank *tegra_gpio_banks; +struct tegra_gpio_soc_config { + bool debounce_supported; + u32 bank_stride; + u32 upper_offset; +}; + +struct tegra_gpio_info { + struct device *dev; + void __iomem *regs; + struct irq_domain *irq_domain; + struct tegra_gpio_bank *bank_info; + const struct tegra_gpio_soc_config *soc; + struct gpio_chip gc; + struct irq_chip ic; + struct lock_class_key lock_class; + u32 bank_count; +}; -static inline void tegra_gpio_writel(u32 val, u32 reg) +static inline void tegra_gpio_writel(struct tegra_gpio_info *tgi, + u32 val, u32 reg) { - __raw_writel(val, regs + reg); + __raw_writel(val, tgi->regs + reg); } -static inline u32 tegra_gpio_readl(u32 reg) +static inline u32 tegra_gpio_readl(struct tegra_gpio_info *tgi, u32 reg) { - return __raw_readl(regs + reg); + return __raw_readl(tgi->regs + reg); } static int tegra_gpio_compose(int bank, int port, int bit) @@ -98,24 +118,25 @@ static int tegra_gpio_compose(int bank, int port, int bit) return (bank << 5) | ((port & 0x3) << 3) | (bit & 0x7); } -static void tegra_gpio_mask_write(u32 reg, int gpio, int value) +static void tegra_gpio_mask_write(struct tegra_gpio_info *tgi, u32 reg, + int gpio, int value) { u32 val; val = 0x100 << GPIO_BIT(gpio); if (value) val |= 1 << GPIO_BIT(gpio); - tegra_gpio_writel(val, reg); + tegra_gpio_writel(tgi, val, reg); } -static void tegra_gpio_enable(int gpio) +static void tegra_gpio_enable(struct tegra_gpio_info *tgi, int gpio) { - tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 1); + tegra_gpio_mask_write(tgi, GPIO_MSK_CNF(tgi, gpio), gpio, 1); } -static void tegra_gpio_disable(int gpio) +static void tegra_gpio_disable(struct tegra_gpio_info *tgi, int gpio) { - tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 0); + tegra_gpio_mask_write(tgi, GPIO_MSK_CNF(tgi, gpio), gpio, 0); } static int tegra_gpio_request(struct gpio_chip *chip, unsigned offset) @@ -125,83 +146,138 @@ static int tegra_gpio_request(struct gpio_chip *chip, unsigned offset) static void tegra_gpio_free(struct gpio_chip *chip, unsigned offset) { + struct tegra_gpio_info *tgi = gpiochip_get_data(chip); + pinctrl_free_gpio(offset); - tegra_gpio_disable(offset); + tegra_gpio_disable(tgi, offset); } static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { - tegra_gpio_mask_write(GPIO_MSK_OUT(offset), offset, value); + struct tegra_gpio_info *tgi = gpiochip_get_data(chip); + + tegra_gpio_mask_write(tgi, GPIO_MSK_OUT(tgi, offset), offset, value); } static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset) { + struct tegra_gpio_info *tgi = gpiochip_get_data(chip); + int bval = BIT(GPIO_BIT(offset)); + /* If gpio is in output mode then read from the out value */ - if ((tegra_gpio_readl(GPIO_OE(offset)) >> GPIO_BIT(offset)) & 1) - return (tegra_gpio_readl(GPIO_OUT(offset)) >> - GPIO_BIT(offset)) & 0x1; + if (tegra_gpio_readl(tgi, GPIO_OE(tgi, offset)) & bval) + return !!(tegra_gpio_readl(tgi, GPIO_OUT(tgi, offset)) & bval); - return (tegra_gpio_readl(GPIO_IN(offset)) >> GPIO_BIT(offset)) & 0x1; + return !!(tegra_gpio_readl(tgi, GPIO_IN(tgi, offset)) & bval); } static int tegra_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { - tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 0); - tegra_gpio_enable(offset); + struct tegra_gpio_info *tgi = gpiochip_get_data(chip); + + tegra_gpio_mask_write(tgi, GPIO_MSK_OE(tgi, offset), offset, 0); + tegra_gpio_enable(tgi, offset); return 0; } static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value) { + struct tegra_gpio_info *tgi = gpiochip_get_data(chip); + tegra_gpio_set(chip, offset, value); - tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 1); - tegra_gpio_enable(offset); + tegra_gpio_mask_write(tgi, GPIO_MSK_OE(tgi, offset), offset, 1); + tegra_gpio_enable(tgi, offset); return 0; } -static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +static int tegra_gpio_get_direction(struct gpio_chip *chip, unsigned offset) { - return irq_find_mapping(irq_domain, offset); + struct tegra_gpio_info *tgi = gpiochip_get_data(chip); + u32 pin_mask = BIT(GPIO_BIT(offset)); + u32 cnf, oe; + + cnf = tegra_gpio_readl(tgi, GPIO_CNF(tgi, offset)); + if (!(cnf & pin_mask)) + return -EINVAL; + + oe = tegra_gpio_readl(tgi, GPIO_OE(tgi, offset)); + + return (oe & pin_mask) ? GPIOF_DIR_OUT : GPIOF_DIR_IN; } -static struct gpio_chip tegra_gpio_chip = { - .label = "tegra-gpio", - .request = tegra_gpio_request, - .free = tegra_gpio_free, - .direction_input = tegra_gpio_direction_input, - .get = tegra_gpio_get, - .direction_output = tegra_gpio_direction_output, - .set = tegra_gpio_set, - .to_irq = tegra_gpio_to_irq, - .base = 0, -}; +static int tegra_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset, + unsigned int debounce) +{ + struct tegra_gpio_info *tgi = gpiochip_get_data(chip); + struct tegra_gpio_bank *bank = &tgi->bank_info[GPIO_BANK(offset)]; + unsigned int debounce_ms = DIV_ROUND_UP(debounce, 1000); + unsigned long flags; + int port; + + if (!debounce_ms) { + tegra_gpio_mask_write(tgi, GPIO_MSK_DBC_EN(tgi, offset), + offset, 0); + return 0; + } + + debounce_ms = min(debounce_ms, 255U); + port = GPIO_PORT(offset); + + /* There is only one debounce count register per port and hence + * set the maximum of current and requested debounce time. + */ + spin_lock_irqsave(&bank->dbc_lock[port], flags); + if (bank->dbc_cnt[port] < debounce_ms) { + tegra_gpio_writel(tgi, debounce_ms, GPIO_DBC_CNT(tgi, offset)); + bank->dbc_cnt[port] = debounce_ms; + } + spin_unlock_irqrestore(&bank->dbc_lock[port], flags); + + tegra_gpio_mask_write(tgi, GPIO_MSK_DBC_EN(tgi, offset), offset, 1); + + return 0; +} + +static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct tegra_gpio_info *tgi = gpiochip_get_data(chip); + + return irq_find_mapping(tgi->irq_domain, offset); +} static void tegra_gpio_irq_ack(struct irq_data *d) { + struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct tegra_gpio_info *tgi = bank->tgi; int gpio = d->hwirq; - tegra_gpio_writel(1 << GPIO_BIT(gpio), GPIO_INT_CLR(gpio)); + tegra_gpio_writel(tgi, 1 << GPIO_BIT(gpio), GPIO_INT_CLR(tgi, gpio)); } static void tegra_gpio_irq_mask(struct irq_data *d) { + struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct tegra_gpio_info *tgi = bank->tgi; int gpio = d->hwirq; - tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 0); + tegra_gpio_mask_write(tgi, GPIO_MSK_INT_ENB(tgi, gpio), gpio, 0); } static void tegra_gpio_irq_unmask(struct irq_data *d) { + struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct tegra_gpio_info *tgi = bank->tgi; int gpio = d->hwirq; - tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 1); + tegra_gpio_mask_write(tgi, GPIO_MSK_INT_ENB(tgi, gpio), gpio, 1); } static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) { int gpio = d->hwirq; struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct tegra_gpio_info *tgi = bank->tgi; int port = GPIO_PORT(gpio); int lvl_type; int val; @@ -233,23 +309,24 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) return -EINVAL; } - ret = gpiochip_lock_as_irq(&tegra_gpio_chip, gpio); + ret = gpiochip_lock_as_irq(&tgi->gc, gpio); if (ret) { - dev_err(dev, "unable to lock Tegra GPIO %d as IRQ\n", gpio); + dev_err(tgi->dev, + "unable to lock Tegra GPIO %d as IRQ\n", gpio); return ret; } spin_lock_irqsave(&bank->lvl_lock[port], flags); - val = tegra_gpio_readl(GPIO_INT_LVL(gpio)); + val = tegra_gpio_readl(tgi, GPIO_INT_LVL(tgi, gpio)); val &= ~(GPIO_INT_LVL_MASK << GPIO_BIT(gpio)); val |= lvl_type << GPIO_BIT(gpio); - tegra_gpio_writel(val, GPIO_INT_LVL(gpio)); + tegra_gpio_writel(tgi, val, GPIO_INT_LVL(tgi, gpio)); spin_unlock_irqrestore(&bank->lvl_lock[port], flags); - tegra_gpio_mask_write(GPIO_MSK_OE(gpio), gpio, 0); - tegra_gpio_enable(gpio); + tegra_gpio_mask_write(tgi, GPIO_MSK_OE(tgi, gpio), gpio, 0); + tegra_gpio_enable(tgi, gpio); if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) irq_set_handler_locked(d, handle_level_irq); @@ -261,9 +338,11 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) static void tegra_gpio_irq_shutdown(struct irq_data *d) { + struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct tegra_gpio_info *tgi = bank->tgi; int gpio = d->hwirq; - gpiochip_unlock_as_irq(&tegra_gpio_chip, gpio); + gpiochip_unlock_as_irq(&tgi->gc, gpio); } static void tegra_gpio_irq_handler(struct irq_desc *desc) @@ -271,19 +350,24 @@ static void tegra_gpio_irq_handler(struct irq_desc *desc) int port; int pin; int unmasked = 0; + int gpio; + u32 lvl; + unsigned long sta; struct irq_chip *chip = irq_desc_get_chip(desc); struct tegra_gpio_bank *bank = irq_desc_get_handler_data(desc); + struct tegra_gpio_info *tgi = bank->tgi; chained_irq_enter(chip, desc); for (port = 0; port < 4; port++) { - int gpio = tegra_gpio_compose(bank->bank, port, 0); - unsigned long sta = tegra_gpio_readl(GPIO_INT_STA(gpio)) & - tegra_gpio_readl(GPIO_INT_ENB(gpio)); - u32 lvl = tegra_gpio_readl(GPIO_INT_LVL(gpio)); + gpio = tegra_gpio_compose(bank->bank, port, 0); + sta = tegra_gpio_readl(tgi, GPIO_INT_STA(tgi, gpio)) & + tegra_gpio_readl(tgi, GPIO_INT_ENB(tgi, gpio)); + lvl = tegra_gpio_readl(tgi, GPIO_INT_LVL(tgi, gpio)); for_each_set_bit(pin, &sta, 8) { - tegra_gpio_writel(1 << pin, GPIO_INT_CLR(gpio)); + tegra_gpio_writel(tgi, 1 << pin, + GPIO_INT_CLR(tgi, gpio)); /* if gpio is edge triggered, clear condition * before executing the handler so that we don't @@ -306,22 +390,37 @@ static void tegra_gpio_irq_handler(struct irq_desc *desc) #ifdef CONFIG_PM_SLEEP static int tegra_gpio_resume(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); + struct tegra_gpio_info *tgi = platform_get_drvdata(pdev); unsigned long flags; int b; int p; local_irq_save(flags); - for (b = 0; b < tegra_gpio_bank_count; b++) { - struct tegra_gpio_bank *bank = &tegra_gpio_banks[b]; + for (b = 0; b < tgi->bank_count; b++) { + struct tegra_gpio_bank *bank = &tgi->bank_info[b]; for (p = 0; p < ARRAY_SIZE(bank->oe); p++) { unsigned int gpio = (b<<5) | (p<<3); - tegra_gpio_writel(bank->cnf[p], GPIO_CNF(gpio)); - tegra_gpio_writel(bank->out[p], GPIO_OUT(gpio)); - tegra_gpio_writel(bank->oe[p], GPIO_OE(gpio)); - tegra_gpio_writel(bank->int_lvl[p], GPIO_INT_LVL(gpio)); - tegra_gpio_writel(bank->int_enb[p], GPIO_INT_ENB(gpio)); + tegra_gpio_writel(tgi, bank->cnf[p], + GPIO_CNF(tgi, gpio)); + + if (tgi->soc->debounce_supported) { + tegra_gpio_writel(tgi, bank->dbc_cnt[p], + GPIO_DBC_CNT(tgi, gpio)); + tegra_gpio_writel(tgi, bank->dbc_enb[p], + GPIO_MSK_DBC_EN(tgi, gpio)); + } + + tegra_gpio_writel(tgi, bank->out[p], + GPIO_OUT(tgi, gpio)); + tegra_gpio_writel(tgi, bank->oe[p], + GPIO_OE(tgi, gpio)); + tegra_gpio_writel(tgi, bank->int_lvl[p], + GPIO_INT_LVL(tgi, gpio)); + tegra_gpio_writel(tgi, bank->int_enb[p], + GPIO_INT_ENB(tgi, gpio)); } } @@ -331,25 +430,39 @@ static int tegra_gpio_resume(struct device *dev) static int tegra_gpio_suspend(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); + struct tegra_gpio_info *tgi = platform_get_drvdata(pdev); unsigned long flags; int b; int p; local_irq_save(flags); - for (b = 0; b < tegra_gpio_bank_count; b++) { - struct tegra_gpio_bank *bank = &tegra_gpio_banks[b]; + for (b = 0; b < tgi->bank_count; b++) { + struct tegra_gpio_bank *bank = &tgi->bank_info[b]; for (p = 0; p < ARRAY_SIZE(bank->oe); p++) { unsigned int gpio = (b<<5) | (p<<3); - bank->cnf[p] = tegra_gpio_readl(GPIO_CNF(gpio)); - bank->out[p] = tegra_gpio_readl(GPIO_OUT(gpio)); - bank->oe[p] = tegra_gpio_readl(GPIO_OE(gpio)); - bank->int_enb[p] = tegra_gpio_readl(GPIO_INT_ENB(gpio)); - bank->int_lvl[p] = tegra_gpio_readl(GPIO_INT_LVL(gpio)); + bank->cnf[p] = tegra_gpio_readl(tgi, + GPIO_CNF(tgi, gpio)); + bank->out[p] = tegra_gpio_readl(tgi, + GPIO_OUT(tgi, gpio)); + bank->oe[p] = tegra_gpio_readl(tgi, + GPIO_OE(tgi, gpio)); + if (tgi->soc->debounce_supported) { + bank->dbc_enb[p] = tegra_gpio_readl(tgi, + GPIO_MSK_DBC_EN(tgi, gpio)); + bank->dbc_enb[p] = (bank->dbc_enb[p] << 8) | + bank->dbc_enb[p]; + } + + bank->int_enb[p] = tegra_gpio_readl(tgi, + GPIO_INT_ENB(tgi, gpio)); + bank->int_lvl[p] = tegra_gpio_readl(tgi, + GPIO_INT_LVL(tgi, gpio)); /* Enable gpio irq for wake up source */ - tegra_gpio_writel(bank->wake_enb[p], - GPIO_INT_ENB(gpio)); + tegra_gpio_writel(tgi, bank->wake_enb[p], + GPIO_INT_ENB(tgi, gpio)); } } local_irq_restore(flags); @@ -382,22 +495,23 @@ static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable) static int dbg_gpio_show(struct seq_file *s, void *unused) { + struct tegra_gpio_info *tgi = s->private; int i; int j; - for (i = 0; i < tegra_gpio_bank_count; i++) { + for (i = 0; i < tgi->bank_count; i++) { for (j = 0; j < 4; j++) { int gpio = tegra_gpio_compose(i, j, 0); seq_printf(s, "%d:%d %02x %02x %02x %02x %02x %02x %06x\n", i, j, - tegra_gpio_readl(GPIO_CNF(gpio)), - tegra_gpio_readl(GPIO_OE(gpio)), - tegra_gpio_readl(GPIO_OUT(gpio)), - tegra_gpio_readl(GPIO_IN(gpio)), - tegra_gpio_readl(GPIO_INT_STA(gpio)), - tegra_gpio_readl(GPIO_INT_ENB(gpio)), - tegra_gpio_readl(GPIO_INT_LVL(gpio))); + tegra_gpio_readl(tgi, GPIO_CNF(tgi, gpio)), + tegra_gpio_readl(tgi, GPIO_OE(tgi, gpio)), + tegra_gpio_readl(tgi, GPIO_OUT(tgi, gpio)), + tegra_gpio_readl(tgi, GPIO_IN(tgi, gpio)), + tegra_gpio_readl(tgi, GPIO_INT_STA(tgi, gpio)), + tegra_gpio_readl(tgi, GPIO_INT_ENB(tgi, gpio)), + tegra_gpio_readl(tgi, GPIO_INT_LVL(tgi, gpio))); } } return 0; @@ -405,7 +519,7 @@ static int dbg_gpio_show(struct seq_file *s, void *unused) static int dbg_gpio_open(struct inode *inode, struct file *file) { - return single_open(file, dbg_gpio_show, &inode->i_private); + return single_open(file, dbg_gpio_show, inode->i_private); } static const struct file_operations debug_fops = { @@ -415,66 +529,28 @@ static const struct file_operations debug_fops = { .release = single_release, }; -static void tegra_gpio_debuginit(void) +static void tegra_gpio_debuginit(struct tegra_gpio_info *tgi) { (void) debugfs_create_file("tegra_gpio", S_IRUGO, - NULL, NULL, &debug_fops); + NULL, tgi, &debug_fops); } #else -static inline void tegra_gpio_debuginit(void) +static inline void tegra_gpio_debuginit(struct tegra_gpio_info *tgi) { } #endif -static struct irq_chip tegra_gpio_irq_chip = { - .name = "GPIO", - .irq_ack = tegra_gpio_irq_ack, - .irq_mask = tegra_gpio_irq_mask, - .irq_unmask = tegra_gpio_irq_unmask, - .irq_set_type = tegra_gpio_irq_set_type, - .irq_shutdown = tegra_gpio_irq_shutdown, -#ifdef CONFIG_PM_SLEEP - .irq_set_wake = tegra_gpio_irq_set_wake, -#endif -}; - static const struct dev_pm_ops tegra_gpio_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(tegra_gpio_suspend, tegra_gpio_resume) }; -struct tegra_gpio_soc_config { - u32 bank_stride; - u32 upper_offset; -}; - -static struct tegra_gpio_soc_config tegra20_gpio_config = { - .bank_stride = 0x80, - .upper_offset = 0x800, -}; - -static struct tegra_gpio_soc_config tegra30_gpio_config = { - .bank_stride = 0x100, - .upper_offset = 0x80, -}; - -static const struct of_device_id tegra_gpio_of_match[] = { - { .compatible = "nvidia,tegra30-gpio", .data = &tegra30_gpio_config }, - { .compatible = "nvidia,tegra20-gpio", .data = &tegra20_gpio_config }, - { }, -}; - -/* This lock class tells lockdep that GPIO irqs are in a different - * category than their parents, so it won't report false recursion. - */ -static struct lock_class_key gpio_lock_class; - static int tegra_gpio_probe(struct platform_device *pdev) { - const struct of_device_id *match; - struct tegra_gpio_soc_config *config; + const struct tegra_gpio_soc_config *config; + struct tegra_gpio_info *tgi; struct resource *res; struct tegra_gpio_bank *bank; int ret; @@ -482,102 +558,153 @@ static int tegra_gpio_probe(struct platform_device *pdev) int i; int j; - dev = &pdev->dev; - - match = of_match_device(tegra_gpio_of_match, &pdev->dev); - if (!match) { + config = of_device_get_match_data(&pdev->dev); + if (!config) { dev_err(&pdev->dev, "Error: No device match found\n"); return -ENODEV; } - config = (struct tegra_gpio_soc_config *)match->data; - tegra_gpio_bank_stride = config->bank_stride; - tegra_gpio_upper_offset = config->upper_offset; + tgi = devm_kzalloc(&pdev->dev, sizeof(*tgi), GFP_KERNEL); + if (!tgi) + return -ENODEV; + + tgi->soc = config; + tgi->dev = &pdev->dev; for (;;) { - res = platform_get_resource(pdev, IORESOURCE_IRQ, tegra_gpio_bank_count); + res = platform_get_resource(pdev, IORESOURCE_IRQ, + tgi->bank_count); if (!res) break; - tegra_gpio_bank_count++; + tgi->bank_count++; } - if (!tegra_gpio_bank_count) { + if (!tgi->bank_count) { dev_err(&pdev->dev, "Missing IRQ resource\n"); return -ENODEV; } - tegra_gpio_chip.ngpio = tegra_gpio_bank_count * 32; + tgi->gc.label = "tegra-gpio"; + tgi->gc.request = tegra_gpio_request; + tgi->gc.free = tegra_gpio_free; + tgi->gc.direction_input = tegra_gpio_direction_input; + tgi->gc.get = tegra_gpio_get; + tgi->gc.direction_output = tegra_gpio_direction_output; + tgi->gc.set = tegra_gpio_set; + tgi->gc.get_direction = tegra_gpio_get_direction; + tgi->gc.to_irq = tegra_gpio_to_irq; + tgi->gc.base = 0; + tgi->gc.ngpio = tgi->bank_count * 32; + tgi->gc.parent = &pdev->dev; + tgi->gc.of_node = pdev->dev.of_node; + + tgi->ic.name = "GPIO"; + tgi->ic.irq_ack = tegra_gpio_irq_ack; + tgi->ic.irq_mask = tegra_gpio_irq_mask; + tgi->ic.irq_unmask = tegra_gpio_irq_unmask; + tgi->ic.irq_set_type = tegra_gpio_irq_set_type; + tgi->ic.irq_shutdown = tegra_gpio_irq_shutdown; +#ifdef CONFIG_PM_SLEEP + tgi->ic.irq_set_wake = tegra_gpio_irq_set_wake; +#endif + + platform_set_drvdata(pdev, tgi); + + if (config->debounce_supported) + tgi->gc.set_debounce = tegra_gpio_set_debounce; - tegra_gpio_banks = devm_kzalloc(&pdev->dev, - tegra_gpio_bank_count * sizeof(*tegra_gpio_banks), - GFP_KERNEL); - if (!tegra_gpio_banks) + tgi->bank_info = devm_kzalloc(&pdev->dev, tgi->bank_count * + sizeof(*tgi->bank_info), GFP_KERNEL); + if (!tgi->bank_info) return -ENODEV; - irq_domain = irq_domain_add_linear(pdev->dev.of_node, - tegra_gpio_chip.ngpio, - &irq_domain_simple_ops, NULL); - if (!irq_domain) + tgi->irq_domain = irq_domain_add_linear(pdev->dev.of_node, + tgi->gc.ngpio, + &irq_domain_simple_ops, NULL); + if (!tgi->irq_domain) return -ENODEV; - for (i = 0; i < tegra_gpio_bank_count; i++) { + for (i = 0; i < tgi->bank_count; i++) { res = platform_get_resource(pdev, IORESOURCE_IRQ, i); if (!res) { dev_err(&pdev->dev, "Missing IRQ resource\n"); return -ENODEV; } - bank = &tegra_gpio_banks[i]; + bank = &tgi->bank_info[i]; bank->bank = i; bank->irq = res->start; + bank->tgi = tgi; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(regs)) - return PTR_ERR(regs); + tgi->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(tgi->regs)) + return PTR_ERR(tgi->regs); - for (i = 0; i < tegra_gpio_bank_count; i++) { + for (i = 0; i < tgi->bank_count; i++) { for (j = 0; j < 4; j++) { int gpio = tegra_gpio_compose(i, j, 0); - tegra_gpio_writel(0x00, GPIO_INT_ENB(gpio)); + tegra_gpio_writel(tgi, 0x00, GPIO_INT_ENB(tgi, gpio)); } } - tegra_gpio_chip.of_node = pdev->dev.of_node; - - ret = devm_gpiochip_add_data(&pdev->dev, &tegra_gpio_chip, NULL); + ret = devm_gpiochip_add_data(&pdev->dev, &tgi->gc, tgi); if (ret < 0) { - irq_domain_remove(irq_domain); + irq_domain_remove(tgi->irq_domain); return ret; } - for (gpio = 0; gpio < tegra_gpio_chip.ngpio; gpio++) { - int irq = irq_create_mapping(irq_domain, gpio); + for (gpio = 0; gpio < tgi->gc.ngpio; gpio++) { + int irq = irq_create_mapping(tgi->irq_domain, gpio); /* No validity check; all Tegra GPIOs are valid IRQs */ - bank = &tegra_gpio_banks[GPIO_BANK(gpio)]; + bank = &tgi->bank_info[GPIO_BANK(gpio)]; - irq_set_lockdep_class(irq, &gpio_lock_class); + irq_set_lockdep_class(irq, &tgi->lock_class); irq_set_chip_data(irq, bank); - irq_set_chip_and_handler(irq, &tegra_gpio_irq_chip, - handle_simple_irq); + irq_set_chip_and_handler(irq, &tgi->ic, handle_simple_irq); } - for (i = 0; i < tegra_gpio_bank_count; i++) { - bank = &tegra_gpio_banks[i]; + for (i = 0; i < tgi->bank_count; i++) { + bank = &tgi->bank_info[i]; irq_set_chained_handler_and_data(bank->irq, tegra_gpio_irq_handler, bank); - for (j = 0; j < 4; j++) + for (j = 0; j < 4; j++) { spin_lock_init(&bank->lvl_lock[j]); + spin_lock_init(&bank->dbc_lock[j]); + } } - tegra_gpio_debuginit(); + tegra_gpio_debuginit(tgi); return 0; } +static const struct tegra_gpio_soc_config tegra20_gpio_config = { + .bank_stride = 0x80, + .upper_offset = 0x800, +}; + +static const struct tegra_gpio_soc_config tegra30_gpio_config = { + .bank_stride = 0x100, + .upper_offset = 0x80, +}; + +static const struct tegra_gpio_soc_config tegra210_gpio_config = { + .debounce_supported = true, + .bank_stride = 0x100, + .upper_offset = 0x80, +}; + +static const struct of_device_id tegra_gpio_of_match[] = { + { .compatible = "nvidia,tegra210-gpio", .data = &tegra210_gpio_config }, + { .compatible = "nvidia,tegra30-gpio", .data = &tegra30_gpio_config }, + { .compatible = "nvidia,tegra20-gpio", .data = &tegra20_gpio_config }, + { }, +}; + static struct platform_driver tegra_gpio_driver = { .driver = { .name = "tegra-gpio", diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index 85ed608..181f86c 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/gpio-timberdale.c @@ -1,5 +1,6 @@ /* * Timberdale FPGA GPIO driver + * Author: Mocean Laboratories * Copyright (c) 2009 Intel Corporation * * This program is free software; you can redistribute it and/or modify @@ -20,7 +21,7 @@ * Timberdale FPGA GPIO */ -#include <linux/module.h> +#include <linux/init.h> #include <linux/gpio.h> #include <linux/platform_device.h> #include <linux/irq.h> @@ -290,40 +291,14 @@ static int timbgpio_probe(struct platform_device *pdev) return 0; } -static int timbgpio_remove(struct platform_device *pdev) -{ - struct timbgpio_platform_data *pdata = dev_get_platdata(&pdev->dev); - struct timbgpio *tgpio = platform_get_drvdata(pdev); - int irq = platform_get_irq(pdev, 0); - - if (irq >= 0 && tgpio->irq_base > 0) { - int i; - for (i = 0; i < pdata->nr_pins; i++) { - irq_set_chip(tgpio->irq_base + i, NULL); - irq_set_chip_data(tgpio->irq_base + i, NULL); - } - - irq_set_handler(irq, NULL); - irq_set_handler_data(irq, NULL); - } - - return 0; -} - static struct platform_driver timbgpio_platform_driver = { .driver = { - .name = DRIVER_NAME, + .name = DRIVER_NAME, + .suppress_bind_attrs = true, }, .probe = timbgpio_probe, - .remove = timbgpio_remove, }; /*--------------------------------------------------------------------------*/ -module_platform_driver(timbgpio_platform_driver); - -MODULE_DESCRIPTION("Timberdale GPIO driver"); -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Mocean Laboratories"); -MODULE_ALIAS("platform:"DRIVER_NAME); - +builtin_platform_driver(timbgpio_platform_driver); diff --git a/drivers/gpio/gpio-tpic2810.c b/drivers/gpio/gpio-tpic2810.c index 9f020aa..cace79c 100644 --- a/drivers/gpio/gpio-tpic2810.c +++ b/drivers/gpio/gpio-tpic2810.c @@ -57,39 +57,34 @@ static int tpic2810_direction_output(struct gpio_chip *chip, return 0; } -static void tpic2810_set(struct gpio_chip *chip, unsigned offset, int value) +static void tpic2810_set_mask_bits(struct gpio_chip *chip, u8 mask, u8 bits) { struct tpic2810 *gpio = gpiochip_get_data(chip); + u8 buffer; + int err; mutex_lock(&gpio->lock); - if (value) - gpio->buffer |= BIT(offset); - else - gpio->buffer &= ~BIT(offset); + buffer = gpio->buffer & ~mask; + buffer |= (mask & bits); - i2c_smbus_write_byte_data(gpio->client, TPIC2810_WS_COMMAND, - gpio->buffer); + err = i2c_smbus_write_byte_data(gpio->client, TPIC2810_WS_COMMAND, + buffer); + if (!err) + gpio->buffer = buffer; mutex_unlock(&gpio->lock); } +static void tpic2810_set(struct gpio_chip *chip, unsigned offset, int value) +{ + tpic2810_set_mask_bits(chip, BIT(offset), value ? BIT(offset) : 0); +} + static void tpic2810_set_multiple(struct gpio_chip *chip, unsigned long *mask, unsigned long *bits) { - struct tpic2810 *gpio = gpiochip_get_data(chip); - - mutex_lock(&gpio->lock); - - /* clear bits under mask */ - gpio->buffer &= ~(*mask); - /* set bits under mask */ - gpio->buffer |= ((*mask) & (*bits)); - - i2c_smbus_write_byte_data(gpio->client, TPIC2810_WS_COMMAND, - gpio->buffer); - - mutex_unlock(&gpio->lock); + tpic2810_set_mask_bits(chip, *mask, *bits); } static struct gpio_chip template_chip = { diff --git a/drivers/gpio/gpio-tps65218.c b/drivers/gpio/gpio-tps65218.c index 313c0e4..0eaeac8 100644 --- a/drivers/gpio/gpio-tps65218.c +++ b/drivers/gpio/gpio-tps65218.c @@ -101,16 +101,6 @@ static int tps65218_gpio_request(struct gpio_chip *gc, unsigned offset) break; case 1: - /* GP02 is push-pull by default, can be set as open drain. */ - if (gpiochip_line_is_open_drain(gc, offset)) { - ret = tps65218_clear_bits(tps65218, - TPS65218_REG_CONFIG1, - TPS65218_CONFIG1_GPO2_BUF, - TPS65218_PROTECT_L1); - if (ret) - return ret; - } - /* Setup GPO2 */ ret = tps65218_clear_bits(tps65218, TPS65218_REG_CONFIG1, TPS65218_CONFIG1_IO1_SEL, @@ -148,6 +138,40 @@ static int tps65218_gpio_request(struct gpio_chip *gc, unsigned offset) return 0; } +static int tps65218_gpio_set_single_ended(struct gpio_chip *gc, + unsigned offset, + enum single_ended_mode mode) +{ + struct tps65218_gpio *tps65218_gpio = gpiochip_get_data(gc); + struct tps65218 *tps65218 = tps65218_gpio->tps65218; + + switch (offset) { + case 0: + case 2: + /* GPO1 is hardwired to be open drain */ + if (mode == LINE_MODE_OPEN_DRAIN) + return 0; + return -ENOTSUPP; + case 1: + /* GPO2 is push-pull by default, can be set as open drain. */ + if (mode == LINE_MODE_OPEN_DRAIN) + return tps65218_clear_bits(tps65218, + TPS65218_REG_CONFIG1, + TPS65218_CONFIG1_GPO2_BUF, + TPS65218_PROTECT_L1); + if (mode == LINE_MODE_PUSH_PULL) + return tps65218_set_bits(tps65218, + TPS65218_REG_CONFIG1, + TPS65218_CONFIG1_GPO2_BUF, + TPS65218_CONFIG1_GPO2_BUF, + TPS65218_PROTECT_L1); + return -ENOTSUPP; + default: + break; + } + return -ENOTSUPP; +} + static struct gpio_chip template_chip = { .label = "gpio-tps65218", .owner = THIS_MODULE, @@ -156,6 +180,7 @@ static struct gpio_chip template_chip = { .direction_input = tps65218_gpio_input, .get = tps65218_gpio_get, .set = tps65218_gpio_set, + .set_single_ended = tps65218_gpio_set_single_ended, .can_sleep = true, .ngpio = 3, .base = -1, diff --git a/drivers/gpio/gpio-tps6586x.c b/drivers/gpio/gpio-tps6586x.c index c88bdc8..6b15e68 100644 --- a/drivers/gpio/gpio-tps6586x.c +++ b/drivers/gpio/gpio-tps6586x.c @@ -24,7 +24,7 @@ #include <linux/errno.h> #include <linux/gpio.h> #include <linux/kernel.h> -#include <linux/module.h> +#include <linux/init.h> #include <linux/mfd/tps6586x.h> #include <linux/of_device.h> #include <linux/platform_device.h> @@ -140,14 +140,3 @@ static int __init tps6586x_gpio_init(void) return platform_driver_register(&tps6586x_gpio_driver); } subsys_initcall(tps6586x_gpio_init); - -static void __exit tps6586x_gpio_exit(void) -{ - platform_driver_unregister(&tps6586x_gpio_driver); -} -module_exit(tps6586x_gpio_exit); - -MODULE_ALIAS("platform:tps6586x-gpio"); -MODULE_DESCRIPTION("GPIO interface for TPS6586X PMIC"); -MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c index cdbd7c7..0ae6a5a 100644 --- a/drivers/gpio/gpio-tps65910.c +++ b/drivers/gpio/gpio-tps65910.c @@ -4,7 +4,7 @@ * Copyright 2010 Texas Instruments Inc. * * Author: Graeme Gregory <gg@slimlogic.co.uk> - * Author: Jorge Eduardo Candelaria jedu@slimlogic.co.uk> + * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -14,7 +14,7 @@ */ #include <linux/kernel.h> -#include <linux/module.h> +#include <linux/init.h> #include <linux/errno.h> #include <linux/gpio.h> #include <linux/i2c.h> @@ -193,15 +193,3 @@ static int __init tps65910_gpio_init(void) return platform_driver_register(&tps65910_gpio_driver); } subsys_initcall(tps65910_gpio_init); - -static void __exit tps65910_gpio_exit(void) -{ - platform_driver_unregister(&tps65910_gpio_driver); -} -module_exit(tps65910_gpio_exit); - -MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>"); -MODULE_AUTHOR("Jorge Eduardo Candelaria jedu@slimlogic.co.uk>"); -MODULE_DESCRIPTION("GPIO interface for TPS65910/TPS6511 PMICs"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:tps65910-gpio"); diff --git a/drivers/gpio/gpio-vx855.c b/drivers/gpio/gpio-vx855.c index 8cdb9f7..4e45012 100644 --- a/drivers/gpio/gpio-vx855.c +++ b/drivers/gpio/gpio-vx855.c @@ -186,6 +186,28 @@ static int vx855gpio_direction_output(struct gpio_chip *gpio, return 0; } +static int vx855gpio_set_single_ended(struct gpio_chip *gpio, + unsigned int nr, + enum single_ended_mode mode) +{ + /* The GPI cannot be single-ended */ + if (nr < NR_VX855_GPI) + return -EINVAL; + + /* The GPO's are push-pull */ + if (nr < NR_VX855_GPInO) { + if (mode != LINE_MODE_PUSH_PULL) + return -ENOTSUPP; + return 0; + } + + /* The GPIO's are open drain */ + if (mode != LINE_MODE_OPEN_DRAIN) + return -ENOTSUPP; + + return 0; +} + static const char *vx855gpio_names[NR_VX855_GP] = { "VX855_GPI0", "VX855_GPI1", "VX855_GPI2", "VX855_GPI3", "VX855_GPI4", "VX855_GPI5", "VX855_GPI6", "VX855_GPI7", "VX855_GPI8", "VX855_GPI9", @@ -209,6 +231,7 @@ static void vx855gpio_gpio_setup(struct vx855_gpio *vg) c->direction_output = vx855gpio_direction_output; c->get = vx855gpio_get; c->set = vx855gpio_set; + c->set_single_ended = vx855gpio_set_single_ended; c->dbg_show = NULL; c->base = 0; c->ngpio = NR_VX855_GP; diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c index 18cb0f5..41ec783 100644 --- a/drivers/gpio/gpio-wm831x.c +++ b/drivers/gpio/gpio-wm831x.c @@ -132,6 +132,28 @@ static int wm831x_gpio_set_debounce(struct gpio_chip *chip, unsigned offset, return wm831x_set_bits(wm831x, reg, WM831X_GPN_FN_MASK, fn); } +static int wm831x_set_single_ended(struct gpio_chip *chip, + unsigned int offset, + enum single_ended_mode mode) +{ + struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip); + struct wm831x *wm831x = wm831x_gpio->wm831x; + int reg = WM831X_GPIO1_CONTROL + offset; + + switch (mode) { + case LINE_MODE_OPEN_DRAIN: + return wm831x_set_bits(wm831x, reg, + WM831X_GPN_OD_MASK, WM831X_GPN_OD); + case LINE_MODE_PUSH_PULL: + return wm831x_set_bits(wm831x, reg, + WM831X_GPN_OD_MASK, 0); + default: + break; + } + + return -ENOTSUPP; +} + #ifdef CONFIG_DEBUG_FS static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) { @@ -216,7 +238,7 @@ static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) pull, powerdomain, reg & WM831X_GPN_POL ? "" : " inverted", - reg & WM831X_GPN_OD ? "open-drain" : "CMOS", + reg & WM831X_GPN_OD ? "open-drain" : "push-pull", tristated ? " tristated" : "", reg); } @@ -234,6 +256,7 @@ static struct gpio_chip template_chip = { .set = wm831x_gpio_set, .to_irq = wm831x_gpio_to_irq, .set_debounce = wm831x_gpio_set_debounce, + .set_single_ended = wm831x_set_single_ended, .dbg_show = wm831x_gpio_dbg_show, .can_sleep = true, }; diff --git a/drivers/gpio/gpio-wm8994.c b/drivers/gpio/gpio-wm8994.c index b089df9..744af38 100644 --- a/drivers/gpio/gpio-wm8994.c +++ b/drivers/gpio/gpio-wm8994.c @@ -103,6 +103,28 @@ static void wm8994_gpio_set(struct gpio_chip *chip, unsigned offset, int value) wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset, WM8994_GPN_LVL, value); } +static int wm8994_gpio_set_single_ended(struct gpio_chip *chip, + unsigned int offset, + enum single_ended_mode mode) +{ + struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip); + struct wm8994 *wm8994 = wm8994_gpio->wm8994; + + switch (mode) { + case LINE_MODE_OPEN_DRAIN: + return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset, + WM8994_GPN_OP_CFG_MASK, + WM8994_GPN_OP_CFG); + case LINE_MODE_PUSH_PULL: + return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset, + WM8994_GPN_OP_CFG_MASK, 0); + default: + break; + } + + return -ENOTSUPP; +} + static int wm8994_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip); @@ -217,7 +239,7 @@ static void wm8994_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) if (reg & WM8994_GPN_OP_CFG) seq_printf(s, "open drain "); else - seq_printf(s, "CMOS "); + seq_printf(s, "push-pull "); seq_printf(s, "%s (%x)\n", wm8994_gpio_fn(reg & WM8994_GPN_FN_MASK), reg); @@ -235,6 +257,7 @@ static struct gpio_chip template_chip = { .get = wm8994_gpio_get, .direction_output = wm8994_gpio_direction_out, .set = wm8994_gpio_set, + .set_single_ended = wm8994_gpio_set_single_ended, .to_irq = wm8994_gpio_to_irq, .dbg_show = wm8994_gpio_dbg_show, .can_sleep = true, diff --git a/drivers/gpio/gpio-xgene-sb.c b/drivers/gpio/gpio-xgene-sb.c index 31cbcb8..0332586 100644 --- a/drivers/gpio/gpio-xgene-sb.c +++ b/drivers/gpio/gpio-xgene-sb.c @@ -216,23 +216,10 @@ static int xgene_gpio_sb_domain_alloc(struct irq_domain *domain, &parent_fwspec); } -static void xgene_gpio_sb_domain_free(struct irq_domain *domain, - unsigned int virq, - unsigned int nr_irqs) -{ - struct irq_data *d; - unsigned int i; - - for (i = 0; i < nr_irqs; i++) { - d = irq_domain_get_irq_data(domain, virq + i); - irq_domain_reset_irq_data(d); - } -} - static const struct irq_domain_ops xgene_gpio_sb_domain_ops = { .translate = xgene_gpio_sb_domain_translate, .alloc = xgene_gpio_sb_domain_alloc, - .free = xgene_gpio_sb_domain_free, + .free = irq_domain_free_irqs_common, .activate = xgene_gpio_sb_domain_activate, .deactivate = xgene_gpio_sb_domain_deactivate, }; diff --git a/drivers/gpio/gpio-xgene.c b/drivers/gpio/gpio-xgene.c index 0dc9161916..40a8881 100644 --- a/drivers/gpio/gpio-xgene.c +++ b/drivers/gpio/gpio-xgene.c @@ -17,7 +17,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <linux/module.h> +#include <linux/acpi.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/io.h> @@ -85,6 +85,17 @@ static void xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val) spin_unlock_irqrestore(&chip->lock, flags); } +static int xgene_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) +{ + struct xgene_gpio *chip = gpiochip_get_data(gc); + unsigned long bank_offset, bit_offset; + + bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset); + bit_offset = GPIO_BIT_OFFSET(offset); + + return !!(ioread32(chip->base + bank_offset) & BIT(bit_offset)); +} + static int xgene_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) { struct xgene_gpio *chip = gpiochip_get_data(gc); @@ -189,6 +200,7 @@ static int xgene_gpio_probe(struct platform_device *pdev) spin_lock_init(&gpio->lock); gpio->chip.parent = &pdev->dev; + gpio->chip.get_direction = xgene_gpio_get_direction; gpio->chip.direction_input = xgene_gpio_dir_in; gpio->chip.direction_output = xgene_gpio_dir_out; gpio->chip.get = xgene_gpio_get; @@ -216,19 +228,21 @@ static const struct of_device_id xgene_gpio_of_match[] = { { .compatible = "apm,xgene-gpio", }, {}, }; -MODULE_DEVICE_TABLE(of, xgene_gpio_of_match); + +#ifdef CONFIG_ACPI +static const struct acpi_device_id xgene_gpio_acpi_match[] = { + { "APMC0D14", 0 }, + { }, +}; +#endif static struct platform_driver xgene_gpio_driver = { .driver = { .name = "xgene-gpio", .of_match_table = xgene_gpio_of_match, + .acpi_match_table = ACPI_PTR(xgene_gpio_acpi_match), .pm = XGENE_GPIO_PM_OPS, }, .probe = xgene_gpio_probe, }; - -module_platform_driver(xgene_gpio_driver); - -MODULE_AUTHOR("Feng Kan <fkan@apm.com>"); -MODULE_DESCRIPTION("APM X-Gene GPIO driver"); -MODULE_LICENSE("GPL"); +builtin_platform_driver(xgene_gpio_driver); diff --git a/drivers/gpio/gpio-xlp.c b/drivers/gpio/gpio-xlp.c index aa5813d..08897dc 100644 --- a/drivers/gpio/gpio-xlp.c +++ b/drivers/gpio/gpio-xlp.c @@ -85,7 +85,8 @@ enum { XLP_GPIO_VARIANT_XLP316, XLP_GPIO_VARIANT_XLP208, XLP_GPIO_VARIANT_XLP980, - XLP_GPIO_VARIANT_XLP532 + XLP_GPIO_VARIANT_XLP532, + GPIO_VARIANT_VULCAN }; struct xlp_gpio_priv { @@ -285,6 +286,10 @@ static const struct of_device_id xlp_gpio_of_ids[] = { .compatible = "netlogic,xlp532-gpio", .data = (void *)XLP_GPIO_VARIANT_XLP532, }, + { + .compatible = "brcm,vulcan-gpio", + .data = (void *)GPIO_VARIANT_VULCAN, + }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, xlp_gpio_of_ids); @@ -347,6 +352,7 @@ static int xlp_gpio_probe(struct platform_device *pdev) break; case XLP_GPIO_VARIANT_XLP980: case XLP_GPIO_VARIANT_XLP532: + case GPIO_VARIANT_VULCAN: priv->gpio_out_en = gpio_base + GPIO_9XX_OUTPUT_EN; priv->gpio_paddrv = gpio_base + GPIO_9XX_PADDRV; priv->gpio_intr_stat = gpio_base + GPIO_9XX_INT_STAT; @@ -354,7 +360,12 @@ static int xlp_gpio_probe(struct platform_device *pdev) priv->gpio_intr_pol = gpio_base + GPIO_9XX_INT_POL; priv->gpio_intr_en = gpio_base + GPIO_9XX_INT_EN00; - ngpio = (soc_type == XLP_GPIO_VARIANT_XLP980) ? 66 : 67; + if (soc_type == XLP_GPIO_VARIANT_XLP980) + ngpio = 66; + else if (soc_type == XLP_GPIO_VARIANT_XLP532) + ngpio = 67; + else + ngpio = 70; break; default: dev_err(&pdev->dev, "Unknown Processor type!\n"); @@ -377,10 +388,14 @@ static int xlp_gpio_probe(struct platform_device *pdev) gc->get = xlp_gpio_get; spin_lock_init(&priv->lock); - irq_base = irq_alloc_descs(-1, XLP_GPIO_IRQ_BASE, gc->ngpio, 0); - if (irq_base < 0) { + /* XLP has fixed IRQ range for GPIO interrupts */ + if (soc_type == GPIO_VARIANT_VULCAN) + irq_base = irq_alloc_descs(-1, 0, gc->ngpio, 0); + else + irq_base = irq_alloc_descs(-1, XLP_GPIO_IRQ_BASE, gc->ngpio, 0); + if (IS_ERR_VALUE(irq_base)) { dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n"); - return -ENODEV; + return irq_base; } err = gpiochip_add_data(gc, priv); diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c index cda6d92..e23ef7b 100644 --- a/drivers/gpio/gpio-zevio.c +++ b/drivers/gpio/gpio-zevio.c @@ -10,7 +10,7 @@ #include <linux/spinlock.h> #include <linux/errno.h> -#include <linux/module.h> +#include <linux/init.h> #include <linux/bitops.h> #include <linux/io.h> #include <linux/of_device.h> @@ -203,32 +203,17 @@ static int zevio_gpio_probe(struct platform_device *pdev) return 0; } -static int zevio_gpio_remove(struct platform_device *pdev) -{ - struct zevio_gpio *controller = platform_get_drvdata(pdev); - - of_mm_gpiochip_remove(&controller->chip); - - return 0; -} - static const struct of_device_id zevio_gpio_of_match[] = { { .compatible = "lsi,zevio-gpio", }, { }, }; -MODULE_DEVICE_TABLE(of, zevio_gpio_of_match); - static struct platform_driver zevio_gpio_driver = { .driver = { .name = "gpio-zevio", .of_match_table = zevio_gpio_of_match, + .suppress_bind_attrs = true, }, .probe = zevio_gpio_probe, - .remove = zevio_gpio_remove, }; -module_platform_driver(zevio_gpio_driver); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Fabian Vogt <fabian@ritter-vogt.de>"); -MODULE_DESCRIPTION("LSI ZEVIO SoC GPIO driver"); +builtin_platform_driver(zevio_gpio_driver); diff --git a/drivers/gpio/gpio-zx.c b/drivers/gpio/gpio-zx.c index 47c79fa..93de8be 100644 --- a/drivers/gpio/gpio-zx.c +++ b/drivers/gpio/gpio-zx.c @@ -1,4 +1,8 @@ /* + * ZTE ZX296702 GPIO driver + * + * Author: Jun Nie <jun.nie@linaro.org> + * * Copyright (C) 2015 Linaro Ltd. * * This program is free software; you can redistribute it and/or modify @@ -10,7 +14,7 @@ #include <linux/errno.h> #include <linux/gpio/driver.h> #include <linux/irqchip/chained_irq.h> -#include <linux/module.h> +#include <linux/init.h> #include <linux/of.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> @@ -282,7 +286,6 @@ static const struct of_device_id zx_gpio_match[] = { }, { }, }; -MODULE_DEVICE_TABLE(of, zx_gpio_match); static struct platform_driver zx_gpio_driver = { .probe = zx_gpio_probe, @@ -291,9 +294,4 @@ static struct platform_driver zx_gpio_driver = { .of_match_table = of_match_ptr(zx_gpio_match), }, }; - -module_platform_driver(zx_gpio_driver) - -MODULE_AUTHOR("Jun Nie <jun.nie@linaro.org>"); -MODULE_DESCRIPTION("ZTE ZX296702 GPIO driver"); -MODULE_LICENSE("GPL"); +builtin_platform_driver(zx_gpio_driver) diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c index 66d3d24..75c6355 100644 --- a/drivers/gpio/gpio-zynq.c +++ b/drivers/gpio/gpio-zynq.c @@ -713,7 +713,7 @@ static int zynq_gpio_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); ret = pm_runtime_get_sync(&pdev->dev); if (ret < 0) - return ret; + goto err_pm_dis; /* report a bug if gpio chip registration fails */ ret = gpiochip_add_data(chip, gpio); @@ -745,6 +745,8 @@ err_rm_gpiochip: gpiochip_remove(chip); err_pm_put: pm_runtime_put(&pdev->dev); +err_pm_dis: + pm_runtime_disable(&pdev->dev); return ret; } diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 42a4bb7..d22dcc3 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -196,21 +196,68 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np, } /** + * of_gpiochip_set_names() - set up the names of the lines + * @chip: GPIO chip whose lines should be named, if possible + */ +static void of_gpiochip_set_names(struct gpio_chip *gc) +{ + struct gpio_device *gdev = gc->gpiodev; + struct device_node *np = gc->of_node; + int i; + int nstrings; + + nstrings = of_property_count_strings(np, "gpio-line-names"); + if (nstrings <= 0) + /* Lines names not present */ + return; + + /* This is normally not what you want */ + if (gdev->ngpio != nstrings) + dev_info(&gdev->dev, "gpio-line-names specifies %d line " + "names but there are %d lines on the chip\n", + nstrings, gdev->ngpio); + + /* + * Make sure to not index beyond the end of the number of descriptors + * of the GPIO device. + */ + for (i = 0; i < gdev->ngpio; i++) { + const char *name; + int ret; + + ret = of_property_read_string_index(np, + "gpio-line-names", + i, + &name); + if (ret) { + if (ret != -ENODATA) + dev_err(&gdev->dev, + "unable to name line %d: %d\n", + i, ret); + break; + } + gdev->descs[i].name = name; + } +} + +/** * of_gpiochip_scan_gpios - Scan gpio-controller for gpio definitions * @chip: gpio chip to act on * * This is only used by of_gpiochip_add to request/set GPIO initial * configuration. + * It retures error if it fails otherwise 0 on success. */ -static void of_gpiochip_scan_gpios(struct gpio_chip *chip) +static int of_gpiochip_scan_gpios(struct gpio_chip *chip) { struct gpio_desc *desc = NULL; struct device_node *np; const char *name; enum gpio_lookup_flags lflags; enum gpiod_flags dflags; + int ret; - for_each_child_of_node(chip->of_node, np) { + for_each_available_child_of_node(chip->of_node, np) { if (!of_property_read_bool(np, "gpio-hog")) continue; @@ -218,9 +265,12 @@ static void of_gpiochip_scan_gpios(struct gpio_chip *chip) if (IS_ERR(desc)) continue; - if (gpiod_hog(desc, name, lflags, dflags)) - continue; + ret = gpiod_hog(desc, name, lflags, dflags); + if (ret < 0) + return ret; } + + return 0; } /** @@ -440,11 +490,13 @@ int of_gpiochip_add(struct gpio_chip *chip) if (status) return status; - of_node_get(chip->of_node); + /* If the chip defines names itself, these take precedence */ + if (!chip->names) + of_gpiochip_set_names(chip); - of_gpiochip_scan_gpios(chip); + of_node_get(chip->of_node); - return 0; + return of_gpiochip_scan_gpios(chip); } void of_gpiochip_remove(struct gpio_chip *chip) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index b747c76..d407f904 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -622,14 +622,31 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data) struct gpio_desc *desc = &gdev->descs[i]; desc->gdev = gdev; - - /* REVISIT: most hardware initializes GPIOs as inputs (often - * with pullups enabled) so power usage is minimized. Linux - * code should set the gpio direction first thing; but until - * it does, and in case chip->get_direction is not set, we may - * expose the wrong direction in sysfs. + /* + * REVISIT: most hardware initializes GPIOs as inputs + * (often with pullups enabled) so power usage is + * minimized. Linux code should set the gpio direction + * first thing; but until it does, and in case + * chip->get_direction is not set, we may expose the + * wrong direction in sysfs. */ - desc->flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0; + + if (chip->get_direction) { + /* + * If we have .get_direction, set up the initial + * direction flag from the hardware. + */ + int dir = chip->get_direction(chip, i); + + if (!dir) + set_bit(FLAG_IS_OUT, &desc->flags); + } else if (!chip->direction_input) { + /* + * If the chip lacks the .direction_input callback + * we logically assume all lines are outputs. + */ + set_bit(FLAG_IS_OUT, &desc->flags); + } } spin_unlock_irqrestore(&gpio_lock, flags); @@ -1547,8 +1564,8 @@ EXPORT_SYMBOL_GPL(gpiod_direction_input); static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value) { - struct gpio_chip *chip; - int status = -EINVAL; + struct gpio_chip *gc = desc->gdev->chip; + int ret; /* GPIOs used for IRQs shall not be set as output */ if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) { @@ -1558,28 +1575,50 @@ static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value) return -EIO; } - /* Open drain pin should not be driven to 1 */ - if (value && test_bit(FLAG_OPEN_DRAIN, &desc->flags)) - return gpiod_direction_input(desc); - - /* Open source pin should not be driven to 0 */ - if (!value && test_bit(FLAG_OPEN_SOURCE, &desc->flags)) - return gpiod_direction_input(desc); + if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) { + /* First see if we can enable open drain in hardware */ + if (gc->set_single_ended) { + ret = gc->set_single_ended(gc, gpio_chip_hwgpio(desc), + LINE_MODE_OPEN_DRAIN); + if (!ret) + goto set_output_value; + } + /* Emulate open drain by not actively driving the line high */ + if (value) + return gpiod_direction_input(desc); + } + else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) { + if (gc->set_single_ended) { + ret = gc->set_single_ended(gc, gpio_chip_hwgpio(desc), + LINE_MODE_OPEN_SOURCE); + if (!ret) + goto set_output_value; + } + /* Emulate open source by not actively driving the line low */ + if (!value) + return gpiod_direction_input(desc); + } else { + /* Make sure to disable open drain/source hardware, if any */ + if (gc->set_single_ended) + gc->set_single_ended(gc, + gpio_chip_hwgpio(desc), + LINE_MODE_PUSH_PULL); + } - chip = desc->gdev->chip; - if (!chip->set || !chip->direction_output) { +set_output_value: + if (!gc->set || !gc->direction_output) { gpiod_warn(desc, "%s: missing set() or direction_output() operations\n", __func__); return -EIO; } - status = chip->direction_output(chip, gpio_chip_hwgpio(desc), value); - if (status == 0) + ret = gc->direction_output(gc, gpio_chip_hwgpio(desc), value); + if (!ret) set_bit(FLAG_IS_OUT, &desc->flags); trace_gpio_value(desc_to_gpio(desc), 0, value); - trace_gpio_direction(desc_to_gpio(desc), 0, status); - return status; + trace_gpio_direction(desc_to_gpio(desc), 0, ret); + return ret; } /** @@ -1841,10 +1880,10 @@ static void gpio_chip_set_multiple(struct gpio_chip *chip, } } -static void gpiod_set_array_value_priv(bool raw, bool can_sleep, - unsigned int array_size, - struct gpio_desc **desc_array, - int *value_array) +void gpiod_set_array_value_complex(bool raw, bool can_sleep, + unsigned int array_size, + struct gpio_desc **desc_array, + int *value_array) { int i = 0; @@ -1950,8 +1989,8 @@ void gpiod_set_raw_array_value(unsigned int array_size, { if (!desc_array) return; - gpiod_set_array_value_priv(true, false, array_size, desc_array, - value_array); + gpiod_set_array_value_complex(true, false, array_size, desc_array, + value_array); } EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value); @@ -1972,8 +2011,8 @@ void gpiod_set_array_value(unsigned int array_size, { if (!desc_array) return; - gpiod_set_array_value_priv(false, false, array_size, desc_array, - value_array); + gpiod_set_array_value_complex(false, false, array_size, desc_array, + value_array); } EXPORT_SYMBOL_GPL(gpiod_set_array_value); @@ -1998,13 +2037,22 @@ EXPORT_SYMBOL_GPL(gpiod_cansleep); */ int gpiod_to_irq(const struct gpio_desc *desc) { - struct gpio_chip *chip; - int offset; + struct gpio_chip *chip; + int offset; VALIDATE_DESC(desc); chip = desc->gdev->chip; offset = gpio_chip_hwgpio(desc); - return chip->to_irq ? chip->to_irq(chip, offset) : -ENXIO; + if (chip->to_irq) { + int retirq = chip->to_irq(chip, offset); + + /* Zero means NO_IRQ */ + if (!retirq) + return -ENXIO; + + return retirq; + } + return -ENXIO; } EXPORT_SYMBOL_GPL(gpiod_to_irq); @@ -2176,8 +2224,8 @@ void gpiod_set_raw_array_value_cansleep(unsigned int array_size, might_sleep_if(extra_checks); if (!desc_array) return; - gpiod_set_array_value_priv(true, true, array_size, desc_array, - value_array); + gpiod_set_array_value_complex(true, true, array_size, desc_array, + value_array); } EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value_cansleep); @@ -2199,8 +2247,8 @@ void gpiod_set_array_value_cansleep(unsigned int array_size, might_sleep_if(extra_checks); if (!desc_array) return; - gpiod_set_array_value_priv(false, true, array_size, desc_array, - value_array); + gpiod_set_array_value_complex(false, true, array_size, desc_array, + value_array); } EXPORT_SYMBOL_GPL(gpiod_set_array_value_cansleep); @@ -2726,15 +2774,16 @@ int gpiod_hog(struct gpio_desc *desc, const char *name, local_desc = gpiochip_request_own_desc(chip, hwnum, name); if (IS_ERR(local_desc)) { - pr_err("requesting hog GPIO %s (chip %s, offset %d) failed\n", - name, chip->label, hwnum); - return PTR_ERR(local_desc); + status = PTR_ERR(local_desc); + pr_err("requesting hog GPIO %s (chip %s, offset %d) failed, %d\n", + name, chip->label, hwnum, status); + return status; } status = gpiod_configure_flags(desc, name, dflags); if (status < 0) { - pr_err("setup of hog GPIO %s (chip %s, offset %d) failed\n", - name, chip->label, hwnum); + pr_err("setup of hog GPIO %s (chip %s, offset %d) failed, %d\n", + name, chip->label, hwnum, status); gpiochip_free_own_desc(desc); return status; } diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index e30e5fd..2d9ea5e 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -141,6 +141,10 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, const char *list_name, int index, enum of_gpio_flags *flags); struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum); +void gpiod_set_array_value_complex(bool raw, bool can_sleep, + unsigned int array_size, + struct gpio_desc **desc_array, + int *value_array); extern struct spinlock gpio_lock; extern struct list_head gpio_devices; diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index 21a62d0..53fe9a3 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -73,7 +73,7 @@ static int adp5588_write(struct i2c_client *client, u8 reg, u8 val) #ifdef CONFIG_GPIOLIB static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off) { - struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc); + struct adp5588_kpad *kpad = gpiochip_get_data(chip); unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]); unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]); int val; @@ -93,7 +93,7 @@ static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off) static void adp5588_gpio_set_value(struct gpio_chip *chip, unsigned off, int val) { - struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc); + struct adp5588_kpad *kpad = gpiochip_get_data(chip); unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]); unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]); @@ -112,7 +112,7 @@ static void adp5588_gpio_set_value(struct gpio_chip *chip, static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned off) { - struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc); + struct adp5588_kpad *kpad = gpiochip_get_data(chip); unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]); unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]); int ret; @@ -130,7 +130,7 @@ static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned off) static int adp5588_gpio_direction_output(struct gpio_chip *chip, unsigned off, int val) { - struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc); + struct adp5588_kpad *kpad = gpiochip_get_data(chip); unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]); unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]); int ret; @@ -210,7 +210,7 @@ static int adp5588_gpio_add(struct adp5588_kpad *kpad) mutex_init(&kpad->gpio_lock); - error = gpiochip_add(&kpad->gc); + error = gpiochip_add_data(&kpad->gc, kpad); if (error) { dev_err(dev, "gpiochip_add failed, err: %d\n", error); return error; diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c index c01a1d6..32d94c6 100644 --- a/drivers/input/keyboard/adp5589-keys.c +++ b/drivers/input/keyboard/adp5589-keys.c @@ -387,7 +387,7 @@ static int adp5589_write(struct i2c_client *client, u8 reg, u8 val) #ifdef CONFIG_GPIOLIB static int adp5589_gpio_get_value(struct gpio_chip *chip, unsigned off) { - struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc); + struct adp5589_kpad *kpad = gpiochip_get_data(chip); unsigned int bank = kpad->var->bank(kpad->gpiomap[off]); unsigned int bit = kpad->var->bit(kpad->gpiomap[off]); @@ -399,7 +399,7 @@ static int adp5589_gpio_get_value(struct gpio_chip *chip, unsigned off) static void adp5589_gpio_set_value(struct gpio_chip *chip, unsigned off, int val) { - struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc); + struct adp5589_kpad *kpad = gpiochip_get_data(chip); unsigned int bank = kpad->var->bank(kpad->gpiomap[off]); unsigned int bit = kpad->var->bit(kpad->gpiomap[off]); @@ -418,7 +418,7 @@ static void adp5589_gpio_set_value(struct gpio_chip *chip, static int adp5589_gpio_direction_input(struct gpio_chip *chip, unsigned off) { - struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc); + struct adp5589_kpad *kpad = gpiochip_get_data(chip); unsigned int bank = kpad->var->bank(kpad->gpiomap[off]); unsigned int bit = kpad->var->bit(kpad->gpiomap[off]); int ret; @@ -438,7 +438,7 @@ static int adp5589_gpio_direction_input(struct gpio_chip *chip, unsigned off) static int adp5589_gpio_direction_output(struct gpio_chip *chip, unsigned off, int val) { - struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc); + struct adp5589_kpad *kpad = gpiochip_get_data(chip); unsigned int bank = kpad->var->bank(kpad->gpiomap[off]); unsigned int bit = kpad->var->bit(kpad->gpiomap[off]); int ret; @@ -525,9 +525,9 @@ static int adp5589_gpio_add(struct adp5589_kpad *kpad) mutex_init(&kpad->gpio_lock); - error = gpiochip_add(&kpad->gc); + error = gpiochip_add_data(&kpad->gc, kpad); if (error) { - dev_err(dev, "gpiochip_add failed, err: %d\n", error); + dev_err(dev, "gpiochip_add_data() failed, err: %d\n", error); return error; } diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index 69d299d..e4bf110 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -379,7 +379,7 @@ static const struct attribute_group ad7879_attr_group = { static int ad7879_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) { - struct ad7879 *ts = container_of(chip, struct ad7879, gc); + struct ad7879 *ts = gpiochip_get_data(chip); int err; mutex_lock(&ts->mutex); @@ -393,7 +393,7 @@ static int ad7879_gpio_direction_input(struct gpio_chip *chip, static int ad7879_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int level) { - struct ad7879 *ts = container_of(chip, struct ad7879, gc); + struct ad7879 *ts = gpiochip_get_data(chip); int err; mutex_lock(&ts->mutex); @@ -412,7 +412,7 @@ static int ad7879_gpio_direction_output(struct gpio_chip *chip, static int ad7879_gpio_get_value(struct gpio_chip *chip, unsigned gpio) { - struct ad7879 *ts = container_of(chip, struct ad7879, gc); + struct ad7879 *ts = gpiochip_get_data(chip); u16 val; mutex_lock(&ts->mutex); @@ -425,7 +425,7 @@ static int ad7879_gpio_get_value(struct gpio_chip *chip, unsigned gpio) static void ad7879_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value) { - struct ad7879 *ts = container_of(chip, struct ad7879, gc); + struct ad7879 *ts = gpiochip_get_data(chip); mutex_lock(&ts->mutex); if (value) @@ -456,7 +456,7 @@ static int ad7879_gpio_add(struct ad7879 *ts, ts->gc.owner = THIS_MODULE; ts->gc.parent = ts->dev; - ret = gpiochip_add(&ts->gc); + ret = gpiochip_add_data(&ts->gc, ts); if (ret) dev_err(ts->dev, "failed to register gpio %d\n", ts->gc.base); diff --git a/drivers/mfd/intel_quark_i2c_gpio.c b/drivers/mfd/intel_quark_i2c_gpio.c index bdc5e27..a24b35f 100644 --- a/drivers/mfd/intel_quark_i2c_gpio.c +++ b/drivers/mfd/intel_quark_i2c_gpio.c @@ -219,8 +219,7 @@ static int intel_quark_gpio_setup(struct pci_dev *pdev, struct mfd_cell *cell) return -ENOMEM; /* Set the properties for portA */ - pdata->properties->node = NULL; - pdata->properties->name = "intel-quark-x1000-gpio-portA"; + pdata->properties->fwnode = NULL; pdata->properties->idx = 0; pdata->properties->ngpio = INTEL_QUARK_MFD_NGPIO; pdata->properties->gpio_base = INTEL_QUARK_MFD_GPIO_BASE; diff --git a/drivers/pinctrl/sh-pfc/gpio.c b/drivers/pinctrl/sh-pfc/gpio.c index a6681b8..97dff6a 100644 --- a/drivers/pinctrl/sh-pfc/gpio.c +++ b/drivers/pinctrl/sh-pfc/gpio.c @@ -212,7 +212,7 @@ static int gpio_pin_to_irq(struct gpio_chip *gc, unsigned offset) } } - return -ENOSYS; + return 0; found: return pfc->irqs[i]; diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c index 0e73fd1..63b371d 100644 --- a/drivers/platform/x86/intel_pmic_gpio.c +++ b/drivers/platform/x86/intel_pmic_gpio.c @@ -30,7 +30,7 @@ #include <linux/ioport.h> #include <linux/init.h> #include <linux/io.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <asm/intel_scu_ipc.h> #include <linux/device.h> #include <linux/intel_pmic_gpio.h> @@ -174,7 +174,7 @@ static int pmic_irq_type(struct irq_data *data, unsigned type) static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { - struct pmic_gpio *pg = container_of(chip, struct pmic_gpio, chip); + struct pmic_gpio *pg = gpiochip_get_data(chip); return pg->irq_base + offset; } @@ -279,7 +279,7 @@ static int platform_pmic_gpio_probe(struct platform_device *pdev) mutex_init(&pg->buslock); pg->chip.parent = dev; - retval = gpiochip_add(&pg->chip); + retval = gpiochip_add_data(&pg->chip, pg); if (retval) { pr_err("Can not add pmic gpio chip\n"); goto err; diff --git a/drivers/soc/fsl/qe/gpio.c b/drivers/soc/fsl/qe/gpio.c index 6584571..333eb22 100644 --- a/drivers/soc/fsl/qe/gpio.c +++ b/drivers/soc/fsl/qe/gpio.c @@ -18,6 +18,8 @@ #include <linux/io.h> #include <linux/of.h> #include <linux/of_gpio.h> +#include <linux/gpio/driver.h> +/* FIXME: needed for gpio_to_chip() get rid of this */ #include <linux/gpio.h> #include <linux/slab.h> #include <linux/export.h> @@ -37,15 +39,9 @@ struct qe_gpio_chip { struct qe_pio_regs saved_regs; }; -static inline struct qe_gpio_chip * -to_qe_gpio_chip(struct of_mm_gpio_chip *mm_gc) -{ - return container_of(mm_gc, struct qe_gpio_chip, mm_gc); -} - static void qe_gpio_save_regs(struct of_mm_gpio_chip *mm_gc) { - struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc); + struct qe_gpio_chip *qe_gc = gpiochip_get_data(&mm_gc->gc); struct qe_pio_regs __iomem *regs = mm_gc->regs; qe_gc->cpdata = in_be32(®s->cpdata); @@ -69,7 +65,7 @@ static int qe_gpio_get(struct gpio_chip *gc, unsigned int gpio) static void qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc); + struct qe_gpio_chip *qe_gc = gpiochip_get_data(gc); struct qe_pio_regs __iomem *regs = mm_gc->regs; unsigned long flags; u32 pin_mask = 1 << (QE_PIO_PINS - 1 - gpio); @@ -89,7 +85,7 @@ static void qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) static int qe_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc); + struct qe_gpio_chip *qe_gc = gpiochip_get_data(gc); unsigned long flags; spin_lock_irqsave(&qe_gc->lock, flags); @@ -104,7 +100,7 @@ static int qe_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) static int qe_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc); + struct qe_gpio_chip *qe_gc = gpiochip_get_data(gc); unsigned long flags; qe_gpio_set(gc, gpio, val); @@ -165,7 +161,7 @@ struct qe_pin *qe_pin_request(struct device_node *np, int index) } mm_gc = to_of_mm_gpio_chip(gc); - qe_gc = to_qe_gpio_chip(mm_gc); + qe_gc = gpiochip_get_data(gc); spin_lock_irqsave(&qe_gc->lock, flags); @@ -302,7 +298,7 @@ static int __init qe_add_gpiochips(void) gc->get = qe_gpio_get; gc->set = qe_gpio_set; - ret = of_mm_gpiochip_add(np, mm_gc); + ret = of_mm_gpiochip_add_data(np, mm_gc, qe_gc); if (ret) goto err; continue; diff --git a/drivers/ssb/driver_gpio.c b/drivers/ssb/driver_gpio.c index f92e266..180e027 100644 --- a/drivers/ssb/driver_gpio.c +++ b/drivers/ssb/driver_gpio.c @@ -8,7 +8,7 @@ * Licensed under the GNU/GPL. See COPYING for details. */ -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/irqdomain.h> @@ -22,15 +22,10 @@ * Shared **************************************************/ -static struct ssb_bus *ssb_gpio_get_bus(struct gpio_chip *chip) -{ - return container_of(chip, struct ssb_bus, gpio); -} - #if IS_ENABLED(CONFIG_SSB_EMBEDDED) static int ssb_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) { - struct ssb_bus *bus = ssb_gpio_get_bus(chip); + struct ssb_bus *bus = gpiochip_get_data(chip); if (bus->bustype == SSB_BUSTYPE_SSB) return irq_find_mapping(bus->irq_domain, gpio); @@ -45,7 +40,7 @@ static int ssb_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) static int ssb_gpio_chipco_get_value(struct gpio_chip *chip, unsigned gpio) { - struct ssb_bus *bus = ssb_gpio_get_bus(chip); + struct ssb_bus *bus = gpiochip_get_data(chip); return !!ssb_chipco_gpio_in(&bus->chipco, 1 << gpio); } @@ -53,7 +48,7 @@ static int ssb_gpio_chipco_get_value(struct gpio_chip *chip, unsigned gpio) static void ssb_gpio_chipco_set_value(struct gpio_chip *chip, unsigned gpio, int value) { - struct ssb_bus *bus = ssb_gpio_get_bus(chip); + struct ssb_bus *bus = gpiochip_get_data(chip); ssb_chipco_gpio_out(&bus->chipco, 1 << gpio, value ? 1 << gpio : 0); } @@ -61,7 +56,7 @@ static void ssb_gpio_chipco_set_value(struct gpio_chip *chip, unsigned gpio, static int ssb_gpio_chipco_direction_input(struct gpio_chip *chip, unsigned gpio) { - struct ssb_bus *bus = ssb_gpio_get_bus(chip); + struct ssb_bus *bus = gpiochip_get_data(chip); ssb_chipco_gpio_outen(&bus->chipco, 1 << gpio, 0); return 0; @@ -70,7 +65,7 @@ static int ssb_gpio_chipco_direction_input(struct gpio_chip *chip, static int ssb_gpio_chipco_direction_output(struct gpio_chip *chip, unsigned gpio, int value) { - struct ssb_bus *bus = ssb_gpio_get_bus(chip); + struct ssb_bus *bus = gpiochip_get_data(chip); ssb_chipco_gpio_outen(&bus->chipco, 1 << gpio, 1 << gpio); ssb_chipco_gpio_out(&bus->chipco, 1 << gpio, value ? 1 << gpio : 0); @@ -79,7 +74,7 @@ static int ssb_gpio_chipco_direction_output(struct gpio_chip *chip, static int ssb_gpio_chipco_request(struct gpio_chip *chip, unsigned gpio) { - struct ssb_bus *bus = ssb_gpio_get_bus(chip); + struct ssb_bus *bus = gpiochip_get_data(chip); ssb_chipco_gpio_control(&bus->chipco, 1 << gpio, 0); /* clear pulldown */ @@ -92,7 +87,7 @@ static int ssb_gpio_chipco_request(struct gpio_chip *chip, unsigned gpio) static void ssb_gpio_chipco_free(struct gpio_chip *chip, unsigned gpio) { - struct ssb_bus *bus = ssb_gpio_get_bus(chip); + struct ssb_bus *bus = gpiochip_get_data(chip); /* clear pullup */ ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 0); @@ -246,7 +241,7 @@ static int ssb_gpio_chipco_init(struct ssb_bus *bus) if (err) return err; - err = gpiochip_add(chip); + err = gpiochip_add_data(chip, bus); if (err) { ssb_gpio_irq_chipco_domain_exit(bus); return err; @@ -263,7 +258,7 @@ static int ssb_gpio_chipco_init(struct ssb_bus *bus) static int ssb_gpio_extif_get_value(struct gpio_chip *chip, unsigned gpio) { - struct ssb_bus *bus = ssb_gpio_get_bus(chip); + struct ssb_bus *bus = gpiochip_get_data(chip); return !!ssb_extif_gpio_in(&bus->extif, 1 << gpio); } @@ -271,7 +266,7 @@ static int ssb_gpio_extif_get_value(struct gpio_chip *chip, unsigned gpio) static void ssb_gpio_extif_set_value(struct gpio_chip *chip, unsigned gpio, int value) { - struct ssb_bus *bus = ssb_gpio_get_bus(chip); + struct ssb_bus *bus = gpiochip_get_data(chip); ssb_extif_gpio_out(&bus->extif, 1 << gpio, value ? 1 << gpio : 0); } @@ -279,7 +274,7 @@ static void ssb_gpio_extif_set_value(struct gpio_chip *chip, unsigned gpio, static int ssb_gpio_extif_direction_input(struct gpio_chip *chip, unsigned gpio) { - struct ssb_bus *bus = ssb_gpio_get_bus(chip); + struct ssb_bus *bus = gpiochip_get_data(chip); ssb_extif_gpio_outen(&bus->extif, 1 << gpio, 0); return 0; @@ -288,7 +283,7 @@ static int ssb_gpio_extif_direction_input(struct gpio_chip *chip, static int ssb_gpio_extif_direction_output(struct gpio_chip *chip, unsigned gpio, int value) { - struct ssb_bus *bus = ssb_gpio_get_bus(chip); + struct ssb_bus *bus = gpiochip_get_data(chip); ssb_extif_gpio_outen(&bus->extif, 1 << gpio, 1 << gpio); ssb_extif_gpio_out(&bus->extif, 1 << gpio, value ? 1 << gpio : 0); @@ -439,7 +434,7 @@ static int ssb_gpio_extif_init(struct ssb_bus *bus) if (err) return err; - err = gpiochip_add(chip); + err = gpiochip_add_data(chip, bus); if (err) { ssb_gpio_irq_extif_domain_exit(bus); return err; diff --git a/drivers/staging/vme/devices/vme_pio2_gpio.c b/drivers/staging/vme/devices/vme_pio2_gpio.c index df992c3..6d361201 100644 --- a/drivers/staging/vme/devices/vme_pio2_gpio.c +++ b/drivers/staging/vme/devices/vme_pio2_gpio.c @@ -17,7 +17,7 @@ #include <linux/device.h> #include <linux/platform_device.h> #include <linux/ctype.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/slab.h> #include <linux/vme.h> @@ -25,16 +25,11 @@ static const char driver_name[] = "pio2_gpio"; -static struct pio2_card *gpio_to_pio2_card(struct gpio_chip *chip) -{ - return container_of(chip, struct pio2_card, gc); -} - static int pio2_gpio_get(struct gpio_chip *chip, unsigned int offset) { u8 reg; int retval; - struct pio2_card *card = gpio_to_pio2_card(chip); + struct pio2_card *card = gpiochip_get_data(chip); if ((card->bank[PIO2_CHANNEL_BANK[offset]].config == OUTPUT) | (card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) { @@ -71,7 +66,7 @@ static void pio2_gpio_set(struct gpio_chip *chip, { u8 reg; int retval; - struct pio2_card *card = gpio_to_pio2_card(chip); + struct pio2_card *card = gpiochip_get_data(chip); if ((card->bank[PIO2_CHANNEL_BANK[offset]].config == INPUT) | (card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) { @@ -100,7 +95,7 @@ static void pio2_gpio_set(struct gpio_chip *chip, static int pio2_gpio_dir_in(struct gpio_chip *chip, unsigned offset) { int data; - struct pio2_card *card = gpio_to_pio2_card(chip); + struct pio2_card *card = gpiochip_get_data(chip); if ((card->bank[PIO2_CHANNEL_BANK[offset]].config == OUTPUT) | (card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) { @@ -119,7 +114,7 @@ static int pio2_gpio_dir_in(struct gpio_chip *chip, unsigned offset) static int pio2_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value) { int data; - struct pio2_card *card = gpio_to_pio2_card(chip); + struct pio2_card *card = gpiochip_get_data(chip); if ((card->bank[PIO2_CHANNEL_BANK[offset]].config == INPUT) | (card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) { @@ -205,7 +200,7 @@ int pio2_gpio_init(struct pio2_card *card) card->gc.set = pio2_gpio_set; /* This function adds a memory mapped GPIO chip */ - retval = gpiochip_add(&card->gc); + retval = gpiochip_add_data(&card->gc, card); if (retval) { dev_err(&card->vdev->dev, "Unable to register GPIO\n"); kfree(card->gc.label); diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 3f98165..3f6e0ab 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -17,7 +17,7 @@ #include <linux/clk.h> #include <linux/delay.h> #include <linux/device.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_device.h> @@ -1036,7 +1036,7 @@ static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume); static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset) { unsigned int val; - struct max310x_port *s = container_of(chip, struct max310x_port, gpio); + struct max310x_port *s = gpiochip_get_data(chip); struct uart_port *port = &s->p[offset / 4].port; val = max310x_port_read(port, MAX310X_GPIODATA_REG); @@ -1046,7 +1046,7 @@ static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset) static void max310x_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { - struct max310x_port *s = container_of(chip, struct max310x_port, gpio); + struct max310x_port *s = gpiochip_get_data(chip); struct uart_port *port = &s->p[offset / 4].port; max310x_port_update(port, MAX310X_GPIODATA_REG, 1 << (offset % 4), @@ -1055,7 +1055,7 @@ static void max310x_gpio_set(struct gpio_chip *chip, unsigned offset, int value) static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { - struct max310x_port *s = container_of(chip, struct max310x_port, gpio); + struct max310x_port *s = gpiochip_get_data(chip); struct uart_port *port = &s->p[offset / 4].port; max310x_port_update(port, MAX310X_GPIOCFG_REG, 1 << (offset % 4), 0); @@ -1066,7 +1066,7 @@ static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned offset) static int max310x_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value) { - struct max310x_port *s = container_of(chip, struct max310x_port, gpio); + struct max310x_port *s = gpiochip_get_data(chip); struct uart_port *port = &s->p[offset / 4].port; max310x_port_update(port, MAX310X_GPIODATA_REG, 1 << (offset % 4), @@ -1183,7 +1183,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, s->gpio.base = -1; s->gpio.ngpio = devtype->nr * 4; s->gpio.can_sleep = 1; - ret = gpiochip_add(&s->gpio); + ret = gpiochip_add_data(&s->gpio, s); if (ret) goto out_uart; #endif diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 025a426..e639361 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -17,7 +17,7 @@ #include <linux/clk.h> #include <linux/delay.h> #include <linux/device.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/of.h> @@ -1104,8 +1104,7 @@ static const struct uart_ops sc16is7xx_ops = { static int sc16is7xx_gpio_get(struct gpio_chip *chip, unsigned offset) { unsigned int val; - struct sc16is7xx_port *s = container_of(chip, struct sc16is7xx_port, - gpio); + struct sc16is7xx_port *s = gpiochip_get_data(chip); struct uart_port *port = &s->p[0].port; val = sc16is7xx_port_read(port, SC16IS7XX_IOSTATE_REG); @@ -1115,8 +1114,7 @@ static int sc16is7xx_gpio_get(struct gpio_chip *chip, unsigned offset) static void sc16is7xx_gpio_set(struct gpio_chip *chip, unsigned offset, int val) { - struct sc16is7xx_port *s = container_of(chip, struct sc16is7xx_port, - gpio); + struct sc16is7xx_port *s = gpiochip_get_data(chip); struct uart_port *port = &s->p[0].port; sc16is7xx_port_update(port, SC16IS7XX_IOSTATE_REG, BIT(offset), @@ -1126,8 +1124,7 @@ static void sc16is7xx_gpio_set(struct gpio_chip *chip, unsigned offset, int val) static int sc16is7xx_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { - struct sc16is7xx_port *s = container_of(chip, struct sc16is7xx_port, - gpio); + struct sc16is7xx_port *s = gpiochip_get_data(chip); struct uart_port *port = &s->p[0].port; sc16is7xx_port_update(port, SC16IS7XX_IODIR_REG, BIT(offset), 0); @@ -1138,8 +1135,7 @@ static int sc16is7xx_gpio_direction_input(struct gpio_chip *chip, static int sc16is7xx_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int val) { - struct sc16is7xx_port *s = container_of(chip, struct sc16is7xx_port, - gpio); + struct sc16is7xx_port *s = gpiochip_get_data(chip); struct uart_port *port = &s->p[0].port; sc16is7xx_port_update(port, SC16IS7XX_IOSTATE_REG, BIT(offset), @@ -1210,7 +1206,7 @@ static int sc16is7xx_probe(struct device *dev, s->gpio.base = -1; s->gpio.ngpio = devtype->nr_gpio; s->gpio.can_sleep = 1; - ret = gpiochip_add(&s->gpio); + ret = gpiochip_add_data(&s->gpio, s); if (ret) goto out_thread; } diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index bee976f..50882e0 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -20,6 +20,18 @@ struct gpio_device; #ifdef CONFIG_GPIOLIB /** + * enum single_ended_mode - mode for single ended operation + * @LINE_MODE_PUSH_PULL: normal mode for a GPIO line, drive actively high/low + * @LINE_MODE_OPEN_DRAIN: set line to be open drain + * @LINE_MODE_OPEN_SOURCE: set line to be open source + */ +enum single_ended_mode { + LINE_MODE_PUSH_PULL, + LINE_MODE_OPEN_DRAIN, + LINE_MODE_OPEN_SOURCE, +}; + +/** * struct gpio_chip - abstract a GPIO controller * @label: a functional name for the GPIO device, such as a part * number or the name of the SoC IP-block implementing it. @@ -38,7 +50,15 @@ struct gpio_device; * @set: assigns output value for signal "offset" * @set_multiple: assigns output values for multiple signals defined by "mask" * @set_debounce: optional hook for setting debounce time for specified gpio in - * interrupt triggered gpio chips + * interrupt triggered gpio chips + * @set_single_ended: optional hook for setting a line as open drain, open + * source, or non-single ended (restore from open drain/source to normal + * push-pull mode) this should be implemented if the hardware supports + * open drain or open source settings. The GPIOlib will otherwise try + * to emulate open drain/source by not actively driving lines high/low + * if a consumer request this. The driver may return -ENOTSUPP if e.g. + * it supports just open drain but not open source and is called + * with LINE_MODE_OPEN_SOURCE as mode argument. * @to_irq: optional hook supporting non-static gpio_to_irq() mappings; * implementation may not sleep * @dbg_show: optional routine to show contents in debugfs; default code @@ -130,6 +150,9 @@ struct gpio_chip { int (*set_debounce)(struct gpio_chip *chip, unsigned offset, unsigned debounce); + int (*set_single_ended)(struct gpio_chip *chip, + unsigned offset, + enum single_ended_mode mode); int (*to_irq)(struct gpio_chip *chip, unsigned offset); diff --git a/include/linux/i2c/sx150x.h b/include/linux/i2c/sx150x.h deleted file mode 100644 index 52baa79..0000000 --- a/include/linux/i2c/sx150x.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Driver for the Semtech SX150x I2C GPIO Expanders - * - * Copyright (c) 2010, Code Aurora Forum. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ -#ifndef __LINUX_I2C_SX150X_H -#define __LINUX_I2C_SX150X_H - -/** - * struct sx150x_platform_data - config data for SX150x driver - * @gpio_base: The index number of the first GPIO assigned to this - * GPIO expander. The expander will create a block of - * consecutively numbered gpios beginning at the given base, - * with the size of the block depending on the model of the - * expander chip. - * @oscio_is_gpo: If set to true, the driver will configure OSCIO as a GPO - * instead of as an oscillator, increasing the size of the - * GP(I)O pool created by this expander by one. The - * output-only GPO pin will be added at the end of the block. - * @io_pullup_ena: A bit-mask which enables or disables the pull-up resistor - * for each IO line in the expander. Setting the bit at - * position n will enable the pull-up for the IO at - * the corresponding offset. For chips with fewer than - * 16 IO pins, high-end bits are ignored. - * @io_pulldn_ena: A bit-mask which enables-or disables the pull-down - * resistor for each IO line in the expander. Setting the - * bit at position n will enable the pull-down for the IO at - * the corresponding offset. For chips with fewer than - * 16 IO pins, high-end bits are ignored. - * @io_open_drain_ena: A bit-mask which enables-or disables open-drain - * operation for each IO line in the expander. Setting the - * bit at position n enables open-drain operation for - * the IO at the corresponding offset. Clearing the bit - * enables regular push-pull operation for that IO. - * For chips with fewer than 16 IO pins, high-end bits - * are ignored. - * @io_polarity: A bit-mask which enables polarity inversion for each IO line - * in the expander. Setting the bit at position n inverts - * the polarity of that IO line, while clearing it results - * in normal polarity. For chips with fewer than 16 IO pins, - * high-end bits are ignored. - * @irq_summary: The 'summary IRQ' line to which the GPIO expander's INT line - * is connected, via which it reports interrupt events - * across all GPIO lines. This must be a real, - * pre-existing IRQ line. - * Setting this value < 0 disables the irq_chip functionality - * of the driver. - * @irq_base: The first 'virtual IRQ' line at which our block of GPIO-based - * IRQ lines will appear. Similarly to gpio_base, the expander - * will create a block of irqs beginning at this number. - * This value is ignored if irq_summary is < 0. - * @reset_during_probe: If set to true, the driver will trigger a full - * reset of the chip at the beginning of the probe - * in order to place it in a known state. - */ -struct sx150x_platform_data { - unsigned gpio_base; - bool oscio_is_gpo; - u16 io_pullup_ena; - u16 io_pulldn_ena; - u16 io_open_drain_ena; - u16 io_polarity; - int irq_summary; - unsigned irq_base; - bool reset_during_probe; -}; - -#endif /* __LINUX_I2C_SX150X_H */ diff --git a/include/linux/platform_data/gpio-dwapb.h b/include/linux/platform_data/gpio-dwapb.h index 28702c8..2dc7f4a 100644 --- a/include/linux/platform_data/gpio-dwapb.h +++ b/include/linux/platform_data/gpio-dwapb.h @@ -15,8 +15,7 @@ #define GPIO_DW_APB_H struct dwapb_port_property { - struct device_node *node; - const char *name; + struct fwnode_handle *fwnode; unsigned int idx; unsigned int ngpio; unsigned int gpio_base; diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 503c5b9..d65f6f3 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -1100,6 +1100,7 @@ void irq_domain_free_irqs_common(struct irq_domain *domain, unsigned int virq, } irq_domain_free_irqs_parent(domain, virq, nr_irqs); } +EXPORT_SYMBOL_GPL(irq_domain_free_irqs_common); /** * irq_domain_free_irqs_top - Clear handler and handler data, clear irqdata and free parent diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 33e290b..6021226 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -4520,14 +4520,9 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec, } #ifdef CONFIG_GPIOLIB -static inline struct rt5677_priv *gpio_to_rt5677(struct gpio_chip *chip) -{ - return container_of(chip, struct rt5677_priv, gpio_chip); -} - static void rt5677_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { - struct rt5677_priv *rt5677 = gpio_to_rt5677(chip); + struct rt5677_priv *rt5677 = gpiochip_get_data(chip); switch (offset) { case RT5677_GPIO1 ... RT5677_GPIO5: @@ -4548,7 +4543,7 @@ static void rt5677_gpio_set(struct gpio_chip *chip, unsigned offset, int value) static int rt5677_gpio_direction_out(struct gpio_chip *chip, unsigned offset, int value) { - struct rt5677_priv *rt5677 = gpio_to_rt5677(chip); + struct rt5677_priv *rt5677 = gpiochip_get_data(chip); switch (offset) { case RT5677_GPIO1 ... RT5677_GPIO5: @@ -4572,7 +4567,7 @@ static int rt5677_gpio_direction_out(struct gpio_chip *chip, static int rt5677_gpio_get(struct gpio_chip *chip, unsigned offset) { - struct rt5677_priv *rt5677 = gpio_to_rt5677(chip); + struct rt5677_priv *rt5677 = gpiochip_get_data(chip); int value, ret; ret = regmap_read(rt5677->regmap, RT5677_GPIO_ST, &value); @@ -4584,7 +4579,7 @@ static int rt5677_gpio_get(struct gpio_chip *chip, unsigned offset) static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset) { - struct rt5677_priv *rt5677 = gpio_to_rt5677(chip); + struct rt5677_priv *rt5677 = gpiochip_get_data(chip); switch (offset) { case RT5677_GPIO1 ... RT5677_GPIO5: @@ -4638,7 +4633,7 @@ static void rt5677_gpio_config(struct rt5677_priv *rt5677, unsigned offset, static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset) { - struct rt5677_priv *rt5677 = gpio_to_rt5677(chip); + struct rt5677_priv *rt5677 = gpiochip_get_data(chip); struct regmap_irq_chip_data *data = rt5677->irq_data; int irq; @@ -4697,7 +4692,7 @@ static void rt5677_init_gpio(struct i2c_client *i2c) rt5677->gpio_chip.parent = &i2c->dev; rt5677->gpio_chip.base = -1; - ret = gpiochip_add(&rt5677->gpio_chip); + ret = gpiochip_add_data(&rt5677->gpio_chip, rt5677); if (ret != 0) dev_err(&i2c->dev, "Failed to add GPIOs: %d\n", ret); } diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 171a23d..512a9d2 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -17,6 +17,7 @@ #include <linux/export.h> #include <linux/pm.h> #include <linux/gcd.h> +#include <linux/gpio/driver.h> #include <linux/gpio.h> #include <linux/i2c.h> #include <linux/pm_runtime.h> @@ -2236,14 +2237,9 @@ static irqreturn_t wm5100_edge_irq(int irq, void *data) } #ifdef CONFIG_GPIOLIB -static inline struct wm5100_priv *gpio_to_wm5100(struct gpio_chip *chip) -{ - return container_of(chip, struct wm5100_priv, gpio_chip); -} - static void wm5100_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { - struct wm5100_priv *wm5100 = gpio_to_wm5100(chip); + struct wm5100_priv *wm5100 = gpiochip_get_data(chip); regmap_update_bits(wm5100->regmap, WM5100_GPIO_CTRL_1 + offset, WM5100_GP1_LVL, !!value << WM5100_GP1_LVL_SHIFT); @@ -2252,7 +2248,7 @@ static void wm5100_gpio_set(struct gpio_chip *chip, unsigned offset, int value) static int wm5100_gpio_direction_out(struct gpio_chip *chip, unsigned offset, int value) { - struct wm5100_priv *wm5100 = gpio_to_wm5100(chip); + struct wm5100_priv *wm5100 = gpiochip_get_data(chip); int val, ret; val = (1 << WM5100_GP1_FN_SHIFT) | (!!value << WM5100_GP1_LVL_SHIFT); @@ -2268,7 +2264,7 @@ static int wm5100_gpio_direction_out(struct gpio_chip *chip, static int wm5100_gpio_get(struct gpio_chip *chip, unsigned offset) { - struct wm5100_priv *wm5100 = gpio_to_wm5100(chip); + struct wm5100_priv *wm5100 = gpiochip_get_data(chip); unsigned int reg; int ret; @@ -2281,7 +2277,7 @@ static int wm5100_gpio_get(struct gpio_chip *chip, unsigned offset) static int wm5100_gpio_direction_in(struct gpio_chip *chip, unsigned offset) { - struct wm5100_priv *wm5100 = gpio_to_wm5100(chip); + struct wm5100_priv *wm5100 = gpiochip_get_data(chip); return regmap_update_bits(wm5100->regmap, WM5100_GPIO_CTRL_1 + offset, WM5100_GP1_FN_MASK | WM5100_GP1_DIR, @@ -2313,7 +2309,7 @@ static void wm5100_init_gpio(struct i2c_client *i2c) else wm5100->gpio_chip.base = -1; - ret = gpiochip_add(&wm5100->gpio_chip); + ret = gpiochip_add_data(&wm5100->gpio_chip, wm5100); if (ret != 0) dev_err(&i2c->dev, "Failed to add GPIOs: %d\n", ret); } diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index a82b8bc..a26ca49 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -20,7 +20,7 @@ #include <linux/init.h> #include <linux/completion.h> #include <linux/delay.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/pm.h> #include <linux/i2c.h> #include <linux/regmap.h> @@ -1766,11 +1766,6 @@ static int wm8903_resume(struct snd_soc_codec *codec) } #ifdef CONFIG_GPIOLIB -static inline struct wm8903_priv *gpio_to_wm8903(struct gpio_chip *chip) -{ - return container_of(chip, struct wm8903_priv, gpio_chip); -} - static int wm8903_gpio_request(struct gpio_chip *chip, unsigned offset) { if (offset >= WM8903_NUM_GPIO) @@ -1781,7 +1776,7 @@ static int wm8903_gpio_request(struct gpio_chip *chip, unsigned offset) static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset) { - struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); + struct wm8903_priv *wm8903 = gpiochip_get_data(chip); unsigned int mask, val; int ret; @@ -1799,7 +1794,7 @@ static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset) static int wm8903_gpio_get(struct gpio_chip *chip, unsigned offset) { - struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); + struct wm8903_priv *wm8903 = gpiochip_get_data(chip); unsigned int reg; regmap_read(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset, ®); @@ -1810,7 +1805,7 @@ static int wm8903_gpio_get(struct gpio_chip *chip, unsigned offset) static int wm8903_gpio_direction_out(struct gpio_chip *chip, unsigned offset, int value) { - struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); + struct wm8903_priv *wm8903 = gpiochip_get_data(chip); unsigned int mask, val; int ret; @@ -1828,7 +1823,7 @@ static int wm8903_gpio_direction_out(struct gpio_chip *chip, static void wm8903_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { - struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); + struct wm8903_priv *wm8903 = gpiochip_get_data(chip); regmap_update_bits(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset, WM8903_GP1_LVL_MASK, @@ -1860,7 +1855,7 @@ static void wm8903_init_gpio(struct wm8903_priv *wm8903) else wm8903->gpio_chip.base = -1; - ret = gpiochip_add(&wm8903->gpio_chip); + ret = gpiochip_add_data(&wm8903->gpio_chip, wm8903); if (ret != 0) dev_err(wm8903->dev, "Failed to add GPIOs: %d\n", ret); } diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 720a14e..fc164d6 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -18,7 +18,7 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/gcd.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/i2c.h> #include <linux/input.h> #include <linux/pm_runtime.h> @@ -3307,14 +3307,9 @@ static void wm8962_set_gpio_mode(struct wm8962_priv *wm8962, int gpio) } #ifdef CONFIG_GPIOLIB -static inline struct wm8962_priv *gpio_to_wm8962(struct gpio_chip *chip) -{ - return container_of(chip, struct wm8962_priv, gpio_chip); -} - static int wm8962_gpio_request(struct gpio_chip *chip, unsigned offset) { - struct wm8962_priv *wm8962 = gpio_to_wm8962(chip); + struct wm8962_priv *wm8962 = gpiochip_get_data(chip); /* The WM8962 GPIOs aren't linearly numbered. For simplicity * we export linear numbers and error out if the unsupported @@ -3337,7 +3332,7 @@ static int wm8962_gpio_request(struct gpio_chip *chip, unsigned offset) static void wm8962_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { - struct wm8962_priv *wm8962 = gpio_to_wm8962(chip); + struct wm8962_priv *wm8962 = gpiochip_get_data(chip); struct snd_soc_codec *codec = wm8962->codec; snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset, @@ -3347,7 +3342,7 @@ static void wm8962_gpio_set(struct gpio_chip *chip, unsigned offset, int value) static int wm8962_gpio_direction_out(struct gpio_chip *chip, unsigned offset, int value) { - struct wm8962_priv *wm8962 = gpio_to_wm8962(chip); + struct wm8962_priv *wm8962 = gpiochip_get_data(chip); struct snd_soc_codec *codec = wm8962->codec; int ret, val; @@ -3386,7 +3381,7 @@ static void wm8962_init_gpio(struct snd_soc_codec *codec) else wm8962->gpio_chip.base = -1; - ret = gpiochip_add(&wm8962->gpio_chip); + ret = gpiochip_add_data(&wm8962->gpio_chip, wm8962); if (ret != 0) dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret); } diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index f99b34f..a730442 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -17,6 +17,7 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/gcd.h> +#include <linux/gpio/driver.h> #include <linux/gpio.h> #include <linux/i2c.h> #include <linux/regmap.h> @@ -2139,14 +2140,9 @@ static int wm8996_set_fll(struct snd_soc_codec *codec, int fll_id, int source, } #ifdef CONFIG_GPIOLIB -static inline struct wm8996_priv *gpio_to_wm8996(struct gpio_chip *chip) -{ - return container_of(chip, struct wm8996_priv, gpio_chip); -} - static void wm8996_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { - struct wm8996_priv *wm8996 = gpio_to_wm8996(chip); + struct wm8996_priv *wm8996 = gpiochip_get_data(chip); regmap_update_bits(wm8996->regmap, WM8996_GPIO_1 + offset, WM8996_GP1_LVL, !!value << WM8996_GP1_LVL_SHIFT); @@ -2155,7 +2151,7 @@ static void wm8996_gpio_set(struct gpio_chip *chip, unsigned offset, int value) static int wm8996_gpio_direction_out(struct gpio_chip *chip, unsigned offset, int value) { - struct wm8996_priv *wm8996 = gpio_to_wm8996(chip); + struct wm8996_priv *wm8996 = gpiochip_get_data(chip); int val; val = (1 << WM8996_GP1_FN_SHIFT) | (!!value << WM8996_GP1_LVL_SHIFT); @@ -2167,7 +2163,7 @@ static int wm8996_gpio_direction_out(struct gpio_chip *chip, static int wm8996_gpio_get(struct gpio_chip *chip, unsigned offset) { - struct wm8996_priv *wm8996 = gpio_to_wm8996(chip); + struct wm8996_priv *wm8996 = gpiochip_get_data(chip); unsigned int reg; int ret; @@ -2180,7 +2176,7 @@ static int wm8996_gpio_get(struct gpio_chip *chip, unsigned offset) static int wm8996_gpio_direction_in(struct gpio_chip *chip, unsigned offset) { - struct wm8996_priv *wm8996 = gpio_to_wm8996(chip); + struct wm8996_priv *wm8996 = gpiochip_get_data(chip); return regmap_update_bits(wm8996->regmap, WM8996_GPIO_1 + offset, WM8996_GP1_FN_MASK | WM8996_GP1_DIR, @@ -2211,7 +2207,7 @@ static void wm8996_init_gpio(struct wm8996_priv *wm8996) else wm8996->gpio_chip.base = -1; - ret = gpiochip_add(&wm8996->gpio_chip); + ret = gpiochip_add_data(&wm8996->gpio_chip, wm8996); if (ret != 0) dev_err(wm8996->dev, "Failed to add GPIOs: %d\n", ret); } diff --git a/sound/soc/soc-ac97.c b/sound/soc/soc-ac97.c index 7e0acd8..bc4a55b 100644 --- a/sound/soc/soc-ac97.c +++ b/sound/soc/soc-ac97.c @@ -59,8 +59,7 @@ static void soc_ac97_device_release(struct device *dev) #ifdef CONFIG_GPIOLIB static inline struct snd_soc_codec *gpio_to_codec(struct gpio_chip *chip) { - struct snd_ac97_gpio_priv *gpio_priv = - container_of(chip, struct snd_ac97_gpio_priv, gpio_chip); + struct snd_ac97_gpio_priv *gpio_priv = gpiochip_get_data(chip); return gpio_priv->codec; } @@ -98,8 +97,7 @@ static int snd_soc_ac97_gpio_get(struct gpio_chip *chip, unsigned offset) static void snd_soc_ac97_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { - struct snd_ac97_gpio_priv *gpio_priv = - container_of(chip, struct snd_ac97_gpio_priv, gpio_chip); + struct snd_ac97_gpio_priv *gpio_priv = gpiochip_get_data(chip); struct snd_soc_codec *codec = gpio_to_codec(chip); gpio_priv->gpios_set &= ~(1 << offset); @@ -145,7 +143,7 @@ static int snd_soc_ac97_init_gpio(struct snd_ac97 *ac97, gpio_priv->gpio_chip.parent = codec->dev; gpio_priv->gpio_chip.base = -1; - ret = gpiochip_add(&gpio_priv->gpio_chip); + ret = gpiochip_add_data(&gpio_priv->gpio_chip, gpio_priv); if (ret != 0) dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret); return ret; diff --git a/tools/gpio/Makefile b/tools/gpio/Makefile index 4d198d5..c155d6b 100644 --- a/tools/gpio/Makefile +++ b/tools/gpio/Makefile @@ -1,5 +1,5 @@ CC = $(CROSS_COMPILE)gcc -CFLAGS += -Wall -g -D_GNU_SOURCE +CFLAGS += -O2 -Wall -g -D_GNU_SOURCE all: lsgpio diff --git a/tools/gpio/lsgpio.c b/tools/gpio/lsgpio.c index 1124da3..eb3f56e 100644 --- a/tools/gpio/lsgpio.c +++ b/tools/gpio/lsgpio.c @@ -147,7 +147,7 @@ void print_usage(void) int main(int argc, char **argv) { - const char *device_name; + const char *device_name = NULL; int ret; int c; |