diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-12 15:50:46 +0900 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-12 15:50:46 +0900 |
commit | c2d33069915d1f9b3b1dcc2199af11d4e072b037 (patch) | |
tree | 2664fd3c41c2f3223cfbb64793c2ddb8e9087ded | |
parent | 8a5dc585d50015af9c079ae2d182dc4c1cd22914 (diff) | |
parent | 993571273275bfecb5161806796eb368db234106 (diff) |
Merge tag 'gpio-v3.13-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio
Pull GPIO changes from Linus Walleij:
"Here is the bulk of GPIO changes for the v3.13 development cycle.
I've got ACKs for the things that affect other subsystems (or it's my
own subsystem, like pinctrl). Most of that pertain to an attempt from
my side to consolidate and get rid of custom GPIO implementations in
the ARM tree. I will continue doing this.
The main change this time is the new GPIO descriptor API, background
for this can be found in Corbet's summary from this january in LWN:
http://lwn.net/Articles/533632/
Summary:
- Merged the GPIO descriptor API from Alexandre Courbot. This is a
first step toward trying to get rid of the global GPIO numberspace
for the future.
- Add an API so that driver can flag that a certain GPIO line is
being used by a irqchip backend for generating IRQs, so that we can
enforce checks, like not allowing users to switch that line to an
output at runtime, since this makes no sense. Implemented
corresponding calls in a few select drivers.
- ACPI GPIO cleanups, refactorings and switch to using the
descriptor-based interface.
- Support for the TPS80036 Palmas GPIO variant.
- A new driver for the Broadcom Kona GPIO SoC IP block.
- Device tree support for the PCF857x driver.
- A set of ARM GPIO refactorings with the goal of getting rid of a
bunch of custom GPIO implementations from the arch/arm/* tree:
* Move the IOP GPIO driver to the GPIO subsystem and fix all users
to use the gpiolib API for accessing GPIOs. Delete the old
custom GPIO implementation.
* Delete the unused custom PXA GPIO implemention.
* Convert all users of the IXP4 custom GPIO implementation to use
gpiolib and delete the custom implementation.
* Delete the custom Gemini GPIO implementation, also completely
unused.
- Various cleanups and renamings"
* tag 'gpio-v3.13-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (85 commits)
gpio: gpio-mxs: Remove unneeded dt checks
gpio: pl061: don't depend on CONFIG_ARM
gpio: bcm-kona: add missing .owner to struct gpio_chip
gpiolib: provide a declaration of seq_file in gpio/driver.h
gpiolib: include gpio/consumer.h in of_gpio.h for desc_to_gpio()
gpio: provide stubs for devres gpio functions
gpiolib: devres: add missing headers
gpiolib: make GPIO_DEVRES depend on GPIOLIB
gpiolib: devres: fix devm_gpiod_get_index()
gpiolib / ACPI: document the GPIO descriptor based interface
gpiolib / ACPI: allow passing GPIOF_ACTIVE_LOW for GpioInt resources
gpiolib / ACPI: add ACPI support for gpiod_get_index()
gpiolib / ACPI: convert to gpiod interfaces
gpiolib: add gpiod_get() and gpiod_put() functions
gpiolib: port of_ functions to use gpiod
gpiolib: export descriptor-based GPIO interface
Fixup "MAINTAINERS: GPIO-INTEL-MID: add maintainer"
gpio: bcm281xx: Don't print addresses of GPIO area in probe()
gpio: tegra: use new gpio_lock_as_irq() API
gpio: rcar: Include linux/of.h header
...
74 files changed, 3199 insertions, 1455 deletions
diff --git a/Documentation/acpi/enumeration.txt b/Documentation/acpi/enumeration.txt index aca4e69121b7..b994bcb32b92 100644 --- a/Documentation/acpi/enumeration.txt +++ b/Documentation/acpi/enumeration.txt @@ -295,10 +295,6 @@ These GPIO numbers are controller relative and path "\\_SB.PCI0.GPI0" specifies the path to the controller. In order to use these GPIOs in Linux we need to translate them to the Linux GPIO numbers. -The driver can do this by including <linux/acpi_gpio.h> and then calling -acpi_get_gpio(path, gpio). This will return the Linux GPIO number or -negative errno if there was no translation found. - In a simple case of just getting the Linux GPIO number from device resources one can use acpi_get_gpio_by_index() helper function. It takes pointer to the device and index of the GpioIo/GpioInt descriptor in the @@ -322,3 +318,25 @@ suitable to the gpiolib before passing them. In case of GpioInt resource an additional call to gpio_to_irq() must be done before calling request_irq(). + +Note that the above API is ACPI specific and not recommended for drivers +that need to support non-ACPI systems. The recommended way is to use +the descriptor based GPIO interfaces. The above example looks like this +when converted to the GPIO desc: + + #include <linux/gpio/consumer.h> + ... + + struct gpio_desc *irq_desc, *power_desc; + + irq_desc = gpiod_get_index(dev, NULL, 1); + if (IS_ERR(irq_desc)) + /* handle error */ + + power_desc = gpiod_get_index(dev, NULL, 0); + if (IS_ERR(power_desc)) + /* handle error */ + + /* Now we can use the GPIO descriptors */ + +See also Documentation/gpio.txt. diff --git a/Documentation/devicetree/bindings/gpio/gpio-bcm-kona.txt b/Documentation/devicetree/bindings/gpio/gpio-bcm-kona.txt new file mode 100644 index 000000000000..4a63bc96b687 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-bcm-kona.txt @@ -0,0 +1,52 @@ +Broadcom Kona Family GPIO +========================= + +This GPIO driver is used in the following Broadcom SoCs: + BCM11130, BCM11140, BCM11351, BCM28145, BCM28155 + +The Broadcom GPIO Controller IP can be configured prior to synthesis to +support up to 8 banks of 32 GPIOs where each bank has its own IRQ. The +GPIO controller only supports edge, not level, triggering of interrupts. + +Required properties +------------------- + +- compatible: "brcm,bcm11351-gpio", "brcm,kona-gpio" +- reg: Physical base address and length of the controller's registers. +- interrupts: The interrupt outputs from the controller. There is one GPIO + interrupt per GPIO bank. The number of interrupts listed depends on the + number of GPIO banks on the SoC. The interrupts must be ordered by bank, + starting with bank 0. There is always a 1:1 mapping between banks and + IRQs. +- #gpio-cells: Should be <2>. The first cell is the pin number, the second + cell is used to specify optional parameters: + - bit 0 specifies polarity (0 for normal, 1 for inverted) + See also "gpio-specifier" in .../devicetree/bindings/gpio/gpio.txt. +- #interrupt-cells: Should be <2>. The first cell is the GPIO number. The + second cell is used to specify flags. The following subset of flags is + supported: + - trigger type (bits[1:0]): + 1 = low-to-high edge triggered. + 2 = high-to-low edge triggered. + 3 = low-to-high or high-to-low edge triggered + Valid values are 1, 2, 3 + See also .../devicetree/bindings/interrupt-controller/interrupts.txt. +- gpio-controller: Marks the device node as a GPIO controller. +- interrupt-controller: Marks the device node as an interrupt controller. + +Example: + gpio: gpio@35003000 { + compatible = "brcm,bcm11351-gpio", "brcm,kona-gpio"; + reg = <0x35003000 0x800>; + interrupts = + <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH + GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH + GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH + GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH + GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH + GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>; + #gpio-cells = <2>; + #interrupt-cells = <2>; + gpio-controller; + interrupt-controller; + }; diff --git a/Documentation/devicetree/bindings/gpio/gpio-pcf857x.txt b/Documentation/devicetree/bindings/gpio/gpio-pcf857x.txt new file mode 100644 index 000000000000..d63194a2c848 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-pcf857x.txt @@ -0,0 +1,71 @@ +* PCF857x-compatible I/O expanders + +The PCF857x-compatible chips have "quasi-bidirectional" I/O lines that can be +driven high by a pull-up current source or driven low to ground. This combines +the direction and output level into a single bit per line, which can't be read +back. We can't actually know at initialization time whether a line is configured +(a) as output and driving the signal low/high, or (b) as input and reporting a +low/high value, without knowing the last value written since the chip came out +of reset (if any). The only reliable solution for setting up line direction is +thus to do it explicitly. + +Required Properties: + + - compatible: should be one of the following. + - "maxim,max7328": For the Maxim MAX7378 + - "maxim,max7329": For the Maxim MAX7329 + - "nxp,pca8574": For the NXP PCA8574 + - "nxp,pca8575": For the NXP PCA8575 + - "nxp,pca9670": For the NXP PCA9670 + - "nxp,pca9671": For the NXP PCA9671 + - "nxp,pca9672": For the NXP PCA9672 + - "nxp,pca9673": For the NXP PCA9673 + - "nxp,pca9674": For the NXP PCA9674 + - "nxp,pca9675": For the NXP PCA9675 + - "nxp,pcf8574": For the NXP PCF8574 + - "nxp,pcf8574a": For the NXP PCF8574A + - "nxp,pcf8575": For the NXP PCF8575 + - "ti,tca9554": For the TI TCA9554 + + - reg: I2C slave address. + + - gpio-controller: Marks the device node as a gpio controller. + - #gpio-cells: Should be 2. The first cell is the GPIO number and the second + cell specifies GPIO flags, as defined in <dt-bindings/gpio/gpio.h>. Only the + GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported. + +Optional Properties: + + - lines-initial-states: Bitmask that specifies the initial state of each + line. When a bit is set to zero, the corresponding line will be initialized to + the input (pulled-up) state. When the bit is set to one, the line will be + initialized the the low-level output state. If the property is not specified + all lines will be initialized to the input state. + + The I/O expander can detect input state changes, and thus optionally act as + an interrupt controller. When the expander interrupt line is connected all the + following properties must be set. For more information please see the + interrupt controller device tree bindings documentation available at + Documentation/devicetree/bindings/interrupt-controller/interrupts.txt. + + - interrupt-controller: Identifies the node as an interrupt controller. + - #interrupt-cells: Number of cells to encode an interrupt source, shall be 2. + - interrupt-parent: phandle of the parent interrupt controller. + - interrupts: Interrupt specifier for the controllers interrupt. + + +Please refer to gpio.txt in this directory for details of the common GPIO +bindings used by client devices. + +Example: PCF8575 I/O expander node + + pcf8575: gpio@20 { + compatible = "nxp,pcf8575"; + reg = <0x20>; + interrupt-parent = <&irqpin2>; + interrupts = <3 0>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 197e2b61fcfe..051e4dc5b70f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4440,6 +4440,12 @@ F: Documentation/networking/ixgbevf.txt F: Documentation/networking/i40e.txt F: drivers/net/ethernet/intel/ +INTEL-MID GPIO DRIVER +M: David Cohen <david.a.cohen@linux.intel.com> +L: linux-gpio@vger.kernel.org +S: Maintained +F: drivers/gpio/gpio-intel-mid.c + INTEL PRO/WIRELESS 2100, 2200BG, 2915ABG NETWORK CONNECTION SUPPORT M: Stanislav Yakovlev <stas.yakovlev@gmail.com> L: linux-wireless@vger.kernel.org diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index aa8300333bc5..acb80708accd 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -389,7 +389,6 @@ config ARCH_GEMINI select CLKSRC_MMIO select CPU_FA526 select GENERIC_CLOCKEVENTS - select NEED_MACH_GPIO_H help Support for the Cortina Systems Gemini family SoCs @@ -458,7 +457,7 @@ config ARCH_IOP32X depends on MMU select ARCH_REQUIRE_GPIOLIB select CPU_XSCALE - select NEED_MACH_GPIO_H + select GPIO_IOP select NEED_RET_TO_USER select PCI select PLAT_IOP @@ -471,7 +470,7 @@ config ARCH_IOP33X depends on MMU select ARCH_REQUIRE_GPIOLIB select CPU_XSCALE - select NEED_MACH_GPIO_H + select GPIO_IOP select NEED_RET_TO_USER select PCI select PLAT_IOP @@ -560,7 +559,6 @@ config ARCH_MMP select GPIO_PXA select IRQ_DOMAIN select MULTI_IRQ_HANDLER - select NEED_MACH_GPIO_H select PINCTRL select PLAT_PXA select SPARSE_IRQ @@ -623,7 +621,6 @@ config ARCH_PXA select GPIO_PXA select HAVE_IDE select MULTI_IRQ_HANDLER - select NEED_MACH_GPIO_H select PLAT_PXA select SPARSE_IRQ help diff --git a/arch/arm/include/asm/hardware/iop3xx-gpio.h b/arch/arm/include/asm/hardware/iop3xx-gpio.h deleted file mode 100644 index 9eda7dc92ad8..000000000000 --- a/arch/arm/include/asm/hardware/iop3xx-gpio.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * arch/arm/include/asm/hardware/iop3xx-gpio.h - * - * IOP3xx GPIO wrappers - * - * Copyright (c) 2008 Arnaud Patard <arnaud.patard@rtp-net.org> - * Based on IXP4XX gpio.h file - * - * 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 Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __ASM_ARM_HARDWARE_IOP3XX_GPIO_H -#define __ASM_ARM_HARDWARE_IOP3XX_GPIO_H - -#include <mach/hardware.h> -#include <asm-generic/gpio.h> - -#define __ARM_GPIOLIB_COMPLEX - -#define IOP3XX_N_GPIOS 8 - -static inline int gpio_get_value(unsigned gpio) -{ - if (gpio > IOP3XX_N_GPIOS) - return __gpio_get_value(gpio); - - return gpio_line_get(gpio); -} - -static inline void gpio_set_value(unsigned gpio, int value) -{ - if (gpio > IOP3XX_N_GPIOS) { - __gpio_set_value(gpio, value); - return; - } - gpio_line_set(gpio, value); -} - -static inline int gpio_cansleep(unsigned gpio) -{ - if (gpio < IOP3XX_N_GPIOS) - return 0; - else - return __gpio_cansleep(gpio); -} - -/* - * The GPIOs are not generating any interrupt - * Note : manuals are not clear about this - */ -static inline int gpio_to_irq(int gpio) -{ - return -EINVAL; -} - -static inline int irq_to_gpio(int gpio) -{ - return -EINVAL; -} - -#endif - diff --git a/arch/arm/include/asm/hardware/iop3xx.h b/arch/arm/include/asm/hardware/iop3xx.h index 423744bf18eb..2594a95ff19a 100644 --- a/arch/arm/include/asm/hardware/iop3xx.h +++ b/arch/arm/include/asm/hardware/iop3xx.h @@ -18,16 +18,9 @@ /* * IOP3XX GPIO handling */ -#define GPIO_IN 0 -#define GPIO_OUT 1 -#define GPIO_LOW 0 -#define GPIO_HIGH 1 #define IOP3XX_GPIO_LINE(x) (x) #ifndef __ASSEMBLY__ -extern void gpio_line_config(int line, int direction); -extern int gpio_line_get(int line); -extern void gpio_line_set(int line, int value); extern int init_atu; extern int iop3xx_get_init_atu(void); #endif @@ -168,11 +161,6 @@ extern int iop3xx_get_init_atu(void); /* PERCR0 DOESN'T EXIST - index from 1! */ #define IOP3XX_PERCR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0710) -/* General Purpose I/O */ -#define IOP3XX_GPOE (volatile u32 *)IOP3XX_GPIO_REG(0x0000) -#define IOP3XX_GPID (volatile u32 *)IOP3XX_GPIO_REG(0x0004) -#define IOP3XX_GPOD (volatile u32 *)IOP3XX_GPIO_REG(0x0008) - /* Timers */ #define IOP3XX_TU_TMR0 (volatile u32 *)IOP3XX_TIMER_REG(0x0000) #define IOP3XX_TU_TMR1 (volatile u32 *)IOP3XX_TIMER_REG(0x0004) diff --git a/arch/arm/mach-gemini/gpio.c b/arch/arm/mach-gemini/gpio.c index 70bfa571b24b..f8cb5710d6ee 100644 --- a/arch/arm/mach-gemini/gpio.c +++ b/arch/arm/mach-gemini/gpio.c @@ -21,9 +21,9 @@ #include <mach/hardware.h> #include <mach/irqs.h> -#include <mach/gpio.h> #define GPIO_BASE(x) IO_ADDRESS(GEMINI_GPIO_BASE(x)) +#define irq_to_gpio(x) ((x) - GPIO_IRQ_BASE) /* GPIO registers definition */ #define GPIO_DATA_OUT 0x0 diff --git a/arch/arm/mach-gemini/include/mach/gpio.h b/arch/arm/mach-gemini/include/mach/gpio.h deleted file mode 100644 index 40a0527bada7..000000000000 --- a/arch/arm/mach-gemini/include/mach/gpio.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Gemini gpiolib specific defines - * - * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> - * - * 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 Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef __MACH_GPIO_H__ -#define __MACH_GPIO_H__ - -#include <mach/irqs.h> - -#define gpio_to_irq(x) ((x) + GPIO_IRQ_BASE) -#define irq_to_gpio(x) ((x) - GPIO_IRQ_BASE) - -#endif /* __MACH_GPIO_H__ */ diff --git a/arch/arm/mach-iop32x/em7210.c b/arch/arm/mach-iop32x/em7210.c index 31fbb6c61b25..177cd073a83b 100644 --- a/arch/arm/mach-iop32x/em7210.c +++ b/arch/arm/mach-iop32x/em7210.c @@ -32,6 +32,7 @@ #include <asm/mach/time.h> #include <asm/mach-types.h> #include <mach/time.h> +#include "gpio-iop32x.h" static void __init em7210_timer_init(void) { @@ -183,6 +184,7 @@ void em7210_power_off(void) static void __init em7210_init_machine(void) { + register_iop32x_gpio(); platform_device_register(&em7210_serial_device); platform_device_register(&iop3xx_i2c0_device); platform_device_register(&iop3xx_i2c1_device); diff --git a/arch/arm/mach-iop32x/glantank.c b/arch/arm/mach-iop32x/glantank.c index ac304705fe68..547b2342d61a 100644 --- a/arch/arm/mach-iop32x/glantank.c +++ b/arch/arm/mach-iop32x/glantank.c @@ -34,6 +34,7 @@ #include <asm/mach-types.h> #include <asm/page.h> #include <mach/time.h> +#include "gpio-iop32x.h" /* * GLAN Tank timer tick configuration. @@ -187,6 +188,7 @@ static void glantank_power_off(void) static void __init glantank_init_machine(void) { + register_iop32x_gpio(); platform_device_register(&iop3xx_i2c0_device); platform_device_register(&iop3xx_i2c1_device); platform_device_register(&glantank_flash_device); diff --git a/arch/arm/mach-iop32x/gpio-iop32x.h b/arch/arm/mach-iop32x/gpio-iop32x.h new file mode 100644 index 000000000000..3c7309c02029 --- /dev/null +++ b/arch/arm/mach-iop32x/gpio-iop32x.h @@ -0,0 +1,10 @@ +static struct resource iop32x_gpio_res[] = { + DEFINE_RES_MEM((IOP3XX_PERIPHERAL_PHYS_BASE + 0x07c4), 0x10), +}; + +static inline void register_iop32x_gpio(void) +{ + platform_device_register_simple("gpio-iop", 0, + iop32x_gpio_res, + ARRAY_SIZE(iop32x_gpio_res)); +} diff --git a/arch/arm/mach-iop32x/include/mach/gpio.h b/arch/arm/mach-iop32x/include/mach/gpio.h deleted file mode 100644 index 708f4ec9db1d..000000000000 --- a/arch/arm/mach-iop32x/include/mach/gpio.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __ASM_ARCH_IOP32X_GPIO_H -#define __ASM_ARCH_IOP32X_GPIO_H - -#include <asm/hardware/iop3xx-gpio.h> - -#endif diff --git a/arch/arm/mach-iop32x/include/mach/iop32x.h b/arch/arm/mach-iop32x/include/mach/iop32x.h index 941f363aca56..56ec864ec313 100644 --- a/arch/arm/mach-iop32x/include/mach/iop32x.h +++ b/arch/arm/mach-iop32x/include/mach/iop32x.h @@ -19,7 +19,6 @@ * Peripherals that are shared between the iop32x and iop33x but * located at different addresses. */ -#define IOP3XX_GPIO_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x07c4 + (reg)) #define IOP3XX_TIMER_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x07e0 + (reg)) #include <asm/hardware/iop3xx.h> diff --git a/arch/arm/mach-iop32x/iq31244.c b/arch/arm/mach-iop32x/iq31244.c index f2cd2966212d..0e1392b20d18 100644 --- a/arch/arm/mach-iop32x/iq31244.c +++ b/arch/arm/mach-iop32x/iq31244.c @@ -37,6 +37,7 @@ #include <asm/page.h> #include <asm/pgtable.h> #include <mach/time.h> +#include "gpio-iop32x.h" /* * Until March of 2007 iq31244 platforms and ep80219 platforms shared the @@ -283,6 +284,7 @@ void ep80219_power_off(void) static void __init iq31244_init_machine(void) { + register_iop32x_gpio(); platform_device_register(&iop3xx_i2c0_device); platform_device_register(&iop3xx_i2c1_device); platform_device_register(&iq31244_flash_device); diff --git a/arch/arm/mach-iop32x/iq80321.c b/arch/arm/mach-iop32x/iq80321.c index 015435de90dd..66782ff1f46a 100644 --- a/arch/arm/mach-iop32x/iq80321.c +++ b/arch/arm/mach-iop32x/iq80321.c @@ -33,6 +33,7 @@ #include <asm/page.h> #include <asm/pgtable.h> #include <mach/time.h> +#include "gpio-iop32x.h" /* * IQ80321 timer tick configuration. @@ -170,6 +171,7 @@ static struct platform_device iq80321_serial_device = { static void __init iq80321_init_machine(void) { + register_iop32x_gpio(); platform_device_register(&iop3xx_i2c0_device); platform_device_register(&iop3xx_i2c1_device); platform_device_register(&iq80321_flash_device); diff --git a/arch/arm/mach-iop32x/n2100.c b/arch/arm/mach-iop32x/n2100.c index 069144300b77..c1cd80ecc219 100644 --- a/arch/arm/mach-iop32x/n2100.c +++ b/arch/arm/mach-iop32x/n2100.c @@ -30,6 +30,7 @@ #include <linux/platform_device.h> #include <linux/reboot.h> #include <linux/io.h> +#include <linux/gpio.h> #include <mach/hardware.h> #include <asm/irq.h> #include <asm/mach/arch.h> @@ -40,6 +41,7 @@ #include <asm/page.h> #include <asm/pgtable.h> #include <mach/time.h> +#include "gpio-iop32x.h" /* * N2100 timer tick configuration. @@ -288,8 +290,14 @@ static void n2100_power_off(void) static void n2100_restart(enum reboot_mode mode, const char *cmd) { - gpio_line_set(N2100_HARDWARE_RESET, GPIO_LOW); - gpio_line_config(N2100_HARDWARE_RESET, GPIO_OUT); + int ret; + + ret = gpio_direction_output(N2100_HARDWARE_RESET, 0); + if (ret) { + pr_crit("could not drive reset GPIO low\n"); + return; + } + /* Wait for reset to happen */ while (1) ; } @@ -299,7 +307,7 @@ static struct timer_list power_button_poll_timer; static void power_button_poll(unsigned long dummy) { - if (gpio_line_get(N2100_POWER_BUTTON) == 0) { + if (gpio_get_value(N2100_POWER_BUTTON) == 0) { ctrl_alt_del(); return; } @@ -308,9 +316,37 @@ static void power_button_poll(unsigned long dummy) add_timer(&power_button_poll_timer); } +static int __init n2100_request_gpios(void) +{ + int ret; + + if (!machine_is_n2100()) + return 0; + + ret = gpio_request(N2100_HARDWARE_RESET, "reset"); + if (ret) + pr_err("could not request reset GPIO\n"); + + ret = gpio_request(N2100_POWER_BUTTON, "power"); + if (ret) + pr_err("could not request power GPIO\n"); + else { + ret = gpio_direction_input(N2100_POWER_BUTTON); + if (ret) + pr_err("could not set power GPIO as input\n"); + } + /* Set up power button poll timer */ + init_timer(&power_button_poll_timer); + power_button_poll_timer.function = power_button_poll; + power_button_poll_timer.expires = jiffies + (HZ / 10); + add_timer(&power_button_poll_timer); + return 0; +} +device_initcall(n2100_request_gpios); static void __init n2100_init_machine(void) { + register_iop32x_gpio(); platform_device_register(&iop3xx_i2c0_device); platform_device_register(&n2100_flash_device); platform_device_register(&n2100_serial_device); @@ -321,11 +357,6 @@ static void __init n2100_init_machine(void) ARRAY_SIZE(n2100_i2c_devices)); pm_power_off = n2100_power_off; - - init_timer(&power_button_poll_timer); - power_button_poll_timer.function = power_button_poll; - power_button_poll_timer.expires = jiffies + (HZ / 10); - add_timer(&power_button_poll_timer); } MACHINE_START(N2100, "Thecus N2100") diff --git a/arch/arm/mach-iop33x/include/mach/gpio.h b/arch/arm/mach-iop33x/include/mach/gpio.h deleted file mode 100644 index ddd55bba9bb9..000000000000 --- a/arch/arm/mach-iop33x/include/mach/gpio.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __ASM_ARCH_IOP33X_GPIO_H -#define __ASM_ARCH_IOP33X_GPIO_H - -#include <asm/hardware/iop3xx-gpio.h> - -#endif diff --git a/arch/arm/mach-iop33x/include/mach/iop33x.h b/arch/arm/mach-iop33x/include/mach/iop33x.h index a89c0a234bff..c95122653094 100644 --- a/arch/arm/mach-iop33x/include/mach/iop33x.h +++ b/arch/arm/mach-iop33x/include/mach/iop33x.h @@ -18,7 +18,6 @@ * Peripherals that are shared between the iop32x and iop33x but * located at different addresses. */ -#define IOP3XX_GPIO_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x1780 + (reg)) #define IOP3XX_TIMER_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x07d0 + (reg)) #include <asm/hardware/iop3xx.h> diff --git a/arch/arm/mach-iop33x/iq80331.c b/arch/arm/mach-iop33x/iq80331.c index c43304a10fa7..e2cb65cfbe23 100644 --- a/arch/arm/mach-iop33x/iq80331.c +++ b/arch/arm/mach-iop33x/iq80331.c @@ -122,8 +122,15 @@ static struct platform_device iq80331_flash_device = { .resource = &iq80331_flash_resource, }; +static struct resource iq80331_gpio_res[] = { + DEFINE_RES_MEM((IOP3XX_PERIPHERAL_PHYS_BASE + 0x1780), 0x10), +}; + static void __init iq80331_init_machine(void) { + platform_device_register_simple("gpio-iop", 0, + iq80331_gpio_res, + ARRAY_SIZE(iq80331_gpio_res)); platform_device_register(&iop3xx_i2c0_device); platform_device_register(&iop3xx_i2c1_device); platform_device_register(&iop33x_uart0_device); diff --git a/arch/arm/mach-iop33x/iq80332.c b/arch/arm/mach-iop33x/iq80332.c index 8192987e78e5..0b6269d94f89 100644 --- a/arch/arm/mach-iop33x/iq80332.c +++ b/arch/arm/mach-iop33x/iq80332.c @@ -122,8 +122,15 @@ static struct platform_device iq80332_flash_device = { .resource = &iq80332_flash_resource, }; +static struct resource iq80332_gpio_res[] = { + DEFINE_RES_MEM((IOP3XX_PERIPHERAL_PHYS_BASE + 0x1780), 0x10), +}; + static void __init iq80332_init_machine(void) { + platform_device_register_simple("gpio-iop", 0, + iq80332_gpio_res, + ARRAY_SIZE(iq80332_gpio_res)); platform_device_register(&iop3xx_i2c0_device); platform_device_register(&iop3xx_i2c1_device); platform_device_register(&iop33x_uart0_device); diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index 5327decde5a0..9edaf4734fa8 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -81,6 +81,44 @@ void __init ixp4xx_map_io(void) iotable_init(ixp4xx_io_desc, ARRAY_SIZE(ixp4xx_io_desc)); } +/* + * GPIO-functions + */ +/* + * The following converted to the real HW bits the gpio_line_config + */ +/* GPIO pin types */ +#define IXP4XX_GPIO_OUT 0x1 +#define IXP4XX_GPIO_IN 0x2 + +/* GPIO signal types */ +#define IXP4XX_GPIO_LOW 0 +#define IXP4XX_GPIO_HIGH 1 + +/* GPIO Clocks */ +#define IXP4XX_GPIO_CLK_0 14 +#define IXP4XX_GPIO_CLK_1 15 + +static void gpio_line_config(u8 line, u32 direction) +{ + if (direction == IXP4XX_GPIO_IN) + *IXP4XX_GPIO_GPOER |= (1 << line); + else + *IXP4XX_GPIO_GPOER &= ~(1 << line); +} + +static void gpio_line_get(u8 line, int *value) +{ + *value = (*IXP4XX_GPIO_GPINR >> line) & 0x1; +} + +static void gpio_line_set(u8 line, int value) +{ + if (value == IXP4XX_GPIO_HIGH) + *IXP4XX_GPIO_GPOUTR |= (1 << line); + else if (value == IXP4XX_GPIO_LOW) + *IXP4XX_GPIO_GPOUTR &= ~(1 << line); +} /************************************************************************* * IXP4xx chipset IRQ handling @@ -117,17 +155,6 @@ static int ixp4xx_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) return -EINVAL; } -int irq_to_gpio(unsigned int irq) -{ - int gpio = (irq < 32) ? irq2gpio[irq] : -EINVAL; - - if (gpio == -1) - return -EINVAL; - - return gpio; -} -EXPORT_SYMBOL(irq_to_gpio); - static int ixp4xx_set_irq_type(struct irq_data *d, unsigned int type) { int line = irq2gpio[d->irq]; diff --git a/arch/arm/mach-ixp4xx/dsmg600-setup.c b/arch/arm/mach-ixp4xx/dsmg600-setup.c index 63de1b3fd06b..736dc692d540 100644 --- a/arch/arm/mach-ixp4xx/dsmg600-setup.c +++ b/arch/arm/mach-ixp4xx/dsmg600-setup.c @@ -26,6 +26,7 @@ #include <linux/reboot.h> #include <linux/i2c.h> #include <linux/i2c-gpio.h> +#include <linux/gpio.h> #include <mach/hardware.h> @@ -161,11 +162,8 @@ static struct platform_device *dsmg600_devices[] __initdata = { static void dsmg600_power_off(void) { - /* enable the pwr cntl gpio */ - gpio_line_config(DSMG600_PO_GPIO, IXP4XX_GPIO_OUT); - - /* poweroff */ - gpio_line_set(DSMG600_PO_GPIO, IXP4XX_GPIO_HIGH); + /* enable the pwr cntl and drive it high */ + gpio_direction_output(DSMG600_PO_GPIO, 1); } /* This is used to make sure the power-button pusher is serious. The button @@ -202,7 +200,7 @@ static void dsmg600_power_handler(unsigned long data) ctrl_alt_del(); /* Change the state of the power LED to "blink" */ - gpio_line_set(DSMG600_LED_PWR_GPIO, IXP4XX_GPIO_LOW); + gpio_set_value(DSMG600_LED_PWR_GPIO, 0); } else { power_button_countdown = PBUTTON_HOLDDOWN_COUNT; } @@ -228,6 +226,40 @@ static void __init dsmg600_timer_init(void) ixp4xx_timer_init(); } +static int __init dsmg600_gpio_init(void) +{ + if (!machine_is_dsmg600()) + return 0; + + gpio_request(DSMG600_RB_GPIO, "reset button"); + if (request_irq(gpio_to_irq(DSMG600_RB_GPIO), &dsmg600_reset_handler, + IRQF_DISABLED | IRQF_TRIGGER_LOW, + "DSM-G600 reset button", NULL) < 0) { + + printk(KERN_DEBUG "Reset Button IRQ %d not available\n", + gpio_to_irq(DSMG600_RB_GPIO)); + } + + /* + * The power button on the D-Link DSM-G600 is on GPIO 15, but + * it cannot handle interrupts on that GPIO line. So we'll + * have to poll it with a kernel timer. + */ + + /* Make sure that the power button GPIO is set up as an input */ + gpio_request(DSMG600_PB_GPIO, "power button"); + gpio_direction_input(DSMG600_PB_GPIO); + /* Request poweroff GPIO line */ + gpio_request(DSMG600_PO_GPIO, "power off button"); + + /* Set the initial value for the power button IRQ handler */ + power_button_countdown = PBUTTON_HOLDDOWN_COUNT; + + mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500)); + return 0; +} +device_initcall(dsmg600_gpio_init); + static void __init dsmg600_init(void) { ixp4xx_sys_init(); @@ -251,27 +283,6 @@ static void __init dsmg600_init(void) platform_add_devices(dsmg600_devices, ARRAY_SIZE(dsmg600_devices)); pm_power_off = dsmg600_power_off; - - if (request_irq(gpio_to_irq(DSMG600_RB_GPIO), &dsmg600_reset_handler, - IRQF_DISABLED | IRQF_TRIGGER_LOW, - "DSM-G600 reset button", NULL) < 0) { - - printk(KERN_DEBUG "Reset Button IRQ %d not available\n", - gpio_to_irq(DSMG600_RB_GPIO)); - } - - /* The power button on the D-Link DSM-G600 is on GPIO 15, but - * it cannot handle interrupts on that GPIO line. So we'll - * have to poll it with a kernel timer. - */ - - /* Make sure that the power button GPIO is set up as an input */ - gpio_line_config(DSMG600_PB_GPIO, IXP4XX_GPIO_IN); - - /* Set the initial value for the power button IRQ handler */ - power_button_countdown = PBUTTON_HOLDDOWN_COUNT; - - mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500)); } MACHINE_START(DSMG600, "D-Link DSM-G600 RevA") diff --git a/arch/arm/mach-ixp4xx/include/mach/platform.h b/arch/arm/mach-ixp4xx/include/mach/platform.h index 4c4c6a6f4526..75c4c6572ad0 100644 --- a/arch/arm/mach-ixp4xx/include/mach/platform.h +++ b/arch/arm/mach-ixp4xx/include/mach/platform.h @@ -131,44 +131,5 @@ struct pci_sys_data; extern int ixp4xx_setup(int nr, struct pci_sys_data *sys); extern struct pci_ops ixp4xx_ops; -/* - * GPIO-functions - */ -/* - * The following converted to the real HW bits the gpio_line_config - */ -/* GPIO pin types */ -#define IXP4XX_GPIO_OUT 0x1 -#define IXP4XX_GPIO_IN 0x2 - -/* GPIO signal types */ -#define IXP4XX_GPIO_LOW 0 -#define IXP4XX_GPIO_HIGH 1 - -/* GPIO Clocks */ -#define IXP4XX_GPIO_CLK_0 14 -#define IXP4XX_GPIO_CLK_1 15 - -static inline void gpio_line_config(u8 line, u32 direction) -{ - if (direction == IXP4XX_GPIO_IN) - *IXP4XX_GPIO_GPOER |= (1 << line); - else - *IXP4XX_GPIO_GPOER &= ~(1 << line); -} - -static inline void gpio_line_get(u8 line, int *value) -{ - *value = (*IXP4XX_GPIO_GPINR >> line) & 0x1; -} - -static inline void gpio_line_set(u8 line, int value) -{ - if (value == IXP4XX_GPIO_HIGH) - *IXP4XX_GPIO_GPOUTR |= (1 << line); - else if (value == IXP4XX_GPIO_LOW) - *IXP4XX_GPIO_GPOUTR &= ~(1 << line); -} - #endif // __ASSEMBLY__ diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c index 22d688b7d513..e7b8befa8729 100644 --- a/arch/arm/mach-ixp4xx/ixdp425-setup.c +++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c @@ -20,6 +20,7 @@ #include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> #include <linux/delay.h> +#include <linux/gpio.h> #include <asm/types.h> #include <asm/setup.h> #include <asm/memory.h> @@ -80,10 +81,10 @@ ixdp425_flash_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) if (ctrl & NAND_CTRL_CHANGE) { if (ctrl & NAND_NCE) { - gpio_line_set(IXDP425_NAND_NCE_PIN, IXP4XX_GPIO_LOW); + gpio_set_value(IXDP425_NAND_NCE_PIN, 0); udelay(5); } else - gpio_line_set(IXDP425_NAND_NCE_PIN, IXP4XX_GPIO_HIGH); + gpio_set_value(IXDP425_NAND_NCE_PIN, 1); offset = (ctrl & NAND_CLE) ? IXDP425_NAND_CMD_BYTE : 0; offset |= (ctrl & NAND_ALE) ? IXDP425_NAND_ADDR_BYTE : 0; @@ -227,7 +228,8 @@ static void __init ixdp425_init(void) ixdp425_flash_nand_resource.start = IXP4XX_EXP_BUS_BASE(3), ixdp425_flash_nand_resource.end = IXP4XX_EXP_BUS_BASE(3) + 0x10 - 1; - gpio_line_config(IXDP425_NAND_NCE_PIN, IXP4XX_GPIO_OUT); + gpio_request(IXDP425_NAND_NCE_PIN, "NAND NCE pin"); + gpio_direction_output(IXDP425_NAND_NCE_PIN, 0); /* Configure expansion bus for NAND Flash */ *IXP4XX_EXP_CS3 = IXP4XX_EXP_BUS_CS_EN | diff --git a/arch/arm/mach-ixp4xx/nas100d-setup.c b/arch/arm/mach-ixp4xx/nas100d-setup.c index ed667ce9f576..507cb5233537 100644 --- a/arch/arm/mach-ixp4xx/nas100d-setup.c +++ b/arch/arm/mach-ixp4xx/nas100d-setup.c @@ -184,11 +184,8 @@ static void nas100d_power_off(void) { /* This causes the box to drop the power and go dead. */ - /* enable the pwr cntl gpio */ - gpio_line_config(NAS100D_PO_GPIO, IXP4XX_GPIO_OUT); - - /* do the deed */ - gpio_line_set(NAS100D_PO_GPIO, IXP4XX_GPIO_HIGH); + /* enable the pwr cntl gpio and assert power off */ + gpio_direction_output(NAS100D_PO_GPIO, 1); } /* This is used to make sure the power-button pusher is serious. The button @@ -225,7 +222,7 @@ static void nas100d_power_handler(unsigned long data) ctrl_alt_del(); /* Change the state of the power LED to "blink" */ - gpio_line_set(NAS100D_LED_PWR_GPIO, IXP4XX_GPIO_LOW); + gpio_set_value(NAS100D_LED_PWR_GPIO, 0); } else { power_button_countdown = PBUTTON_HOLDDOWN_COUNT; } @@ -242,6 +239,33 @@ static irqreturn_t nas100d_reset_handler(int irq, void *dev_id) return IRQ_HANDLED; } +static int __init nas100d_gpio_init(void) +{ + if (!machine_is_nas100d()) + return 0; + + /* + * The power button on the Iomega NAS100d is on GPIO 14, but + * it cannot handle interrupts on that GPIO line. So we'll + * have to poll it with a kernel timer. + */ + + /* Request the power off GPIO */ + gpio_request(NAS100D_PO_GPIO, "power off"); + + /* Make sure that the power button GPIO is set up as an input */ + gpio_request(NAS100D_PB_GPIO, "power button"); + gpio_direction_input(NAS100D_PB_GPIO); + + /* Set the initial value for the power button IRQ handler */ + power_button_countdown = PBUTTON_HOLDDOWN_COUNT; + + mod_timer(&nas100d_power_timer, jiffies + msecs_to_jiffies(500)); + + return 0; +} +device_initcall(nas100d_gpio_init); + static void __init nas100d_init(void) { uint8_t __iomem *f; @@ -278,19 +302,6 @@ static void __init nas100d_init(void) gpio_to_irq(NAS100D_RB_GPIO)); } - /* The power button on the Iomega NAS100d is on GPIO 14, but - * it cannot handle interrupts on that GPIO line. So we'll - * have to poll it with a kernel timer. - */ - - /* Make sure that the power button GPIO is set up as an input */ - gpio_line_config(NAS100D_PB_GPIO, IXP4XX_GPIO_IN); - - /* Set the initial value for the power button IRQ handler */ - power_button_countdown = PBUTTON_HOLDDOWN_COUNT; - - mod_timer(&nas100d_power_timer, jiffies + msecs_to_jiffies(500)); - /* * Map in a portion of the flash and read the MAC address. * Since it is stored in BE in the flash itself, we need to diff --git a/arch/arm/mach-ixp4xx/nslu2-setup.c b/arch/arm/mach-ixp4xx/nslu2-setup.c index 7e55236c26ea..ba5f1cda2a9d 100644 --- a/arch/arm/mach-ixp4xx/nslu2-setup.c +++ b/arch/arm/mach-ixp4xx/nslu2-setup.c @@ -197,11 +197,8 @@ static void nslu2_power_off(void) { /* This causes the box to drop the power and go dead. */ - /* enable the pwr cntl gpio */ - gpio_line_config(NSLU2_PO_GPIO, IXP4XX_GPIO_OUT); - - /* do the deed */ - gpio_line_set(NSLU2_PO_GPIO, IXP4XX_GPIO_HIGH); + /* enable the pwr cntl gpio and assert power off */ + gpio_direction_output(NSLU2_PO_GPIO, 1); } static irqreturn_t nslu2_power_handler(int irq, void *dev_id) @@ -223,6 +220,16 @@ static irqreturn_t nslu2_reset_handler(int irq, void *dev_id) return IRQ_HANDLED; } +static int __init nslu2_gpio_init(void) +{ + if (!machine_is_nslu2()) + return 0; + + /* Request the power off GPIO */ + return gpio_request(NSLU2_PO_GPIO, "power off"); +} +device_initcall(nslu2_gpio_init); + static void __init nslu2_timer_init(void) { /* The xtal on this machine is non-standard. */ diff --git a/arch/arm/mach-mmp/include/mach/gpio.h b/arch/arm/mach-mmp/include/mach/gpio.h deleted file mode 100644 index 13219ebf5128..000000000000 --- a/arch/arm/mach-mmp/include/mach/gpio.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef __ASM_MACH_GPIO_H -#define __ASM_MACH_GPIO_H - -#include <asm-generic/gpio.h> - -#include <mach/cputype.h> - -#endif /* __ASM_MACH_GPIO_H */ diff --git a/arch/arm/mach-pxa/include/mach/gpio.h b/arch/arm/mach-pxa/include/mach/gpio.h deleted file mode 100644 index 0248e433bc98..000000000000 --- a/arch/arm/mach-pxa/include/mach/gpio.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * arch/arm/mach-pxa/include/mach/gpio.h - * - * PXA GPIO wrappers for arch-neutral GPIO calls - * - * Written by Philipp Zabel <philipp.zabel@gmail.com> - * - * 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 Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __ASM_ARCH_PXA_GPIO_H -#define __ASM_ARCH_PXA_GPIO_H - -#include <asm-generic/gpio.h> - -#include <mach/irqs.h> -#include <mach/hardware.h> - -#endif diff --git a/arch/arm/mach-w90x900/include/mach/gpio.h b/arch/arm/mach-w90x900/include/mach/gpio.h deleted file mode 100644 index 5385a4203277..000000000000 --- a/arch/arm/mach-w90x900/include/mach/gpio.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * linux/arch/arm/mach-w90p910/include/mach/gpio.h - * - * Generic w90p910 GPIO handling - * - * Wan ZongShun <mcuos.com@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __ASM_ARCH_W90P910_GPIO_H -#define __ASM_ARCH_W90P910_GPIO_H - -#include <mach/hardware.h> -#include <asm/irq.h> - -static inline int gpio_to_irq(unsigned gpio) -{ - return gpio; -} -#define gpio_to_irq gpio_to_irq - -static inline int irq_to_gpio(unsigned irq) -{ - return irq; -} - -#endif diff --git a/arch/arm/plat-iop/Makefile b/arch/arm/plat-iop/Makefile index a99dc15a70f7..224e56c6049b 100644 --- a/arch/arm/plat-iop/Makefile +++ b/arch/arm/plat-iop/Makefile @@ -5,7 +5,6 @@ obj-y := # IOP32X -obj-$(CONFIG_ARCH_IOP32X) += gpio.o obj-$(CONFIG_ARCH_IOP32X) += i2c.o obj-$(CONFIG_ARCH_IOP32X) += pci.o obj-$(CONFIG_ARCH_IOP32X) += setup.o @@ -16,7 +15,6 @@ obj-$(CONFIG_ARCH_IOP32X) += pmu.o obj-$(CONFIG_ARCH_IOP32X) += restart.o # IOP33X -obj-$(CONFIG_ARCH_IOP33X) += gpio.o obj-$(CONFIG_ARCH_IOP33X) += i2c.o obj-$(CONFIG_ARCH_IOP33X) += pci.o obj-$(CONFIG_ARCH_IOP33X) += setup.o diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 661ca82814e5..0f0444475bf0 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -30,10 +30,6 @@ config ARCH_REQUIRE_GPIOLIB Selecting this from the architecture code will cause the gpiolib code to always get built in. -config GPIO_DEVRES - def_bool y - depends on HAS_IOMEM - menuconfig GPIOLIB bool "GPIO Support" @@ -47,6 +43,10 @@ menuconfig GPIOLIB if GPIOLIB +config GPIO_DEVRES + def_bool y + depends on HAS_IOMEM + config OF_GPIO def_bool y depends on OF @@ -129,7 +129,7 @@ config GPIO_IT8761E config GPIO_EM tristate "Emma Mobile GPIO" - depends on ARM + depends on ARM && OF_GPIO help Say yes here to support GPIO on Renesas Emma Mobile SoCs. @@ -213,7 +213,7 @@ config GPIO_OCTEON config GPIO_PL061 bool "PrimeCell PL061 GPIO support" - depends on ARM && ARM_AMBA + depends on ARM_AMBA select GENERIC_IRQ_CHIP help Say yes here to support the PrimeCell PL061 GPIO device @@ -320,6 +320,15 @@ config GPIO_ICH If unsure, say N. +config GPIO_IOP + tristate "Intel IOP GPIO" + depends on ARM && (ARCH_IOP32X || ARCH_IOP33X) + help + Say yes here to support the GPIO functionality of a number of Intel + IOP32X or IOP33X. + + If unsure, say N. + config GPIO_VX855 tristate "VIA VX855/VX875 GPIO" depends on PCI @@ -616,12 +625,12 @@ config GPIO_AMD8111 If unsure, say N -config GPIO_LANGWELL - bool "Intel Langwell/Penwell GPIO support" +config GPIO_INTEL_MID + bool "Intel Mid GPIO support" depends on PCI && X86 select IRQ_DOMAIN help - Say Y here to support Intel Langwell/Penwell GPIO. + Say Y here to support Intel Mid GPIO. config GPIO_PCH tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7223/ML7831) GPIO" @@ -707,7 +716,7 @@ config GPIO_74X164 comment "AC97 GPIO expanders:" config GPIO_UCB1400 - bool "Philips UCB1400 GPIO" + tristate "Philips UCB1400 GPIO" depends on UCB1400_CORE help This enables support for the Philips UCB1400 GPIO pins. @@ -763,6 +772,12 @@ config GPIO_MSIC Enable support for GPIO on intel MSIC controllers found in intel MID devices +config GPIO_BCM_KONA + bool "Broadcom Kona GPIO" + depends on OF_GPIO + help + Turn on GPIO support for Broadcom "Kona" chips. + comment "USB GPIO expanders:" config GPIO_VIPERBOARD diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 2931c996e71f..7971e36b8b12 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o +obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o @@ -28,11 +29,12 @@ obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o obj-$(CONFIG_GPIO_ICH) += gpio-ich.o +obj-$(CONFIG_GPIO_IOP) += gpio-iop.o obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o -obj-$(CONFIG_GPIO_LANGWELL) += gpio-langwell.o +obj-$(CONFIG_GPIO_INTEL_MID) += gpio-intel-mid.o obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c index 3e7812f0405e..307464fd015f 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c @@ -15,10 +15,95 @@ */ #include <linux/module.h> +#include <linux/err.h> #include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/device.h> #include <linux/gfp.h> +static void devm_gpiod_release(struct device *dev, void *res) +{ + struct gpio_desc **desc = res; + + gpiod_put(*desc); +} + +static int devm_gpiod_match(struct device *dev, void *res, void *data) +{ + struct gpio_desc **this = res, **gpio = data; + + return *this == *gpio; +} + +/** + * devm_gpiod_get - Resource-managed gpiod_get() + * @dev: GPIO consumer + * @con_id: function within the GPIO consumer + * + * Managed gpiod_get(). GPIO descriptors returned from this function are + * automatically disposed on driver detach. See gpiod_get() for detailed + * information about behavior and return values. + */ +struct gpio_desc *__must_check devm_gpiod_get(struct device *dev, + const char *con_id) +{ + return devm_gpiod_get_index(dev, con_id, 0); +} +EXPORT_SYMBOL(devm_gpiod_get); + +/** + * devm_gpiod_get_index - Resource-managed gpiod_get_index() + * @dev: GPIO consumer + * @con_id: function within the GPIO consumer + * @idx: index of the GPIO to obtain in the consumer + * + * Managed gpiod_get_index(). GPIO descriptors returned from this function are + * automatically disposed on driver detach. See gpiod_get_index() for detailed + * information about behavior and return values. + */ +struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, + const char *con_id, + unsigned int idx) +{ + struct gpio_desc **dr; + struct gpio_desc *desc; + + dr = devres_alloc(devm_gpiod_release, sizeof(struct gpiod_desc *), + GFP_KERNEL); + if (!dr) + return ERR_PTR(-ENOMEM); + + desc = gpiod_get_index(dev, con_id, idx); + if (IS_ERR(desc)) { + devres_free(dr); + return desc; + } + + *dr = desc; + devres_add(dev, dr); + + return desc; +} +EXPORT_SYMBOL(devm_gpiod_get_index); + +/** + * devm_gpiod_put - Resource-managed gpiod_put() + * @desc: GPIO descriptor to dispose of + * + * Dispose of a GPIO descriptor obtained with devm_gpiod_get() or + * devm_gpiod_get_index(). Normally this function will not be called as the GPIO + * will be disposed of by the resource management code. + */ +void devm_gpiod_put(struct device *dev, struct gpio_desc *desc) +{ + WARN_ON(devres_release(dev, devm_gpiod_release, devm_gpiod_match, + &desc)); +} +EXPORT_SYMBOL(devm_gpiod_put); + + + + static void devm_gpio_release(struct device *dev, void *res) { unsigned *gpio = res; diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index 5d518d5db7a0..1e04bf91328d 100644 --- a/drivers/gpio/gpio-74x164.c +++ b/drivers/gpio/gpio-74x164.c @@ -176,7 +176,6 @@ static int gen_74x164_probe(struct spi_device *spi) return ret; exit_destroy: - spi_set_drvdata(spi, NULL); mutex_destroy(&chip->lock); return ret; } @@ -190,8 +189,6 @@ static int gen_74x164_remove(struct spi_device *spi) if (chip == NULL) return -ENODEV; - spi_set_drvdata(spi, NULL); - ret = gpiochip_remove(&chip->gpio_chip); if (!ret) mutex_destroy(&chip->lock); @@ -212,7 +209,7 @@ static struct spi_driver gen_74x164_driver = { .driver = { .name = "74x164", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(gen_74x164_dt_ids), + .of_match_table = gen_74x164_dt_ids, }, .probe = gen_74x164_probe, .remove = gen_74x164_remove, diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c index c0f3fc44ab0e..b204033acaeb 100644 --- a/drivers/gpio/gpio-adnp.c +++ b/drivers/gpio/gpio-adnp.c @@ -325,9 +325,9 @@ static irqreturn_t adnp_irq(int irq, void *data) pending &= isr & ier; for_each_set_bit(bit, &pending, 8) { - unsigned int virq; - virq = irq_find_mapping(adnp->domain, base + bit); - handle_nested_irq(virq); + unsigned int child_irq; + child_irq = irq_find_mapping(adnp->domain, base + bit); + handle_nested_irq(child_irq); } } @@ -594,7 +594,7 @@ static struct i2c_driver adnp_i2c_driver = { .driver = { .name = "gpio-adnp", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(adnp_of_match), + .of_match_table = adnp_of_match, }, .probe = adnp_i2c_probe, .remove = adnp_i2c_remove, diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c index fa8b6a762761..dceb5dcf9d16 100644 --- a/drivers/gpio/gpio-arizona.c +++ b/drivers/gpio/gpio-arizona.c @@ -109,10 +109,14 @@ static int arizona_gpio_probe(struct platform_device *pdev) arizona_gpio->arizona = arizona; arizona_gpio->gpio_chip = template_chip; arizona_gpio->gpio_chip.dev = &pdev->dev; +#ifdef CONFIG_OF_GPIO + arizona_gpio->gpio_chip.of_node = arizona->dev->of_node; +#endif switch (arizona->type) { case WM5102: case WM5110: + case WM8997: arizona_gpio->gpio_chip.ngpio = 5; break; default: diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c new file mode 100644 index 000000000000..72c927dc3be1 --- /dev/null +++ b/drivers/gpio/gpio-bcm-kona.c @@ -0,0 +1,640 @@ +/* + * Copyright (C) 2012-2013 Broadcom Corporation + * + * 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 Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/bitops.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/of_device.h> +#include <linux/of_irq.h> +#include <linux/module.h> +#include <linux/irqdomain.h> +#include <linux/irqchip/chained_irq.h> + +#define BCM_GPIO_PASSWD 0x00a5a501 +#define GPIO_PER_BANK 32 +#define GPIO_MAX_BANK_NUM 8 + +#define GPIO_BANK(gpio) ((gpio) >> 5) +#define GPIO_BIT(gpio) ((gpio) & (GPIO_PER_BANK - 1)) + +#define GPIO_OUT_STATUS(bank) (0x00000000 + ((bank) << 2)) +#define GPIO_IN_STATUS(bank) (0x00000020 + ((bank) << 2)) +#define GPIO_OUT_SET(bank) (0x00000040 + ((bank) << 2)) +#define GPIO_OUT_CLEAR(bank) (0x00000060 + ((bank) << 2)) +#define GPIO_INT_STATUS(bank) (0x00000080 + ((bank) << 2)) +#define GPIO_INT_MASK(bank) (0x000000a0 + ((bank) << 2)) +#define GPIO_INT_MSKCLR(bank) (0x000000c0 + ((bank) << 2)) +#define GPIO_CONTROL(bank) (0x00000100 + ((bank) << 2)) +#define GPIO_PWD_STATUS(bank) (0x00000500 + ((bank) << 2)) + +#define GPIO_GPPWR_OFFSET 0x00000520 + +#define GPIO_GPCTR0_DBR_SHIFT 5 +#define GPIO_GPCTR0_DBR_MASK 0x000001e0 + +#define GPIO_GPCTR0_ITR_SHIFT 3 +#define GPIO_GPCTR0_ITR_MASK 0x00000018 +#define GPIO_GPCTR0_ITR_CMD_RISING_EDGE 0x00000001 +#define GPIO_GPCTR0_ITR_CMD_FALLING_EDGE 0x00000002 +#define GPIO_GPCTR0_ITR_CMD_BOTH_EDGE 0x00000003 + +#define GPIO_GPCTR0_IOTR_MASK 0x00000001 +#define GPIO_GPCTR0_IOTR_CMD_0UTPUT 0x00000000 +#define GPIO_GPCTR0_IOTR_CMD_INPUT 0x00000001 + +#define GPIO_GPCTR0_DB_ENABLE_MASK 0x00000100 + +#define LOCK_CODE 0xffffffff +#define UNLOCK_CODE 0x00000000 + +struct bcm_kona_gpio { + void __iomem *reg_base; + int num_bank; + spinlock_t lock; + struct gpio_chip gpio_chip; + struct irq_domain *irq_domain; + struct bcm_kona_gpio_bank *banks; + struct platform_device *pdev; +}; + +struct bcm_kona_gpio_bank { + int id; + int irq; + /* Used in the interrupt handler */ + struct bcm_kona_gpio *kona_gpio; +}; + +static inline struct bcm_kona_gpio *to_kona_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct bcm_kona_gpio, gpio_chip); +} + +static void bcm_kona_gpio_set_lockcode_bank(void __iomem *reg_base, + int bank_id, int lockcode) +{ + writel(BCM_GPIO_PASSWD, reg_base + GPIO_GPPWR_OFFSET); + writel(lockcode, reg_base + GPIO_PWD_STATUS(bank_id)); +} + +static inline void bcm_kona_gpio_lock_bank(void __iomem *reg_base, int bank_id) +{ + bcm_kona_gpio_set_lockcode_bank(reg_base, bank_id, LOCK_CODE); +} + +static inline void bcm_kona_gpio_unlock_bank(void __iomem *reg_base, + int bank_id) +{ + bcm_kona_gpio_set_lockcode_bank(reg_base, bank_id, UNLOCK_CODE); +} + +static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) +{ + struct bcm_kona_gpio *kona_gpio; + void __iomem *reg_base; + int bank_id = GPIO_BANK(gpio); + int bit = GPIO_BIT(gpio); + u32 val, reg_offset; + unsigned long flags; + + kona_gpio = to_kona_gpio(chip); + reg_base = kona_gpio->reg_base; + spin_lock_irqsave(&kona_gpio->lock, flags); + bcm_kona_gpio_unlock_bank(reg_base, bank_id); + + /* determine the GPIO pin direction */ + val = readl(reg_base + GPIO_CONTROL(gpio)); + val &= GPIO_GPCTR0_IOTR_MASK; + + /* this function only applies to output pin */ + if (GPIO_GPCTR0_IOTR_CMD_INPUT == val) + goto out; + + reg_offset = value ? GPIO_OUT_SET(bank_id) : GPIO_OUT_CLEAR(bank_id); + + val = readl(reg_base + reg_offset); + val |= BIT(bit); + writel(val, reg_base + reg_offset); + +out: + bcm_kona_gpio_lock_bank(reg_base, bank_id); + spin_unlock_irqrestore(&kona_gpio->lock, flags); +} + +static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio) +{ + struct bcm_kona_gpio *kona_gpio; + void __iomem *reg_base; + int bank_id = GPIO_BANK(gpio); + int bit = GPIO_BIT(gpio); + u32 val, reg_offset; + unsigned long flags; + + kona_gpio = to_kona_gpio(chip); + reg_base = kona_gpio->reg_base; + spin_lock_irqsave(&kona_gpio->lock, flags); + bcm_kona_gpio_unlock_bank(reg_base, bank_id); + + /* determine the GPIO pin direction */ + val = readl(reg_base + GPIO_CONTROL(gpio)); + val &= GPIO_GPCTR0_IOTR_MASK; + + /* read the GPIO bank status */ + reg_offset = (GPIO_GPCTR0_IOTR_CMD_INPUT == val) ? + GPIO_IN_STATUS(bank_id) : GPIO_OUT_STATUS(bank_id); + val = readl(reg_base + reg_offset); + + bcm_kona_gpio_lock_bank(reg_base, bank_id); + spin_unlock_irqrestore(&kona_gpio->lock, flags); + + /* return the specified bit status */ + return !!(val & bit); +} + +static int bcm_kona_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) +{ + struct bcm_kona_gpio *kona_gpio; + void __iomem *reg_base; + u32 val; + unsigned long flags; + int bank_id = GPIO_BANK(gpio); + + kona_gpio = to_kona_gpio(chip); + reg_base = kona_gpio->reg_base; + spin_lock_irqsave(&kona_gpio->lock, flags); + bcm_kona_gpio_unlock_bank(reg_base, bank_id); + + val = readl(reg_base + GPIO_CONTROL(gpio)); + val &= ~GPIO_GPCTR0_IOTR_MASK; + val |= GPIO_GPCTR0_IOTR_CMD_INPUT; + writel(val, reg_base + GPIO_CONTROL(gpio)); + + bcm_kona_gpio_lock_bank(reg_base, bank_id); + spin_unlock_irqrestore(&kona_gpio->lock, flags); + + return 0; +} + +static int bcm_kona_gpio_direction_output(struct gpio_chip *chip, + unsigned gpio, int value) +{ + struct bcm_kona_gpio *kona_gpio; + void __iomem *reg_base; + int bank_id = GPIO_BANK(gpio); + int bit = GPIO_BIT(gpio); + u32 val, reg_offset; + unsigned long flags; + + kona_gpio = to_kona_gpio(chip); + reg_base = kona_gpio->reg_base; + spin_lock_irqsave(&kona_gpio->lock, flags); + bcm_kona_gpio_unlock_bank(reg_base, bank_id); + + val = readl(reg_base + GPIO_CONTROL(gpio)); + val &= ~GPIO_GPCTR0_IOTR_MASK; + val |= GPIO_GPCTR0_IOTR_CMD_0UTPUT; + writel(val, reg_base + GPIO_CONTROL(gpio)); + reg_offset = value ? GPIO_OUT_SET(bank_id) : GPIO_OUT_CLEAR(bank_id); + + val = readl(reg_base + reg_offset); + val |= BIT(bit); + writel(val, reg_base + reg_offset); + + bcm_kona_gpio_lock_bank(reg_base, bank_id); + spin_unlock_irqrestore(&kona_gpio->lock, flags); + + return 0; +} + +static int bcm_kona_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) +{ + struct bcm_kona_gpio *kona_gpio; + + kona_gpio = to_kona_gpio(chip); + if (gpio >= kona_gpio->gpio_chip.ngpio) + return -ENXIO; + return irq_create_mapping(kona_gpio->irq_domain, gpio); +} + +static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio, + unsigned debounce) +{ + struct bcm_kona_gpio *kona_gpio; + void __iomem *reg_base; + u32 val, res; + unsigned long flags; + int bank_id = GPIO_BANK(gpio); + + kona_gpio = to_kona_gpio(chip); + reg_base = kona_gpio->reg_base; + /* debounce must be 1-128ms (or 0) */ + if ((debounce > 0 && debounce < 1000) || debounce > 128000) { + dev_err(chip->dev, "Debounce value %u not in range\n", + debounce); + return -EINVAL; + } + + /* calculate debounce bit value */ + if (debounce != 0) { + /* Convert to ms */ + debounce /= 1000; + /* find the MSB */ + res = fls(debounce) - 1; + /* Check if MSB-1 is set (round up or down) */ + if (res > 0 && (debounce & BIT(res - 1))) + res++; + } + + /* spin lock for read-modify-write of the GPIO register */ + spin_lock_irqsave(&kona_gpio->lock, flags); + bcm_kona_gpio_unlock_bank(reg_base, bank_id); + + val = readl(reg_base + GPIO_CONTROL(gpio)); + val &= ~GPIO_GPCTR0_DBR_MASK; + + if (debounce == 0) { + /* disable debounce */ + val &= ~GPIO_GPCTR0_DB_ENABLE_MASK; + } else { + val |= GPIO_GPCTR0_DB_ENABLE_MASK | + (res << GPIO_GPCTR0_DBR_SHIFT); + } + + writel(val, reg_base + GPIO_CONTROL(gpio)); + + bcm_kona_gpio_lock_bank(reg_base, bank_id); + spin_unlock_irqrestore(&kona_gpio->lock, flags); + + return 0; +} + +static struct gpio_chip template_chip = { + .label = "bcm-kona-gpio", + .owner = THIS_MODULE, + .direction_input = bcm_kona_gpio_direction_input, + .get = bcm_kona_gpio_get, + .direction_output = bcm_kona_gpio_direction_output, + .set = bcm_kona_gpio_set, + .set_debounce = bcm_kona_gpio_set_debounce, + .to_irq = bcm_kona_gpio_to_irq, + .base = 0, +}; + +static void bcm_kona_gpio_irq_ack(struct irq_data *d) +{ + struct bcm_kona_gpio *kona_gpio; + void __iomem *reg_base; + int gpio = d->hwirq; + int bank_id = GPIO_BANK(gpio); + int bit = GPIO_BIT(gpio); + u32 val; + unsigned long flags; + + kona_gpio = irq_data_get_irq_chip_data(d); + reg_base = kona_gpio->reg_base; + spin_lock_irqsave(&kona_gpio->lock, flags); + bcm_kona_gpio_unlock_bank(reg_base, bank_id); + + val = readl(reg_base + GPIO_INT_STATUS(bank_id)); + val |= BIT(bit); + writel(val, reg_base + GPIO_INT_STATUS(bank_id)); + + bcm_kona_gpio_lock_bank(reg_base, bank_id); + spin_unlock_irqrestore(&kona_gpio->lock, flags); +} + +static void bcm_kona_gpio_irq_mask(struct irq_data *d) +{ + struct bcm_kona_gpio *kona_gpio; + void __iomem *reg_base; + int gpio = d->hwirq; + int bank_id = GPIO_BANK(gpio); + int bit = GPIO_BIT(gpio); + u32 val; + unsigned long flags; + + kona_gpio = irq_data_get_irq_chip_data(d); + reg_base = kona_gpio->reg_base; + spin_lock_irqsave(&kona_gpio->lock, flags); + bcm_kona_gpio_unlock_bank(reg_base, bank_id); + + val = readl(reg_base + GPIO_INT_MASK(bank_id)); + val |= BIT(bit); + writel(val, reg_base + GPIO_INT_MASK(bank_id)); + + bcm_kona_gpio_lock_bank(reg_base, bank_id); + spin_unlock_irqrestore(&kona_gpio->lock, flags); +} + +static void bcm_kona_gpio_irq_unmask(struct irq_data *d) +{ + struct bcm_kona_gpio *kona_gpio; + void __iomem *reg_base; + int gpio = d->hwirq; + int bank_id = GPIO_BANK(gpio); + int bit = GPIO_BIT(gpio); + u32 val; + unsigned long flags; + + kona_gpio = irq_data_get_irq_chip_data(d); + reg_base = kona_gpio->reg_base; + spin_lock_irqsave(&kona_gpio->lock, flags); + bcm_kona_gpio_unlock_bank(reg_base, bank_id); + + val = readl(reg_base + GPIO_INT_MSKCLR(bank_id)); + val |= BIT(bit); + writel(val, reg_base + GPIO_INT_MSKCLR(bank_id)); + + bcm_kona_gpio_lock_bank(reg_base, bank_id); + spin_unlock_irqrestore(&kona_gpio->lock, flags); +} + +static int bcm_kona_gpio_irq_set_type(struct irq_data *d, unsigned int type) +{ + struct bcm_kona_gpio *kona_gpio; + void __iomem *reg_base; + int gpio = d->hwirq; + u32 lvl_type; + u32 val; + unsigned long flags; + int bank_id = GPIO_BANK(gpio); + + kona_gpio = irq_data_get_irq_chip_data(d); + reg_base = kona_gpio->reg_base; + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_RISING: + lvl_type = GPIO_GPCTR0_ITR_CMD_RISING_EDGE; + break; + + case IRQ_TYPE_EDGE_FALLING: + lvl_type = GPIO_GPCTR0_ITR_CMD_FALLING_EDGE; + break; + + case IRQ_TYPE_EDGE_BOTH: + lvl_type = GPIO_GPCTR0_ITR_CMD_BOTH_EDGE; + break; + + case IRQ_TYPE_LEVEL_HIGH: + case IRQ_TYPE_LEVEL_LOW: + /* BCM GPIO doesn't support level triggering */ + default: + dev_err(kona_gpio->gpio_chip.dev, + "Invalid BCM GPIO irq type 0x%x\n", type); + return -EINVAL; + } + + spin_lock_irqsave(&kona_gpio->lock, flags); + bcm_kona_gpio_unlock_bank(reg_base, bank_id); + + val = readl(reg_base + GPIO_CONTROL(gpio)); + val &= ~GPIO_GPCTR0_ITR_MASK; + val |= lvl_type << GPIO_GPCTR0_ITR_SHIFT; + writel(val, reg_base + GPIO_CONTROL(gpio)); + + bcm_kona_gpio_lock_bank(reg_base, bank_id); + spin_unlock_irqrestore(&kona_gpio->lock, flags); + + return 0; +} + +static void bcm_kona_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + void __iomem *reg_base; + int bit, bank_id; + unsigned long sta; + struct bcm_kona_gpio_bank *bank = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + + chained_irq_enter(chip, desc); + + /* + * For bank interrupts, we can't use chip_data to store the kona_gpio + * pointer, since GIC needs it for its own purposes. Therefore, we get + * our pointer from the bank structure. + */ + reg_base = bank->kona_gpio->reg_base; + bank_id = bank->id; + bcm_kona_gpio_unlock_bank(reg_base, bank_id); + + while ((sta = readl(reg_base + GPIO_INT_STATUS(bank_id)) & + (~(readl(reg_base + GPIO_INT_MASK(bank_id)))))) { + for_each_set_bit(bit, &sta, 32) { + int hwirq = GPIO_PER_BANK * bank_id + bit; + int child_irq = + irq_find_mapping(bank->kona_gpio->irq_domain, + hwirq); + /* + * Clear interrupt before handler is called so we don't + * miss any interrupt occurred during executing them. + */ + writel(readl(reg_base + GPIO_INT_STATUS(bank_id)) | + BIT(bit), reg_base + GPIO_INT_STATUS(bank_id)); + /* Invoke interrupt handler */ + generic_handle_irq(child_irq); + } + } + + bcm_kona_gpio_lock_bank(reg_base, bank_id); + + chained_irq_exit(chip, desc); +} + +static struct irq_chip bcm_gpio_irq_chip = { + .name = "bcm-kona-gpio", + .irq_ack = bcm_kona_gpio_irq_ack, + .irq_mask = bcm_kona_gpio_irq_mask, + .irq_unmask = bcm_kona_gpio_irq_unmask, + .irq_set_type = bcm_kona_gpio_irq_set_type, +}; + +static struct __initconst of_device_id bcm_kona_gpio_of_match[] = { + { .compatible = "brcm,kona-gpio" }, + {} +}; + +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. + */ +static struct lock_class_key gpio_lock_class; + +static int bcm_kona_gpio_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + int ret; + + ret = irq_set_chip_data(irq, d->host_data); + if (ret < 0) + return ret; + irq_set_lockdep_class(irq, &gpio_lock_class); + irq_set_chip_and_handler(irq, &bcm_gpio_irq_chip, handle_simple_irq); +#ifdef CONFIG_ARM + set_irq_flags(irq, IRQF_VALID); +#else + irq_set_noprobe(irq); +#endif + + return 0; +} + +static void bcm_kona_gpio_irq_unmap(struct irq_domain *d, unsigned int irq) +{ + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); +} + +static struct irq_domain_ops bcm_kona_irq_ops = { + .map = bcm_kona_gpio_irq_map, + .unmap = bcm_kona_gpio_irq_unmap, + .xlate = irq_domain_xlate_twocell, +}; + +static void bcm_kona_gpio_reset(struct bcm_kona_gpio *kona_gpio) +{ + void __iomem *reg_base; + int i; + + reg_base = kona_gpio->reg_base; + /* disable interrupts and clear status */ + for (i = 0; i < kona_gpio->num_bank; i++) { + bcm_kona_gpio_unlock_bank(reg_base, i); + writel(0xffffffff, reg_base + GPIO_INT_MASK(i)); + writel(0xffffffff, reg_base + GPIO_INT_STATUS(i)); + bcm_kona_gpio_lock_bank(reg_base, i); + } +} + +static int bcm_kona_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct of_device_id *match; + struct resource *res; + struct bcm_kona_gpio_bank *bank; + struct bcm_kona_gpio *kona_gpio; + struct gpio_chip *chip; + int ret; + int i; + + match = of_match_device(bcm_kona_gpio_of_match, dev); + if (!match) { + dev_err(dev, "Failed to find gpio controller\n"); + return -ENODEV; + } + + kona_gpio = devm_kzalloc(dev, sizeof(*kona_gpio), GFP_KERNEL); + if (!kona_gpio) + return -ENOMEM; + + kona_gpio->gpio_chip = template_chip; + chip = &kona_gpio->gpio_chip; + kona_gpio->num_bank = of_irq_count(dev->of_node); + if (kona_gpio->num_bank == 0) { + dev_err(dev, "Couldn't determine # GPIO banks\n"); + return -ENOENT; + } + if (kona_gpio->num_bank > GPIO_MAX_BANK_NUM) { + dev_err(dev, "Too many GPIO banks configured (max=%d)\n", + GPIO_MAX_BANK_NUM); + return -ENXIO; + } + kona_gpio->banks = devm_kzalloc(dev, + kona_gpio->num_bank * + sizeof(*kona_gpio->banks), GFP_KERNEL); + if (!kona_gpio->banks) + return -ENOMEM; + + kona_gpio->pdev = pdev; + platform_set_drvdata(pdev, kona_gpio); + chip->of_node = dev->of_node; + chip->ngpio = kona_gpio->num_bank * GPIO_PER_BANK; + + kona_gpio->irq_domain = irq_domain_add_linear(dev->of_node, + chip->ngpio, + &bcm_kona_irq_ops, + kona_gpio); + if (!kona_gpio->irq_domain) { + dev_err(dev, "Couldn't allocate IRQ domain\n"); + return -ENXIO; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + kona_gpio->reg_base = devm_ioremap_resource(dev, res); + if (IS_ERR(kona_gpio->reg_base)) { + ret = -ENXIO; + goto err_irq_domain; + } + + for (i = 0; i < kona_gpio->num_bank; i++) { + bank = &kona_gpio->banks[i]; + bank->id = i; + bank->irq = platform_get_irq(pdev, i); + bank->kona_gpio = kona_gpio; + if (bank->irq < 0) { + dev_err(dev, "Couldn't get IRQ for bank %d", i); + ret = -ENOENT; + goto err_irq_domain; + } + } + + dev_info(&pdev->dev, "Setting up Kona GPIO\n"); + + bcm_kona_gpio_reset(kona_gpio); + + ret = gpiochip_add(chip); + if (ret < 0) { + dev_err(dev, "Couldn't add GPIO chip -- %d\n", ret); + goto err_irq_domain; + } + for (i = 0; i < chip->ngpio; i++) { + int irq = bcm_kona_gpio_to_irq(chip, i); + irq_set_lockdep_class(irq, &gpio_lock_class); + irq_set_chip_and_handler(irq, &bcm_gpio_irq_chip, + handle_simple_irq); +#ifdef CONFIG_ARM + set_irq_flags(irq, IRQF_VALID); +#else + irq_set_noprobe(irq); +#endif + } + for (i = 0; i < kona_gpio->num_bank; i++) { + bank = &kona_gpio->banks[i]; + irq_set_chained_handler(bank->irq, bcm_kona_gpio_irq_handler); + irq_set_handler_data(bank->irq, bank); + } + + spin_lock_init(&kona_gpio->lock); + + return 0; + +err_irq_domain: + irq_domain_remove(kona_gpio->irq_domain); + + return ret; +} + +static struct platform_driver bcm_kona_gpio_driver = { + .driver = { + .name = "bcm-kona-gpio", + .owner = THIS_MODULE, + .of_match_table = bcm_kona_gpio_of_match, + }, + .probe = bcm_kona_gpio_probe, +}; + +module_platform_driver(bcm_kona_gpio_driver); + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("Broadcom Kona GPIO Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-bt8xx.c b/drivers/gpio/gpio-bt8xx.c index 8369e71ebe4f..9dfe36fd8baf 100644 --- a/drivers/gpio/gpio-bt8xx.c +++ b/drivers/gpio/gpio-bt8xx.c @@ -228,7 +228,6 @@ static int bt8xxgpio_probe(struct pci_dev *dev, err_release_mem: release_mem_region(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); - pci_set_drvdata(dev, NULL); err_disable: pci_disable_device(dev); err_freebg: @@ -252,7 +251,6 @@ static void bt8xxgpio_remove(struct pci_dev *pdev) pci_resource_len(pdev, 0)); pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); kfree(bg); } diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c index 0edaf2ce9266..0924f20fa47f 100644 --- a/drivers/gpio/gpio-clps711x.c +++ b/drivers/gpio/gpio-clps711x.c @@ -87,7 +87,7 @@ static struct platform_driver clps711x_gpio_driver = { .driver = { .name = "clps711x-gpio", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(clps711x_gpio_ids), + .of_match_table = clps711x_gpio_ids, }, .probe = clps711x_gpio_probe, .remove = clps711x_gpio_remove, diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index c6e1f086efe8..ec190361bf2e 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -232,16 +232,16 @@ static void em_gio_free(struct gpio_chip *chip, unsigned offset) em_gio_direction_input(chip, offset); } -static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw) +static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int irq, + irq_hw_number_t hwirq) { struct em_gio_priv *p = h->host_data; - pr_debug("gio: map hw irq = %d, virq = %d\n", (int)hw, virq); + pr_debug("gio: map hw irq = %d, irq = %d\n", (int)hwirq, irq); - irq_set_chip_data(virq, h->host_data); - irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq); - set_irq_flags(virq, IRQF_VALID); /* kill me now */ + irq_set_chip_data(irq, h->host_data); + irq_set_chip_and_handler(irq, &p->irq_chip, handle_level_irq); + set_irq_flags(irq, IRQF_VALID); /* kill me now */ return 0; } @@ -319,6 +319,7 @@ static int em_gio_probe(struct platform_device *pdev) } gpio_chip = &p->gpio_chip; + gpio_chip->of_node = pdev->dev.of_node; gpio_chip->direction_input = em_gio_direction_input; gpio_chip->get = em_gio_get; gpio_chip->direction_output = em_gio_direction_output; diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 56b98eebe1fc..80829f3c6543 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -51,15 +51,15 @@ static void ep93xx_gpio_update_int_params(unsigned port) { BUG_ON(port > 2); - __raw_writeb(0, EP93XX_GPIO_REG(int_en_register_offset[port])); + writeb_relaxed(0, EP93XX_GPIO_REG(int_en_register_offset[port])); - __raw_writeb(gpio_int_type2[port], + writeb_relaxed(gpio_int_type2[port], EP93XX_GPIO_REG(int_type2_register_offset[port])); - __raw_writeb(gpio_int_type1[port], + writeb_relaxed(gpio_int_type1[port], EP93XX_GPIO_REG(int_type1_register_offset[port])); - __raw_writeb(gpio_int_unmasked[port] & gpio_int_enabled[port], + writeb(gpio_int_unmasked[port] & gpio_int_enabled[port], EP93XX_GPIO_REG(int_en_register_offset[port])); } @@ -74,7 +74,7 @@ static void ep93xx_gpio_int_debounce(unsigned int irq, bool enable) else gpio_int_debounce[port] &= ~port_mask; - __raw_writeb(gpio_int_debounce[port], + writeb(gpio_int_debounce[port], EP93XX_GPIO_REG(int_debounce_register_offset[port])); } @@ -83,7 +83,7 @@ static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc) unsigned char status; int i; - status = __raw_readb(EP93XX_GPIO_A_INT_STATUS); + status = readb(EP93XX_GPIO_A_INT_STATUS); for (i = 0; i < 8; i++) { if (status & (1 << i)) { int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_A(0)) + i; @@ -91,7 +91,7 @@ static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc) } } - status = __raw_readb(EP93XX_GPIO_B_INT_STATUS); + status = readb(EP93XX_GPIO_B_INT_STATUS); for (i = 0; i < 8; i++) { if (status & (1 << i)) { int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_B(0)) + i; @@ -124,7 +124,7 @@ static void ep93xx_gpio_irq_ack(struct irq_data *d) ep93xx_gpio_update_int_params(port); } - __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); + writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); } static void ep93xx_gpio_irq_mask_ack(struct irq_data *d) @@ -139,7 +139,7 @@ static void ep93xx_gpio_irq_mask_ack(struct irq_data *d) gpio_int_unmasked[port] &= ~port_mask; ep93xx_gpio_update_int_params(port); - __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); + writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); } static void ep93xx_gpio_irq_mask(struct irq_data *d) diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c new file mode 100644 index 000000000000..be803af658ac --- /dev/null +++ b/drivers/gpio/gpio-intel-mid.c @@ -0,0 +1,471 @@ +/* + * Moorestown platform Langwell chip GPIO driver + * + * Copyright (c) 2008, 2009, 2013, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* Supports: + * Moorestown platform Langwell chip. + * Medfield platform Penwell chip. + * Clovertrail platform Cloverview chip. + * Merrifield platform Tangier chip. + */ + +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/platform_device.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/stddef.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/slab.h> +#include <linux/pm_runtime.h> +#include <linux/irqdomain.h> + +#define INTEL_MID_IRQ_TYPE_EDGE (1 << 0) +#define INTEL_MID_IRQ_TYPE_LEVEL (1 << 1) + +/* + * Langwell chip has 64 pins and thus there are 2 32bit registers to control + * each feature, while Penwell chip has 96 pins for each block, and need 3 32bit + * registers to control them, so we only define the order here instead of a + * structure, to get a bit offset for a pin (use GPDR as an example): + * + * nreg = ngpio / 32; + * reg = offset / 32; + * bit = offset % 32; + * reg_addr = reg_base + GPDR * nreg * 4 + reg * 4; + * + * so the bit of reg_addr is to control pin offset's GPDR feature +*/ + +enum GPIO_REG { + GPLR = 0, /* pin level read-only */ + GPDR, /* pin direction */ + GPSR, /* pin set */ + GPCR, /* pin clear */ + GRER, /* rising edge detect */ + GFER, /* falling edge detect */ + GEDR, /* edge detect result */ + GAFR, /* alt function */ +}; + +/* intel_mid gpio driver data */ +struct intel_mid_gpio_ddata { + u16 ngpio; /* number of gpio pins */ + u32 gplr_offset; /* offset of first GPLR register from base */ + u32 flis_base; /* base address of FLIS registers */ + u32 flis_len; /* length of FLIS registers */ + u32 (*get_flis_offset)(int gpio); + u32 chip_irq_type; /* chip interrupt type */ +}; + +struct intel_mid_gpio { + struct gpio_chip chip; + void __iomem *reg_base; + spinlock_t lock; + struct pci_dev *pdev; + struct irq_domain *domain; +}; + +#define to_intel_gpio_priv(chip) container_of(chip, struct intel_mid_gpio, chip) + +static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset, + enum GPIO_REG reg_type) +{ + struct intel_mid_gpio *priv = to_intel_gpio_priv(chip); + unsigned nreg = chip->ngpio / 32; + u8 reg = offset / 32; + + return priv->reg_base + reg_type * nreg * 4 + reg * 4; +} + +static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset, + enum GPIO_REG reg_type) +{ + struct intel_mid_gpio *priv = to_intel_gpio_priv(chip); + unsigned nreg = chip->ngpio / 32; + u8 reg = offset / 16; + + return priv->reg_base + reg_type * nreg * 4 + reg * 4; +} + +static int intel_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + void __iomem *gafr = gpio_reg_2bit(chip, offset, GAFR); + u32 value = readl(gafr); + int shift = (offset % 16) << 1, af = (value >> shift) & 3; + + if (af) { + value &= ~(3 << shift); + writel(value, gafr); + } + return 0; +} + +static int intel_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + void __iomem *gplr = gpio_reg(chip, offset, GPLR); + + return readl(gplr) & BIT(offset % 32); +} + +static void intel_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + void __iomem *gpsr, *gpcr; + + if (value) { + gpsr = gpio_reg(chip, offset, GPSR); + writel(BIT(offset % 32), gpsr); + } else { + gpcr = gpio_reg(chip, offset, GPCR); + writel(BIT(offset % 32), gpcr); + } +} + +static int intel_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct intel_mid_gpio *priv = to_intel_gpio_priv(chip); + void __iomem *gpdr = gpio_reg(chip, offset, GPDR); + u32 value; + unsigned long flags; + + if (priv->pdev) + pm_runtime_get(&priv->pdev->dev); + + spin_lock_irqsave(&priv->lock, flags); + value = readl(gpdr); + value &= ~BIT(offset % 32); + writel(value, gpdr); + spin_unlock_irqrestore(&priv->lock, flags); + + if (priv->pdev) + pm_runtime_put(&priv->pdev->dev); + + return 0; +} + +static int intel_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct intel_mid_gpio *priv = to_intel_gpio_priv(chip); + void __iomem *gpdr = gpio_reg(chip, offset, GPDR); + unsigned long flags; + + intel_gpio_set(chip, offset, value); + + if (priv->pdev) + pm_runtime_get(&priv->pdev->dev); + + spin_lock_irqsave(&priv->lock, flags); + value = readl(gpdr); + value |= BIT(offset % 32); + writel(value, gpdr); + spin_unlock_irqrestore(&priv->lock, flags); + + if (priv->pdev) + pm_runtime_put(&priv->pdev->dev); + + return 0; +} + +static int intel_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct intel_mid_gpio *priv = to_intel_gpio_priv(chip); + return irq_create_mapping(priv->domain, offset); +} + +static int intel_mid_irq_type(struct irq_data *d, unsigned type) +{ + struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d); + u32 gpio = irqd_to_hwirq(d); + unsigned long flags; + u32 value; + void __iomem *grer = gpio_reg(&priv->chip, gpio, GRER); + void __iomem *gfer = gpio_reg(&priv->chip, gpio, GFER); + + if (gpio >= priv->chip.ngpio) + return -EINVAL; + + if (priv->pdev) + pm_runtime_get(&priv->pdev->dev); + + spin_lock_irqsave(&priv->lock, flags); + if (type & IRQ_TYPE_EDGE_RISING) + value = readl(grer) | BIT(gpio % 32); + else + value = readl(grer) & (~BIT(gpio % 32)); + writel(value, grer); + + if (type & IRQ_TYPE_EDGE_FALLING) + value = readl(gfer) | BIT(gpio % 32); + else + value = readl(gfer) & (~BIT(gpio % 32)); + writel(value, gfer); + spin_unlock_irqrestore(&priv->lock, flags); + + if (priv->pdev) + pm_runtime_put(&priv->pdev->dev); + + return 0; +} + +static void intel_mid_irq_unmask(struct irq_data *d) +{ +} + +static void intel_mid_irq_mask(struct irq_data *d) +{ +} + +static struct irq_chip intel_mid_irqchip = { + .name = "INTEL_MID-GPIO", + .irq_mask = intel_mid_irq_mask, + .irq_unmask = intel_mid_irq_unmask, + .irq_set_type = intel_mid_irq_type, +}; + +static const struct intel_mid_gpio_ddata gpio_lincroft = { + .ngpio = 64, +}; + +static const struct intel_mid_gpio_ddata gpio_penwell_aon = { + .ngpio = 96, + .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE, +}; + +static const struct intel_mid_gpio_ddata gpio_penwell_core = { + .ngpio = 96, + .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE, +}; + +static const struct intel_mid_gpio_ddata gpio_cloverview_aon = { + .ngpio = 96, + .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE | INTEL_MID_IRQ_TYPE_LEVEL, +}; + +static const struct intel_mid_gpio_ddata gpio_cloverview_core = { + .ngpio = 96, + .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE, +}; + +static const struct intel_mid_gpio_ddata gpio_tangier = { + .ngpio = 192, + .gplr_offset = 4, + .flis_base = 0xff0c0000, + .flis_len = 0x8000, + .get_flis_offset = NULL, + .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE, +}; + +static DEFINE_PCI_DEVICE_TABLE(intel_gpio_ids) = { + { + /* Lincroft */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f), + .driver_data = (kernel_ulong_t)&gpio_lincroft, + }, + { + /* Penwell AON */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081f), + .driver_data = (kernel_ulong_t)&gpio_penwell_aon, + }, + { + /* Penwell Core */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081a), + .driver_data = (kernel_ulong_t)&gpio_penwell_core, + }, + { + /* Cloverview Aon */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08eb), + .driver_data = (kernel_ulong_t)&gpio_cloverview_aon, + }, + { + /* Cloverview Core */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08f7), + .driver_data = (kernel_ulong_t)&gpio_cloverview_core, + }, + { + /* Tangier */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x1199), + .driver_data = (kernel_ulong_t)&gpio_tangier, + }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, intel_gpio_ids); + +static void intel_mid_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct irq_data *data = irq_desc_get_irq_data(desc); + struct intel_mid_gpio *priv = irq_data_get_irq_handler_data(data); + struct irq_chip *chip = irq_data_get_irq_chip(data); + u32 base, gpio, mask; + unsigned long pending; + void __iomem *gedr; + + /* check GPIO controller to check which pin triggered the interrupt */ + for (base = 0; base < priv->chip.ngpio; base += 32) { + gedr = gpio_reg(&priv->chip, base, GEDR); + while ((pending = readl(gedr))) { + gpio = __ffs(pending); + mask = BIT(gpio); + /* Clear before handling so we can't lose an edge */ + writel(mask, gedr); + generic_handle_irq(irq_find_mapping(priv->domain, + base + gpio)); + } + } + + chip->irq_eoi(data); +} + +static void intel_mid_irq_init_hw(struct intel_mid_gpio *priv) +{ + void __iomem *reg; + unsigned base; + + for (base = 0; base < priv->chip.ngpio; base += 32) { + /* Clear the rising-edge detect register */ + reg = gpio_reg(&priv->chip, base, GRER); + writel(0, reg); + /* Clear the falling-edge detect register */ + reg = gpio_reg(&priv->chip, base, GFER); + writel(0, reg); + /* Clear the edge detect status register */ + reg = gpio_reg(&priv->chip, base, GEDR); + writel(~0, reg); + } +} + +static int intel_gpio_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + struct intel_mid_gpio *priv = d->host_data; + + irq_set_chip_and_handler_name(irq, &intel_mid_irqchip, + handle_simple_irq, "demux"); + irq_set_chip_data(irq, priv); + irq_set_irq_type(irq, IRQ_TYPE_NONE); + + return 0; +} + +static const struct irq_domain_ops intel_gpio_irq_ops = { + .map = intel_gpio_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + +static int intel_gpio_runtime_idle(struct device *dev) +{ + pm_schedule_suspend(dev, 500); + return -EBUSY; +} + +static const struct dev_pm_ops intel_gpio_pm_ops = { + SET_RUNTIME_PM_OPS(NULL, NULL, intel_gpio_runtime_idle) +}; + +static int intel_gpio_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + void __iomem *base; + struct intel_mid_gpio *priv; + u32 gpio_base; + u32 irq_base; + int retval; + struct intel_mid_gpio_ddata *ddata = + (struct intel_mid_gpio_ddata *)id->driver_data; + + retval = pcim_enable_device(pdev); + if (retval) + return retval; + + retval = pcim_iomap_regions(pdev, 1 << 0 | 1 << 1, pci_name(pdev)); + if (retval) { + dev_err(&pdev->dev, "I/O memory mapping error\n"); + return retval; + } + + base = pcim_iomap_table(pdev)[1]; + + irq_base = readl(base); + gpio_base = readl(sizeof(u32) + base); + + /* release the IO mapping, since we already get the info from bar1 */ + pcim_iounmap_regions(pdev, 1 << 1); + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(&pdev->dev, "can't allocate chip data\n"); + return -ENOMEM; + } + + priv->reg_base = pcim_iomap_table(pdev)[0]; + priv->chip.label = dev_name(&pdev->dev); + priv->chip.request = intel_gpio_request; + priv->chip.direction_input = intel_gpio_direction_input; + priv->chip.direction_output = intel_gpio_direction_output; + priv->chip.get = intel_gpio_get; + priv->chip.set = intel_gpio_set; + priv->chip.to_irq = intel_gpio_to_irq; + priv->chip.base = gpio_base; + priv->chip.ngpio = ddata->ngpio; + priv->chip.can_sleep = 0; + priv->pdev = pdev; + + spin_lock_init(&priv->lock); + + priv->domain = irq_domain_add_simple(pdev->dev.of_node, ddata->ngpio, + irq_base, &intel_gpio_irq_ops, priv); + if (!priv->domain) + return -ENOMEM; + + pci_set_drvdata(pdev, priv); + retval = gpiochip_add(&priv->chip); + if (retval) { + dev_err(&pdev->dev, "gpiochip_add error %d\n", retval); + return retval; + } + + intel_mid_irq_init_hw(priv); + + irq_set_handler_data(pdev->irq, priv); + irq_set_chained_handler(pdev->irq, intel_mid_irq_handler); + + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_allow(&pdev->dev); + + return 0; +} + +static struct pci_driver intel_gpio_driver = { + .name = "intel_mid_gpio", + .id_table = intel_gpio_ids, + .probe = intel_gpio_probe, + .driver = { + .pm = &intel_gpio_pm_ops, + }, +}; + +static int __init intel_gpio_init(void) +{ + return pci_register_driver(&intel_gpio_driver); +} + +device_initcall(intel_gpio_init); diff --git a/arch/arm/plat-iop/gpio.c b/drivers/gpio/gpio-iop.c index 697de6dc4936..c22a61be3a9c 100644 --- a/arch/arm/plat-iop/gpio.c +++ b/drivers/gpio/gpio-iop.c @@ -16,42 +16,61 @@ #include <linux/errno.h> #include <linux/gpio.h> #include <linux/export.h> -#include <asm/hardware/iop3xx.h> -#include <mach/gpio.h> +#include <linux/platform_device.h> +#include <linux/bitops.h> +#include <linux/io.h> -void gpio_line_config(int line, int direction) +#define IOP3XX_N_GPIOS 8 + +#define GPIO_IN 0 +#define GPIO_OUT 1 +#define GPIO_LOW 0 +#define GPIO_HIGH 1 + +/* Memory base offset */ +static void __iomem *base; + +#define IOP3XX_GPIO_REG(reg) (base + (reg)) +#define IOP3XX_GPOE IOP3XX_GPIO_REG(0x0000) +#define IOP3XX_GPID IOP3XX_GPIO_REG(0x0004) +#define IOP3XX_GPOD IOP3XX_GPIO_REG(0x0008) + +static void gpio_line_config(int line, int direction) { unsigned long flags; + u32 val; local_irq_save(flags); + val = readl(IOP3XX_GPOE); if (direction == GPIO_IN) { - *IOP3XX_GPOE |= 1 << line; + val |= BIT(line); } else if (direction == GPIO_OUT) { - *IOP3XX_GPOE &= ~(1 << line); + val &= ~BIT(line); } + writel(val, IOP3XX_GPOE); local_irq_restore(flags); } -EXPORT_SYMBOL(gpio_line_config); -int gpio_line_get(int line) +static int gpio_line_get(int line) { - return !!(*IOP3XX_GPID & (1 << line)); + return !!(readl(IOP3XX_GPID) & BIT(line)); } -EXPORT_SYMBOL(gpio_line_get); -void gpio_line_set(int line, int value) +static void gpio_line_set(int line, int value) { unsigned long flags; + u32 val; local_irq_save(flags); + val = readl(IOP3XX_GPOD); if (value == GPIO_LOW) { - *IOP3XX_GPOD &= ~(1 << line); + val &= ~BIT(line); } else if (value == GPIO_HIGH) { - *IOP3XX_GPOD |= 1 << line; + val |= BIT(line); } + writel(val, IOP3XX_GPOD); local_irq_restore(flags); } -EXPORT_SYMBOL(gpio_line_set); static int iop3xx_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) { @@ -86,8 +105,26 @@ static struct gpio_chip iop3xx_chip = { .ngpio = IOP3XX_N_GPIOS, }; -static int __init iop3xx_gpio_setup(void) +static int iop3xx_gpio_probe(struct platform_device *pdev) { + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + return gpiochip_add(&iop3xx_chip); } -arch_initcall(iop3xx_gpio_setup); + +static struct platform_driver iop3xx_gpio_driver = { + .driver = { + .name = "gpio-iop", + .owner = THIS_MODULE, + }, + .probe = iop3xx_gpio_probe, +}; + +static int __init iop3xx_gpio_init(void) +{ + return platform_driver_register(&iop3xx_gpio_driver); +} +arch_initcall(iop3xx_gpio_init); diff --git a/drivers/gpio/gpio-langwell.c b/drivers/gpio/gpio-langwell.c deleted file mode 100644 index bfa1af1b519f..000000000000 --- a/drivers/gpio/gpio-langwell.c +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Moorestown platform Langwell chip GPIO driver - * - * Copyright (c) 2008, 2009, 2013, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* Supports: - * Moorestown platform Langwell chip. - * Medfield platform Penwell chip. - */ - -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/platform_device.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/stddef.h> -#include <linux/interrupt.h> -#include <linux/init.h> -#include <linux/irq.h> -#include <linux/io.h> -#include <linux/gpio.h> -#include <linux/slab.h> -#include <linux/pm_runtime.h> -#include <linux/irqdomain.h> - -/* - * Langwell chip has 64 pins and thus there are 2 32bit registers to control - * each feature, while Penwell chip has 96 pins for each block, and need 3 32bit - * registers to control them, so we only define the order here instead of a - * structure, to get a bit offset for a pin (use GPDR as an example): - * - * nreg = ngpio / 32; - * reg = offset / 32; - * bit = offset % 32; - * reg_addr = reg_base + GPDR * nreg * 4 + reg * 4; - * - * so the bit of reg_addr is to control pin offset's GPDR feature -*/ - -enum GPIO_REG { - GPLR = 0, /* pin level read-only */ - GPDR, /* pin direction */ - GPSR, /* pin set */ - GPCR, /* pin clear */ - GRER, /* rising edge detect */ - GFER, /* falling edge detect */ - GEDR, /* edge detect result */ - GAFR, /* alt function */ -}; - -struct lnw_gpio { - struct gpio_chip chip; - void __iomem *reg_base; - spinlock_t lock; - struct pci_dev *pdev; - struct irq_domain *domain; -}; - -#define to_lnw_priv(chip) container_of(chip, struct lnw_gpio, chip) - -static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset, - enum GPIO_REG reg_type) -{ - struct lnw_gpio *lnw = to_lnw_priv(chip); - unsigned nreg = chip->ngpio / 32; - u8 reg = offset / 32; - - return lnw->reg_base + reg_type * nreg * 4 + reg * 4; -} - -static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset, - enum GPIO_REG reg_type) -{ - struct lnw_gpio *lnw = to_lnw_priv(chip); - unsigned nreg = chip->ngpio / 32; - u8 reg = offset / 16; - - return lnw->reg_base + reg_type * nreg * 4 + reg * 4; -} - -static int lnw_gpio_request(struct gpio_chip *chip, unsigned offset) -{ - void __iomem *gafr = gpio_reg_2bit(chip, offset, GAFR); - u32 value = readl(gafr); - int shift = (offset % 16) << 1, af = (value >> shift) & 3; - - if (af) { - value &= ~(3 << shift); - writel(value, gafr); - } - return 0; -} - -static int lnw_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - void __iomem *gplr = gpio_reg(chip, offset, GPLR); - - return readl(gplr) & BIT(offset % 32); -} - -static void lnw_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - void __iomem *gpsr, *gpcr; - - if (value) { - gpsr = gpio_reg(chip, offset, GPSR); - writel(BIT(offset % 32), gpsr); - } else { - gpcr = gpio_reg(chip, offset, GPCR); - writel(BIT(offset % 32), gpcr); - } -} - -static int lnw_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - struct lnw_gpio *lnw = to_lnw_priv(chip); - void __iomem *gpdr = gpio_reg(chip, offset, GPDR); - u32 value; - unsigned long flags; - - if (lnw->pdev) - pm_runtime_get(&lnw->pdev->dev); - - spin_lock_irqsave(&lnw->lock, flags); - value = readl(gpdr); - value &= ~BIT(offset % 32); - writel(value, gpdr); - spin_unlock_irqrestore(&lnw->lock, flags); - - if (lnw->pdev) - pm_runtime_put(&lnw->pdev->dev); - - return 0; -} - -static int lnw_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct lnw_gpio *lnw = to_lnw_priv(chip); - void __iomem *gpdr = gpio_reg(chip, offset, GPDR); - unsigned long flags; - - lnw_gpio_set(chip, offset, value); - - if (lnw->pdev) - pm_runtime_get(&lnw->pdev->dev); - - spin_lock_irqsave(&lnw->lock, flags); - value = readl(gpdr); - value |= BIT(offset % 32); - writel(value, gpdr); - spin_unlock_irqrestore(&lnw->lock, flags); - - if (lnw->pdev) - pm_runtime_put(&lnw->pdev->dev); - - return 0; -} - -static int lnw_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct lnw_gpio *lnw = to_lnw_priv(chip); - return irq_create_mapping(lnw->domain, offset); -} - -static int lnw_irq_type(struct irq_data *d, unsigned type) -{ - struct lnw_gpio *lnw = irq_data_get_irq_chip_data(d); - u32 gpio = irqd_to_hwirq(d); - unsigned long flags; - u32 value; - void __iomem *grer = gpio_reg(&lnw->chip, gpio, GRER); - void __iomem *gfer = gpio_reg(&lnw->chip, gpio, GFER); - - if (gpio >= lnw->chip.ngpio) - return -EINVAL; - - if (lnw->pdev) - pm_runtime_get(&lnw->pdev->dev); - - spin_lock_irqsave(&lnw->lock, flags); - if (type & IRQ_TYPE_EDGE_RISING) - value = readl(grer) | BIT(gpio % 32); - else - value = readl(grer) & (~BIT(gpio % 32)); - writel(value, grer); - - if (type & IRQ_TYPE_EDGE_FALLING) - value = readl(gfer) | BIT(gpio % 32); - else - value = readl(gfer) & (~BIT(gpio % 32)); - writel(value, gfer); - spin_unlock_irqrestore(&lnw->lock, flags); - - if (lnw->pdev) - pm_runtime_put(&lnw->pdev->dev); - - return 0; -} - -static void lnw_irq_unmask(struct irq_data *d) -{ -} - -static void lnw_irq_mask(struct irq_data *d) -{ -} - -static struct irq_chip lnw_irqchip = { - .name = "LNW-GPIO", - .irq_mask = lnw_irq_mask, - .irq_unmask = lnw_irq_unmask, - .irq_set_type = lnw_irq_type, -}; - -static DEFINE_PCI_DEVICE_TABLE(lnw_gpio_ids) = { /* pin number */ - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f), .driver_data = 64 }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081f), .driver_data = 96 }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081a), .driver_data = 96 }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08eb), .driver_data = 96 }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08f7), .driver_data = 96 }, - { 0, } -}; -MODULE_DEVICE_TABLE(pci, lnw_gpio_ids); - -static void lnw_irq_handler(unsigned irq, struct irq_desc *desc) -{ - struct irq_data *data = irq_desc_get_irq_data(desc); - struct lnw_gpio *lnw = irq_data_get_irq_handler_data(data); - struct irq_chip *chip = irq_data_get_irq_chip(data); - u32 base, gpio, mask; - unsigned long pending; - void __iomem *gedr; - - /* check GPIO controller to check which pin triggered the interrupt */ - for (base = 0; base < lnw->chip.ngpio; base += 32) { - gedr = gpio_reg(&lnw->chip, base, GEDR); - while ((pending = readl(gedr))) { - gpio = __ffs(pending); - mask = BIT(gpio); - /* Clear before handling so we can't lose an edge */ - writel(mask, gedr); - generic_handle_irq(irq_find_mapping(lnw->domain, - base + gpio)); - } - } - - chip->irq_eoi(data); -} - -static void lnw_irq_init_hw(struct lnw_gpio *lnw) -{ - void __iomem *reg; - unsigned base; - - for (base = 0; base < lnw->chip.ngpio; base += 32) { - /* Clear the rising-edge detect register */ - reg = gpio_reg(&lnw->chip, base, GRER); - writel(0, reg); - /* Clear the falling-edge detect register */ - reg = gpio_reg(&lnw->chip, base, GFER); - writel(0, reg); - /* Clear the edge detect status register */ - reg = gpio_reg(&lnw->chip, base, GEDR); - writel(~0, reg); - } -} - -static int lnw_gpio_irq_map(struct irq_domain *d, unsigned int virq, - irq_hw_number_t hw) -{ - struct lnw_gpio *lnw = d->host_data; - - irq_set_chip_and_handler_name(virq, &lnw_irqchip, handle_simple_irq, - "demux"); - irq_set_chip_data(virq, lnw); - irq_set_irq_type(virq, IRQ_TYPE_NONE); - - return 0; -} - -static const struct irq_domain_ops lnw_gpio_irq_ops = { - .map = lnw_gpio_irq_map, - .xlate = irq_domain_xlate_twocell, -}; - -static int lnw_gpio_runtime_idle(struct device *dev) -{ - pm_schedule_suspend(dev, 500); - return -EBUSY; -} - -static const struct dev_pm_ops lnw_gpio_pm_ops = { - SET_RUNTIME_PM_OPS(NULL, NULL, lnw_gpio_runtime_idle) -}; - -static int lnw_gpio_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - void __iomem *base; - struct lnw_gpio *lnw; - u32 gpio_base; - u32 irq_base; - int retval; - int ngpio = id->driver_data; - - retval = pcim_enable_device(pdev); - if (retval) - return retval; - - retval = pcim_iomap_regions(pdev, 1 << 0 | 1 << 1, pci_name(pdev)); - if (retval) { - dev_err(&pdev->dev, "I/O memory mapping error\n"); - return retval; - } - - base = pcim_iomap_table(pdev)[1]; - - irq_base = readl(base); - gpio_base = readl(sizeof(u32) + base); - - /* release the IO mapping, since we already get the info from bar1 */ - pcim_iounmap_regions(pdev, 1 << 1); - - lnw = devm_kzalloc(&pdev->dev, sizeof(*lnw), GFP_KERNEL); - if (!lnw) { - dev_err(&pdev->dev, "can't allocate chip data\n"); - return -ENOMEM; - } - - lnw->reg_base = pcim_iomap_table(pdev)[0]; - lnw->chip.label = dev_name(&pdev->dev); - lnw->chip.request = lnw_gpio_request; - lnw->chip.direction_input = lnw_gpio_direction_input; - lnw->chip.direction_output = lnw_gpio_direction_output; - lnw->chip.get = lnw_gpio_get; - lnw->chip.set = lnw_gpio_set; - lnw->chip.to_irq = lnw_gpio_to_irq; - lnw->chip.base = gpio_base; - lnw->chip.ngpio = ngpio; - lnw->chip.can_sleep = 0; - lnw->pdev = pdev; - - spin_lock_init(&lnw->lock); - - lnw->domain = irq_domain_add_simple(pdev->dev.of_node, ngpio, irq_base, - &lnw_gpio_irq_ops, lnw); - if (!lnw->domain) - return -ENOMEM; - - pci_set_drvdata(pdev, lnw); - retval = gpiochip_add(&lnw->chip); - if (retval) { - dev_err(&pdev->dev, "gpiochip_add error %d\n", retval); - return retval; - } - - lnw_irq_init_hw(lnw); - - irq_set_handler_data(pdev->irq, lnw); - irq_set_chained_handler(pdev->irq, lnw_irq_handler); - - pm_runtime_put_noidle(&pdev->dev); - pm_runtime_allow(&pdev->dev); - - return 0; -} - -static struct pci_driver lnw_gpio_driver = { - .name = "langwell_gpio", - .id_table = lnw_gpio_ids, - .probe = lnw_gpio_probe, - .driver = { - .pm = &lnw_gpio_pm_ops, - }, -}; - -static int __init lnw_gpio_init(void) -{ - return pci_register_driver(&lnw_gpio_driver); -} - -device_initcall(lnw_gpio_init); diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index 90a80eb688a9..2d5555decf0c 100644 --- a/drivers/gpio/gpio-lpc32xx.c +++ b/drivers/gpio/gpio-lpc32xx.c @@ -21,6 +21,7 @@ #include <linux/io.h> #include <linux/errno.h> #include <linux/gpio.h> +#include <linux/of.h> #include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/module.h> diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c index 41b5913ddabe..a0804740a0b7 100644 --- a/drivers/gpio/gpio-lynxpoint.c +++ b/drivers/gpio/gpio-lynxpoint.c @@ -242,14 +242,13 @@ static int lp_gpio_to_irq(struct gpio_chip *chip, unsigned offset) return irq_create_mapping(lg->domain, offset); } -static void lp_gpio_irq_handler(unsigned irq, struct irq_desc *desc) +static void lp_gpio_irq_handler(unsigned hwirq, struct irq_desc *desc) { struct irq_data *data = irq_desc_get_irq_data(desc); struct lp_gpio *lg = irq_data_get_irq_handler_data(data); struct irq_chip *chip = irq_data_get_irq_chip(data); u32 base, pin, mask; unsigned long reg, ena, pending; - unsigned virq; /* check from GPIO controller which pin triggered the interrupt */ for (base = 0; base < lg->chip.ngpio; base += 32) { @@ -257,12 +256,14 @@ static void lp_gpio_irq_handler(unsigned irq, struct irq_desc *desc) ena = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE); while ((pending = (inl(reg) & inl(ena)))) { + unsigned irq; + pin = __ffs(pending); mask = BIT(pin); /* Clear before handling so we don't lose an edge */ outl(mask, reg); - virq = irq_find_mapping(lg->domain, base + pin); - generic_handle_irq(virq); + irq = irq_find_mapping(lg->domain, base + pin); + generic_handle_irq(irq); } } chip->irq_eoi(data); @@ -325,15 +326,15 @@ static void lp_gpio_irq_init_hw(struct lp_gpio *lg) } } -static int lp_gpio_irq_map(struct irq_domain *d, unsigned int virq, - irq_hw_number_t hw) +static int lp_gpio_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) { struct lp_gpio *lg = d->host_data; - irq_set_chip_and_handler_name(virq, &lp_irqchip, handle_simple_irq, + irq_set_chip_and_handler_name(irq, &lp_irqchip, handle_simple_irq, "demux"); - irq_set_chip_data(virq, lg); - irq_set_irq_type(virq, IRQ_TYPE_NONE); + irq_set_chip_data(irq, lg); + irq_set_irq_type(irq, IRQ_TYPE_NONE); return 0; } diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c index 3fd2caa4a2e0..c0b7835f5136 100644 --- a/drivers/gpio/gpio-mc33880.c +++ b/drivers/gpio/gpio-mc33880.c @@ -142,7 +142,6 @@ static int mc33880_probe(struct spi_device *spi) return ret; exit_destroy: - spi_set_drvdata(spi, NULL); mutex_destroy(&mc->lock); return ret; } @@ -156,8 +155,6 @@ static int mc33880_remove(struct spi_device *spi) if (mc == NULL) return -ENODEV; - spi_set_drvdata(spi, NULL); - ret = gpiochip_remove(&mc->chip); if (!ret) mutex_destroy(&mc->lock); diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index a0b33a216d4a..b350649b9764 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -282,16 +282,16 @@ static struct irq_chip mpc8xxx_irq_chip = { .irq_set_type = mpc8xxx_irq_set_type, }; -static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw) +static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int irq, + irq_hw_number_t hwirq) { struct mpc8xxx_gpio_chip *mpc8xxx_gc = h->host_data; if (mpc8xxx_gc->of_dev_id_data) mpc8xxx_irq_chip.irq_set_type = mpc8xxx_gc->of_dev_id_data; - irq_set_chip_data(virq, h->host_data); - irq_set_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq); + irq_set_chip_data(irq, h->host_data); + irq_set_chip_and_handler(irq, &mpc8xxx_irq_chip, handle_level_irq); return 0; } diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index f8e6af20dfbf..532bcb336eff 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -254,7 +254,6 @@ static int mxs_gpio_probe(struct platform_device *pdev) struct device_node *parent; static void __iomem *base; struct mxs_gpio_port *port; - struct resource *iores = NULL; int irq_base; int err; @@ -262,16 +261,10 @@ static int mxs_gpio_probe(struct platform_device *pdev) if (!port) return -ENOMEM; - if (np) { - port->id = of_alias_get_id(np, "gpio"); - if (port->id < 0) - return port->id; - port->devid = (enum mxs_gpio_id) of_id->data; - } else { - port->id = pdev->id; - port->devid = pdev->id_entry->driver_data; - } - + port->id = of_alias_get_id(np, "gpio"); + if (port->id < 0) + return port->id; + port->devid = (enum mxs_gpio_id) of_id->data; port->irq = platform_get_irq(pdev, 0); if (port->irq < 0) return port->irq; @@ -281,18 +274,11 @@ static int mxs_gpio_probe(struct platform_device *pdev) * share the same one */ if (!base) { - if (np) { - parent = of_get_parent(np); - base = of_iomap(parent, 0); - of_node_put(parent); - if (!base) - return -EADDRNOTAVAIL; - } else { - iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, iores); - if (IS_ERR(base)) - return PTR_ERR(base); - } + parent = of_get_parent(np); + base = of_iomap(parent, 0); + of_node_put(parent); + if (!base) + return -EADDRNOTAVAIL; } port->base = base; diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 89675f862308..f319c9ffd4a8 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -514,6 +514,14 @@ static int gpio_irq_type(struct irq_data *d, unsigned type) return -EINVAL; } + retval = gpio_lock_as_irq(&bank->chip, offset); + if (retval) { + dev_err(bank->dev, "unable to lock offset %d for IRQ\n", + offset); + spin_unlock_irqrestore(&bank->lock, flags); + return retval; + } + bank->irq_usage |= 1 << GPIO_INDEX(bank, gpio); spin_unlock_irqrestore(&bank->lock, flags); @@ -797,6 +805,7 @@ static void gpio_irq_shutdown(struct irq_data *d) unsigned offset = GPIO_INDEX(bank, gpio); spin_lock_irqsave(&bank->lock, flags); + gpio_unlock_as_irq(&bank->chip, offset); bank->irq_usage &= ~(1 << offset); _disable_gpio_module(bank, offset); _reset_gpio(bank, gpio); @@ -957,22 +966,13 @@ static int gpio_output(struct gpio_chip *chip, unsigned offset, int value) { struct gpio_bank *bank; unsigned long flags; - int retval = 0; bank = container_of(chip, struct gpio_bank, chip); spin_lock_irqsave(&bank->lock, flags); - - if (LINE_USED(bank->irq_usage, offset)) { - retval = -EINVAL; - goto exit; - } - bank->set_dataout(bank, offset, value); _set_gpio_direction(bank, offset, 0); - -exit: spin_unlock_irqrestore(&bank->lock, flags); - return retval; + return 0; } static int gpio_debounce(struct gpio_chip *chip, unsigned offset, diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c index 8588af0f7661..11801e986dd9 100644 --- a/drivers/gpio/gpio-palmas.c +++ b/drivers/gpio/gpio-palmas.c @@ -31,6 +31,10 @@ struct palmas_gpio { struct palmas *palmas; }; +struct palmas_device_data { + int ngpio; +}; + static inline struct palmas_gpio *to_palmas_gpio(struct gpio_chip *chip) { return container_of(chip, struct palmas_gpio, gpio_chip); @@ -42,23 +46,26 @@ static int palmas_gpio_get(struct gpio_chip *gc, unsigned offset) struct palmas *palmas = pg->palmas; unsigned int val; int ret; + unsigned int reg; + int gpio16 = (offset/8); + + offset %= 8; + reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR; - ret = palmas_read(palmas, PALMAS_GPIO_BASE, PALMAS_GPIO_DATA_DIR, &val); + ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg, &val); if (ret < 0) { - dev_err(gc->dev, "GPIO_DATA_DIR read failed, err = %d\n", ret); + dev_err(gc->dev, "Reg 0x%02x read failed, %d\n", reg, ret); return ret; } - if (val & (1 << offset)) { - ret = palmas_read(palmas, PALMAS_GPIO_BASE, - PALMAS_GPIO_DATA_OUT, &val); - } else { - ret = palmas_read(palmas, PALMAS_GPIO_BASE, - PALMAS_GPIO_DATA_IN, &val); - } + if (val & BIT(offset)) + reg = (gpio16) ? PALMAS_GPIO_DATA_OUT2 : PALMAS_GPIO_DATA_OUT; + else + reg = (gpio16) ? PALMAS_GPIO_DATA_IN2 : PALMAS_GPIO_DATA_IN; + + ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg, &val); if (ret < 0) { - dev_err(gc->dev, "GPIO_DATA_IN/OUT read failed, err = %d\n", - ret); + dev_err(gc->dev, "Reg 0x%02x read failed, %d\n", reg, ret); return ret; } return !!(val & BIT(offset)); @@ -70,17 +77,20 @@ static void palmas_gpio_set(struct gpio_chip *gc, unsigned offset, struct palmas_gpio *pg = to_palmas_gpio(gc); struct palmas *palmas = pg->palmas; int ret; + unsigned int reg; + int gpio16 = (offset/8); - if (value) - ret = palmas_write(palmas, PALMAS_GPIO_BASE, - PALMAS_GPIO_SET_DATA_OUT, BIT(offset)); + offset %= 8; + if (gpio16) + reg = (value) ? + PALMAS_GPIO_SET_DATA_OUT2 : PALMAS_GPIO_CLEAR_DATA_OUT2; else - ret = palmas_write(palmas, PALMAS_GPIO_BASE, - PALMAS_GPIO_CLEAR_DATA_OUT, BIT(offset)); + reg = (value) ? + PALMAS_GPIO_SET_DATA_OUT : PALMAS_GPIO_CLEAR_DATA_OUT; + + ret = palmas_write(palmas, PALMAS_GPIO_BASE, reg, BIT(offset)); if (ret < 0) - dev_err(gc->dev, "%s write failed, err = %d\n", - (value) ? "GPIO_SET_DATA_OUT" : "GPIO_CLEAR_DATA_OUT", - ret); + dev_err(gc->dev, "Reg 0x%02x write failed, %d\n", reg, ret); } static int palmas_gpio_output(struct gpio_chip *gc, unsigned offset, @@ -89,14 +99,19 @@ static int palmas_gpio_output(struct gpio_chip *gc, unsigned offset, struct palmas_gpio *pg = to_palmas_gpio(gc); struct palmas *palmas = pg->palmas; int ret; + unsigned int reg; + int gpio16 = (offset/8); + + offset %= 8; + reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR; /* Set the initial value */ palmas_gpio_set(gc, offset, value); - ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, - PALMAS_GPIO_DATA_DIR, BIT(offset), BIT(offset)); + ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg, + BIT(offset), BIT(offset)); if (ret < 0) - dev_err(gc->dev, "GPIO_DATA_DIR write failed, err = %d\n", ret); + dev_err(gc->dev, "Reg 0x%02x update failed, %d\n", reg, ret); return ret; } @@ -105,11 +120,15 @@ static int palmas_gpio_input(struct gpio_chip *gc, unsigned offset) struct palmas_gpio *pg = to_palmas_gpio(gc); struct palmas *palmas = pg->palmas; int ret; + unsigned int reg; + int gpio16 = (offset/8); + + offset %= 8; + reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR; - ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, - PALMAS_GPIO_DATA_DIR, BIT(offset), 0); + ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg, BIT(offset), 0); if (ret < 0) - dev_err(gc->dev, "GPIO_DATA_DIR write failed, err = %d\n", ret); + dev_err(gc->dev, "Reg 0x%02x update failed, %d\n", reg, ret); return ret; } @@ -121,12 +140,36 @@ static int palmas_gpio_to_irq(struct gpio_chip *gc, unsigned offset) return palmas_irq_get_virq(palmas, PALMAS_GPIO_0_IRQ + offset); } +static const struct palmas_device_data palmas_dev_data = { + .ngpio = 8, +}; + +static const struct palmas_device_data tps80036_dev_data = { + .ngpio = 16, +}; + +static struct of_device_id of_palmas_gpio_match[] = { + { .compatible = "ti,palmas-gpio", .data = &palmas_dev_data,}, + { .compatible = "ti,tps65913-gpio", .data = &palmas_dev_data,}, + { .compatible = "ti,tps65914-gpio", .data = &palmas_dev_data,}, + { .compatible = "ti,tps80036-gpio", .data = &tps80036_dev_data,}, + { }, +}; +MODULE_DEVICE_TABLE(of, of_palmas_gpio_match); + static int palmas_gpio_probe(struct platform_device *pdev) { struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); struct palmas_platform_data *palmas_pdata; struct palmas_gpio *palmas_gpio; int ret; + const struct of_device_id *match; + const struct palmas_device_data *dev_data; + + match = of_match_device(of_palmas_gpio_match, &pdev->dev); + dev_data = match->data; + if (!dev_data) + dev_data = &palmas_dev_data; palmas_gpio = devm_kzalloc(&pdev->dev, sizeof(*palmas_gpio), GFP_KERNEL); @@ -138,7 +181,7 @@ static int palmas_gpio_probe(struct platform_device *pdev) palmas_gpio->palmas = palmas; palmas_gpio->gpio_chip.owner = THIS_MODULE; palmas_gpio->gpio_chip.label = dev_name(&pdev->dev); - palmas_gpio->gpio_chip.ngpio = 8; + palmas_gpio->gpio_chip.ngpio = dev_data->ngpio; palmas_gpio->gpio_chip.can_sleep = 1; palmas_gpio->gpio_chip.direction_input = palmas_gpio_input; palmas_gpio->gpio_chip.direction_output = palmas_gpio_output; @@ -172,15 +215,6 @@ static int palmas_gpio_remove(struct platform_device *pdev) return gpiochip_remove(&palmas_gpio->gpio_chip); } -static struct of_device_id of_palmas_gpio_match[] = { - { .compatible = "ti,palmas-gpio"}, - { .compatible = "ti,tps65913-gpio"}, - { .compatible = "ti,tps65914-gpio"}, - { .compatible = "ti,tps80036-gpio"}, - { }, -}; -MODULE_DEVICE_TABLE(of, of_palmas_gpio_match); - static struct platform_driver palmas_gpio_driver = { .driver.name = "palmas-gpio", .driver.owner = THIS_MODULE, diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index cdd1aa12b895..6e48c07e3d8c 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -683,17 +683,6 @@ static int device_pca957x_init(struct pca953x_chip *chip, u32 invert) int ret; u8 val[MAX_BANK]; - /* Let every port in proper state, that could save power */ - memset(val, 0, NBANK(chip)); - pca953x_write_regs(chip, PCA957X_PUPD, val); - memset(val, 0xFF, NBANK(chip)); - pca953x_write_regs(chip, PCA957X_CFG, val); - memset(val, 0, NBANK(chip)); - pca953x_write_regs(chip, PCA957X_OUT, val); - - ret = pca953x_read_regs(chip, PCA957X_IN, val); - if (ret) - goto out; ret = pca953x_read_regs(chip, PCA957X_OUT, chip->reg_output); if (ret) goto out; diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 9e61bb0719d0..1535686e74ea 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -26,9 +26,10 @@ #include <linux/irqdomain.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/slab.h> #include <linux/spinlock.h> -#include <linux/workqueue.h> static const struct i2c_device_id pcf857x_id[] = { @@ -50,6 +51,27 @@ static const struct i2c_device_id pcf857x_id[] = { }; MODULE_DEVICE_TABLE(i2c, pcf857x_id); +#ifdef CONFIG_OF +static const struct of_device_id pcf857x_of_table[] = { + { .compatible = "nxp,pcf8574" }, + { .compatible = "nxp,pcf8574a" }, + { .compatible = "nxp,pca8574" }, + { .compatible = "nxp,pca9670" }, + { .compatible = "nxp,pca9672" }, + { .compatible = "nxp,pca9674" }, + { .compatible = "nxp,pcf8575" }, + { .compatible = "nxp,pca8575" }, + { .compatible = "nxp,pca9671" }, + { .compatible = "nxp,pca9673" }, + { .compatible = "nxp,pca9675" }, + { .compatible = "maxim,max7328" }, + { .compatible = "maxim,max7329" }, + { .compatible = "ti,tca9554" }, + { } +}; +MODULE_DEVICE_TABLE(of, pcf857x_of_table); +#endif + /* * The pcf857x, pca857x, and pca967x chips only expose one read and one * write register. Writing a "one" bit (to match the reset state) lets @@ -66,12 +88,11 @@ struct pcf857x { struct gpio_chip chip; struct i2c_client *client; struct mutex lock; /* protect 'out' */ - struct work_struct work; /* irq demux work */ struct irq_domain *irq_domain; /* for irq demux */ spinlock_t slock; /* protect irq demux */ unsigned out; /* software latch */ unsigned status; /* current status */ - int irq; /* real irq number */ + unsigned irq_mapped; /* mapped gpio irqs */ int (*write)(struct i2c_client *client, unsigned data); int (*read)(struct i2c_client *client); @@ -164,48 +185,54 @@ static void pcf857x_set(struct gpio_chip *chip, unsigned offset, int value) static int pcf857x_to_irq(struct gpio_chip *chip, unsigned offset) { struct pcf857x *gpio = container_of(chip, struct pcf857x, chip); + int ret; - return irq_create_mapping(gpio->irq_domain, offset); + ret = irq_create_mapping(gpio->irq_domain, offset); + if (ret > 0) + gpio->irq_mapped |= (1 << offset); + + return ret; } -static void pcf857x_irq_demux_work(struct work_struct *work) +static irqreturn_t pcf857x_irq(int irq, void *data) { - struct pcf857x *gpio = container_of(work, - struct pcf857x, - work); + struct pcf857x *gpio = data; unsigned long change, i, status, flags; status = gpio->read(gpio->client); spin_lock_irqsave(&gpio->slock, flags); - change = gpio->status ^ status; + /* + * call the interrupt handler iff gpio is used as + * interrupt source, just to avoid bad irqs + */ + + change = ((gpio->status ^ status) & gpio->irq_mapped); for_each_set_bit(i, &change, gpio->chip.ngpio) generic_handle_irq(irq_find_mapping(gpio->irq_domain, i)); gpio->status = status; spin_unlock_irqrestore(&gpio->slock, flags); -} - -static irqreturn_t pcf857x_irq_demux(int irq, void *data) -{ - struct pcf857x *gpio = data; - - /* - * pcf857x can't read/write data here, - * since i2c data access might go to sleep. - */ - schedule_work(&gpio->work); return IRQ_HANDLED; } -static int pcf857x_irq_domain_map(struct irq_domain *domain, unsigned int virq, +static int pcf857x_irq_domain_map(struct irq_domain *domain, unsigned int irq, irq_hw_number_t hw) { - irq_set_chip_and_handler(virq, + struct pcf857x *gpio = domain->host_data; + + irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_level_irq); +#ifdef CONFIG_ARM + set_irq_flags(irq, IRQF_VALID); +#else + irq_set_noprobe(irq); +#endif + gpio->irq_mapped |= (1 << hw); + return 0; } @@ -218,8 +245,6 @@ static void pcf857x_irq_domain_cleanup(struct pcf857x *gpio) if (gpio->irq_domain) irq_domain_remove(gpio->irq_domain); - if (gpio->irq) - free_irq(gpio->irq, gpio); } static int pcf857x_irq_domain_init(struct pcf857x *gpio, @@ -230,20 +255,21 @@ static int pcf857x_irq_domain_init(struct pcf857x *gpio, gpio->irq_domain = irq_domain_add_linear(client->dev.of_node, gpio->chip.ngpio, &pcf857x_irq_domain_ops, - NULL); + gpio); if (!gpio->irq_domain) goto fail; /* enable real irq */ - status = request_irq(client->irq, pcf857x_irq_demux, 0, - dev_name(&client->dev), gpio); + status = devm_request_threaded_irq(&client->dev, client->irq, + NULL, pcf857x_irq, IRQF_ONESHOT | + IRQF_TRIGGER_FALLING, + dev_name(&client->dev), gpio); + if (status) goto fail; /* enable gpio_to_irq() */ - INIT_WORK(&gpio->work, pcf857x_irq_demux_work); gpio->chip.to_irq = pcf857x_to_irq; - gpio->irq = client->irq; return 0; @@ -257,14 +283,18 @@ fail: static int pcf857x_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct pcf857x_platform_data *pdata; + struct pcf857x_platform_data *pdata = dev_get_platdata(&client->dev); + struct device_node *np = client->dev.of_node; struct pcf857x *gpio; + unsigned int n_latch = 0; int status; - pdata = dev_get_platdata(&client->dev); - if (!pdata) { + if (IS_ENABLED(CONFIG_OF) && np) + of_property_read_u32(np, "lines-initial-states", &n_latch); + else if (pdata) + n_latch = pdata->n_latch; + else dev_dbg(&client->dev, "no platform data\n"); - } /* Allocate, initialize, and register this gpio_chip. */ gpio = devm_kzalloc(&client->dev, sizeof(*gpio), GFP_KERNEL); @@ -357,11 +387,11 @@ static int pcf857x_probe(struct i2c_client *client, * may cause transient glitching since it can't know the last value * written (some pins may need to be driven low). * - * Using pdata->n_latch avoids that trouble. When left initialized - * to zero, our software copy of the "latch" then matches the chip's - * all-ones reset state. Otherwise it flags pins to be driven low. + * Using n_latch avoids that trouble. When left initialized to zero, + * our software copy of the "latch" then matches the chip's all-ones + * reset state. Otherwise it flags pins to be driven low. */ - gpio->out = pdata ? ~pdata->n_latch : ~0; + gpio->out = ~n_latch; gpio->status = gpio->out; status = gpiochip_add(&gpio->chip); @@ -423,6 +453,7 @@ static struct i2c_driver pcf857x_driver = { .driver = { .name = "pcf857x", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(pcf857x_of_table), }, .probe = pcf857x_probe, .remove = pcf857x_remove, diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 4274e2e70ef8..f22f7f3e2e53 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -238,15 +238,15 @@ static struct irq_chip pl061_irqchip = { .irq_set_type = pl061_irq_type, }; -static int pl061_irq_map(struct irq_domain *d, unsigned int virq, - irq_hw_number_t hw) +static int pl061_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) { struct pl061_gpio *chip = d->host_data; - irq_set_chip_and_handler_name(virq, &pl061_irqchip, handle_simple_irq, + irq_set_chip_and_handler_name(irq, &pl061_irqchip, handle_simple_irq, "pl061"); - irq_set_chip_data(virq, chip); - irq_set_irq_type(virq, IRQ_TYPE_NONE); + irq_set_chip_data(irq, chip); + irq_set_irq_type(irq, IRQ_TYPE_NONE); return 0; } diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 6038966ab045..d3f15ae93bd3 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -22,6 +22,7 @@ #include <linux/irq.h> #include <linux/irqdomain.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_data/gpio-rcar.h> #include <linux/platform_device.h> @@ -266,16 +267,16 @@ static int gpio_rcar_to_irq(struct gpio_chip *chip, unsigned offset) return irq_create_mapping(gpio_to_priv(chip)->irq_domain, offset); } -static int gpio_rcar_irq_domain_map(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw) +static int gpio_rcar_irq_domain_map(struct irq_domain *h, unsigned int irq, + irq_hw_number_t hwirq) { struct gpio_rcar_priv *p = h->host_data; - dev_dbg(&p->pdev->dev, "map hw irq = %d, virq = %d\n", (int)hw, virq); + dev_dbg(&p->pdev->dev, "map hw irq = %d, irq = %d\n", (int)hwirq, irq); - irq_set_chip_data(virq, h->host_data); - irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq); - set_irq_flags(virq, IRQF_VALID); /* kill me now */ + irq_set_chip_data(irq, h->host_data); + irq_set_chip_and_handler(irq, &p->irq_chip, handle_level_irq); + set_irq_flags(irq, IRQF_VALID); /* kill me now */ return 0; } diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index b33bad1bb4df..2647e243d471 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -254,9 +254,10 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev) while (stat) { int bit = __ffs(stat); int line = bank * 8 + bit; - int virq = irq_find_mapping(stmpe_gpio->domain, line); + int child_irq = irq_find_mapping(stmpe_gpio->domain, + line); - handle_nested_irq(virq); + handle_nested_irq(child_irq); stat &= ~(1 << bit); } @@ -271,7 +272,7 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev) return IRQ_HANDLED; } -static int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq, +static int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq) { struct stmpe_gpio *stmpe_gpio = d->host_data; @@ -279,26 +280,26 @@ static int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq, if (!stmpe_gpio) return -EINVAL; - irq_set_chip_data(hwirq, stmpe_gpio); - irq_set_chip_and_handler(hwirq, &stmpe_gpio_irq_chip, + irq_set_chip_data(irq, stmpe_gpio); + irq_set_chip_and_handler(irq, &stmpe_gpio_irq_chip, handle_simple_irq); - irq_set_nested_thread(hwirq, 1); + irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM - set_irq_flags(hwirq, IRQF_VALID); + set_irq_flags(irq, IRQF_VALID); #else - irq_set_noprobe(hwirq); + irq_set_noprobe(irq); #endif return 0; } -static void stmpe_gpio_irq_unmap(struct irq_domain *d, unsigned int virq) +static void stmpe_gpio_irq_unmap(struct irq_domain *d, unsigned int irq) { #ifdef CONFIG_ARM - set_irq_flags(virq, 0); + set_irq_flags(irq, 0); #endif - irq_set_chip_and_handler(virq, NULL, NULL); - irq_set_chip_data(virq, NULL); + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); } static const struct irq_domain_ops stmpe_gpio_irq_simple_ops = { diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index 4a5de273c230..ddb5fefaa715 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -96,27 +96,27 @@ static int tc3589x_gpio_direction_input(struct gpio_chip *chip, } /** - * tc3589x_gpio_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ + * tc3589x_gpio_irq_get_irq(): Map a hardware IRQ on a chip to a Linux IRQ * * @tc3589x_gpio: tc3589x_gpio_irq controller to operate on. - * @irq: index of the interrupt requested in the chip IRQs + * @irq: index of the hardware interrupt requested in the chip IRQs * * Useful for drivers to request their own IRQs. */ -static int tc3589x_gpio_irq_get_virq(struct tc3589x_gpio *tc3589x_gpio, - int irq) +static int tc3589x_gpio_irq_get_irq(struct tc3589x_gpio *tc3589x_gpio, + int hwirq) { if (!tc3589x_gpio) return -EINVAL; - return irq_create_mapping(tc3589x_gpio->domain, irq); + return irq_create_mapping(tc3589x_gpio->domain, hwirq); } static int tc3589x_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip); - return tc3589x_gpio_irq_get_virq(tc3589x_gpio, offset); + return tc3589x_gpio_irq_get_irq(tc3589x_gpio, offset); } static struct gpio_chip template_chip = { @@ -242,9 +242,9 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) while (stat) { int bit = __ffs(stat); int line = i * 8 + bit; - int virq = tc3589x_gpio_irq_get_virq(tc3589x_gpio, line); + int irq = tc3589x_gpio_irq_get_irq(tc3589x_gpio, line); - handle_nested_irq(virq); + handle_nested_irq(irq); stat &= ~(1 << bit); } @@ -254,31 +254,31 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) return IRQ_HANDLED; } -static int tc3589x_gpio_irq_map(struct irq_domain *d, unsigned int virq, +static int tc3589x_gpio_irq_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq) { struct tc3589x *tc3589x_gpio = d->host_data; - irq_set_chip_data(virq, tc3589x_gpio); - irq_set_chip_and_handler(virq, &tc3589x_gpio_irq_chip, + irq_set_chip_data(irq, tc3589x_gpio); + irq_set_chip_and_handler(irq, &tc3589x_gpio_irq_chip, handle_simple_irq); - irq_set_nested_thread(virq, 1); + irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM - set_irq_flags(virq, IRQF_VALID); + set_irq_flags(irq, IRQF_VALID); #else - irq_set_noprobe(virq); + irq_set_noprobe(irq); #endif return 0; } -static void tc3589x_gpio_irq_unmap(struct irq_domain *d, unsigned int virq) +static void tc3589x_gpio_irq_unmap(struct irq_domain *d, unsigned int irq) { #ifdef CONFIG_ARM - set_irq_flags(virq, 0); + set_irq_flags(irq, 0); #endif - irq_set_chip_and_handler(virq, NULL, NULL); - irq_set_chip_data(virq, NULL); + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); } static struct irq_domain_ops tc3589x_irq_ops = { diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 9a62672f1bed..cfd3b9037bc7 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -75,6 +75,7 @@ struct tegra_gpio_bank { #endif }; +static struct device *dev; static struct irq_domain *irq_domain; static void __iomem *regs; static u32 tegra_gpio_bank_count; @@ -205,6 +206,7 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) int lvl_type; int val; unsigned long flags; + int ret; switch (type & IRQ_TYPE_SENSE_MASK) { case IRQ_TYPE_EDGE_RISING: @@ -231,6 +233,12 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) return -EINVAL; } + ret = gpio_lock_as_irq(&tegra_gpio_chip, gpio); + if (ret) { + dev_err(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)); @@ -251,6 +259,13 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) return 0; } +static void tegra_gpio_irq_shutdown(struct irq_data *d) +{ + int gpio = d->hwirq; + + gpio_unlock_as_irq(&tegra_gpio_chip, gpio); +} + static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) { struct tegra_gpio_bank *bank; @@ -368,6 +383,7 @@ static struct irq_chip tegra_gpio_irq_chip = { .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 @@ -413,6 +429,8 @@ 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) { dev_err(&pdev->dev, "Error: No device match found\n"); diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index d8e4f6efcb29..0c7e891c8651 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -594,7 +594,7 @@ static struct platform_driver gpio_twl4030_driver = { .driver = { .name = "twl4030_gpio", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(twl_gpio_match), + .of_match_table = twl_gpio_match, }, .probe = gpio_twl4030_probe, .remove = gpio_twl4030_remove, diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 5c1ef2b3ef18..ae0ffdce8bd5 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -11,7 +11,7 @@ */ #include <linux/errno.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/export.h> #include <linux/acpi_gpio.h> #include <linux/acpi.h> @@ -33,14 +33,15 @@ static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) } /** - * acpi_get_gpio() - Translate ACPI GPIO pin to GPIO number usable with GPIO API + * acpi_get_gpiod() - Translate ACPI GPIO pin to GPIO descriptor usable with GPIO API * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1") * @pin: ACPI GPIO pin number (0-based, controller-relative) * - * Returns GPIO number to use with Linux generic GPIO API, or errno error value + * Returns GPIO descriptor to use with Linux generic GPIO API, or ERR_PTR + * error value */ -int acpi_get_gpio(char *path, int pin) +static struct gpio_desc *acpi_get_gpiod(char *path, int pin) { struct gpio_chip *chip; acpi_handle handle; @@ -48,18 +49,17 @@ int acpi_get_gpio(char *path, int pin) status = acpi_get_handle(NULL, path, &handle); if (ACPI_FAILURE(status)) - return -ENODEV; + return ERR_PTR(-ENODEV); chip = gpiochip_find(handle, acpi_gpiochip_find); if (!chip) - return -ENODEV; + return ERR_PTR(-ENODEV); - if (!gpio_is_valid(chip->base + pin)) - return -EINVAL; + if (pin < 0 || pin > chip->ngpio) + return ERR_PTR(-EINVAL); - return chip->base + pin; + return gpio_to_desc(chip->base + pin); } -EXPORT_SYMBOL_GPL(acpi_get_gpio); static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) { @@ -73,15 +73,8 @@ static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) static irqreturn_t acpi_gpio_irq_handler_evt(int irq, void *data) { struct acpi_gpio_evt_pin *evt_pin = data; - struct acpi_object_list args; - union acpi_object arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = evt_pin->pin; - args.count = 1; - args.pointer = &arg; - - acpi_evaluate_object(evt_pin->evt_handle, NULL, &args, NULL); + acpi_execute_simple_method(evt_pin->evt_handle, NULL, evt_pin->pin); return IRQ_HANDLED; } @@ -201,10 +194,48 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) } EXPORT_SYMBOL(acpi_gpiochip_request_interrupts); +/** + * acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts. + * @chip: gpio chip + * + * Free interrupts associated with the _EVT method for the given GPIO chip. + * + * The remaining ACPI event interrupts associated with the chip are freed + * automatically. + */ +void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) +{ + acpi_handle handle; + acpi_status status; + struct list_head *evt_pins; + struct acpi_gpio_evt_pin *evt_pin, *ep; + + if (!chip->dev || !chip->to_irq) + return; + + handle = ACPI_HANDLE(chip->dev); + if (!handle) + return; + + status = acpi_get_data(handle, acpi_gpio_evt_dh, (void **)&evt_pins); + if (ACPI_FAILURE(status)) + return; + + list_for_each_entry_safe_reverse(evt_pin, ep, evt_pins, node) { + devm_free_irq(chip->dev, evt_pin->irq, evt_pin); + list_del(&evt_pin->node); + kfree(evt_pin); + } + + acpi_detach_data(handle, acpi_gpio_evt_dh); + kfree(evt_pins); +} +EXPORT_SYMBOL(acpi_gpiochip_free_interrupts); + struct acpi_gpio_lookup { struct acpi_gpio_info info; int index; - int gpio; + struct gpio_desc *desc; int n; }; @@ -215,37 +246,39 @@ static int acpi_find_gpio(struct acpi_resource *ares, void *data) if (ares->type != ACPI_RESOURCE_TYPE_GPIO) return 1; - if (lookup->n++ == lookup->index && lookup->gpio < 0) { + if (lookup->n++ == lookup->index && !lookup->desc) { const struct acpi_resource_gpio *agpio = &ares->data.gpio; - lookup->gpio = acpi_get_gpio(agpio->resource_source.string_ptr, - agpio->pin_table[0]); + lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr, + agpio->pin_table[0]); lookup->info.gpioint = agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT; + lookup->info.active_low = + agpio->polarity == ACPI_ACTIVE_LOW; } return 1; } /** - * acpi_get_gpio_by_index() - get a GPIO number from device resources + * acpi_get_gpiod_by_index() - get a GPIO descriptor from device resources * @dev: pointer to a device to get GPIO from * @index: index of GpioIo/GpioInt resource (starting from %0) * @info: info pointer to fill in (optional) * * Function goes through ACPI resources for @dev and based on @index looks - * up a GpioIo/GpioInt resource, translates it to the Linux GPIO number, + * up a GpioIo/GpioInt resource, translates it to the Linux GPIO descriptor, * and returns it. @index matches GpioIo/GpioInt resources only so if there * are total %3 GPIO resources, the index goes from %0 to %2. * - * If the GPIO cannot be translated or there is an error, negative errno is + * If the GPIO cannot be translated or there is an error an ERR_PTR is * returned. * * Note: if the GPIO resource has multiple entries in the pin list, this * function only returns the first. */ -int acpi_get_gpio_by_index(struct device *dev, int index, - struct acpi_gpio_info *info) +struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index, + struct acpi_gpio_info *info) { struct acpi_gpio_lookup lookup; struct list_head resource_list; @@ -254,65 +287,26 @@ int acpi_get_gpio_by_index(struct device *dev, int index, int ret; if (!dev) - return -EINVAL; + return ERR_PTR(-EINVAL); handle = ACPI_HANDLE(dev); if (!handle || acpi_bus_get_device(handle, &adev)) - return -ENODEV; + return ERR_PTR(-ENODEV); memset(&lookup, 0, sizeof(lookup)); lookup.index = index; - lookup.gpio = -ENODEV; INIT_LIST_HEAD(&resource_list); ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio, &lookup); if (ret < 0) - return ret; + return ERR_PTR(ret); acpi_dev_free_resource_list(&resource_list); - if (lookup.gpio >= 0 && info) + if (lookup.desc && info) *info = lookup.info; - return lookup.gpio; + return lookup.desc ? lookup.desc : ERR_PTR(-ENODEV); } -EXPORT_SYMBOL_GPL(acpi_get_gpio_by_index); - -/** - * acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts. - * @chip: gpio chip - * - * Free interrupts associated with the _EVT method for the given GPIO chip. - * - * The remaining ACPI event interrupts associated with the chip are freed - * automatically. - */ -void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) -{ - acpi_handle handle; - acpi_status status; - struct list_head *evt_pins; - struct acpi_gpio_evt_pin *evt_pin, *ep; - - if (!chip->dev || !chip->to_irq) - return; - - handle = ACPI_HANDLE(chip->dev); - if (!handle) - return; - - status = acpi_get_data(handle, acpi_gpio_evt_dh, (void **)&evt_pins); - if (ACPI_FAILURE(status)) - return; - - list_for_each_entry_safe_reverse(evt_pin, ep, evt_pins, node) { - devm_free_irq(chip->dev, evt_pin->irq, evt_pin); - list_del(&evt_pin->node); - kfree(evt_pin); - } - - acpi_detach_data(handle, acpi_gpio_evt_dh); - kfree(evt_pins); -} -EXPORT_SYMBOL(acpi_gpiochip_free_interrupts); +EXPORT_SYMBOL_GPL(acpi_get_gpiod_by_index); diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index e78760921bd7..e0a98f581f58 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -15,19 +15,21 @@ #include <linux/errno.h> #include <linux/module.h> #include <linux/io.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_gpio.h> #include <linux/pinctrl/pinctrl.h> #include <linux/slab.h> +struct gpio_desc; + /* Private data structure for of_gpiochip_find_and_xlate */ struct gg_data { enum of_gpio_flags *flags; struct of_phandle_args gpiospec; - int out_gpio; + struct gpio_desc *out_gpio; }; /* Private function for resolving node pointer to gpio_chip */ @@ -45,28 +47,31 @@ static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data) if (ret < 0) return false; - gg_data->out_gpio = ret + gc->base; + gg_data->out_gpio = gpio_to_desc(ret + gc->base); return true; } /** - * of_get_named_gpio_flags() - Get a GPIO number and flags to use with GPIO API + * of_get_named_gpiod_flags() - Get a GPIO descriptor and flags for GPIO API * @np: device node to get GPIO from * @propname: property name containing gpio specifier(s) * @index: index of the GPIO * @flags: a flags pointer to fill in * - * Returns GPIO number to use with Linux generic GPIO API, or one of the errno + * Returns GPIO descriptor to use with Linux GPIO API, or one of the errno * value on the error condition. If @flags is not NULL the function also fills * in flags for the GPIO. */ -int of_get_named_gpio_flags(struct device_node *np, const char *propname, - int index, enum of_gpio_flags *flags) +struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, + const char *propname, int index, enum of_gpio_flags *flags) { /* Return -EPROBE_DEFER to support probe() functions to be called * later when the GPIO actually becomes available */ - struct gg_data gg_data = { .flags = flags, .out_gpio = -EPROBE_DEFER }; + struct gg_data gg_data = { + .flags = flags, + .out_gpio = ERR_PTR(-EPROBE_DEFER) + }; int ret; /* .of_xlate might decide to not fill in the flags, so clear it. */ @@ -78,16 +83,17 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname, if (ret) { pr_debug("%s: can't parse gpios property of node '%s[%d]'\n", __func__, np->full_name, index); - return ret; + return ERR_PTR(ret); } gpiochip_find(&gg_data, of_gpiochip_find_and_xlate); of_node_put(gg_data.gpiospec.np); - pr_debug("%s exited with status %d\n", __func__, gg_data.out_gpio); + pr_debug("%s exited with status %d\n", __func__, + PTR_RET(gg_data.out_gpio)); return gg_data.out_gpio; } -EXPORT_SYMBOL(of_get_named_gpio_flags); +EXPORT_SYMBOL(of_get_named_gpiod_flags); /** * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 4a34ca9c1768..7dd446150294 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -10,22 +10,18 @@ #include <linux/seq_file.h> #include <linux/gpio.h> #include <linux/of_gpio.h> +#include <linux/acpi_gpio.h> #include <linux/idr.h> #include <linux/slab.h> #define CREATE_TRACE_POINTS #include <trace/events/gpio.h> -/* Optional implementation infrastructure for GPIO interfaces. +/* Implementation infrastructure for GPIO interfaces. * - * Platforms may want to use this if they tend to use very many GPIOs - * that aren't part of a System-On-Chip core; or across I2C/SPI/etc. - * - * When kernel footprint or instruction count is an issue, simpler - * implementations may be preferred. The GPIO programming interface - * allows for inlining speed-critical get/set operations for common - * cases, so that access to SOC-integrated GPIOs can sometimes cost - * only an instruction or two per bit. + * The GPIO programming interface allows for inlining speed-critical + * get/set operations for common cases, so that access to SOC-integrated + * GPIOs can sometimes cost only an instruction or two per bit. */ @@ -57,9 +53,10 @@ struct gpio_desc { #define FLAG_SYSFS 3 /* exported via /sys/class/gpio/control */ #define FLAG_TRIG_FALL 4 /* trigger on falling edge */ #define FLAG_TRIG_RISE 5 /* trigger on rising edge */ -#define FLAG_ACTIVE_LOW 6 /* sysfs value has active low */ +#define FLAG_ACTIVE_LOW 6 /* value has active low */ #define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */ #define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */ +#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */ #define ID_SHIFT 16 /* add new flags before this one */ @@ -74,34 +71,50 @@ static struct gpio_desc gpio_desc[ARCH_NR_GPIOS]; #define GPIO_OFFSET_VALID(chip, offset) (offset >= 0 && offset < chip->ngpio) +static DEFINE_MUTEX(gpio_lookup_lock); +static LIST_HEAD(gpio_lookup_list); static LIST_HEAD(gpio_chips); #ifdef CONFIG_GPIO_SYSFS static DEFINE_IDR(dirent_idr); #endif -/* - * Internal gpiod_* API using descriptors instead of the integer namespace. - * Most of this should eventually go public. - */ static int gpiod_request(struct gpio_desc *desc, const char *label); static void gpiod_free(struct gpio_desc *desc); -static int gpiod_direction_input(struct gpio_desc *desc); -static int gpiod_direction_output(struct gpio_desc *desc, int value); -static int gpiod_get_direction(const struct gpio_desc *desc); -static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce); -static int gpiod_get_value_cansleep(const struct gpio_desc *desc); -static void gpiod_set_value_cansleep(struct gpio_desc *desc, int value); -static int gpiod_get_value(const struct gpio_desc *desc); -static void gpiod_set_value(struct gpio_desc *desc, int value); -static int gpiod_cansleep(const struct gpio_desc *desc); -static int gpiod_to_irq(const struct gpio_desc *desc); -static int gpiod_export(struct gpio_desc *desc, bool direction_may_change); -static int gpiod_export_link(struct device *dev, const char *name, - struct gpio_desc *desc); -static int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value); -static void gpiod_unexport(struct gpio_desc *desc); +#ifdef CONFIG_DEBUG_FS +#define gpiod_emerg(desc, fmt, ...) \ + pr_emerg("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ + ##__VA_ARGS__) +#define gpiod_crit(desc, fmt, ...) \ + pr_crit("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ + ##__VA_ARGS__) +#define gpiod_err(desc, fmt, ...) \ + pr_err("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ + ##__VA_ARGS__) +#define gpiod_warn(desc, fmt, ...) \ + pr_warn("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ + ##__VA_ARGS__) +#define gpiod_info(desc, fmt, ...) \ + pr_info("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ + ##__VA_ARGS__) +#define gpiod_dbg(desc, fmt, ...) \ + pr_debug("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ + ##__VA_ARGS__) +#else +#define gpiod_emerg(desc, fmt, ...) \ + pr_emerg("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) +#define gpiod_crit(desc, fmt, ...) \ + pr_crit("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) +#define gpiod_err(desc, fmt, ...) \ + pr_err("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) +#define gpiod_warn(desc, fmt, ...) \ + pr_warn("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) +#define gpiod_info(desc, fmt, ...) \ + pr_info("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) +#define gpiod_dbg(desc, fmt, ...) \ + pr_debug("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) +#endif static inline void desc_set_label(struct gpio_desc *d, const char *label) { @@ -121,23 +134,36 @@ static int gpio_chip_hwgpio(const struct gpio_desc *desc) /** * Convert a GPIO number to its descriptor */ -static struct gpio_desc *gpio_to_desc(unsigned gpio) +struct gpio_desc *gpio_to_desc(unsigned gpio) { if (WARN(!gpio_is_valid(gpio), "invalid GPIO %d\n", gpio)) return NULL; else return &gpio_desc[gpio]; } +EXPORT_SYMBOL_GPL(gpio_to_desc); + +/** + * Convert an offset on a certain chip to a corresponding descriptor + */ +static struct gpio_desc *gpiochip_offset_to_desc(struct gpio_chip *chip, + unsigned int offset) +{ + unsigned int gpio = chip->base + offset; + + return gpio_to_desc(gpio); +} /** * Convert a GPIO descriptor to the integer namespace. * This should disappear in the future but is needed since we still * use GPIO numbers for error messages and sysfs nodes */ -static int desc_to_gpio(const struct gpio_desc *desc) +int desc_to_gpio(const struct gpio_desc *desc) { return desc - &gpio_desc[0]; } +EXPORT_SYMBOL_GPL(desc_to_gpio); /* Warn when drivers omit gpio_request() calls -- legal but ill-advised @@ -172,16 +198,15 @@ static int gpio_ensure_requested(struct gpio_desc *desc) return 0; } -static struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc) +/** + * gpiod_to_chip - Return the GPIO chip to which a GPIO descriptor belongs + * @desc: descriptor to return the chip of + */ +struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc) { return desc ? desc->chip : NULL; } - -/* caller holds gpio_lock *OR* gpio is marked as requested */ -struct gpio_chip *gpio_to_chip(unsigned gpio) -{ - return gpiod_to_chip(gpio_to_desc(gpio)); -} +EXPORT_SYMBOL_GPL(gpiod_to_chip); /* dynamic allocation of GPIOs, e.g. on a hotplugged device */ static int gpiochip_find_base(int ngpio) @@ -207,8 +232,15 @@ static int gpiochip_find_base(int ngpio) } } -/* caller ensures gpio is valid and requested, chip->get_direction may sleep */ -static int gpiod_get_direction(const struct gpio_desc *desc) +/** + * gpiod_get_direction - return the current direction of a GPIO + * @desc: GPIO to get the direction of + * + * Return GPIOF_DIR_IN or GPIOF_DIR_OUT, or an error code in case of error. + * + * This function may sleep if gpiod_cansleep() is true. + */ +int gpiod_get_direction(const struct gpio_desc *desc) { struct gpio_chip *chip; unsigned offset; @@ -234,6 +266,7 @@ static int gpiod_get_direction(const struct gpio_desc *desc) } return status; } +EXPORT_SYMBOL_GPL(gpiod_get_direction); #ifdef CONFIG_GPIO_SYSFS @@ -318,17 +351,10 @@ static ssize_t gpio_value_show(struct device *dev, mutex_lock(&sysfs_lock); - if (!test_bit(FLAG_EXPORT, &desc->flags)) { + if (!test_bit(FLAG_EXPORT, &desc->flags)) status = -EIO; - } else { - int value; - - value = !!gpiod_get_value_cansleep(desc); - if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) - value = !value; - - status = sprintf(buf, "%d\n", value); - } + else + status = sprintf(buf, "%d\n", gpiod_get_value_cansleep(desc)); mutex_unlock(&sysfs_lock); return status; @@ -351,9 +377,7 @@ static ssize_t gpio_value_store(struct device *dev, status = kstrtol(buf, 0, &value); if (status == 0) { - if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) - value = !value; - gpiod_set_value_cansleep(desc, value != 0); + gpiod_set_value_cansleep(desc, value); status = size; } } @@ -395,6 +419,7 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, desc->flags &= ~GPIO_TRIGGER_MASK; if (!gpio_flags) { + gpiod_unlock_as_irq(desc); ret = 0; goto free_id; } @@ -433,6 +458,12 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, if (ret < 0) goto free_id; + ret = gpiod_lock_as_irq(desc); + if (ret < 0) { + gpiod_warn(desc, "failed to flag the GPIO for IRQ\n"); + goto free_id; + } + desc->flags |= gpio_flags; return 0; @@ -736,7 +767,7 @@ static struct class gpio_class = { /** - * gpio_export - export a GPIO through sysfs + * gpiod_export - export a GPIO through sysfs * @gpio: gpio to make available, already requested * @direction_may_change: true if userspace may change gpio direction * Context: arch_initcall or later @@ -750,7 +781,7 @@ static struct class gpio_class = { * * Returns zero on success, else an error. */ -static int gpiod_export(struct gpio_desc *desc, bool direction_may_change) +int gpiod_export(struct gpio_desc *desc, bool direction_may_change) { unsigned long flags; int status; @@ -828,12 +859,7 @@ fail_unlock: status); return status; } - -int gpio_export(unsigned gpio, bool direction_may_change) -{ - return gpiod_export(gpio_to_desc(gpio), direction_may_change); -} -EXPORT_SYMBOL_GPL(gpio_export); +EXPORT_SYMBOL_GPL(gpiod_export); static int match_export(struct device *dev, const void *data) { @@ -841,7 +867,7 @@ static int match_export(struct device *dev, const void *data) } /** - * gpio_export_link - create a sysfs link to an exported GPIO node + * gpiod_export_link - create a sysfs link to an exported GPIO node * @dev: device under which to create symlink * @name: name of the symlink * @gpio: gpio to create symlink to, already exported @@ -851,8 +877,8 @@ static int match_export(struct device *dev, const void *data) * * Returns zero on success, else an error. */ -static int gpiod_export_link(struct device *dev, const char *name, - struct gpio_desc *desc) +int gpiod_export_link(struct device *dev, const char *name, + struct gpio_desc *desc) { int status = -EINVAL; @@ -883,15 +909,10 @@ static int gpiod_export_link(struct device *dev, const char *name, return status; } - -int gpio_export_link(struct device *dev, const char *name, unsigned gpio) -{ - return gpiod_export_link(dev, name, gpio_to_desc(gpio)); -} -EXPORT_SYMBOL_GPL(gpio_export_link); +EXPORT_SYMBOL_GPL(gpiod_export_link); /** - * gpio_sysfs_set_active_low - set the polarity of gpio sysfs value + * gpiod_sysfs_set_active_low - set the polarity of gpio sysfs value * @gpio: gpio to change * @value: non-zero to use active low, i.e. inverted values * @@ -902,7 +923,7 @@ EXPORT_SYMBOL_GPL(gpio_export_link); * * Returns zero on success, else an error. */ -static int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value) +int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value) { struct device *dev = NULL; int status = -EINVAL; @@ -933,20 +954,15 @@ unlock: return status; } - -int gpio_sysfs_set_active_low(unsigned gpio, int value) -{ - return gpiod_sysfs_set_active_low(gpio_to_desc(gpio), value); -} -EXPORT_SYMBOL_GPL(gpio_sysfs_set_active_low); +EXPORT_SYMBOL_GPL(gpiod_sysfs_set_active_low); /** - * gpio_unexport - reverse effect of gpio_export() + * gpiod_unexport - reverse effect of gpio_export() * @gpio: gpio to make unavailable * * This is implicit on gpio_free(). */ -static void gpiod_unexport(struct gpio_desc *desc) +void gpiod_unexport(struct gpio_desc *desc) { int status = 0; struct device *dev = NULL; @@ -979,12 +995,7 @@ static void gpiod_unexport(struct gpio_desc *desc) pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), status); } - -void gpio_unexport(unsigned gpio) -{ - gpiod_unexport(gpio_to_desc(gpio)); -} -EXPORT_SYMBOL_GPL(gpio_unexport); +EXPORT_SYMBOL_GPL(gpiod_unexport); static int gpiochip_export(struct gpio_chip *chip) { @@ -1091,27 +1102,6 @@ static inline void gpiochip_unexport(struct gpio_chip *chip) { } -static inline int gpiod_export(struct gpio_desc *desc, - bool direction_may_change) -{ - return -ENOSYS; -} - -static inline int gpiod_export_link(struct device *dev, const char *name, - struct gpio_desc *desc) -{ - return -ENOSYS; -} - -static inline int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value) -{ - return -ENOSYS; -} - -static inline void gpiod_unexport(struct gpio_desc *desc) -{ -} - #endif /* CONFIG_GPIO_SYSFS */ /* @@ -1670,7 +1660,16 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested); * rely on gpio_request() having been called beforehand. */ -static int gpiod_direction_input(struct gpio_desc *desc) +/** + * gpiod_direction_input - set the GPIO direction to input + * @desc: GPIO to set to input + * + * Set the direction of the passed GPIO to input, such as gpiod_get_value() can + * be called safely on it. + * + * Return 0 in case of success, else an error code. + */ +int gpiod_direction_input(struct gpio_desc *desc) { unsigned long flags; struct gpio_chip *chip; @@ -1684,8 +1683,9 @@ static int gpiod_direction_input(struct gpio_desc *desc) chip = desc->chip; if (!chip->get || !chip->direction_input) { - pr_warn("%s: missing get() or direction_input() operations\n", - __func__); + gpiod_warn(desc, + "%s: missing get() or direction_input() operations\n", + __func__); return -EIO; } @@ -1705,8 +1705,7 @@ static int gpiod_direction_input(struct gpio_desc *desc) if (status) { status = chip->request(chip, offset); if (status < 0) { - pr_debug("GPIO-%d: chip request fail, %d\n", - desc_to_gpio(desc), status); + gpiod_dbg(desc, "chip request fail, %d\n", status); /* and it's not available to anyone else ... * gpio_request() is the fully clean solution. */ @@ -1724,18 +1723,22 @@ lose: fail: spin_unlock_irqrestore(&gpio_lock, flags); if (status) - pr_debug("%s: gpio-%d status %d\n", __func__, - desc_to_gpio(desc), status); + gpiod_dbg(desc, "%s status %d\n", __func__, status); return status; } +EXPORT_SYMBOL_GPL(gpiod_direction_input); -int gpio_direction_input(unsigned gpio) -{ - return gpiod_direction_input(gpio_to_desc(gpio)); -} -EXPORT_SYMBOL_GPL(gpio_direction_input); - -static int gpiod_direction_output(struct gpio_desc *desc, int value) +/** + * gpiod_direction_output - set the GPIO direction to input + * @desc: GPIO to set to output + * @value: initial output value of the GPIO + * + * Set the direction of the passed GPIO to output, such as gpiod_set_value() can + * be called safely on it. The initial value of the output must be specified. + * + * Return 0 in case of success, else an error code. + */ +int gpiod_direction_output(struct gpio_desc *desc, int value) { unsigned long flags; struct gpio_chip *chip; @@ -1747,6 +1750,14 @@ static int gpiod_direction_output(struct gpio_desc *desc, int value) return -EINVAL; } + /* GPIOs used for IRQs shall not be set as output */ + if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) { + gpiod_err(desc, + "%s: tried to set a GPIO tied to an IRQ as output\n", + __func__); + 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); @@ -1757,8 +1768,9 @@ static int gpiod_direction_output(struct gpio_desc *desc, int value) chip = desc->chip; if (!chip->set || !chip->direction_output) { - pr_warn("%s: missing set() or direction_output() operations\n", - __func__); + gpiod_warn(desc, + "%s: missing set() or direction_output() operations\n", + __func__); return -EIO; } @@ -1778,8 +1790,7 @@ static int gpiod_direction_output(struct gpio_desc *desc, int value) if (status) { status = chip->request(chip, offset); if (status < 0) { - pr_debug("GPIO-%d: chip request fail, %d\n", - desc_to_gpio(desc), status); + gpiod_dbg(desc, "chip request fail, %d\n", status); /* and it's not available to anyone else ... * gpio_request() is the fully clean solution. */ @@ -1797,26 +1808,20 @@ lose: fail: spin_unlock_irqrestore(&gpio_lock, flags); if (status) - pr_debug("%s: gpio-%d status %d\n", __func__, - desc_to_gpio(desc), status); + gpiod_dbg(desc, "%s: gpio status %d\n", __func__, status); return status; } - -int gpio_direction_output(unsigned gpio, int value) -{ - return gpiod_direction_output(gpio_to_desc(gpio), value); -} -EXPORT_SYMBOL_GPL(gpio_direction_output); +EXPORT_SYMBOL_GPL(gpiod_direction_output); /** - * gpio_set_debounce - sets @debounce time for a @gpio + * gpiod_set_debounce - sets @debounce time for a @gpio * @gpio: the gpio to set debounce time * @debounce: debounce time is microseconds * * returns -ENOTSUPP if the controller does not support setting * debounce. */ -static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) +int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) { unsigned long flags; struct gpio_chip *chip; @@ -1830,8 +1835,9 @@ static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) chip = desc->chip; if (!chip->set || !chip->set_debounce) { - pr_debug("%s: missing set() or set_debounce() operations\n", - __func__); + gpiod_dbg(desc, + "%s: missing set() or set_debounce() operations\n", + __func__); return -ENOTSUPP; } @@ -1853,17 +1859,23 @@ static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) fail: spin_unlock_irqrestore(&gpio_lock, flags); if (status) - pr_debug("%s: gpio-%d status %d\n", __func__, - desc_to_gpio(desc), status); + gpiod_dbg(desc, "%s: status %d\n", __func__, status); return status; } +EXPORT_SYMBOL_GPL(gpiod_set_debounce); -int gpio_set_debounce(unsigned gpio, unsigned debounce) +/** + * gpiod_is_active_low - test whether a GPIO is active-low or not + * @desc: the gpio descriptor to test + * + * Returns 1 if the GPIO is active-low, 0 otherwise. + */ +int gpiod_is_active_low(const struct gpio_desc *desc) { - return gpiod_set_debounce(gpio_to_desc(gpio), debounce); + return test_bit(FLAG_ACTIVE_LOW, &desc->flags); } -EXPORT_SYMBOL_GPL(gpio_set_debounce); +EXPORT_SYMBOL_GPL(gpiod_is_active_low); /* I/O calls are only valid after configuration completed; the relevant * "is this a valid GPIO" error checks should already have been done. @@ -1887,42 +1899,68 @@ EXPORT_SYMBOL_GPL(gpio_set_debounce); * that the GPIO was actually requested. */ -/** - * __gpio_get_value() - return a gpio's value - * @gpio: gpio whose value will be returned - * Context: any - * - * This is used directly or indirectly to implement gpio_get_value(). - * It returns the zero or nonzero value provided by the associated - * gpio_chip.get() method; or zero if no such method is provided. - */ -static int gpiod_get_value(const struct gpio_desc *desc) +static int _gpiod_get_raw_value(const struct gpio_desc *desc) { struct gpio_chip *chip; int value; int offset; - if (!desc) - return 0; chip = desc->chip; offset = gpio_chip_hwgpio(desc); - /* Should be using gpio_get_value_cansleep() */ - WARN_ON(chip->can_sleep); value = chip->get ? chip->get(chip, offset) : 0; trace_gpio_value(desc_to_gpio(desc), 1, value); return value; } -int __gpio_get_value(unsigned gpio) +/** + * gpiod_get_raw_value() - return a gpio's raw value + * @desc: gpio whose value will be returned + * + * Return the GPIO's raw value, i.e. the value of the physical line disregarding + * its ACTIVE_LOW status. + * + * This function should be called from contexts where we cannot sleep, and will + * complain if the GPIO chip functions potentially sleep. + */ +int gpiod_get_raw_value(const struct gpio_desc *desc) +{ + if (!desc) + return 0; + /* Should be using gpio_get_value_cansleep() */ + WARN_ON(desc->chip->can_sleep); + return _gpiod_get_raw_value(desc); +} +EXPORT_SYMBOL_GPL(gpiod_get_raw_value); + +/** + * gpiod_get_value() - return a gpio's value + * @desc: gpio whose value will be returned + * + * Return the GPIO's logical value, i.e. taking the ACTIVE_LOW status into + * account. + * + * This function should be called from contexts where we cannot sleep, and will + * complain if the GPIO chip functions potentially sleep. + */ +int gpiod_get_value(const struct gpio_desc *desc) { - return gpiod_get_value(gpio_to_desc(gpio)); + int value; + if (!desc) + return 0; + /* Should be using gpio_get_value_cansleep() */ + WARN_ON(desc->chip->can_sleep); + + value = _gpiod_get_raw_value(desc); + if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) + value = !value; + + return value; } -EXPORT_SYMBOL_GPL(__gpio_get_value); +EXPORT_SYMBOL_GPL(gpiod_get_value); /* * _gpio_set_open_drain_value() - Set the open drain gpio's value. - * @gpio: Gpio whose state need to be set. - * @chip: Gpio chip. + * @desc: gpio descriptor whose state need to be set. * @value: Non-zero for setting it HIGH otherise it will set to LOW. */ static void _gpio_set_open_drain_value(struct gpio_desc *desc, int value) @@ -1942,14 +1980,14 @@ static void _gpio_set_open_drain_value(struct gpio_desc *desc, int value) } trace_gpio_direction(desc_to_gpio(desc), value, err); if (err < 0) - pr_err("%s: Error in set_value for open drain gpio%d err %d\n", - __func__, desc_to_gpio(desc), err); + gpiod_err(desc, + "%s: Error in set_value for open drain err %d\n", + __func__, err); } /* - * _gpio_set_open_source() - Set the open source gpio's value. - * @gpio: Gpio whose state need to be set. - * @chip: Gpio chip. + * _gpio_set_open_source_value() - Set the open source gpio's value. + * @desc: gpio descriptor whose state need to be set. * @value: Non-zero for setting it HIGH otherise it will set to LOW. */ static void _gpio_set_open_source_value(struct gpio_desc *desc, int value) @@ -1969,28 +2007,16 @@ static void _gpio_set_open_source_value(struct gpio_desc *desc, int value) } trace_gpio_direction(desc_to_gpio(desc), !value, err); if (err < 0) - pr_err("%s: Error in set_value for open source gpio%d err %d\n", - __func__, desc_to_gpio(desc), err); + gpiod_err(desc, + "%s: Error in set_value for open source err %d\n", + __func__, err); } -/** - * __gpio_set_value() - assign a gpio's value - * @gpio: gpio whose value will be assigned - * @value: value to assign - * Context: any - * - * This is used directly or indirectly to implement gpio_set_value(). - * It invokes the associated gpio_chip.set() method. - */ -static void gpiod_set_value(struct gpio_desc *desc, int value) +static void _gpiod_set_raw_value(struct gpio_desc *desc, int value) { struct gpio_chip *chip; - if (!desc) - return; chip = desc->chip; - /* Should be using gpio_set_value_cansleep() */ - WARN_ON(chip->can_sleep); trace_gpio_value(desc_to_gpio(desc), 0, value); if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) _gpio_set_open_drain_value(desc, value); @@ -2000,44 +2026,71 @@ static void gpiod_set_value(struct gpio_desc *desc, int value) chip->set(chip, gpio_chip_hwgpio(desc), value); } -void __gpio_set_value(unsigned gpio, int value) +/** + * gpiod_set_raw_value() - assign a gpio's raw value + * @desc: gpio whose value will be assigned + * @value: value to assign + * + * Set the raw value of the GPIO, i.e. the value of its physical line without + * regard for its ACTIVE_LOW status. + * + * This function should be called from contexts where we cannot sleep, and will + * complain if the GPIO chip functions potentially sleep. + */ +void gpiod_set_raw_value(struct gpio_desc *desc, int value) { - return gpiod_set_value(gpio_to_desc(gpio), value); + if (!desc) + return; + /* Should be using gpio_set_value_cansleep() */ + WARN_ON(desc->chip->can_sleep); + _gpiod_set_raw_value(desc, value); } -EXPORT_SYMBOL_GPL(__gpio_set_value); +EXPORT_SYMBOL_GPL(gpiod_set_raw_value); /** - * __gpio_cansleep() - report whether gpio value access will sleep - * @gpio: gpio in question - * Context: any + * gpiod_set_value() - assign a gpio's value + * @desc: gpio whose value will be assigned + * @value: value to assign + * + * Set the logical value of the GPIO, i.e. taking its ACTIVE_LOW status into + * account * - * This is used directly or indirectly to implement gpio_cansleep(). It - * returns nonzero if access reading or writing the GPIO value can sleep. + * This function should be called from contexts where we cannot sleep, and will + * complain if the GPIO chip functions potentially sleep. */ -static int gpiod_cansleep(const struct gpio_desc *desc) +void gpiod_set_value(struct gpio_desc *desc, int value) { if (!desc) - return 0; - /* only call this on GPIOs that are valid! */ - return desc->chip->can_sleep; + return; + /* Should be using gpio_set_value_cansleep() */ + WARN_ON(desc->chip->can_sleep); + if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) + value = !value; + _gpiod_set_raw_value(desc, value); } +EXPORT_SYMBOL_GPL(gpiod_set_value); -int __gpio_cansleep(unsigned gpio) +/** + * gpiod_cansleep() - report whether gpio value access may sleep + * @desc: gpio to check + * + */ +int gpiod_cansleep(const struct gpio_desc *desc) { - return gpiod_cansleep(gpio_to_desc(gpio)); + if (!desc) + return 0; + return desc->chip->can_sleep; } -EXPORT_SYMBOL_GPL(__gpio_cansleep); +EXPORT_SYMBOL_GPL(gpiod_cansleep); /** - * __gpio_to_irq() - return the IRQ corresponding to a GPIO - * @gpio: gpio whose IRQ will be returned (already requested) - * Context: any + * gpiod_to_irq() - return the IRQ corresponding to a GPIO + * @desc: gpio whose IRQ will be returned (already requested) * - * This is used directly or indirectly to implement gpio_to_irq(). - * It returns the number of the IRQ signaled by this (input) GPIO, - * or a negative errno. + * Return the IRQ corresponding to the passed GPIO, or an error code in case of + * error. */ -static int gpiod_to_irq(const struct gpio_desc *desc) +int gpiod_to_irq(const struct gpio_desc *desc) { struct gpio_chip *chip; int offset; @@ -2048,62 +2101,366 @@ static int gpiod_to_irq(const struct gpio_desc *desc) offset = gpio_chip_hwgpio(desc); return chip->to_irq ? chip->to_irq(chip, offset) : -ENXIO; } +EXPORT_SYMBOL_GPL(gpiod_to_irq); + +/** + * gpiod_lock_as_irq() - lock a GPIO to be used as IRQ + * @gpio: the GPIO line to lock as used for IRQ + * + * This is used directly by GPIO drivers that want to lock down + * a certain GPIO line to be used as IRQs, for example in the + * .to_irq() callback of their gpio_chip, or in the .irq_enable() + * of its irq_chip implementation if the GPIO is known from that + * code. + */ +int gpiod_lock_as_irq(struct gpio_desc *desc) +{ + if (!desc) + return -EINVAL; + + if (test_bit(FLAG_IS_OUT, &desc->flags)) { + gpiod_err(desc, + "%s: tried to flag a GPIO set as output for IRQ\n", + __func__); + return -EIO; + } + + set_bit(FLAG_USED_AS_IRQ, &desc->flags); + return 0; +} +EXPORT_SYMBOL_GPL(gpiod_lock_as_irq); + +int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset) +{ + return gpiod_lock_as_irq(gpiochip_offset_to_desc(chip, offset)); +} +EXPORT_SYMBOL_GPL(gpio_lock_as_irq); -int __gpio_to_irq(unsigned gpio) +/** + * gpiod_unlock_as_irq() - unlock a GPIO used as IRQ + * @gpio: the GPIO line to unlock from IRQ usage + * + * This is used directly by GPIO drivers that want to indicate + * that a certain GPIO is no longer used exclusively for IRQ. + */ +void gpiod_unlock_as_irq(struct gpio_desc *desc) { - return gpiod_to_irq(gpio_to_desc(gpio)); + if (!desc) + return; + + clear_bit(FLAG_USED_AS_IRQ, &desc->flags); } -EXPORT_SYMBOL_GPL(__gpio_to_irq); +EXPORT_SYMBOL_GPL(gpiod_unlock_as_irq); +void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset) +{ + return gpiod_unlock_as_irq(gpiochip_offset_to_desc(chip, offset)); +} +EXPORT_SYMBOL_GPL(gpio_unlock_as_irq); -/* There's no value in making it easy to inline GPIO calls that may sleep. - * Common examples include ones connected to I2C or SPI chips. +/** + * gpiod_get_raw_value_cansleep() - return a gpio's raw value + * @desc: gpio whose value will be returned + * + * Return the GPIO's raw value, i.e. the value of the physical line disregarding + * its ACTIVE_LOW status. + * + * This function is to be called from contexts that can sleep. */ +int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc) +{ + might_sleep_if(extra_checks); + if (!desc) + return 0; + return _gpiod_get_raw_value(desc); +} +EXPORT_SYMBOL_GPL(gpiod_get_raw_value_cansleep); -static int gpiod_get_value_cansleep(const struct gpio_desc *desc) +/** + * gpiod_get_value_cansleep() - return a gpio's value + * @desc: gpio whose value will be returned + * + * Return the GPIO's logical value, i.e. taking the ACTIVE_LOW status into + * account. + * + * This function is to be called from contexts that can sleep. + */ +int gpiod_get_value_cansleep(const struct gpio_desc *desc) { - struct gpio_chip *chip; int value; - int offset; might_sleep_if(extra_checks); if (!desc) return 0; - chip = desc->chip; - offset = gpio_chip_hwgpio(desc); - value = chip->get ? chip->get(chip, offset) : 0; - trace_gpio_value(desc_to_gpio(desc), 1, value); + + value = _gpiod_get_raw_value(desc); + if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) + value = !value; + return value; } +EXPORT_SYMBOL_GPL(gpiod_get_value_cansleep); -int gpio_get_value_cansleep(unsigned gpio) +/** + * gpiod_set_raw_value_cansleep() - assign a gpio's raw value + * @desc: gpio whose value will be assigned + * @value: value to assign + * + * Set the raw value of the GPIO, i.e. the value of its physical line without + * regard for its ACTIVE_LOW status. + * + * This function is to be called from contexts that can sleep. + */ +void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value) { - return gpiod_get_value_cansleep(gpio_to_desc(gpio)); + might_sleep_if(extra_checks); + if (!desc) + return; + _gpiod_set_raw_value(desc, value); } -EXPORT_SYMBOL_GPL(gpio_get_value_cansleep); +EXPORT_SYMBOL_GPL(gpiod_set_raw_value_cansleep); -static void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) +/** + * gpiod_set_value_cansleep() - assign a gpio's value + * @desc: gpio whose value will be assigned + * @value: value to assign + * + * Set the logical value of the GPIO, i.e. taking its ACTIVE_LOW status into + * account + * + * This function is to be called from contexts that can sleep. + */ +void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) { - struct gpio_chip *chip; - might_sleep_if(extra_checks); if (!desc) return; - chip = desc->chip; - trace_gpio_value(desc_to_gpio(desc), 0, value); - if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) - _gpio_set_open_drain_value(desc, value); - else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) - _gpio_set_open_source_value(desc, value); + + if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) + value = !value; + _gpiod_set_raw_value(desc, value); +} +EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep); + +/** + * gpiod_add_table() - register GPIO device consumers + * @table: array of consumers to register + * @num: number of consumers in table + */ +void gpiod_add_table(struct gpiod_lookup *table, size_t size) +{ + mutex_lock(&gpio_lookup_lock); + + while (size--) { + list_add_tail(&table->list, &gpio_lookup_list); + table++; + } + + mutex_unlock(&gpio_lookup_lock); +} + +/* + * Caller must have a acquired gpio_lookup_lock + */ +static struct gpio_chip *find_chip_by_name(const char *name) +{ + struct gpio_chip *chip = NULL; + + list_for_each_entry(chip, &gpio_lookup_list, list) { + if (chip->label == NULL) + continue; + if (!strcmp(chip->label, name)) + break; + } + + return chip; +} + +#ifdef CONFIG_OF +static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, + unsigned int idx, unsigned long *flags) +{ + char prop_name[32]; /* 32 is max size of property name */ + enum of_gpio_flags of_flags; + struct gpio_desc *desc; + + if (con_id) + snprintf(prop_name, 32, "%s-gpios", con_id); else - chip->set(chip, gpio_chip_hwgpio(desc), value); + snprintf(prop_name, 32, "gpios"); + + desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx, + &of_flags); + + if (IS_ERR(desc)) + return desc; + + if (of_flags & OF_GPIO_ACTIVE_LOW) + *flags |= GPIOF_ACTIVE_LOW; + + return desc; +} +#else +static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, + unsigned int idx, unsigned long *flags) +{ + return ERR_PTR(-ENODEV); +} +#endif + +static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id, + unsigned int idx, unsigned long *flags) +{ + struct acpi_gpio_info info; + struct gpio_desc *desc; + + desc = acpi_get_gpiod_by_index(dev, idx, &info); + if (IS_ERR(desc)) + return desc; + + if (info.gpioint && info.active_low) + *flags |= GPIOF_ACTIVE_LOW; + + return desc; +} + +static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, + unsigned int idx, unsigned long *flags) +{ + const char *dev_id = dev ? dev_name(dev) : NULL; + struct gpio_desc *desc = ERR_PTR(-ENODEV); + unsigned int match, best = 0; + struct gpiod_lookup *p; + + mutex_lock(&gpio_lookup_lock); + + list_for_each_entry(p, &gpio_lookup_list, list) { + match = 0; + + if (p->dev_id) { + if (!dev_id || strcmp(p->dev_id, dev_id)) + continue; + + match += 2; + } + + if (p->con_id) { + if (!con_id || strcmp(p->con_id, con_id)) + continue; + + match += 1; + } + + if (p->idx != idx) + continue; + + if (match > best) { + struct gpio_chip *chip; + + chip = find_chip_by_name(p->chip_label); + + if (!chip) { + dev_warn(dev, "cannot find GPIO chip %s\n", + p->chip_label); + continue; + } + + if (chip->ngpio >= p->chip_hwnum) { + dev_warn(dev, "GPIO chip %s has %d GPIOs\n", + chip->label, chip->ngpio); + continue; + } + + desc = gpio_to_desc(chip->base + p->chip_hwnum); + *flags = p->flags; + + if (match != 3) + best = match; + else + break; + } + } + + mutex_unlock(&gpio_lookup_lock); + + return desc; +} + +/** + * gpio_get - obtain a GPIO for a given GPIO function + * @dev: GPIO consumer + * @con_id: function within the GPIO consumer + * + * Return the GPIO descriptor corresponding to the function con_id of device + * dev, or an IS_ERR() condition if an error occured. + */ +struct gpio_desc *__must_check gpiod_get(struct device *dev, const char *con_id) +{ + return gpiod_get_index(dev, con_id, 0); +} +EXPORT_SYMBOL_GPL(gpiod_get); + +/** + * gpiod_get_index - obtain a GPIO from a multi-index GPIO function + * @dev: GPIO consumer + * @con_id: function within the GPIO consumer + * @idx: index of the GPIO to obtain in the consumer + * + * This variant of gpiod_get() allows to access GPIOs other than the first + * defined one for functions that define several GPIOs. + * + * Return a valid GPIO descriptor, or an IS_ERR() condition in case of error. + */ +struct gpio_desc *__must_check gpiod_get_index(struct device *dev, + const char *con_id, + unsigned int idx) +{ + struct gpio_desc *desc; + int status; + unsigned long flags = 0; + + dev_dbg(dev, "GPIO lookup for consumer %s\n", con_id); + + /* Using device tree? */ + if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node) { + dev_dbg(dev, "using device tree for GPIO lookup\n"); + desc = of_find_gpio(dev, con_id, idx, &flags); + } else if (IS_ENABLED(CONFIG_ACPI) && dev && ACPI_HANDLE(dev)) { + dev_dbg(dev, "using ACPI for GPIO lookup\n"); + desc = acpi_find_gpio(dev, con_id, idx, &flags); + } else { + dev_dbg(dev, "using lookup tables for GPIO lookup"); + desc = gpiod_find(dev, con_id, idx, &flags); + } + + if (IS_ERR(desc)) { + dev_warn(dev, "lookup for GPIO %s failed\n", con_id); + return desc; + } + + status = gpiod_request(desc, con_id); + + if (status < 0) + return ERR_PTR(status); + + if (flags & GPIOF_ACTIVE_LOW) + set_bit(FLAG_ACTIVE_LOW, &desc->flags); + + return desc; } +EXPORT_SYMBOL_GPL(gpiod_get_index); -void gpio_set_value_cansleep(unsigned gpio, int value) +/** + * gpiod_put - dispose of a GPIO descriptor + * @desc: GPIO descriptor to dispose of + * + * No descriptor can be used after gpiod_put() has been called on it. + */ +void gpiod_put(struct gpio_desc *desc) { - return gpiod_set_value_cansleep(gpio_to_desc(gpio), value); + gpiod_free(desc); } -EXPORT_SYMBOL_GPL(gpio_set_value_cansleep); +EXPORT_SYMBOL_GPL(gpiod_put); #ifdef CONFIG_DEBUG_FS @@ -2113,6 +2470,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) unsigned gpio = chip->base; struct gpio_desc *gdesc = &chip->desc[0]; int is_out; + int is_irq; for (i = 0; i < chip->ngpio; i++, gpio++, gdesc++) { if (!test_bit(FLAG_REQUESTED, &gdesc->flags)) @@ -2120,12 +2478,14 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) gpiod_get_direction(gdesc); is_out = test_bit(FLAG_IS_OUT, &gdesc->flags); - seq_printf(s, " gpio-%-3d (%-20.20s) %s %s", + is_irq = test_bit(FLAG_USED_AS_IRQ, &gdesc->flags); + seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s", gpio, gdesc->label, is_out ? "out" : "in ", chip->get ? (chip->get(chip, i) ? "hi" : "lo") - : "? "); + : "? ", + is_irq ? "IRQ" : " "); seq_printf(s, "\n"); } } diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c index f34beb228d36..17ccba88d636 100644 --- a/drivers/input/misc/ixp4xx-beeper.c +++ b/drivers/input/misc/ixp4xx-beeper.c @@ -20,6 +20,7 @@ #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/interrupt.h> +#include <linux/gpio.h> #include <mach/hardware.h> MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); @@ -35,15 +36,12 @@ static void ixp4xx_spkr_control(unsigned int pin, unsigned int count) spin_lock_irqsave(&beep_lock, flags); - if (count) { - gpio_line_config(pin, IXP4XX_GPIO_OUT); - gpio_line_set(pin, IXP4XX_GPIO_LOW); - + if (count) { + gpio_direction_output(pin, 0); *IXP4XX_OSRT2 = (count & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE; } else { - gpio_line_config(pin, IXP4XX_GPIO_IN); - gpio_line_set(pin, IXP4XX_GPIO_HIGH); - + gpio_direction_output(pin, 1); + gpio_direction_input(pin); *IXP4XX_OSRT2 = 0; } @@ -78,11 +76,13 @@ static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned static irqreturn_t ixp4xx_spkr_interrupt(int irq, void *dev_id) { + unsigned int pin = (unsigned int) dev_id; + /* clear interrupt */ *IXP4XX_OSST = IXP4XX_OSST_TIMER_2_PEND; /* flip the beeper output */ - *IXP4XX_GPIO_GPOUTR ^= (1 << (unsigned int) dev_id); + gpio_set_value(pin, !gpio_get_value(pin)); return IRQ_HANDLED; } @@ -110,11 +110,15 @@ static int ixp4xx_spkr_probe(struct platform_device *dev) input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE); input_dev->event = ixp4xx_spkr_event; + err = gpio_request(dev->id, "ixp4-beeper"); + if (err) + goto err_free_device; + err = request_irq(IRQ_IXP4XX_TIMER2, &ixp4xx_spkr_interrupt, IRQF_NO_SUSPEND, "ixp4xx-beeper", (void *) dev->id); if (err) - goto err_free_device; + goto err_free_gpio; err = input_register_device(input_dev); if (err) @@ -126,6 +130,8 @@ static int ixp4xx_spkr_probe(struct platform_device *dev) err_free_irq: free_irq(IRQ_IXP4XX_TIMER2, (void *)dev->id); + err_free_gpio: + gpio_free(dev->id); err_free_device: input_free_device(input_dev); @@ -144,6 +150,7 @@ static int ixp4xx_spkr_remove(struct platform_device *dev) ixp4xx_spkr_control(pin, 0); free_irq(IRQ_IXP4XX_TIMER2, (void *)dev->id); + gpio_free(dev->id); return 0; } diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c index f22a2193d949..162ac0d73739 100644 --- a/drivers/pinctrl/pinctrl-coh901.c +++ b/drivers/pinctrl/pinctrl-coh901.c @@ -529,6 +529,10 @@ static void u300_gpio_irq_enable(struct irq_data *d) dev_dbg(gpio->dev, "enable IRQ for hwirq %lu on port %s, offset %d\n", d->hwirq, port->name, offset); + if (gpio_lock_as_irq(&gpio->chip, d->hwirq)) + dev_err(gpio->dev, + "unable to lock HW IRQ %lu for IRQ\n", + d->hwirq); local_irq_save(flags); val = readl(U300_PIN_REG(offset, ien)); writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, ien)); @@ -547,6 +551,7 @@ static void u300_gpio_irq_disable(struct irq_data *d) val = readl(U300_PIN_REG(offset, ien)); writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, ien)); local_irq_restore(flags); + gpio_unlock_as_irq(&gpio->chip, d->hwirq); } static struct irq_chip u300_gpio_irqchip = { diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index d7c3ae300fa7..7111c3b59130 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c @@ -634,6 +634,10 @@ static unsigned int nmk_gpio_irq_startup(struct irq_data *d) { struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d); + if (gpio_lock_as_irq(&nmk_chip->chip, d->hwirq)) + dev_err(nmk_chip->chip.dev, + "unable to lock HW IRQ %lu for IRQ\n", + d->hwirq); clk_enable(nmk_chip->clk); nmk_gpio_irq_unmask(d); return 0; @@ -645,6 +649,7 @@ static void nmk_gpio_irq_shutdown(struct irq_data *d) nmk_gpio_irq_mask(d); clk_disable(nmk_chip->clk); + gpio_unlock_as_irq(&nmk_chip->chip, d->hwirq); } static struct irq_chip nmk_gpio_irq_chip = { diff --git a/drivers/ptp/ptp_ixp46x.c b/drivers/ptp/ptp_ixp46x.c index d49b85164fd2..4a08727fcaf3 100644 --- a/drivers/ptp/ptp_ixp46x.c +++ b/drivers/ptp/ptp_ixp46x.c @@ -259,8 +259,15 @@ static struct ixp_clock ixp_clock; static int setup_interrupt(int gpio) { int irq; + int err; - gpio_line_config(gpio, IXP4XX_GPIO_IN); + err = gpio_request(gpio, "ixp4-ptp"); + if (err) + return err; + + err = gpio_direction_input(gpio); + if (err) + return err; irq = gpio_to_irq(gpio); diff --git a/drivers/staging/media/lirc/lirc_serial.c b/drivers/staging/media/lirc/lirc_serial.c index af08e677b60f..f6bc4c91ab35 100644 --- a/drivers/staging/media/lirc/lirc_serial.c +++ b/drivers/staging/media/lirc/lirc_serial.c @@ -67,7 +67,7 @@ #include <linux/delay.h> #include <linux/poll.h> #include <linux/platform_device.h> - +#include <linux/gpio.h> #include <linux/io.h> #include <linux/irq.h> #include <linux/fcntl.h> @@ -321,7 +321,7 @@ static void on(void) * status LED and ground */ if (type == LIRC_NSLU2) { - gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_LOW); + gpio_set_value(NSLU2_LED_GRN, 0); return; } #endif @@ -335,7 +335,7 @@ static void off(void) { #ifdef CONFIG_LIRC_SERIAL_NSLU2 if (type == LIRC_NSLU2) { - gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_HIGH); + gpio_set_value(NSLU2_LED_GRN, 1); return; } #endif @@ -839,6 +839,16 @@ static int lirc_serial_probe(struct platform_device *dev) { int i, nlow, nhigh, result; +#ifdef CONFIG_LIRC_SERIAL_NSLU2 + /* This GPIO is used for a LED on the NSLU2 */ + result = devm_gpio_request(dev, NSLU2_LED_GRN, "lirc-serial"); + if (result) + return result; + result = gpio_direction_output(NSLU2_LED_GRN, 0); + if (result) + return result; +#endif + result = request_irq(irq, irq_handler, (share_irq ? IRQF_SHARED : 0), LIRC_DRIVER_NAME, (void *)&hardware); diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 523f40525535..a5f56a0213a7 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -10,6 +10,8 @@ #ifdef CONFIG_GPIOLIB #include <linux/compiler.h> +#include <linux/gpio/driver.h> +#include <linux/gpio/consumer.h> /* Platforms may implement their GPIO interface with library code, * at a small performance cost for non-inlined operations and some @@ -49,122 +51,11 @@ struct module; struct device_node; struct gpio_desc; -/** - * struct gpio_chip - abstract a GPIO controller - * @label: for diagnostics - * @dev: optional device providing the GPIOs - * @owner: helps prevent removal of modules exporting active GPIOs - * @list: links gpio_chips together for traversal - * @request: optional hook for chip-specific activation, such as - * enabling module power and clock; may sleep - * @free: optional hook for chip-specific deactivation, such as - * disabling module power and clock; may sleep - * @get_direction: returns direction for signal "offset", 0=out, 1=in, - * (same as GPIOF_DIR_XXX), or negative error - * @direction_input: configures signal "offset" as input, or returns error - * @get: returns value for signal "offset"; for output signals this - * returns either the value actually sensed, or zero - * @direction_output: configures signal "offset" as output, or returns error - * @set_debounce: optional hook for setting debounce time for specified gpio in - * interrupt triggered gpio chips - * @set: assigns output value for signal "offset" - * @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 - * will be used when this is omitted, but custom code can show extra - * state (such as pullup/pulldown configuration). - * @base: identifies the first GPIO number handled by this chip; or, if - * negative during registration, requests dynamic ID allocation. - * @ngpio: the number of GPIOs handled by this controller; the last GPIO - * handled is (base + ngpio - 1). - * @desc: array of ngpio descriptors. Private. - * @can_sleep: flag must be set iff get()/set() methods sleep, as they - * must while accessing GPIO expander chips over I2C or SPI - * @names: if set, must be an array of strings to use as alternative - * names for the GPIOs in this chip. Any entry in the array - * may be NULL if there is no alias for the GPIO, however the - * array must be @ngpio entries long. A name can include a single printk - * format specifier for an unsigned int. It is substituted by the actual - * number of the gpio. - * - * A gpio_chip can help platforms abstract various sources of GPIOs so - * they can all be accessed through a common programing interface. - * Example sources would be SOC controllers, FPGAs, multifunction - * chips, dedicated GPIO expanders, and so on. - * - * Each chip controls a number of signals, identified in method calls - * by "offset" values in the range 0..(@ngpio - 1). When those signals - * are referenced through calls like gpio_get_value(gpio), the offset - * is calculated by subtracting @base from the gpio number. - */ -struct gpio_chip { - const char *label; - struct device *dev; - struct module *owner; - struct list_head list; - - int (*request)(struct gpio_chip *chip, - unsigned offset); - void (*free)(struct gpio_chip *chip, - unsigned offset); - int (*get_direction)(struct gpio_chip *chip, - unsigned offset); - int (*direction_input)(struct gpio_chip *chip, - unsigned offset); - int (*get)(struct gpio_chip *chip, - unsigned offset); - int (*direction_output)(struct gpio_chip *chip, - unsigned offset, int value); - int (*set_debounce)(struct gpio_chip *chip, - unsigned offset, unsigned debounce); - - void (*set)(struct gpio_chip *chip, - unsigned offset, int value); - - int (*to_irq)(struct gpio_chip *chip, - unsigned offset); - - void (*dbg_show)(struct seq_file *s, - struct gpio_chip *chip); - int base; - u16 ngpio; - struct gpio_desc *desc; - const char *const *names; - unsigned can_sleep:1; - unsigned exported:1; - -#if defined(CONFIG_OF_GPIO) - /* - * If CONFIG_OF is enabled, then all GPIO controllers described in the - * device tree automatically may have an OF translation - */ - struct device_node *of_node; - int of_gpio_n_cells; - int (*of_xlate)(struct gpio_chip *gc, - const struct of_phandle_args *gpiospec, u32 *flags); -#endif -#ifdef CONFIG_PINCTRL - /* - * If CONFIG_PINCTRL is enabled, then gpio controllers can optionally - * describe the actual pin range which they serve in an SoC. This - * information would be used by pinctrl subsystem to configure - * corresponding pins for gpio usage. - */ - struct list_head pin_ranges; -#endif -}; - -extern const char *gpiochip_is_requested(struct gpio_chip *chip, - unsigned offset); -extern struct gpio_chip *gpio_to_chip(unsigned gpio); - -/* add/remove chips */ -extern int gpiochip_add(struct gpio_chip *chip); -extern int __must_check gpiochip_remove(struct gpio_chip *chip); -extern struct gpio_chip *gpiochip_find(void *data, - int (*match)(struct gpio_chip *chip, - void *data)); - +/* caller holds gpio_lock *OR* gpio is marked as requested */ +static inline struct gpio_chip *gpio_to_chip(unsigned gpio) +{ + return gpiod_to_chip(gpio_to_desc(gpio)); +} /* Always use the library code for GPIO management calls, * or when sleeping may be involved. @@ -172,43 +63,84 @@ extern struct gpio_chip *gpiochip_find(void *data, extern int gpio_request(unsigned gpio, const char *label); extern void gpio_free(unsigned gpio); -extern int gpio_direction_input(unsigned gpio); -extern int gpio_direction_output(unsigned gpio, int value); +static inline int gpio_direction_input(unsigned gpio) +{ + return gpiod_direction_input(gpio_to_desc(gpio)); +} +static inline int gpio_direction_output(unsigned gpio, int value) +{ + return gpiod_direction_output(gpio_to_desc(gpio), value); +} -extern int gpio_set_debounce(unsigned gpio, unsigned debounce); +static inline int gpio_set_debounce(unsigned gpio, unsigned debounce) +{ + return gpiod_set_debounce(gpio_to_desc(gpio), debounce); +} -extern int gpio_get_value_cansleep(unsigned gpio); -extern void gpio_set_value_cansleep(unsigned gpio, int value); +static inline int gpio_get_value_cansleep(unsigned gpio) +{ + return gpiod_get_raw_value_cansleep(gpio_to_desc(gpio)); +} +static inline void gpio_set_value_cansleep(unsigned gpio, int value) +{ + return gpiod_set_raw_value_cansleep(gpio_to_desc(gpio), value); +} /* A platform's <asm/gpio.h> code may want to inline the I/O calls when * the GPIO is constant and refers to some always-present controller, * giving direct access to chip registers and tight bitbanging loops. */ -extern int __gpio_get_value(unsigned gpio); -extern void __gpio_set_value(unsigned gpio, int value); +static inline int __gpio_get_value(unsigned gpio) +{ + return gpiod_get_raw_value(gpio_to_desc(gpio)); +} +static inline void __gpio_set_value(unsigned gpio, int value) +{ + return gpiod_set_raw_value(gpio_to_desc(gpio), value); +} + +static inline int __gpio_cansleep(unsigned gpio) +{ + return gpiod_cansleep(gpio_to_desc(gpio)); +} -extern int __gpio_cansleep(unsigned gpio); +static inline int __gpio_to_irq(unsigned gpio) +{ + return gpiod_to_irq(gpio_to_desc(gpio)); +} -extern int __gpio_to_irq(unsigned gpio); +extern int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset); +extern void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset); extern int gpio_request_one(unsigned gpio, unsigned long flags, const char *label); extern int gpio_request_array(const struct gpio *array, size_t num); extern void gpio_free_array(const struct gpio *array, size_t num); -#ifdef CONFIG_GPIO_SYSFS - /* * A sysfs interface can be exported by individual drivers if they want, * but more typically is configured entirely from userspace. */ -extern int gpio_export(unsigned gpio, bool direction_may_change); -extern int gpio_export_link(struct device *dev, const char *name, - unsigned gpio); -extern int gpio_sysfs_set_active_low(unsigned gpio, int value); -extern void gpio_unexport(unsigned gpio); +static inline int gpio_export(unsigned gpio, bool direction_may_change) +{ + return gpiod_export(gpio_to_desc(gpio), direction_may_change); +} -#endif /* CONFIG_GPIO_SYSFS */ +static inline int gpio_export_link(struct device *dev, const char *name, + unsigned gpio) +{ + return gpiod_export_link(dev, name, gpio_to_desc(gpio)); +} + +static inline int gpio_sysfs_set_active_low(unsigned gpio, int value) +{ + return gpiod_sysfs_set_active_low(gpio_to_desc(gpio), value); +} + +static inline void gpio_unexport(unsigned gpio) +{ + gpiod_unexport(gpio_to_desc(gpio)); +} #ifdef CONFIG_PINCTRL @@ -288,31 +220,4 @@ static inline void gpio_set_value_cansleep(unsigned gpio, int value) #endif /* !CONFIG_GPIOLIB */ -#ifndef CONFIG_GPIO_SYSFS - -struct device; - -/* sysfs support is only available with gpiolib, where it's optional */ - -static inline int gpio_export(unsigned gpio, bool direction_may_change) -{ - return -ENOSYS; -} - -static inline int gpio_export_link(struct device *dev, const char *name, - unsigned gpio) -{ - return -ENOSYS; -} - -static inline int gpio_sysfs_set_active_low(unsigned gpio, int value) -{ - return -ENOSYS; -} - -static inline void gpio_unexport(unsigned gpio) -{ -} -#endif /* CONFIG_GPIO_SYSFS */ - #endif /* _ASM_GENERIC_GPIO_H */ diff --git a/include/linux/acpi_gpio.h b/include/linux/acpi_gpio.h index 4c120a1e0ca3..d875bc3dba3c 100644 --- a/include/linux/acpi_gpio.h +++ b/include/linux/acpi_gpio.h @@ -2,36 +2,35 @@ #define _LINUX_ACPI_GPIO_H_ #include <linux/device.h> +#include <linux/err.h> #include <linux/errno.h> #include <linux/gpio.h> +#include <linux/gpio/consumer.h> /** * struct acpi_gpio_info - ACPI GPIO specific information * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo + * @active_low: in case of @gpioint, the pin is active low */ struct acpi_gpio_info { bool gpioint; + bool active_low; }; #ifdef CONFIG_GPIO_ACPI -int acpi_get_gpio(char *path, int pin); -int acpi_get_gpio_by_index(struct device *dev, int index, - struct acpi_gpio_info *info); +struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index, + struct acpi_gpio_info *info); void acpi_gpiochip_request_interrupts(struct gpio_chip *chip); void acpi_gpiochip_free_interrupts(struct gpio_chip *chip); #else /* CONFIG_GPIO_ACPI */ -static inline int acpi_get_gpio(char *path, int pin) +static inline struct gpio_desc * +acpi_get_gpiod_by_index(struct device *dev, int index, + struct acpi_gpio_info *info) { - return -ENODEV; -} - -static inline int acpi_get_gpio_by_index(struct device *dev, int index, - struct acpi_gpio_info *info) -{ - return -ENODEV; + return ERR_PTR(-ENOSYS); } static inline void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { } @@ -39,4 +38,14 @@ static inline void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { } #endif /* CONFIG_GPIO_ACPI */ +static inline int acpi_get_gpio_by_index(struct device *dev, int index, + struct acpi_gpio_info *info) +{ + struct gpio_desc *desc = acpi_get_gpiod_by_index(dev, index, info); + + if (IS_ERR(desc)) + return PTR_ERR(desc); + return desc_to_gpio(desc); +} + #endif /* _LINUX_ACPI_GPIO_H_ */ diff --git a/include/linux/gpio.h b/include/linux/gpio.h index b8d0e53a802f..13dfd24d01ab 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h @@ -16,14 +16,17 @@ #define GPIOF_OUT_INIT_LOW (GPIOF_DIR_OUT | GPIOF_INIT_LOW) #define GPIOF_OUT_INIT_HIGH (GPIOF_DIR_OUT | GPIOF_INIT_HIGH) +/* Gpio pin is active-low */ +#define GPIOF_ACTIVE_LOW (1 << 2) + /* Gpio pin is open drain */ -#define GPIOF_OPEN_DRAIN (1 << 2) +#define GPIOF_OPEN_DRAIN (1 << 3) /* Gpio pin is open source */ -#define GPIOF_OPEN_SOURCE (1 << 3) +#define GPIOF_OPEN_SOURCE (1 << 4) -#define GPIOF_EXPORT (1 << 4) -#define GPIOF_EXPORT_CHANGEABLE (1 << 5) +#define GPIOF_EXPORT (1 << 5) +#define GPIOF_EXPORT_CHANGEABLE (1 << 6) #define GPIOF_EXPORT_DIR_FIXED (GPIOF_EXPORT) #define GPIOF_EXPORT_DIR_CHANGEABLE (GPIOF_EXPORT | GPIOF_EXPORT_CHANGEABLE) @@ -74,6 +77,15 @@ static inline int irq_to_gpio(unsigned int irq) #endif /* ! CONFIG_ARCH_HAVE_CUSTOM_GPIO_H */ +/* CONFIG_GPIOLIB: bindings for managed devices that want to request gpios */ + +struct device; + +int devm_gpio_request(struct device *dev, unsigned gpio, const char *label); +int devm_gpio_request_one(struct device *dev, unsigned gpio, + unsigned long flags, const char *label); +void devm_gpio_free(struct device *dev, unsigned int gpio); + #else /* ! CONFIG_GPIOLIB */ #include <linux/kernel.h> @@ -205,6 +217,18 @@ static inline int gpio_to_irq(unsigned gpio) return -EINVAL; } +static inline int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset) +{ + WARN_ON(1); + return -EINVAL; +} + +static inline void gpio_unlock_as_irq(struct gpio_chip *chip, + unsigned int offset) +{ + WARN_ON(1); +} + static inline int irq_to_gpio(unsigned irq) { /* irq can never have been returned from gpio_to_irq() */ @@ -236,14 +260,25 @@ gpiochip_remove_pin_ranges(struct gpio_chip *chip) WARN_ON(1); } -#endif /* ! CONFIG_GPIOLIB */ +static inline int devm_gpio_request(struct device *dev, unsigned gpio, + const char *label) +{ + WARN_ON(1); + return -EINVAL; +} -struct device; +static inline int devm_gpio_request_one(struct device *dev, unsigned gpio, + unsigned long flags, const char *label) +{ + WARN_ON(1); + return -EINVAL; +} -/* bindings for managed devices that want to request gpios */ -int devm_gpio_request(struct device *dev, unsigned gpio, const char *label); -int devm_gpio_request_one(struct device *dev, unsigned gpio, - unsigned long flags, const char *label); -void devm_gpio_free(struct device *dev, unsigned int gpio); +static inline void devm_gpio_free(struct device *dev, unsigned int gpio) +{ + WARN_ON(1); +} + +#endif /* ! CONFIG_GPIOLIB */ #endif /* __LINUX_GPIO_H */ diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h new file mode 100644 index 000000000000..4d34dbbbad4d --- /dev/null +++ b/include/linux/gpio/consumer.h @@ -0,0 +1,253 @@ +#ifndef __LINUX_GPIO_CONSUMER_H +#define __LINUX_GPIO_CONSUMER_H + +#include <linux/err.h> +#include <linux/kernel.h> + +#ifdef CONFIG_GPIOLIB + +struct device; +struct gpio_chip; + +/** + * Opaque descriptor for a GPIO. These are obtained using gpiod_get() and are + * preferable to the old integer-based handles. + * + * Contrary to integers, a pointer to a gpio_desc is guaranteed to be valid + * until the GPIO is released. + */ +struct gpio_desc; + +/* Acquire and dispose GPIOs */ +struct gpio_desc *__must_check gpiod_get(struct device *dev, + const char *con_id); +struct gpio_desc *__must_check gpiod_get_index(struct device *dev, + const char *con_id, + unsigned int idx); +void gpiod_put(struct gpio_desc *desc); + +struct gpio_desc *__must_check devm_gpiod_get(struct device *dev, + const char *con_id); +struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, + const char *con_id, + unsigned int idx); +void devm_gpiod_put(struct device *dev, struct gpio_desc *desc); + +int gpiod_get_direction(const struct gpio_desc *desc); +int gpiod_direction_input(struct gpio_desc *desc); +int gpiod_direction_output(struct gpio_desc *desc, int value); + +/* Value get/set from non-sleeping context */ +int gpiod_get_value(const struct gpio_desc *desc); +void gpiod_set_value(struct gpio_desc *desc, int value); +int gpiod_get_raw_value(const struct gpio_desc *desc); +void gpiod_set_raw_value(struct gpio_desc *desc, int value); + +/* Value get/set from sleeping context */ +int gpiod_get_value_cansleep(const struct gpio_desc *desc); +void gpiod_set_value_cansleep(struct gpio_desc *desc, int value); +int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc); +void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value); + +int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce); + +int gpiod_is_active_low(const struct gpio_desc *desc); +int gpiod_cansleep(const struct gpio_desc *desc); + +int gpiod_to_irq(const struct gpio_desc *desc); + +/* Convert between the old gpio_ and new gpiod_ interfaces */ +struct gpio_desc *gpio_to_desc(unsigned gpio); +int desc_to_gpio(const struct gpio_desc *desc); +struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc); + +#else /* CONFIG_GPIOLIB */ + +static inline struct gpio_desc *__must_check gpiod_get(struct device *dev, + const char *con_id) +{ + return ERR_PTR(-ENOSYS); +} +static inline struct gpio_desc *__must_check gpiod_get_index(struct device *dev, + const char *con_id, + unsigned int idx) +{ + return ERR_PTR(-ENOSYS); +} +static inline void gpiod_put(struct gpio_desc *desc) +{ + might_sleep(); + + /* GPIO can never have been requested */ + WARN_ON(1); +} + +static inline struct gpio_desc *__must_check devm_gpiod_get(struct device *dev, + const char *con_id) +{ + return ERR_PTR(-ENOSYS); +} +static inline +struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, + const char *con_id, + unsigned int idx) +{ + return ERR_PTR(-ENOSYS); +} +static inline void devm_gpiod_put(struct device *dev, struct gpio_desc *desc) +{ + might_sleep(); + + /* GPIO can never have been requested */ + WARN_ON(1); +} + + +static inline int gpiod_get_direction(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return -ENOSYS; +} +static inline int gpiod_direction_input(struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return -ENOSYS; +} +static inline int gpiod_direction_output(struct gpio_desc *desc, int value) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return -ENOSYS; +} + + +static inline int gpiod_get_value(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return 0; +} +static inline void gpiod_set_value(struct gpio_desc *desc, int value) +{ + /* GPIO can never have been requested */ + WARN_ON(1); +} +static inline int gpiod_get_raw_value(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return 0; +} +static inline void gpiod_set_raw_value(struct gpio_desc *desc, int value) +{ + /* GPIO can never have been requested */ + WARN_ON(1); +} + +static inline int gpiod_get_value_cansleep(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return 0; +} +static inline void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) +{ + /* GPIO can never have been requested */ + WARN_ON(1); +} +static inline int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return 0; +} +static inline void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, + int value) +{ + /* GPIO can never have been requested */ + WARN_ON(1); +} + +static inline int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return -ENOSYS; +} + +static inline int gpiod_is_active_low(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return 0; +} +static inline int gpiod_cansleep(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return 0; +} + +static inline int gpiod_to_irq(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return -EINVAL; +} + +static inline struct gpio_desc *gpio_to_desc(unsigned gpio) +{ + return ERR_PTR(-EINVAL); +} +static inline int desc_to_gpio(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return -EINVAL; +} +static inline struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return ERR_PTR(-ENODEV); +} + + +#endif /* CONFIG_GPIOLIB */ + +#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS) + +int gpiod_export(struct gpio_desc *desc, bool direction_may_change); +int gpiod_export_link(struct device *dev, const char *name, + struct gpio_desc *desc); +int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value); +void gpiod_unexport(struct gpio_desc *desc); + +#else /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */ + +static inline int gpiod_export(struct gpio_desc *desc, + bool direction_may_change) +{ + return -ENOSYS; +} + +static inline int gpiod_export_link(struct device *dev, const char *name, + struct gpio_desc *desc) +{ + return -ENOSYS; +} + +static inline int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value) +{ + return -ENOSYS; +} + +static inline void gpiod_unexport(struct gpio_desc *desc) +{ +} + +#endif /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */ + +#endif diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h new file mode 100644 index 000000000000..656a27efb2c8 --- /dev/null +++ b/include/linux/gpio/driver.h @@ -0,0 +1,184 @@ +#ifndef __LINUX_GPIO_DRIVER_H +#define __LINUX_GPIO_DRIVER_H + +#include <linux/types.h> + +struct device; +struct gpio_desc; +struct seq_file; + +/** + * struct gpio_chip - abstract a GPIO controller + * @label: for diagnostics + * @dev: optional device providing the GPIOs + * @owner: helps prevent removal of modules exporting active GPIOs + * @list: links gpio_chips together for traversal + * @request: optional hook for chip-specific activation, such as + * enabling module power and clock; may sleep + * @free: optional hook for chip-specific deactivation, such as + * disabling module power and clock; may sleep + * @get_direction: returns direction for signal "offset", 0=out, 1=in, + * (same as GPIOF_DIR_XXX), or negative error + * @direction_input: configures signal "offset" as input, or returns error + * @direction_output: configures signal "offset" as output, or returns error + * @get: returns value for signal "offset"; for output signals this + * returns either the value actually sensed, or zero + * @set: assigns output value for signal "offset" + * @set_debounce: optional hook for setting debounce time for specified gpio in + * interrupt triggered gpio chips + * @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 + * will be used when this is omitted, but custom code can show extra + * state (such as pullup/pulldown configuration). + * @base: identifies the first GPIO number handled by this chip; or, if + * negative during registration, requests dynamic ID allocation. + * @ngpio: the number of GPIOs handled by this controller; the last GPIO + * handled is (base + ngpio - 1). + * @desc: array of ngpio descriptors. Private. + * @can_sleep: flag must be set iff get()/set() methods sleep, as they + * must while accessing GPIO expander chips over I2C or SPI + * @names: if set, must be an array of strings to use as alternative + * names for the GPIOs in this chip. Any entry in the array + * may be NULL if there is no alias for the GPIO, however the + * array must be @ngpio entries long. A name can include a single printk + * format specifier for an unsigned int. It is substituted by the actual + * number of the gpio. + * + * A gpio_chip can help platforms abstract various sources of GPIOs so + * they can all be accessed through a common programing interface. + * Example sources would be SOC controllers, FPGAs, multifunction + * chips, dedicated GPIO expanders, and so on. + * + * Each chip controls a number of signals, identified in method calls + * by "offset" values in the range 0..(@ngpio - 1). When those signals + * are referenced through calls like gpio_get_value(gpio), the offset + * is calculated by subtracting @base from the gpio number. + */ +struct gpio_chip { + const char *label; + struct device *dev; + struct module *owner; + struct list_head list; + + int (*request)(struct gpio_chip *chip, + unsigned offset); + void (*free)(struct gpio_chip *chip, + unsigned offset); + int (*get_direction)(struct gpio_chip *chip, + unsigned offset); + int (*direction_input)(struct gpio_chip *chip, + unsigned offset); + int (*direction_output)(struct gpio_chip *chip, + unsigned offset, int value); + int (*get)(struct gpio_chip *chip, + unsigned offset); + void (*set)(struct gpio_chip *chip, + unsigned offset, int value); + int (*set_debounce)(struct gpio_chip *chip, + unsigned offset, + unsigned debounce); + + int (*to_irq)(struct gpio_chip *chip, + unsigned offset); + + void (*dbg_show)(struct seq_file *s, + struct gpio_chip *chip); + int base; + u16 ngpio; + struct gpio_desc *desc; + const char *const *names; + unsigned can_sleep:1; + unsigned exported:1; + +#if defined(CONFIG_OF_GPIO) + /* + * If CONFIG_OF is enabled, then all GPIO controllers described in the + * device tree automatically may have an OF translation + */ + struct device_node *of_node; + int of_gpio_n_cells; + int (*of_xlate)(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, u32 *flags); +#endif +#ifdef CONFIG_PINCTRL + /* + * If CONFIG_PINCTRL is enabled, then gpio controllers can optionally + * describe the actual pin range which they serve in an SoC. This + * information would be used by pinctrl subsystem to configure + * corresponding pins for gpio usage. + */ + struct list_head pin_ranges; +#endif +}; + +extern const char *gpiochip_is_requested(struct gpio_chip *chip, + unsigned offset); + +/* add/remove chips */ +extern int gpiochip_add(struct gpio_chip *chip); +extern int __must_check gpiochip_remove(struct gpio_chip *chip); +extern struct gpio_chip *gpiochip_find(void *data, + int (*match)(struct gpio_chip *chip, void *data)); + +/* lock/unlock as IRQ */ +int gpiod_lock_as_irq(struct gpio_desc *desc); +void gpiod_unlock_as_irq(struct gpio_desc *desc); + +/** + * Lookup table for associating GPIOs to specific devices and functions using + * platform data. + */ +struct gpiod_lookup { + struct list_head list; + /* + * name of the chip the GPIO belongs to + */ + const char *chip_label; + /* + * hardware number (i.e. relative to the chip) of the GPIO + */ + u16 chip_hwnum; + /* + * name of device that can claim this GPIO + */ + const char *dev_id; + /* + * name of the GPIO from the device's point of view + */ + const char *con_id; + /* + * index of the GPIO in case several GPIOs share the same name + */ + unsigned int idx; + /* + * mask of GPIOF_* values + */ + unsigned long flags; +}; + +/* + * Simple definition of a single GPIO under a con_id + */ +#define GPIO_LOOKUP(_chip_label, _chip_hwnum, _dev_id, _con_id, _flags) \ + GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _dev_id, _con_id, 0, _flags) + +/* + * Use this macro if you need to have several GPIOs under the same con_id. + * Each GPIO needs to use a different index and can be accessed using + * gpiod_get_index() + */ +#define GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _dev_id, _con_id, _idx, \ + _flags) \ +{ \ + .chip_label = _chip_label, \ + .chip_hwnum = _chip_hwnum, \ + .dev_id = _dev_id, \ + .con_id = _con_id, \ + .idx = _idx, \ + .flags = _flags, \ +} + +void gpiod_add_table(struct gpiod_lookup *table, size_t size); + +#endif diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h index a83dc6f5008e..f14123a5a9df 100644 --- a/include/linux/of_gpio.h +++ b/include/linux/of_gpio.h @@ -19,6 +19,7 @@ #include <linux/errno.h> #include <linux/gpio.h> #include <linux/of.h> +#include <linux/gpio/consumer.h> struct device_node; @@ -47,7 +48,7 @@ static inline struct of_mm_gpio_chip *to_of_mm_gpio_chip(struct gpio_chip *gc) return container_of(gc, struct of_mm_gpio_chip, gc); } -extern int of_get_named_gpio_flags(struct device_node *np, +extern struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, const char *list_name, int index, enum of_gpio_flags *flags); extern int of_mm_gpiochip_add(struct device_node *np, @@ -62,10 +63,10 @@ extern int of_gpio_simple_xlate(struct gpio_chip *gc, #else /* CONFIG_OF_GPIO */ /* Drivers may not strictly depend on the GPIO support, so let them link. */ -static inline int of_get_named_gpio_flags(struct device_node *np, +static inline struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, const char *list_name, int index, enum of_gpio_flags *flags) { - return -ENOSYS; + return ERR_PTR(-ENOSYS); } static inline int of_gpio_simple_xlate(struct gpio_chip *gc, @@ -80,6 +81,18 @@ static inline void of_gpiochip_remove(struct gpio_chip *gc) { } #endif /* CONFIG_OF_GPIO */ +static inline int of_get_named_gpio_flags(struct device_node *np, + const char *list_name, int index, enum of_gpio_flags *flags) +{ + struct gpio_desc *desc; + desc = of_get_named_gpiod_flags(np, list_name, index, flags); + + if (IS_ERR(desc)) + return PTR_ERR(desc); + else + return desc_to_gpio(desc); +} + /** * of_gpio_named_count() - Count GPIOs for a device * @np: device node to count GPIOs for @@ -117,15 +130,21 @@ static inline int of_gpio_count(struct device_node *np) } /** - * of_get_gpio_flags() - Get a GPIO number and flags to use with GPIO API + * of_get_gpiod_flags() - Get a GPIO descriptor and flags to use with GPIO API * @np: device node to get GPIO from * @index: index of the GPIO * @flags: a flags pointer to fill in * - * Returns GPIO number to use with Linux generic GPIO API, or one of the errno + * Returns GPIO descriptor to use with Linux generic GPIO API, or a errno * value on the error condition. If @flags is not NULL the function also fills * in flags for the GPIO. */ +static inline struct gpio_desc *of_get_gpiod_flags(struct device_node *np, + int index, enum of_gpio_flags *flags) +{ + return of_get_named_gpiod_flags(np, "gpios", index, flags); +} + static inline int of_get_gpio_flags(struct device_node *np, int index, enum of_gpio_flags *flags) { |