diff options
author | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-04-11 10:41:07 +0300 |
---|---|---|
committer | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-04-13 08:17:18 +0300 |
commit | e09b41010ba33a20a87472ee821fa407a5b8da36 (patch) | |
tree | d10dc367189862e7ca5c592f033dc3726e1df4e3 /kernel/drivers/gpio | |
parent | f93b97fd65072de626c074dbe099a1fff05ce060 (diff) |
These changes are the raw update to linux-4.4.6-rt14. Kernel sources
are taken from kernel.org, and rt patch from the rt wiki download page.
During the rebasing, the following patch collided:
Force tick interrupt and get rid of softirq magic(I70131fb85).
Collisions have been removed because its logic was found on the
source already.
Change-Id: I7f57a4081d9deaa0d9ccfc41a6c8daccdee3b769
Signed-off-by: José Pekkarinen <jose.pekkarinen@nokia.com>
Diffstat (limited to 'kernel/drivers/gpio')
73 files changed, 4988 insertions, 2036 deletions
diff --git a/kernel/drivers/gpio/Kconfig b/kernel/drivers/gpio/Kconfig index caefe806d..b18bea08f 100644 --- a/kernel/drivers/gpio/Kconfig +++ b/kernel/drivers/gpio/Kconfig @@ -113,19 +113,34 @@ config GPIO_74XX_MMIO config GPIO_ALTERA tristate "Altera GPIO" depends on OF_GPIO - select GPIO_GENERIC select GPIOLIB_IRQCHIP help Say Y or M here to build support for the Altera PIO device. If driver is built as a module it will be called gpio-altera. +config GPIO_AMDPT + tristate "AMD Promontory GPIO support" + depends on ACPI + help + driver for GPIO functionality on Promontory IOHub + Require ACPI ASL code to enumerate as a platform device. + config GPIO_BCM_KONA bool "Broadcom Kona GPIO" depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST) help Turn on GPIO support for Broadcom "Kona" chips. +config GPIO_BRCMSTB + tristate "BRCMSTB GPIO support" + default y if ARCH_BRCMSTB + depends on OF_GPIO && (ARCH_BRCMSTB || COMPILE_TEST) + select GPIO_GENERIC + select GPIOLIB_IRQCHIP + help + Say yes here to enable GPIO support for Broadcom STB (BCM7XXX) SoCs. + config GPIO_CLPS711X tristate "CLPS711X GPIO support" depends on ARCH_CLPS711X || COMPILE_TEST @@ -159,15 +174,14 @@ config GPIO_EP93XX depends on ARCH_EP93XX select GPIO_GENERIC -config GPIO_F7188X - tristate "F71869, F71869A, F71882FG and F71889F GPIO support" - depends on X86 +config GPIO_ETRAXFS + bool "Axis ETRAX FS General I/O" + depends on CRIS || COMPILE_TEST + depends on OF + select GPIO_GENERIC + select GPIOLIB_IRQCHIP help - This option enables support for GPIOs found on Fintek Super-I/O - chips F71869, F71869A, F71882FG and F71889F. - - To compile this driver as a module, choose M here: the module will - be called f7188x-gpio. + Say yes here to support the GPIO controller on Axis ETRAX FS SoCs. config GPIO_GE_FPGA bool "GE FPGA based GPIO" @@ -218,18 +232,20 @@ config GPIO_IOP If unsure, say N. -config GPIO_IT8761E - tristate "IT8761E GPIO support" - depends on X86 # unconditional access to IO space. - help - Say yes here to support GPIO functionality of IT8761E super I/O chip. - config GPIO_LOONGSON bool "Loongson-2/3 GPIO support" depends on CPU_LOONGSON2 || CPU_LOONGSON3 help driver for GPIO functionality on Loongson-2F/3A/3B processors. +config GPIO_LPC18XX + bool "NXP LPC18XX/43XX GPIO support" + default y if ARCH_LPC18XX + depends on OF_GPIO && (ARCH_LPC18XX || COMPILE_TEST) + help + Select this option to enable GPIO driver for + NXP LPC18XX/43XX devices. + config GPIO_LYNXPOINT tristate "Intel Lynxpoint GPIO support" depends on ACPI && X86 @@ -272,19 +288,10 @@ config GPIO_MPC8XXX Say Y here if you're going to use hardware that connects to the MPC512x/831x/834x/837x/8572/8610 GPIOs. -config GPIO_MSM_V2 - tristate "Qualcomm MSM GPIO v2" - depends on GPIOLIB && OF && ARCH_QCOM - help - Say yes here to support the GPIO interface on ARM v7 based - Qualcomm MSM chips. Most of the pins on the MSM can be - selected for GPIO, and are controlled by this driver. - config GPIO_MVEBU def_bool y depends on PLAT_ORION depends on OF - select GPIO_GENERIC select GENERIC_IRQ_CHIP config GPIO_MXC @@ -308,7 +315,7 @@ config GPIO_OCTEON family of SOCs. config GPIO_OMAP - bool "TI OMAP GPIO support" if COMPILE_TEST && !ARCH_OMAP2PLUS + tristate "TI OMAP GPIO support" if ARCH_OMAP2PLUS || COMPILE_TEST default y if ARCH_OMAP depends on ARM select GENERIC_IRQ_CHIP @@ -332,7 +339,7 @@ config GPIO_PXA config GPIO_RCAR tristate "Renesas R-Car GPIO" - depends on ARM && (ARCH_SHMOBILE || COMPILE_TEST) + depends on ARCH_SHMOBILE || COMPILE_TEST select GPIOLIB_IRQCHIP help Say yes here to support GPIO on Renesas R-Car SoCs. @@ -344,42 +351,6 @@ config GPIO_SAMSUNG Legacy GPIO support. Use only for platforms without support for pinctrl. -config GPIO_SCH - tristate "Intel SCH/TunnelCreek/Centerton/Quark X1000 GPIO" - depends on PCI && X86 - select MFD_CORE - select LPC_SCH - help - Say yes here to support GPIO interface on Intel Poulsbo SCH, - Intel Tunnel Creek processor, Intel Centerton processor or - Intel Quark X1000 SoC. - - The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are - powered by the core power rail and are turned off during sleep - modes (S3 and higher). The remaining four GPIOs are powered by - the Intel SCH suspend power supply. These GPIOs remain - active during S3. The suspend powered GPIOs can be used to wake the - system from the Suspend-to-RAM state. - - The Intel Tunnel Creek processor has 5 GPIOs powered by the - core power rail and 9 from suspend power supply. - - The Intel Centerton processor has a total of 30 GPIO pins. - Twenty-one are powered by the core power rail and 9 from the - suspend power supply. - - The Intel Quark X1000 SoC has 2 GPIOs powered by the core - power well and 6 from the suspend power well. - -config GPIO_SCH311X - tristate "SMSC SCH311x SuperI/O GPIO" - help - Driver to enable the GPIOs found on SMSC SMSC SCH3112, SCH3114 and - SCH3116 "Super I/O" chipsets. - - To compile this driver as a module, choose M here: the module will - be called gpio-sch311x. - config GPIO_SPEAR_SPICS bool "ST SPEAr13xx SPI Chip Select as GPIO support" depends on PLAT_SPEAR @@ -416,15 +387,6 @@ config GPIO_TB10X select GENERIC_IRQ_CHIP select OF_GPIO -config GPIO_TS5500 - tristate "TS-5500 DIO blocks and compatibles" - depends on TS5500 || COMPILE_TEST - help - This driver supports Digital I/O exposed by pin blocks found on some - Technologic Systems platforms. It includes, but is not limited to, 3 - blocks of the TS-5500: DIO1, DIO2 and the LCD port, and the TS-5600 - LCD port. - config GPIO_TZ1090 bool "Toumaz Xenif TZ1090 GPIO support" depends on SOC_TZ1090 @@ -484,10 +446,21 @@ config GPIO_XGENE_SB config GPIO_XILINX tristate "Xilinx GPIO support" - depends on OF_GPIO && (PPC || MICROBLAZE || ARCH_ZYNQ || X86) + depends on OF_GPIO help Say yes here to support the Xilinx FPGA GPIO device +config GPIO_XLP + tristate "Netlogic XLP GPIO support" + depends on CPU_XLP && OF_GPIO + select GPIOLIB_IRQCHIP + help + This driver provides support for GPIO interface on Netlogic XLP MIPS64 + SoCs. Currently supported XLP variants are XLP8XX, XLP3XX, XLP2XX, + XLP9XX and XLP5XX. + + If unsure, say N. + config GPIO_XTENSA bool "Xtensa GPIO32 support" depends on XTENSA @@ -505,11 +478,92 @@ config GPIO_ZEVIO config GPIO_ZYNQ tristate "Xilinx Zynq GPIO support" - depends on ARCH_ZYNQ + depends on ARCH_ZYNQ || ARCH_ZYNQMP select GPIOLIB_IRQCHIP help Say yes here to support Xilinx Zynq GPIO controller. +config GPIO_ZX + bool "ZTE ZX GPIO support" + select GPIOLIB_IRQCHIP + help + Say yes here to support the GPIO device on ZTE ZX SoCs. + +endmenu + +menu "Port-mapped I/O GPIO drivers" + depends on X86 # Unconditional I/O space access + +config GPIO_104_IDIO_16 + tristate "ACCES 104-IDIO-16 GPIO support" + help + Enables GPIO support for the ACCES 104-IDIO-16 family. + +config GPIO_F7188X + tristate "F71869, F71869A, F71882FG and F71889F GPIO support" + help + This option enables support for GPIOs found on Fintek Super-I/O + chips F71869, F71869A, F71882FG and F71889F. + + To compile this driver as a module, choose M here: the module will + be called f7188x-gpio. + +config GPIO_IT87 + tristate "IT87xx GPIO support" + help + Say yes here to support GPIO functionality of IT87xx Super I/O chips. + + This driver is tested with ITE IT8728 and IT8732 Super I/O chips, and + supports the IT8761E Super I/O chip as well. + + To compile this driver as a module, choose M here: the module will + be called gpio_it87 + +config GPIO_SCH + tristate "Intel SCH/TunnelCreek/Centerton/Quark X1000 GPIO" + depends on PCI + select MFD_CORE + select LPC_SCH + help + Say yes here to support GPIO interface on Intel Poulsbo SCH, + Intel Tunnel Creek processor, Intel Centerton processor or + Intel Quark X1000 SoC. + + The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are + powered by the core power rail and are turned off during sleep + modes (S3 and higher). The remaining four GPIOs are powered by + the Intel SCH suspend power supply. These GPIOs remain + active during S3. The suspend powered GPIOs can be used to wake the + system from the Suspend-to-RAM state. + + The Intel Tunnel Creek processor has 5 GPIOs powered by the + core power rail and 9 from suspend power supply. + + The Intel Centerton processor has a total of 30 GPIO pins. + Twenty-one are powered by the core power rail and 9 from the + suspend power supply. + + The Intel Quark X1000 SoC has 2 GPIOs powered by the core + power well and 6 from the suspend power well. + +config GPIO_SCH311X + tristate "SMSC SCH311x SuperI/O GPIO" + help + Driver to enable the GPIOs found on SMSC SMSC SCH3112, SCH3114 and + SCH3116 "Super I/O" chipsets. + + To compile this driver as a module, choose M here: the module will + be called gpio-sch311x. + +config GPIO_TS5500 + tristate "TS-5500 DIO blocks and compatibles" + depends on TS5500 || COMPILE_TEST + help + This driver supports Digital I/O exposed by pin blocks found on some + Technologic Systems platforms. It includes, but is not limited to, 3 + blocks of the TS-5500: DIO1, DIO2 and the LCD port, and the TS-5600 + LCD port. + endmenu menu "I2C GPIO expanders" @@ -517,7 +571,6 @@ menu "I2C GPIO expanders" config GPIO_ADP5588 tristate "ADP5588 I2C GPIO expander" - depends on I2C help This option enables support for 18 GPIOs found on Analog Devices ADP5588 GPIO Expanders. @@ -531,7 +584,7 @@ config GPIO_ADP5588_IRQ config GPIO_ADNP tristate "Avionic Design N-bit GPIO expander" - depends on I2C && OF_GPIO + depends on OF_GPIO select GPIOLIB_IRQCHIP help This option enables support for N GPIOs found on Avionic Design @@ -543,14 +596,12 @@ config GPIO_ADNP config GPIO_MAX7300 tristate "Maxim MAX7300 GPIO expander" - depends on I2C select GPIO_MAX730X help GPIO driver for Maxim MAX7300 I2C-based GPIO expander. config GPIO_MAX732X tristate "MAX7319, MAX7320-7327 I2C Port Expanders" - depends on I2C help Say yes here to support the MAX7319, MAX7320-7327 series of I2C Port Expanders. Each IO port on these chips has a fixed role of @@ -583,7 +634,6 @@ config GPIO_MC9S08DZ60 config GPIO_PCA953X tristate "PCA95[357]x, PCA9698, TCA64xx, and MAX7310 I/O ports" - depends on I2C help Say yes here to provide access to several register-oriented SMBus I/O expanders, made mostly by NXP or TI. Compatible @@ -611,7 +661,6 @@ config GPIO_PCA953X_IRQ config GPIO_PCF857X tristate "PCF857x, PCA{85,96}7x, and MAX732[89] I2C GPIO expanders" - depends on I2C select GPIOLIB_IRQCHIP select IRQ_DOMAIN help @@ -941,7 +990,7 @@ menu "SPI GPIO expanders" config GPIO_74X164 tristate "74x164 serial-in/parallel-out 8-bits shift register" - depends on SPI_MASTER && OF + depends on OF help Driver for 74x164 compatible serial-in/parallel-out 8-outputs shift registers. This driver can be used to provide access @@ -949,27 +998,29 @@ config GPIO_74X164 config GPIO_MAX7301 tristate "Maxim MAX7301 GPIO expander" - depends on SPI_MASTER select GPIO_MAX730X help GPIO driver for Maxim MAX7301 SPI-based GPIO expander. +config GPIO_MC33880 + tristate "Freescale MC33880 high-side/low-side switch" + help + SPI driver for Freescale MC33880 high-side/low-side switch. + This provides GPIO interface supporting inputs and outputs. + +endmenu + +menu "SPI or I2C GPIO expanders" + depends on (SPI_MASTER && !I2C) || I2C + config GPIO_MCP23S08 tristate "Microchip MCP23xxx I/O expander" - depends on (SPI_MASTER && !I2C) || I2C help SPI/I2C driver for Microchip MCP23S08/MCP23S17/MCP23008/MCP23017 I/O expanders. This provides a GPIO interface supporting inputs and outputs. The I2C versions of the chips can be used as interrupt-controller. -config GPIO_MC33880 - tristate "Freescale MC33880 high-side/low-side switch" - depends on SPI_MASTER - help - SPI driver for Freescale MC33880 high-side/low-side switch. - This provides GPIO interface supporting inputs and outputs. - endmenu menu "USB GPIO expanders" diff --git a/kernel/drivers/gpio/Makefile b/kernel/drivers/gpio/Makefile index f71bb9713..986dbd838 100644 --- a/kernel/drivers/gpio/Makefile +++ b/kernel/drivers/gpio/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o # Device drivers. Generally keep list sorted alphabetically obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o +obj-$(CONFIG_GPIO_104_IDIO_16) += gpio-104-idio-16.o obj-$(CONFIG_GPIO_74X164) += gpio-74x164.o obj-$(CONFIG_GPIO_74XX_MMIO) += gpio-74xx-mmio.o obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o @@ -19,8 +20,11 @@ obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o +obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o +obj-$(CONFIG_ATH79) += gpio-ath79.o obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o +obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o @@ -32,18 +36,20 @@ obj-$(CONFIG_GPIO_DLN2) += gpio-dln2.o obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o obj-$(CONFIG_GPIO_EM) += gpio-em.o obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o +obj-$(CONFIG_GPIO_ETRAXFS) += gpio-etraxfs.o 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_IT87) += gpio-it87.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_INTEL_MID) += gpio-intel-mid.o obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o +obj-$(CONFIG_GPIO_LPC18XX) += gpio-lpc18xx.o obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o @@ -60,7 +66,6 @@ obj-$(CONFIG_GPIO_MOXART) += gpio-moxart.o obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o -obj-$(CONFIG_GPIO_MSM_V2) += gpio-msm-v2.o obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o @@ -109,6 +114,8 @@ obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o obj-$(CONFIG_GPIO_XGENE_SB) += gpio-xgene-sb.o obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o +obj-$(CONFIG_GPIO_XLP) += gpio-xlp.o obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o +obj-$(CONFIG_GPIO_ZX) += gpio-zx.o diff --git a/kernel/drivers/gpio/devres.c b/kernel/drivers/gpio/devres.c index 07ba82317..903fcf4d0 100644 --- a/kernel/drivers/gpio/devres.c +++ b/kernel/drivers/gpio/devres.c @@ -59,13 +59,13 @@ static int devm_gpiod_match_array(struct device *dev, void *res, void *data) * 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, +struct gpio_desc *__must_check devm_gpiod_get(struct device *dev, const char *con_id, enum gpiod_flags flags) { return devm_gpiod_get_index(dev, con_id, 0, flags); } -EXPORT_SYMBOL(__devm_gpiod_get); +EXPORT_SYMBOL(devm_gpiod_get); /** * devm_gpiod_get_optional - Resource-managed gpiod_get_optional() @@ -77,13 +77,13 @@ EXPORT_SYMBOL(__devm_gpiod_get); * are automatically disposed on driver detach. See gpiod_get_optional() for * detailed information about behavior and return values. */ -struct gpio_desc *__must_check __devm_gpiod_get_optional(struct device *dev, +struct gpio_desc *__must_check devm_gpiod_get_optional(struct device *dev, const char *con_id, enum gpiod_flags flags) { return devm_gpiod_get_index_optional(dev, con_id, 0, flags); } -EXPORT_SYMBOL(__devm_gpiod_get_optional); +EXPORT_SYMBOL(devm_gpiod_get_optional); /** * devm_gpiod_get_index - Resource-managed gpiod_get_index() @@ -96,7 +96,7 @@ EXPORT_SYMBOL(__devm_gpiod_get_optional); * 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, +struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, const char *con_id, unsigned int idx, enum gpiod_flags flags) @@ -120,7 +120,7 @@ struct gpio_desc *__must_check __devm_gpiod_get_index(struct device *dev, return desc; } -EXPORT_SYMBOL(__devm_gpiod_get_index); +EXPORT_SYMBOL(devm_gpiod_get_index); /** * devm_get_gpiod_from_child - get a GPIO descriptor from a device's child node @@ -182,10 +182,10 @@ EXPORT_SYMBOL(devm_get_gpiod_from_child); * gpiod_get_index_optional() for detailed information about behavior and * return values. */ -struct gpio_desc *__must_check __devm_gpiod_get_index_optional(struct device *dev, +struct gpio_desc *__must_check devm_gpiod_get_index_optional(struct device *dev, const char *con_id, unsigned int index, - enum gpiod_flags flags) + enum gpiod_flags flags) { struct gpio_desc *desc; @@ -197,7 +197,7 @@ struct gpio_desc *__must_check __devm_gpiod_get_index_optional(struct device *de return desc; } -EXPORT_SYMBOL(__devm_gpiod_get_index_optional); +EXPORT_SYMBOL(devm_gpiod_get_index_optional); /** * devm_gpiod_get_array - Resource-managed gpiod_get_array() diff --git a/kernel/drivers/gpio/gpio-104-idio-16.c b/kernel/drivers/gpio/gpio-104-idio-16.c new file mode 100644 index 000000000..5400d7d4d --- /dev/null +++ b/kernel/drivers/gpio/gpio-104-idio-16.c @@ -0,0 +1,216 @@ +/* + * GPIO driver for the ACCES 104-IDIO-16 family + * Copyright (C) 2015 William Breathitt Gray + * + * 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. + */ +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/gpio/driver.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> + +static unsigned idio_16_base; +module_param(idio_16_base, uint, 0); +MODULE_PARM_DESC(idio_16_base, "ACCES 104-IDIO-16 base address"); + +/** + * struct idio_16_gpio - GPIO device private data structure + * @chip: instance of the gpio_chip + * @lock: synchronization lock to prevent gpio_set race conditions + * @base: base port address of the GPIO device + * @extent: extent of port address region of the GPIO device + * @out_state: output bits state + */ +struct idio_16_gpio { + struct gpio_chip chip; + spinlock_t lock; + unsigned base; + unsigned extent; + unsigned out_state; +}; + +static int idio_16_gpio_get_direction(struct gpio_chip *chip, unsigned offset) +{ + if (offset > 15) + return 1; + + return 0; +} + +static int idio_16_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + return 0; +} + +static int idio_16_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + chip->set(chip, offset, value); + return 0; +} + +static struct idio_16_gpio *to_idio16gpio(struct gpio_chip *gc) +{ + return container_of(gc, struct idio_16_gpio, chip); +} + +static int idio_16_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct idio_16_gpio *const idio16gpio = to_idio16gpio(chip); + const unsigned BIT_MASK = 1U << (offset-16); + + if (offset < 16) + return -EINVAL; + + if (offset < 24) + return !!(inb(idio16gpio->base + 1) & BIT_MASK); + + return !!(inb(idio16gpio->base + 5) & (BIT_MASK>>8)); +} + +static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct idio_16_gpio *const idio16gpio = to_idio16gpio(chip); + const unsigned BIT_MASK = 1U << offset; + unsigned long flags; + + if (offset > 15) + return; + + spin_lock_irqsave(&idio16gpio->lock, flags); + + if (value) + idio16gpio->out_state |= BIT_MASK; + else + idio16gpio->out_state &= ~BIT_MASK; + + if (offset > 7) + outb(idio16gpio->out_state >> 8, idio16gpio->base + 4); + else + outb(idio16gpio->out_state, idio16gpio->base); + + spin_unlock_irqrestore(&idio16gpio->lock, flags); +} + +static int __init idio_16_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct idio_16_gpio *idio16gpio; + int err; + + const unsigned BASE = idio_16_base; + const unsigned EXTENT = 8; + const char *const NAME = dev_name(dev); + + idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL); + if (!idio16gpio) + return -ENOMEM; + + if (!request_region(BASE, EXTENT, NAME)) { + dev_err(dev, "Unable to lock %s port addresses (0x%X-0x%X)\n", + NAME, BASE, BASE + EXTENT); + err = -EBUSY; + goto err_lock_io_port; + } + + idio16gpio->chip.label = NAME; + idio16gpio->chip.dev = dev; + idio16gpio->chip.owner = THIS_MODULE; + idio16gpio->chip.base = -1; + idio16gpio->chip.ngpio = 32; + idio16gpio->chip.get_direction = idio_16_gpio_get_direction; + idio16gpio->chip.direction_input = idio_16_gpio_direction_input; + idio16gpio->chip.direction_output = idio_16_gpio_direction_output; + idio16gpio->chip.get = idio_16_gpio_get; + idio16gpio->chip.set = idio_16_gpio_set; + idio16gpio->base = BASE; + idio16gpio->extent = EXTENT; + idio16gpio->out_state = 0xFFFF; + + spin_lock_init(&idio16gpio->lock); + + dev_set_drvdata(dev, idio16gpio); + + err = gpiochip_add(&idio16gpio->chip); + if (err) { + dev_err(dev, "GPIO registering failed (%d)\n", err); + goto err_gpio_register; + } + + return 0; + +err_gpio_register: + release_region(BASE, EXTENT); +err_lock_io_port: + return err; +} + +static int idio_16_remove(struct platform_device *pdev) +{ + struct idio_16_gpio *const idio16gpio = platform_get_drvdata(pdev); + + gpiochip_remove(&idio16gpio->chip); + release_region(idio16gpio->base, idio16gpio->extent); + + return 0; +} + +static struct platform_device *idio_16_device; + +static struct platform_driver idio_16_driver = { + .driver = { + .name = "104-idio-16" + }, + .remove = idio_16_remove +}; + +static void __exit idio_16_exit(void) +{ + platform_device_unregister(idio_16_device); + platform_driver_unregister(&idio_16_driver); +} + +static int __init idio_16_init(void) +{ + int err; + + idio_16_device = platform_device_alloc(idio_16_driver.driver.name, -1); + if (!idio_16_device) + return -ENOMEM; + + err = platform_device_add(idio_16_device); + if (err) + goto err_platform_device; + + err = platform_driver_probe(&idio_16_driver, idio_16_probe); + if (err) + goto err_platform_driver; + + return 0; + +err_platform_driver: + platform_device_del(idio_16_device); +err_platform_device: + platform_device_put(idio_16_device); + return err; +} + +module_init(idio_16_init); +module_exit(idio_16_exit); + +MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); +MODULE_DESCRIPTION("ACCES 104-IDIO-16 GPIO driver"); +MODULE_LICENSE("GPL"); diff --git a/kernel/drivers/gpio/gpio-74x164.c b/kernel/drivers/gpio/gpio-74x164.c index e3d968f75..60172f835 100644 --- a/kernel/drivers/gpio/gpio-74x164.c +++ b/kernel/drivers/gpio/gpio-74x164.c @@ -183,7 +183,6 @@ MODULE_DEVICE_TABLE(of, gen_74x164_dt_ids); static struct spi_driver gen_74x164_driver = { .driver = { .name = "74x164", - .owner = THIS_MODULE, .of_match_table = gen_74x164_dt_ids, }, .probe = gen_74x164_probe, diff --git a/kernel/drivers/gpio/gpio-74xx-mmio.c b/kernel/drivers/gpio/gpio-74xx-mmio.c index 0763655cc..6b1868290 100644 --- a/kernel/drivers/gpio/gpio-74xx-mmio.c +++ b/kernel/drivers/gpio/gpio-74xx-mmio.c @@ -113,13 +113,16 @@ static int mmio_74xx_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) static int mmio_74xx_gpio_probe(struct platform_device *pdev) { - const struct of_device_id *of_id = - of_match_device(mmio_74xx_gpio_ids, &pdev->dev); + const struct of_device_id *of_id; struct mmio_74xx_gpio_priv *priv; struct resource *res; void __iomem *dat; int err; + of_id = of_match_device(mmio_74xx_gpio_ids, &pdev->dev); + if (!of_id) + return -ENODEV; + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -129,7 +132,7 @@ static int mmio_74xx_gpio_probe(struct platform_device *pdev) if (IS_ERR(dat)) return PTR_ERR(dat); - priv->flags = (unsigned)of_id->data; + priv->flags = (uintptr_t) of_id->data; err = bgpio_init(&priv->bgc, &pdev->dev, DIV_ROUND_UP(MMIO_74XX_BIT_CNT(priv->flags), 8), diff --git a/kernel/drivers/gpio/gpio-adp5588.c b/kernel/drivers/gpio/gpio-adp5588.c index d3fe6a677..984186ee5 100644 --- a/kernel/drivers/gpio/gpio-adp5588.c +++ b/kernel/drivers/gpio/gpio-adp5588.c @@ -305,15 +305,7 @@ static int adp5588_irq_setup(struct adp5588_gpio *dev) irq_set_chip_and_handler(irq, &adp5588_irq_chip, handle_level_irq); irq_set_nested_thread(irq, 1); -#ifdef CONFIG_ARM - /* - * ARM needs us to explicitly flag the IRQ as VALID, - * once we do so, it will also set the noprobe. - */ - set_irq_flags(irq, IRQF_VALID); -#else - irq_set_noprobe(irq); -#endif + irq_modify_status(irq, IRQ_NOREQUEST, IRQ_NOPROBE); } ret = request_threaded_irq(client->irq, diff --git a/kernel/drivers/gpio/gpio-altera.c b/kernel/drivers/gpio/gpio-altera.c index 449fb46cb..3e6661bab 100644 --- a/kernel/drivers/gpio/gpio-altera.c +++ b/kernel/drivers/gpio/gpio-altera.c @@ -42,6 +42,11 @@ struct altera_gpio_chip { int mapped_irq; }; +static struct altera_gpio_chip *to_altera(struct gpio_chip *gc) +{ + return container_of(gc, struct altera_gpio_chip, mmchip.gc); +} + static void altera_gpio_irq_unmask(struct irq_data *d) { struct altera_gpio_chip *altera_gc; @@ -49,7 +54,7 @@ static void altera_gpio_irq_unmask(struct irq_data *d) unsigned long flags; u32 intmask; - altera_gc = irq_data_get_irq_chip_data(d); + altera_gc = to_altera(irq_data_get_irq_chip_data(d)); mm_gc = &altera_gc->mmchip; spin_lock_irqsave(&altera_gc->gpio_lock, flags); @@ -67,7 +72,7 @@ static void altera_gpio_irq_mask(struct irq_data *d) unsigned long flags; u32 intmask; - altera_gc = irq_data_get_irq_chip_data(d); + altera_gc = to_altera(irq_data_get_irq_chip_data(d)); mm_gc = &altera_gc->mmchip; spin_lock_irqsave(&altera_gc->gpio_lock, flags); @@ -87,7 +92,7 @@ static int altera_gpio_irq_set_type(struct irq_data *d, { struct altera_gpio_chip *altera_gc; - altera_gc = irq_data_get_irq_chip_data(d); + altera_gc = to_altera(irq_data_get_irq_chip_data(d)); if (type == IRQ_TYPE_NONE) return 0; @@ -107,7 +112,8 @@ static int altera_gpio_irq_set_type(struct irq_data *d, return -EINVAL; } -static unsigned int altera_gpio_irq_startup(struct irq_data *d) { +static unsigned int altera_gpio_irq_startup(struct irq_data *d) +{ altera_gpio_irq_unmask(d); return 0; @@ -200,8 +206,7 @@ static int altera_gpio_direction_output(struct gpio_chip *gc, return 0; } -static void altera_gpio_irq_edge_handler(unsigned int irq, - struct irq_desc *desc) +static void altera_gpio_irq_edge_handler(struct irq_desc *desc) { struct altera_gpio_chip *altera_gc; struct irq_chip *chip; @@ -210,7 +215,7 @@ static void altera_gpio_irq_edge_handler(unsigned int irq, unsigned long status; int i; - altera_gc = irq_desc_get_handler_data(desc); + altera_gc = to_altera(irq_desc_get_handler_data(desc)); chip = irq_desc_get_chip(desc); mm_gc = &altera_gc->mmchip; irqdomain = altera_gc->mmchip.gc.irqdomain; @@ -230,8 +235,7 @@ static void altera_gpio_irq_edge_handler(unsigned int irq, } -static void altera_gpio_irq_leveL_high_handler(unsigned int irq, - struct irq_desc *desc) +static void altera_gpio_irq_leveL_high_handler(struct irq_desc *desc) { struct altera_gpio_chip *altera_gc; struct irq_chip *chip; @@ -240,7 +244,7 @@ static void altera_gpio_irq_leveL_high_handler(unsigned int irq, unsigned long status; int i; - altera_gc = irq_desc_get_handler_data(desc); + altera_gc = to_altera(irq_desc_get_handler_data(desc)); chip = irq_desc_get_chip(desc); mm_gc = &altera_gc->mmchip; irqdomain = altera_gc->mmchip.gc.irqdomain; @@ -337,9 +341,9 @@ static int altera_gpio_remove(struct platform_device *pdev) { struct altera_gpio_chip *altera_gc = platform_get_drvdata(pdev); - gpiochip_remove(&altera_gc->mmchip.gc); + of_mm_gpiochip_remove(&altera_gc->mmchip); - return -EIO; + return 0; } static const struct of_device_id altera_gpio_of_match[] = { diff --git a/kernel/drivers/gpio/gpio-amdpt.c b/kernel/drivers/gpio/gpio-amdpt.c new file mode 100644 index 000000000..cbbb966d4 --- /dev/null +++ b/kernel/drivers/gpio/gpio-amdpt.c @@ -0,0 +1,261 @@ +/* + * AMD Promontory GPIO driver + * + * Copyright (C) 2015 ASMedia Technology Inc. + * Author: YD Tseng <yd_tseng@asmedia.com.tw> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/gpio/driver.h> +#include <linux/spinlock.h> +#include <linux/acpi.h> +#include <linux/platform_device.h> + +#define PT_TOTAL_GPIO 8 + +/* PCI-E MMIO register offsets */ +#define PT_DIRECTION_REG 0x00 +#define PT_INPUTDATA_REG 0x04 +#define PT_OUTPUTDATA_REG 0x08 +#define PT_CLOCKRATE_REG 0x0C +#define PT_SYNC_REG 0x28 + +struct pt_gpio_chip { + struct gpio_chip gc; + void __iomem *reg_base; + spinlock_t lock; +}; + +#define to_pt_gpio(c) container_of(c, struct pt_gpio_chip, gc) + +static int pt_gpio_request(struct gpio_chip *gc, unsigned offset) +{ + struct pt_gpio_chip *pt_gpio = to_pt_gpio(gc); + unsigned long flags; + u32 using_pins; + + dev_dbg(gc->dev, "pt_gpio_request offset=%x\n", offset); + + spin_lock_irqsave(&pt_gpio->lock, flags); + + using_pins = readl(pt_gpio->reg_base + PT_SYNC_REG); + if (using_pins & BIT(offset)) { + dev_warn(gc->dev, "PT GPIO pin %x reconfigured\n", + offset); + spin_unlock_irqrestore(&pt_gpio->lock, flags); + return -EINVAL; + } + + writel(using_pins | BIT(offset), pt_gpio->reg_base + PT_SYNC_REG); + + spin_unlock_irqrestore(&pt_gpio->lock, flags); + + return 0; +} + +static void pt_gpio_free(struct gpio_chip *gc, unsigned offset) +{ + struct pt_gpio_chip *pt_gpio = to_pt_gpio(gc); + unsigned long flags; + u32 using_pins; + + spin_lock_irqsave(&pt_gpio->lock, flags); + + using_pins = readl(pt_gpio->reg_base + PT_SYNC_REG); + using_pins &= ~BIT(offset); + writel(using_pins, pt_gpio->reg_base + PT_SYNC_REG); + + spin_unlock_irqrestore(&pt_gpio->lock, flags); + + dev_dbg(gc->dev, "pt_gpio_free offset=%x\n", offset); +} + +static void pt_gpio_set_value(struct gpio_chip *gc, unsigned offset, int value) +{ + struct pt_gpio_chip *pt_gpio = to_pt_gpio(gc); + unsigned long flags; + u32 data; + + dev_dbg(gc->dev, "pt_gpio_set_value offset=%x, value=%x\n", + offset, value); + + spin_lock_irqsave(&pt_gpio->lock, flags); + + data = readl(pt_gpio->reg_base + PT_OUTPUTDATA_REG); + data &= ~BIT(offset); + if (value) + data |= BIT(offset); + writel(data, pt_gpio->reg_base + PT_OUTPUTDATA_REG); + + spin_unlock_irqrestore(&pt_gpio->lock, flags); +} + +static int pt_gpio_get_value(struct gpio_chip *gc, unsigned offset) +{ + struct pt_gpio_chip *pt_gpio = to_pt_gpio(gc); + unsigned long flags; + u32 data; + + spin_lock_irqsave(&pt_gpio->lock, flags); + + data = readl(pt_gpio->reg_base + PT_DIRECTION_REG); + + /* configure as output */ + if (data & BIT(offset)) + data = readl(pt_gpio->reg_base + PT_OUTPUTDATA_REG); + else /* configure as input */ + data = readl(pt_gpio->reg_base + PT_INPUTDATA_REG); + + spin_unlock_irqrestore(&pt_gpio->lock, flags); + + data >>= offset; + data &= 1; + + dev_dbg(gc->dev, "pt_gpio_get_value offset=%x, value=%x\n", + offset, data); + + return data; +} + +static int pt_gpio_direction_input(struct gpio_chip *gc, unsigned offset) +{ + struct pt_gpio_chip *pt_gpio = to_pt_gpio(gc); + unsigned long flags; + u32 data; + + dev_dbg(gc->dev, "pt_gpio_dirction_input offset=%x\n", offset); + + spin_lock_irqsave(&pt_gpio->lock, flags); + + data = readl(pt_gpio->reg_base + PT_DIRECTION_REG); + data &= ~BIT(offset); + writel(data, pt_gpio->reg_base + PT_DIRECTION_REG); + + spin_unlock_irqrestore(&pt_gpio->lock, flags); + + return 0; +} + +static int pt_gpio_direction_output(struct gpio_chip *gc, + unsigned offset, int value) +{ + struct pt_gpio_chip *pt_gpio = to_pt_gpio(gc); + unsigned long flags; + u32 data; + + dev_dbg(gc->dev, "pt_gpio_direction_output offset=%x, value=%x\n", + offset, value); + + spin_lock_irqsave(&pt_gpio->lock, flags); + + data = readl(pt_gpio->reg_base + PT_OUTPUTDATA_REG); + if (value) + data |= BIT(offset); + else + data &= ~BIT(offset); + writel(data, pt_gpio->reg_base + PT_OUTPUTDATA_REG); + + data = readl(pt_gpio->reg_base + PT_DIRECTION_REG); + data |= BIT(offset); + writel(data, pt_gpio->reg_base + PT_DIRECTION_REG); + + spin_unlock_irqrestore(&pt_gpio->lock, flags); + + return 0; +} + +static int pt_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct acpi_device *acpi_dev; + acpi_handle handle = ACPI_HANDLE(dev); + struct pt_gpio_chip *pt_gpio; + struct resource *res_mem; + int ret = 0; + + if (acpi_bus_get_device(handle, &acpi_dev)) { + dev_err(dev, "PT GPIO device node not found\n"); + return -ENODEV; + } + + pt_gpio = devm_kzalloc(dev, sizeof(struct pt_gpio_chip), GFP_KERNEL); + if (!pt_gpio) + return -ENOMEM; + + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res_mem) { + dev_err(&pdev->dev, "Failed to get MMIO resource for PT GPIO.\n"); + return -EINVAL; + } + pt_gpio->reg_base = devm_ioremap_resource(dev, res_mem); + if (IS_ERR(pt_gpio->reg_base)) { + dev_err(&pdev->dev, "Failed to map MMIO resource for PT GPIO.\n"); + return PTR_ERR(pt_gpio->reg_base); + } + + spin_lock_init(&pt_gpio->lock); + + pt_gpio->gc.label = pdev->name; + pt_gpio->gc.owner = THIS_MODULE; + pt_gpio->gc.dev = dev; + pt_gpio->gc.request = pt_gpio_request; + pt_gpio->gc.free = pt_gpio_free; + pt_gpio->gc.direction_input = pt_gpio_direction_input; + pt_gpio->gc.direction_output = pt_gpio_direction_output; + pt_gpio->gc.get = pt_gpio_get_value; + pt_gpio->gc.set = pt_gpio_set_value; + pt_gpio->gc.base = -1; + pt_gpio->gc.ngpio = PT_TOTAL_GPIO; +#if defined(CONFIG_OF_GPIO) + pt_gpio->gc.of_node = pdev->dev.of_node; +#endif + ret = gpiochip_add(&pt_gpio->gc); + if (ret) { + dev_err(&pdev->dev, "Failed to register GPIO lib\n"); + return ret; + } + + platform_set_drvdata(pdev, pt_gpio); + + /* initialize register setting */ + writel(0, pt_gpio->reg_base + PT_SYNC_REG); + writel(0, pt_gpio->reg_base + PT_CLOCKRATE_REG); + + dev_dbg(&pdev->dev, "PT GPIO driver loaded\n"); + return ret; +} + +static int pt_gpio_remove(struct platform_device *pdev) +{ + struct pt_gpio_chip *pt_gpio = platform_get_drvdata(pdev); + + gpiochip_remove(&pt_gpio->gc); + + return 0; +} + +static const struct acpi_device_id pt_gpio_acpi_match[] = { + { "AMDF030", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, pt_gpio_acpi_match); + +static struct platform_driver pt_gpio_driver = { + .driver = { + .name = "pt-gpio", + .acpi_match_table = ACPI_PTR(pt_gpio_acpi_match), + }, + .probe = pt_gpio_probe, + .remove = pt_gpio_remove, +}; + +module_platform_driver(pt_gpio_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("YD Tseng <yd_tseng@asmedia.com.tw>"); +MODULE_DESCRIPTION("AMD Promontory GPIO Driver"); diff --git a/kernel/drivers/gpio/gpio-arizona.c b/kernel/drivers/gpio/gpio-arizona.c index 052fbc8fd..ca0027396 100644 --- a/kernel/drivers/gpio/gpio-arizona.c +++ b/kernel/drivers/gpio/gpio-arizona.c @@ -118,6 +118,8 @@ static int arizona_gpio_probe(struct platform_device *pdev) case WM5110: case WM8280: case WM8997: + case WM8998: + case WM1814: arizona_gpio->gpio_chip.ngpio = 5; break; default: diff --git a/kernel/drivers/gpio/gpio-ath79.c b/kernel/drivers/gpio/gpio-ath79.c new file mode 100644 index 000000000..5eaea8b81 --- /dev/null +++ b/kernel/drivers/gpio/gpio-ath79.c @@ -0,0 +1,205 @@ +/* + * Atheros AR71XX/AR724X/AR913X GPIO API support + * + * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> + * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> + * + * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include <linux/gpio/driver.h> +#include <linux/platform_data/gpio-ath79.h> +#include <linux/of_device.h> + +#include <asm/mach-ath79/ar71xx_regs.h> + +struct ath79_gpio_ctrl { + struct gpio_chip chip; + void __iomem *base; + spinlock_t lock; +}; + +#define to_ath79_gpio_ctrl(c) container_of(c, struct ath79_gpio_ctrl, chip) + +static void ath79_gpio_set_value(struct gpio_chip *chip, + unsigned gpio, int value) +{ + struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip); + + if (value) + __raw_writel(BIT(gpio), ctrl->base + AR71XX_GPIO_REG_SET); + else + __raw_writel(BIT(gpio), ctrl->base + AR71XX_GPIO_REG_CLEAR); +} + +static int ath79_gpio_get_value(struct gpio_chip *chip, unsigned gpio) +{ + struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip); + + return (__raw_readl(ctrl->base + AR71XX_GPIO_REG_IN) >> gpio) & 1; +} + +static int ath79_gpio_direction_input(struct gpio_chip *chip, + unsigned offset) +{ + struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip); + unsigned long flags; + + spin_lock_irqsave(&ctrl->lock, flags); + + __raw_writel( + __raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) & ~BIT(offset), + ctrl->base + AR71XX_GPIO_REG_OE); + + spin_unlock_irqrestore(&ctrl->lock, flags); + + return 0; +} + +static int ath79_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip); + unsigned long flags; + + spin_lock_irqsave(&ctrl->lock, flags); + + if (value) + __raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_SET); + else + __raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_CLEAR); + + __raw_writel( + __raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) | BIT(offset), + ctrl->base + AR71XX_GPIO_REG_OE); + + spin_unlock_irqrestore(&ctrl->lock, flags); + + return 0; +} + +static int ar934x_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip); + unsigned long flags; + + spin_lock_irqsave(&ctrl->lock, flags); + + __raw_writel( + __raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) | BIT(offset), + ctrl->base + AR71XX_GPIO_REG_OE); + + spin_unlock_irqrestore(&ctrl->lock, flags); + + return 0; +} + +static int ar934x_gpio_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip); + unsigned long flags; + + spin_lock_irqsave(&ctrl->lock, flags); + + if (value) + __raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_SET); + else + __raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_CLEAR); + + __raw_writel( + __raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) & ~BIT(offset), + ctrl->base + AR71XX_GPIO_REG_OE); + + spin_unlock_irqrestore(&ctrl->lock, flags); + + return 0; +} + +static const struct gpio_chip ath79_gpio_chip = { + .label = "ath79", + .get = ath79_gpio_get_value, + .set = ath79_gpio_set_value, + .direction_input = ath79_gpio_direction_input, + .direction_output = ath79_gpio_direction_output, + .base = 0, +}; + +static const struct of_device_id ath79_gpio_of_match[] = { + { .compatible = "qca,ar7100-gpio" }, + { .compatible = "qca,ar9340-gpio" }, + {}, +}; + +static int ath79_gpio_probe(struct platform_device *pdev) +{ + struct ath79_gpio_platform_data *pdata = pdev->dev.platform_data; + struct device_node *np = pdev->dev.of_node; + struct ath79_gpio_ctrl *ctrl; + struct resource *res; + u32 ath79_gpio_count; + bool oe_inverted; + int err; + + ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL); + if (!ctrl) + return -ENOMEM; + + if (np) { + err = of_property_read_u32(np, "ngpios", &ath79_gpio_count); + if (err) { + dev_err(&pdev->dev, "ngpios property is not valid\n"); + return err; + } + if (ath79_gpio_count >= 32) { + dev_err(&pdev->dev, "ngpios must be less than 32\n"); + return -EINVAL; + } + oe_inverted = of_device_is_compatible(np, "qca,ar9340-gpio"); + } else if (pdata) { + ath79_gpio_count = pdata->ngpios; + oe_inverted = pdata->oe_inverted; + } else { + dev_err(&pdev->dev, "No DT node or platform data found\n"); + return -EINVAL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ctrl->base = devm_ioremap_nocache( + &pdev->dev, res->start, resource_size(res)); + if (!ctrl->base) + return -ENOMEM; + + spin_lock_init(&ctrl->lock); + memcpy(&ctrl->chip, &ath79_gpio_chip, sizeof(ctrl->chip)); + ctrl->chip.dev = &pdev->dev; + ctrl->chip.ngpio = ath79_gpio_count; + if (oe_inverted) { + ctrl->chip.direction_input = ar934x_gpio_direction_input; + ctrl->chip.direction_output = ar934x_gpio_direction_output; + } + + err = gpiochip_add(&ctrl->chip); + if (err) { + dev_err(&pdev->dev, + "cannot add AR71xx GPIO chip, error=%d", err); + return err; + } + + return 0; +} + +static struct platform_driver ath79_gpio_driver = { + .driver = { + .name = "ath79-gpio", + .of_match_table = ath79_gpio_of_match, + }, + .probe = ath79_gpio_probe, +}; + +module_platform_driver(ath79_gpio_driver); diff --git a/kernel/drivers/gpio/gpio-bcm-kona.c b/kernel/drivers/gpio/gpio-bcm-kona.c index b164ce837..33a1f9779 100644 --- a/kernel/drivers/gpio/gpio-bcm-kona.c +++ b/kernel/drivers/gpio/gpio-bcm-kona.c @@ -122,6 +122,16 @@ static void bcm_kona_gpio_unlock_gpio(struct bcm_kona_gpio *kona_gpio, spin_unlock_irqrestore(&kona_gpio->lock, flags); } +static int bcm_kona_gpio_get_dir(struct gpio_chip *chip, unsigned gpio) +{ + struct bcm_kona_gpio *kona_gpio = to_kona_gpio(chip); + void __iomem *reg_base = kona_gpio->reg_base; + u32 val; + + val = readl(reg_base + GPIO_CONTROL(gpio)) & GPIO_GPCTR0_IOTR_MASK; + return val ? GPIOF_DIR_IN : GPIOF_DIR_OUT; +} + static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) { struct bcm_kona_gpio *kona_gpio; @@ -135,12 +145,8 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - /* 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) + if (bcm_kona_gpio_get_dir(chip, gpio) == GPIOF_DIR_IN) goto out; reg_offset = value ? GPIO_OUT_SET(bank_id) : GPIO_OUT_CLEAR(bank_id); @@ -166,13 +172,12 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio) reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - /* determine the GPIO pin direction */ - val = readl(reg_base + GPIO_CONTROL(gpio)); - val &= GPIO_GPCTR0_IOTR_MASK; + if (bcm_kona_gpio_get_dir(chip, gpio) == GPIOF_DIR_IN) + reg_offset = GPIO_IN_STATUS(bank_id); + else + reg_offset = GPIO_OUT_STATUS(bank_id); /* 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); spin_unlock_irqrestore(&kona_gpio->lock, flags); @@ -310,6 +315,7 @@ static struct gpio_chip template_chip = { .owner = THIS_MODULE, .request = bcm_kona_gpio_request, .free = bcm_kona_gpio_free, + .get_direction = bcm_kona_gpio_get_dir, .direction_input = bcm_kona_gpio_direction_input, .get = bcm_kona_gpio_get, .direction_output = bcm_kona_gpio_direction_output, @@ -427,12 +433,12 @@ static int bcm_kona_gpio_irq_set_type(struct irq_data *d, unsigned int type) return 0; } -static void bcm_kona_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +static void bcm_kona_gpio_irq_handler(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 bcm_kona_gpio_bank *bank = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); chained_irq_enter(chip, desc); @@ -519,11 +525,7 @@ static int bcm_kona_gpio_irq_map(struct irq_domain *d, unsigned int irq, 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; } @@ -534,7 +536,7 @@ static void bcm_kona_gpio_irq_unmap(struct irq_domain *d, unsigned int irq) irq_set_chip_data(irq, NULL); } -static struct irq_domain_ops bcm_kona_irq_ops = { +static const 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, @@ -638,21 +640,11 @@ static int bcm_kona_gpio_probe(struct platform_device *pdev) 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); + irq_set_chained_handler_and_data(bank->irq, + bcm_kona_gpio_irq_handler, + bank); } spin_lock_init(&kona_gpio->lock); diff --git a/kernel/drivers/gpio/gpio-brcmstb.c b/kernel/drivers/gpio/gpio-brcmstb.c new file mode 100644 index 000000000..4c64627c6 --- /dev/null +++ b/kernel/drivers/gpio/gpio-brcmstb.c @@ -0,0 +1,554 @@ +/* + * Copyright (C) 2015 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/gpio/driver.h> +#include <linux/of_device.h> +#include <linux/of_irq.h> +#include <linux/module.h> +#include <linux/basic_mmio_gpio.h> +#include <linux/irqdomain.h> +#include <linux/irqchip/chained_irq.h> +#include <linux/interrupt.h> +#include <linux/reboot.h> + +#define GIO_BANK_SIZE 0x20 +#define GIO_ODEN(bank) (((bank) * GIO_BANK_SIZE) + 0x00) +#define GIO_DATA(bank) (((bank) * GIO_BANK_SIZE) + 0x04) +#define GIO_IODIR(bank) (((bank) * GIO_BANK_SIZE) + 0x08) +#define GIO_EC(bank) (((bank) * GIO_BANK_SIZE) + 0x0c) +#define GIO_EI(bank) (((bank) * GIO_BANK_SIZE) + 0x10) +#define GIO_MASK(bank) (((bank) * GIO_BANK_SIZE) + 0x14) +#define GIO_LEVEL(bank) (((bank) * GIO_BANK_SIZE) + 0x18) +#define GIO_STAT(bank) (((bank) * GIO_BANK_SIZE) + 0x1c) + +struct brcmstb_gpio_bank { + struct list_head node; + int id; + struct bgpio_chip bgc; + struct brcmstb_gpio_priv *parent_priv; + u32 width; + struct irq_chip irq_chip; +}; + +struct brcmstb_gpio_priv { + struct list_head bank_list; + void __iomem *reg_base; + struct platform_device *pdev; + int parent_irq; + int gpio_base; + bool can_wake; + int parent_wake_irq; + struct notifier_block reboot_notifier; +}; + +#define MAX_GPIO_PER_BANK 32 +#define GPIO_BANK(gpio) ((gpio) >> 5) +/* assumes MAX_GPIO_PER_BANK is a multiple of 2 */ +#define GPIO_BIT(gpio) ((gpio) & (MAX_GPIO_PER_BANK - 1)) + +static inline struct brcmstb_gpio_bank * +brcmstb_gpio_gc_to_bank(struct gpio_chip *gc) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + return container_of(bgc, struct brcmstb_gpio_bank, bgc); +} + +static inline struct brcmstb_gpio_priv * +brcmstb_gpio_gc_to_priv(struct gpio_chip *gc) +{ + struct brcmstb_gpio_bank *bank = brcmstb_gpio_gc_to_bank(gc); + return bank->parent_priv; +} + +static void brcmstb_gpio_set_imask(struct brcmstb_gpio_bank *bank, + unsigned int offset, bool enable) +{ + struct bgpio_chip *bgc = &bank->bgc; + struct brcmstb_gpio_priv *priv = bank->parent_priv; + u32 mask = bgc->pin2mask(bgc, offset); + u32 imask; + unsigned long flags; + + spin_lock_irqsave(&bgc->lock, flags); + imask = bgc->read_reg(priv->reg_base + GIO_MASK(bank->id)); + if (enable) + imask |= mask; + else + imask &= ~mask; + bgc->write_reg(priv->reg_base + GIO_MASK(bank->id), imask); + spin_unlock_irqrestore(&bgc->lock, flags); +} + +/* -------------------- IRQ chip functions -------------------- */ + +static void brcmstb_gpio_irq_mask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct brcmstb_gpio_bank *bank = brcmstb_gpio_gc_to_bank(gc); + + brcmstb_gpio_set_imask(bank, d->hwirq, false); +} + +static void brcmstb_gpio_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct brcmstb_gpio_bank *bank = brcmstb_gpio_gc_to_bank(gc); + + brcmstb_gpio_set_imask(bank, d->hwirq, true); +} + +static int brcmstb_gpio_irq_set_type(struct irq_data *d, unsigned int type) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct brcmstb_gpio_bank *bank = brcmstb_gpio_gc_to_bank(gc); + struct brcmstb_gpio_priv *priv = bank->parent_priv; + u32 mask = BIT(d->hwirq); + u32 edge_insensitive, iedge_insensitive; + u32 edge_config, iedge_config; + u32 level, ilevel; + unsigned long flags; + + switch (type) { + case IRQ_TYPE_LEVEL_LOW: + level = 0; + edge_config = 0; + edge_insensitive = 0; + break; + case IRQ_TYPE_LEVEL_HIGH: + level = mask; + edge_config = 0; + edge_insensitive = 0; + break; + case IRQ_TYPE_EDGE_FALLING: + level = 0; + edge_config = 0; + edge_insensitive = 0; + break; + case IRQ_TYPE_EDGE_RISING: + level = 0; + edge_config = mask; + edge_insensitive = 0; + break; + case IRQ_TYPE_EDGE_BOTH: + level = 0; + edge_config = 0; /* don't care, but want known value */ + edge_insensitive = mask; + break; + default: + return -EINVAL; + } + + spin_lock_irqsave(&bank->bgc.lock, flags); + + iedge_config = bank->bgc.read_reg(priv->reg_base + + GIO_EC(bank->id)) & ~mask; + iedge_insensitive = bank->bgc.read_reg(priv->reg_base + + GIO_EI(bank->id)) & ~mask; + ilevel = bank->bgc.read_reg(priv->reg_base + + GIO_LEVEL(bank->id)) & ~mask; + + bank->bgc.write_reg(priv->reg_base + GIO_EC(bank->id), + iedge_config | edge_config); + bank->bgc.write_reg(priv->reg_base + GIO_EI(bank->id), + iedge_insensitive | edge_insensitive); + bank->bgc.write_reg(priv->reg_base + GIO_LEVEL(bank->id), + ilevel | level); + + spin_unlock_irqrestore(&bank->bgc.lock, flags); + return 0; +} + +static int brcmstb_gpio_priv_set_wake(struct brcmstb_gpio_priv *priv, + unsigned int enable) +{ + int ret = 0; + + /* + * Only enable wake IRQ once for however many hwirqs can wake + * since they all use the same wake IRQ. Mask will be set + * up appropriately thanks to IRQCHIP_MASK_ON_SUSPEND flag. + */ + if (enable) + ret = enable_irq_wake(priv->parent_wake_irq); + else + ret = disable_irq_wake(priv->parent_wake_irq); + if (ret) + dev_err(&priv->pdev->dev, "failed to %s wake-up interrupt\n", + enable ? "enable" : "disable"); + return ret; +} + +static int brcmstb_gpio_irq_set_wake(struct irq_data *d, unsigned int enable) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct brcmstb_gpio_priv *priv = brcmstb_gpio_gc_to_priv(gc); + + return brcmstb_gpio_priv_set_wake(priv, enable); +} + +static irqreturn_t brcmstb_gpio_wake_irq_handler(int irq, void *data) +{ + struct brcmstb_gpio_priv *priv = data; + + if (!priv || irq != priv->parent_wake_irq) + return IRQ_NONE; + pm_wakeup_event(&priv->pdev->dev, 0); + return IRQ_HANDLED; +} + +static void brcmstb_gpio_irq_bank_handler(struct brcmstb_gpio_bank *bank) +{ + struct brcmstb_gpio_priv *priv = bank->parent_priv; + struct irq_domain *irq_domain = bank->bgc.gc.irqdomain; + void __iomem *reg_base = priv->reg_base; + unsigned long status; + unsigned long flags; + + spin_lock_irqsave(&bank->bgc.lock, flags); + while ((status = bank->bgc.read_reg(reg_base + GIO_STAT(bank->id)) & + bank->bgc.read_reg(reg_base + GIO_MASK(bank->id)))) { + int bit; + + for_each_set_bit(bit, &status, 32) { + u32 stat = bank->bgc.read_reg(reg_base + + GIO_STAT(bank->id)); + if (bit >= bank->width) + dev_warn(&priv->pdev->dev, + "IRQ for invalid GPIO (bank=%d, offset=%d)\n", + bank->id, bit); + bank->bgc.write_reg(reg_base + GIO_STAT(bank->id), + stat | BIT(bit)); + generic_handle_irq(irq_find_mapping(irq_domain, bit)); + } + } + spin_unlock_irqrestore(&bank->bgc.lock, flags); +} + +/* Each UPG GIO block has one IRQ for all banks */ +static void brcmstb_gpio_irq_handler(struct irq_desc *desc) +{ + struct gpio_chip *gc = irq_desc_get_handler_data(desc); + struct brcmstb_gpio_priv *priv = brcmstb_gpio_gc_to_priv(gc); + struct irq_chip *chip = irq_desc_get_chip(desc); + struct list_head *pos; + + /* Interrupts weren't properly cleared during probe */ + BUG_ON(!priv || !chip); + + chained_irq_enter(chip, desc); + list_for_each(pos, &priv->bank_list) { + struct brcmstb_gpio_bank *bank = + list_entry(pos, struct brcmstb_gpio_bank, node); + brcmstb_gpio_irq_bank_handler(bank); + } + chained_irq_exit(chip, desc); +} + +static int brcmstb_gpio_reboot(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct brcmstb_gpio_priv *priv = + container_of(nb, struct brcmstb_gpio_priv, reboot_notifier); + + /* Enable GPIO for S5 cold boot */ + if (action == SYS_POWER_OFF) + brcmstb_gpio_priv_set_wake(priv, 1); + + return NOTIFY_DONE; +} + +/* Make sure that the number of banks matches up between properties */ +static int brcmstb_gpio_sanity_check_banks(struct device *dev, + struct device_node *np, struct resource *res) +{ + int res_num_banks = resource_size(res) / GIO_BANK_SIZE; + int num_banks = + of_property_count_u32_elems(np, "brcm,gpio-bank-widths"); + + if (res_num_banks != num_banks) { + dev_err(dev, "Mismatch in banks: res had %d, bank-widths had %d\n", + res_num_banks, num_banks); + return -EINVAL; + } else { + return 0; + } +} + +static int brcmstb_gpio_remove(struct platform_device *pdev) +{ + struct brcmstb_gpio_priv *priv = platform_get_drvdata(pdev); + struct list_head *pos; + struct brcmstb_gpio_bank *bank; + int ret = 0; + + if (!priv) { + dev_err(&pdev->dev, "called %s without drvdata!\n", __func__); + return -EFAULT; + } + + /* + * You can lose return values below, but we report all errors, and it's + * more important to actually perform all of the steps. + */ + list_for_each(pos, &priv->bank_list) { + bank = list_entry(pos, struct brcmstb_gpio_bank, node); + ret = bgpio_remove(&bank->bgc); + if (ret) + dev_err(&pdev->dev, "gpiochip_remove fail in cleanup\n"); + } + if (priv->reboot_notifier.notifier_call) { + ret = unregister_reboot_notifier(&priv->reboot_notifier); + if (ret) + dev_err(&pdev->dev, + "failed to unregister reboot notifier\n"); + } + return ret; +} + +static int brcmstb_gpio_of_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, u32 *flags) +{ + struct brcmstb_gpio_priv *priv = brcmstb_gpio_gc_to_priv(gc); + struct brcmstb_gpio_bank *bank = brcmstb_gpio_gc_to_bank(gc); + int offset; + + if (gc->of_gpio_n_cells != 2) { + WARN_ON(1); + return -EINVAL; + } + + if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells)) + return -EINVAL; + + offset = gpiospec->args[0] - (gc->base - priv->gpio_base); + if (offset >= gc->ngpio || offset < 0) + return -EINVAL; + + if (unlikely(offset >= bank->width)) { + dev_warn_ratelimited(&priv->pdev->dev, + "Received request for invalid GPIO offset %d\n", + gpiospec->args[0]); + } + + if (flags) + *flags = gpiospec->args[1]; + + return offset; +} + +/* Before calling, must have bank->parent_irq set and gpiochip registered */ +static int brcmstb_gpio_irq_setup(struct platform_device *pdev, + struct brcmstb_gpio_bank *bank) +{ + struct brcmstb_gpio_priv *priv = bank->parent_priv; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + + bank->irq_chip.name = dev_name(dev); + bank->irq_chip.irq_mask = brcmstb_gpio_irq_mask; + bank->irq_chip.irq_unmask = brcmstb_gpio_irq_unmask; + bank->irq_chip.irq_set_type = brcmstb_gpio_irq_set_type; + + /* Ensures that all non-wakeup IRQs are disabled at suspend */ + bank->irq_chip.flags = IRQCHIP_MASK_ON_SUSPEND; + + if (IS_ENABLED(CONFIG_PM_SLEEP) && !priv->can_wake && + of_property_read_bool(np, "wakeup-source")) { + priv->parent_wake_irq = platform_get_irq(pdev, 1); + if (priv->parent_wake_irq < 0) { + dev_warn(dev, + "Couldn't get wake IRQ - GPIOs will not be able to wake from sleep"); + } else { + int err; + + /* + * Set wakeup capability before requesting wakeup + * interrupt, so we can process boot-time "wakeups" + * (e.g., from S5 cold boot) + */ + device_set_wakeup_capable(dev, true); + device_wakeup_enable(dev); + err = devm_request_irq(dev, priv->parent_wake_irq, + brcmstb_gpio_wake_irq_handler, 0, + "brcmstb-gpio-wake", priv); + + if (err < 0) { + dev_err(dev, "Couldn't request wake IRQ"); + return err; + } + + priv->reboot_notifier.notifier_call = + brcmstb_gpio_reboot; + register_reboot_notifier(&priv->reboot_notifier); + priv->can_wake = true; + } + } + + if (priv->can_wake) + bank->irq_chip.irq_set_wake = brcmstb_gpio_irq_set_wake; + + gpiochip_irqchip_add(&bank->bgc.gc, &bank->irq_chip, 0, + handle_simple_irq, IRQ_TYPE_NONE); + gpiochip_set_chained_irqchip(&bank->bgc.gc, &bank->irq_chip, + priv->parent_irq, brcmstb_gpio_irq_handler); + + return 0; +} + +static int brcmstb_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + void __iomem *reg_base; + struct brcmstb_gpio_priv *priv; + struct resource *res; + struct property *prop; + const __be32 *p; + u32 bank_width; + int num_banks = 0; + int err; + static int gpio_base; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + platform_set_drvdata(pdev, priv); + INIT_LIST_HEAD(&priv->bank_list); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + reg_base = devm_ioremap_resource(dev, res); + if (IS_ERR(reg_base)) + return PTR_ERR(reg_base); + + priv->gpio_base = gpio_base; + priv->reg_base = reg_base; + priv->pdev = pdev; + + if (of_property_read_bool(np, "interrupt-controller")) { + priv->parent_irq = platform_get_irq(pdev, 0); + if (priv->parent_irq <= 0) { + dev_err(dev, "Couldn't get IRQ"); + return -ENOENT; + } + } else { + priv->parent_irq = -ENOENT; + } + + if (brcmstb_gpio_sanity_check_banks(dev, np, res)) + return -EINVAL; + + of_property_for_each_u32(np, "brcm,gpio-bank-widths", prop, p, + bank_width) { + struct brcmstb_gpio_bank *bank; + struct bgpio_chip *bgc; + struct gpio_chip *gc; + + bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL); + if (!bank) { + err = -ENOMEM; + goto fail; + } + + bank->parent_priv = priv; + bank->id = num_banks; + if (bank_width <= 0 || bank_width > MAX_GPIO_PER_BANK) { + dev_err(dev, "Invalid bank width %d\n", bank_width); + goto fail; + } else { + bank->width = bank_width; + } + + /* + * Regs are 4 bytes wide, have data reg, no set/clear regs, + * and direction bits have 0 = output and 1 = input + */ + bgc = &bank->bgc; + err = bgpio_init(bgc, dev, 4, + reg_base + GIO_DATA(bank->id), + NULL, NULL, NULL, + reg_base + GIO_IODIR(bank->id), 0); + if (err) { + dev_err(dev, "bgpio_init() failed\n"); + goto fail; + } + + gc = &bgc->gc; + gc->of_node = np; + gc->owner = THIS_MODULE; + gc->label = np->full_name; + gc->base = gpio_base; + gc->of_gpio_n_cells = 2; + gc->of_xlate = brcmstb_gpio_of_xlate; + /* not all ngpio lines are valid, will use bank width later */ + gc->ngpio = MAX_GPIO_PER_BANK; + + /* + * Mask all interrupts by default, since wakeup interrupts may + * be retained from S5 cold boot + */ + bank->bgc.write_reg(reg_base + GIO_MASK(bank->id), 0); + + err = gpiochip_add(gc); + if (err) { + dev_err(dev, "Could not add gpiochip for bank %d\n", + bank->id); + goto fail; + } + gpio_base += gc->ngpio; + + if (priv->parent_irq > 0) { + err = brcmstb_gpio_irq_setup(pdev, bank); + if (err) + goto fail; + } + + dev_dbg(dev, "bank=%d, base=%d, ngpio=%d, width=%d\n", bank->id, + gc->base, gc->ngpio, bank->width); + + /* Everything looks good, so add bank to list */ + list_add(&bank->node, &priv->bank_list); + + num_banks++; + } + + dev_info(dev, "Registered %d banks (GPIO(s): %d-%d)\n", + num_banks, priv->gpio_base, gpio_base - 1); + + return 0; + +fail: + (void) brcmstb_gpio_remove(pdev); + return err; +} + +static const struct of_device_id brcmstb_gpio_of_match[] = { + { .compatible = "brcm,brcmstb-gpio" }, + {}, +}; + +MODULE_DEVICE_TABLE(of, brcmstb_gpio_of_match); + +static struct platform_driver brcmstb_gpio_driver = { + .driver = { + .name = "brcmstb-gpio", + .of_match_table = brcmstb_gpio_of_match, + }, + .probe = brcmstb_gpio_probe, + .remove = brcmstb_gpio_remove, +}; +module_platform_driver(brcmstb_gpio_driver); + +MODULE_AUTHOR("Gregory Fong"); +MODULE_DESCRIPTION("Driver for Broadcom BRCMSTB SoC UPG GPIO"); +MODULE_LICENSE("GPL v2"); diff --git a/kernel/drivers/gpio/gpio-crystalcove.c b/kernel/drivers/gpio/gpio-crystalcove.c index ab457fc00..fddd204dc 100644 --- a/kernel/drivers/gpio/gpio-crystalcove.c +++ b/kernel/drivers/gpio/gpio-crystalcove.c @@ -16,6 +16,7 @@ */ #include <linux/interrupt.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/gpio.h> #include <linux/seq_file.h> @@ -94,9 +95,8 @@ static inline int to_reg(int gpio, enum ctrl_register reg_type) { int reg; - if (gpio == 94) { + if (gpio == 94) return GPIOPANELCTL; - } if (reg_type == CTRL_IN) { if (gpio < 8) diff --git a/kernel/drivers/gpio/gpio-davinci.c b/kernel/drivers/gpio/gpio-davinci.c index c5e05c82d..5e7153888 100644 --- a/kernel/drivers/gpio/gpio-davinci.c +++ b/kernel/drivers/gpio/gpio-davinci.c @@ -65,11 +65,11 @@ static struct davinci_gpio_regs __iomem *gpio2regs(unsigned gpio) return ptr; } -static inline struct davinci_gpio_regs __iomem *irq2regs(int irq) +static inline struct davinci_gpio_regs __iomem *irq2regs(struct irq_data *d) { struct davinci_gpio_regs __iomem *g; - g = (__force struct davinci_gpio_regs __iomem *)irq_get_chip_data(irq); + g = (__force struct davinci_gpio_regs __iomem *)irq_data_get_irq_chip_data(d); return g; } @@ -287,7 +287,7 @@ static int davinci_gpio_probe(struct platform_device *pdev) static void gpio_irq_disable(struct irq_data *d) { - struct davinci_gpio_regs __iomem *g = irq2regs(d->irq); + struct davinci_gpio_regs __iomem *g = irq2regs(d); u32 mask = (u32) irq_data_get_irq_handler_data(d); writel_relaxed(mask, &g->clr_falling); @@ -296,7 +296,7 @@ static void gpio_irq_disable(struct irq_data *d) static void gpio_irq_enable(struct irq_data *d) { - struct davinci_gpio_regs __iomem *g = irq2regs(d->irq); + struct davinci_gpio_regs __iomem *g = irq2regs(d); u32 mask = (u32) irq_data_get_irq_handler_data(d); unsigned status = irqd_get_trigger_type(d); @@ -326,9 +326,9 @@ static struct irq_chip gpio_irqchip = { .flags = IRQCHIP_SET_TYPE_MASKED, }; -static void -gpio_irq_handler(unsigned irq, struct irq_desc *desc) +static void gpio_irq_handler(struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); struct davinci_gpio_regs __iomem *g; u32 mask = 0xffff; struct davinci_gpio_controller *d; @@ -396,7 +396,7 @@ static int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger) struct davinci_gpio_regs __iomem *g; u32 mask; - d = (struct davinci_gpio_controller *)data->handler_data; + d = (struct davinci_gpio_controller *)irq_data_get_irq_handler_data(data); g = (struct davinci_gpio_regs __iomem *)d->regs; mask = __gpio_mask(data->irq - d->gpio_irq); @@ -422,7 +422,6 @@ davinci_gpio_irq_map(struct irq_domain *d, unsigned int irq, irq_set_irq_type(irq, IRQ_TYPE_NONE); irq_set_chip_data(irq, (__force void *)g); irq_set_handler_data(irq, (void *)__gpio_mask(hw)); - set_irq_flags(irq, IRQF_VALID); return 0; } @@ -545,7 +544,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) chips[0].chip.to_irq = gpio_to_irq_unbanked; chips[0].gpio_irq = bank_irq; chips[0].gpio_unbanked = pdata->gpio_unbanked; - binten = BIT(0); + binten = GENMASK(pdata->gpio_unbanked / 16, 0); /* AINTC handles mask/unmask; GPIO handles triggering */ irq = bank_irq; @@ -578,15 +577,13 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) writel_relaxed(~0, &g->clr_falling); writel_relaxed(~0, &g->clr_rising); - /* set up all irqs in this bank */ - irq_set_chained_handler(bank_irq, gpio_irq_handler); - /* * Each chip handles 32 gpios, and each irq bank consists of 16 * gpio irqs. Pass the irq bank's corresponding controller to * the chained irq handler. */ - irq_set_handler_data(bank_irq, &chips[gpio / 32]); + irq_set_chained_handler_and_data(bank_irq, gpio_irq_handler, + &chips[gpio / 32]); binten |= BIT(bank); } diff --git a/kernel/drivers/gpio/gpio-dln2.c b/kernel/drivers/gpio/gpio-dln2.c index dbdb4de82..6685712c1 100644 --- a/kernel/drivers/gpio/gpio-dln2.c +++ b/kernel/drivers/gpio/gpio-dln2.c @@ -466,7 +466,6 @@ static int dln2_gpio_probe(struct platform_device *pdev) dln2->gpio.owner = THIS_MODULE; dln2->gpio.base = -1; dln2->gpio.ngpio = pins; - dln2->gpio.exported = true; dln2->gpio.can_sleep = true; dln2->gpio.irq_not_threaded = true; dln2->gpio.set = dln2_gpio_set; diff --git a/kernel/drivers/gpio/gpio-dwapb.c b/kernel/drivers/gpio/gpio-dwapb.c index 58faf04fc..fcd5b0acf 100644 --- a/kernel/drivers/gpio/gpio-dwapb.c +++ b/kernel/drivers/gpio/gpio-dwapb.c @@ -147,9 +147,9 @@ static u32 dwapb_do_irq(struct dwapb_gpio *gpio) return ret; } -static void dwapb_irq_handler(u32 irq, struct irq_desc *desc) +static void dwapb_irq_handler(struct irq_desc *desc) { - struct dwapb_gpio *gpio = irq_get_handler_data(irq); + struct dwapb_gpio *gpio = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); dwapb_do_irq(gpio); @@ -348,8 +348,8 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio, irq_gc->chip_types[1].handler = handle_edge_irq; if (!pp->irq_shared) { - irq_set_chained_handler(pp->irq, dwapb_irq_handler); - irq_set_handler_data(pp->irq, gpio); + irq_set_chained_handler_and_data(pp->irq, dwapb_irq_handler, + gpio); } else { /* * Request a shared IRQ since where MFD would have devices diff --git a/kernel/drivers/gpio/gpio-em.c b/kernel/drivers/gpio/gpio-em.c index 3cfcfc620..6bca1e125 100644 --- a/kernel/drivers/gpio/gpio-em.c +++ b/kernel/drivers/gpio/gpio-em.c @@ -31,7 +31,6 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/pinctrl/consumer.h> -#include <linux/platform_data/gpio-em.h> struct em_gio_priv { void __iomem *base0; @@ -262,24 +261,22 @@ static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int irq, 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; } -static struct irq_domain_ops em_gio_irq_domain_ops = { +static const struct irq_domain_ops em_gio_irq_domain_ops = { .map = em_gio_irq_domain_map, .xlate = irq_domain_xlate_twocell, }; static int em_gio_probe(struct platform_device *pdev) { - struct gpio_em_config pdata_dt; - struct gpio_em_config *pdata = dev_get_platdata(&pdev->dev); struct em_gio_priv *p; struct resource *io[2], *irq[2]; struct gpio_chip *gpio_chip; struct irq_chip *irq_chip; const char *name = dev_name(&pdev->dev); + unsigned int ngpios; int ret; p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); @@ -319,18 +316,10 @@ static int em_gio_probe(struct platform_device *pdev) goto err0; } - if (!pdata) { - memset(&pdata_dt, 0, sizeof(pdata_dt)); - pdata = &pdata_dt; - - if (of_property_read_u32(pdev->dev.of_node, "ngpios", - &pdata->number_of_pins)) { - dev_err(&pdev->dev, "Missing ngpios OF property\n"); - ret = -EINVAL; - goto err0; - } - - pdata->gpio_base = -1; + if (of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios)) { + dev_err(&pdev->dev, "Missing ngpios OF property\n"); + ret = -EINVAL; + goto err0; } gpio_chip = &p->gpio_chip; @@ -345,8 +334,8 @@ static int em_gio_probe(struct platform_device *pdev) gpio_chip->label = name; gpio_chip->dev = &pdev->dev; gpio_chip->owner = THIS_MODULE; - gpio_chip->base = pdata->gpio_base; - gpio_chip->ngpio = pdata->number_of_pins; + gpio_chip->base = -1; + gpio_chip->ngpio = ngpios; irq_chip = &p->irq_chip; irq_chip->name = name; @@ -357,9 +346,7 @@ static int em_gio_probe(struct platform_device *pdev) irq_chip->irq_release_resources = em_gio_irq_relres; irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND; - p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, - pdata->number_of_pins, - pdata->irq_base, + p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, ngpios, 0, &em_gio_irq_domain_ops, p); if (!p->irq_domain) { ret = -ENXIO; @@ -387,12 +374,6 @@ static int em_gio_probe(struct platform_device *pdev) goto err1; } - if (pdata->pctl_name) { - ret = gpiochip_add_pin_range(gpio_chip, pdata->pctl_name, 0, - gpio_chip->base, gpio_chip->ngpio); - if (ret < 0) - dev_warn(&pdev->dev, "failed to add pin range\n"); - } return 0; err1: diff --git a/kernel/drivers/gpio/gpio-ep93xx.c b/kernel/drivers/gpio/gpio-ep93xx.c index 45684f36d..3e3947b35 100644 --- a/kernel/drivers/gpio/gpio-ep93xx.c +++ b/kernel/drivers/gpio/gpio-ep93xx.c @@ -78,7 +78,7 @@ static void ep93xx_gpio_int_debounce(unsigned int irq, bool enable) EP93XX_GPIO_REG(int_debounce_register_offset[port])); } -static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc) +static void ep93xx_gpio_ab_irq_handler(struct irq_desc *desc) { unsigned char status; int i; @@ -100,13 +100,14 @@ static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc) } } -static void ep93xx_gpio_f_irq_handler(unsigned int irq, struct irq_desc *desc) +static void ep93xx_gpio_f_irq_handler(struct irq_desc *desc) { /* * map discontiguous hw irq range to continuous sw irq range: * * IRQ_EP93XX_GPIO{0..7}MUX -> gpio_to_irq(EP93XX_GPIO_LINE_F({0..7}) */ + unsigned int irq = irq_desc_get_irq(desc); int port_f_idx = ((irq + 1) & 7) ^ 4; /* {19..22,47..50} -> {0..7} */ int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_F(0)) + port_f_idx; @@ -208,7 +209,7 @@ static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type) return -EINVAL; } - __irq_set_handler_locked(d->irq, handler); + irq_set_handler_locked(d, handler); gpio_int_enabled[port] |= port_mask; @@ -234,7 +235,7 @@ static void ep93xx_gpio_init_irq(void) gpio_irq <= gpio_to_irq(EP93XX_GPIO_LINE_MAX_IRQ); ++gpio_irq) { irq_set_chip_and_handler(gpio_irq, &ep93xx_gpio_irq_chip, handle_level_irq); - set_irq_flags(gpio_irq, IRQF_VALID); + irq_clear_status_flags(gpio_irq, IRQ_NOREQUEST); } irq_set_chained_handler(IRQ_EP93XX_GPIO_AB, diff --git a/kernel/drivers/gpio/gpio-etraxfs.c b/kernel/drivers/gpio/gpio-etraxfs.c new file mode 100644 index 000000000..5c15dd121 --- /dev/null +++ b/kernel/drivers/gpio/gpio-etraxfs.c @@ -0,0 +1,486 @@ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/gpio/driver.h> +#include <linux/of_gpio.h> +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/basic_mmio_gpio.h> + +#define ETRAX_FS_rw_pa_dout 0 +#define ETRAX_FS_r_pa_din 4 +#define ETRAX_FS_rw_pa_oe 8 +#define ETRAX_FS_rw_intr_cfg 12 +#define ETRAX_FS_rw_intr_mask 16 +#define ETRAX_FS_rw_ack_intr 20 +#define ETRAX_FS_r_intr 24 +#define ETRAX_FS_r_masked_intr 28 +#define ETRAX_FS_rw_pb_dout 32 +#define ETRAX_FS_r_pb_din 36 +#define ETRAX_FS_rw_pb_oe 40 +#define ETRAX_FS_rw_pc_dout 48 +#define ETRAX_FS_r_pc_din 52 +#define ETRAX_FS_rw_pc_oe 56 +#define ETRAX_FS_rw_pd_dout 64 +#define ETRAX_FS_r_pd_din 68 +#define ETRAX_FS_rw_pd_oe 72 +#define ETRAX_FS_rw_pe_dout 80 +#define ETRAX_FS_r_pe_din 84 +#define ETRAX_FS_rw_pe_oe 88 + +#define ARTPEC3_r_pa_din 0 +#define ARTPEC3_rw_pa_dout 4 +#define ARTPEC3_rw_pa_oe 8 +#define ARTPEC3_r_pb_din 44 +#define ARTPEC3_rw_pb_dout 48 +#define ARTPEC3_rw_pb_oe 52 +#define ARTPEC3_r_pc_din 88 +#define ARTPEC3_rw_pc_dout 92 +#define ARTPEC3_rw_pc_oe 96 +#define ARTPEC3_r_pd_din 116 +#define ARTPEC3_rw_intr_cfg 120 +#define ARTPEC3_rw_intr_pins 124 +#define ARTPEC3_rw_intr_mask 128 +#define ARTPEC3_rw_ack_intr 132 +#define ARTPEC3_r_masked_intr 140 + +#define GIO_CFG_OFF 0 +#define GIO_CFG_HI 1 +#define GIO_CFG_LO 2 +#define GIO_CFG_SET 3 +#define GIO_CFG_POSEDGE 5 +#define GIO_CFG_NEGEDGE 6 +#define GIO_CFG_ANYEDGE 7 + +struct etraxfs_gpio_info; + +struct etraxfs_gpio_block { + spinlock_t lock; + u32 mask; + u32 cfg; + u32 pins; + unsigned int group[8]; + + void __iomem *regs; + const struct etraxfs_gpio_info *info; +}; + +struct etraxfs_gpio_chip { + struct bgpio_chip bgc; + struct etraxfs_gpio_block *block; +}; + +struct etraxfs_gpio_port { + const char *label; + unsigned int oe; + unsigned int dout; + unsigned int din; + unsigned int ngpio; +}; + +struct etraxfs_gpio_info { + unsigned int num_ports; + const struct etraxfs_gpio_port *ports; + + unsigned int rw_ack_intr; + unsigned int rw_intr_mask; + unsigned int rw_intr_cfg; + unsigned int rw_intr_pins; + unsigned int r_masked_intr; +}; + +static const struct etraxfs_gpio_port etraxfs_gpio_etraxfs_ports[] = { + { + .label = "A", + .ngpio = 8, + .oe = ETRAX_FS_rw_pa_oe, + .dout = ETRAX_FS_rw_pa_dout, + .din = ETRAX_FS_r_pa_din, + }, + { + .label = "B", + .ngpio = 18, + .oe = ETRAX_FS_rw_pb_oe, + .dout = ETRAX_FS_rw_pb_dout, + .din = ETRAX_FS_r_pb_din, + }, + { + .label = "C", + .ngpio = 18, + .oe = ETRAX_FS_rw_pc_oe, + .dout = ETRAX_FS_rw_pc_dout, + .din = ETRAX_FS_r_pc_din, + }, + { + .label = "D", + .ngpio = 18, + .oe = ETRAX_FS_rw_pd_oe, + .dout = ETRAX_FS_rw_pd_dout, + .din = ETRAX_FS_r_pd_din, + }, + { + .label = "E", + .ngpio = 18, + .oe = ETRAX_FS_rw_pe_oe, + .dout = ETRAX_FS_rw_pe_dout, + .din = ETRAX_FS_r_pe_din, + }, +}; + +static const struct etraxfs_gpio_info etraxfs_gpio_etraxfs = { + .num_ports = ARRAY_SIZE(etraxfs_gpio_etraxfs_ports), + .ports = etraxfs_gpio_etraxfs_ports, + .rw_ack_intr = ETRAX_FS_rw_ack_intr, + .rw_intr_mask = ETRAX_FS_rw_intr_mask, + .rw_intr_cfg = ETRAX_FS_rw_intr_cfg, + .r_masked_intr = ETRAX_FS_r_masked_intr, +}; + +static const struct etraxfs_gpio_port etraxfs_gpio_artpec3_ports[] = { + { + .label = "A", + .ngpio = 32, + .oe = ARTPEC3_rw_pa_oe, + .dout = ARTPEC3_rw_pa_dout, + .din = ARTPEC3_r_pa_din, + }, + { + .label = "B", + .ngpio = 32, + .oe = ARTPEC3_rw_pb_oe, + .dout = ARTPEC3_rw_pb_dout, + .din = ARTPEC3_r_pb_din, + }, + { + .label = "C", + .ngpio = 16, + .oe = ARTPEC3_rw_pc_oe, + .dout = ARTPEC3_rw_pc_dout, + .din = ARTPEC3_r_pc_din, + }, + { + .label = "D", + .ngpio = 32, + .din = ARTPEC3_r_pd_din, + }, +}; + +static const struct etraxfs_gpio_info etraxfs_gpio_artpec3 = { + .num_ports = ARRAY_SIZE(etraxfs_gpio_artpec3_ports), + .ports = etraxfs_gpio_artpec3_ports, + .rw_ack_intr = ARTPEC3_rw_ack_intr, + .rw_intr_mask = ARTPEC3_rw_intr_mask, + .rw_intr_cfg = ARTPEC3_rw_intr_cfg, + .r_masked_intr = ARTPEC3_r_masked_intr, + .rw_intr_pins = ARTPEC3_rw_intr_pins, +}; + +static struct etraxfs_gpio_chip *to_etraxfs(struct gpio_chip *gc) +{ + return container_of(gc, struct etraxfs_gpio_chip, bgc.gc); +} + +static unsigned int etraxfs_gpio_chip_to_port(struct gpio_chip *gc) +{ + return gc->label[0] - 'A'; +} + +static int etraxfs_gpio_of_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, + u32 *flags) +{ + /* + * Port numbers are A to E, and the properties are integers, so we + * specify them as 0xA - 0xE. + */ + if (etraxfs_gpio_chip_to_port(gc) + 0xA != gpiospec->args[2]) + return -EINVAL; + + return of_gpio_simple_xlate(gc, gpiospec, flags); +} + +static const struct of_device_id etraxfs_gpio_of_table[] = { + { + .compatible = "axis,etraxfs-gio", + .data = &etraxfs_gpio_etraxfs, + }, + { + .compatible = "axis,artpec3-gio", + .data = &etraxfs_gpio_artpec3, + }, + {}, +}; + +static unsigned int etraxfs_gpio_to_group_irq(unsigned int gpio) +{ + return gpio % 8; +} + +static unsigned int etraxfs_gpio_to_group_pin(struct etraxfs_gpio_chip *chip, + unsigned int gpio) +{ + return 4 * etraxfs_gpio_chip_to_port(&chip->bgc.gc) + gpio / 8; +} + +static void etraxfs_gpio_irq_ack(struct irq_data *d) +{ + struct etraxfs_gpio_chip *chip = + to_etraxfs(irq_data_get_irq_chip_data(d)); + struct etraxfs_gpio_block *block = chip->block; + unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); + + writel(BIT(grpirq), block->regs + block->info->rw_ack_intr); +} + +static void etraxfs_gpio_irq_mask(struct irq_data *d) +{ + struct etraxfs_gpio_chip *chip = + to_etraxfs(irq_data_get_irq_chip_data(d)); + struct etraxfs_gpio_block *block = chip->block; + unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); + + spin_lock(&block->lock); + block->mask &= ~BIT(grpirq); + writel(block->mask, block->regs + block->info->rw_intr_mask); + spin_unlock(&block->lock); +} + +static void etraxfs_gpio_irq_unmask(struct irq_data *d) +{ + struct etraxfs_gpio_chip *chip = + to_etraxfs(irq_data_get_irq_chip_data(d)); + struct etraxfs_gpio_block *block = chip->block; + unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); + + spin_lock(&block->lock); + block->mask |= BIT(grpirq); + writel(block->mask, block->regs + block->info->rw_intr_mask); + spin_unlock(&block->lock); +} + +static int etraxfs_gpio_irq_set_type(struct irq_data *d, u32 type) +{ + struct etraxfs_gpio_chip *chip = + to_etraxfs(irq_data_get_irq_chip_data(d)); + struct etraxfs_gpio_block *block = chip->block; + unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); + u32 cfg; + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + cfg = GIO_CFG_POSEDGE; + break; + case IRQ_TYPE_EDGE_FALLING: + cfg = GIO_CFG_NEGEDGE; + break; + case IRQ_TYPE_EDGE_BOTH: + cfg = GIO_CFG_ANYEDGE; + break; + case IRQ_TYPE_LEVEL_LOW: + cfg = GIO_CFG_LO; + break; + case IRQ_TYPE_LEVEL_HIGH: + cfg = GIO_CFG_HI; + break; + default: + return -EINVAL; + } + + spin_lock(&block->lock); + block->cfg &= ~(0x7 << (grpirq * 3)); + block->cfg |= (cfg << (grpirq * 3)); + writel(block->cfg, block->regs + block->info->rw_intr_cfg); + spin_unlock(&block->lock); + + return 0; +} + +static int etraxfs_gpio_irq_request_resources(struct irq_data *d) +{ + struct etraxfs_gpio_chip *chip = + to_etraxfs(irq_data_get_irq_chip_data(d)); + struct etraxfs_gpio_block *block = chip->block; + unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); + int ret = -EBUSY; + + spin_lock(&block->lock); + if (block->group[grpirq]) + goto out; + + ret = gpiochip_lock_as_irq(&chip->bgc.gc, d->hwirq); + if (ret) + goto out; + + block->group[grpirq] = d->irq; + if (block->info->rw_intr_pins) { + unsigned int pin = etraxfs_gpio_to_group_pin(chip, d->hwirq); + + block->pins &= ~(0xf << (grpirq * 4)); + block->pins |= (pin << (grpirq * 4)); + + writel(block->pins, block->regs + block->info->rw_intr_pins); + } + +out: + spin_unlock(&block->lock); + return ret; +} + +static void etraxfs_gpio_irq_release_resources(struct irq_data *d) +{ + struct etraxfs_gpio_chip *chip = + to_etraxfs(irq_data_get_irq_chip_data(d)); + struct etraxfs_gpio_block *block = chip->block; + unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); + + spin_lock(&block->lock); + block->group[grpirq] = 0; + gpiochip_unlock_as_irq(&chip->bgc.gc, d->hwirq); + spin_unlock(&block->lock); +} + +static struct irq_chip etraxfs_gpio_irq_chip = { + .name = "gpio-etraxfs", + .irq_ack = etraxfs_gpio_irq_ack, + .irq_mask = etraxfs_gpio_irq_mask, + .irq_unmask = etraxfs_gpio_irq_unmask, + .irq_set_type = etraxfs_gpio_irq_set_type, + .irq_request_resources = etraxfs_gpio_irq_request_resources, + .irq_release_resources = etraxfs_gpio_irq_release_resources, +}; + +static irqreturn_t etraxfs_gpio_interrupt(int irq, void *dev_id) +{ + struct etraxfs_gpio_block *block = dev_id; + unsigned long intr = readl(block->regs + block->info->r_masked_intr); + int bit; + + for_each_set_bit(bit, &intr, 8) + generic_handle_irq(block->group[bit]); + + return IRQ_RETVAL(intr & 0xff); +} + +static int etraxfs_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct etraxfs_gpio_info *info; + const struct of_device_id *match; + struct etraxfs_gpio_block *block; + struct etraxfs_gpio_chip *chips; + struct resource *res, *irq; + bool allportsirq = false; + void __iomem *regs; + int ret; + int i; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + match = of_match_node(etraxfs_gpio_of_table, dev->of_node); + if (!match) + return -EINVAL; + + info = match->data; + + chips = devm_kzalloc(dev, sizeof(*chips) * info->num_ports, GFP_KERNEL); + if (!chips) + return -ENOMEM; + + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!irq) + return -EINVAL; + + block = devm_kzalloc(dev, sizeof(*block), GFP_KERNEL); + if (!block) + return -ENOMEM; + + spin_lock_init(&block->lock); + + block->regs = regs; + block->info = info; + + writel(0, block->regs + info->rw_intr_mask); + writel(0, block->regs + info->rw_intr_cfg); + if (info->rw_intr_pins) { + allportsirq = true; + writel(0, block->regs + info->rw_intr_pins); + } + + ret = devm_request_irq(dev, irq->start, etraxfs_gpio_interrupt, + IRQF_SHARED, dev_name(dev), block); + if (ret) { + dev_err(dev, "Unable to request irq %d\n", ret); + return ret; + } + + for (i = 0; i < info->num_ports; i++) { + struct etraxfs_gpio_chip *chip = &chips[i]; + struct bgpio_chip *bgc = &chip->bgc; + const struct etraxfs_gpio_port *port = &info->ports[i]; + unsigned long flags = BGPIOF_READ_OUTPUT_REG_SET; + void __iomem *dat = regs + port->din; + void __iomem *set = regs + port->dout; + void __iomem *dirout = regs + port->oe; + + chip->block = block; + + if (dirout == set) { + dirout = set = NULL; + flags = BGPIOF_NO_OUTPUT; + } + + ret = bgpio_init(bgc, dev, 4, + dat, set, NULL, dirout, NULL, + flags); + if (ret) { + dev_err(dev, "Unable to init port %s\n", + port->label); + continue; + } + + bgc->gc.ngpio = port->ngpio; + bgc->gc.label = port->label; + + bgc->gc.of_node = dev->of_node; + bgc->gc.of_gpio_n_cells = 3; + bgc->gc.of_xlate = etraxfs_gpio_of_xlate; + + ret = gpiochip_add(&bgc->gc); + if (ret) { + dev_err(dev, "Unable to register port %s\n", + bgc->gc.label); + continue; + } + + if (i > 0 && !allportsirq) + continue; + + ret = gpiochip_irqchip_add(&bgc->gc, &etraxfs_gpio_irq_chip, 0, + handle_level_irq, IRQ_TYPE_NONE); + if (ret) { + dev_err(dev, "Unable to add irqchip to port %s\n", + bgc->gc.label); + } + } + + return 0; +} + +static struct platform_driver etraxfs_gpio_driver = { + .driver = { + .name = "etraxfs-gpio", + .of_match_table = of_match_ptr(etraxfs_gpio_of_table), + }, + .probe = etraxfs_gpio_probe, +}; + +static int __init etraxfs_gpio_init(void) +{ + return platform_driver_register(&etraxfs_gpio_driver); +} + +device_initcall(etraxfs_gpio_init); diff --git a/kernel/drivers/gpio/gpio-f7188x.c b/kernel/drivers/gpio/gpio-f7188x.c index dbda8433c..5e3c4fa67 100644 --- a/kernel/drivers/gpio/gpio-f7188x.c +++ b/kernel/drivers/gpio/gpio-f7188x.c @@ -172,7 +172,7 @@ static struct f7188x_gpio_bank f71869a_gpio_bank[] = { }; static struct f7188x_gpio_bank f71882_gpio_bank[] = { - F7188X_GPIO_BANK(0 , 8, 0xF0), + F7188X_GPIO_BANK(0, 8, 0xF0), F7188X_GPIO_BANK(10, 8, 0xE0), F7188X_GPIO_BANK(20, 8, 0xD0), F7188X_GPIO_BANK(30, 4, 0xC0), @@ -180,7 +180,7 @@ static struct f7188x_gpio_bank f71882_gpio_bank[] = { }; static struct f7188x_gpio_bank f71889_gpio_bank[] = { - F7188X_GPIO_BANK(0 , 7, 0xF0), + F7188X_GPIO_BANK(0, 7, 0xF0), F7188X_GPIO_BANK(10, 7, 0xE0), F7188X_GPIO_BANK(20, 8, 0xD0), F7188X_GPIO_BANK(30, 8, 0xC0), diff --git a/kernel/drivers/gpio/gpio-generic.c b/kernel/drivers/gpio/gpio-generic.c index b92a690f5..88ae70ddb 100644 --- a/kernel/drivers/gpio/gpio-generic.c +++ b/kernel/drivers/gpio/gpio-generic.c @@ -135,6 +135,17 @@ static unsigned long bgpio_pin2mask_be(struct bgpio_chip *bgc, return 1 << (bgc->bits - 1 - pin); } +static int bgpio_get_set(struct gpio_chip *gc, unsigned int gpio) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + unsigned long pinmask = bgc->pin2mask(bgc, gpio); + + if (bgc->dir & pinmask) + return !!(bgc->read_reg(bgc->reg_set) & pinmask); + else + return !!(bgc->read_reg(bgc->reg_dat) & pinmask); +} + static int bgpio_get(struct gpio_chip *gc, unsigned int gpio) { struct bgpio_chip *bgc = to_bgpio_chip(gc); @@ -142,6 +153,10 @@ static int bgpio_get(struct gpio_chip *gc, unsigned int gpio) return !!(bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio)); } +static void bgpio_set_none(struct gpio_chip *gc, unsigned int gpio, int val) +{ +} + static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) { struct bgpio_chip *bgc = to_bgpio_chip(gc); @@ -268,6 +283,12 @@ static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio) return 0; } +static int bgpio_dir_out_err(struct gpio_chip *gc, unsigned int gpio, + int val) +{ + return -EINVAL; +} + static int bgpio_simple_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) { @@ -291,6 +312,14 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) return 0; } +static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + + return (bgc->read_reg(bgc->reg_dir) & bgc->pin2mask(bgc, gpio)) ? + GPIOF_DIR_OUT : GPIOF_DIR_IN; +} + static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) { struct bgpio_chip *bgc = to_bgpio_chip(gc); @@ -340,6 +369,14 @@ static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val) return 0; } +static int bgpio_get_dir_inv(struct gpio_chip *gc, unsigned int gpio) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + + return (bgc->read_reg(bgc->reg_dir) & bgc->pin2mask(bgc, gpio)) ? + GPIOF_DIR_IN : GPIOF_DIR_OUT; +} + static int bgpio_setup_accessors(struct device *dev, struct bgpio_chip *bgc, bool bit_be, @@ -416,7 +453,8 @@ static int bgpio_setup_accessors(struct device *dev, static int bgpio_setup_io(struct bgpio_chip *bgc, void __iomem *dat, void __iomem *set, - void __iomem *clr) + void __iomem *clr, + unsigned long flags) { bgc->reg_dat = dat; @@ -432,19 +470,27 @@ static int bgpio_setup_io(struct bgpio_chip *bgc, bgc->reg_set = set; bgc->gc.set = bgpio_set_set; bgc->gc.set_multiple = bgpio_set_multiple_set; + } else if (flags & BGPIOF_NO_OUTPUT) { + bgc->gc.set = bgpio_set_none; + bgc->gc.set_multiple = NULL; } else { bgc->gc.set = bgpio_set; bgc->gc.set_multiple = bgpio_set_multiple; } - bgc->gc.get = bgpio_get; + if (!(flags & BGPIOF_UNREADABLE_REG_SET) && + (flags & BGPIOF_READ_OUTPUT_REG_SET)) + bgc->gc.get = bgpio_get_set; + else + bgc->gc.get = bgpio_get; return 0; } static int bgpio_setup_direction(struct bgpio_chip *bgc, void __iomem *dirout, - void __iomem *dirin) + void __iomem *dirin, + unsigned long flags) { if (dirout && dirin) { return -EINVAL; @@ -452,12 +498,17 @@ static int bgpio_setup_direction(struct bgpio_chip *bgc, bgc->reg_dir = dirout; bgc->gc.direction_output = bgpio_dir_out; bgc->gc.direction_input = bgpio_dir_in; + bgc->gc.get_direction = bgpio_get_dir; } else if (dirin) { bgc->reg_dir = dirin; bgc->gc.direction_output = bgpio_dir_out_inv; bgc->gc.direction_input = bgpio_dir_in_inv; + bgc->gc.get_direction = bgpio_get_dir_inv; } else { - bgc->gc.direction_output = bgpio_simple_dir_out; + if (flags & BGPIOF_NO_OUTPUT) + bgc->gc.direction_output = bgpio_dir_out_err; + else + bgc->gc.direction_output = bgpio_simple_dir_out; bgc->gc.direction_input = bgpio_simple_dir_in; } @@ -500,7 +551,7 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev, bgc->gc.ngpio = bgc->bits; bgc->gc.request = bgpio_request; - ret = bgpio_setup_io(bgc, dat, set, clr); + ret = bgpio_setup_io(bgc, dat, set, clr, flags); if (ret) return ret; @@ -509,7 +560,7 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev, if (ret) return ret; - ret = bgpio_setup_direction(bgc, dirout, dirin); + ret = bgpio_setup_direction(bgc, dirout, dirin, flags); if (ret) return ret; @@ -528,40 +579,20 @@ EXPORT_SYMBOL_GPL(bgpio_init); static void __iomem *bgpio_map(struct platform_device *pdev, const char *name, - resource_size_t sane_sz, - int *err) + resource_size_t sane_sz) { - struct device *dev = &pdev->dev; struct resource *r; - resource_size_t start; resource_size_t sz; - void __iomem *ret; - - *err = 0; r = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); if (!r) return NULL; sz = resource_size(r); - if (sz != sane_sz) { - *err = -EINVAL; - return NULL; - } - - start = r->start; - if (!devm_request_mem_region(dev, start, sz, r->name)) { - *err = -EBUSY; - return NULL; - } - - ret = devm_ioremap(dev, start, sz); - if (!ret) { - *err = -ENOMEM; - return NULL; - } + if (sz != sane_sz) + return IOMEM_ERR_PTR(-EINVAL); - return ret; + return devm_ioremap_resource(&pdev->dev, r); } static int bgpio_pdev_probe(struct platform_device *pdev) @@ -585,25 +616,25 @@ static int bgpio_pdev_probe(struct platform_device *pdev) sz = resource_size(r); - dat = bgpio_map(pdev, "dat", sz, &err); - if (!dat) - return err ? err : -EINVAL; + dat = bgpio_map(pdev, "dat", sz); + if (IS_ERR(dat)) + return PTR_ERR(dat); - set = bgpio_map(pdev, "set", sz, &err); - if (err) - return err; + set = bgpio_map(pdev, "set", sz); + if (IS_ERR(set)) + return PTR_ERR(set); - clr = bgpio_map(pdev, "clr", sz, &err); - if (err) - return err; + clr = bgpio_map(pdev, "clr", sz); + if (IS_ERR(clr)) + return PTR_ERR(clr); - dirout = bgpio_map(pdev, "dirout", sz, &err); - if (err) - return err; + dirout = bgpio_map(pdev, "dirout", sz); + if (IS_ERR(dirout)) + return PTR_ERR(dirout); - dirin = bgpio_map(pdev, "dirin", sz, &err); - if (err) - return err; + dirin = bgpio_map(pdev, "dirin", sz); + if (IS_ERR(dirin)) + return PTR_ERR(dirin); bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL); if (!bgc) diff --git a/kernel/drivers/gpio/gpio-grgpio.c b/kernel/drivers/gpio/gpio-grgpio.c index 35a02770c..801423fe8 100644 --- a/kernel/drivers/gpio/gpio-grgpio.c +++ b/kernel/drivers/gpio/gpio-grgpio.c @@ -104,17 +104,12 @@ static void grgpio_set_imask(struct grgpio_priv *priv, unsigned int offset, { struct bgpio_chip *bgc = &priv->bgc; unsigned long mask = bgc->pin2mask(bgc, offset); - unsigned long flags; - - spin_lock_irqsave(&bgc->lock, flags); if (val) priv->imask |= mask; else priv->imask &= ~mask; bgc->write_reg(priv->regs + GRGPIO_IMASK, priv->imask); - - spin_unlock_irqrestore(&bgc->lock, flags); } static int grgpio_to_irq(struct gpio_chip *gc, unsigned offset) @@ -180,16 +175,26 @@ static void grgpio_irq_mask(struct irq_data *d) { struct grgpio_priv *priv = irq_data_get_irq_chip_data(d); int offset = d->hwirq; + unsigned long flags; + + spin_lock_irqsave(&priv->bgc.lock, flags); grgpio_set_imask(priv, offset, 0); + + spin_unlock_irqrestore(&priv->bgc.lock, flags); } static void grgpio_irq_unmask(struct irq_data *d) { struct grgpio_priv *priv = irq_data_get_irq_chip_data(d); int offset = d->hwirq; + unsigned long flags; + + spin_lock_irqsave(&priv->bgc.lock, flags); grgpio_set_imask(priv, offset, 1); + + spin_unlock_irqrestore(&priv->bgc.lock, flags); } static struct irq_chip grgpio_irq_chip = { @@ -281,12 +286,7 @@ static int grgpio_irq_map(struct irq_domain *d, unsigned int irq, irq_set_chip_data(irq, priv); irq_set_chip_and_handler(irq, &grgpio_irq_chip, handle_simple_irq); - irq_clear_status_flags(irq, IRQ_NOREQUEST); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else irq_set_noprobe(irq); -#endif return ret; } @@ -301,9 +301,6 @@ static void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq) int ngpio = priv->bgc.gc.ngpio; int i; -#ifdef CONFIG_ARM - set_irq_flags(irq, 0); -#endif irq_set_chip_and_handler(irq, NULL, NULL); irq_set_chip_data(irq, NULL); @@ -332,7 +329,7 @@ static void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq) spin_unlock_irqrestore(&priv->bgc.lock, flags); } -static struct irq_domain_ops grgpio_irq_domain_ops = { +static const struct irq_domain_ops grgpio_irq_domain_ops = { .map = grgpio_irq_map, .unmap = grgpio_irq_unmap, }; diff --git a/kernel/drivers/gpio/gpio-intel-mid.c b/kernel/drivers/gpio/gpio-intel-mid.c index aa28c65eb..70097472b 100644 --- a/kernel/drivers/gpio/gpio-intel-mid.c +++ b/kernel/drivers/gpio/gpio-intel-mid.c @@ -301,7 +301,7 @@ static const struct pci_device_id intel_gpio_ids[] = { }; MODULE_DEVICE_TABLE(pci, intel_gpio_ids); -static void intel_mid_irq_handler(unsigned irq, struct irq_desc *desc) +static void intel_mid_irq_handler(struct irq_desc *desc) { struct gpio_chip *gc = irq_desc_get_handler_data(desc); struct intel_mid_gpio *priv = to_intel_gpio_priv(gc); diff --git a/kernel/drivers/gpio/gpio-it87.c b/kernel/drivers/gpio/gpio-it87.c new file mode 100644 index 000000000..21f6f7c0e --- /dev/null +++ b/kernel/drivers/gpio/gpio-it87.c @@ -0,0 +1,411 @@ +/* + * GPIO interface for IT87xx Super I/O chips + * + * Author: Diego Elio Pettenò <flameeyes@flameeyes.eu> + * + * Based on it87_wdt.c by Oliver Schuster + * gpio-it8761e.c by Denis Turischev + * gpio-stmpe.c by Rabin Vincent + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 2 as published + * by the Free Software Foundation. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/io.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/gpio.h> + +/* Chip Id numbers */ +#define NO_DEV_ID 0xffff +#define IT8728_ID 0x8728 +#define IT8732_ID 0x8732 +#define IT8761_ID 0x8761 + +/* IO Ports */ +#define REG 0x2e +#define VAL 0x2f + +/* Logical device Numbers LDN */ +#define GPIO 0x07 + +/* Configuration Registers and Functions */ +#define LDNREG 0x07 +#define CHIPID 0x20 +#define CHIPREV 0x22 + +/** + * struct it87_gpio - it87-specific GPIO chip + * @chip the underlying gpio_chip structure + * @lock a lock to avoid races between operations + * @io_base base address for gpio ports + * @io_size size of the port rage starting from io_base. + * @output_base Super I/O register address for Output Enable register + * @simple_base Super I/O 'Simple I/O' Enable register + * @simple_size Super IO 'Simple I/O' Enable register size; this is + * required because IT87xx chips might only provide Simple I/O + * switches on a subset of lines, whereas the others keep the + * same status all time. + */ +struct it87_gpio { + struct gpio_chip chip; + spinlock_t lock; + u16 io_base; + u16 io_size; + u8 output_base; + u8 simple_base; + u8 simple_size; +}; + +static struct it87_gpio it87_gpio_chip = { + .lock = __SPIN_LOCK_UNLOCKED(it87_gpio_chip.lock), +}; + +static inline struct it87_gpio *to_it87_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct it87_gpio, chip); +} + +/* Superio chip access functions; copied from wdt_it87 */ + +static inline int superio_enter(void) +{ + /* + * Try to reserve REG and REG + 1 for exclusive access. + */ + if (!request_muxed_region(REG, 2, KBUILD_MODNAME)) + return -EBUSY; + + outb(0x87, REG); + outb(0x01, REG); + outb(0x55, REG); + outb(0x55, REG); + return 0; +} + +static inline void superio_exit(void) +{ + outb(0x02, REG); + outb(0x02, VAL); + release_region(REG, 2); +} + +static inline void superio_select(int ldn) +{ + outb(LDNREG, REG); + outb(ldn, VAL); +} + +static inline int superio_inb(int reg) +{ + outb(reg, REG); + return inb(VAL); +} + +static inline void superio_outb(int val, int reg) +{ + outb(reg, REG); + outb(val, VAL); +} + +static inline int superio_inw(int reg) +{ + int val; + + outb(reg++, REG); + val = inb(VAL) << 8; + outb(reg, REG); + val |= inb(VAL); + return val; +} + +static inline void superio_outw(int val, int reg) +{ + outb(reg++, REG); + outb(val >> 8, VAL); + outb(reg, REG); + outb(val, VAL); +} + +static inline void superio_set_mask(int mask, int reg) +{ + u8 curr_val = superio_inb(reg); + u8 new_val = curr_val | mask; + + if (curr_val != new_val) + superio_outb(new_val, reg); +} + +static inline void superio_clear_mask(int mask, int reg) +{ + u8 curr_val = superio_inb(reg); + u8 new_val = curr_val & ~mask; + + if (curr_val != new_val) + superio_outb(new_val, reg); +} + +static int it87_gpio_request(struct gpio_chip *chip, unsigned gpio_num) +{ + u8 mask, group; + int rc = 0; + struct it87_gpio *it87_gpio = to_it87_gpio(chip); + + mask = 1 << (gpio_num % 8); + group = (gpio_num / 8); + + spin_lock(&it87_gpio->lock); + + rc = superio_enter(); + if (rc) + goto exit; + + /* not all the IT87xx chips support Simple I/O and not all of + * them allow all the lines to be set/unset to Simple I/O. + */ + if (group < it87_gpio->simple_size) + superio_set_mask(mask, group + it87_gpio->simple_base); + + /* clear output enable, setting the pin to input, as all the + * newly-exported GPIO interfaces are set to input. + */ + superio_clear_mask(mask, group + it87_gpio->output_base); + + superio_exit(); + +exit: + spin_unlock(&it87_gpio->lock); + return rc; +} + +static int it87_gpio_get(struct gpio_chip *chip, unsigned gpio_num) +{ + u16 reg; + u8 mask; + struct it87_gpio *it87_gpio = to_it87_gpio(chip); + + mask = 1 << (gpio_num % 8); + reg = (gpio_num / 8) + it87_gpio->io_base; + + return !!(inb(reg) & mask); +} + +static int it87_gpio_direction_in(struct gpio_chip *chip, unsigned gpio_num) +{ + u8 mask, group; + int rc = 0; + struct it87_gpio *it87_gpio = to_it87_gpio(chip); + + mask = 1 << (gpio_num % 8); + group = (gpio_num / 8); + + spin_lock(&it87_gpio->lock); + + rc = superio_enter(); + if (rc) + goto exit; + + /* clear the output enable bit */ + superio_clear_mask(mask, group + it87_gpio->output_base); + + superio_exit(); + +exit: + spin_unlock(&it87_gpio->lock); + return rc; +} + +static void it87_gpio_set(struct gpio_chip *chip, + unsigned gpio_num, int val) +{ + u8 mask, curr_vals; + u16 reg; + struct it87_gpio *it87_gpio = to_it87_gpio(chip); + + mask = 1 << (gpio_num % 8); + reg = (gpio_num / 8) + it87_gpio->io_base; + + curr_vals = inb(reg); + if (val) + outb(curr_vals | mask, reg); + else + outb(curr_vals & ~mask, reg); +} + +static int it87_gpio_direction_out(struct gpio_chip *chip, + unsigned gpio_num, int val) +{ + u8 mask, group; + int rc = 0; + struct it87_gpio *it87_gpio = to_it87_gpio(chip); + + mask = 1 << (gpio_num % 8); + group = (gpio_num / 8); + + spin_lock(&it87_gpio->lock); + + rc = superio_enter(); + if (rc) + goto exit; + + /* set the output enable bit */ + superio_set_mask(mask, group + it87_gpio->output_base); + + it87_gpio_set(chip, gpio_num, val); + + superio_exit(); + +exit: + spin_unlock(&it87_gpio->lock); + return rc; +} + +static struct gpio_chip it87_template_chip = { + .label = KBUILD_MODNAME, + .owner = THIS_MODULE, + .request = it87_gpio_request, + .get = it87_gpio_get, + .direction_input = it87_gpio_direction_in, + .set = it87_gpio_set, + .direction_output = it87_gpio_direction_out, + .base = -1 +}; + +static int __init it87_gpio_init(void) +{ + int rc = 0, i; + u16 chip_type; + u8 chip_rev, gpio_ba_reg; + char *labels, **labels_table; + + struct it87_gpio *it87_gpio = &it87_gpio_chip; + + rc = superio_enter(); + if (rc) + return rc; + + chip_type = superio_inw(CHIPID); + chip_rev = superio_inb(CHIPREV) & 0x0f; + superio_exit(); + + it87_gpio->chip = it87_template_chip; + + switch (chip_type) { + case IT8728_ID: + case IT8732_ID: + gpio_ba_reg = 0x62; + it87_gpio->io_size = 8; + it87_gpio->output_base = 0xc8; + it87_gpio->simple_base = 0xc0; + it87_gpio->simple_size = 5; + it87_gpio->chip.ngpio = 64; + break; + case IT8761_ID: + gpio_ba_reg = 0x60; + it87_gpio->io_size = 4; + it87_gpio->output_base = 0xf0; + it87_gpio->simple_size = 0; + it87_gpio->chip.ngpio = 16; + break; + case NO_DEV_ID: + pr_err("no device\n"); + return -ENODEV; + default: + pr_err("Unknown Chip found, Chip %04x Revision %x\n", + chip_type, chip_rev); + return -ENODEV; + } + + rc = superio_enter(); + if (rc) + return rc; + + superio_select(GPIO); + + /* fetch GPIO base address */ + it87_gpio->io_base = superio_inw(gpio_ba_reg); + + superio_exit(); + + pr_info("Found Chip IT%04x rev %x. %u GPIO lines starting at %04xh\n", + chip_type, chip_rev, it87_gpio->chip.ngpio, + it87_gpio->io_base); + + if (!request_region(it87_gpio->io_base, it87_gpio->io_size, + KBUILD_MODNAME)) + return -EBUSY; + + /* Set up aliases for the GPIO connection. + * + * ITE documentation for recent chips such as the IT8728F + * refers to the GPIO lines as GPxy, with a coordinates system + * where x is the GPIO group (starting from 1) and y is the + * bit within the group. + * + * By creating these aliases, we make it easier to understand + * to which GPIO pin we're referring to. + */ + labels = kcalloc(it87_gpio->chip.ngpio, sizeof("it87_gpXY"), + GFP_KERNEL); + labels_table = kcalloc(it87_gpio->chip.ngpio, sizeof(const char *), + GFP_KERNEL); + + if (!labels || !labels_table) { + rc = -ENOMEM; + goto labels_free; + } + + for (i = 0; i < it87_gpio->chip.ngpio; i++) { + char *label = &labels[i * sizeof("it87_gpXY")]; + + sprintf(label, "it87_gp%u%u", 1+(i/8), i%8); + labels_table[i] = label; + } + + it87_gpio->chip.names = (const char *const*)labels_table; + + rc = gpiochip_add(&it87_gpio->chip); + if (rc) + goto labels_free; + + return 0; + +labels_free: + kfree(labels_table); + kfree(labels); + release_region(it87_gpio->io_base, it87_gpio->io_size); + return rc; +} + +static void __exit it87_gpio_exit(void) +{ + struct it87_gpio *it87_gpio = &it87_gpio_chip; + + gpiochip_remove(&it87_gpio->chip); + release_region(it87_gpio->io_base, it87_gpio->io_size); + kfree(it87_gpio->chip.names[0]); + kfree(it87_gpio->chip.names); +} + +module_init(it87_gpio_init); +module_exit(it87_gpio_exit); + +MODULE_AUTHOR("Diego Elio Pettenò <flameeyes@flameeyes.eu>"); +MODULE_DESCRIPTION("GPIO interface for IT87xx Super I/O chips"); +MODULE_LICENSE("GPL"); diff --git a/kernel/drivers/gpio/gpio-it8761e.c b/kernel/drivers/gpio/gpio-it8761e.c deleted file mode 100644 index dadfc245c..000000000 --- a/kernel/drivers/gpio/gpio-it8761e.c +++ /dev/null @@ -1,230 +0,0 @@ -/* - * GPIO interface for IT8761E Super I/O chip - * - * Author: Denis Turischev <denis@compulab.co.il> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License 2 as published - * by the Free Software Foundation. - * - * 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; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/io.h> -#include <linux/errno.h> -#include <linux/ioport.h> - -#include <linux/gpio.h> - -#define SIO_CHIP_ID 0x8761 -#define CHIP_ID_HIGH_BYTE 0x20 -#define CHIP_ID_LOW_BYTE 0x21 - -static u8 ports[2] = { 0x2e, 0x4e }; -static u8 port; - -static DEFINE_SPINLOCK(sio_lock); - -#define GPIO_NAME "it8761-gpio" -#define GPIO_BA_HIGH_BYTE 0x60 -#define GPIO_BA_LOW_BYTE 0x61 -#define GPIO_IOSIZE 4 -#define GPIO1X_IO 0xf0 -#define GPIO2X_IO 0xf1 - -static u16 gpio_ba; - -static u8 read_reg(u8 addr, u8 port) -{ - outb(addr, port); - return inb(port + 1); -} - -static void write_reg(u8 data, u8 addr, u8 port) -{ - outb(addr, port); - outb(data, port + 1); -} - -static void enter_conf_mode(u8 port) -{ - outb(0x87, port); - outb(0x61, port); - outb(0x55, port); - outb((port == 0x2e) ? 0x55 : 0xaa, port); -} - -static void exit_conf_mode(u8 port) -{ - outb(0x2, port); - outb(0x2, port + 1); -} - -static void enter_gpio_mode(u8 port) -{ - write_reg(0x2, 0x7, port); -} - -static int it8761e_gpio_get(struct gpio_chip *gc, unsigned gpio_num) -{ - u16 reg; - u8 bit; - - bit = gpio_num % 8; - reg = (gpio_num >= 8) ? gpio_ba + 1 : gpio_ba; - - return !!(inb(reg) & (1 << bit)); -} - -static int it8761e_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num) -{ - u8 curr_dirs; - u8 io_reg, bit; - - bit = gpio_num % 8; - io_reg = (gpio_num >= 8) ? GPIO2X_IO : GPIO1X_IO; - - spin_lock(&sio_lock); - - enter_conf_mode(port); - enter_gpio_mode(port); - - curr_dirs = read_reg(io_reg, port); - - if (curr_dirs & (1 << bit)) - write_reg(curr_dirs & ~(1 << bit), io_reg, port); - - exit_conf_mode(port); - - spin_unlock(&sio_lock); - return 0; -} - -static void it8761e_gpio_set(struct gpio_chip *gc, - unsigned gpio_num, int val) -{ - u8 curr_vals, bit; - u16 reg; - - bit = gpio_num % 8; - reg = (gpio_num >= 8) ? gpio_ba + 1 : gpio_ba; - - spin_lock(&sio_lock); - - curr_vals = inb(reg); - if (val) - outb(curr_vals | (1 << bit) , reg); - else - outb(curr_vals & ~(1 << bit), reg); - - spin_unlock(&sio_lock); -} - -static int it8761e_gpio_direction_out(struct gpio_chip *gc, - unsigned gpio_num, int val) -{ - u8 curr_dirs, io_reg, bit; - - bit = gpio_num % 8; - io_reg = (gpio_num >= 8) ? GPIO2X_IO : GPIO1X_IO; - - it8761e_gpio_set(gc, gpio_num, val); - - spin_lock(&sio_lock); - - enter_conf_mode(port); - enter_gpio_mode(port); - - curr_dirs = read_reg(io_reg, port); - - if (!(curr_dirs & (1 << bit))) - write_reg(curr_dirs | (1 << bit), io_reg, port); - - exit_conf_mode(port); - - spin_unlock(&sio_lock); - return 0; -} - -static struct gpio_chip it8761e_gpio_chip = { - .label = GPIO_NAME, - .owner = THIS_MODULE, - .get = it8761e_gpio_get, - .direction_input = it8761e_gpio_direction_in, - .set = it8761e_gpio_set, - .direction_output = it8761e_gpio_direction_out, -}; - -static int __init it8761e_gpio_init(void) -{ - int i, id, err; - - /* chip and port detection */ - for (i = 0; i < ARRAY_SIZE(ports); i++) { - spin_lock(&sio_lock); - enter_conf_mode(ports[i]); - - id = (read_reg(CHIP_ID_HIGH_BYTE, ports[i]) << 8) + - read_reg(CHIP_ID_LOW_BYTE, ports[i]); - - exit_conf_mode(ports[i]); - spin_unlock(&sio_lock); - - if (id == SIO_CHIP_ID) { - port = ports[i]; - break; - } - } - - if (!port) - return -ENODEV; - - /* fetch GPIO base address */ - enter_conf_mode(port); - enter_gpio_mode(port); - gpio_ba = (read_reg(GPIO_BA_HIGH_BYTE, port) << 8) + - read_reg(GPIO_BA_LOW_BYTE, port); - exit_conf_mode(port); - - if (!request_region(gpio_ba, GPIO_IOSIZE, GPIO_NAME)) - return -EBUSY; - - it8761e_gpio_chip.base = -1; - it8761e_gpio_chip.ngpio = 16; - - err = gpiochip_add(&it8761e_gpio_chip); - if (err < 0) - goto gpiochip_add_err; - - return 0; - -gpiochip_add_err: - release_region(gpio_ba, GPIO_IOSIZE); - gpio_ba = 0; - return err; -} - -static void __exit it8761e_gpio_exit(void) -{ - if (gpio_ba) { - gpiochip_remove(&it8761e_gpio_chip); - release_region(gpio_ba, GPIO_IOSIZE); - gpio_ba = 0; - } -} -module_init(it8761e_gpio_init); -module_exit(it8761e_gpio_exit); - -MODULE_AUTHOR("Denis Turischev <denis@compulab.co.il>"); -MODULE_DESCRIPTION("GPIO interface for IT8761E Super I/O chip"); -MODULE_LICENSE("GPL"); diff --git a/kernel/drivers/gpio/gpio-lpc18xx.c b/kernel/drivers/gpio/gpio-lpc18xx.c new file mode 100644 index 000000000..e39dcb0af --- /dev/null +++ b/kernel/drivers/gpio/gpio-lpc18xx.c @@ -0,0 +1,170 @@ +/* + * GPIO driver for NXP LPC18xx/43xx. + * + * Copyright (C) 2015 Joachim Eastwood <manabian@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. + * + */ + +#include <linux/clk.h> +#include <linux/gpio/driver.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/pinctrl/consumer.h> +#include <linux/platform_device.h> + +/* LPC18xx GPIO register offsets */ +#define LPC18XX_REG_DIR(n) (0x2000 + n * sizeof(u32)) + +#define LPC18XX_MAX_PORTS 8 +#define LPC18XX_PINS_PER_PORT 32 + +struct lpc18xx_gpio_chip { + struct gpio_chip gpio; + void __iomem *base; + struct clk *clk; + spinlock_t lock; +}; + +static inline struct lpc18xx_gpio_chip *to_lpc18xx_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct lpc18xx_gpio_chip, gpio); +} + +static void lpc18xx_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct lpc18xx_gpio_chip *gc = to_lpc18xx_gpio(chip); + writeb(value ? 1 : 0, gc->base + offset); +} + +static int lpc18xx_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct lpc18xx_gpio_chip *gc = to_lpc18xx_gpio(chip); + return !!readb(gc->base + offset); +} + +static int lpc18xx_gpio_direction(struct gpio_chip *chip, unsigned offset, + bool out) +{ + struct lpc18xx_gpio_chip *gc = to_lpc18xx_gpio(chip); + unsigned long flags; + u32 port, pin, dir; + + port = offset / LPC18XX_PINS_PER_PORT; + pin = offset % LPC18XX_PINS_PER_PORT; + + spin_lock_irqsave(&gc->lock, flags); + dir = readl(gc->base + LPC18XX_REG_DIR(port)); + if (out) + dir |= BIT(pin); + else + dir &= ~BIT(pin); + writel(dir, gc->base + LPC18XX_REG_DIR(port)); + spin_unlock_irqrestore(&gc->lock, flags); + + return 0; +} + +static int lpc18xx_gpio_direction_input(struct gpio_chip *chip, + unsigned offset) +{ + return lpc18xx_gpio_direction(chip, offset, false); +} + +static int lpc18xx_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + lpc18xx_gpio_set(chip, offset, value); + return lpc18xx_gpio_direction(chip, offset, true); +} + +static struct gpio_chip lpc18xx_chip = { + .label = "lpc18xx/43xx-gpio", + .request = gpiochip_generic_request, + .free = gpiochip_generic_free, + .direction_input = lpc18xx_gpio_direction_input, + .direction_output = lpc18xx_gpio_direction_output, + .set = lpc18xx_gpio_set, + .get = lpc18xx_gpio_get, + .ngpio = LPC18XX_MAX_PORTS * LPC18XX_PINS_PER_PORT, + .owner = THIS_MODULE, +}; + +static int lpc18xx_gpio_probe(struct platform_device *pdev) +{ + struct lpc18xx_gpio_chip *gc; + struct resource *res; + int ret; + + gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL); + if (!gc) + return -ENOMEM; + + gc->gpio = lpc18xx_chip; + platform_set_drvdata(pdev, gc); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + gc->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(gc->base)) + return PTR_ERR(gc->base); + + gc->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(gc->clk)) { + dev_err(&pdev->dev, "input clock not found\n"); + return PTR_ERR(gc->clk); + } + + ret = clk_prepare_enable(gc->clk); + if (ret) { + dev_err(&pdev->dev, "unable to enable clock\n"); + return ret; + } + + spin_lock_init(&gc->lock); + + gc->gpio.dev = &pdev->dev; + + ret = gpiochip_add(&gc->gpio); + if (ret) { + dev_err(&pdev->dev, "failed to add gpio chip\n"); + clk_disable_unprepare(gc->clk); + return ret; + } + + return 0; +} + +static int lpc18xx_gpio_remove(struct platform_device *pdev) +{ + struct lpc18xx_gpio_chip *gc = platform_get_drvdata(pdev); + + gpiochip_remove(&gc->gpio); + clk_disable_unprepare(gc->clk); + + return 0; +} + +static const struct of_device_id lpc18xx_gpio_match[] = { + { .compatible = "nxp,lpc1850-gpio" }, + { } +}; +MODULE_DEVICE_TABLE(of, lpc18xx_gpio_match); + +static struct platform_driver lpc18xx_gpio_driver = { + .probe = lpc18xx_gpio_probe, + .remove = lpc18xx_gpio_remove, + .driver = { + .name = "lpc18xx-gpio", + .of_match_table = lpc18xx_gpio_match, + }, +}; +module_platform_driver(lpc18xx_gpio_driver); + +MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>"); +MODULE_DESCRIPTION("GPIO driver for LPC18xx/43xx"); +MODULE_LICENSE("GPL v2"); diff --git a/kernel/drivers/gpio/gpio-lynxpoint.c b/kernel/drivers/gpio/gpio-lynxpoint.c index 127c755b3..127c37b38 100644 --- a/kernel/drivers/gpio/gpio-lynxpoint.c +++ b/kernel/drivers/gpio/gpio-lynxpoint.c @@ -72,7 +72,7 @@ struct lp_gpio { * * per gpio specific registers consist of two 32bit registers per gpio * (LP_CONFIG1 and LP_CONFIG2), with 94 gpios there's a total of - * 188 config registes. + * 188 config registers. * * A simplified view of the register layout look like this: * @@ -234,7 +234,7 @@ static int lp_gpio_direction_output(struct gpio_chip *chip, return 0; } -static void lp_gpio_irq_handler(unsigned hwirq, struct irq_desc *desc) +static void lp_gpio_irq_handler(struct irq_desc *desc) { struct irq_data *data = irq_desc_get_irq_data(desc); struct gpio_chip *gc = irq_desc_get_handler_data(desc); diff --git a/kernel/drivers/gpio/gpio-max7301.c b/kernel/drivers/gpio/gpio-max7301.c index 6e1c984a7..05813fbf3 100644 --- a/kernel/drivers/gpio/gpio-max7301.c +++ b/kernel/drivers/gpio/gpio-max7301.c @@ -87,7 +87,6 @@ MODULE_DEVICE_TABLE(spi, max7301_id); static struct spi_driver max7301_driver = { .driver = { .name = "max7301", - .owner = THIS_MODULE, }, .probe = max7301_probe, .remove = max7301_remove, diff --git a/kernel/drivers/gpio/gpio-max730x.c b/kernel/drivers/gpio/gpio-max730x.c index 18ab89e20..0f57d2d24 100644 --- a/kernel/drivers/gpio/gpio-max730x.c +++ b/kernel/drivers/gpio/gpio-max730x.c @@ -236,7 +236,6 @@ int __max730x_remove(struct device *dev) ts->write(dev, 0x04, 0x00); gpiochip_remove(&ts->chip); mutex_destroy(&ts->lock); - kfree(ts); return 0; } EXPORT_SYMBOL_GPL(__max730x_remove); diff --git a/kernel/drivers/gpio/gpio-max732x.c b/kernel/drivers/gpio/gpio-max732x.c index 0fa4543c5..8c5252c6c 100644 --- a/kernel/drivers/gpio/gpio-max732x.c +++ b/kernel/drivers/gpio/gpio-max732x.c @@ -429,6 +429,14 @@ static int max732x_irq_set_type(struct irq_data *d, unsigned int type) return 0; } +static int max732x_irq_set_wake(struct irq_data *data, unsigned int on) +{ + struct max732x_chip *chip = irq_data_get_irq_chip_data(data); + + irq_set_irq_wake(chip->client->irq, on); + return 0; +} + static struct irq_chip max732x_irq_chip = { .name = "max732x", .irq_mask = max732x_irq_mask, @@ -436,6 +444,7 @@ static struct irq_chip max732x_irq_chip = { .irq_bus_lock = max732x_irq_bus_lock, .irq_bus_sync_unlock = max732x_irq_bus_sync_unlock, .irq_set_type = max732x_irq_set_type, + .irq_set_wake = max732x_irq_set_wake, }; static uint8_t max732x_irq_pending(struct max732x_chip *chip) @@ -507,12 +516,10 @@ static int max732x_irq_setup(struct max732x_chip *chip, chip->irq_features = has_irq; mutex_init(&chip->irq_lock); - ret = devm_request_threaded_irq(&client->dev, - client->irq, - NULL, - max732x_irq_handler, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - dev_name(&client->dev), chip); + ret = devm_request_threaded_irq(&client->dev, client->irq, + NULL, max732x_irq_handler, IRQF_ONESHOT | + IRQF_TRIGGER_FALLING | IRQF_SHARED, + dev_name(&client->dev), chip); if (ret) { dev_err(&client->dev, "failed to request irq %d\n", client->irq); @@ -521,7 +528,7 @@ static int max732x_irq_setup(struct max732x_chip *chip, ret = gpiochip_irqchip_add(&chip->gpio_chip, &max732x_irq_chip, irq_base, - handle_edge_irq, + handle_simple_irq, IRQ_TYPE_NONE); if (ret) { dev_err(&client->dev, @@ -596,6 +603,7 @@ static int max732x_setup_gpio(struct max732x_chip *chip, gc->base = gpio_start; gc->ngpio = port; gc->label = chip->client->name; + gc->dev = &chip->client->dev; gc->owner = THIS_MODULE; return port; @@ -677,9 +685,14 @@ static int max732x_probe(struct i2c_client *client, mutex_init(&chip->lock); - max732x_readb(chip, is_group_a(chip, 0), &chip->reg_out[0]); - if (nr_port > 8) - max732x_readb(chip, is_group_a(chip, 8), &chip->reg_out[1]); + ret = max732x_readb(chip, is_group_a(chip, 0), &chip->reg_out[0]); + if (ret) + goto out_failed; + if (nr_port > 8) { + ret = max732x_readb(chip, is_group_a(chip, 8), &chip->reg_out[1]); + if (ret) + goto out_failed; + } ret = gpiochip_add(&chip->gpio_chip); if (ret) diff --git a/kernel/drivers/gpio/gpio-mc33880.c b/kernel/drivers/gpio/gpio-mc33880.c index a431604c9..2853731db 100644 --- a/kernel/drivers/gpio/gpio-mc33880.c +++ b/kernel/drivers/gpio/gpio-mc33880.c @@ -163,7 +163,6 @@ static int mc33880_remove(struct spi_device *spi) static struct spi_driver mc33880_driver = { .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, }, .probe = mc33880_probe, .remove = mc33880_remove, diff --git a/kernel/drivers/gpio/gpio-mcp23s08.c b/kernel/drivers/gpio/gpio-mcp23s08.c index 2fc7ff852..4a4169491 100644 --- a/kernel/drivers/gpio/gpio-mcp23s08.c +++ b/kernel/drivers/gpio/gpio-mcp23s08.c @@ -507,11 +507,7 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp) irq_set_chip_data(irq, mcp); irq_set_chip(irq, &mcp23s08_irq_chip); irq_set_nested_thread(irq, true); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else irq_set_noprobe(irq); -#endif } return 0; } @@ -852,7 +848,6 @@ MODULE_DEVICE_TABLE(i2c, mcp230xx_id); static struct i2c_driver mcp230xx_driver = { .driver = { .name = "mcp230xx", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(mcp23s08_i2c_of_match), }, .probe = mcp230xx_probe, @@ -1025,7 +1020,6 @@ static struct spi_driver mcp23s08_driver = { .id_table = mcp23s08_ids, .driver = { .name = "mcp23s08", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(mcp23s08_spi_of_match), }, }; diff --git a/kernel/drivers/gpio/gpio-moxart.c b/kernel/drivers/gpio/gpio-moxart.c index c3ab46e59..d3355a6dc 100644 --- a/kernel/drivers/gpio/gpio-moxart.c +++ b/kernel/drivers/gpio/gpio-moxart.c @@ -29,27 +29,6 @@ #define GPIO_DATA_IN 0x04 #define GPIO_PIN_DIRECTION 0x08 -static int moxart_gpio_request(struct gpio_chip *chip, unsigned offset) -{ - return pinctrl_request_gpio(offset); -} - -static void moxart_gpio_free(struct gpio_chip *chip, unsigned offset) -{ - pinctrl_free_gpio(offset); -} - -static int moxart_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - struct bgpio_chip *bgc = to_bgpio_chip(chip); - u32 ret = bgc->read_reg(bgc->reg_dir); - - if (ret & BIT(offset)) - return !!(bgc->read_reg(bgc->reg_set) & BIT(offset)); - else - return !!(bgc->read_reg(bgc->reg_dat) & BIT(offset)); -} - static int moxart_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -68,17 +47,17 @@ static int moxart_gpio_probe(struct platform_device *pdev) return PTR_ERR(base); ret = bgpio_init(bgc, dev, 4, base + GPIO_DATA_IN, - base + GPIO_DATA_OUT, NULL, - base + GPIO_PIN_DIRECTION, NULL, 0); + base + GPIO_DATA_OUT, NULL, + base + GPIO_PIN_DIRECTION, NULL, + BGPIOF_READ_OUTPUT_REG_SET); if (ret) { dev_err(&pdev->dev, "bgpio_init failed\n"); return ret; } bgc->gc.label = "moxart-gpio"; - bgc->gc.request = moxart_gpio_request; - bgc->gc.free = moxart_gpio_free; - bgc->gc.get = moxart_gpio_get; + bgc->gc.request = gpiochip_generic_request; + bgc->gc.free = gpiochip_generic_free; bgc->data = bgc->read_reg(bgc->reg_set); bgc->gc.base = 0; bgc->gc.ngpio = 32; diff --git a/kernel/drivers/gpio/gpio-mpc8xxx.c b/kernel/drivers/gpio/gpio-mpc8xxx.c index a65b75161..48ef36834 100644 --- a/kernel/drivers/gpio/gpio-mpc8xxx.c +++ b/kernel/drivers/gpio/gpio-mpc8xxx.c @@ -32,7 +32,7 @@ struct mpc8xxx_gpio_chip { struct of_mm_gpio_chip mm_gc; - spinlock_t lock; + raw_spinlock_t lock; /* * shadowed data register to be able to clear/set output pins in @@ -95,7 +95,7 @@ static void mpc8xxx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); unsigned long flags; - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); if (val) mpc8xxx_gc->data |= mpc8xxx_gpio2mask(gpio); @@ -104,7 +104,7 @@ static void mpc8xxx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) out_be32(mm->regs + GPIO_DAT, mpc8xxx_gc->data); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); } static void mpc8xxx_gpio_set_multiple(struct gpio_chip *gc, @@ -115,7 +115,7 @@ static void mpc8xxx_gpio_set_multiple(struct gpio_chip *gc, unsigned long flags; int i; - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); for (i = 0; i < gc->ngpio; i++) { if (*mask == 0) @@ -130,7 +130,7 @@ static void mpc8xxx_gpio_set_multiple(struct gpio_chip *gc, out_be32(mm->regs + GPIO_DAT, mpc8xxx_gc->data); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); } static int mpc8xxx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) @@ -139,11 +139,11 @@ static int mpc8xxx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); unsigned long flags; - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); clrbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio)); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); return 0; } @@ -156,11 +156,11 @@ static int mpc8xxx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val mpc8xxx_gpio_set(gc, gpio, val); - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); setbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio)); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); return 0; } @@ -174,6 +174,15 @@ static int mpc5121_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val return mpc8xxx_gpio_dir_out(gc, gpio, val); } +static int mpc5125_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) +{ + /* GPIO 0..3 are input only on MPC5125 */ + if (gpio <= 3) + return -EINVAL; + + return mpc8xxx_gpio_dir_out(gc, gpio, val); +} + static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset) { struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); @@ -185,7 +194,7 @@ static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset) return -ENXIO; } -static void mpc8xxx_gpio_irq_cascade(unsigned int irq, struct irq_desc *desc) +static void mpc8xxx_gpio_irq_cascade(struct irq_desc *desc) { struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); @@ -206,11 +215,11 @@ static void mpc8xxx_irq_unmask(struct irq_data *d) struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; unsigned long flags; - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); } static void mpc8xxx_irq_mask(struct irq_data *d) @@ -219,11 +228,11 @@ static void mpc8xxx_irq_mask(struct irq_data *d) struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; unsigned long flags; - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); } static void mpc8xxx_irq_ack(struct irq_data *d) @@ -242,17 +251,17 @@ static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type) switch (flow_type) { case IRQ_TYPE_EDGE_FALLING: - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); setbits32(mm->regs + GPIO_ICR, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); break; case IRQ_TYPE_EDGE_BOTH: - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); clrbits32(mm->regs + GPIO_ICR, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); break; default: @@ -282,22 +291,22 @@ static int mpc512x_irq_set_type(struct irq_data *d, unsigned int flow_type) switch (flow_type) { case IRQ_TYPE_EDGE_FALLING: case IRQ_TYPE_LEVEL_LOW: - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); clrsetbits_be32(reg, 3 << shift, 2 << shift); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); break; case IRQ_TYPE_EDGE_RISING: case IRQ_TYPE_LEVEL_HIGH: - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); clrsetbits_be32(reg, 3 << shift, 1 << shift); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); break; case IRQ_TYPE_EDGE_BOTH: - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); clrbits32(reg, 3 << shift); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); break; default: @@ -312,33 +321,56 @@ static struct irq_chip mpc8xxx_irq_chip = { .irq_unmask = mpc8xxx_irq_unmask, .irq_mask = mpc8xxx_irq_mask, .irq_ack = mpc8xxx_irq_ack, + /* this might get overwritten in mpc8xxx_probe() */ .irq_set_type = mpc8xxx_irq_set_type, }; 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(irq, h->host_data); irq_set_chip_and_handler(irq, &mpc8xxx_irq_chip, handle_level_irq); return 0; } -static struct irq_domain_ops mpc8xxx_gpio_irq_ops = { +static const struct irq_domain_ops mpc8xxx_gpio_irq_ops = { .map = mpc8xxx_gpio_irq_map, .xlate = irq_domain_xlate_twocell, }; -static struct of_device_id mpc8xxx_gpio_ids[] = { +struct mpc8xxx_gpio_devtype { + int (*gpio_dir_out)(struct gpio_chip *, unsigned int, int); + int (*gpio_get)(struct gpio_chip *, unsigned int); + int (*irq_set_type)(struct irq_data *, unsigned int); +}; + +static const struct mpc8xxx_gpio_devtype mpc512x_gpio_devtype = { + .gpio_dir_out = mpc5121_gpio_dir_out, + .irq_set_type = mpc512x_irq_set_type, +}; + +static const struct mpc8xxx_gpio_devtype mpc5125_gpio_devtype = { + .gpio_dir_out = mpc5125_gpio_dir_out, + .irq_set_type = mpc512x_irq_set_type, +}; + +static const struct mpc8xxx_gpio_devtype mpc8572_gpio_devtype = { + .gpio_get = mpc8572_gpio_get, +}; + +static const struct mpc8xxx_gpio_devtype mpc8xxx_gpio_devtype_default = { + .gpio_dir_out = mpc8xxx_gpio_dir_out, + .gpio_get = mpc8xxx_gpio_get, + .irq_set_type = mpc8xxx_irq_set_type, +}; + +static const struct of_device_id mpc8xxx_gpio_ids[] = { { .compatible = "fsl,mpc8349-gpio", }, - { .compatible = "fsl,mpc8572-gpio", }, + { .compatible = "fsl,mpc8572-gpio", .data = &mpc8572_gpio_devtype, }, { .compatible = "fsl,mpc8610-gpio", }, - { .compatible = "fsl,mpc5121-gpio", .data = mpc512x_irq_set_type, }, + { .compatible = "fsl,mpc5121-gpio", .data = &mpc512x_gpio_devtype, }, + { .compatible = "fsl,mpc5125-gpio", .data = &mpc5125_gpio_devtype, }, { .compatible = "fsl,pq3-gpio", }, { .compatible = "fsl,qoriq-gpio", }, {} @@ -351,6 +383,8 @@ static int mpc8xxx_probe(struct platform_device *pdev) struct of_mm_gpio_chip *mm_gc; struct gpio_chip *gc; const struct of_device_id *id; + const struct mpc8xxx_gpio_devtype *devtype = + of_device_get_match_data(&pdev->dev); int ret; mpc8xxx_gc = devm_kzalloc(&pdev->dev, sizeof(*mpc8xxx_gc), GFP_KERNEL); @@ -359,7 +393,7 @@ static int mpc8xxx_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mpc8xxx_gc); - spin_lock_init(&mpc8xxx_gc->lock); + raw_spin_lock_init(&mpc8xxx_gc->lock); mm_gc = &mpc8xxx_gc->mm_gc; gc = &mm_gc->gc; @@ -367,10 +401,18 @@ static int mpc8xxx_probe(struct platform_device *pdev) mm_gc->save_regs = mpc8xxx_gpio_save_regs; gc->ngpio = MPC8XXX_GPIO_PINS; gc->direction_input = mpc8xxx_gpio_dir_in; - gc->direction_output = of_device_is_compatible(np, "fsl,mpc5121-gpio") ? - mpc5121_gpio_dir_out : mpc8xxx_gpio_dir_out; - gc->get = of_device_is_compatible(np, "fsl,mpc8572-gpio") ? - mpc8572_gpio_get : mpc8xxx_gpio_get; + + if (!devtype) + devtype = &mpc8xxx_gpio_devtype_default; + + /* + * It's assumed that only a single type of gpio controller is available + * on the current machine, so overwriting global data is fine. + */ + mpc8xxx_irq_chip.irq_set_type = devtype->irq_set_type; + + gc->direction_output = devtype->gpio_dir_out ?: mpc8xxx_gpio_dir_out; + gc->get = devtype->gpio_get ?: mpc8xxx_gpio_get; gc->set = mpc8xxx_gpio_set; gc->set_multiple = mpc8xxx_gpio_set_multiple; gc->to_irq = mpc8xxx_gpio_to_irq; @@ -396,8 +438,8 @@ static int mpc8xxx_probe(struct platform_device *pdev) out_be32(mm_gc->regs + GPIO_IER, 0xffffffff); out_be32(mm_gc->regs + GPIO_IMR, 0); - irq_set_handler_data(mpc8xxx_gc->irqn, mpc8xxx_gc); - irq_set_chained_handler(mpc8xxx_gc->irqn, mpc8xxx_gpio_irq_cascade); + irq_set_chained_handler_and_data(mpc8xxx_gc->irqn, + mpc8xxx_gpio_irq_cascade, mpc8xxx_gc); return 0; } @@ -407,8 +449,7 @@ static int mpc8xxx_remove(struct platform_device *pdev) struct mpc8xxx_gpio_chip *mpc8xxx_gc = platform_get_drvdata(pdev); if (mpc8xxx_gc->irq) { - irq_set_handler_data(mpc8xxx_gc->irqn, NULL); - irq_set_chained_handler(mpc8xxx_gc->irqn, NULL); + irq_set_chained_handler_and_data(mpc8xxx_gc->irqn, NULL, NULL); irq_domain_remove(mpc8xxx_gc->irq); } diff --git a/kernel/drivers/gpio/gpio-msic.c b/kernel/drivers/gpio/gpio-msic.c index 01acf0a8c..22523aae8 100644 --- a/kernel/drivers/gpio/gpio-msic.c +++ b/kernel/drivers/gpio/gpio-msic.c @@ -232,7 +232,7 @@ static struct irq_chip msic_irqchip = { .irq_bus_sync_unlock = msic_bus_sync_unlock, }; -static void msic_gpio_irq_handler(unsigned irq, struct irq_desc *desc) +static void msic_gpio_irq_handler(struct irq_desc *desc) { struct irq_data *data = irq_desc_get_irq_data(desc); struct msic_gpio *mg = irq_data_get_irq_handler_data(data); @@ -309,8 +309,7 @@ static int platform_msic_gpio_probe(struct platform_device *pdev) &msic_irqchip, handle_simple_irq); } - irq_set_chained_handler(mg->irq, msic_gpio_irq_handler); - irq_set_handler_data(mg->irq, mg); + irq_set_chained_handler_and_data(mg->irq, msic_gpio_irq_handler, mg); return 0; err: diff --git a/kernel/drivers/gpio/gpio-msm-v2.c b/kernel/drivers/gpio/gpio-msm-v2.c deleted file mode 100644 index 52ff18229..000000000 --- a/kernel/drivers/gpio/gpio-msm-v2.c +++ /dev/null @@ -1,462 +0,0 @@ -/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ -#define pr_fmt(fmt) "%s: " fmt, __func__ - -#include <linux/bitmap.h> -#include <linux/bitops.h> -#include <linux/err.h> -#include <linux/gpio.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/irqchip/chained_irq.h> -#include <linux/irq.h> -#include <linux/irqdomain.h> -#include <linux/module.h> -#include <linux/of_address.h> -#include <linux/platform_device.h> -#include <linux/spinlock.h> -#include <linux/slab.h> - -#define MAX_NR_GPIO 300 - -/* Bits of interest in the GPIO_IN_OUT register. - */ -enum { - GPIO_IN = 0, - GPIO_OUT = 1 -}; - -/* Bits of interest in the GPIO_INTR_STATUS register. - */ -enum { - INTR_STATUS = 0, -}; - -/* Bits of interest in the GPIO_CFG register. - */ -enum { - GPIO_OE = 9, -}; - -/* Bits of interest in the GPIO_INTR_CFG register. - * When a GPIO triggers, two separate decisions are made, controlled - * by two separate flags. - * - * - First, INTR_RAW_STATUS_EN controls whether or not the GPIO_INTR_STATUS - * register for that GPIO will be updated to reflect the triggering of that - * gpio. If this bit is 0, this register will not be updated. - * - Second, INTR_ENABLE controls whether an interrupt is triggered. - * - * If INTR_ENABLE is set and INTR_RAW_STATUS_EN is NOT set, an interrupt - * can be triggered but the status register will not reflect it. - */ -enum { - INTR_ENABLE = 0, - INTR_POL_CTL = 1, - INTR_DECT_CTL = 2, - INTR_RAW_STATUS_EN = 3, -}; - -/* Codes of interest in GPIO_INTR_CFG_SU. - */ -enum { - TARGET_PROC_SCORPION = 4, - TARGET_PROC_NONE = 7, -}; - -/** - * struct msm_gpio_dev: the MSM8660 SoC GPIO device structure - * - * @enabled_irqs: a bitmap used to optimize the summary-irq handler. By - * keeping track of which gpios are unmasked as irq sources, we avoid - * having to do readl calls on hundreds of iomapped registers each time - * the summary interrupt fires in order to locate the active interrupts. - * - * @wake_irqs: a bitmap for tracking which interrupt lines are enabled - * as wakeup sources. When the device is suspended, interrupts which are - * not wakeup sources are disabled. - * - * @dual_edge_irqs: a bitmap used to track which irqs are configured - * as dual-edge, as this is not supported by the hardware and requires - * some special handling in the driver. - */ -struct msm_gpio_dev { - struct gpio_chip gpio_chip; - DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO); - DECLARE_BITMAP(wake_irqs, MAX_NR_GPIO); - DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO); - struct irq_domain *domain; - int summary_irq; - void __iomem *msm_tlmm_base; -}; - -static struct msm_gpio_dev msm_gpio; - -#define GPIO_INTR_CFG_SU(gpio) (msm_gpio.msm_tlmm_base + 0x0400 + \ - (0x04 * (gpio))) -#define GPIO_CONFIG(gpio) (msm_gpio.msm_tlmm_base + 0x1000 + \ - (0x10 * (gpio))) -#define GPIO_IN_OUT(gpio) (msm_gpio.msm_tlmm_base + 0x1004 + \ - (0x10 * (gpio))) -#define GPIO_INTR_CFG(gpio) (msm_gpio.msm_tlmm_base + 0x1008 + \ - (0x10 * (gpio))) -#define GPIO_INTR_STATUS(gpio) (msm_gpio.msm_tlmm_base + 0x100c + \ - (0x10 * (gpio))) - -static DEFINE_SPINLOCK(tlmm_lock); - -static inline struct msm_gpio_dev *to_msm_gpio_dev(struct gpio_chip *chip) -{ - return container_of(chip, struct msm_gpio_dev, gpio_chip); -} - -static inline void set_gpio_bits(unsigned n, void __iomem *reg) -{ - writel(readl(reg) | n, reg); -} - -static inline void clear_gpio_bits(unsigned n, void __iomem *reg) -{ - writel(readl(reg) & ~n, reg); -} - -static int msm_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - return readl(GPIO_IN_OUT(offset)) & BIT(GPIO_IN); -} - -static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int val) -{ - writel(val ? BIT(GPIO_OUT) : 0, GPIO_IN_OUT(offset)); -} - -static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - unsigned long irq_flags; - - spin_lock_irqsave(&tlmm_lock, irq_flags); - clear_gpio_bits(BIT(GPIO_OE), GPIO_CONFIG(offset)); - spin_unlock_irqrestore(&tlmm_lock, irq_flags); - return 0; -} - -static int msm_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, - int val) -{ - unsigned long irq_flags; - - spin_lock_irqsave(&tlmm_lock, irq_flags); - msm_gpio_set(chip, offset, val); - set_gpio_bits(BIT(GPIO_OE), GPIO_CONFIG(offset)); - spin_unlock_irqrestore(&tlmm_lock, irq_flags); - return 0; -} - -static int msm_gpio_request(struct gpio_chip *chip, unsigned offset) -{ - return 0; -} - -static void msm_gpio_free(struct gpio_chip *chip, unsigned offset) -{ - return; -} - -static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct msm_gpio_dev *g_dev = to_msm_gpio_dev(chip); - struct irq_domain *domain = g_dev->domain; - - return irq_create_mapping(domain, offset); -} - -static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq) -{ - struct irq_data *irq_data = irq_get_irq_data(irq); - - return irq_data->hwirq; -} - - -/* For dual-edge interrupts in software, since the hardware has no - * such support: - * - * At appropriate moments, this function may be called to flip the polarity - * settings of both-edge irq lines to try and catch the next edge. - * - * The attempt is considered successful if: - * - the status bit goes high, indicating that an edge was caught, or - * - the input value of the gpio doesn't change during the attempt. - * If the value changes twice during the process, that would cause the first - * test to fail but would force the second, as two opposite - * transitions would cause a detection no matter the polarity setting. - * - * The do-loop tries to sledge-hammer closed the timing hole between - * the initial value-read and the polarity-write - if the line value changes - * during that window, an interrupt is lost, the new polarity setting is - * incorrect, and the first success test will fail, causing a retry. - * - * Algorithm comes from Google's msmgpio driver, see mach-msm/gpio.c. - */ -static void msm_gpio_update_dual_edge_pos(unsigned gpio) -{ - int loop_limit = 100; - unsigned val, val2, intstat; - - do { - val = readl(GPIO_IN_OUT(gpio)) & BIT(GPIO_IN); - if (val) - clear_gpio_bits(BIT(INTR_POL_CTL), GPIO_INTR_CFG(gpio)); - else - set_gpio_bits(BIT(INTR_POL_CTL), GPIO_INTR_CFG(gpio)); - val2 = readl(GPIO_IN_OUT(gpio)) & BIT(GPIO_IN); - intstat = readl(GPIO_INTR_STATUS(gpio)) & BIT(INTR_STATUS); - if (intstat || val == val2) - return; - } while (loop_limit-- > 0); - pr_err("%s: dual-edge irq failed to stabilize, " - "interrupts dropped. %#08x != %#08x\n", - __func__, val, val2); -} - -static void msm_gpio_irq_ack(struct irq_data *d) -{ - int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq); - - writel(BIT(INTR_STATUS), GPIO_INTR_STATUS(gpio)); - if (test_bit(gpio, msm_gpio.dual_edge_irqs)) - msm_gpio_update_dual_edge_pos(gpio); -} - -static void msm_gpio_irq_mask(struct irq_data *d) -{ - int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq); - unsigned long irq_flags; - - spin_lock_irqsave(&tlmm_lock, irq_flags); - writel(TARGET_PROC_NONE, GPIO_INTR_CFG_SU(gpio)); - clear_gpio_bits(BIT(INTR_RAW_STATUS_EN) | BIT(INTR_ENABLE), GPIO_INTR_CFG(gpio)); - __clear_bit(gpio, msm_gpio.enabled_irqs); - spin_unlock_irqrestore(&tlmm_lock, irq_flags); -} - -static void msm_gpio_irq_unmask(struct irq_data *d) -{ - int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq); - unsigned long irq_flags; - - spin_lock_irqsave(&tlmm_lock, irq_flags); - __set_bit(gpio, msm_gpio.enabled_irqs); - set_gpio_bits(BIT(INTR_RAW_STATUS_EN) | BIT(INTR_ENABLE), GPIO_INTR_CFG(gpio)); - writel(TARGET_PROC_SCORPION, GPIO_INTR_CFG_SU(gpio)); - spin_unlock_irqrestore(&tlmm_lock, irq_flags); -} - -static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type) -{ - int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq); - unsigned long irq_flags; - uint32_t bits; - - spin_lock_irqsave(&tlmm_lock, irq_flags); - - bits = readl(GPIO_INTR_CFG(gpio)); - - if (flow_type & IRQ_TYPE_EDGE_BOTH) { - bits |= BIT(INTR_DECT_CTL); - __irq_set_handler_locked(d->irq, handle_edge_irq); - if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) - __set_bit(gpio, msm_gpio.dual_edge_irqs); - else - __clear_bit(gpio, msm_gpio.dual_edge_irqs); - } else { - bits &= ~BIT(INTR_DECT_CTL); - __irq_set_handler_locked(d->irq, handle_level_irq); - __clear_bit(gpio, msm_gpio.dual_edge_irqs); - } - - if (flow_type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH)) - bits |= BIT(INTR_POL_CTL); - else - bits &= ~BIT(INTR_POL_CTL); - - writel(bits, GPIO_INTR_CFG(gpio)); - - if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) - msm_gpio_update_dual_edge_pos(gpio); - - spin_unlock_irqrestore(&tlmm_lock, irq_flags); - - return 0; -} - -/* - * When the summary IRQ is raised, any number of GPIO lines may be high. - * It is the job of the summary handler to find all those GPIO lines - * which have been set as summary IRQ lines and which are triggered, - * and to call their interrupt handlers. - */ -static void msm_summary_irq_handler(unsigned int irq, struct irq_desc *desc) -{ - unsigned long i; - struct irq_chip *chip = irq_desc_get_chip(desc); - - chained_irq_enter(chip, desc); - - for_each_set_bit(i, msm_gpio.enabled_irqs, MAX_NR_GPIO) { - if (readl(GPIO_INTR_STATUS(i)) & BIT(INTR_STATUS)) - generic_handle_irq(irq_find_mapping(msm_gpio.domain, - i)); - } - - chained_irq_exit(chip, desc); -} - -static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on) -{ - int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq); - - if (on) { - if (bitmap_empty(msm_gpio.wake_irqs, MAX_NR_GPIO)) - irq_set_irq_wake(msm_gpio.summary_irq, 1); - set_bit(gpio, msm_gpio.wake_irqs); - } else { - clear_bit(gpio, msm_gpio.wake_irqs); - if (bitmap_empty(msm_gpio.wake_irqs, MAX_NR_GPIO)) - irq_set_irq_wake(msm_gpio.summary_irq, 0); - } - - return 0; -} - -static struct irq_chip msm_gpio_irq_chip = { - .name = "msmgpio", - .irq_mask = msm_gpio_irq_mask, - .irq_unmask = msm_gpio_irq_unmask, - .irq_ack = msm_gpio_irq_ack, - .irq_set_type = msm_gpio_irq_set_type, - .irq_set_wake = msm_gpio_irq_set_wake, -}; - -static struct lock_class_key msm_gpio_lock_class; - -static int msm_gpio_irq_domain_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) -{ - irq_set_lockdep_class(irq, &msm_gpio_lock_class); - irq_set_chip_and_handler(irq, &msm_gpio_irq_chip, - handle_level_irq); - set_irq_flags(irq, IRQF_VALID); - - return 0; -} - -static const struct irq_domain_ops msm_gpio_irq_domain_ops = { - .xlate = irq_domain_xlate_twocell, - .map = msm_gpio_irq_domain_map, -}; - -static int msm_gpio_probe(struct platform_device *pdev) -{ - int ret, ngpio; - struct resource *res; - - if (of_property_read_u32(pdev->dev.of_node, "ngpio", &ngpio)) { - dev_err(&pdev->dev, "%s: ngpio property missing\n", __func__); - return -EINVAL; - } - - if (ngpio > MAX_NR_GPIO) - WARN(1, "ngpio exceeds the MAX_NR_GPIO. Increase MAX_NR_GPIO\n"); - - bitmap_zero(msm_gpio.enabled_irqs, MAX_NR_GPIO); - bitmap_zero(msm_gpio.wake_irqs, MAX_NR_GPIO); - bitmap_zero(msm_gpio.dual_edge_irqs, MAX_NR_GPIO); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - msm_gpio.msm_tlmm_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(msm_gpio.msm_tlmm_base)) - return PTR_ERR(msm_gpio.msm_tlmm_base); - - msm_gpio.gpio_chip.ngpio = ngpio; - msm_gpio.gpio_chip.label = pdev->name; - msm_gpio.gpio_chip.dev = &pdev->dev; - msm_gpio.gpio_chip.base = 0; - msm_gpio.gpio_chip.direction_input = msm_gpio_direction_input; - msm_gpio.gpio_chip.direction_output = msm_gpio_direction_output; - msm_gpio.gpio_chip.get = msm_gpio_get; - msm_gpio.gpio_chip.set = msm_gpio_set; - msm_gpio.gpio_chip.to_irq = msm_gpio_to_irq; - msm_gpio.gpio_chip.request = msm_gpio_request; - msm_gpio.gpio_chip.free = msm_gpio_free; - - ret = gpiochip_add(&msm_gpio.gpio_chip); - if (ret < 0) { - dev_err(&pdev->dev, "gpiochip_add failed with error %d\n", ret); - return ret; - } - - msm_gpio.summary_irq = platform_get_irq(pdev, 0); - if (msm_gpio.summary_irq < 0) { - dev_err(&pdev->dev, "No Summary irq defined for msmgpio\n"); - return msm_gpio.summary_irq; - } - - msm_gpio.domain = irq_domain_add_linear(pdev->dev.of_node, ngpio, - &msm_gpio_irq_domain_ops, - &msm_gpio); - if (!msm_gpio.domain) - return -ENODEV; - - irq_set_chained_handler(msm_gpio.summary_irq, msm_summary_irq_handler); - - return 0; -} - -static const struct of_device_id msm_gpio_of_match[] = { - { .compatible = "qcom,msm-gpio", }, - { }, -}; -MODULE_DEVICE_TABLE(of, msm_gpio_of_match); - -static int msm_gpio_remove(struct platform_device *dev) -{ - gpiochip_remove(&msm_gpio.gpio_chip); - - irq_set_handler(msm_gpio.summary_irq, NULL); - - return 0; -} - -static struct platform_driver msm_gpio_driver = { - .probe = msm_gpio_probe, - .remove = msm_gpio_remove, - .driver = { - .name = "msmgpio", - .of_match_table = msm_gpio_of_match, - }, -}; - -module_platform_driver(msm_gpio_driver) - -MODULE_AUTHOR("Gregory Bean <gbean@codeaurora.org>"); -MODULE_DESCRIPTION("Driver for Qualcomm MSM TLMMv2 SoC GPIOs"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:msmgpio"); diff --git a/kernel/drivers/gpio/gpio-mvebu.c b/kernel/drivers/gpio/gpio-mvebu.c index 1a5420586..d428b9787 100644 --- a/kernel/drivers/gpio/gpio-mvebu.c +++ b/kernel/drivers/gpio/gpio-mvebu.c @@ -185,16 +185,6 @@ static void __iomem *mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip) * Functions implementing the gpio_chip methods */ -static int mvebu_gpio_request(struct gpio_chip *chip, unsigned pin) -{ - return pinctrl_request_gpio(chip->base + pin); -} - -static void mvebu_gpio_free(struct gpio_chip *chip, unsigned pin) -{ - pinctrl_free_gpio(chip->base + pin); -} - static void mvebu_gpio_set(struct gpio_chip *chip, unsigned pin, int value) { struct mvebu_gpio_chip *mvchip = @@ -458,9 +448,9 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type) return 0; } -static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +static void mvebu_gpio_irq_handler(struct irq_desc *desc) { - struct mvebu_gpio_chip *mvchip = irq_get_handler_data(irq); + struct mvebu_gpio_chip *mvchip = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); u32 cause, type; int i; @@ -709,8 +699,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev) mvchip->soc_variant = soc_variant; mvchip->chip.label = dev_name(&pdev->dev); mvchip->chip.dev = &pdev->dev; - mvchip->chip.request = mvebu_gpio_request; - mvchip->chip.free = mvebu_gpio_free; + mvchip->chip.request = gpiochip_generic_request; + mvchip->chip.free = gpiochip_generic_free; mvchip->chip.direction_input = mvebu_gpio_direction_input; mvchip->chip.get = mvebu_gpio_get; mvchip->chip.direction_output = mvebu_gpio_direction_output; @@ -787,8 +777,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev) if (irq < 0) continue; - irq_set_handler_data(irq, mvchip); - irq_set_chained_handler(irq, mvebu_gpio_irq_handler); + irq_set_chained_handler_and_data(irq, mvebu_gpio_irq_handler, + mvchip); } mvchip->irqbase = irq_alloc_descs(-1, 0, ngpios, -1); diff --git a/kernel/drivers/gpio/gpio-mxc.c b/kernel/drivers/gpio/gpio-mxc.c index 9f7446a7a..6ea8df6c7 100644 --- a/kernel/drivers/gpio/gpio-mxc.c +++ b/kernel/drivers/gpio/gpio-mxc.c @@ -33,7 +33,7 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/module.h> -#include <asm-generic/bug.h> +#include <linux/bug.h> enum mxc_gpio_hwtype { IMX1_GPIO, /* runs on i.mx1 */ @@ -131,7 +131,7 @@ static struct mxc_gpio_hwdata *mxc_gpio_hwdata; #define GPIO_INT_FALL_EDGE (mxc_gpio_hwdata->fall_edge) #define GPIO_INT_BOTH_EDGES 0x4 -static struct platform_device_id mxc_gpio_devtype[] = { +static const struct platform_device_id mxc_gpio_devtype[] = { { .name = "imx1-gpio", .driver_data = IMX1_GPIO, @@ -272,11 +272,11 @@ static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat) } /* MX1 and MX3 has one interrupt *per* gpio port */ -static void mx3_gpio_irq_handler(u32 irq, struct irq_desc *desc) +static void mx3_gpio_irq_handler(struct irq_desc *desc) { u32 irq_stat; - struct mxc_gpio_port *port = irq_get_handler_data(irq); - struct irq_chip *chip = irq_get_chip(irq); + struct mxc_gpio_port *port = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); chained_irq_enter(chip, desc); @@ -288,11 +288,11 @@ static void mx3_gpio_irq_handler(u32 irq, struct irq_desc *desc) } /* MX2 has one interrupt *for all* gpio ports */ -static void mx2_gpio_irq_handler(u32 irq, struct irq_desc *desc) +static void mx2_gpio_irq_handler(struct irq_desc *desc) { u32 irq_msk, irq_stat; struct mxc_gpio_port *port; - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); chained_irq_enter(chip, desc); @@ -339,13 +339,15 @@ static int gpio_set_wake_irq(struct irq_data *d, u32 enable) return 0; } -static void __init mxc_gpio_init_gc(struct mxc_gpio_port *port, int irq_base) +static int mxc_gpio_init_gc(struct mxc_gpio_port *port, int irq_base) { struct irq_chip_generic *gc; struct irq_chip_type *ct; gc = irq_alloc_generic_chip("gpio-mxc", 1, irq_base, port->base, handle_level_irq); + if (!gc) + return -ENOMEM; gc->private = port; ct = gc->chip_types; @@ -354,11 +356,14 @@ static void __init mxc_gpio_init_gc(struct mxc_gpio_port *port, int irq_base) ct->chip.irq_unmask = irq_gc_mask_set_bit; ct->chip.irq_set_type = gpio_set_irq_type; ct->chip.irq_set_wake = gpio_set_wake_irq; + ct->chip.flags = IRQCHIP_MASK_ON_SUSPEND; ct->regs.ack = GPIO_ISR; ct->regs.mask = GPIO_IMR; irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0); + + return 0; } static void mxc_gpio_get_hw(struct platform_device *pdev) @@ -437,20 +442,20 @@ static int mxc_gpio_probe(struct platform_device *pdev) irq_set_chained_handler(port->irq, mx2_gpio_irq_handler); } else { /* setup one handler for each entry */ - irq_set_chained_handler(port->irq, mx3_gpio_irq_handler); - irq_set_handler_data(port->irq, port); - if (port->irq_high > 0) { + irq_set_chained_handler_and_data(port->irq, + mx3_gpio_irq_handler, port); + if (port->irq_high > 0) /* setup handler for GPIO 16 to 31 */ - irq_set_chained_handler(port->irq_high, - mx3_gpio_irq_handler); - irq_set_handler_data(port->irq_high, port); - } + irq_set_chained_handler_and_data(port->irq_high, + mx3_gpio_irq_handler, + port); } err = bgpio_init(&port->bgc, &pdev->dev, 4, port->base + GPIO_PSR, port->base + GPIO_DR, NULL, - port->base + GPIO_GDIR, NULL, 0); + port->base + GPIO_GDIR, NULL, + BGPIOF_READ_OUTPUT_REG_SET); if (err) goto out_bgio; @@ -476,12 +481,16 @@ static int mxc_gpio_probe(struct platform_device *pdev) } /* gpio-mxc can be a generic irq chip */ - mxc_gpio_init_gc(port, irq_base); + err = mxc_gpio_init_gc(port, irq_base); + if (err < 0) + goto out_irqdomain_remove; list_add_tail(&port->node, &mxc_gpio_ports); return 0; +out_irqdomain_remove: + irq_domain_remove(port->domain); out_irqdesc_free: irq_free_descs(irq_base, 32); out_gpiochip_remove: diff --git a/kernel/drivers/gpio/gpio-mxs.c b/kernel/drivers/gpio/gpio-mxs.c index 84cbda6ac..a4288f428 100644 --- a/kernel/drivers/gpio/gpio-mxs.c +++ b/kernel/drivers/gpio/gpio-mxs.c @@ -154,10 +154,10 @@ static void mxs_flip_edge(struct mxs_gpio_port *port, u32 gpio) } /* MXS has one interrupt *per* gpio port */ -static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc) +static void mxs_gpio_irq_handler(struct irq_desc *desc) { u32 irq_stat; - struct mxs_gpio_port *port = irq_get_handler_data(irq); + struct mxs_gpio_port *port = irq_desc_get_handler_data(desc); desc->irq_data.chip->irq_ack(&desc->irq_data); @@ -196,13 +196,16 @@ static int mxs_gpio_set_wake_irq(struct irq_data *d, unsigned int enable) return 0; } -static void __init mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base) +static int __init mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base) { struct irq_chip_generic *gc; struct irq_chip_type *ct; gc = irq_alloc_generic_chip("gpio-mxs", 1, irq_base, port->base, handle_level_irq); + if (!gc) + return -ENOMEM; + gc->private = port; ct = gc->chip_types; @@ -216,6 +219,8 @@ static void __init mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base) irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0); + + return 0; } static int mxs_gpio_to_irq(struct gpio_chip *gc, unsigned offset) @@ -239,7 +244,7 @@ static int mxs_gpio_get_direction(struct gpio_chip *gc, unsigned offset) return !(dir & mask); } -static struct platform_device_id mxs_gpio_ids[] = { +static const struct platform_device_id mxs_gpio_ids[] = { { .name = "imx23-gpio", .driver_data = IMX23_GPIO, @@ -317,11 +322,13 @@ static int mxs_gpio_probe(struct platform_device *pdev) } /* gpio-mxs can be a generic irq chip */ - mxs_gpio_init_gc(port, irq_base); + err = mxs_gpio_init_gc(port, irq_base); + if (err < 0) + goto out_irqdomain_remove; /* setup one handler for each entry */ - irq_set_chained_handler(port->irq, mxs_gpio_irq_handler); - irq_set_handler_data(port->irq, port); + irq_set_chained_handler_and_data(port->irq, mxs_gpio_irq_handler, + port); err = bgpio_init(&port->bgc, &pdev->dev, 4, port->base + PINCTRL_DIN(port), @@ -343,6 +350,8 @@ static int mxs_gpio_probe(struct platform_device *pdev) out_bgpio_remove: bgpio_remove(&port->bgc); +out_irqdomain_remove: + irq_domain_remove(port->domain); out_irqdesc_free: irq_free_descs(irq_base, 32); return err; diff --git a/kernel/drivers/gpio/gpio-omap.c b/kernel/drivers/gpio/gpio-omap.c index a0ace2758..f7fbb46d5 100644 --- a/kernel/drivers/gpio/gpio-omap.c +++ b/kernel/drivers/gpio/gpio-omap.c @@ -29,6 +29,7 @@ #include <linux/platform_data/gpio-omap.h> #define OFF_MODE 1 +#define OMAP4_GPIO_DEBOUNCINGTIME_MASK 0xFF static LIST_HEAD(omap_gpio_list); @@ -50,7 +51,7 @@ struct gpio_regs { struct gpio_bank { struct list_head node; void __iomem *base; - u16 irq; + int irq; u32 non_wakeup_gpios; u32 enabled_non_wakeup_gpios; struct gpio_regs context; @@ -58,6 +59,7 @@ struct gpio_bank { u32 level_mask; u32 toggle_mask; raw_spinlock_t lock; + raw_spinlock_t wa_lock; struct gpio_chip chip; struct clk *dbck; u32 mod_usage; @@ -175,7 +177,7 @@ static inline void omap_gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set static inline void omap_gpio_dbck_enable(struct gpio_bank *bank) { if (bank->dbck_enable_mask && !bank->dbck_enabled) { - clk_prepare_enable(bank->dbck); + clk_enable(bank->dbck); bank->dbck_enabled = true; writel_relaxed(bank->dbck_enable_mask, @@ -193,7 +195,7 @@ static inline void omap_gpio_dbck_disable(struct gpio_bank *bank) */ writel_relaxed(0, bank->base + bank->regs->debounce_en); - clk_disable_unprepare(bank->dbck); + clk_disable(bank->dbck); bank->dbck_enabled = false; } } @@ -204,8 +206,9 @@ static inline void omap_gpio_dbck_disable(struct gpio_bank *bank) * @offset: the gpio number on this @bank * @debounce: debounce time to use * - * OMAP's debounce time is in 31us steps so we need - * to convert and round up to the closest unit. + * OMAP's debounce time is in 31us steps + * <debounce time> = (GPIO_DEBOUNCINGTIME[7:0].DEBOUNCETIME + 1) x 31 + * so we need to convert and round up to the closest unit. */ static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, unsigned debounce) @@ -213,34 +216,33 @@ static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, void __iomem *reg; u32 val; u32 l; + bool enable = !!debounce; if (!bank->dbck_flag) return; - if (debounce < 32) - debounce = 0x01; - else if (debounce > 7936) - debounce = 0xff; - else - debounce = (debounce / 0x1f) - 1; + if (enable) { + debounce = DIV_ROUND_UP(debounce, 31) - 1; + debounce &= OMAP4_GPIO_DEBOUNCINGTIME_MASK; + } l = BIT(offset); - clk_prepare_enable(bank->dbck); + clk_enable(bank->dbck); reg = bank->base + bank->regs->debounce; writel_relaxed(debounce, reg); reg = bank->base + bank->regs->debounce_en; val = readl_relaxed(reg); - if (debounce) + if (enable) val |= l; else val &= ~l; bank->dbck_enable_mask = val; writel_relaxed(val, reg); - clk_disable_unprepare(bank->dbck); + clk_disable(bank->dbck); /* * Enable debounce clock per module. * This call is mandatory because in omap_gpio_request() when @@ -285,7 +287,7 @@ static void omap_clear_gpio_debounce(struct gpio_bank *bank, unsigned offset) bank->context.debounce = 0; writel_relaxed(bank->context.debounce, bank->base + bank->regs->debounce); - clk_disable_unprepare(bank->dbck); + clk_disable(bank->dbck); bank->dbck_enabled = false; } } @@ -488,9 +490,6 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type) unsigned long flags; unsigned offset = d->hwirq; - if (!BANK_USED(bank)) - pm_runtime_get_sync(bank->dev); - if (type & ~IRQ_TYPE_SENSE_MASK) return -EINVAL; @@ -500,18 +499,26 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type) raw_spin_lock_irqsave(&bank->lock, flags); retval = omap_set_gpio_triggering(bank, offset, type); + if (retval) { + raw_spin_unlock_irqrestore(&bank->lock, flags); + goto error; + } omap_gpio_init_irq(bank, offset); if (!omap_gpio_is_input(bank, offset)) { raw_spin_unlock_irqrestore(&bank->lock, flags); - return -EINVAL; + retval = -EINVAL; + goto error; } raw_spin_unlock_irqrestore(&bank->lock, flags); if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); + + return 0; +error: return retval; } @@ -638,22 +645,18 @@ static int omap_set_gpio_wakeup(struct gpio_bank *bank, unsigned offset, return 0; } -static void omap_reset_gpio(struct gpio_bank *bank, unsigned offset) -{ - omap_set_gpio_direction(bank, offset, 1); - omap_set_gpio_irqenable(bank, offset, 0); - omap_clear_gpio_irqstatus(bank, offset); - omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); - omap_clear_gpio_debounce(bank, offset); -} - /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */ static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable) { struct gpio_bank *bank = omap_irq_data_get_bank(d); unsigned offset = d->hwirq; + int ret; + + ret = omap_set_gpio_wakeup(bank, offset, enable); + if (!ret) + ret = irq_set_irq_wake(bank->irq, enable); - return omap_set_gpio_wakeup(bank, offset, enable); + return ret; } static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) @@ -669,14 +672,7 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) pm_runtime_get_sync(bank->dev); raw_spin_lock_irqsave(&bank->lock, flags); - /* Set trigger to none. You need to enable the desired trigger with - * request_irq() or set_irq_type(). Only do this if the IRQ line has - * not already been requested. - */ - if (!LINE_USED(bank->irq_usage, offset)) { - omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); - omap_enable_gpio_module(bank, offset); - } + omap_enable_gpio_module(bank, offset); bank->mod_usage |= BIT(offset); raw_spin_unlock_irqrestore(&bank->lock, flags); @@ -690,8 +686,11 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) raw_spin_lock_irqsave(&bank->lock, flags); bank->mod_usage &= ~(BIT(offset)); + if (!LINE_USED(bank->irq_usage, offset)) { + omap_set_gpio_direction(bank, offset, 1); + omap_clear_gpio_debounce(bank, offset); + } omap_disable_gpio_module(bank, offset); - omap_reset_gpio(bank, offset); raw_spin_unlock_irqrestore(&bank->lock, flags); /* @@ -711,29 +710,27 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) * line's interrupt handler has been run, we may miss some nested * interrupts. */ -static void omap_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank) { void __iomem *isr_reg = NULL; u32 isr; unsigned int bit; - struct gpio_bank *bank; - int unmasked = 0; - struct irq_chip *irqchip = irq_desc_get_chip(desc); - struct gpio_chip *chip = irq_get_handler_data(irq); + struct gpio_bank *bank = gpiobank; + unsigned long wa_lock_flags; + unsigned long lock_flags; - chained_irq_enter(irqchip, desc); - - bank = container_of(chip, struct gpio_bank, chip); isr_reg = bank->base + bank->regs->irqstatus; - pm_runtime_get_sync(bank->dev); - if (WARN_ON(!isr_reg)) goto exit; + pm_runtime_get_sync(bank->dev); + while (1) { u32 isr_saved, level_mask = 0; u32 enabled; + raw_spin_lock_irqsave(&bank->lock, lock_flags); + enabled = omap_get_gpio_irqbank_mask(bank); isr_saved = isr = readl_relaxed(isr_reg) & enabled; @@ -747,12 +744,7 @@ static void omap_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) omap_clear_gpio_irqbank(bank, isr_saved & ~level_mask); omap_enable_gpio_irqbank(bank, isr_saved & ~level_mask); - /* if there is only edge sensitive GPIO pin interrupts - configured, we could unmask GPIO bank interrupt immediately */ - if (!level_mask && !unmasked) { - unmasked = 1; - chained_irq_exit(irqchip, desc); - } + raw_spin_unlock_irqrestore(&bank->lock, lock_flags); if (!isr) break; @@ -761,6 +753,7 @@ static void omap_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) bit = __ffs(isr); isr &= ~(BIT(bit)); + raw_spin_lock_irqsave(&bank->lock, lock_flags); /* * Some chips can't respond to both rising and falling * at the same time. If this irq was requested with @@ -771,18 +764,20 @@ static void omap_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) if (bank->toggle_mask & (BIT(bit))) omap_toggle_gpio_edge_triggering(bank, bit); + raw_spin_unlock_irqrestore(&bank->lock, lock_flags); + + raw_spin_lock_irqsave(&bank->wa_lock, wa_lock_flags); + generic_handle_irq(irq_find_mapping(bank->chip.irqdomain, bit)); + + raw_spin_unlock_irqrestore(&bank->wa_lock, + wa_lock_flags); } } - /* if bank has any level sensitive GPIO pin interrupt - configured, we must unmask the bank interrupt only after - handler(s) are executed in order to avoid spurious bank - interrupt */ exit: - if (!unmasked) - chained_irq_exit(irqchip, desc); pm_runtime_put(bank->dev); + return IRQ_HANDLED; } static unsigned int omap_gpio_irq_startup(struct irq_data *d) @@ -791,15 +786,22 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d) unsigned long flags; unsigned offset = d->hwirq; - if (!BANK_USED(bank)) - pm_runtime_get_sync(bank->dev); - raw_spin_lock_irqsave(&bank->lock, flags); - omap_gpio_init_irq(bank, offset); + + if (!LINE_USED(bank->mod_usage, offset)) + omap_set_gpio_direction(bank, offset, 1); + else if (!omap_gpio_is_input(bank, offset)) + goto err; + omap_enable_gpio_module(bank, offset); + bank->irq_usage |= BIT(offset); + raw_spin_unlock_irqrestore(&bank->lock, flags); omap_gpio_unmask_irq(d); return 0; +err: + raw_spin_unlock_irqrestore(&bank->lock, flags); + return -EINVAL; } static void omap_gpio_irq_shutdown(struct irq_data *d) @@ -810,9 +812,26 @@ static void omap_gpio_irq_shutdown(struct irq_data *d) raw_spin_lock_irqsave(&bank->lock, flags); bank->irq_usage &= ~(BIT(offset)); + omap_set_gpio_irqenable(bank, offset, 0); + omap_clear_gpio_irqstatus(bank, offset); + omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); + if (!LINE_USED(bank->mod_usage, offset)) + omap_clear_gpio_debounce(bank, offset); omap_disable_gpio_module(bank, offset); - omap_reset_gpio(bank, offset); raw_spin_unlock_irqrestore(&bank->lock, flags); +} + +static void omap_gpio_irq_bus_lock(struct irq_data *data) +{ + struct gpio_bank *bank = omap_irq_data_get_bank(data); + + if (!BANK_USED(bank)) + pm_runtime_get_sync(bank->dev); +} + +static void gpio_irq_bus_sync_unlock(struct irq_data *data) +{ + struct gpio_bank *bank = omap_irq_data_get_bank(data); /* * If this is the last IRQ to be freed in the bank, @@ -1048,10 +1067,6 @@ static void omap_gpio_mod_init(struct gpio_bank *bank) /* Initialize interface clk ungated, module enabled */ if (bank->regs->ctrl) writel_relaxed(0, base + bank->regs->ctrl); - - bank->dbck = clk_get(bank->dev, "dbclk"); - if (IS_ERR(bank->dbck)) - dev_err(bank->dev, "Could not get gpio dbck\n"); } static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) @@ -1080,7 +1095,6 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) } else { bank->chip.label = "gpio"; bank->chip.base = gpio; - gpio += bank->width; } bank->chip.ngpio = bank->width; @@ -1090,6 +1104,9 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) return ret; } + if (!bank->is_mpuio) + gpio += bank->width; + #ifdef CONFIG_ARCH_OMAP1 /* * REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop @@ -1105,14 +1122,12 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) /* MPUIO is a bit different, reading IRQ status clears it */ if (bank->is_mpuio) { irqc->irq_ack = dummy_irq_chip.irq_ack; - irqc->irq_mask = irq_gc_mask_set_bit; - irqc->irq_unmask = irq_gc_mask_clr_bit; if (!bank->regs->wkup_en) irqc->irq_set_wake = NULL; } ret = gpiochip_irqchip_add(&bank->chip, irqc, - irq_base, omap_gpio_irq_handler, + irq_base, handle_bad_irq, IRQ_TYPE_NONE); if (ret) { @@ -1121,10 +1136,14 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) return -ENODEV; } - gpiochip_set_chained_irqchip(&bank->chip, irqc, - bank->irq, omap_gpio_irq_handler); + gpiochip_set_chained_irqchip(&bank->chip, irqc, bank->irq, NULL); - return 0; + ret = devm_request_irq(bank->dev, bank->irq, omap_gpio_irq_handler, + 0, dev_name(bank->dev), bank); + if (ret) + gpiochip_remove(&bank->chip); + + return ret; } static const struct of_device_id omap_gpio_match[]; @@ -1163,17 +1182,23 @@ static int omap_gpio_probe(struct platform_device *pdev) irqc->irq_unmask = omap_gpio_unmask_irq, irqc->irq_set_type = omap_gpio_irq_type, irqc->irq_set_wake = omap_gpio_wake_enable, + irqc->irq_bus_lock = omap_gpio_irq_bus_lock, + irqc->irq_bus_sync_unlock = gpio_irq_bus_sync_unlock, irqc->name = dev_name(&pdev->dev); - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (unlikely(!res)) { - dev_err(dev, "Invalid IRQ resource\n"); - return -ENODEV; + bank->irq = platform_get_irq(pdev, 0); + if (bank->irq <= 0) { + if (!bank->irq) + bank->irq = -ENXIO; + if (bank->irq != -EPROBE_DEFER) + dev_err(dev, + "can't get irq resource ret=%d\n", bank->irq); + return bank->irq; } - bank->irq = res->start; bank->dev = dev; bank->chip.dev = dev; + bank->chip.owner = THIS_MODULE; bank->dbck_flag = pdata->dbck_flag; bank->stride = pdata->bank_stride; bank->width = pdata->bank_width; @@ -1200,15 +1225,26 @@ static int omap_gpio_probe(struct platform_device *pdev) bank->set_dataout = omap_set_gpio_dataout_mask; raw_spin_lock_init(&bank->lock); + raw_spin_lock_init(&bank->wa_lock); /* Static mapping, never released */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); bank->base = devm_ioremap_resource(dev, res); if (IS_ERR(bank->base)) { - irq_domain_remove(bank->chip.irqdomain); return PTR_ERR(bank->base); } + if (bank->dbck_flag) { + bank->dbck = devm_clk_get(bank->dev, "dbclk"); + if (IS_ERR(bank->dbck)) { + dev_err(bank->dev, + "Could not get gpio dbck. Disable debounce\n"); + bank->dbck_flag = false; + } else { + clk_prepare(bank->dbck); + } + } + platform_set_drvdata(pdev, bank); pm_runtime_enable(bank->dev); @@ -1221,8 +1257,11 @@ static int omap_gpio_probe(struct platform_device *pdev) omap_gpio_mod_init(bank); ret = omap_gpio_chip_init(bank, irqc); - if (ret) + if (ret) { + pm_runtime_put_sync(bank->dev); + pm_runtime_disable(bank->dev); return ret; + } omap_gpio_show_rev(bank); @@ -1233,6 +1272,19 @@ static int omap_gpio_probe(struct platform_device *pdev) return 0; } +static int omap_gpio_remove(struct platform_device *pdev) +{ + struct gpio_bank *bank = platform_get_drvdata(pdev); + + list_del(&bank->node); + gpiochip_remove(&bank->chip); + pm_runtime_disable(bank->dev); + if (bank->dbck_flag) + clk_unprepare(bank->dbck); + + return 0; +} + #ifdef CONFIG_ARCH_OMAP2PLUS #if defined(CONFIG_PM) @@ -1418,6 +1470,7 @@ static int omap_gpio_runtime_resume(struct device *dev) } #endif /* CONFIG_PM */ +#if IS_BUILTIN(CONFIG_GPIO_OMAP) void omap2_gpio_prepare_for_idle(int pwr_mode) { struct gpio_bank *bank; @@ -1443,6 +1496,7 @@ void omap2_gpio_resume_after_idle(void) pm_runtime_get_sync(bank->dev); } } +#endif #if defined(CONFIG_PM) static void omap_gpio_init_context(struct gpio_bank *p) @@ -1598,6 +1652,7 @@ MODULE_DEVICE_TABLE(of, omap_gpio_match); static struct platform_driver omap_gpio_driver = { .probe = omap_gpio_probe, + .remove = omap_gpio_remove, .driver = { .name = "omap_gpio", .pm = &gpio_pm_ops, @@ -1615,3 +1670,13 @@ static int __init omap_gpio_drv_reg(void) return platform_driver_register(&omap_gpio_driver); } postcore_initcall(omap_gpio_drv_reg); + +static void __exit omap_gpio_exit(void) +{ + platform_driver_unregister(&omap_gpio_driver); +} +module_exit(omap_gpio_exit); + +MODULE_DESCRIPTION("omap gpio driver"); +MODULE_ALIAS("platform:gpio-omap"); +MODULE_LICENSE("GPL v2"); diff --git a/kernel/drivers/gpio/gpio-palmas.c b/kernel/drivers/gpio/gpio-palmas.c index 171a6389f..52b447c07 100644 --- a/kernel/drivers/gpio/gpio-palmas.c +++ b/kernel/drivers/gpio/gpio-palmas.c @@ -167,6 +167,8 @@ static int palmas_gpio_probe(struct platform_device *pdev) const struct palmas_device_data *dev_data; match = of_match_device(of_palmas_gpio_match, &pdev->dev); + if (!match) + return -ENODEV; dev_data = match->data; if (!dev_data) dev_data = &palmas_dev_data; diff --git a/kernel/drivers/gpio/gpio-pca953x.c b/kernel/drivers/gpio/gpio-pca953x.c index e2da64abb..2d4892cc7 100644 --- a/kernel/drivers/gpio/gpio-pca953x.c +++ b/kernel/drivers/gpio/gpio-pca953x.c @@ -21,6 +21,7 @@ #ifdef CONFIG_OF_GPIO #include <linux/of_platform.h> #endif +#include <linux/acpi.h> #define PCA953X_INPUT 0 #define PCA953X_OUTPUT 1 @@ -42,6 +43,9 @@ #define PCA_INT 0x0100 #define PCA953X_TYPE 0x1000 #define PCA957X_TYPE 0x2000 +#define PCA_TYPE_MASK 0xF000 + +#define PCA_CHIP_TYPE(x) ((x) & PCA_TYPE_MASK) static const struct i2c_device_id pca953x_id[] = { { "pca9505", 40 | PCA953X_TYPE | PCA_INT, }, @@ -67,11 +71,18 @@ static const struct i2c_device_id pca953x_id[] = { { "tca6408", 8 | PCA953X_TYPE | PCA_INT, }, { "tca6416", 16 | PCA953X_TYPE | PCA_INT, }, { "tca6424", 24 | PCA953X_TYPE | PCA_INT, }, + { "tca9539", 16 | PCA953X_TYPE | PCA_INT, }, { "xra1202", 8 | PCA953X_TYPE }, { } }; MODULE_DEVICE_TABLE(i2c, pca953x_id); +static const struct acpi_device_id pca953x_acpi_ids[] = { + { "INT3491", 16 | PCA953X_TYPE | PCA_INT, }, + { } +}; +MODULE_DEVICE_TABLE(acpi, pca953x_acpi_ids); + #define MAX_BANK 5 #define BANK_SZ 8 @@ -95,6 +106,7 @@ struct pca953x_chip { struct gpio_chip gpio_chip; const char *const *names; int chip_type; + unsigned long driver_data; }; static inline struct pca953x_chip *to_pca(struct gpio_chip *gc) @@ -443,12 +455,13 @@ static struct irq_chip pca953x_irq_chip = { .irq_set_type = pca953x_irq_set_type, }; -static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending) +static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending) { u8 cur_stat[MAX_BANK]; u8 old_stat[MAX_BANK]; - u8 pendings = 0; - u8 trigger[MAX_BANK], triggers = 0; + bool pending_seen = false; + bool trigger_seen = false; + u8 trigger[MAX_BANK]; int ret, i, offset = 0; switch (chip->chip_type) { @@ -461,7 +474,7 @@ static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending) } ret = pca953x_read_regs(chip, offset, cur_stat); if (ret) - return 0; + return false; /* Remove output pins from the equation */ for (i = 0; i < NBANK(chip); i++) @@ -471,11 +484,12 @@ static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending) for (i = 0; i < NBANK(chip); i++) { trigger[i] = (cur_stat[i] ^ old_stat[i]) & chip->irq_mask[i]; - triggers += trigger[i]; + if (trigger[i]) + trigger_seen = true; } - if (!triggers) - return 0; + if (!trigger_seen) + return false; memcpy(chip->irq_stat, cur_stat, NBANK(chip)); @@ -483,10 +497,11 @@ static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending) pending[i] = (old_stat[i] & chip->irq_trig_fall[i]) | (cur_stat[i] & chip->irq_trig_raise[i]); pending[i] &= trigger[i]; - pendings += pending[i]; + if (pending[i]) + pending_seen = true; } - return pendings; + return pending_seen; } static irqreturn_t pca953x_irq_handler(int irq, void *devid) @@ -514,14 +529,13 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid) } static int pca953x_irq_setup(struct pca953x_chip *chip, - const struct i2c_device_id *id, int irq_base) { struct i2c_client *client = chip->client; int ret, i, offset = 0; if (client->irq && irq_base != -1 - && (id->driver_data & PCA_INT)) { + && (chip->driver_data & PCA_INT)) { switch (chip->chip_type) { case PCA953X_TYPE: @@ -567,6 +581,10 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, "could not connect irqchip to gpiochip\n"); return ret; } + + gpiochip_set_chained_irqchip(&chip->gpio_chip, + &pca953x_irq_chip, + client->irq, NULL); } return 0; @@ -574,12 +592,11 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, #else /* CONFIG_GPIO_PCA953X_IRQ */ static int pca953x_irq_setup(struct pca953x_chip *chip, - const struct i2c_device_id *id, int irq_base) { struct i2c_client *client = chip->client; - if (irq_base != -1 && (id->driver_data & PCA_INT)) + if (irq_base != -1 && (chip->driver_data & PCA_INT)) dev_warn(&client->dev, "interrupt support not compiled in\n"); return 0; @@ -628,11 +645,15 @@ static int device_pca957x_init(struct pca953x_chip *chip, u32 invert) memset(val, 0xFF, NBANK(chip)); else memset(val, 0, NBANK(chip)); - pca953x_write_regs(chip, PCA957X_INVRT, val); + ret = pca953x_write_regs(chip, PCA957X_INVRT, val); + if (ret) + goto out; - /* To enable register 6, 7 to controll pull up and pull down */ + /* To enable register 6, 7 to control pull up and pull down */ memset(val, 0x02, NBANK(chip)); - pca953x_write_regs(chip, PCA957X_BKEN, val); + ret = pca953x_write_regs(chip, PCA957X_BKEN, val); + if (ret) + goto out; return 0; out: @@ -666,14 +687,26 @@ static int pca953x_probe(struct i2c_client *client, chip->client = client; - chip->chip_type = id->driver_data & (PCA953X_TYPE | PCA957X_TYPE); + if (id) { + chip->driver_data = id->driver_data; + } else { + const struct acpi_device_id *id; + + id = acpi_match_device(pca953x_acpi_ids, &client->dev); + if (!id) + return -ENODEV; + + chip->driver_data = id->driver_data; + } + + chip->chip_type = PCA_CHIP_TYPE(chip->driver_data); mutex_init(&chip->i2c_lock); /* initialize cached registers from their original values. * we can't share this chip with another i2c master. */ - pca953x_setup_gpio(chip, id->driver_data & PCA_GPIO_MASK); + pca953x_setup_gpio(chip, chip->driver_data & PCA_GPIO_MASK); if (chip->chip_type == PCA953X_TYPE) ret = device_pca953x_init(chip, invert); @@ -686,7 +719,7 @@ static int pca953x_probe(struct i2c_client *client, if (ret) return ret; - ret = pca953x_irq_setup(chip, id, irq_base); + ret = pca953x_irq_setup(chip, irq_base); if (ret) return ret; @@ -758,6 +791,7 @@ static struct i2c_driver pca953x_driver = { .driver = { .name = "pca953x", .of_match_table = pca953x_dt_ids, + .acpi_match_table = ACPI_PTR(pca953x_acpi_ids), }, .probe = pca953x_probe, .remove = pca953x_remove, diff --git a/kernel/drivers/gpio/gpio-pcf857x.c b/kernel/drivers/gpio/gpio-pcf857x.c index 945f0cda8..1d4d9bc8b 100644 --- a/kernel/drivers/gpio/gpio-pcf857x.c +++ b/kernel/drivers/gpio/gpio-pcf857x.c @@ -88,9 +88,10 @@ struct pcf857x { struct gpio_chip chip; struct i2c_client *client; struct mutex lock; /* protect 'out' */ - spinlock_t slock; /* protect irq demux */ unsigned out; /* software latch */ unsigned status; /* current status */ + unsigned int irq_parent; + unsigned irq_enabled; /* enabled irqs */ int (*write)(struct i2c_client *client, unsigned data); int (*read)(struct i2c_client *client); @@ -183,23 +184,21 @@ static void pcf857x_set(struct gpio_chip *chip, unsigned offset, int value) static irqreturn_t pcf857x_irq(int irq, void *data) { struct pcf857x *gpio = data; - unsigned long change, i, status, flags; + unsigned long change, i, status; status = gpio->read(gpio->client); - spin_lock_irqsave(&gpio->slock, flags); - /* * call the interrupt handler iff gpio is used as * interrupt source, just to avoid bad irqs */ + mutex_lock(&gpio->lock); + change = (gpio->status ^ status) & gpio->irq_enabled; + gpio->status = status; + mutex_unlock(&gpio->lock); - change = (gpio->status ^ status); for_each_set_bit(i, &change, gpio->chip.ngpio) handle_nested_irq(irq_find_mapping(gpio->chip.irqdomain, i)); - gpio->status = status; - - spin_unlock_irqrestore(&gpio->slock, flags); return IRQ_HANDLED; } @@ -209,29 +208,62 @@ static irqreturn_t pcf857x_irq(int irq, void *data) */ static void noop(struct irq_data *data) { } -static unsigned int noop_ret(struct irq_data *data) +static int pcf857x_irq_set_wake(struct irq_data *data, unsigned int on) { - return 0; + struct pcf857x *gpio = irq_data_get_irq_chip_data(data); + + int error = 0; + + if (gpio->irq_parent) { + error = irq_set_irq_wake(gpio->irq_parent, on); + if (error) { + dev_dbg(&gpio->client->dev, + "irq %u doesn't support irq_set_wake\n", + gpio->irq_parent); + gpio->irq_parent = 0; + } + } + return error; } -static int pcf857x_irq_set_wake(struct irq_data *data, unsigned int on) +static void pcf857x_irq_enable(struct irq_data *data) { struct pcf857x *gpio = irq_data_get_irq_chip_data(data); - irq_set_irq_wake(gpio->client->irq, on); - return 0; + gpio->irq_enabled |= (1 << data->hwirq); +} + +static void pcf857x_irq_disable(struct irq_data *data) +{ + struct pcf857x *gpio = irq_data_get_irq_chip_data(data); + + gpio->irq_enabled &= ~(1 << data->hwirq); +} + +static void pcf857x_irq_bus_lock(struct irq_data *data) +{ + struct pcf857x *gpio = irq_data_get_irq_chip_data(data); + + mutex_lock(&gpio->lock); +} + +static void pcf857x_irq_bus_sync_unlock(struct irq_data *data) +{ + struct pcf857x *gpio = irq_data_get_irq_chip_data(data); + + mutex_unlock(&gpio->lock); } static struct irq_chip pcf857x_irq_chip = { .name = "pcf857x", - .irq_startup = noop_ret, - .irq_shutdown = noop, - .irq_enable = noop, - .irq_disable = noop, + .irq_enable = pcf857x_irq_enable, + .irq_disable = pcf857x_irq_disable, .irq_ack = noop, .irq_mask = noop, .irq_unmask = noop, .irq_set_wake = pcf857x_irq_set_wake, + .irq_bus_lock = pcf857x_irq_bus_lock, + .irq_bus_sync_unlock = pcf857x_irq_bus_sync_unlock, }; /*-------------------------------------------------------------------------*/ @@ -258,7 +290,6 @@ static int pcf857x_probe(struct i2c_client *client, return -ENOMEM; mutex_init(&gpio->lock); - spin_lock_init(&gpio->slock); gpio->chip.base = pdata ? pdata->gpio_base : -1; gpio->chip.can_sleep = true; @@ -364,6 +395,7 @@ static int pcf857x_probe(struct i2c_client *client, gpiochip_set_chained_irqchip(&gpio->chip, &pcf857x_irq_chip, client->irq, NULL); + gpio->irq_parent = client->irq; } /* Let platform code set up the GPIOs and their users. diff --git a/kernel/drivers/gpio/gpio-pch.c b/kernel/drivers/gpio/gpio-pch.c index 2d9a950ca..34ed176df 100644 --- a/kernel/drivers/gpio/gpio-pch.c +++ b/kernel/drivers/gpio/gpio-pch.c @@ -281,9 +281,9 @@ static int pch_irq_type(struct irq_data *d, unsigned int type) /* And the handler */ if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); unlock: spin_unlock_irqrestore(&chip->spinlock, flags); diff --git a/kernel/drivers/gpio/gpio-pl061.c b/kernel/drivers/gpio/gpio-pl061.c index 047561304..4d4b37676 100644 --- a/kernel/drivers/gpio/gpio-pl061.c +++ b/kernel/drivers/gpio/gpio-pl061.c @@ -52,36 +52,12 @@ struct pl061_gpio { void __iomem *base; struct gpio_chip gc; - bool uses_pinctrl; #ifdef CONFIG_PM struct pl061_context_save_regs csave_regs; #endif }; -static int pl061_gpio_request(struct gpio_chip *gc, unsigned offset) -{ - /* - * Map back to global GPIO space and request muxing, the direction - * parameter does not matter for this controller. - */ - struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); - int gpio = gc->base + offset; - - if (chip->uses_pinctrl) - return pinctrl_request_gpio(gpio); - return 0; -} - -static void pl061_gpio_free(struct gpio_chip *gc, unsigned offset) -{ - struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); - int gpio = gc->base + offset; - - if (chip->uses_pinctrl) - pinctrl_free_gpio(gpio); -} - static int pl061_direction_input(struct gpio_chip *gc, unsigned offset) { struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); @@ -152,6 +128,17 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger) if (offset < 0 || offset >= PL061_GPIO_NR) return -EINVAL; + if ((trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) && + (trigger & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))) + { + dev_err(gc->dev, + "trying to configure line %d for both level and edge " + "detection, choose one!\n", + offset); + return -EINVAL; + } + + spin_lock_irqsave(&chip->lock, flags); gpioiev = readb(chip->base + GPIOIEV); @@ -159,23 +146,53 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger) gpioibe = readb(chip->base + GPIOIBE); if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { + bool polarity = trigger & IRQ_TYPE_LEVEL_HIGH; + + /* Disable edge detection */ + gpioibe &= ~bit; + /* Enable level detection */ gpiois |= bit; - if (trigger & IRQ_TYPE_LEVEL_HIGH) + /* Select polarity */ + if (polarity) gpioiev |= bit; else gpioiev &= ~bit; - } else + irq_set_handler_locked(d, handle_level_irq); + dev_dbg(gc->dev, "line %d: IRQ on %s level\n", + offset, + polarity ? "HIGH" : "LOW"); + } else if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) { + /* Disable level detection */ gpiois &= ~bit; - - if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) - /* Setting this makes GPIOEV be ignored */ + /* Select both edges, setting this makes GPIOEV be ignored */ gpioibe |= bit; - else { + irq_set_handler_locked(d, handle_edge_irq); + dev_dbg(gc->dev, "line %d: IRQ on both edges\n", offset); + } else if ((trigger & IRQ_TYPE_EDGE_RISING) || + (trigger & IRQ_TYPE_EDGE_FALLING)) { + bool rising = trigger & IRQ_TYPE_EDGE_RISING; + + /* Disable level detection */ + gpiois &= ~bit; + /* Clear detection on both edges */ gpioibe &= ~bit; - if (trigger & IRQ_TYPE_EDGE_RISING) + /* Select edge */ + if (rising) gpioiev |= bit; - else if (trigger & IRQ_TYPE_EDGE_FALLING) + else gpioiev &= ~bit; + irq_set_handler_locked(d, handle_edge_irq); + dev_dbg(gc->dev, "line %d: IRQ on %s edge\n", + offset, + rising ? "RISING" : "FALLING"); + } else { + /* No trigger: disable everything */ + gpiois &= ~bit; + gpioibe &= ~bit; + gpioiev &= ~bit; + irq_set_handler_locked(d, handle_bad_irq); + dev_warn(gc->dev, "no trigger selected for line %d\n", + offset); } writeb(gpiois, chip->base + GPIOIS); @@ -187,7 +204,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger) return 0; } -static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) +static void pl061_irq_handler(struct irq_desc *desc) { unsigned long pending; int offset; @@ -198,7 +215,6 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) chained_irq_enter(irqchip, desc); pending = readb(chip->base + GPIOMIS); - writeb(pending, chip->base + GPIOIC); if (pending) { for_each_set_bit(offset, &pending, PL061_GPIO_NR) generic_handle_irq(irq_find_mapping(gc->irqdomain, @@ -234,8 +250,28 @@ static void pl061_irq_unmask(struct irq_data *d) spin_unlock(&chip->lock); } +/** + * pl061_irq_ack() - ACK an edge IRQ + * @d: IRQ data for this IRQ + * + * This gets called from the edge IRQ handler to ACK the edge IRQ + * in the GPIOIC (interrupt-clear) register. For level IRQs this is + * not needed: these go away when the level signal goes away. + */ +static void pl061_irq_ack(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); + u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); + + spin_lock(&chip->lock); + writeb(mask, chip->base + GPIOIC); + spin_unlock(&chip->lock); +} + static struct irq_chip pl061_irqchip = { .name = "pl061", + .irq_ack = pl061_irq_ack, .irq_mask = pl061_irq_mask, .irq_unmask = pl061_irq_unmask, .irq_set_type = pl061_irq_type, @@ -269,11 +305,11 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) return PTR_ERR(chip->base); spin_lock_init(&chip->lock); - if (of_property_read_bool(dev->of_node, "gpio-ranges")) - chip->uses_pinctrl = true; + if (of_property_read_bool(dev->of_node, "gpio-ranges")) { + chip->gc.request = gpiochip_generic_request; + chip->gc.free = gpiochip_generic_free; + } - chip->gc.request = pl061_gpio_request; - chip->gc.free = pl061_gpio_free; chip->gc.direction_input = pl061_direction_input; chip->gc.direction_output = pl061_direction_output; chip->gc.get = pl061_get_value; @@ -298,7 +334,7 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) } ret = gpiochip_irqchip_add(&chip->gc, &pl061_irqchip, - irq_base, handle_simple_irq, + irq_base, handle_bad_irq, IRQ_TYPE_NONE); if (ret) { dev_info(&adev->dev, "could not add irqchip\n"); diff --git a/kernel/drivers/gpio/gpio-pxa.c b/kernel/drivers/gpio/gpio-pxa.c index cdbbcf0fa..df2ce550f 100644 --- a/kernel/drivers/gpio/gpio-pxa.c +++ b/kernel/drivers/gpio/gpio-pxa.c @@ -401,7 +401,7 @@ static int pxa_gpio_irq_type(struct irq_data *d, unsigned int type) return 0; } -static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) +static void pxa_gpio_demux_handler(struct irq_desc *desc) { struct pxa_gpio_chip *c; int loop, gpio, gpio_base, n; @@ -524,7 +524,7 @@ static int pxa_irq_domain_map(struct irq_domain *d, unsigned int irq, { irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_set_noprobe(irq); return 0; } @@ -643,20 +643,20 @@ static int pxa_gpio_probe(struct platform_device *pdev) irq = gpio_to_irq(0); irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); } if (irq1 > 0) { irq = gpio_to_irq(1); irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); } for (irq = gpio_to_irq(gpio_offset); irq <= gpio_to_irq(pxa_last_gpio); irq++) { irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); } } diff --git a/kernel/drivers/gpio/gpio-rcar.c b/kernel/drivers/gpio/gpio-rcar.c index 1e14a6c74..2a8122444 100644 --- a/kernel/drivers/gpio/gpio-rcar.c +++ b/kernel/drivers/gpio/gpio-rcar.c @@ -251,17 +251,32 @@ static void gpio_rcar_config_general_input_output_mode(struct gpio_chip *chip, static int gpio_rcar_request(struct gpio_chip *chip, unsigned offset) { - return pinctrl_request_gpio(chip->base + offset); + struct gpio_rcar_priv *p = gpio_to_priv(chip); + int error; + + error = pm_runtime_get_sync(&p->pdev->dev); + if (error < 0) + return error; + + error = pinctrl_request_gpio(chip->base + offset); + if (error) + pm_runtime_put(&p->pdev->dev); + + return error; } static void gpio_rcar_free(struct gpio_chip *chip, unsigned offset) { + struct gpio_rcar_priv *p = gpio_to_priv(chip); + pinctrl_free_gpio(chip->base + offset); /* Set the GPIO as an input to ensure that the next GPIO request won't * drive the GPIO pin as an output. */ gpio_rcar_config_general_input_output_mode(chip, offset, false); + + pm_runtime_put(&p->pdev->dev); } static int gpio_rcar_direction_input(struct gpio_chip *chip, unsigned offset) @@ -327,6 +342,10 @@ static const struct of_device_id gpio_rcar_of_table[] = { .compatible = "renesas,gpio-r8a7794", .data = &gpio_rcar_info_gen2, }, { + .compatible = "renesas,gpio-r8a7795", + /* Gen3 GPIO is identical to Gen2. */ + .data = &gpio_rcar_info_gen2, + }, { .compatible = "renesas,gpio-rcar", .data = &gpio_rcar_info_gen1, }, { @@ -405,7 +424,6 @@ static int gpio_rcar_probe(struct platform_device *pdev) } pm_runtime_enable(dev); - pm_runtime_get_sync(dev); io = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); @@ -487,7 +505,6 @@ static int gpio_rcar_probe(struct platform_device *pdev) err1: gpiochip_remove(gpio_chip); err0: - pm_runtime_put(dev); pm_runtime_disable(dev); return ret; } @@ -498,7 +515,6 @@ static int gpio_rcar_remove(struct platform_device *pdev) gpiochip_remove(&p->gpio_chip); - pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); return 0; } diff --git a/kernel/drivers/gpio/gpio-sa1100.c b/kernel/drivers/gpio/gpio-sa1100.c index bec397a60..990fa9023 100644 --- a/kernel/drivers/gpio/gpio-sa1100.c +++ b/kernel/drivers/gpio/gpio-sa1100.c @@ -155,12 +155,12 @@ static int sa1100_gpio_irqdomain_map(struct irq_domain *d, { irq_set_chip_and_handler(irq, &sa1100_gpio_irq_chip, handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_set_noprobe(irq); return 0; } -static struct irq_domain_ops sa1100_gpio_irqdomain_ops = { +static const struct irq_domain_ops sa1100_gpio_irqdomain_ops = { .map = sa1100_gpio_irqdomain_map, .xlate = irq_domain_xlate_onetwocell, }; @@ -172,10 +172,9 @@ static struct irq_domain *sa1100_gpio_irqdomain; * irq_controller_lock held, and IRQs disabled. Decode the IRQ * and call the handler. */ -static void -sa1100_gpio_handler(unsigned int irq, struct irq_desc *desc) +static void sa1100_gpio_handler(struct irq_desc *desc) { - unsigned int mask; + unsigned int irq, mask; mask = GEDR; do { diff --git a/kernel/drivers/gpio/gpio-sodaville.c b/kernel/drivers/gpio/gpio-sodaville.c index d8da36cd8..34b02b42a 100644 --- a/kernel/drivers/gpio/gpio-sodaville.c +++ b/kernel/drivers/gpio/gpio-sodaville.c @@ -102,7 +102,7 @@ static int sdv_xlate(struct irq_domain *h, struct device_node *node, { u32 line, type; - if (node != h->of_node) + if (node != irq_domain_get_of_node(h)) return -EINVAL; if (intsize < 2) @@ -125,7 +125,7 @@ static int sdv_xlate(struct irq_domain *h, struct device_node *node, return 0; } -static struct irq_domain_ops irq_domain_sdv_ops = { +static const struct irq_domain_ops irq_domain_sdv_ops = { .xlate = sdv_xlate, }; diff --git a/kernel/drivers/gpio/gpio-sta2x11.c b/kernel/drivers/gpio/gpio-sta2x11.c index 18579ac65..55e47828d 100644 --- a/kernel/drivers/gpio/gpio-sta2x11.c +++ b/kernel/drivers/gpio/gpio-sta2x11.c @@ -346,7 +346,7 @@ static void gsta_alloc_irq_chip(struct gsta_gpio *chip) i = chip->irq_base + j; irq_set_chip_and_handler(i, &ct->chip, ct->handler); irq_set_chip_data(i, gc); - irq_modify_status(i, IRQ_NOREQUEST | IRQ_NOPROBE, 0); + irq_clear_status_flags(i, IRQ_NOREQUEST | IRQ_NOPROBE); } gc->irq_cnt = i - gc->irq_base; } diff --git a/kernel/drivers/gpio/gpio-stp-xway.c b/kernel/drivers/gpio/gpio-stp-xway.c index 202361eb7..81bdbe7ba 100644 --- a/kernel/drivers/gpio/gpio-stp-xway.c +++ b/kernel/drivers/gpio/gpio-stp-xway.c @@ -58,7 +58,7 @@ #define XWAY_STP_ADSL_MASK 0x3 /* 2 groups of 3 bits can be driven by the phys */ -#define XWAY_STP_PHY_MASK 0x3 +#define XWAY_STP_PHY_MASK 0x7 #define XWAY_STP_PHY1_SHIFT 27 #define XWAY_STP_PHY2_SHIFT 15 @@ -200,7 +200,7 @@ static int xway_stp_hw_init(struct xway_stp *chip) static int xway_stp_probe(struct platform_device *pdev) { struct resource *res; - const __be32 *shadow, *groups, *dsl, *phy; + u32 shadow, groups, dsl, phy; struct xway_stp *chip; struct clk *clk; int ret = 0; @@ -223,33 +223,28 @@ static int xway_stp_probe(struct platform_device *pdev) chip->gc.owner = THIS_MODULE; /* store the shadow value if one was passed by the devicetree */ - shadow = of_get_property(pdev->dev.of_node, "lantiq,shadow", NULL); - if (shadow) - chip->shadow = be32_to_cpu(*shadow); + if (!of_property_read_u32(pdev->dev.of_node, "lantiq,shadow", &shadow)) + chip->shadow = shadow; /* find out which gpio groups should be enabled */ - groups = of_get_property(pdev->dev.of_node, "lantiq,groups", NULL); - if (groups) - chip->groups = be32_to_cpu(*groups) & XWAY_STP_GROUP_MASK; + if (!of_property_read_u32(pdev->dev.of_node, "lantiq,groups", &groups)) + chip->groups = groups & XWAY_STP_GROUP_MASK; else chip->groups = XWAY_STP_GROUP0; chip->gc.ngpio = fls(chip->groups) * 8; /* find out which gpios are controlled by the dsl core */ - dsl = of_get_property(pdev->dev.of_node, "lantiq,dsl", NULL); - if (dsl) - chip->dsl = be32_to_cpu(*dsl) & XWAY_STP_ADSL_MASK; + if (!of_property_read_u32(pdev->dev.of_node, "lantiq,dsl", &dsl)) + chip->dsl = dsl & XWAY_STP_ADSL_MASK; /* find out which gpios are controlled by the phys */ if (of_machine_is_compatible("lantiq,ar9") || of_machine_is_compatible("lantiq,gr9") || of_machine_is_compatible("lantiq,vr9")) { - phy = of_get_property(pdev->dev.of_node, "lantiq,phy1", NULL); - if (phy) - chip->phy1 = be32_to_cpu(*phy) & XWAY_STP_PHY_MASK; - phy = of_get_property(pdev->dev.of_node, "lantiq,phy2", NULL); - if (phy) - chip->phy2 = be32_to_cpu(*phy) & XWAY_STP_PHY_MASK; + if (!of_property_read_u32(pdev->dev.of_node, "lantiq,phy1", &phy)) + chip->phy1 = phy & XWAY_STP_PHY_MASK; + if (!of_property_read_u32(pdev->dev.of_node, "lantiq,phy2", &phy)) + chip->phy2 = phy & XWAY_STP_PHY_MASK; } /* check which edge trigger we should use, default to a falling edge */ diff --git a/kernel/drivers/gpio/gpio-sx150x.c b/kernel/drivers/gpio/gpio-sx150x.c index 458d9d795..76f920173 100644 --- a/kernel/drivers/gpio/gpio-sx150x.c +++ b/kernel/drivers/gpio/gpio-sx150x.c @@ -160,6 +160,11 @@ static const struct of_device_id sx150x_of_match[] = { }; MODULE_DEVICE_TABLE(of, sx150x_of_match); +struct sx150x_chip *to_sx150x(struct gpio_chip *gc) +{ + return container_of(gc, struct sx150x_chip, gpio_chip); +} + static s32 sx150x_i2c_write(struct i2c_client *client, u8 reg, u8 val) { s32 err = i2c_smbus_write_byte_data(client, reg, val); @@ -296,11 +301,9 @@ static int sx150x_io_output(struct sx150x_chip *chip, unsigned offset, int val) static int sx150x_gpio_get(struct gpio_chip *gc, unsigned offset) { - struct sx150x_chip *chip; + struct sx150x_chip *chip = to_sx150x(gc); int status = -EINVAL; - chip = container_of(gc, struct sx150x_chip, gpio_chip); - if (!offset_is_oscio(chip, offset)) { mutex_lock(&chip->lock); status = sx150x_get_io(chip, offset); @@ -312,9 +315,7 @@ static int sx150x_gpio_get(struct gpio_chip *gc, unsigned offset) static void sx150x_gpio_set(struct gpio_chip *gc, unsigned offset, int val) { - struct sx150x_chip *chip; - - chip = container_of(gc, struct sx150x_chip, gpio_chip); + struct sx150x_chip *chip = to_sx150x(gc); mutex_lock(&chip->lock); if (offset_is_oscio(chip, offset)) @@ -326,11 +327,9 @@ static void sx150x_gpio_set(struct gpio_chip *gc, unsigned offset, int val) static int sx150x_gpio_direction_input(struct gpio_chip *gc, unsigned offset) { - struct sx150x_chip *chip; + struct sx150x_chip *chip = to_sx150x(gc); int status = -EINVAL; - chip = container_of(gc, struct sx150x_chip, gpio_chip); - if (!offset_is_oscio(chip, offset)) { mutex_lock(&chip->lock); status = sx150x_io_input(chip, offset); @@ -343,11 +342,9 @@ static int sx150x_gpio_direction_output(struct gpio_chip *gc, unsigned offset, int val) { - struct sx150x_chip *chip; + struct sx150x_chip *chip = to_sx150x(gc); int status = 0; - chip = container_of(gc, struct sx150x_chip, gpio_chip); - if (!offset_is_oscio(chip, offset)) { mutex_lock(&chip->lock); status = sx150x_io_output(chip, offset, val); @@ -358,7 +355,7 @@ static int sx150x_gpio_direction_output(struct gpio_chip *gc, static void sx150x_irq_mask(struct irq_data *d) { - struct sx150x_chip *chip = irq_data_get_irq_chip_data(d); + struct sx150x_chip *chip = to_sx150x(irq_data_get_irq_chip_data(d)); unsigned n = d->hwirq; chip->irq_masked |= (1 << n); @@ -367,7 +364,7 @@ static void sx150x_irq_mask(struct irq_data *d) static void sx150x_irq_unmask(struct irq_data *d) { - struct sx150x_chip *chip = irq_data_get_irq_chip_data(d); + struct sx150x_chip *chip = to_sx150x(irq_data_get_irq_chip_data(d)); unsigned n = d->hwirq; chip->irq_masked &= ~(1 << n); @@ -376,7 +373,7 @@ static void sx150x_irq_unmask(struct irq_data *d) static int sx150x_irq_set_type(struct irq_data *d, unsigned int flow_type) { - struct sx150x_chip *chip = irq_data_get_irq_chip_data(d); + struct sx150x_chip *chip = to_sx150x(irq_data_get_irq_chip_data(d)); unsigned n, val = 0; if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) @@ -431,14 +428,14 @@ static irqreturn_t sx150x_irq_thread_fn(int irq, void *dev_id) static void sx150x_irq_bus_lock(struct irq_data *d) { - struct sx150x_chip *chip = irq_data_get_irq_chip_data(d); + struct sx150x_chip *chip = to_sx150x(irq_data_get_irq_chip_data(d)); mutex_lock(&chip->lock); } static void sx150x_irq_bus_sync_unlock(struct irq_data *d) { - struct sx150x_chip *chip = irq_data_get_irq_chip_data(d); + struct sx150x_chip *chip = to_sx150x(irq_data_get_irq_chip_data(d)); unsigned n; if (chip->irq_update == NO_UPDATE_PENDING) @@ -706,4 +703,3 @@ module_exit(sx150x_exit); MODULE_AUTHOR("Gregory Bean <gbean@codeaurora.org>"); MODULE_DESCRIPTION("Driver for Semtech SX150X I2C GPIO Expanders"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("i2c:sx150x"); diff --git a/kernel/drivers/gpio/gpio-syscon.c b/kernel/drivers/gpio/gpio-syscon.c index 045a95257..7b25fdf64 100644 --- a/kernel/drivers/gpio/gpio-syscon.c +++ b/kernel/drivers/gpio/gpio-syscon.c @@ -187,11 +187,15 @@ MODULE_DEVICE_TABLE(of, syscon_gpio_ids); static int syscon_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - const struct of_device_id *of_id = of_match_device(syscon_gpio_ids, dev); + const struct of_device_id *of_id; struct syscon_gpio_priv *priv; struct device_node *np = dev->of_node; int ret; + of_id = of_match_device(syscon_gpio_ids, dev); + if (!of_id) + return -ENODEV; + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; diff --git a/kernel/drivers/gpio/gpio-tb10x.c b/kernel/drivers/gpio/gpio-tb10x.c index 46b89614a..4356e6c20 100644 --- a/kernel/drivers/gpio/gpio-tb10x.c +++ b/kernel/drivers/gpio/gpio-tb10x.c @@ -138,16 +138,6 @@ static int tb10x_gpio_direction_out(struct gpio_chip *chip, return 0; } -static int tb10x_gpio_request(struct gpio_chip *chip, unsigned offset) -{ - return pinctrl_request_gpio(chip->base + offset); -} - -static void tb10x_gpio_free(struct gpio_chip *chip, unsigned offset) -{ - pinctrl_free_gpio(chip->base + offset); -} - static int tb10x_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { struct tb10x_gpio *tb10x_gpio = to_tb10x_gpio(chip); @@ -213,8 +203,8 @@ static int tb10x_gpio_probe(struct platform_device *pdev) tb10x_gpio->gc.get = tb10x_gpio_get; tb10x_gpio->gc.direction_output = tb10x_gpio_direction_out; tb10x_gpio->gc.set = tb10x_gpio_set; - tb10x_gpio->gc.request = tb10x_gpio_request; - tb10x_gpio->gc.free = tb10x_gpio_free; + tb10x_gpio->gc.request = gpiochip_generic_request; + tb10x_gpio->gc.free = gpiochip_generic_free; tb10x_gpio->gc.base = -1; tb10x_gpio->gc.ngpio = ngpio; tb10x_gpio->gc.can_sleep = false; @@ -292,7 +282,6 @@ static int tb10x_gpio_remove(struct platform_device *pdev) BIT(tb10x_gpio->gc.ngpio) - 1, 0, 0); kfree(tb10x_gpio->domain->gc); irq_domain_remove(tb10x_gpio->domain); - free_irq(tb10x_gpio->irq, tb10x_gpio); } gpiochip_remove(&tb10x_gpio->gc); diff --git a/kernel/drivers/gpio/gpio-tc3589x.c b/kernel/drivers/gpio/gpio-tc3589x.c index 31b244cff..d1d585ddb 100644 --- a/kernel/drivers/gpio/gpio-tc3589x.c +++ b/kernel/drivers/gpio/gpio-tc3589x.c @@ -102,7 +102,7 @@ static struct gpio_chip template_chip = { static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); + struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(gc); int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -130,7 +130,7 @@ static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type) static void tc3589x_gpio_irq_lock(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); + struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(gc); mutex_lock(&tc3589x_gpio->irq_lock); } @@ -138,7 +138,7 @@ static void tc3589x_gpio_irq_lock(struct irq_data *d) static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); + struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(gc); struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; static const u8 regmap[] = { [REG_IBE] = TC3589x_GPIOIBE0, @@ -167,7 +167,7 @@ static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d) static void tc3589x_gpio_irq_mask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); + struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(gc); int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -178,7 +178,7 @@ static void tc3589x_gpio_irq_mask(struct irq_data *d) static void tc3589x_gpio_irq_unmask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); + struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(gc); int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); diff --git a/kernel/drivers/gpio/gpio-tegra.c b/kernel/drivers/gpio/gpio-tegra.c index 1741981d5..896bf2977 100644 --- a/kernel/drivers/gpio/gpio-tegra.c +++ b/kernel/drivers/gpio/gpio-tegra.c @@ -252,9 +252,9 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) tegra_gpio_enable(gpio); if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); return 0; } @@ -266,18 +266,16 @@ static void tegra_gpio_irq_shutdown(struct irq_data *d) gpiochip_unlock_as_irq(&tegra_gpio_chip, gpio); } -static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +static void tegra_gpio_irq_handler(struct irq_desc *desc) { - struct tegra_gpio_bank *bank; int port; int pin; int unmasked = 0; struct irq_chip *chip = irq_desc_get_chip(desc); + struct tegra_gpio_bank *bank = irq_desc_get_handler_data(desc); chained_irq_enter(chip, desc); - bank = irq_get_handler_data(irq); - for (port = 0; port < 4; port++) { int gpio = tegra_gpio_compose(bank->bank, port, 0); unsigned long sta = tegra_gpio_readl(GPIO_INT_STA(gpio)) & @@ -288,7 +286,7 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) tegra_gpio_writel(1 << pin, GPIO_INT_CLR(gpio)); /* if gpio is edge triggered, clear condition - * before executing the hander so that we don't + * before executing the handler so that we don't * miss edges */ if (lvl & (0x100 << pin)) { @@ -377,6 +375,60 @@ static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable) } #endif +#ifdef CONFIG_DEBUG_FS + +#include <linux/debugfs.h> +#include <linux/seq_file.h> + +static int dbg_gpio_show(struct seq_file *s, void *unused) +{ + int i; + int j; + + for (i = 0; i < tegra_gpio_bank_count; i++) { + for (j = 0; j < 4; j++) { + int gpio = tegra_gpio_compose(i, j, 0); + seq_printf(s, + "%d:%d %02x %02x %02x %02x %02x %02x %06x\n", + i, j, + tegra_gpio_readl(GPIO_CNF(gpio)), + tegra_gpio_readl(GPIO_OE(gpio)), + tegra_gpio_readl(GPIO_OUT(gpio)), + tegra_gpio_readl(GPIO_IN(gpio)), + tegra_gpio_readl(GPIO_INT_STA(gpio)), + tegra_gpio_readl(GPIO_INT_ENB(gpio)), + tegra_gpio_readl(GPIO_INT_LVL(gpio))); + } + } + return 0; +} + +static int dbg_gpio_open(struct inode *inode, struct file *file) +{ + return single_open(file, dbg_gpio_show, &inode->i_private); +} + +static const struct file_operations debug_fops = { + .open = dbg_gpio_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void tegra_gpio_debuginit(void) +{ + (void) debugfs_create_file("tegra_gpio", S_IRUGO, + NULL, NULL, &debug_fops); +} + +#else + +static inline void tegra_gpio_debuginit(void) +{ +} + +#endif + static struct irq_chip tegra_gpio_irq_chip = { .name = "GPIO", .irq_ack = tegra_gpio_irq_ack, @@ -509,19 +561,20 @@ static int tegra_gpio_probe(struct platform_device *pdev) irq_set_chip_data(irq, bank); irq_set_chip_and_handler(irq, &tegra_gpio_irq_chip, handle_simple_irq); - set_irq_flags(irq, IRQF_VALID); } for (i = 0; i < tegra_gpio_bank_count; i++) { bank = &tegra_gpio_banks[i]; - irq_set_chained_handler(bank->irq, tegra_gpio_irq_handler); - irq_set_handler_data(bank->irq, bank); + irq_set_chained_handler_and_data(bank->irq, + tegra_gpio_irq_handler, bank); for (j = 0; j < 4; j++) spin_lock_init(&bank->lvl_lock[j]); } + tegra_gpio_debuginit(); + return 0; } @@ -539,52 +592,3 @@ static int __init tegra_gpio_init(void) return platform_driver_register(&tegra_gpio_driver); } postcore_initcall(tegra_gpio_init); - -#ifdef CONFIG_DEBUG_FS - -#include <linux/debugfs.h> -#include <linux/seq_file.h> - -static int dbg_gpio_show(struct seq_file *s, void *unused) -{ - int i; - int j; - - for (i = 0; i < tegra_gpio_bank_count; i++) { - for (j = 0; j < 4; j++) { - int gpio = tegra_gpio_compose(i, j, 0); - seq_printf(s, - "%d:%d %02x %02x %02x %02x %02x %02x %06x\n", - i, j, - tegra_gpio_readl(GPIO_CNF(gpio)), - tegra_gpio_readl(GPIO_OE(gpio)), - tegra_gpio_readl(GPIO_OUT(gpio)), - tegra_gpio_readl(GPIO_IN(gpio)), - tegra_gpio_readl(GPIO_INT_STA(gpio)), - tegra_gpio_readl(GPIO_INT_ENB(gpio)), - tegra_gpio_readl(GPIO_INT_LVL(gpio))); - } - } - return 0; -} - -static int dbg_gpio_open(struct inode *inode, struct file *file) -{ - return single_open(file, dbg_gpio_show, &inode->i_private); -} - -static const struct file_operations debug_fops = { - .open = dbg_gpio_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init tegra_gpio_debuginit(void) -{ - (void) debugfs_create_file("tegra_gpio", S_IRUGO, - NULL, NULL, &debug_fops); - return 0; -} -late_initcall(tegra_gpio_debuginit); -#endif diff --git a/kernel/drivers/gpio/gpio-timberdale.c b/kernel/drivers/gpio/gpio-timberdale.c index e8f97e03c..30653e631 100644 --- a/kernel/drivers/gpio/gpio-timberdale.c +++ b/kernel/drivers/gpio/gpio-timberdale.c @@ -192,13 +192,14 @@ out: return ret; } -static void timbgpio_irq(unsigned int irq, struct irq_desc *desc) +static void timbgpio_irq(struct irq_desc *desc) { - struct timbgpio *tgpio = irq_get_handler_data(irq); + struct timbgpio *tgpio = irq_desc_get_handler_data(desc); + struct irq_data *data = irq_desc_get_irq_data(desc); unsigned long ipr; int offset; - desc->irq_data.chip->irq_ack(irq_get_irq_data(irq)); + data->chip->irq_ack(data); ipr = ioread32(tgpio->membase + TGPIO_IPR); iowrite32(ipr, tgpio->membase + TGPIO_ICR); @@ -294,13 +295,10 @@ static int timbgpio_probe(struct platform_device *pdev) irq_set_chip_and_handler(tgpio->irq_base + i, &timbgpio_irqchip, handle_simple_irq); irq_set_chip_data(tgpio->irq_base + i, tgpio); -#ifdef CONFIG_ARM - set_irq_flags(tgpio->irq_base + i, IRQF_VALID | IRQF_PROBE); -#endif + irq_clear_status_flags(tgpio->irq_base + i, IRQ_NOREQUEST | IRQ_NOPROBE); } - irq_set_handler_data(irq, tgpio); - irq_set_chained_handler(irq, timbgpio_irq); + irq_set_chained_handler_and_data(irq, timbgpio_irq, tgpio); return 0; } diff --git a/kernel/drivers/gpio/gpio-ts5500.c b/kernel/drivers/gpio/gpio-ts5500.c index 92fbabd82..b29a102d1 100644 --- a/kernel/drivers/gpio/gpio-ts5500.c +++ b/kernel/drivers/gpio/gpio-ts5500.c @@ -440,7 +440,7 @@ static int ts5500_dio_remove(struct platform_device *pdev) return 0; } -static struct platform_device_id ts5500_dio_ids[] = { +static const struct platform_device_id ts5500_dio_ids[] = { { "ts5500-dio1", TS5500_DIO1 }, { "ts5500-dio2", TS5500_DIO2 }, { "ts5500-dio-lcd", TS5500_LCD }, diff --git a/kernel/drivers/gpio/gpio-tz1090-pdc.c b/kernel/drivers/gpio/gpio-tz1090-pdc.c index ede7e403f..3623d009d 100644 --- a/kernel/drivers/gpio/gpio-tz1090-pdc.c +++ b/kernel/drivers/gpio/gpio-tz1090-pdc.c @@ -137,16 +137,6 @@ static void tz1090_pdc_gpio_set(struct gpio_chip *chip, unsigned int offset, __global_unlock2(lstat); } -static int tz1090_pdc_gpio_request(struct gpio_chip *chip, unsigned int offset) -{ - return pinctrl_request_gpio(chip->base + offset); -} - -static void tz1090_pdc_gpio_free(struct gpio_chip *chip, unsigned int offset) -{ - pinctrl_free_gpio(chip->base + offset); -} - static int tz1090_pdc_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) { struct tz1090_pdc_gpio *priv = to_pdc(chip); @@ -203,8 +193,8 @@ static int tz1090_pdc_gpio_probe(struct platform_device *pdev) priv->chip.direction_output = tz1090_pdc_gpio_direction_output; priv->chip.get = tz1090_pdc_gpio_get; priv->chip.set = tz1090_pdc_gpio_set; - priv->chip.free = tz1090_pdc_gpio_free; - priv->chip.request = tz1090_pdc_gpio_request; + priv->chip.free = gpiochip_generic_free; + priv->chip.request = gpiochip_generic_request; priv->chip.to_irq = tz1090_pdc_gpio_to_irq; priv->chip.of_node = np; diff --git a/kernel/drivers/gpio/gpio-tz1090.c b/kernel/drivers/gpio/gpio-tz1090.c index 445660adc..87bb1b1ee 100644 --- a/kernel/drivers/gpio/gpio-tz1090.c +++ b/kernel/drivers/gpio/gpio-tz1090.c @@ -375,7 +375,7 @@ static int gpio_set_irq_wake(struct irq_data *data, unsigned int on) #define gpio_set_irq_wake NULL #endif -static void tz1090_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +static void tz1090_gpio_irq_handler(struct irq_desc *desc) { irq_hw_number_t hw; unsigned int irq_stat, irq_no; @@ -400,7 +400,7 @@ static void tz1090_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) == IRQ_TYPE_EDGE_BOTH) tz1090_gpio_irq_next_edge(bank, hw); - generic_handle_irq_desc(irq_no, child_desc); + generic_handle_irq_desc(child_desc); } } @@ -510,8 +510,8 @@ static int tz1090_gpio_bank_probe(struct tz1090_gpio_bank_info *info) gc->chip_types[1].chip.flags = IRQCHIP_MASK_ON_SUSPEND; /* Setup chained handler for this GPIO bank */ - irq_set_handler_data(bank->irq, bank); - irq_set_chained_handler(bank->irq, tz1090_gpio_irq_handler); + irq_set_chained_handler_and_data(bank->irq, tz1090_gpio_irq_handler, + bank); return 0; } diff --git a/kernel/drivers/gpio/gpio-vf610.c b/kernel/drivers/gpio/gpio-vf610.c index 7bd9f209f..87b950cec 100644 --- a/kernel/drivers/gpio/gpio-vf610.c +++ b/kernel/drivers/gpio/gpio-vf610.c @@ -60,6 +60,13 @@ struct vf610_gpio_port { #define PORT_INT_EITHER_EDGE 0xb #define PORT_INT_LOGIC_ONE 0xc +static struct irq_chip vf610_gpio_irq_chip; + +static struct vf610_gpio_port *to_vf610_gp(struct gpio_chip *gc) +{ + return container_of(gc, struct vf610_gpio_port, gc); +} + static const struct of_device_id vf610_gpio_dt_ids[] = { { .compatible = "fsl,vf610-gpio" }, { /* sentinel */ } @@ -75,28 +82,16 @@ static inline u32 vf610_gpio_readl(void __iomem *reg) return readl_relaxed(reg); } -static int vf610_gpio_request(struct gpio_chip *chip, unsigned offset) -{ - return pinctrl_request_gpio(chip->base + offset); -} - -static void vf610_gpio_free(struct gpio_chip *chip, unsigned offset) -{ - pinctrl_free_gpio(chip->base + offset); -} - static int vf610_gpio_get(struct gpio_chip *gc, unsigned int gpio) { - struct vf610_gpio_port *port = - container_of(gc, struct vf610_gpio_port, gc); + struct vf610_gpio_port *port = to_vf610_gp(gc); return !!(vf610_gpio_readl(port->gpio_base + GPIO_PDIR) & BIT(gpio)); } static void vf610_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) { - struct vf610_gpio_port *port = - container_of(gc, struct vf610_gpio_port, gc); + struct vf610_gpio_port *port = to_vf610_gp(gc); unsigned long mask = BIT(gpio); if (val) @@ -118,9 +113,10 @@ static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, return pinctrl_gpio_direction_output(chip->base + gpio); } -static void vf610_gpio_irq_handler(u32 irq, struct irq_desc *desc) +static void vf610_gpio_irq_handler(struct irq_desc *desc) { - struct vf610_gpio_port *port = irq_get_handler_data(irq); + struct vf610_gpio_port *port = + to_vf610_gp(irq_desc_get_handler_data(desc)); struct irq_chip *chip = irq_desc_get_chip(desc); int pin; unsigned long irq_isfr; @@ -140,7 +136,8 @@ static void vf610_gpio_irq_handler(u32 irq, struct irq_desc *desc) static void vf610_gpio_irq_ack(struct irq_data *d) { - struct vf610_gpio_port *port = irq_data_get_irq_chip_data(d); + struct vf610_gpio_port *port = + to_vf610_gp(irq_data_get_irq_chip_data(d)); int gpio = d->hwirq; vf610_gpio_writel(BIT(gpio), port->base + PORT_ISFR); @@ -148,7 +145,8 @@ static void vf610_gpio_irq_ack(struct irq_data *d) static int vf610_gpio_irq_set_type(struct irq_data *d, u32 type) { - struct vf610_gpio_port *port = irq_data_get_irq_chip_data(d); + struct vf610_gpio_port *port = + to_vf610_gp(irq_data_get_irq_chip_data(d)); u8 irqc; switch (type) { @@ -173,12 +171,18 @@ static int vf610_gpio_irq_set_type(struct irq_data *d, u32 type) port->irqc[d->hwirq] = irqc; + if (type & IRQ_TYPE_LEVEL_MASK) + irq_set_handler_locked(d, handle_level_irq); + else + irq_set_handler_locked(d, handle_edge_irq); + return 0; } static void vf610_gpio_irq_mask(struct irq_data *d) { - struct vf610_gpio_port *port = irq_data_get_irq_chip_data(d); + struct vf610_gpio_port *port = + to_vf610_gp(irq_data_get_irq_chip_data(d)); void __iomem *pcr_base = port->base + PORT_PCR(d->hwirq); vf610_gpio_writel(0, pcr_base); @@ -186,7 +190,8 @@ static void vf610_gpio_irq_mask(struct irq_data *d) static void vf610_gpio_irq_unmask(struct irq_data *d) { - struct vf610_gpio_port *port = irq_data_get_irq_chip_data(d); + struct vf610_gpio_port *port = + to_vf610_gp(irq_data_get_irq_chip_data(d)); void __iomem *pcr_base = port->base + PORT_PCR(d->hwirq); vf610_gpio_writel(port->irqc[d->hwirq] << PORT_PCR_IRQC_OFFSET, @@ -195,7 +200,8 @@ static void vf610_gpio_irq_unmask(struct irq_data *d) static int vf610_gpio_irq_set_wake(struct irq_data *d, u32 enable) { - struct vf610_gpio_port *port = irq_data_get_irq_chip_data(d); + struct vf610_gpio_port *port = + to_vf610_gp(irq_data_get_irq_chip_data(d)); if (enable) enable_irq_wake(port->irq); @@ -248,8 +254,8 @@ static int vf610_gpio_probe(struct platform_device *pdev) gc->ngpio = VF610_GPIO_PER_PORT; gc->base = of_alias_get_id(np, "gpio") * VF610_GPIO_PER_PORT; - gc->request = vf610_gpio_request; - gc->free = vf610_gpio_free; + gc->request = gpiochip_generic_request; + gc->free = gpiochip_generic_free; gc->direction_input = vf610_gpio_direction_input; gc->get = vf610_gpio_get; gc->direction_output = vf610_gpio_direction_output; @@ -263,7 +269,7 @@ static int vf610_gpio_probe(struct platform_device *pdev) vf610_gpio_writel(~0, port->base + PORT_ISFR); ret = gpiochip_irqchip_add(gc, &vf610_gpio_irq_chip, 0, - handle_simple_irq, IRQ_TYPE_NONE); + handle_edge_irq, IRQ_TYPE_NONE); if (ret) { dev_err(dev, "failed to add irqchip\n"); gpiochip_remove(gc); diff --git a/kernel/drivers/gpio/gpio-xgene-sb.c b/kernel/drivers/gpio/gpio-xgene-sb.c index fb9d29a5d..d57068b90 100644 --- a/kernel/drivers/gpio/gpio-xgene-sb.c +++ b/kernel/drivers/gpio/gpio-xgene-sb.c @@ -25,8 +25,11 @@ #include <linux/of_gpio.h> #include <linux/gpio.h> #include <linux/gpio/driver.h> +#include <linux/acpi.h> #include <linux/basic_mmio_gpio.h> +#include "gpiolib.h" + #define XGENE_MAX_GPIO_DS 22 #define XGENE_MAX_GPIO_DS_IRQ 6 @@ -112,7 +115,6 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev) GFP_KERNEL); if (!priv->irq) return -ENOMEM; - memset(priv->irq, 0, sizeof(u32) * XGENE_MAX_GPIO_DS); for (i = 0; i < priv->nirq; i++) { priv->irq[default_lines[i]] = platform_get_irq(pdev, i); @@ -129,6 +131,11 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev) else dev_info(&pdev->dev, "X-Gene GPIO Standby driver registered\n"); + if (priv->nirq > 0) { + /* Register interrupt handlers for gpio signaled acpi events */ + acpi_gpiochip_request_interrupts(&priv->bgc.gc); + } + return ret; } @@ -136,6 +143,10 @@ static int xgene_gpio_sb_remove(struct platform_device *pdev) { struct xgene_gpio_sb *priv = platform_get_drvdata(pdev); + if (priv->nirq > 0) { + acpi_gpiochip_free_interrupts(&priv->bgc.gc); + } + return bgpio_remove(&priv->bgc); } @@ -145,10 +156,19 @@ static const struct of_device_id xgene_gpio_sb_of_match[] = { }; MODULE_DEVICE_TABLE(of, xgene_gpio_sb_of_match); +#ifdef CONFIG_ACPI +static const struct acpi_device_id xgene_gpio_sb_acpi_match[] = { + {"APMC0D15", 0}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, xgene_gpio_sb_acpi_match); +#endif + static struct platform_driver xgene_gpio_sb_driver = { .driver = { .name = "xgene-gpio-sb", .of_match_table = xgene_gpio_sb_of_match, + .acpi_match_table = ACPI_PTR(xgene_gpio_sb_acpi_match), }, .probe = xgene_gpio_sb_probe, .remove = xgene_gpio_sb_remove, diff --git a/kernel/drivers/gpio/gpio-xilinx.c b/kernel/drivers/gpio/gpio-xilinx.c index 61243d177..d5284dfe0 100644 --- a/kernel/drivers/gpio/gpio-xilinx.c +++ b/kernel/drivers/gpio/gpio-xilinx.c @@ -41,10 +41,10 @@ /** * struct xgpio_instance - Stores information about GPIO device * @mmchip: OF GPIO chip for memory mapped banks + * @gpio_width: GPIO width for every channel * @gpio_state: GPIO state shadow register * @gpio_dir: GPIO direction shadow register * @gpio_lock: Lock used for synchronization - * @inited: True if the port has been inited */ struct xgpio_instance { struct of_mm_gpio_chip mmchip; @@ -220,9 +220,9 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc) if (!chip->gpio_width[1]) return; - xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + XGPIO_TRI_OFFSET, + xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + XGPIO_CHANNEL_OFFSET, chip->gpio_state[1]); - xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET + XGPIO_TRI_OFFSET, + xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET + XGPIO_CHANNEL_OFFSET, chip->gpio_dir[1]); } @@ -231,6 +231,8 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc) * @pdev: pointer to the platform device * * This function remove gpiochips and frees all the allocated resources. + * + * Return: 0 always */ static int xgpio_remove(struct platform_device *pdev) { diff --git a/kernel/drivers/gpio/gpio-xlp.c b/kernel/drivers/gpio/gpio-xlp.c new file mode 100644 index 000000000..bc06a2cd2 --- /dev/null +++ b/kernel/drivers/gpio/gpio-xlp.c @@ -0,0 +1,428 @@ +/* + * Copyright (C) 2003-2015 Broadcom Corporation + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/of_device.h> +#include <linux/module.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/irqchip/chained_irq.h> + +/* + * XLP GPIO has multiple 32 bit registers for each feature where each register + * controls 32 pins. So, pins up to 64 require 2 32-bit registers and up to 96 + * require 3 32-bit registers for each feature. + * Here we only define offset of the first register for each feature. Offset of + * the registers for pins greater than 32 can be calculated as following(Use + * GPIO_INT_STAT as example): + * + * offset = (gpio / XLP_GPIO_REGSZ) * 4; + * reg_addr = addr + offset; + * + * where addr is base address of the that feature register and gpio is the pin. + */ +#define GPIO_OUTPUT_EN 0x00 +#define GPIO_PADDRV 0x08 +#define GPIO_INT_EN00 0x18 +#define GPIO_INT_EN10 0x20 +#define GPIO_INT_EN20 0x28 +#define GPIO_INT_EN30 0x30 +#define GPIO_INT_POL 0x38 +#define GPIO_INT_TYPE 0x40 +#define GPIO_INT_STAT 0x48 + +#define GPIO_9XX_BYTESWAP 0X00 +#define GPIO_9XX_CTRL 0X04 +#define GPIO_9XX_OUTPUT_EN 0x14 +#define GPIO_9XX_PADDRV 0x24 +/* + * Only for 4 interrupt enable reg are defined for now, + * total reg available are 12. + */ +#define GPIO_9XX_INT_EN00 0x44 +#define GPIO_9XX_INT_EN10 0x54 +#define GPIO_9XX_INT_EN20 0x64 +#define GPIO_9XX_INT_EN30 0x74 +#define GPIO_9XX_INT_POL 0x104 +#define GPIO_9XX_INT_TYPE 0x114 +#define GPIO_9XX_INT_STAT 0x124 + +#define GPIO_3XX_INT_EN00 0x18 +#define GPIO_3XX_INT_EN10 0x20 +#define GPIO_3XX_INT_EN20 0x28 +#define GPIO_3XX_INT_EN30 0x30 +#define GPIO_3XX_INT_POL 0x78 +#define GPIO_3XX_INT_TYPE 0x80 +#define GPIO_3XX_INT_STAT 0x88 + +/* Interrupt type register mask */ +#define XLP_GPIO_IRQ_TYPE_LVL 0x0 +#define XLP_GPIO_IRQ_TYPE_EDGE 0x1 + +/* Interrupt polarity register mask */ +#define XLP_GPIO_IRQ_POL_HIGH 0x0 +#define XLP_GPIO_IRQ_POL_LOW 0x1 + +#define XLP_GPIO_REGSZ 32 +#define XLP_GPIO_IRQ_BASE 768 +#define XLP_MAX_NR_GPIO 96 + +/* XLP variants supported by this driver */ +enum { + XLP_GPIO_VARIANT_XLP832 = 1, + XLP_GPIO_VARIANT_XLP316, + XLP_GPIO_VARIANT_XLP208, + XLP_GPIO_VARIANT_XLP980, + XLP_GPIO_VARIANT_XLP532 +}; + +struct xlp_gpio_priv { + struct gpio_chip chip; + DECLARE_BITMAP(gpio_enabled_mask, XLP_MAX_NR_GPIO); + void __iomem *gpio_intr_en; /* pointer to first intr enable reg */ + void __iomem *gpio_intr_stat; /* pointer to first intr status reg */ + void __iomem *gpio_intr_type; /* pointer to first intr type reg */ + void __iomem *gpio_intr_pol; /* pointer to first intr polarity reg */ + void __iomem *gpio_out_en; /* pointer to first output enable reg */ + void __iomem *gpio_paddrv; /* pointer to first pad drive reg */ + spinlock_t lock; +}; + +static struct xlp_gpio_priv *gpio_chip_to_xlp_priv(struct gpio_chip *gc) +{ + return container_of(gc, struct xlp_gpio_priv, chip); +} + +static int xlp_gpio_get_reg(void __iomem *addr, unsigned gpio) +{ + u32 pos, regset; + + pos = gpio % XLP_GPIO_REGSZ; + regset = (gpio / XLP_GPIO_REGSZ) * 4; + return !!(readl(addr + regset) & BIT(pos)); +} + +static void xlp_gpio_set_reg(void __iomem *addr, unsigned gpio, int state) +{ + u32 value, pos, regset; + + pos = gpio % XLP_GPIO_REGSZ; + regset = (gpio / XLP_GPIO_REGSZ) * 4; + value = readl(addr + regset); + + if (state) + value |= BIT(pos); + else + value &= ~BIT(pos); + + writel(value, addr + regset); +} + +static void xlp_gpio_irq_disable(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc); + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + xlp_gpio_set_reg(priv->gpio_intr_en, d->hwirq, 0x0); + __clear_bit(d->hwirq, priv->gpio_enabled_mask); + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void xlp_gpio_irq_mask_ack(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc); + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + xlp_gpio_set_reg(priv->gpio_intr_en, d->hwirq, 0x0); + xlp_gpio_set_reg(priv->gpio_intr_stat, d->hwirq, 0x1); + __clear_bit(d->hwirq, priv->gpio_enabled_mask); + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void xlp_gpio_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc); + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + xlp_gpio_set_reg(priv->gpio_intr_en, d->hwirq, 0x1); + __set_bit(d->hwirq, priv->gpio_enabled_mask); + spin_unlock_irqrestore(&priv->lock, flags); +} + +static int xlp_gpio_set_irq_type(struct irq_data *d, unsigned int type) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc); + int pol, irq_type; + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + irq_type = XLP_GPIO_IRQ_TYPE_EDGE; + pol = XLP_GPIO_IRQ_POL_HIGH; + break; + case IRQ_TYPE_EDGE_FALLING: + irq_type = XLP_GPIO_IRQ_TYPE_EDGE; + pol = XLP_GPIO_IRQ_POL_LOW; + break; + case IRQ_TYPE_LEVEL_HIGH: + irq_type = XLP_GPIO_IRQ_TYPE_LVL; + pol = XLP_GPIO_IRQ_POL_HIGH; + break; + case IRQ_TYPE_LEVEL_LOW: + irq_type = XLP_GPIO_IRQ_TYPE_LVL; + pol = XLP_GPIO_IRQ_POL_LOW; + break; + default: + return -EINVAL; + } + + xlp_gpio_set_reg(priv->gpio_intr_type, d->hwirq, irq_type); + xlp_gpio_set_reg(priv->gpio_intr_pol, d->hwirq, pol); + + return 0; +} + +static struct irq_chip xlp_gpio_irq_chip = { + .name = "XLP-GPIO", + .irq_mask_ack = xlp_gpio_irq_mask_ack, + .irq_disable = xlp_gpio_irq_disable, + .irq_set_type = xlp_gpio_set_irq_type, + .irq_unmask = xlp_gpio_irq_unmask, + .flags = IRQCHIP_ONESHOT_SAFE, +}; + +static void xlp_gpio_generic_handler(struct irq_desc *desc) +{ + struct xlp_gpio_priv *priv = irq_desc_get_handler_data(desc); + struct irq_chip *irqchip = irq_desc_get_chip(desc); + int gpio, regoff; + u32 gpio_stat; + + regoff = -1; + gpio_stat = 0; + + chained_irq_enter(irqchip, desc); + for_each_set_bit(gpio, priv->gpio_enabled_mask, XLP_MAX_NR_GPIO) { + if (regoff != gpio / XLP_GPIO_REGSZ) { + regoff = gpio / XLP_GPIO_REGSZ; + gpio_stat = readl(priv->gpio_intr_stat + regoff * 4); + } + + if (gpio_stat & BIT(gpio % XLP_GPIO_REGSZ)) + generic_handle_irq(irq_find_mapping( + priv->chip.irqdomain, gpio)); + } + chained_irq_exit(irqchip, desc); +} + +static int xlp_gpio_dir_output(struct gpio_chip *gc, unsigned gpio, int state) +{ + struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc); + + BUG_ON(gpio >= gc->ngpio); + xlp_gpio_set_reg(priv->gpio_out_en, gpio, 0x1); + + return 0; +} + +static int xlp_gpio_dir_input(struct gpio_chip *gc, unsigned gpio) +{ + struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc); + + BUG_ON(gpio >= gc->ngpio); + xlp_gpio_set_reg(priv->gpio_out_en, gpio, 0x0); + + return 0; +} + +static int xlp_gpio_get(struct gpio_chip *gc, unsigned gpio) +{ + struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc); + + BUG_ON(gpio >= gc->ngpio); + return xlp_gpio_get_reg(priv->gpio_paddrv, gpio); +} + +static void xlp_gpio_set(struct gpio_chip *gc, unsigned gpio, int state) +{ + struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc); + + BUG_ON(gpio >= gc->ngpio); + xlp_gpio_set_reg(priv->gpio_paddrv, gpio, state); +} + +static const struct of_device_id xlp_gpio_of_ids[] = { + { + .compatible = "netlogic,xlp832-gpio", + .data = (void *)XLP_GPIO_VARIANT_XLP832, + }, + { + .compatible = "netlogic,xlp316-gpio", + .data = (void *)XLP_GPIO_VARIANT_XLP316, + }, + { + .compatible = "netlogic,xlp208-gpio", + .data = (void *)XLP_GPIO_VARIANT_XLP208, + }, + { + .compatible = "netlogic,xlp980-gpio", + .data = (void *)XLP_GPIO_VARIANT_XLP980, + }, + { + .compatible = "netlogic,xlp532-gpio", + .data = (void *)XLP_GPIO_VARIANT_XLP532, + }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, xlp_gpio_of_ids); + +static int xlp_gpio_probe(struct platform_device *pdev) +{ + struct gpio_chip *gc; + struct resource *iores; + struct xlp_gpio_priv *priv; + const struct of_device_id *of_id; + void __iomem *gpio_base; + int irq_base, irq, err; + int ngpio; + u32 soc_type; + + iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!iores) + return -ENODEV; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + gpio_base = devm_ioremap_resource(&pdev->dev, iores); + if (IS_ERR(gpio_base)) + return PTR_ERR(gpio_base); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + of_id = of_match_device(xlp_gpio_of_ids, &pdev->dev); + if (!of_id) { + dev_err(&pdev->dev, "Failed to get soc type!\n"); + return -ENODEV; + } + + soc_type = (uintptr_t) of_id->data; + + switch (soc_type) { + case XLP_GPIO_VARIANT_XLP832: + priv->gpio_out_en = gpio_base + GPIO_OUTPUT_EN; + priv->gpio_paddrv = gpio_base + GPIO_PADDRV; + priv->gpio_intr_stat = gpio_base + GPIO_INT_STAT; + priv->gpio_intr_type = gpio_base + GPIO_INT_TYPE; + priv->gpio_intr_pol = gpio_base + GPIO_INT_POL; + priv->gpio_intr_en = gpio_base + GPIO_INT_EN00; + ngpio = 41; + break; + case XLP_GPIO_VARIANT_XLP208: + case XLP_GPIO_VARIANT_XLP316: + priv->gpio_out_en = gpio_base + GPIO_OUTPUT_EN; + priv->gpio_paddrv = gpio_base + GPIO_PADDRV; + priv->gpio_intr_stat = gpio_base + GPIO_3XX_INT_STAT; + priv->gpio_intr_type = gpio_base + GPIO_3XX_INT_TYPE; + priv->gpio_intr_pol = gpio_base + GPIO_3XX_INT_POL; + priv->gpio_intr_en = gpio_base + GPIO_3XX_INT_EN00; + + ngpio = (soc_type == XLP_GPIO_VARIANT_XLP208) ? 42 : 57; + break; + case XLP_GPIO_VARIANT_XLP980: + case XLP_GPIO_VARIANT_XLP532: + priv->gpio_out_en = gpio_base + GPIO_9XX_OUTPUT_EN; + priv->gpio_paddrv = gpio_base + GPIO_9XX_PADDRV; + priv->gpio_intr_stat = gpio_base + GPIO_9XX_INT_STAT; + priv->gpio_intr_type = gpio_base + GPIO_9XX_INT_TYPE; + priv->gpio_intr_pol = gpio_base + GPIO_9XX_INT_POL; + priv->gpio_intr_en = gpio_base + GPIO_9XX_INT_EN00; + + ngpio = (soc_type == XLP_GPIO_VARIANT_XLP980) ? 66 : 67; + break; + default: + dev_err(&pdev->dev, "Unknown Processor type!\n"); + return -ENODEV; + } + + bitmap_zero(priv->gpio_enabled_mask, XLP_MAX_NR_GPIO); + + gc = &priv->chip; + + gc->owner = THIS_MODULE; + gc->label = dev_name(&pdev->dev); + gc->base = 0; + gc->dev = &pdev->dev; + gc->ngpio = ngpio; + gc->of_node = pdev->dev.of_node; + gc->direction_output = xlp_gpio_dir_output; + gc->direction_input = xlp_gpio_dir_input; + gc->set = xlp_gpio_set; + gc->get = xlp_gpio_get; + + spin_lock_init(&priv->lock); + irq_base = irq_alloc_descs(-1, XLP_GPIO_IRQ_BASE, gc->ngpio, 0); + if (irq_base < 0) { + dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n"); + return -ENODEV; + } + + err = gpiochip_add(gc); + if (err < 0) + goto out_free_desc; + + err = gpiochip_irqchip_add(gc, &xlp_gpio_irq_chip, irq_base, + handle_level_irq, IRQ_TYPE_NONE); + if (err) { + dev_err(&pdev->dev, "Could not connect irqchip to gpiochip!\n"); + goto out_gpio_remove; + } + + gpiochip_set_chained_irqchip(gc, &xlp_gpio_irq_chip, irq, + xlp_gpio_generic_handler); + + dev_info(&pdev->dev, "registered %d GPIOs\n", gc->ngpio); + + return 0; + +out_gpio_remove: + gpiochip_remove(gc); +out_free_desc: + irq_free_descs(irq_base, gc->ngpio); + return err; +} + +static struct platform_driver xlp_gpio_driver = { + .driver = { + .name = "xlp-gpio", + .of_match_table = xlp_gpio_of_ids, + }, + .probe = xlp_gpio_probe, +}; +module_platform_driver(xlp_gpio_driver); + +MODULE_AUTHOR("Kamlakant Patel <kamlakant.patel@broadcom.com>"); +MODULE_AUTHOR("Ganesan Ramalingam <ganesanr@broadcom.com>"); +MODULE_DESCRIPTION("Netlogic XLP GPIO Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/kernel/drivers/gpio/gpio-zx.c b/kernel/drivers/gpio/gpio-zx.c new file mode 100644 index 000000000..1dcf7a66d --- /dev/null +++ b/kernel/drivers/gpio/gpio-zx.c @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2015 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/bitops.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/gpio/driver.h> +#include <linux/irqchip/chained_irq.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/pinctrl/consumer.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + +#define ZX_GPIO_DIR 0x00 +#define ZX_GPIO_IVE 0x04 +#define ZX_GPIO_IV 0x08 +#define ZX_GPIO_IEP 0x0C +#define ZX_GPIO_IEN 0x10 +#define ZX_GPIO_DI 0x14 +#define ZX_GPIO_DO1 0x18 +#define ZX_GPIO_DO0 0x1C +#define ZX_GPIO_DO 0x20 + +#define ZX_GPIO_IM 0x28 +#define ZX_GPIO_IE 0x2C + +#define ZX_GPIO_MIS 0x30 +#define ZX_GPIO_IC 0x34 + +#define ZX_GPIO_NR 16 + +struct zx_gpio { + spinlock_t lock; + + void __iomem *base; + struct gpio_chip gc; +}; + +static inline struct zx_gpio *to_zx(struct gpio_chip *gc) +{ + return container_of(gc, struct zx_gpio, gc); +} + +static int zx_direction_input(struct gpio_chip *gc, unsigned offset) +{ + struct zx_gpio *chip = to_zx(gc); + unsigned long flags; + u16 gpiodir; + + if (offset >= gc->ngpio) + return -EINVAL; + + spin_lock_irqsave(&chip->lock, flags); + gpiodir = readw_relaxed(chip->base + ZX_GPIO_DIR); + gpiodir &= ~BIT(offset); + writew_relaxed(gpiodir, chip->base + ZX_GPIO_DIR); + spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +static int zx_direction_output(struct gpio_chip *gc, unsigned offset, + int value) +{ + struct zx_gpio *chip = to_zx(gc); + unsigned long flags; + u16 gpiodir; + + if (offset >= gc->ngpio) + return -EINVAL; + + spin_lock_irqsave(&chip->lock, flags); + gpiodir = readw_relaxed(chip->base + ZX_GPIO_DIR); + gpiodir |= BIT(offset); + writew_relaxed(gpiodir, chip->base + ZX_GPIO_DIR); + + if (value) + writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO1); + else + writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO0); + spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +static int zx_get_value(struct gpio_chip *gc, unsigned offset) +{ + struct zx_gpio *chip = to_zx(gc); + + return !!(readw_relaxed(chip->base + ZX_GPIO_DI) & BIT(offset)); +} + +static void zx_set_value(struct gpio_chip *gc, unsigned offset, int value) +{ + struct zx_gpio *chip = to_zx(gc); + + if (value) + writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO1); + else + writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO0); +} + +static int zx_irq_type(struct irq_data *d, unsigned trigger) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct zx_gpio *chip = to_zx(gc); + int offset = irqd_to_hwirq(d); + unsigned long flags; + u16 gpiois, gpioi_epos, gpioi_eneg, gpioiev; + u16 bit = BIT(offset); + + if (offset < 0 || offset >= ZX_GPIO_NR) + return -EINVAL; + + spin_lock_irqsave(&chip->lock, flags); + + gpioiev = readw_relaxed(chip->base + ZX_GPIO_IV); + gpiois = readw_relaxed(chip->base + ZX_GPIO_IVE); + gpioi_epos = readw_relaxed(chip->base + ZX_GPIO_IEP); + gpioi_eneg = readw_relaxed(chip->base + ZX_GPIO_IEN); + + if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { + gpiois |= bit; + if (trigger & IRQ_TYPE_LEVEL_HIGH) + gpioiev |= bit; + else + gpioiev &= ~bit; + } else + gpiois &= ~bit; + + if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) { + gpioi_epos |= bit; + gpioi_eneg |= bit; + } else { + if (trigger & IRQ_TYPE_EDGE_RISING) { + gpioi_epos |= bit; + gpioi_eneg &= ~bit; + } else if (trigger & IRQ_TYPE_EDGE_FALLING) { + gpioi_eneg |= bit; + gpioi_epos &= ~bit; + } + } + + writew_relaxed(gpiois, chip->base + ZX_GPIO_IVE); + writew_relaxed(gpioi_epos, chip->base + ZX_GPIO_IEP); + writew_relaxed(gpioi_eneg, chip->base + ZX_GPIO_IEN); + writew_relaxed(gpioiev, chip->base + ZX_GPIO_IV); + spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +static void zx_irq_handler(struct irq_desc *desc) +{ + unsigned long pending; + int offset; + struct gpio_chip *gc = irq_desc_get_handler_data(desc); + struct zx_gpio *chip = to_zx(gc); + struct irq_chip *irqchip = irq_desc_get_chip(desc); + + chained_irq_enter(irqchip, desc); + + pending = readw_relaxed(chip->base + ZX_GPIO_MIS); + writew_relaxed(pending, chip->base + ZX_GPIO_IC); + if (pending) { + for_each_set_bit(offset, &pending, ZX_GPIO_NR) + generic_handle_irq(irq_find_mapping(gc->irqdomain, + offset)); + } + + chained_irq_exit(irqchip, desc); +} + +static void zx_irq_mask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct zx_gpio *chip = to_zx(gc); + u16 mask = BIT(irqd_to_hwirq(d) % ZX_GPIO_NR); + u16 gpioie; + + spin_lock(&chip->lock); + gpioie = readw_relaxed(chip->base + ZX_GPIO_IM) | mask; + writew_relaxed(gpioie, chip->base + ZX_GPIO_IM); + gpioie = readw_relaxed(chip->base + ZX_GPIO_IE) & ~mask; + writew_relaxed(gpioie, chip->base + ZX_GPIO_IE); + spin_unlock(&chip->lock); +} + +static void zx_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct zx_gpio *chip = to_zx(gc); + u16 mask = BIT(irqd_to_hwirq(d) % ZX_GPIO_NR); + u16 gpioie; + + spin_lock(&chip->lock); + gpioie = readw_relaxed(chip->base + ZX_GPIO_IM) & ~mask; + writew_relaxed(gpioie, chip->base + ZX_GPIO_IM); + gpioie = readw_relaxed(chip->base + ZX_GPIO_IE) | mask; + writew_relaxed(gpioie, chip->base + ZX_GPIO_IE); + spin_unlock(&chip->lock); +} + +static struct irq_chip zx_irqchip = { + .name = "zx-gpio", + .irq_mask = zx_irq_mask, + .irq_unmask = zx_irq_unmask, + .irq_set_type = zx_irq_type, +}; + +static int zx_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct zx_gpio *chip; + struct resource *res; + int irq, id, ret; + + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + chip->base = devm_ioremap_resource(dev, res); + if (IS_ERR(chip->base)) + return PTR_ERR(chip->base); + + spin_lock_init(&chip->lock); + if (of_property_read_bool(dev->of_node, "gpio-ranges")) { + chip->gc.request = gpiochip_generic_request; + chip->gc.free = gpiochip_generic_free; + } + + id = of_alias_get_id(dev->of_node, "gpio"); + chip->gc.direction_input = zx_direction_input; + chip->gc.direction_output = zx_direction_output; + chip->gc.get = zx_get_value; + chip->gc.set = zx_set_value; + chip->gc.base = ZX_GPIO_NR * id; + chip->gc.ngpio = ZX_GPIO_NR; + chip->gc.label = dev_name(dev); + chip->gc.dev = dev; + chip->gc.owner = THIS_MODULE; + + ret = gpiochip_add(&chip->gc); + if (ret) + return ret; + + /* + * irq_chip support + */ + writew_relaxed(0xffff, chip->base + ZX_GPIO_IM); + writew_relaxed(0, chip->base + ZX_GPIO_IE); + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "invalid IRQ\n"); + gpiochip_remove(&chip->gc); + return -ENODEV; + } + + ret = gpiochip_irqchip_add(&chip->gc, &zx_irqchip, + 0, handle_simple_irq, + IRQ_TYPE_NONE); + if (ret) { + dev_err(dev, "could not add irqchip\n"); + gpiochip_remove(&chip->gc); + return ret; + } + gpiochip_set_chained_irqchip(&chip->gc, &zx_irqchip, + irq, zx_irq_handler); + + platform_set_drvdata(pdev, chip); + dev_info(dev, "ZX GPIO chip registered\n"); + + return 0; +} + +static const struct of_device_id zx_gpio_match[] = { + { + .compatible = "zte,zx296702-gpio", + }, + { }, +}; +MODULE_DEVICE_TABLE(of, zx_gpio_match); + +static struct platform_driver zx_gpio_driver = { + .probe = zx_gpio_probe, + .driver = { + .name = "zx_gpio", + .of_match_table = of_match_ptr(zx_gpio_match), + }, +}; + +module_platform_driver(zx_gpio_driver) + +MODULE_AUTHOR("Jun Nie <jun.nie@linaro.org>"); +MODULE_DESCRIPTION("ZTE ZX296702 GPIO driver"); +MODULE_LICENSE("GPL"); diff --git a/kernel/drivers/gpio/gpio-zynq.c b/kernel/drivers/gpio/gpio-zynq.c index 184c4b1b2..8abeacac5 100644 --- a/kernel/drivers/gpio/gpio-zynq.c +++ b/kernel/drivers/gpio/gpio-zynq.c @@ -18,34 +18,47 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/of.h> #define DRIVER_NAME "zynq-gpio" /* Maximum banks */ #define ZYNQ_GPIO_MAX_BANK 4 +#define ZYNQMP_GPIO_MAX_BANK 6 #define ZYNQ_GPIO_BANK0_NGPIO 32 #define ZYNQ_GPIO_BANK1_NGPIO 22 #define ZYNQ_GPIO_BANK2_NGPIO 32 #define ZYNQ_GPIO_BANK3_NGPIO 32 -#define ZYNQ_GPIO_NR_GPIOS (ZYNQ_GPIO_BANK0_NGPIO + \ - ZYNQ_GPIO_BANK1_NGPIO + \ - ZYNQ_GPIO_BANK2_NGPIO + \ - ZYNQ_GPIO_BANK3_NGPIO) - -#define ZYNQ_GPIO_BANK0_PIN_MIN 0 -#define ZYNQ_GPIO_BANK0_PIN_MAX (ZYNQ_GPIO_BANK0_PIN_MIN + \ - ZYNQ_GPIO_BANK0_NGPIO - 1) -#define ZYNQ_GPIO_BANK1_PIN_MIN (ZYNQ_GPIO_BANK0_PIN_MAX + 1) -#define ZYNQ_GPIO_BANK1_PIN_MAX (ZYNQ_GPIO_BANK1_PIN_MIN + \ - ZYNQ_GPIO_BANK1_NGPIO - 1) -#define ZYNQ_GPIO_BANK2_PIN_MIN (ZYNQ_GPIO_BANK1_PIN_MAX + 1) -#define ZYNQ_GPIO_BANK2_PIN_MAX (ZYNQ_GPIO_BANK2_PIN_MIN + \ - ZYNQ_GPIO_BANK2_NGPIO - 1) -#define ZYNQ_GPIO_BANK3_PIN_MIN (ZYNQ_GPIO_BANK2_PIN_MAX + 1) -#define ZYNQ_GPIO_BANK3_PIN_MAX (ZYNQ_GPIO_BANK3_PIN_MIN + \ - ZYNQ_GPIO_BANK3_NGPIO - 1) +#define ZYNQMP_GPIO_BANK0_NGPIO 26 +#define ZYNQMP_GPIO_BANK1_NGPIO 26 +#define ZYNQMP_GPIO_BANK2_NGPIO 26 +#define ZYNQMP_GPIO_BANK3_NGPIO 32 +#define ZYNQMP_GPIO_BANK4_NGPIO 32 +#define ZYNQMP_GPIO_BANK5_NGPIO 32 + +#define ZYNQ_GPIO_NR_GPIOS 118 +#define ZYNQMP_GPIO_NR_GPIOS 174 + +#define ZYNQ_GPIO_BANK0_PIN_MIN(str) 0 +#define ZYNQ_GPIO_BANK0_PIN_MAX(str) (ZYNQ_GPIO_BANK0_PIN_MIN(str) + \ + ZYNQ##str##_GPIO_BANK0_NGPIO - 1) +#define ZYNQ_GPIO_BANK1_PIN_MIN(str) (ZYNQ_GPIO_BANK0_PIN_MAX(str) + 1) +#define ZYNQ_GPIO_BANK1_PIN_MAX(str) (ZYNQ_GPIO_BANK1_PIN_MIN(str) + \ + ZYNQ##str##_GPIO_BANK1_NGPIO - 1) +#define ZYNQ_GPIO_BANK2_PIN_MIN(str) (ZYNQ_GPIO_BANK1_PIN_MAX(str) + 1) +#define ZYNQ_GPIO_BANK2_PIN_MAX(str) (ZYNQ_GPIO_BANK2_PIN_MIN(str) + \ + ZYNQ##str##_GPIO_BANK2_NGPIO - 1) +#define ZYNQ_GPIO_BANK3_PIN_MIN(str) (ZYNQ_GPIO_BANK2_PIN_MAX(str) + 1) +#define ZYNQ_GPIO_BANK3_PIN_MAX(str) (ZYNQ_GPIO_BANK3_PIN_MIN(str) + \ + ZYNQ##str##_GPIO_BANK3_NGPIO - 1) +#define ZYNQ_GPIO_BANK4_PIN_MIN(str) (ZYNQ_GPIO_BANK3_PIN_MAX(str) + 1) +#define ZYNQ_GPIO_BANK4_PIN_MAX(str) (ZYNQ_GPIO_BANK4_PIN_MIN(str) + \ + ZYNQ##str##_GPIO_BANK4_NGPIO - 1) +#define ZYNQ_GPIO_BANK5_PIN_MIN(str) (ZYNQ_GPIO_BANK4_PIN_MAX(str) + 1) +#define ZYNQ_GPIO_BANK5_PIN_MAX(str) (ZYNQ_GPIO_BANK5_PIN_MIN(str) + \ + ZYNQ##str##_GPIO_BANK5_NGPIO - 1) /* Register offsets for the GPIO device */ @@ -89,16 +102,40 @@ * @base_addr: base address of the GPIO device * @clk: clock resource for this controller * @irq: interrupt for the GPIO device + * @p_data: pointer to platform data */ struct zynq_gpio { struct gpio_chip chip; void __iomem *base_addr; struct clk *clk; int irq; + const struct zynq_platform_data *p_data; +}; + +/** + * struct zynq_platform_data - zynq gpio platform data structure + * @label: string to store in gpio->label + * @ngpio: max number of gpio pins + * @max_bank: maximum number of gpio banks + * @bank_min: this array represents bank's min pin + * @bank_max: this array represents bank's max pin +*/ +struct zynq_platform_data { + const char *label; + u16 ngpio; + int max_bank; + int bank_min[ZYNQMP_GPIO_MAX_BANK]; + int bank_max[ZYNQMP_GPIO_MAX_BANK]; }; static struct irq_chip zynq_gpio_level_irqchip; static struct irq_chip zynq_gpio_edge_irqchip; + +static struct zynq_gpio *to_zynq_gpio(struct gpio_chip *gc) +{ + return container_of(gc, struct zynq_gpio, chip); +} + /** * zynq_gpio_get_bank_pin - Get the bank number and pin number within that bank * for a given pin in the GPIO device @@ -112,39 +149,26 @@ static struct irq_chip zynq_gpio_edge_irqchip; */ static inline void zynq_gpio_get_bank_pin(unsigned int pin_num, unsigned int *bank_num, - unsigned int *bank_pin_num) + unsigned int *bank_pin_num, + struct zynq_gpio *gpio) { - switch (pin_num) { - case ZYNQ_GPIO_BANK0_PIN_MIN ... ZYNQ_GPIO_BANK0_PIN_MAX: - *bank_num = 0; - *bank_pin_num = pin_num; - break; - case ZYNQ_GPIO_BANK1_PIN_MIN ... ZYNQ_GPIO_BANK1_PIN_MAX: - *bank_num = 1; - *bank_pin_num = pin_num - ZYNQ_GPIO_BANK1_PIN_MIN; - break; - case ZYNQ_GPIO_BANK2_PIN_MIN ... ZYNQ_GPIO_BANK2_PIN_MAX: - *bank_num = 2; - *bank_pin_num = pin_num - ZYNQ_GPIO_BANK2_PIN_MIN; - break; - case ZYNQ_GPIO_BANK3_PIN_MIN ... ZYNQ_GPIO_BANK3_PIN_MAX: - *bank_num = 3; - *bank_pin_num = pin_num - ZYNQ_GPIO_BANK3_PIN_MIN; - break; - default: - WARN(true, "invalid GPIO pin number: %u", pin_num); - *bank_num = 0; - *bank_pin_num = 0; - break; + int bank; + + for (bank = 0; bank < gpio->p_data->max_bank; bank++) { + if ((pin_num >= gpio->p_data->bank_min[bank]) && + (pin_num <= gpio->p_data->bank_max[bank])) { + *bank_num = bank; + *bank_pin_num = pin_num - + gpio->p_data->bank_min[bank]; + return; + } } -} -static const unsigned int zynq_gpio_bank_offset[] = { - ZYNQ_GPIO_BANK0_PIN_MIN, - ZYNQ_GPIO_BANK1_PIN_MIN, - ZYNQ_GPIO_BANK2_PIN_MIN, - ZYNQ_GPIO_BANK3_PIN_MIN, -}; + /* default */ + WARN(true, "invalid GPIO pin number: %u", pin_num); + *bank_num = 0; + *bank_pin_num = 0; +} /** * zynq_gpio_get_value - Get the state of the specified pin of GPIO device @@ -159,9 +183,9 @@ static int zynq_gpio_get_value(struct gpio_chip *chip, unsigned int pin) { u32 data; unsigned int bank_num, bank_pin_num; - struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip); + struct zynq_gpio *gpio = to_zynq_gpio(chip); - zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num); + zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio); data = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DATA_RO_OFFSET(bank_num)); @@ -183,9 +207,9 @@ static void zynq_gpio_set_value(struct gpio_chip *chip, unsigned int pin, int state) { unsigned int reg_offset, bank_num, bank_pin_num; - struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip); + struct zynq_gpio *gpio = to_zynq_gpio(chip); - zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num); + zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio); if (bank_pin_num >= ZYNQ_GPIO_MID_PIN_NUM) { /* only 16 data bits in bit maskable reg */ @@ -220,9 +244,9 @@ static int zynq_gpio_dir_in(struct gpio_chip *chip, unsigned int pin) { u32 reg; unsigned int bank_num, bank_pin_num; - struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip); + struct zynq_gpio *gpio = to_zynq_gpio(chip); - zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num); + zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio); /* bank 0 pins 7 and 8 are special and cannot be used as inputs */ if (bank_num == 0 && (bank_pin_num == 7 || bank_pin_num == 8)) @@ -253,9 +277,9 @@ static int zynq_gpio_dir_out(struct gpio_chip *chip, unsigned int pin, { u32 reg; unsigned int bank_num, bank_pin_num; - struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip); + struct zynq_gpio *gpio = to_zynq_gpio(chip); - zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num); + zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio); /* set the GPIO pin as output */ reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); @@ -283,10 +307,11 @@ static int zynq_gpio_dir_out(struct gpio_chip *chip, unsigned int pin, static void zynq_gpio_irq_mask(struct irq_data *irq_data) { unsigned int device_pin_num, bank_num, bank_pin_num; - struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data); + struct zynq_gpio *gpio = + to_zynq_gpio(irq_data_get_irq_chip_data(irq_data)); device_pin_num = irq_data->hwirq; - zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num); + zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio); writel_relaxed(BIT(bank_pin_num), gpio->base_addr + ZYNQ_GPIO_INTDIS_OFFSET(bank_num)); } @@ -303,10 +328,11 @@ static void zynq_gpio_irq_mask(struct irq_data *irq_data) static void zynq_gpio_irq_unmask(struct irq_data *irq_data) { unsigned int device_pin_num, bank_num, bank_pin_num; - struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data); + struct zynq_gpio *gpio = + to_zynq_gpio(irq_data_get_irq_chip_data(irq_data)); device_pin_num = irq_data->hwirq; - zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num); + zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio); writel_relaxed(BIT(bank_pin_num), gpio->base_addr + ZYNQ_GPIO_INTEN_OFFSET(bank_num)); } @@ -322,10 +348,11 @@ static void zynq_gpio_irq_unmask(struct irq_data *irq_data) static void zynq_gpio_irq_ack(struct irq_data *irq_data) { unsigned int device_pin_num, bank_num, bank_pin_num; - struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data); + struct zynq_gpio *gpio = + to_zynq_gpio(irq_data_get_irq_chip_data(irq_data)); device_pin_num = irq_data->hwirq; - zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num); + zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio); writel_relaxed(BIT(bank_pin_num), gpio->base_addr + ZYNQ_GPIO_INTSTS_OFFSET(bank_num)); } @@ -335,7 +362,7 @@ static void zynq_gpio_irq_ack(struct irq_data *irq_data) * @irq_data: irq data containing irq number of gpio pin for the interrupt * to enable * - * Clears the INTSTS bit and unmasks the given interrrupt. + * Clears the INTSTS bit and unmasks the given interrupt. */ static void zynq_gpio_irq_enable(struct irq_data *irq_data) { @@ -372,10 +399,11 @@ static int zynq_gpio_set_irq_type(struct irq_data *irq_data, unsigned int type) { u32 int_type, int_pol, int_any; unsigned int device_pin_num, bank_num, bank_pin_num; - struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data); + struct zynq_gpio *gpio = + to_zynq_gpio(irq_data_get_irq_chip_data(irq_data)); device_pin_num = irq_data->hwirq; - zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num); + zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio); int_type = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_INTTYPE_OFFSET(bank_num)); @@ -423,10 +451,10 @@ static int zynq_gpio_set_irq_type(struct irq_data *irq_data, unsigned int type) gpio->base_addr + ZYNQ_GPIO_INTANY_OFFSET(bank_num)); if (type & IRQ_TYPE_LEVEL_MASK) { - __irq_set_chip_handler_name_locked(irq_data->irq, + irq_set_chip_handler_name_locked(irq_data, &zynq_gpio_level_irqchip, handle_fasteoi_irq, NULL); } else { - __irq_set_chip_handler_name_locked(irq_data->irq, + irq_set_chip_handler_name_locked(irq_data, &zynq_gpio_edge_irqchip, handle_level_irq, NULL); } @@ -435,7 +463,8 @@ static int zynq_gpio_set_irq_type(struct irq_data *irq_data, unsigned int type) static int zynq_gpio_set_wake(struct irq_data *data, unsigned int on) { - struct zynq_gpio *gpio = irq_data_get_irq_chip_data(data); + struct zynq_gpio *gpio = + to_zynq_gpio(irq_data_get_irq_chip_data(data)); irq_set_irq_wake(gpio->irq, on); @@ -470,7 +499,7 @@ static void zynq_gpio_handle_bank_irq(struct zynq_gpio *gpio, unsigned int bank_num, unsigned long pending) { - unsigned int bank_offset = zynq_gpio_bank_offset[bank_num]; + unsigned int bank_offset = gpio->p_data->bank_min[bank_num]; struct irq_domain *irqdomain = gpio->chip.irqdomain; int offset; @@ -496,16 +525,17 @@ static void zynq_gpio_handle_bank_irq(struct zynq_gpio *gpio, * application for that pin. * Note: A bug is reported if no handler is set for the gpio pin. */ -static void zynq_gpio_irqhandler(unsigned int irq, struct irq_desc *desc) +static void zynq_gpio_irqhandler(struct irq_desc *desc) { u32 int_sts, int_enb; unsigned int bank_num; - struct zynq_gpio *gpio = irq_get_handler_data(irq); + struct zynq_gpio *gpio = + to_zynq_gpio(irq_desc_get_handler_data(desc)); struct irq_chip *irqchip = irq_desc_get_chip(desc); chained_irq_enter(irqchip, desc); - for (bank_num = 0; bank_num < ZYNQ_GPIO_MAX_BANK; bank_num++) { + for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++) { int_sts = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_INTSTS_OFFSET(bank_num)); int_enb = readl_relaxed(gpio->base_addr + @@ -582,6 +612,46 @@ static const struct dev_pm_ops zynq_gpio_dev_pm_ops = { zynq_gpio_runtime_resume, NULL) }; +static const struct zynq_platform_data zynqmp_gpio_def = { + .label = "zynqmp_gpio", + .ngpio = ZYNQMP_GPIO_NR_GPIOS, + .max_bank = ZYNQMP_GPIO_MAX_BANK, + .bank_min[0] = ZYNQ_GPIO_BANK0_PIN_MIN(MP), + .bank_max[0] = ZYNQ_GPIO_BANK0_PIN_MAX(MP), + .bank_min[1] = ZYNQ_GPIO_BANK1_PIN_MIN(MP), + .bank_max[1] = ZYNQ_GPIO_BANK1_PIN_MAX(MP), + .bank_min[2] = ZYNQ_GPIO_BANK2_PIN_MIN(MP), + .bank_max[2] = ZYNQ_GPIO_BANK2_PIN_MAX(MP), + .bank_min[3] = ZYNQ_GPIO_BANK3_PIN_MIN(MP), + .bank_max[3] = ZYNQ_GPIO_BANK3_PIN_MAX(MP), + .bank_min[4] = ZYNQ_GPIO_BANK4_PIN_MIN(MP), + .bank_max[4] = ZYNQ_GPIO_BANK4_PIN_MAX(MP), + .bank_min[5] = ZYNQ_GPIO_BANK5_PIN_MIN(MP), + .bank_max[5] = ZYNQ_GPIO_BANK5_PIN_MAX(MP), +}; + +static const struct zynq_platform_data zynq_gpio_def = { + .label = "zynq_gpio", + .ngpio = ZYNQ_GPIO_NR_GPIOS, + .max_bank = ZYNQ_GPIO_MAX_BANK, + .bank_min[0] = ZYNQ_GPIO_BANK0_PIN_MIN(), + .bank_max[0] = ZYNQ_GPIO_BANK0_PIN_MAX(), + .bank_min[1] = ZYNQ_GPIO_BANK1_PIN_MIN(), + .bank_max[1] = ZYNQ_GPIO_BANK1_PIN_MAX(), + .bank_min[2] = ZYNQ_GPIO_BANK2_PIN_MIN(), + .bank_max[2] = ZYNQ_GPIO_BANK2_PIN_MAX(), + .bank_min[3] = ZYNQ_GPIO_BANK3_PIN_MIN(), + .bank_max[3] = ZYNQ_GPIO_BANK3_PIN_MAX(), +}; + +static const struct of_device_id zynq_gpio_of_match[] = { + { .compatible = "xlnx,zynq-gpio-1.0", .data = (void *)&zynq_gpio_def }, + { .compatible = "xlnx,zynqmp-gpio-1.0", + .data = (void *)&zynqmp_gpio_def }, + { /* end of table */ } +}; +MODULE_DEVICE_TABLE(of, zynq_gpio_of_match); + /** * zynq_gpio_probe - Initialization method for a zynq_gpio device * @pdev: platform device instance @@ -599,11 +669,18 @@ static int zynq_gpio_probe(struct platform_device *pdev) struct zynq_gpio *gpio; struct gpio_chip *chip; struct resource *res; + const struct of_device_id *match; gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); if (!gpio) return -ENOMEM; + match = of_match_node(zynq_gpio_of_match, pdev->dev.of_node); + if (!match) { + dev_err(&pdev->dev, "of_match_node() failed\n"); + return -EINVAL; + } + gpio->p_data = match->data; platform_set_drvdata(pdev, gpio); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -619,7 +696,7 @@ static int zynq_gpio_probe(struct platform_device *pdev) /* configure the gpio chip */ chip = &gpio->chip; - chip->label = "zynq_gpio"; + chip->label = gpio->p_data->label; chip->owner = THIS_MODULE; chip->dev = &pdev->dev; chip->get = zynq_gpio_get_value; @@ -629,7 +706,7 @@ static int zynq_gpio_probe(struct platform_device *pdev) chip->direction_input = zynq_gpio_dir_in; chip->direction_output = zynq_gpio_dir_out; chip->base = -1; - chip->ngpio = ZYNQ_GPIO_NR_GPIOS; + chip->ngpio = gpio->p_data->ngpio; /* Enable GPIO clock */ gpio->clk = devm_clk_get(&pdev->dev, NULL); @@ -651,7 +728,7 @@ static int zynq_gpio_probe(struct platform_device *pdev) } /* disable interrupts for all banks */ - for (bank_num = 0; bank_num < ZYNQ_GPIO_MAX_BANK; bank_num++) + for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++) writel_relaxed(ZYNQ_GPIO_IXR_DISABLE_ALL, gpio->base_addr + ZYNQ_GPIO_INTDIS_OFFSET(bank_num)); @@ -692,15 +769,10 @@ static int zynq_gpio_remove(struct platform_device *pdev) gpiochip_remove(&gpio->chip); clk_disable_unprepare(gpio->clk); device_set_wakeup_capable(&pdev->dev, 0); + pm_runtime_disable(&pdev->dev); return 0; } -static struct of_device_id zynq_gpio_of_match[] = { - { .compatible = "xlnx,zynq-gpio-1.0", }, - { /* end of table */ } -}; -MODULE_DEVICE_TABLE(of, zynq_gpio_of_match); - static struct platform_driver zynq_gpio_driver = { .driver = { .name = DRIVER_NAME, @@ -722,6 +794,12 @@ static int __init zynq_gpio_init(void) } postcore_initcall(zynq_gpio_init); +static void __exit zynq_gpio_exit(void) +{ + platform_driver_unregister(&zynq_gpio_driver); +} +module_exit(zynq_gpio_exit); + MODULE_AUTHOR("Xilinx Inc."); MODULE_DESCRIPTION("Zynq GPIO driver"); MODULE_LICENSE("GPL"); diff --git a/kernel/drivers/gpio/gpiolib-acpi.c b/kernel/drivers/gpio/gpiolib-acpi.c index 725d16138..16a7b6816 100644 --- a/kernel/drivers/gpio/gpiolib-acpi.c +++ b/kernel/drivers/gpio/gpiolib-acpi.c @@ -68,7 +68,7 @@ static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) * GPIO controller driver. * * Typically the returned offset is same as @pin, but if the GPIO - * controller uses pin controller and the mapping is not contigous the + * controller uses pin controller and the mapping is not contiguous the * offset might be different. */ static int acpi_gpiochip_pin_to_gpio_offset(struct gpio_chip *chip, int pin) @@ -114,10 +114,11 @@ static inline int acpi_gpiochip_pin_to_gpio_offset(struct gpio_chip *chip, * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1") * @pin: ACPI GPIO pin number (0-based, controller-relative) * - * Returns GPIO descriptor to use with Linux generic GPIO API, or ERR_PTR - * error value + * Return: GPIO descriptor to use with Linux generic GPIO API, or ERR_PTR + * error value. Specifically returns %-EPROBE_DEFER if the referenced GPIO + * controller does not have gpiochip registered at the moment. This is to + * support probe deferral. */ - static struct gpio_desc *acpi_get_gpiod(char *path, int pin) { struct gpio_chip *chip; @@ -131,7 +132,7 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin) chip = gpiochip_find(handle, acpi_gpiochip_find); if (!chip) - return ERR_PTR(-ENODEV); + return ERR_PTR(-EPROBE_DEFER); offset = acpi_gpiochip_pin_to_gpio_offset(chip, pin); if (offset < 0) @@ -303,10 +304,10 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) if (ACPI_FAILURE(status)) return; - INIT_LIST_HEAD(&acpi_gpio->events); acpi_walk_resources(handle, "_AEI", acpi_gpiochip_request_interrupt, acpi_gpio); } +EXPORT_SYMBOL_GPL(acpi_gpiochip_request_interrupts); /** * acpi_gpiochip_free_interrupts() - Free GPIO ACPI event interrupts. @@ -346,6 +347,7 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) kfree(event); } } +EXPORT_SYMBOL_GPL(acpi_gpiochip_free_interrupts); int acpi_dev_add_driver_gpios(struct acpi_device *adev, const struct acpi_gpio_mapping *gpios) @@ -386,6 +388,8 @@ struct acpi_gpio_lookup { struct acpi_gpio_info info; int index; int pin_index; + bool active_low; + struct acpi_device *adev; struct gpio_desc *desc; int n; }; @@ -422,6 +426,65 @@ static int acpi_find_gpio(struct acpi_resource *ares, void *data) return 1; } +static int acpi_gpio_resource_lookup(struct acpi_gpio_lookup *lookup, + struct acpi_gpio_info *info) +{ + struct list_head res_list; + int ret; + + INIT_LIST_HEAD(&res_list); + + ret = acpi_dev_get_resources(lookup->adev, &res_list, acpi_find_gpio, + lookup); + if (ret < 0) + return ret; + + acpi_dev_free_resource_list(&res_list); + + if (!lookup->desc) + return -ENOENT; + + if (info) { + *info = lookup->info; + if (lookup->active_low) + info->active_low = lookup->active_low; + } + return 0; +} + +static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode, + const char *propname, int index, + struct acpi_gpio_lookup *lookup) +{ + struct acpi_reference_args args; + int ret; + + memset(&args, 0, sizeof(args)); + ret = acpi_node_get_property_reference(fwnode, propname, index, &args); + if (ret) { + struct acpi_device *adev = to_acpi_device_node(fwnode); + + if (!adev) + return ret; + + if (!acpi_get_driver_gpio_data(adev, propname, index, &args)) + return ret; + } + /* + * The property was found and resolved, so need to lookup the GPIO based + * on returned args. + */ + lookup->adev = args.adev; + if (args.nargs >= 2) { + lookup->index = args.args[0]; + lookup->pin_index = args.args[1]; + /* 3rd argument, if present is used to specify active_low. */ + if (args.nargs >= 3) + lookup->active_low = !!args.args[2]; + } + return 0; +} + /** * acpi_get_gpiod_by_index() - get a GPIO descriptor from device resources * @adev: pointer to a ACPI device to get GPIO from @@ -449,8 +512,6 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev, struct acpi_gpio_info *info) { struct acpi_gpio_lookup lookup; - struct list_head resource_list; - bool active_low = false; int ret; if (!adev) @@ -460,59 +521,94 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev, lookup.index = index; if (propname) { - struct acpi_reference_args args; - dev_dbg(&adev->dev, "GPIO: looking up %s\n", propname); - memset(&args, 0, sizeof(args)); - ret = acpi_dev_get_property_reference(adev, propname, - index, &args); - if (ret) { - bool found = acpi_get_driver_gpio_data(adev, propname, - index, &args); - if (!found) - return ERR_PTR(ret); - } - - /* - * The property was found and resolved so need to - * lookup the GPIO based on returned args instead. - */ - adev = args.adev; - if (args.nargs >= 2) { - lookup.index = args.args[0]; - lookup.pin_index = args.args[1]; - /* - * 3rd argument, if present is used to - * specify active_low. - */ - if (args.nargs >= 3) - active_low = !!args.args[2]; - } + ret = acpi_gpio_property_lookup(acpi_fwnode_handle(adev), + propname, index, &lookup); + if (ret) + return ERR_PTR(ret); - dev_dbg(&adev->dev, "GPIO: _DSD returned %s %zd %llu %llu %llu\n", - dev_name(&adev->dev), args.nargs, - args.args[0], args.args[1], args.args[2]); + dev_dbg(&adev->dev, "GPIO: _DSD returned %s %d %d %u\n", + dev_name(&lookup.adev->dev), lookup.index, + lookup.pin_index, lookup.active_low); } else { dev_dbg(&adev->dev, "GPIO: looking up %d in _CRS\n", index); + lookup.adev = adev; } - INIT_LIST_HEAD(&resource_list); - ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio, - &lookup); - if (ret < 0) + ret = acpi_gpio_resource_lookup(&lookup, info); + return ret ? ERR_PTR(ret) : lookup.desc; +} + +/** + * acpi_node_get_gpiod() - get a GPIO descriptor from ACPI resources + * @fwnode: pointer to an ACPI firmware node to get the GPIO information from + * @propname: Property name of the GPIO + * @index: index of GpioIo/GpioInt resource (starting from %0) + * @info: info pointer to fill in (optional) + * + * If @fwnode is an ACPI device object, call %acpi_get_gpiod_by_index() for it. + * Otherwise (ie. it is a data-only non-device object), use the property-based + * GPIO lookup to get to the GPIO resource with the relevant information and use + * that to obtain the GPIO descriptor to return. + */ +struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode, + const char *propname, int index, + struct acpi_gpio_info *info) +{ + struct acpi_gpio_lookup lookup; + struct acpi_device *adev; + int ret; + + adev = to_acpi_device_node(fwnode); + if (adev) + return acpi_get_gpiod_by_index(adev, propname, index, info); + + if (!is_acpi_data_node(fwnode)) + return ERR_PTR(-ENODEV); + + if (!propname) + return ERR_PTR(-EINVAL); + + memset(&lookup, 0, sizeof(lookup)); + lookup.index = index; + + ret = acpi_gpio_property_lookup(fwnode, propname, index, &lookup); + if (ret) return ERR_PTR(ret); - acpi_dev_free_resource_list(&resource_list); + ret = acpi_gpio_resource_lookup(&lookup, info); + return ret ? ERR_PTR(ret) : lookup.desc; +} - if (lookup.desc && info) { - *info = lookup.info; - if (active_low) - info->active_low = active_low; - } +/** + * acpi_dev_gpio_irq_get() - Find GpioInt and translate it to Linux IRQ number + * @adev: pointer to a ACPI device to get IRQ from + * @index: index of GpioInt resource (starting from %0) + * + * If the device has one or more GpioInt resources, this function can be + * used to translate from the GPIO offset in the resource to the Linux IRQ + * number. + * + * Return: Linux IRQ number (>%0) on success, negative errno on failure. + */ +int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index) +{ + int idx, i; - return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT); + for (i = 0, idx = 0; idx <= index; i++) { + struct acpi_gpio_info info; + struct gpio_desc *desc; + + desc = acpi_get_gpiod_by_index(adev, NULL, i, &info); + if (IS_ERR(desc)) + break; + if (info.gpioint && idx++ == index) + return gpiod_to_irq(desc); + } + return -ENOENT; } +EXPORT_SYMBOL_GPL(acpi_dev_gpio_irq_get); static acpi_status acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, @@ -571,6 +667,25 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, break; } } + + /* + * The same GPIO can be shared between operation region and + * event but only if the access here is ACPI_READ. In that + * case we "borrow" the event GPIO instead. + */ + if (!found && agpio->sharable == ACPI_SHARED && + function == ACPI_READ) { + struct acpi_gpio_event *event; + + list_for_each_entry(event, &achip->events, node) { + if (event->pin == pin) { + desc = event->desc; + found = true; + break; + } + } + } + if (!found) { desc = gpiochip_request_own_desc(chip, pin, "ACPI:OpRegion"); @@ -687,6 +802,7 @@ void acpi_gpiochip_add(struct gpio_chip *chip) } acpi_gpio->chip = chip; + INIT_LIST_HEAD(&acpi_gpio->events); status = acpi_attach_data(handle, acpi_gpio_chip_dh, acpi_gpio); if (ACPI_FAILURE(status)) { diff --git a/kernel/drivers/gpio/gpiolib-legacy.c b/kernel/drivers/gpio/gpiolib-legacy.c index 8b830996f..3a5c7011a 100644 --- a/kernel/drivers/gpio/gpiolib-legacy.c +++ b/kernel/drivers/gpio/gpiolib-legacy.c @@ -28,10 +28,6 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) if (!desc && gpio_is_valid(gpio)) return -EPROBE_DEFER; - err = gpiod_request(desc, label); - if (err) - return err; - if (flags & GPIOF_OPEN_DRAIN) set_bit(FLAG_OPEN_DRAIN, &desc->flags); @@ -41,6 +37,10 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) if (flags & GPIOF_ACTIVE_LOW) set_bit(FLAG_ACTIVE_LOW, &desc->flags); + err = gpiod_request(desc, label); + if (err) + return err; + if (flags & GPIOF_DIR_IN) err = gpiod_direction_input(desc); else diff --git a/kernel/drivers/gpio/gpiolib-of.c b/kernel/drivers/gpio/gpiolib-of.c index a6c67c6b4..5fe34a9df 100644 --- a/kernel/drivers/gpio/gpiolib-of.c +++ b/kernel/drivers/gpio/gpiolib-of.c @@ -119,24 +119,23 @@ int of_get_named_gpio_flags(struct device_node *np, const char *list_name, EXPORT_SYMBOL(of_get_named_gpio_flags); /** - * of_get_gpio_hog() - Get a GPIO hog descriptor, names and flags for GPIO API + * of_parse_own_gpio() - Get a GPIO hog descriptor, names and flags for GPIO API * @np: device node to get GPIO from * @name: GPIO line name * @lflags: gpio_lookup_flags - returned from of_find_gpio() or - * of_get_gpio_hog() + * of_parse_own_gpio() * @dflags: gpiod_flags - optional GPIO initialization flags * * Returns GPIO descriptor to use with Linux GPIO API, or one of the errno * value on the error condition. */ -static struct gpio_desc *of_get_gpio_hog(struct device_node *np, - const char **name, - enum gpio_lookup_flags *lflags, - enum gpiod_flags *dflags) +static struct gpio_desc *of_parse_own_gpio(struct device_node *np, + const char **name, + enum gpio_lookup_flags *lflags, + enum gpiod_flags *dflags) { struct device_node *chip_np; enum of_gpio_flags xlate_flags; - struct gpio_desc *desc; struct gg_data gg_data = { .flags = &xlate_flags, }; @@ -193,19 +192,17 @@ static struct gpio_desc *of_get_gpio_hog(struct device_node *np, if (name && of_property_read_string(np, "line-name", name)) *name = np->name; - desc = gg_data.out_gpio; - - return desc; + return gg_data.out_gpio; } /** - * of_gpiochip_scan_hogs - Scan gpio-controller and apply GPIO hog as requested + * of_gpiochip_scan_gpios - Scan gpio-controller for gpio definitions * @chip: gpio chip to act on * * This is only used by of_gpiochip_add to request/set GPIO initial * configuration. */ -static void of_gpiochip_scan_hogs(struct gpio_chip *chip) +static void of_gpiochip_scan_gpios(struct gpio_chip *chip) { struct gpio_desc *desc = NULL; struct device_node *np; @@ -217,7 +214,7 @@ static void of_gpiochip_scan_hogs(struct gpio_chip *chip) if (!of_property_read_bool(np, "gpio-hog")) continue; - desc = of_get_gpio_hog(np, &name, &lflags, &dflags); + desc = of_parse_own_gpio(np, &name, &lflags, &dflags); if (IS_ERR(desc)) continue; @@ -242,7 +239,7 @@ int of_gpio_simple_xlate(struct gpio_chip *gc, { /* * We're discouraging gpio_cells < 2, since that way you'll have to - * write your own xlate function (that will have to retrive the GPIO + * write your own xlate function (that will have to retrieve the GPIO * number and the flags from a single gpio cell -- this is possible, * but not recommended). */ @@ -338,7 +335,7 @@ void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc) EXPORT_SYMBOL(of_mm_gpiochip_remove); #ifdef CONFIG_PINCTRL -static void of_gpiochip_add_pin_range(struct gpio_chip *chip) +static int of_gpiochip_add_pin_range(struct gpio_chip *chip) { struct device_node *np = chip->of_node; struct of_phandle_args pinspec; @@ -349,7 +346,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip) struct property *group_names; if (!np) - return; + return 0; group_names = of_find_property(np, group_names_propname, NULL); @@ -361,11 +358,11 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip) pctldev = of_pinctrl_get(pinspec.np); if (!pctldev) - break; + return -EPROBE_DEFER; if (pinspec.args[2]) { if (group_names) { - ret = of_property_read_string_index(np, + of_property_read_string_index(np, group_names_propname, index, &name); if (strlen(name)) { @@ -381,7 +378,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip) pinspec.args[1], pinspec.args[2]); if (ret) - break; + return ret; } else { /* npins == 0: special range */ if (pinspec.args[1]) { @@ -411,32 +408,41 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip) ret = gpiochip_add_pingroup_range(chip, pctldev, pinspec.args[0], name); if (ret) - break; + return ret; } } + + return 0; } #else -static void of_gpiochip_add_pin_range(struct gpio_chip *chip) {} +static int of_gpiochip_add_pin_range(struct gpio_chip *chip) { return 0; } #endif -void of_gpiochip_add(struct gpio_chip *chip) +int of_gpiochip_add(struct gpio_chip *chip) { + int status; + if ((!chip->of_node) && (chip->dev)) chip->of_node = chip->dev->of_node; if (!chip->of_node) - return; + return 0; if (!chip->of_xlate) { chip->of_gpio_n_cells = 2; chip->of_xlate = of_gpio_simple_xlate; } - of_gpiochip_add_pin_range(chip); + status = of_gpiochip_add_pin_range(chip); + if (status) + return status; + of_node_get(chip->of_node); - of_gpiochip_scan_hogs(chip); + of_gpiochip_scan_gpios(chip); + + return 0; } void of_gpiochip_remove(struct gpio_chip *chip) diff --git a/kernel/drivers/gpio/gpiolib-sysfs.c b/kernel/drivers/gpio/gpiolib-sysfs.c index af3bc7a80..b57ed8e55 100644 --- a/kernel/drivers/gpio/gpiolib-sysfs.c +++ b/kernel/drivers/gpio/gpiolib-sysfs.c @@ -6,14 +6,29 @@ #include <linux/gpio/driver.h> #include <linux/interrupt.h> #include <linux/kdev_t.h> +#include <linux/slab.h> #include "gpiolib.h" -static DEFINE_IDR(dirent_idr); +#define GPIO_IRQF_TRIGGER_FALLING BIT(0) +#define GPIO_IRQF_TRIGGER_RISING BIT(1) +#define GPIO_IRQF_TRIGGER_BOTH (GPIO_IRQF_TRIGGER_FALLING | \ + GPIO_IRQF_TRIGGER_RISING) +struct gpiod_data { + struct gpio_desc *desc; + + struct mutex mutex; + struct kernfs_node *value_kn; + int irq; + unsigned char irq_flags; -/* lock protects against unexport_gpio() being called while - * sysfs files are active. + bool direction_can_change; +}; + +/* + * Lock to serialise gpiod export and unexport, and prevent re-export of + * gpiod whose chip is being unregistered. */ static DEFINE_MUTEX(sysfs_lock); @@ -38,38 +53,35 @@ static DEFINE_MUTEX(sysfs_lock); * /edge configuration */ -static ssize_t gpio_direction_show(struct device *dev, +static ssize_t direction_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct gpio_desc *desc = dev_get_drvdata(dev); + struct gpiod_data *data = dev_get_drvdata(dev); + struct gpio_desc *desc = data->desc; ssize_t status; - mutex_lock(&sysfs_lock); + mutex_lock(&data->mutex); - if (!test_bit(FLAG_EXPORT, &desc->flags)) { - status = -EIO; - } else { - gpiod_get_direction(desc); - status = sprintf(buf, "%s\n", + gpiod_get_direction(desc); + status = sprintf(buf, "%s\n", test_bit(FLAG_IS_OUT, &desc->flags) ? "out" : "in"); - } - mutex_unlock(&sysfs_lock); + mutex_unlock(&data->mutex); + return status; } -static ssize_t gpio_direction_store(struct device *dev, +static ssize_t direction_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - struct gpio_desc *desc = dev_get_drvdata(dev); + struct gpiod_data *data = dev_get_drvdata(dev); + struct gpio_desc *desc = data->desc; ssize_t status; - mutex_lock(&sysfs_lock); + mutex_lock(&data->mutex); - if (!test_bit(FLAG_EXPORT, &desc->flags)) - status = -EIO; - else if (sysfs_streq(buf, "high")) + if (sysfs_streq(buf, "high")) status = gpiod_direction_output_raw(desc, 1); else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low")) status = gpiod_direction_output_raw(desc, 0); @@ -78,43 +90,40 @@ static ssize_t gpio_direction_store(struct device *dev, else status = -EINVAL; - mutex_unlock(&sysfs_lock); + mutex_unlock(&data->mutex); + return status ? : size; } +static DEVICE_ATTR_RW(direction); -static /* const */ DEVICE_ATTR(direction, 0644, - gpio_direction_show, gpio_direction_store); - -static ssize_t gpio_value_show(struct device *dev, +static ssize_t value_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct gpio_desc *desc = dev_get_drvdata(dev); + struct gpiod_data *data = dev_get_drvdata(dev); + struct gpio_desc *desc = data->desc; ssize_t status; - mutex_lock(&sysfs_lock); + mutex_lock(&data->mutex); - if (!test_bit(FLAG_EXPORT, &desc->flags)) - status = -EIO; - else - status = sprintf(buf, "%d\n", gpiod_get_value_cansleep(desc)); + status = sprintf(buf, "%d\n", gpiod_get_value_cansleep(desc)); + + mutex_unlock(&data->mutex); - mutex_unlock(&sysfs_lock); return status; } -static ssize_t gpio_value_store(struct device *dev, +static ssize_t value_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - struct gpio_desc *desc = dev_get_drvdata(dev); + struct gpiod_data *data = dev_get_drvdata(dev); + struct gpio_desc *desc = data->desc; ssize_t status; - mutex_lock(&sysfs_lock); + mutex_lock(&data->mutex); - if (!test_bit(FLAG_EXPORT, &desc->flags)) - status = -EIO; - else if (!test_bit(FLAG_IS_OUT, &desc->flags)) + if (!test_bit(FLAG_IS_OUT, &desc->flags)) { status = -EPERM; - else { + } else { long value; status = kstrtol(buf, 0, &value); @@ -124,172 +133,168 @@ static ssize_t gpio_value_store(struct device *dev, } } - mutex_unlock(&sysfs_lock); + mutex_unlock(&data->mutex); + return status; } - -static DEVICE_ATTR(value, 0644, - gpio_value_show, gpio_value_store); +static DEVICE_ATTR_RW(value); static irqreturn_t gpio_sysfs_irq(int irq, void *priv) { - struct kernfs_node *value_sd = priv; + struct gpiod_data *data = priv; + + sysfs_notify_dirent(data->value_kn); - sysfs_notify_dirent(value_sd); return IRQ_HANDLED; } -static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, - unsigned long gpio_flags) +/* Caller holds gpiod-data mutex. */ +static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags) { - struct kernfs_node *value_sd; + struct gpiod_data *data = dev_get_drvdata(dev); + struct gpio_desc *desc = data->desc; unsigned long irq_flags; - int ret, irq, id; + int ret; - if ((desc->flags & GPIO_TRIGGER_MASK) == gpio_flags) - return 0; - - irq = gpiod_to_irq(desc); - if (irq < 0) + data->irq = gpiod_to_irq(desc); + if (data->irq < 0) return -EIO; - id = desc->flags >> ID_SHIFT; - value_sd = idr_find(&dirent_idr, id); - if (value_sd) - free_irq(irq, value_sd); - - desc->flags &= ~GPIO_TRIGGER_MASK; - - if (!gpio_flags) { - gpiochip_unlock_as_irq(desc->chip, gpio_chip_hwgpio(desc)); - ret = 0; - goto free_id; - } + data->value_kn = sysfs_get_dirent(dev->kobj.sd, "value"); + if (!data->value_kn) + return -ENODEV; irq_flags = IRQF_SHARED; - if (test_bit(FLAG_TRIG_FALL, &gpio_flags)) + if (flags & GPIO_IRQF_TRIGGER_FALLING) irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ? IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING; - if (test_bit(FLAG_TRIG_RISE, &gpio_flags)) + if (flags & GPIO_IRQF_TRIGGER_RISING) irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING; - if (!value_sd) { - value_sd = sysfs_get_dirent(dev->kobj.sd, "value"); - if (!value_sd) { - ret = -ENODEV; - goto err_out; - } - - ret = idr_alloc(&dirent_idr, value_sd, 1, 0, GFP_KERNEL); - if (ret < 0) - goto free_sd; - id = ret; - - desc->flags &= GPIO_FLAGS_MASK; - desc->flags |= (unsigned long)id << ID_SHIFT; - - if (desc->flags >> ID_SHIFT != id) { - ret = -ERANGE; - goto free_id; - } - } + /* + * FIXME: This should be done in the irq_request_resources callback + * when the irq is requested, but a few drivers currently fail + * to do so. + * + * Remove this redundant call (along with the corresponding + * unlock) when those drivers have been fixed. + */ + ret = gpiochip_lock_as_irq(desc->chip, gpio_chip_hwgpio(desc)); + if (ret < 0) + goto err_put_kn; - ret = request_any_context_irq(irq, gpio_sysfs_irq, irq_flags, - "gpiolib", value_sd); + ret = request_any_context_irq(data->irq, gpio_sysfs_irq, irq_flags, + "gpiolib", data); if (ret < 0) - goto free_id; + goto err_unlock; - ret = gpiochip_lock_as_irq(desc->chip, gpio_chip_hwgpio(desc)); - if (ret < 0) { - gpiod_warn(desc, "failed to flag the GPIO for IRQ\n"); - goto free_id; - } + data->irq_flags = flags; - desc->flags |= gpio_flags; return 0; -free_id: - idr_remove(&dirent_idr, id); - desc->flags &= GPIO_FLAGS_MASK; -free_sd: - if (value_sd) - sysfs_put(value_sd); -err_out: +err_unlock: + gpiochip_unlock_as_irq(desc->chip, gpio_chip_hwgpio(desc)); +err_put_kn: + sysfs_put(data->value_kn); + return ret; } +/* + * Caller holds gpiod-data mutex (unless called after class-device + * deregistration). + */ +static void gpio_sysfs_free_irq(struct device *dev) +{ + struct gpiod_data *data = dev_get_drvdata(dev); + struct gpio_desc *desc = data->desc; + + data->irq_flags = 0; + free_irq(data->irq, data); + gpiochip_unlock_as_irq(desc->chip, gpio_chip_hwgpio(desc)); + sysfs_put(data->value_kn); +} + static const struct { const char *name; - unsigned long flags; + unsigned char flags; } trigger_types[] = { { "none", 0 }, - { "falling", BIT(FLAG_TRIG_FALL) }, - { "rising", BIT(FLAG_TRIG_RISE) }, - { "both", BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE) }, + { "falling", GPIO_IRQF_TRIGGER_FALLING }, + { "rising", GPIO_IRQF_TRIGGER_RISING }, + { "both", GPIO_IRQF_TRIGGER_BOTH }, }; -static ssize_t gpio_edge_show(struct device *dev, +static ssize_t edge_show(struct device *dev, struct device_attribute *attr, char *buf) { - const struct gpio_desc *desc = dev_get_drvdata(dev); - ssize_t status; + struct gpiod_data *data = dev_get_drvdata(dev); + ssize_t status = 0; + int i; - mutex_lock(&sysfs_lock); - - if (!test_bit(FLAG_EXPORT, &desc->flags)) - status = -EIO; - else { - int i; + mutex_lock(&data->mutex); - status = 0; - for (i = 0; i < ARRAY_SIZE(trigger_types); i++) - if ((desc->flags & GPIO_TRIGGER_MASK) - == trigger_types[i].flags) { - status = sprintf(buf, "%s\n", - trigger_types[i].name); - break; - } + for (i = 0; i < ARRAY_SIZE(trigger_types); i++) { + if (data->irq_flags == trigger_types[i].flags) { + status = sprintf(buf, "%s\n", trigger_types[i].name); + break; + } } - mutex_unlock(&sysfs_lock); + mutex_unlock(&data->mutex); + return status; } -static ssize_t gpio_edge_store(struct device *dev, +static ssize_t edge_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - struct gpio_desc *desc = dev_get_drvdata(dev); - ssize_t status; - int i; + struct gpiod_data *data = dev_get_drvdata(dev); + unsigned char flags; + ssize_t status = size; + int i; - for (i = 0; i < ARRAY_SIZE(trigger_types); i++) + for (i = 0; i < ARRAY_SIZE(trigger_types); i++) { if (sysfs_streq(trigger_types[i].name, buf)) - goto found; - return -EINVAL; + break; + } -found: - mutex_lock(&sysfs_lock); + if (i == ARRAY_SIZE(trigger_types)) + return -EINVAL; - if (!test_bit(FLAG_EXPORT, &desc->flags)) - status = -EIO; - else { - status = gpio_setup_irq(desc, dev, trigger_types[i].flags); + flags = trigger_types[i].flags; + + mutex_lock(&data->mutex); + + if (flags == data->irq_flags) { + status = size; + goto out_unlock; + } + + if (data->irq_flags) + gpio_sysfs_free_irq(dev); + + if (flags) { + status = gpio_sysfs_request_irq(dev, flags); if (!status) status = size; } - mutex_unlock(&sysfs_lock); +out_unlock: + mutex_unlock(&data->mutex); return status; } +static DEVICE_ATTR_RW(edge); -static DEVICE_ATTR(edge, 0644, gpio_edge_show, gpio_edge_store); - -static int sysfs_set_active_low(struct gpio_desc *desc, struct device *dev, - int value) +/* Caller holds gpiod-data mutex. */ +static int gpio_sysfs_set_active_low(struct device *dev, int value) { + struct gpiod_data *data = dev_get_drvdata(dev); + struct gpio_desc *desc = data->desc; int status = 0; + unsigned int flags = data->irq_flags; if (!!test_bit(FLAG_ACTIVE_LOW, &desc->flags) == !!value) return 0; @@ -300,69 +305,59 @@ static int sysfs_set_active_low(struct gpio_desc *desc, struct device *dev, clear_bit(FLAG_ACTIVE_LOW, &desc->flags); /* reconfigure poll(2) support if enabled on one edge only */ - if (dev != NULL && (!!test_bit(FLAG_TRIG_RISE, &desc->flags) ^ - !!test_bit(FLAG_TRIG_FALL, &desc->flags))) { - unsigned long trigger_flags = desc->flags & GPIO_TRIGGER_MASK; - - gpio_setup_irq(desc, dev, 0); - status = gpio_setup_irq(desc, dev, trigger_flags); + if (flags == GPIO_IRQF_TRIGGER_FALLING || + flags == GPIO_IRQF_TRIGGER_RISING) { + gpio_sysfs_free_irq(dev); + status = gpio_sysfs_request_irq(dev, flags); } return status; } -static ssize_t gpio_active_low_show(struct device *dev, +static ssize_t active_low_show(struct device *dev, struct device_attribute *attr, char *buf) { - const struct gpio_desc *desc = dev_get_drvdata(dev); + struct gpiod_data *data = dev_get_drvdata(dev); + struct gpio_desc *desc = data->desc; ssize_t status; - mutex_lock(&sysfs_lock); + mutex_lock(&data->mutex); - if (!test_bit(FLAG_EXPORT, &desc->flags)) - status = -EIO; - else - status = sprintf(buf, "%d\n", + status = sprintf(buf, "%d\n", !!test_bit(FLAG_ACTIVE_LOW, &desc->flags)); - mutex_unlock(&sysfs_lock); + mutex_unlock(&data->mutex); return status; } -static ssize_t gpio_active_low_store(struct device *dev, +static ssize_t active_low_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - struct gpio_desc *desc = dev_get_drvdata(dev); + struct gpiod_data *data = dev_get_drvdata(dev); ssize_t status; + long value; - mutex_lock(&sysfs_lock); + mutex_lock(&data->mutex); - if (!test_bit(FLAG_EXPORT, &desc->flags)) { - status = -EIO; - } else { - long value; + status = kstrtol(buf, 0, &value); + if (status == 0) + status = gpio_sysfs_set_active_low(dev, value); - status = kstrtol(buf, 0, &value); - if (status == 0) - status = sysfs_set_active_low(desc, dev, value != 0); - } - - mutex_unlock(&sysfs_lock); + mutex_unlock(&data->mutex); return status ? : size; } - -static DEVICE_ATTR(active_low, 0644, - gpio_active_low_show, gpio_active_low_store); +static DEVICE_ATTR_RW(active_low); static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr, int n) { struct device *dev = container_of(kobj, struct device, kobj); - struct gpio_desc *desc = dev_get_drvdata(dev); + struct gpiod_data *data = dev_get_drvdata(dev); + struct gpio_desc *desc = data->desc; umode_t mode = attr->mode; - bool show_direction = test_bit(FLAG_SYSFS_DIR, &desc->flags); + bool show_direction = data->direction_can_change; if (attr == &dev_attr_direction.attr) { if (!show_direction) @@ -402,32 +397,32 @@ static const struct attribute_group *gpio_groups[] = { * /ngpio ... matching gpio_chip.ngpio */ -static ssize_t chip_base_show(struct device *dev, +static ssize_t base_show(struct device *dev, struct device_attribute *attr, char *buf) { const struct gpio_chip *chip = dev_get_drvdata(dev); return sprintf(buf, "%d\n", chip->base); } -static DEVICE_ATTR(base, 0444, chip_base_show, NULL); +static DEVICE_ATTR_RO(base); -static ssize_t chip_label_show(struct device *dev, +static ssize_t label_show(struct device *dev, struct device_attribute *attr, char *buf) { const struct gpio_chip *chip = dev_get_drvdata(dev); return sprintf(buf, "%s\n", chip->label ? : ""); } -static DEVICE_ATTR(label, 0444, chip_label_show, NULL); +static DEVICE_ATTR_RO(label); -static ssize_t chip_ngpio_show(struct device *dev, +static ssize_t ngpio_show(struct device *dev, struct device_attribute *attr, char *buf) { const struct gpio_chip *chip = dev_get_drvdata(dev); return sprintf(buf, "%u\n", chip->ngpio); } -static DEVICE_ATTR(ngpio, 0444, chip_ngpio_show, NULL); +static DEVICE_ATTR_RO(ngpio); static struct attribute *gpiochip_attrs[] = { &dev_attr_base.attr, @@ -552,6 +547,7 @@ static struct class gpio_class = { int gpiod_export(struct gpio_desc *desc, bool direction_may_change) { struct gpio_chip *chip; + struct gpiod_data *data; unsigned long flags; int status; const char *ioname = NULL; @@ -574,9 +570,9 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) mutex_lock(&sysfs_lock); /* check if chip is being removed */ - if (!chip || !chip->exported) { + if (!chip || !chip->cdev) { status = -ENODEV; - goto fail_unlock; + goto err_unlock; } spin_lock_irqsave(&gpio_lock, flags); @@ -588,43 +584,54 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) test_bit(FLAG_REQUESTED, &desc->flags), test_bit(FLAG_EXPORT, &desc->flags)); status = -EPERM; - goto fail_unlock; + goto err_unlock; } + spin_unlock_irqrestore(&gpio_lock, flags); - if (desc->chip->direction_input && desc->chip->direction_output && - direction_may_change) { - set_bit(FLAG_SYSFS_DIR, &desc->flags); + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto err_unlock; } - spin_unlock_irqrestore(&gpio_lock, flags); + data->desc = desc; + mutex_init(&data->mutex); + if (chip->direction_input && chip->direction_output) + data->direction_can_change = direction_may_change; + else + data->direction_can_change = false; offset = gpio_chip_hwgpio(desc); - if (desc->chip->names && desc->chip->names[offset]) - ioname = desc->chip->names[offset]; + if (chip->names && chip->names[offset]) + ioname = chip->names[offset]; - dev = device_create_with_groups(&gpio_class, desc->chip->dev, - MKDEV(0, 0), desc, gpio_groups, + dev = device_create_with_groups(&gpio_class, chip->dev, + MKDEV(0, 0), data, gpio_groups, ioname ? ioname : "gpio%u", desc_to_gpio(desc)); if (IS_ERR(dev)) { status = PTR_ERR(dev); - goto fail_unlock; + goto err_free_data; } set_bit(FLAG_EXPORT, &desc->flags); mutex_unlock(&sysfs_lock); return 0; -fail_unlock: +err_free_data: + kfree(data); +err_unlock: mutex_unlock(&sysfs_lock); gpiod_dbg(desc, "%s: status %d\n", __func__, status); return status; } EXPORT_SYMBOL_GPL(gpiod_export); -static int match_export(struct device *dev, const void *data) +static int match_export(struct device *dev, const void *desc) { - return dev_get_drvdata(dev) == data; + struct gpiod_data *data = dev_get_drvdata(dev); + + return data->desc == desc; } /** @@ -641,82 +648,26 @@ static int match_export(struct device *dev, const void *data) int gpiod_export_link(struct device *dev, const char *name, struct gpio_desc *desc) { - int status = -EINVAL; + struct device *cdev; + int ret; if (!desc) { pr_warn("%s: invalid GPIO\n", __func__); return -EINVAL; } - mutex_lock(&sysfs_lock); - - if (test_bit(FLAG_EXPORT, &desc->flags)) { - struct device *tdev; - - tdev = class_find_device(&gpio_class, NULL, desc, match_export); - if (tdev != NULL) { - status = sysfs_create_link(&dev->kobj, &tdev->kobj, - name); - put_device(tdev); - } else { - status = -ENODEV; - } - } - - mutex_unlock(&sysfs_lock); + cdev = class_find_device(&gpio_class, NULL, desc, match_export); + if (!cdev) + return -ENODEV; - if (status) - gpiod_dbg(desc, "%s: status %d\n", __func__, status); + ret = sysfs_create_link(&dev->kobj, &cdev->kobj, name); + put_device(cdev); - return status; + return ret; } EXPORT_SYMBOL_GPL(gpiod_export_link); /** - * 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 - * - * Set the polarity of /sys/class/gpio/gpioN/value sysfs attribute. - * The GPIO does not have to be exported yet. If poll(2) support has - * been enabled for either rising or falling edge, it will be - * reconfigured to follow the new polarity. - * - * Returns zero on success, else an error. - */ -int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value) -{ - struct device *dev = NULL; - int status = -EINVAL; - - if (!desc) { - pr_warn("%s: invalid GPIO\n", __func__); - return -EINVAL; - } - - mutex_lock(&sysfs_lock); - - if (test_bit(FLAG_EXPORT, &desc->flags)) { - dev = class_find_device(&gpio_class, NULL, desc, match_export); - if (dev == NULL) { - status = -ENODEV; - goto unlock; - } - } - - status = sysfs_set_active_low(desc, dev, value); - put_device(dev); -unlock: - mutex_unlock(&sysfs_lock); - - if (status) - gpiod_dbg(desc, "%s: status %d\n", __func__, status); - - return status; -} -EXPORT_SYMBOL_GPL(gpiod_sysfs_set_active_low); - -/** * gpiod_unexport - reverse effect of gpio_export() * @gpio: gpio to make unavailable * @@ -724,8 +675,8 @@ EXPORT_SYMBOL_GPL(gpiod_sysfs_set_active_low); */ void gpiod_unexport(struct gpio_desc *desc) { - int status = 0; - struct device *dev = NULL; + struct gpiod_data *data; + struct device *dev; if (!desc) { pr_warn("%s: invalid GPIO\n", __func__); @@ -734,82 +685,79 @@ void gpiod_unexport(struct gpio_desc *desc) mutex_lock(&sysfs_lock); - if (test_bit(FLAG_EXPORT, &desc->flags)) { + if (!test_bit(FLAG_EXPORT, &desc->flags)) + goto err_unlock; - dev = class_find_device(&gpio_class, NULL, desc, match_export); - if (dev) { - gpio_setup_irq(desc, dev, 0); - clear_bit(FLAG_SYSFS_DIR, &desc->flags); - clear_bit(FLAG_EXPORT, &desc->flags); - } else - status = -ENODEV; - } + dev = class_find_device(&gpio_class, NULL, desc, match_export); + if (!dev) + goto err_unlock; + + data = dev_get_drvdata(dev); + + clear_bit(FLAG_EXPORT, &desc->flags); + + device_unregister(dev); + + /* + * Release irq after deregistration to prevent race with edge_store. + */ + if (data->irq_flags) + gpio_sysfs_free_irq(dev); mutex_unlock(&sysfs_lock); - if (dev) { - device_unregister(dev); - put_device(dev); - } + put_device(dev); + kfree(data); - if (status) - gpiod_dbg(desc, "%s: status %d\n", __func__, status); + return; + +err_unlock: + mutex_unlock(&sysfs_lock); } EXPORT_SYMBOL_GPL(gpiod_unexport); -int gpiochip_export(struct gpio_chip *chip) +int gpiochip_sysfs_register(struct gpio_chip *chip) { - int status; struct device *dev; - /* Many systems register gpio chips for SOC support very early, + /* + * Many systems add gpio chips for SOC support very early, * before driver model support is available. In those cases we - * export this later, in gpiolib_sysfs_init() ... here we just + * register later, in gpiolib_sysfs_init() ... here we just * verify that _some_ field of gpio_class got initialized. */ if (!gpio_class.p) return 0; /* use chip->base for the ID; it's already known to be unique */ - mutex_lock(&sysfs_lock); dev = device_create_with_groups(&gpio_class, chip->dev, MKDEV(0, 0), chip, gpiochip_groups, "gpiochip%d", chip->base); if (IS_ERR(dev)) - status = PTR_ERR(dev); - else - status = 0; - chip->exported = (status == 0); - mutex_unlock(&sysfs_lock); + return PTR_ERR(dev); - if (status) - chip_dbg(chip, "%s: status %d\n", __func__, status); + mutex_lock(&sysfs_lock); + chip->cdev = dev; + mutex_unlock(&sysfs_lock); - return status; + return 0; } -void gpiochip_unexport(struct gpio_chip *chip) +void gpiochip_sysfs_unregister(struct gpio_chip *chip) { - int status; - struct device *dev; struct gpio_desc *desc; unsigned int i; + if (!chip->cdev) + return; + + device_unregister(chip->cdev); + + /* prevent further gpiod exports */ mutex_lock(&sysfs_lock); - dev = class_find_device(&gpio_class, NULL, chip, match_export); - if (dev) { - put_device(dev); - device_unregister(dev); - /* prevent further gpiod exports */ - chip->exported = false; - status = 0; - } else - status = -ENODEV; + chip->cdev = NULL; mutex_unlock(&sysfs_lock); - if (status) - chip_dbg(chip, "%s: status %d\n", __func__, status); - /* unregister gpiod class devices owned by sysfs */ for (i = 0; i < chip->ngpio; i++) { desc = &chip->desc[i]; @@ -836,19 +784,20 @@ static int __init gpiolib_sysfs_init(void) */ spin_lock_irqsave(&gpio_lock, flags); list_for_each_entry(chip, &gpio_chips, list) { - if (chip->exported) + if (chip->cdev) continue; /* - * TODO we yield gpio_lock here because gpiochip_export() - * acquires a mutex. This is unsafe and needs to be fixed. + * TODO we yield gpio_lock here because + * gpiochip_sysfs_register() acquires a mutex. This is unsafe + * and needs to be fixed. * * Also it would be nice to use gpiochip_find() here so we * can keep gpio_chips local to gpiolib.c, but the yield of * gpio_lock prevents us from doing this. */ spin_unlock_irqrestore(&gpio_lock, flags); - status = gpiochip_export(chip); + status = gpiochip_sysfs_register(chip); spin_lock_irqsave(&gpio_lock, flags); } spin_unlock_irqrestore(&gpio_lock, flags); diff --git a/kernel/drivers/gpio/gpiolib.c b/kernel/drivers/gpio/gpiolib.c index 6bc612b8a..4e4c3083a 100644 --- a/kernel/drivers/gpio/gpiolib.c +++ b/kernel/drivers/gpio/gpiolib.c @@ -15,6 +15,7 @@ #include <linux/acpi.h> #include <linux/gpio/driver.h> #include <linux/gpio/machine.h> +#include <linux/pinctrl/consumer.h> #include "gpiolib.h" @@ -47,8 +48,6 @@ */ DEFINE_SPINLOCK(gpio_lock); -#define GPIO_OFFSET_VALID(chip, offset) (offset >= 0 && offset < chip->ngpio) - static DEFINE_MUTEX(gpio_lookup_lock); static LIST_HEAD(gpio_lookup_list); LIST_HEAD(gpio_chips); @@ -190,7 +189,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_direction); */ static int gpiochip_add_to_list(struct gpio_chip *chip) { - struct list_head *pos = &gpio_chips; + struct list_head *pos; struct gpio_chip *_chip; int err = 0; @@ -219,6 +218,68 @@ static int gpiochip_add_to_list(struct gpio_chip *chip) } /** + * Convert a GPIO name to its descriptor + */ +static struct gpio_desc *gpio_name_to_desc(const char * const name) +{ + struct gpio_chip *chip; + unsigned long flags; + + spin_lock_irqsave(&gpio_lock, flags); + + list_for_each_entry(chip, &gpio_chips, list) { + int i; + + for (i = 0; i != chip->ngpio; ++i) { + struct gpio_desc *gpio = &chip->desc[i]; + + if (!gpio->name || !name) + continue; + + if (!strcmp(gpio->name, name)) { + spin_unlock_irqrestore(&gpio_lock, flags); + return gpio; + } + } + } + + spin_unlock_irqrestore(&gpio_lock, flags); + + return NULL; +} + +/* + * Takes the names from gc->names and checks if they are all unique. If they + * are, they are assigned to their gpio descriptors. + * + * Returns -EEXIST if one of the names is already used for a different GPIO. + */ +static int gpiochip_set_desc_names(struct gpio_chip *gc) +{ + int i; + + if (!gc->names) + return 0; + + /* First check all names if they are unique */ + for (i = 0; i != gc->ngpio; ++i) { + struct gpio_desc *gpio; + + gpio = gpio_name_to_desc(gc->names[i]); + if (gpio) + dev_warn(gc->dev, "Detected name collision for " + "GPIO name '%s'\n", + gc->names[i]); + } + + /* Then add all names to the GPIO descriptors */ + for (i = 0; i != gc->ngpio; ++i) + gc->desc[i].name = gc->names[i]; + + return 0; +} + +/** * gpiochip_add() - register a gpio_chip * @chip: the chip to register, with chip->base initialized * Context: potentially before irqs will work @@ -287,10 +348,20 @@ int gpiochip_add(struct gpio_chip *chip) INIT_LIST_HEAD(&chip->pin_ranges); #endif - of_gpiochip_add(chip); + if (!chip->owner && chip->dev && chip->dev->driver) + chip->owner = chip->dev->driver->owner; + + status = gpiochip_set_desc_names(chip); + if (status) + goto err_remove_from_list; + + status = of_gpiochip_add(chip); + if (status) + goto err_remove_chip; + acpi_gpiochip_add(chip); - status = gpiochip_export(chip); + status = gpiochip_sysfs_register(chip); if (status) goto err_remove_chip; @@ -304,6 +375,7 @@ err_remove_chip: acpi_gpiochip_remove(chip); gpiochip_free_hogs(chip); of_gpiochip_remove(chip); +err_remove_from_list: spin_lock_irqsave(&gpio_lock, flags); list_del(&chip->list); spin_unlock_irqrestore(&gpio_lock, flags); @@ -327,10 +399,12 @@ EXPORT_SYMBOL_GPL(gpiochip_add); */ void gpiochip_remove(struct gpio_chip *chip) { + struct gpio_desc *desc; unsigned long flags; unsigned id; + bool requested = false; - gpiochip_unexport(chip); + gpiochip_sysfs_unregister(chip); gpiochip_irqchip_remove(chip); @@ -341,15 +415,17 @@ void gpiochip_remove(struct gpio_chip *chip) spin_lock_irqsave(&gpio_lock, flags); for (id = 0; id < chip->ngpio; id++) { - if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) - dev_crit(chip->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n"); + desc = &chip->desc[id]; + desc->chip = NULL; + if (test_bit(FLAG_REQUESTED, &desc->flags)) + requested = true; } - for (id = 0; id < chip->ngpio; id++) - chip->desc[id].chip = NULL; - list_del(&chip->list); spin_unlock_irqrestore(&gpio_lock, flags); + if (requested) + dev_crit(chip->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n"); + kfree(chip->desc); chip->desc = NULL; } @@ -439,8 +515,10 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, * The parent irqchip is already using the chip_data for this * irqchip, so our callbacks simply use the handler_data. */ - irq_set_handler_data(parent_irq, gpiochip); - irq_set_chained_handler(parent_irq, parent_handler); + irq_set_chained_handler_and_data(parent_irq, parent_handler, + gpiochip); + + gpiochip->irq_parent = parent_irq; } /* Set the parent IRQ for all affected IRQs */ @@ -450,12 +528,6 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, } EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip); -/* - * 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 gpiochip_irq_lock_class; - /** * gpiochip_irq_map() - maps an IRQ into a GPIO irqchip * @d: the irqdomain used by this irqchip @@ -472,16 +544,17 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, struct gpio_chip *chip = d->host_data; irq_set_chip_data(irq, chip); - irq_set_lockdep_class(irq, &gpiochip_irq_lock_class); + /* + * This lock class tells lockdep that GPIO irqs are in a different + * category than their parents, so it won't report false recursion. + */ + irq_set_lockdep_class(irq, chip->lock_key); irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler); /* Chips that can sleep need nested thread handlers */ if (chip->can_sleep && !chip->irq_not_threaded) irq_set_nested_thread(irq, 1); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else irq_set_noprobe(irq); -#endif + /* * No set-up of the hardware will happen if IRQ_TYPE_NONE * is passed as default type. @@ -496,9 +569,6 @@ static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq) { struct gpio_chip *chip = d->host_data; -#ifdef CONFIG_ARM - set_irq_flags(irq, 0); -#endif if (chip->can_sleep) irq_set_nested_thread(irq, 0); irq_set_chip_and_handler(irq, NULL, NULL); @@ -516,10 +586,14 @@ static int gpiochip_irq_reqres(struct irq_data *d) { struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + if (!try_module_get(chip->owner)) + return -ENODEV; + if (gpiochip_lock_as_irq(chip, d->hwirq)) { chip_err(chip, "unable to lock HW IRQ %lu for IRQ\n", d->hwirq); + module_put(chip->owner); return -EINVAL; } return 0; @@ -530,6 +604,7 @@ static void gpiochip_irq_relres(struct irq_data *d) struct gpio_chip *chip = irq_data_get_irq_chip_data(d); gpiochip_unlock_as_irq(chip, d->hwirq); + module_put(chip->owner); } static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset) @@ -549,6 +624,11 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) acpi_gpiochip_free_interrupts(gpiochip); + if (gpiochip->irq_parent) { + irq_set_chained_handler(gpiochip->irq_parent, NULL); + irq_set_handler_data(gpiochip->irq_parent, NULL); + } + /* Remove all IRQ mappings and delete the domain */ if (gpiochip->irqdomain) { for (offset = 0; offset < gpiochip->ngpio; offset++) @@ -573,6 +653,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) * @handler: the irq handler to use (often a predefined irq core function) * @type: the default type for IRQs on this irqchip, pass IRQ_TYPE_NONE * to have the core avoid setting up any default type in the hardware. + * @lock_key: lockdep class * * This function closely associates a certain irqchip with a certain * gpiochip, providing an irq domain to translate the local IRQs to @@ -588,11 +669,12 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) * the pins on the gpiochip can generate a unique IRQ. Everything else * need to be open coded. */ -int gpiochip_irqchip_add(struct gpio_chip *gpiochip, - struct irq_chip *irqchip, - unsigned int first_irq, - irq_flow_handler_t handler, - unsigned int type) +int _gpiochip_irqchip_add(struct gpio_chip *gpiochip, + struct irq_chip *irqchip, + unsigned int first_irq, + irq_flow_handler_t handler, + unsigned int type, + struct lock_class_key *lock_key) { struct device_node *of_node; unsigned int offset; @@ -608,7 +690,7 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip, of_node = gpiochip->dev->of_node; #ifdef CONFIG_OF_GPIO /* - * If the gpiochip has an assigned OF node this takes precendence + * If the gpiochip has an assigned OF node this takes precedence * FIXME: get rid of this and use gpiochip->dev->of_node everywhere */ if (gpiochip->of_node) @@ -618,6 +700,7 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip, gpiochip->irq_handler = handler; gpiochip->irq_default_type = type; gpiochip->to_irq = gpiochip_to_irq; + gpiochip->lock_key = lock_key; gpiochip->irqdomain = irq_domain_add_simple(of_node, gpiochip->ngpio, first_irq, &gpiochip_domain_ops, gpiochip); @@ -625,8 +708,16 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip, gpiochip->irqchip = NULL; return -EINVAL; } - irqchip->irq_request_resources = gpiochip_irq_reqres; - irqchip->irq_release_resources = gpiochip_irq_relres; + + /* + * It is possible for a driver to override this, but only if the + * alternative functions are both implemented. + */ + if (!irqchip->irq_request_resources && + !irqchip->irq_release_resources) { + irqchip->irq_request_resources = gpiochip_irq_reqres; + irqchip->irq_release_resources = gpiochip_irq_relres; + } /* * Prepare the mapping since the irqchip shall be orthogonal to @@ -647,7 +738,7 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip, return 0; } -EXPORT_SYMBOL_GPL(gpiochip_irqchip_add); +EXPORT_SYMBOL_GPL(_gpiochip_irqchip_add); #else /* CONFIG_GPIOLIB_IRQCHIP */ @@ -655,12 +746,34 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {} #endif /* CONFIG_GPIOLIB_IRQCHIP */ +/** + * gpiochip_generic_request() - request the gpio function for a pin + * @chip: the gpiochip owning the GPIO + * @offset: the offset of the GPIO to request for GPIO function + */ +int gpiochip_generic_request(struct gpio_chip *chip, unsigned offset) +{ + return pinctrl_request_gpio(chip->base + offset); +} +EXPORT_SYMBOL_GPL(gpiochip_generic_request); + +/** + * gpiochip_generic_free() - free the gpio function from a pin + * @chip: the gpiochip to request the gpio function for + * @offset: the offset of the GPIO to free from GPIO function + */ +void gpiochip_generic_free(struct gpio_chip *chip, unsigned offset) +{ + pinctrl_free_gpio(chip->base + offset); +} +EXPORT_SYMBOL_GPL(gpiochip_generic_free); + #ifdef CONFIG_PINCTRL /** * gpiochip_add_pingroup_range() - add a range for GPIO <-> pin mapping * @chip: the gpiochip to add the range for - * @pinctrl: the dev_name() of the pin controller to map to + * @pctldev: the pin controller to map to * @gpio_offset: the start offset in the current gpio_chip number space * @pin_group: name of the pin group inside the pin controller */ @@ -814,6 +927,14 @@ static int __gpiod_request(struct gpio_desc *desc, const char *label) spin_lock_irqsave(&gpio_lock, flags); } done: + if (status < 0) { + /* Clear flags that might have been set by the caller before + * requesting the GPIO. + */ + clear_bit(FLAG_ACTIVE_LOW, &desc->flags); + clear_bit(FLAG_OPEN_DRAIN, &desc->flags); + clear_bit(FLAG_OPEN_SOURCE, &desc->flags); + } spin_unlock_irqrestore(&gpio_lock, flags); return status; } @@ -903,7 +1024,7 @@ const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset) { struct gpio_desc *desc; - if (!GPIO_OFFSET_VALID(chip, offset)) + if (offset >= chip->ngpio) return NULL; desc = &chip->desc[offset]; @@ -1149,15 +1270,22 @@ EXPORT_SYMBOL_GPL(gpiod_is_active_low); * that the GPIO was actually requested. */ -static bool _gpiod_get_raw_value(const struct gpio_desc *desc) +static int _gpiod_get_raw_value(const struct gpio_desc *desc) { struct gpio_chip *chip; - bool value; int offset; + int value; chip = desc->chip; offset = gpio_chip_hwgpio(desc); - value = chip->get ? chip->get(chip, offset) : false; + value = chip->get ? chip->get(chip, offset) : -EIO; + /* + * FIXME: fix all drivers to clamp to [0,1] or return negative, + * then change this to: + * value = value < 0 ? value : !!value; + * so we can properly propagate error codes. + */ + value = !!value; trace_gpio_value(desc_to_gpio(desc), 1, value); return value; } @@ -1167,7 +1295,7 @@ static bool _gpiod_get_raw_value(const struct gpio_desc *desc) * @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. + * its ACTIVE_LOW status, or negative errno on failure. * * This function should be called from contexts where we cannot sleep, and will * complain if the GPIO chip functions potentially sleep. @@ -1187,7 +1315,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_value); * @desc: gpio whose value will be returned * * Return the GPIO's logical value, i.e. taking the ACTIVE_LOW status into - * account. + * account, or negative errno on failure. * * This function should be called from contexts where we cannot sleep, and will * complain if the GPIO chip functions potentially sleep. @@ -1201,6 +1329,9 @@ int gpiod_get_value(const struct gpio_desc *desc) WARN_ON(desc->chip->can_sleep); value = _gpiod_get_raw_value(desc); + if (value < 0) + return value; + if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) value = !value; @@ -1211,7 +1342,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_value); /* * _gpio_set_open_drain_value() - Set the open drain 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. + * @value: Non-zero for setting it HIGH otherwise it will set to LOW. */ static void _gpio_set_open_drain_value(struct gpio_desc *desc, bool value) { @@ -1238,7 +1369,7 @@ static void _gpio_set_open_drain_value(struct gpio_desc *desc, bool value) /* * _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. + * @value: Non-zero for setting it HIGH otherwise it will set to LOW. */ static void _gpio_set_open_source_value(struct gpio_desc *desc, bool value) { @@ -1300,17 +1431,16 @@ static void gpio_chip_set_multiple(struct gpio_chip *chip, continue; } /* set outputs if the corresponding mask bit is set */ - if (__test_and_clear_bit(i, mask)) { + if (__test_and_clear_bit(i, mask)) chip->set(chip, i, test_bit(i, bits)); - } } } } -static void gpiod_set_array_priv(bool raw, bool can_sleep, - unsigned int array_size, - struct gpio_desc **desc_array, - int *value_array) +static void gpiod_set_array_value_priv(bool raw, bool can_sleep, + unsigned int array_size, + struct gpio_desc **desc_array, + int *value_array) { int i = 0; @@ -1320,9 +1450,9 @@ static void gpiod_set_array_priv(bool raw, bool can_sleep, unsigned long bits[BITS_TO_LONGS(chip->ngpio)]; int count = 0; - if (!can_sleep) { + if (!can_sleep) WARN_ON(chip->can_sleep); - } + memset(mask, 0, sizeof(mask)); do { struct gpio_desc *desc = desc_array[i]; @@ -1337,24 +1467,22 @@ static void gpiod_set_array_priv(bool raw, bool can_sleep, * open drain and open source outputs are set individually */ if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) { - _gpio_set_open_drain_value(desc,value); + _gpio_set_open_drain_value(desc, value); } else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) { _gpio_set_open_source_value(desc, value); } else { __set_bit(hwgpio, mask); - if (value) { + if (value) __set_bit(hwgpio, bits); - } else { + else __clear_bit(hwgpio, bits); - } count++; } i++; } while ((i < array_size) && (desc_array[i]->chip == chip)); /* push collected bits to outputs */ - if (count != 0) { + if (count != 0) gpio_chip_set_multiple(chip, mask, bits); - } } } @@ -1403,7 +1531,7 @@ void gpiod_set_value(struct gpio_desc *desc, int value) EXPORT_SYMBOL_GPL(gpiod_set_value); /** - * gpiod_set_raw_array() - assign values to an array of GPIOs + * gpiod_set_raw_array_value() - assign values to an array of GPIOs * @array_size: number of elements in the descriptor / value arrays * @desc_array: array of GPIO descriptors whose values will be assigned * @value_array: array of values to assign @@ -1414,17 +1542,18 @@ EXPORT_SYMBOL_GPL(gpiod_set_value); * 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_array(unsigned int array_size, +void gpiod_set_raw_array_value(unsigned int array_size, struct gpio_desc **desc_array, int *value_array) { if (!desc_array) return; - gpiod_set_array_priv(true, false, array_size, desc_array, value_array); + gpiod_set_array_value_priv(true, false, array_size, desc_array, + value_array); } -EXPORT_SYMBOL_GPL(gpiod_set_raw_array); +EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value); /** - * gpiod_set_array() - assign values to an array of GPIOs + * gpiod_set_array_value() - assign values to an array of GPIOs * @array_size: number of elements in the descriptor / value arrays * @desc_array: array of GPIO descriptors whose values will be assigned * @value_array: array of values to assign @@ -1435,14 +1564,15 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_array); * This function should be called from contexts where we cannot sleep, and will * complain if the GPIO chip functions potentially sleep. */ -void gpiod_set_array(unsigned int array_size, - struct gpio_desc **desc_array, int *value_array) +void gpiod_set_array_value(unsigned int array_size, + struct gpio_desc **desc_array, int *value_array) { if (!desc_array) return; - gpiod_set_array_priv(false, false, array_size, desc_array, value_array); + gpiod_set_array_value_priv(false, false, array_size, desc_array, + value_array); } -EXPORT_SYMBOL_GPL(gpiod_set_array); +EXPORT_SYMBOL_GPL(gpiod_set_array_value); /** * gpiod_cansleep() - report whether gpio value access may sleep @@ -1524,7 +1654,7 @@ EXPORT_SYMBOL_GPL(gpiochip_unlock_as_irq); * @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. + * its ACTIVE_LOW status, or negative errno on failure. * * This function is to be called from contexts that can sleep. */ @@ -1542,7 +1672,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_value_cansleep); * @desc: gpio whose value will be returned * * Return the GPIO's logical value, i.e. taking the ACTIVE_LOW status into - * account. + * account, or negative errno on failure. * * This function is to be called from contexts that can sleep. */ @@ -1555,6 +1685,9 @@ int gpiod_get_value_cansleep(const struct gpio_desc *desc) return 0; value = _gpiod_get_raw_value(desc); + if (value < 0) + return value; + if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) value = !value; @@ -1604,7 +1737,7 @@ void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep); /** - * gpiod_set_raw_array_cansleep() - assign values to an array of GPIOs + * gpiod_set_raw_array_value_cansleep() - assign values to an array of GPIOs * @array_size: number of elements in the descriptor / value arrays * @desc_array: array of GPIO descriptors whose values will be assigned * @value_array: array of values to assign @@ -1614,19 +1747,20 @@ EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep); * * This function is to be called from contexts that can sleep. */ -void gpiod_set_raw_array_cansleep(unsigned int array_size, - struct gpio_desc **desc_array, - int *value_array) +void gpiod_set_raw_array_value_cansleep(unsigned int array_size, + struct gpio_desc **desc_array, + int *value_array) { might_sleep_if(extra_checks); if (!desc_array) return; - gpiod_set_array_priv(true, true, array_size, desc_array, value_array); + gpiod_set_array_value_priv(true, true, array_size, desc_array, + value_array); } -EXPORT_SYMBOL_GPL(gpiod_set_raw_array_cansleep); +EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value_cansleep); /** - * gpiod_set_array_cansleep() - assign values to an array of GPIOs + * gpiod_set_array_value_cansleep() - assign values to an array of GPIOs * @array_size: number of elements in the descriptor / value arrays * @desc_array: array of GPIO descriptors whose values will be assigned * @value_array: array of values to assign @@ -1636,16 +1770,17 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_array_cansleep); * * This function is to be called from contexts that can sleep. */ -void gpiod_set_array_cansleep(unsigned int array_size, - struct gpio_desc **desc_array, - int *value_array) +void gpiod_set_array_value_cansleep(unsigned int array_size, + struct gpio_desc **desc_array, + int *value_array) { might_sleep_if(extra_checks); if (!desc_array) return; - gpiod_set_array_priv(false, true, array_size, desc_array, value_array); + gpiod_set_array_value_priv(false, true, array_size, desc_array, + value_array); } -EXPORT_SYMBOL_GPL(gpiod_set_array_cansleep); +EXPORT_SYMBOL_GPL(gpiod_set_array_value_cansleep); /** * gpiod_add_lookup_table() - register GPIO device consumers @@ -1660,6 +1795,19 @@ void gpiod_add_lookup_table(struct gpiod_lookup_table *table) mutex_unlock(&gpio_lookup_lock); } +/** + * gpiod_remove_lookup_table() - unregister GPIO device consumers + * @table: table of consumers to unregister + */ +void gpiod_remove_lookup_table(struct gpiod_lookup_table *table) +{ + mutex_lock(&gpio_lookup_lock); + + list_del(&table->list); + + mutex_unlock(&gpio_lookup_lock); +} + static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, unsigned int idx, enum gpio_lookup_flags *flags) @@ -1689,6 +1837,13 @@ static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, if (of_flags & OF_GPIO_ACTIVE_LOW) *flags |= GPIO_ACTIVE_LOW; + if (of_flags & OF_GPIO_SINGLE_ENDED) { + if (of_flags & OF_GPIO_ACTIVE_LOW) + *flags |= GPIO_OPEN_DRAIN; + else + *flags |= GPIO_OPEN_SOURCE; + } + return desc; } @@ -1880,14 +2035,14 @@ EXPORT_SYMBOL_GPL(gpiod_count); * * Return the GPIO descriptor corresponding to the function con_id of device * dev, -ENOENT if no GPIO has been assigned to the requested function, or - * another IS_ERR() code if an error occured while trying to acquire the GPIO. + * another IS_ERR() code if an error occurred while trying to acquire the GPIO. */ -struct gpio_desc *__must_check __gpiod_get(struct device *dev, const char *con_id, +struct gpio_desc *__must_check gpiod_get(struct device *dev, const char *con_id, enum gpiod_flags flags) { return gpiod_get_index(dev, con_id, 0, flags); } -EXPORT_SYMBOL_GPL(__gpiod_get); +EXPORT_SYMBOL_GPL(gpiod_get); /** * gpiod_get_optional - obtain an optional GPIO for a given GPIO function @@ -1899,21 +2054,36 @@ EXPORT_SYMBOL_GPL(__gpiod_get); * the requested function it will return NULL. This is convenient for drivers * that need to handle optional GPIOs. */ -struct gpio_desc *__must_check __gpiod_get_optional(struct device *dev, +struct gpio_desc *__must_check gpiod_get_optional(struct device *dev, const char *con_id, enum gpiod_flags flags) { return gpiod_get_index_optional(dev, con_id, 0, flags); } -EXPORT_SYMBOL_GPL(__gpiod_get_optional); +EXPORT_SYMBOL_GPL(gpiod_get_optional); +/** + * gpiod_parse_flags - helper function to parse GPIO lookup flags + * @desc: gpio to be setup + * @lflags: gpio_lookup_flags - returned from of_find_gpio() or + * of_get_gpio_hog() + * + * Set the GPIO descriptor flags based on the given GPIO lookup flags. + */ +static void gpiod_parse_flags(struct gpio_desc *desc, unsigned long lflags) +{ + if (lflags & GPIO_ACTIVE_LOW) + set_bit(FLAG_ACTIVE_LOW, &desc->flags); + if (lflags & GPIO_OPEN_DRAIN) + set_bit(FLAG_OPEN_DRAIN, &desc->flags); + if (lflags & GPIO_OPEN_SOURCE) + set_bit(FLAG_OPEN_SOURCE, &desc->flags); +} /** * gpiod_configure_flags - helper function to configure a given GPIO * @desc: gpio whose value will be assigned * @con_id: function within the GPIO consumer - * @lflags: gpio_lookup_flags - returned from of_find_gpio() or - * of_get_gpio_hog() * @dflags: gpiod_flags - optional GPIO initialization flags * * Return 0 on success, -ENOENT if no GPIO has been assigned to the @@ -1921,17 +2091,10 @@ EXPORT_SYMBOL_GPL(__gpiod_get_optional); * occurred while trying to acquire the GPIO. */ static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, - unsigned long lflags, enum gpiod_flags dflags) + enum gpiod_flags dflags) { int status; - if (lflags & GPIO_ACTIVE_LOW) - set_bit(FLAG_ACTIVE_LOW, &desc->flags); - if (lflags & GPIO_OPEN_DRAIN) - set_bit(FLAG_OPEN_DRAIN, &desc->flags); - if (lflags & GPIO_OPEN_SOURCE) - set_bit(FLAG_OPEN_SOURCE, &desc->flags); - /* No particular flag request, return here... */ if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) { pr_debug("no flags found for %s\n", con_id); @@ -1960,9 +2123,9 @@ static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, * * Return a valid GPIO descriptor, -ENOENT if no GPIO has been assigned to the * requested function and/or index, or another IS_ERR() code if an error - * occured while trying to acquire the GPIO. + * occurred while trying to acquire the GPIO. */ -struct gpio_desc *__must_check __gpiod_get_index(struct device *dev, +struct gpio_desc *__must_check gpiod_get_index(struct device *dev, const char *con_id, unsigned int idx, enum gpiod_flags flags) @@ -1998,11 +2161,13 @@ struct gpio_desc *__must_check __gpiod_get_index(struct device *dev, return desc; } + gpiod_parse_flags(desc, lookupflags); + status = gpiod_request(desc, con_id); if (status < 0) return ERR_PTR(status); - status = gpiod_configure_flags(desc, con_id, lookupflags, flags); + status = gpiod_configure_flags(desc, con_id, flags); if (status < 0) { dev_dbg(dev, "setup of GPIO %s failed\n", con_id); gpiod_put(desc); @@ -2011,7 +2176,7 @@ struct gpio_desc *__must_check __gpiod_get_index(struct device *dev, return desc; } -EXPORT_SYMBOL_GPL(__gpiod_get_index); +EXPORT_SYMBOL_GPL(gpiod_get_index); /** * fwnode_get_named_gpiod - obtain a GPIO from firmware node @@ -2032,6 +2197,7 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, { struct gpio_desc *desc = ERR_PTR(-ENODEV); bool active_low = false; + bool single_ended = false; int ret; if (!fwnode) @@ -2040,15 +2206,16 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, if (is_of_node(fwnode)) { enum of_gpio_flags flags; - desc = of_get_named_gpiod_flags(of_node(fwnode), propname, 0, + desc = of_get_named_gpiod_flags(to_of_node(fwnode), propname, 0, &flags); - if (!IS_ERR(desc)) + if (!IS_ERR(desc)) { active_low = flags & OF_GPIO_ACTIVE_LOW; + single_ended = flags & OF_GPIO_SINGLE_ENDED; + } } else if (is_acpi_node(fwnode)) { struct acpi_gpio_info info; - desc = acpi_get_gpiod_by_index(acpi_node(fwnode), propname, 0, - &info); + desc = acpi_node_get_gpiod(fwnode, propname, 0, &info); if (!IS_ERR(desc)) active_low = info.active_low; } @@ -2056,14 +2223,20 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, if (IS_ERR(desc)) return desc; + if (active_low) + set_bit(FLAG_ACTIVE_LOW, &desc->flags); + + if (single_ended) { + if (active_low) + set_bit(FLAG_OPEN_DRAIN, &desc->flags); + else + set_bit(FLAG_OPEN_SOURCE, &desc->flags); + } + ret = gpiod_request(desc, NULL); if (ret) return ERR_PTR(ret); - /* Only value flag can be set from both DT and ACPI is active_low */ - if (active_low) - set_bit(FLAG_ACTIVE_LOW, &desc->flags); - return desc; } EXPORT_SYMBOL_GPL(fwnode_get_named_gpiod); @@ -2080,7 +2253,7 @@ EXPORT_SYMBOL_GPL(fwnode_get_named_gpiod); * specified index was assigned to the requested function it will return NULL. * This is convenient for drivers that need to handle optional GPIOs. */ -struct gpio_desc *__must_check __gpiod_get_index_optional(struct device *dev, +struct gpio_desc *__must_check gpiod_get_index_optional(struct device *dev, const char *con_id, unsigned int index, enum gpiod_flags flags) @@ -2095,7 +2268,7 @@ struct gpio_desc *__must_check __gpiod_get_index_optional(struct device *dev, return desc; } -EXPORT_SYMBOL_GPL(__gpiod_get_index_optional); +EXPORT_SYMBOL_GPL(gpiod_get_index_optional); /** * gpiod_hog - Hog the specified GPIO desc given the provided flags @@ -2116,15 +2289,19 @@ int gpiod_hog(struct gpio_desc *desc, const char *name, chip = gpiod_to_chip(desc); hwnum = gpio_chip_hwgpio(desc); + gpiod_parse_flags(desc, lflags); + local_desc = gpiochip_request_own_desc(chip, hwnum, name); if (IS_ERR(local_desc)) { - pr_debug("requesting own GPIO %s failed\n", name); + pr_err("requesting hog GPIO %s (chip %s, offset %d) failed\n", + name, chip->label, hwnum); return PTR_ERR(local_desc); } - status = gpiod_configure_flags(desc, name, lflags, dflags); + status = gpiod_configure_flags(desc, name, dflags); if (status < 0) { - pr_debug("setup of GPIO %s failed\n", name); + pr_err("setup of hog GPIO %s (chip %s, offset %d) failed\n", + name, chip->label, hwnum); gpiochip_free_own_desc(desc); return status; } @@ -2261,14 +2438,19 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) int is_irq; for (i = 0; i < chip->ngpio; i++, gpio++, gdesc++) { - if (!test_bit(FLAG_REQUESTED, &gdesc->flags)) + if (!test_bit(FLAG_REQUESTED, &gdesc->flags)) { + if (gdesc->name) { + seq_printf(s, " gpio-%-3d (%-20.20s)\n", + gpio, gdesc->name); + } continue; + } gpiod_get_direction(gdesc); is_out = test_bit(FLAG_IS_OUT, &gdesc->flags); is_irq = test_bit(FLAG_USED_AS_IRQ, &gdesc->flags); - seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s", - gpio, gdesc->label, + seq_printf(s, " gpio-%-3d (%-20.20s|%-20.20s) %s %s %s", + gpio, gdesc->name ? gdesc->name : "", gdesc->label, is_out ? "out" : "in ", chip->get ? (chip->get(chip, i) ? "hi" : "lo") diff --git a/kernel/drivers/gpio/gpiolib.h b/kernel/drivers/gpio/gpiolib.h index 594b1798c..98ab08c0a 100644 --- a/kernel/drivers/gpio/gpiolib.h +++ b/kernel/drivers/gpio/gpiolib.h @@ -42,6 +42,9 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip); struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev, const char *propname, int index, struct acpi_gpio_info *info); +struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode, + const char *propname, int index, + struct acpi_gpio_info *info); int acpi_gpio_count(struct device *dev, const char *con_id); #else @@ -60,7 +63,12 @@ acpi_get_gpiod_by_index(struct acpi_device *adev, const char *propname, { return ERR_PTR(-ENOSYS); } - +static inline struct gpio_desc * +acpi_node_get_gpiod(struct fwnode_handle *fwnode, const char *propname, + int index, struct acpi_gpio_info *info) +{ + return ERR_PTR(-ENXIO); +} static inline int acpi_gpio_count(struct device *dev, const char *con_id) { return -ENODEV; @@ -83,21 +91,16 @@ struct gpio_desc { #define FLAG_IS_OUT 1 #define FLAG_EXPORT 2 /* protected by sysfs_lock */ #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 /* 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 FLAG_SYSFS_DIR 10 /* show sysfs direction attribute */ #define FLAG_IS_HOGGED 11 /* GPIO is hogged */ -#define ID_SHIFT 16 /* add new flags before this one */ - -#define GPIO_FLAGS_MASK ((1 << ID_SHIFT) - 1) -#define GPIO_TRIGGER_MASK (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE)) - + /* Connection label */ const char *label; + /* Name of the GPIO */ + const char *name; }; int gpiod_request(struct gpio_desc *desc, const char *label); @@ -151,17 +154,17 @@ static int __maybe_unused gpio_chip_hwgpio(const struct gpio_desc *desc) #ifdef CONFIG_GPIO_SYSFS -int gpiochip_export(struct gpio_chip *chip); -void gpiochip_unexport(struct gpio_chip *chip); +int gpiochip_sysfs_register(struct gpio_chip *chip); +void gpiochip_sysfs_unregister(struct gpio_chip *chip); #else -static inline int gpiochip_export(struct gpio_chip *chip) +static inline int gpiochip_sysfs_register(struct gpio_chip *chip) { return 0; } -static inline void gpiochip_unexport(struct gpio_chip *chip) +static inline void gpiochip_sysfs_unregister(struct gpio_chip *chip) { } |