summaryrefslogtreecommitdiff
path: root/drivers/gpio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/Kconfig196
-rw-r--r--drivers/gpio/Makefile5
-rw-r--r--drivers/gpio/gpio-104-idio-16.c216
-rw-r--r--drivers/gpio/gpio-74x164.c1
-rw-r--r--drivers/gpio/gpio-74xx-mmio.c7
-rw-r--r--drivers/gpio/gpio-altera.c15
-rw-r--r--drivers/gpio/gpio-amdpt.c261
-rw-r--r--drivers/gpio/gpio-arizona.c2
-rw-r--r--drivers/gpio/gpio-ath79.c119
-rw-r--r--drivers/gpio/gpio-etraxfs.c23
-rw-r--r--drivers/gpio/gpio-generic.c62
-rw-r--r--drivers/gpio/gpio-it87.c411
-rw-r--r--drivers/gpio/gpio-it8761e.c230
-rw-r--r--drivers/gpio/gpio-lpc18xx.c14
-rw-r--r--drivers/gpio/gpio-max7301.c1
-rw-r--r--drivers/gpio/gpio-max730x.c1
-rw-r--r--drivers/gpio/gpio-mc33880.c1
-rw-r--r--drivers/gpio/gpio-mcp23s08.c2
-rw-r--r--drivers/gpio/gpio-moxart.c14
-rw-r--r--drivers/gpio/gpio-msm-v2.c453
-rw-r--r--drivers/gpio/gpio-mvebu.c14
-rw-r--r--drivers/gpio/gpio-mxc.c2
-rw-r--r--drivers/gpio/gpio-omap.c84
-rw-r--r--drivers/gpio/gpio-palmas.c2
-rw-r--r--drivers/gpio/gpio-pca953x.c45
-rw-r--r--drivers/gpio/gpio-pl061.c112
-rw-r--r--drivers/gpio/gpio-sodaville.c2
-rw-r--r--drivers/gpio/gpio-sx150x.c31
-rw-r--r--drivers/gpio/gpio-syscon.c6
-rw-r--r--drivers/gpio/gpio-tb10x.c14
-rw-r--r--drivers/gpio/gpio-tegra.c105
-rw-r--r--drivers/gpio/gpio-tz1090-pdc.c14
-rw-r--r--drivers/gpio/gpio-vf610.c43
-rw-r--r--drivers/gpio/gpio-xlp.c21
-rw-r--r--drivers/gpio/gpio-zx.c28
-rw-r--r--drivers/gpio/gpio-zynq.c32
-rw-r--r--drivers/gpio/gpiolib-acpi.c217
-rw-r--r--drivers/gpio/gpiolib-legacy.c8
-rw-r--r--drivers/gpio/gpiolib-of.c20
-rw-r--r--drivers/gpio/gpiolib.c189
-rw-r--r--drivers/gpio/gpiolib.h21
41 files changed, 1778 insertions, 1266 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 8949b3f6f..b18bea08f 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -119,6 +119,13 @@ config GPIO_ALTERA
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)
@@ -176,16 +183,6 @@ config GPIO_ETRAXFS
help
Say yes here to support the GPIO controller on Axis ETRAX FS SoCs.
-config GPIO_F7188X
- tristate "F71869, F71869A, F71882FG and F71889F GPIO support"
- depends on X86
- 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_GE_FPGA
bool "GE FPGA based GPIO"
depends on GE_FPGA
@@ -235,12 +232,6 @@ 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
@@ -297,14 +288,6 @@ 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
@@ -368,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
@@ -440,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
@@ -508,13 +446,13 @@ 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
+ depends on CPU_XLP && OF_GPIO
select GPIOLIB_IRQCHIP
help
This driver provides support for GPIO interface on Netlogic XLP MIPS64
@@ -545,6 +483,87 @@ config GPIO_ZYNQ
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"
@@ -552,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.
@@ -566,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
@@ -578,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
@@ -618,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
@@ -646,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
@@ -976,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
@@ -984,32 +998,28 @@ 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_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.
-config GPIO_ZX
- bool "ZTE ZX GPIO support"
- select GPIOLIB_IRQCHIP
+endmenu
+
+menu "SPI or I2C GPIO expanders"
+ depends on (SPI_MASTER && !I2C) || I2C
+
+config GPIO_MCP23S08
+ tristate "Microchip MCP23xxx I/O expander"
help
- Say yes here to support the GPIO device on ZTE ZX SoCs.
+ 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.
endmenu
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index f79a7c482..986dbd838 100644
--- a/drivers/gpio/Makefile
+++ b/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,6 +20,7 @@ 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
@@ -40,7 +42,7 @@ 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
@@ -64,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
diff --git a/drivers/gpio/gpio-104-idio-16.c b/drivers/gpio/gpio-104-idio-16.c
new file mode 100644
index 000000000..5400d7d4d
--- /dev/null
+++ b/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/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c
index e3d968f75..60172f835 100644
--- a/drivers/gpio/gpio-74x164.c
+++ b/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/drivers/gpio/gpio-74xx-mmio.c b/drivers/gpio/gpio-74xx-mmio.c
index 6ed7c0fb3..6b1868290 100644
--- a/drivers/gpio/gpio-74xx-mmio.c
+++ b/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;
diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c
index 1b4494157..3e6661bab 100644
--- a/drivers/gpio/gpio-altera.c
+++ b/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;
@@ -210,7 +215,7 @@ static void altera_gpio_irq_edge_handler(struct irq_desc *desc)
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;
@@ -239,7 +244,7 @@ static void altera_gpio_irq_leveL_high_handler(struct irq_desc *desc)
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;
diff --git a/drivers/gpio/gpio-amdpt.c b/drivers/gpio/gpio-amdpt.c
new file mode 100644
index 000000000..cbbb966d4
--- /dev/null
+++ b/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/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c
index 052fbc8fd..ca0027396 100644
--- a/drivers/gpio/gpio-arizona.c
+++ b/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/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c
index 03b995304..5eaea8b81 100644
--- a/drivers/gpio/gpio-ath79.c
+++ b/drivers/gpio/gpio-ath79.c
@@ -12,61 +12,51 @@
* by the Free Software Foundation.
*/
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/spinlock.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/platform_data/gpio-ath79.h>
#include <linux/of_device.h>
#include <asm/mach-ath79/ar71xx_regs.h>
-static void __iomem *ath79_gpio_base;
-static u32 ath79_gpio_count;
-static DEFINE_SPINLOCK(ath79_gpio_lock);
+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(unsigned gpio, int value)
+static void ath79_gpio_set_value(struct gpio_chip *chip,
+ unsigned gpio, int value)
{
- void __iomem *base = ath79_gpio_base;
+ struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip);
if (value)
- __raw_writel(1 << gpio, base + AR71XX_GPIO_REG_SET);
+ __raw_writel(BIT(gpio), ctrl->base + AR71XX_GPIO_REG_SET);
else
- __raw_writel(1 << gpio, base + AR71XX_GPIO_REG_CLEAR);
+ __raw_writel(BIT(gpio), ctrl->base + AR71XX_GPIO_REG_CLEAR);
}
-static int __ath79_gpio_get_value(unsigned gpio)
+static int ath79_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
{
- return (__raw_readl(ath79_gpio_base + AR71XX_GPIO_REG_IN) >> gpio) & 1;
-}
+ struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip);
-static int ath79_gpio_get_value(struct gpio_chip *chip, unsigned offset)
-{
- return __ath79_gpio_get_value(offset);
-}
-
-static void ath79_gpio_set_value(struct gpio_chip *chip,
- unsigned offset, int value)
-{
- __ath79_gpio_set_value(offset, value);
+ return (__raw_readl(ctrl->base + AR71XX_GPIO_REG_IN) >> gpio) & 1;
}
static int ath79_gpio_direction_input(struct gpio_chip *chip,
unsigned offset)
{
- void __iomem *base = ath79_gpio_base;
+ struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip);
unsigned long flags;
- spin_lock_irqsave(&ath79_gpio_lock, flags);
+ spin_lock_irqsave(&ctrl->lock, flags);
- __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << offset),
- base + AR71XX_GPIO_REG_OE);
+ __raw_writel(
+ __raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) & ~BIT(offset),
+ ctrl->base + AR71XX_GPIO_REG_OE);
- spin_unlock_irqrestore(&ath79_gpio_lock, flags);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
return 0;
}
@@ -74,35 +64,37 @@ static int ath79_gpio_direction_input(struct gpio_chip *chip,
static int ath79_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
- void __iomem *base = ath79_gpio_base;
+ struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip);
unsigned long flags;
- spin_lock_irqsave(&ath79_gpio_lock, flags);
+ spin_lock_irqsave(&ctrl->lock, flags);
if (value)
- __raw_writel(1 << offset, base + AR71XX_GPIO_REG_SET);
+ __raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_SET);
else
- __raw_writel(1 << offset, base + AR71XX_GPIO_REG_CLEAR);
+ __raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_CLEAR);
- __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) | (1 << offset),
- base + AR71XX_GPIO_REG_OE);
+ __raw_writel(
+ __raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) | BIT(offset),
+ ctrl->base + AR71XX_GPIO_REG_OE);
- spin_unlock_irqrestore(&ath79_gpio_lock, flags);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
return 0;
}
static int ar934x_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
- void __iomem *base = ath79_gpio_base;
+ struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip);
unsigned long flags;
- spin_lock_irqsave(&ath79_gpio_lock, flags);
+ spin_lock_irqsave(&ctrl->lock, flags);
- __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) | (1 << offset),
- base + AR71XX_GPIO_REG_OE);
+ __raw_writel(
+ __raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) | BIT(offset),
+ ctrl->base + AR71XX_GPIO_REG_OE);
- spin_unlock_irqrestore(&ath79_gpio_lock, flags);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
return 0;
}
@@ -110,25 +102,26 @@ static int ar934x_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
static int ar934x_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
int value)
{
- void __iomem *base = ath79_gpio_base;
+ struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip);
unsigned long flags;
- spin_lock_irqsave(&ath79_gpio_lock, flags);
+ spin_lock_irqsave(&ctrl->lock, flags);
if (value)
- __raw_writel(1 << offset, base + AR71XX_GPIO_REG_SET);
+ __raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_SET);
else
- __raw_writel(1 << offset, base + AR71XX_GPIO_REG_CLEAR);
+ __raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_CLEAR);
- __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << offset),
- base + AR71XX_GPIO_REG_OE);
+ __raw_writel(
+ __raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) & ~BIT(offset),
+ ctrl->base + AR71XX_GPIO_REG_OE);
- spin_unlock_irqrestore(&ath79_gpio_lock, flags);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
return 0;
}
-static struct gpio_chip ath79_gpio_chip = {
+static const struct gpio_chip ath79_gpio_chip = {
.label = "ath79",
.get = ath79_gpio_get_value,
.set = ath79_gpio_set_value,
@@ -147,10 +140,16 @@ 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) {
@@ -171,19 +170,21 @@ static int ath79_gpio_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- ath79_gpio_base = devm_ioremap_nocache(
+ ctrl->base = devm_ioremap_nocache(
&pdev->dev, res->start, resource_size(res));
- if (!ath79_gpio_base)
+ if (!ctrl->base)
return -ENOMEM;
- ath79_gpio_chip.dev = &pdev->dev;
- ath79_gpio_chip.ngpio = ath79_gpio_count;
+ 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) {
- ath79_gpio_chip.direction_input = ar934x_gpio_direction_input;
- ath79_gpio_chip.direction_output = ar934x_gpio_direction_output;
+ ctrl->chip.direction_input = ar934x_gpio_direction_input;
+ ctrl->chip.direction_output = ar934x_gpio_direction_output;
}
- err = gpiochip_add(&ath79_gpio_chip);
+ err = gpiochip_add(&ctrl->chip);
if (err) {
dev_err(&pdev->dev,
"cannot add AR71xx GPIO chip, error=%d", err);
diff --git a/drivers/gpio/gpio-etraxfs.c b/drivers/gpio/gpio-etraxfs.c
index 2ffcd9fdd..5c15dd121 100644
--- a/drivers/gpio/gpio-etraxfs.c
+++ b/drivers/gpio/gpio-etraxfs.c
@@ -176,6 +176,11 @@ static const struct etraxfs_gpio_info etraxfs_gpio_artpec3 = {
.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';
@@ -220,7 +225,8 @@ static unsigned int etraxfs_gpio_to_group_pin(struct etraxfs_gpio_chip *chip,
static void etraxfs_gpio_irq_ack(struct irq_data *d)
{
- struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_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);
@@ -229,7 +235,8 @@ static void etraxfs_gpio_irq_ack(struct irq_data *d)
static void etraxfs_gpio_irq_mask(struct irq_data *d)
{
- struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_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);
@@ -241,7 +248,8 @@ static void etraxfs_gpio_irq_mask(struct irq_data *d)
static void etraxfs_gpio_irq_unmask(struct irq_data *d)
{
- struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_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);
@@ -253,7 +261,8 @@ static void etraxfs_gpio_irq_unmask(struct irq_data *d)
static int etraxfs_gpio_irq_set_type(struct irq_data *d, u32 type)
{
- struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_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);
u32 cfg;
@@ -289,7 +298,8 @@ static int etraxfs_gpio_irq_set_type(struct irq_data *d, u32 type)
static int etraxfs_gpio_irq_request_resources(struct irq_data *d)
{
- struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_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;
@@ -319,7 +329,8 @@ out:
static void etraxfs_gpio_irq_release_resources(struct irq_data *d)
{
- struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_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);
diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c
index a3f07537f..88ae70ddb 100644
--- a/drivers/gpio/gpio-generic.c
+++ b/drivers/gpio/gpio-generic.c
@@ -141,9 +141,9 @@ static int bgpio_get_set(struct gpio_chip *gc, unsigned int gpio)
unsigned long pinmask = bgc->pin2mask(bgc, gpio);
if (bgc->dir & pinmask)
- return bgc->read_reg(bgc->reg_set) & pinmask;
+ return !!(bgc->read_reg(bgc->reg_set) & pinmask);
else
- return bgc->read_reg(bgc->reg_dat) & pinmask;
+ return !!(bgc->read_reg(bgc->reg_dat) & pinmask);
}
static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
@@ -579,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)
@@ -636,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/drivers/gpio/gpio-it87.c b/drivers/gpio/gpio-it87.c
new file mode 100644
index 000000000..21f6f7c0e
--- /dev/null
+++ b/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/drivers/gpio/gpio-it8761e.c b/drivers/gpio/gpio-it8761e.c
deleted file mode 100644
index 30a8f24c9..000000000
--- a/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/drivers/gpio/gpio-lpc18xx.c b/drivers/gpio/gpio-lpc18xx.c
index eb6860313..e39dcb0af 100644
--- a/drivers/gpio/gpio-lpc18xx.c
+++ b/drivers/gpio/gpio-lpc18xx.c
@@ -36,16 +36,6 @@ static inline struct lpc18xx_gpio_chip *to_lpc18xx_gpio(struct gpio_chip *chip)
return container_of(chip, struct lpc18xx_gpio_chip, gpio);
}
-static int lpc18xx_gpio_request(struct gpio_chip *chip, unsigned offset)
-{
- return pinctrl_request_gpio(offset);
-}
-
-static void lpc18xx_gpio_free(struct gpio_chip *chip, unsigned offset)
-{
- pinctrl_free_gpio(offset);
-}
-
static void lpc18xx_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct lpc18xx_gpio_chip *gc = to_lpc18xx_gpio(chip);
@@ -95,8 +85,8 @@ static int lpc18xx_gpio_direction_output(struct gpio_chip *chip,
static struct gpio_chip lpc18xx_chip = {
.label = "lpc18xx/43xx-gpio",
- .request = lpc18xx_gpio_request,
- .free = lpc18xx_gpio_free,
+ .request = gpiochip_generic_request,
+ .free = gpiochip_generic_free,
.direction_input = lpc18xx_gpio_direction_input,
.direction_output = lpc18xx_gpio_direction_output,
.set = lpc18xx_gpio_set,
diff --git a/drivers/gpio/gpio-max7301.c b/drivers/gpio/gpio-max7301.c
index 6e1c984a7..05813fbf3 100644
--- a/drivers/gpio/gpio-max7301.c
+++ b/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/drivers/gpio/gpio-max730x.c b/drivers/gpio/gpio-max730x.c
index 18ab89e20..0f57d2d24 100644
--- a/drivers/gpio/gpio-max730x.c
+++ b/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/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c
index a431604c9..2853731db 100644
--- a/drivers/gpio/gpio-mc33880.c
+++ b/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/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c
index 73db7ecd7..4a4169491 100644
--- a/drivers/gpio/gpio-mcp23s08.c
+++ b/drivers/gpio/gpio-mcp23s08.c
@@ -848,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,
@@ -1021,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/drivers/gpio/gpio-moxart.c b/drivers/gpio/gpio-moxart.c
index abd8676ce..d3355a6dc 100644
--- a/drivers/gpio/gpio-moxart.c
+++ b/drivers/gpio/gpio-moxart.c
@@ -29,16 +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_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -66,8 +56,8 @@ static int moxart_gpio_probe(struct platform_device *pdev)
}
bgc->gc.label = "moxart-gpio";
- bgc->gc.request = moxart_gpio_request;
- bgc->gc.free = moxart_gpio_free;
+ 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/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c
deleted file mode 100644
index 4b4222145..000000000
--- a/drivers/gpio/gpio-msm-v2.c
+++ /dev/null
@@ -1,453 +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);
-}
-
-/* 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 = d->hwirq;
-
- 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)
-{
- unsigned long irq_flags;
- int gpio = d->hwirq;
-
- 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)
-{
- unsigned long irq_flags;
- int gpio = d->hwirq;
-
- 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)
-{
- unsigned long irq_flags;
- int gpio = d->hwirq;
- 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, 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, 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(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 = d->hwirq;
-
- 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);
-
- 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/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index df418b814..d428b9787 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/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 =
@@ -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;
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index b8dd84744..6ea8df6c7 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/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 */
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 5236db161..f7fbb46d5 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -51,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;
@@ -59,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;
@@ -496,9 +497,6 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
(type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)))
return -EINVAL;
- if (!BANK_USED(bank))
- pm_runtime_get_sync(bank->dev);
-
raw_spin_lock_irqsave(&bank->lock, flags);
retval = omap_set_gpio_triggering(bank, offset, type);
if (retval) {
@@ -521,8 +519,6 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
return 0;
error:
- if (!BANK_USED(bank))
- pm_runtime_put(bank->dev);
return retval;
}
@@ -654,8 +650,13 @@ 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)
@@ -709,26 +710,21 @@ 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(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_desc_get_handler_data(desc);
+ 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;
@@ -750,13 +746,6 @@ static void omap_gpio_irq_handler(struct irq_desc *desc)
raw_spin_unlock_irqrestore(&bank->lock, lock_flags);
- /* 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);
- }
-
if (!isr)
break;
@@ -777,18 +766,18 @@ static void omap_gpio_irq_handler(struct irq_desc *desc)
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)
@@ -797,9 +786,6 @@ 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);
if (!LINE_USED(bank->mod_usage, offset))
@@ -815,8 +801,6 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d)
return 0;
err:
raw_spin_unlock_irqrestore(&bank->lock, flags);
- if (!BANK_USED(bank))
- pm_runtime_put(bank->dev);
return -EINVAL;
}
@@ -835,6 +819,19 @@ static void omap_gpio_irq_shutdown(struct irq_data *d)
omap_clear_gpio_debounce(bank, offset);
omap_disable_gpio_module(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,
@@ -1125,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) {
@@ -1141,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[];
@@ -1183,6 +1182,8 @@ 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);
bank->irq = platform_get_irq(pdev, 0);
@@ -1224,6 +1225,7 @@ 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);
diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c
index 171a6389f..52b447c07 100644
--- a/drivers/gpio/gpio-palmas.c
+++ b/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/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 50caeb1ee..2d4892cc7 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/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)
@@ -517,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:
@@ -581,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;
@@ -635,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 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:
@@ -673,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);
@@ -693,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;
@@ -765,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/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index 229ef653e..4d4b37676 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/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);
@@ -198,7 +215,6 @@ static void pl061_irq_handler(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/drivers/gpio/gpio-sodaville.c b/drivers/gpio/gpio-sodaville.c
index 65bc9f47a..34b02b42a 100644
--- a/drivers/gpio/gpio-sodaville.c
+++ b/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)
diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c
index 9c6b96707..76f920173 100644
--- a/drivers/gpio/gpio-sx150x.c
+++ b/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)
diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c
index 045a95257..7b25fdf64 100644
--- a/drivers/gpio/gpio-syscon.c
+++ b/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/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c
index 12c99d969..4356e6c20 100644
--- a/drivers/gpio/gpio-tb10x.c
+++ b/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;
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 027e5f47d..896bf2977 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -375,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,
@@ -519,6 +573,8 @@ static int tegra_gpio_probe(struct platform_device *pdev)
spin_lock_init(&bank->lvl_lock[j]);
}
+ tegra_gpio_debuginit();
+
return 0;
}
@@ -536,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/drivers/gpio/gpio-tz1090-pdc.c b/drivers/gpio/gpio-tz1090-pdc.c
index ede7e403f..3623d009d 100644
--- a/drivers/gpio/gpio-tz1090-pdc.c
+++ b/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/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c
index 069f9e4b7..87b950cec 100644
--- a/drivers/gpio/gpio-vf610.c
+++ b/drivers/gpio/gpio-vf610.c
@@ -62,6 +62,11 @@ struct vf610_gpio_port {
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 */ }
@@ -77,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)
@@ -122,7 +115,8 @@ static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
static void vf610_gpio_irq_handler(struct irq_desc *desc)
{
- struct vf610_gpio_port *port = irq_desc_get_handler_data(desc);
+ 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;
@@ -142,7 +136,8 @@ static void vf610_gpio_irq_handler(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);
@@ -150,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) {
@@ -185,7 +181,8 @@ static int vf610_gpio_irq_set_type(struct irq_data *d, u32 type)
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);
@@ -193,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,
@@ -202,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);
@@ -255,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;
diff --git a/drivers/gpio/gpio-xlp.c b/drivers/gpio/gpio-xlp.c
index e02499a15..bc06a2cd2 100644
--- a/drivers/gpio/gpio-xlp.c
+++ b/drivers/gpio/gpio-xlp.c
@@ -18,6 +18,7 @@
#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
@@ -208,25 +209,28 @@ static struct irq_chip xlp_gpio_irq_chip = {
.flags = IRQCHIP_ONESHOT_SAFE,
};
-static irqreturn_t xlp_gpio_generic_handler(int irq, void *data)
+static void xlp_gpio_generic_handler(struct irq_desc *desc)
{
- struct xlp_gpio_priv *priv = data;
+ 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));
}
-
- return IRQ_HANDLED;
+ chained_irq_exit(irqchip, desc);
}
static int xlp_gpio_dir_output(struct gpio_chip *gc, unsigned gpio, int state)
@@ -378,12 +382,6 @@ static int xlp_gpio_probe(struct platform_device *pdev)
gc->get = xlp_gpio_get;
spin_lock_init(&priv->lock);
-
- err = devm_request_irq(&pdev->dev, irq, xlp_gpio_generic_handler,
- IRQ_TYPE_NONE, pdev->name, priv);
- if (err)
- return err;
-
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");
@@ -401,6 +399,9 @@ static int xlp_gpio_probe(struct platform_device *pdev)
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;
diff --git a/drivers/gpio/gpio-zx.c b/drivers/gpio/gpio-zx.c
index 4b8a26910..1dcf7a66d 100644
--- a/drivers/gpio/gpio-zx.c
+++ b/drivers/gpio/gpio-zx.c
@@ -41,7 +41,6 @@ struct zx_gpio {
void __iomem *base;
struct gpio_chip gc;
- bool uses_pinctrl;
};
static inline struct zx_gpio *to_zx(struct gpio_chip *gc)
@@ -49,25 +48,6 @@ static inline struct zx_gpio *to_zx(struct gpio_chip *gc)
return container_of(gc, struct zx_gpio, gc);
}
-static int zx_gpio_request(struct gpio_chip *gc, unsigned offset)
-{
- struct zx_gpio *chip = to_zx(gc);
- int gpio = gc->base + offset;
-
- if (chip->uses_pinctrl)
- return pinctrl_request_gpio(gpio);
- return 0;
-}
-
-static void zx_gpio_free(struct gpio_chip *gc, unsigned offset)
-{
- struct zx_gpio *chip = to_zx(gc);
- int gpio = gc->base + offset;
-
- if (chip->uses_pinctrl)
- pinctrl_free_gpio(gpio);
-}
-
static int zx_direction_input(struct gpio_chip *gc, unsigned offset)
{
struct zx_gpio *chip = to_zx(gc);
@@ -252,12 +232,12 @@ static int zx_gpio_probe(struct platform_device *pdev)
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;
+ }
id = of_alias_get_id(dev->of_node, "gpio");
- chip->gc.request = zx_gpio_request;
- chip->gc.free = zx_gpio_free;
chip->gc.direction_input = zx_direction_input;
chip->gc.direction_output = zx_direction_output;
chip->gc.get = zx_get_value;
diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c
index 1d1a5865e..8abeacac5 100644
--- a/drivers/gpio/gpio-zynq.c
+++ b/drivers/gpio/gpio-zynq.c
@@ -130,6 +130,12 @@ struct zynq_platform_data {
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
@@ -177,7 +183,7 @@ 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, gpio);
@@ -201,7 +207,7 @@ 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, gpio);
@@ -238,7 +244,7 @@ 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, gpio);
@@ -271,7 +277,7 @@ 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, gpio);
@@ -301,7 +307,8 @@ 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, gpio);
@@ -321,7 +328,8 @@ 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, gpio);
@@ -340,7 +348,8 @@ 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, gpio);
@@ -390,7 +399,8 @@ 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, gpio);
@@ -453,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);
@@ -518,7 +529,8 @@ static void zynq_gpio_irqhandler(struct irq_desc *desc)
{
u32 int_sts, int_enb;
unsigned int bank_num;
- struct zynq_gpio *gpio = irq_desc_get_handler_data(desc);
+ 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);
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index 143a9bdba..7ab7bc3c9 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -304,7 +304,6 @@ 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);
}
@@ -389,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;
};
@@ -425,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
@@ -452,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)
@@ -463,58 +521,64 @@ 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)
- return ERR_PTR(ret);
+ 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;
- acpi_dev_free_resource_list(&resource_list);
+ adev = to_acpi_device_node(fwnode);
+ if (adev)
+ return acpi_get_gpiod_by_index(adev, propname, index, info);
- if (lookup.desc && info) {
- *info = lookup.info;
- if (active_low)
- info->active_low = active_low;
- }
+ 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);
- return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT);
+ ret = acpi_gpio_resource_lookup(&lookup, info);
+ return ret ? ERR_PTR(ret) : lookup.desc;
}
/**
@@ -603,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");
@@ -719,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)) {
@@ -838,3 +922,46 @@ int acpi_gpio_count(struct device *dev, const char *con_id)
}
return count;
}
+
+struct acpi_crs_lookup {
+ struct list_head node;
+ struct acpi_device *adev;
+ const char *con_id;
+};
+
+static DEFINE_MUTEX(acpi_crs_lookup_lock);
+static LIST_HEAD(acpi_crs_lookup_list);
+
+bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id)
+{
+ struct acpi_crs_lookup *l, *lookup = NULL;
+
+ /* Never allow fallback if the device has properties */
+ if (adev->data.properties || adev->driver_gpios)
+ return false;
+
+ mutex_lock(&acpi_crs_lookup_lock);
+
+ list_for_each_entry(l, &acpi_crs_lookup_list, node) {
+ if (l->adev == adev) {
+ lookup = l;
+ break;
+ }
+ }
+
+ if (!lookup) {
+ lookup = kmalloc(sizeof(*lookup), GFP_KERNEL);
+ if (lookup) {
+ lookup->adev = adev;
+ lookup->con_id = con_id;
+ list_add_tail(&lookup->node, &acpi_crs_lookup_list);
+ }
+ }
+
+ mutex_unlock(&acpi_crs_lookup_lock);
+
+ return lookup &&
+ ((!lookup->con_id && !con_id) ||
+ (lookup->con_id && con_id &&
+ strcmp(lookup->con_id, con_id) == 0));
+}
diff --git a/drivers/gpio/gpiolib-legacy.c b/drivers/gpio/gpiolib-legacy.c
index 8b830996f..3a5c7011a 100644
--- a/drivers/gpio/gpiolib-legacy.c
+++ b/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/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index fa6e3c882..5fe34a9df 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -119,20 +119,20 @@ 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;
@@ -196,13 +196,13 @@ static struct gpio_desc *of_get_gpio_hog(struct device_node *np,
}
/**
- * 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;
@@ -214,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;
@@ -440,7 +440,7 @@ int of_gpiochip_add(struct gpio_chip *chip)
of_node_get(chip->of_node);
- of_gpiochip_scan_hogs(chip);
+ of_gpiochip_scan_gpios(chip);
return 0;
}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 5db344555..a3ad3bab2 100644
--- a/drivers/gpio/gpiolib.c
+++ b/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);
@@ -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
@@ -290,6 +351,10 @@ int gpiochip_add(struct gpio_chip *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;
@@ -310,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);
@@ -680,6 +746,28 @@ 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
/**
@@ -839,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;
}
@@ -928,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];
@@ -1183,7 +1279,13 @@ static int _gpiod_get_raw_value(const struct gpio_desc *desc)
chip = desc->chip;
offset = gpio_chip_hwgpio(desc);
value = chip->get ? chip->get(chip, offset) : -EIO;
- value = value < 0 ? value : !!value;
+ /*
+ * 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;
}
@@ -1735,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;
}
@@ -1765,6 +1874,9 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
/* Then from plain _CRS GPIOs */
if (IS_ERR(desc)) {
+ if (!acpi_can_fallback_to_crs(adev, con_id))
+ return ERR_PTR(-ENOENT);
+
desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info);
if (IS_ERR(desc))
return desc;
@@ -1953,13 +2065,28 @@ struct gpio_desc *__must_check gpiod_get_optional(struct device *dev,
}
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
@@ -1967,17 +2094,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);
@@ -2044,11 +2164,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);
@@ -2078,6 +2200,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)
@@ -2088,13 +2211,14 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
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(to_acpi_node(fwnode), propname, 0,
- &info);
+ desc = acpi_node_get_gpiod(fwnode, propname, 0, &info);
if (!IS_ERR(desc))
active_low = info.active_low;
}
@@ -2102,14 +2226,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);
@@ -2162,6 +2292,8 @@ 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_err("requesting hog GPIO %s (chip %s, offset %d) failed\n",
@@ -2169,7 +2301,7 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
return PTR_ERR(local_desc);
}
- status = gpiod_configure_flags(desc, name, lflags, dflags);
+ status = gpiod_configure_flags(desc, name, dflags);
if (status < 0) {
pr_err("setup of hog GPIO %s (chip %s, offset %d) failed\n",
name, chip->label, hwnum);
@@ -2309,14 +2441,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/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index bf343004b..2b87cbd68 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -42,8 +42,13 @@ 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);
+
+bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id);
#else
static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { }
@@ -60,11 +65,22 @@ 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;
}
+
+static inline bool acpi_can_fallback_to_crs(struct acpi_device *adev,
+ const char *con_id)
+{
+ return false;
+}
#endif
struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
@@ -89,7 +105,10 @@ struct gpio_desc {
#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */
#define FLAG_IS_HOGGED 11 /* GPIO is hogged */
+ /* Connection label */
const char *label;
+ /* Name of the GPIO */
+ const char *name;
};
int gpiod_request(struct gpio_desc *desc, const char *label);