summaryrefslogtreecommitdiffstats
path: root/drivers/gpio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/Kconfig43
-rw-r--r--drivers/gpio/Makefile6
-rw-r--r--drivers/gpio/devres.c67
-rw-r--r--drivers/gpio/gpio-74x164.c8
-rw-r--r--drivers/gpio/gpio-adnp.c9
-rw-r--r--drivers/gpio/gpio-adp5520.c12
-rw-r--r--drivers/gpio/gpio-adp5588.c10
-rw-r--r--drivers/gpio/gpio-amd8111.c3
-rw-r--r--drivers/gpio/gpio-arizona.c3
-rw-r--r--drivers/gpio/gpio-bt8xx.c19
-rw-r--r--drivers/gpio/gpio-crystalcove.c380
-rw-r--r--drivers/gpio/gpio-cs5535.c8
-rw-r--r--drivers/gpio/gpio-da9052.c3
-rw-r--r--drivers/gpio/gpio-da9055.c3
-rw-r--r--drivers/gpio/gpio-davinci.c4
-rw-r--r--drivers/gpio/gpio-dwapb.c40
-rw-r--r--drivers/gpio/gpio-em.c8
-rw-r--r--drivers/gpio/gpio-ep93xx.c34
-rw-r--r--drivers/gpio/gpio-f7188x.c18
-rw-r--r--drivers/gpio/gpio-ge.c174
-rw-r--r--drivers/gpio/gpio-generic.c12
-rw-r--r--drivers/gpio/gpio-grgpio.c6
-rw-r--r--drivers/gpio/gpio-ich.c9
-rw-r--r--drivers/gpio/gpio-intel-mid.c86
-rw-r--r--drivers/gpio/gpio-it8761e.c6
-rw-r--r--drivers/gpio/gpio-janz-ttl.c46
-rw-r--r--drivers/gpio/gpio-kempld.c7
-rw-r--r--drivers/gpio/gpio-lp3943.c3
-rw-r--r--drivers/gpio/gpio-lpc32xx.c2
-rw-r--r--drivers/gpio/gpio-lynxpoint.c102
-rw-r--r--drivers/gpio/gpio-max730x.c14
-rw-r--r--drivers/gpio/gpio-max732x.c7
-rw-r--r--drivers/gpio/gpio-mc33880.c11
-rw-r--r--drivers/gpio/gpio-mc9s08dz60.c3
-rw-r--r--drivers/gpio/gpio-mcp23s08.c37
-rw-r--r--drivers/gpio/gpio-ml-ioh.c8
-rw-r--r--drivers/gpio/gpio-moxart.c4
-rw-r--r--drivers/gpio/gpio-msm-v2.c5
-rw-r--r--drivers/gpio/gpio-mvebu.c13
-rw-r--r--drivers/gpio/gpio-mxc.c2
-rw-r--r--drivers/gpio/gpio-octeon.c3
-rw-r--r--drivers/gpio/gpio-omap.c452
-rw-r--r--drivers/gpio/gpio-palmas.c9
-rw-r--r--drivers/gpio/gpio-pca953x.c109
-rw-r--r--drivers/gpio/gpio-pcf857x.c15
-rw-r--r--drivers/gpio/gpio-pch.c11
-rw-r--r--drivers/gpio/gpio-pl061.c27
-rw-r--r--drivers/gpio/gpio-pxa.c7
-rw-r--r--drivers/gpio/gpio-rc5t583.c7
-rw-r--r--drivers/gpio/gpio-rcar.c19
-rw-r--r--drivers/gpio/gpio-rdc321x.c30
-rw-r--r--drivers/gpio/gpio-samsung.c965
-rw-r--r--drivers/gpio/gpio-sch.c42
-rw-r--r--drivers/gpio/gpio-sch311x.c22
-rw-r--r--drivers/gpio/gpio-sodaville.c4
-rw-r--r--drivers/gpio/gpio-spear-spics.c4
-rw-r--r--drivers/gpio/gpio-stmpe.c135
-rw-r--r--drivers/gpio/gpio-sx150x.c8
-rw-r--r--drivers/gpio/gpio-syscon.c3
-rw-r--r--drivers/gpio/gpio-tb10x.c5
-rw-r--r--drivers/gpio/gpio-tc3589x.c156
-rw-r--r--drivers/gpio/gpio-tegra.c6
-rw-r--r--drivers/gpio/gpio-timberdale.c52
-rw-r--r--drivers/gpio/gpio-tps6586x.c7
-rw-r--r--drivers/gpio/gpio-tps65910.c7
-rw-r--r--drivers/gpio/gpio-tps65912.c3
-rw-r--r--drivers/gpio/gpio-ts5500.c6
-rw-r--r--drivers/gpio/gpio-twl4030.c6
-rw-r--r--drivers/gpio/gpio-twl6040.c3
-rw-r--r--drivers/gpio/gpio-ucb1400.c4
-rw-r--r--drivers/gpio/gpio-viperboard.c10
-rw-r--r--drivers/gpio/gpio-vr41xx.c8
-rw-r--r--drivers/gpio/gpio-vx855.c3
-rw-r--r--drivers/gpio/gpio-wm831x.c3
-rw-r--r--drivers/gpio/gpio-wm8350.c3
-rw-r--r--drivers/gpio/gpio-wm8994.c3
-rw-r--r--drivers/gpio/gpio-xilinx.c2
-rw-r--r--drivers/gpio/gpio-zevio.c18
-rw-r--r--drivers/gpio/gpio-zynq.c692
-rw-r--r--drivers/gpio/gpiolib-acpi.c49
-rw-r--r--drivers/gpio/gpiolib-legacy.c102
-rw-r--r--drivers/gpio/gpiolib-of.c26
-rw-r--r--drivers/gpio/gpiolib-sysfs.c827
-rw-r--r--drivers/gpio/gpiolib.c1358
-rw-r--r--drivers/gpio/gpiolib.h108
85 files changed, 3145 insertions, 3429 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index a86c49a605c6..9de1515e5808 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -56,6 +56,7 @@ config GPIO_ACPI
depends on ACPI
config GPIOLIB_IRQCHIP
+ select IRQ_DOMAIN
bool
config DEBUG_GPIO
@@ -243,6 +244,15 @@ config GPIO_OCTEON
Say yes here to support the on-chip GPIO lines on the OCTEON
family of SOCs.
+config GPIO_OMAP
+ bool "TI OMAP GPIO support" if COMPILE_TEST && !ARCH_OMAP2PLUS
+ default y if ARCH_OMAP
+ depends on ARM
+ select GENERIC_IRQ_CHIP
+ select GPIOLIB_IRQCHIP
+ help
+ Say yes here to enable GPIO support for TI OMAP SoCs.
+
config GPIO_PL061
bool "PrimeCell PL061 GPIO support"
depends on ARM_AMBA
@@ -259,7 +269,7 @@ config GPIO_PXA
config GPIO_RCAR
tristate "Renesas R-Car GPIO"
- depends on ARM
+ depends on ARM && (ARCH_SHMOBILE || COMPILE_TEST)
help
Say yes here to support GPIO on Renesas R-Car SoCs.
@@ -330,6 +340,13 @@ config GPIO_XILINX
help
Say yes here to support the Xilinx FPGA GPIO device
+config GPIO_ZYNQ
+ tristate "Xilinx Zynq GPIO support"
+ depends on ARCH_ZYNQ
+ select GPIOLIB_IRQCHIP
+ help
+ Say yes here to support Xilinx Zynq GPIO controller.
+
config GPIO_XTENSA
bool "Xtensa GPIO32 support"
depends on XTENSA
@@ -413,7 +430,7 @@ config GPIO_GE_FPGA
config GPIO_LYNXPOINT
tristate "Intel Lynxpoint GPIO support"
depends on ACPI && X86
- select IRQ_DOMAIN
+ select GPIOLIB_IRQCHIP
help
driver for GPIO functionality on Intel Lynxpoint PCH chipset
Requires ACPI device enumeration code to set up a platform device.
@@ -440,6 +457,19 @@ config GPIO_ARIZONA
help
Support for GPIOs on Wolfson Arizona class devices.
+config GPIO_CRYSTAL_COVE
+ tristate "GPIO support for Crystal Cove PMIC"
+ depends on INTEL_SOC_PMIC
+ select GPIOLIB_IRQCHIP
+ help
+ Support for GPIO pins on Crystal Cove PMIC.
+
+ Say Yes if you have a Intel SoC based tablet with Crystal Cove PMIC
+ inside.
+
+ This driver can also be built as a module. If so, the module will be
+ called gpio-crystalcove.
+
config GPIO_LP3943
tristate "TI/National Semiconductor LP3943 GPIO expander"
depends on MFD_LP3943
@@ -510,6 +540,7 @@ config GPIO_PCA953X
config GPIO_PCA953X_IRQ
bool "Interrupt controller support for PCA953x"
depends on GPIO_PCA953X=y
+ select GPIOLIB_IRQCHIP
help
Say yes here to enable the pca953x to be used as an interrupt
controller. It requires the driver to be built in the kernel.
@@ -562,6 +593,7 @@ config GPIO_SX150X
config GPIO_STMPE
bool "STMPE GPIOs"
depends on MFD_STMPE
+ select GPIOLIB_IRQCHIP
help
This enables support for the GPIOs found on the STMPE I/O
Expanders.
@@ -579,6 +611,7 @@ config GPIO_STP_XWAY
config GPIO_TC3589X
bool "TC3589X GPIOs"
depends on MFD_TC3589X
+ select GPIOLIB_IRQCHIP
help
This enables support for the GPIOs found on the TC3589X
I/O Expander.
@@ -699,13 +732,13 @@ config GPIO_AMD8111
config GPIO_INTEL_MID
bool "Intel Mid GPIO support"
depends on PCI && X86
- select IRQ_DOMAIN
+ select GPIOLIB_IRQCHIP
help
Say Y here to support Intel Mid GPIO.
config GPIO_PCH
tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7223/ML7831) GPIO"
- depends on PCI && X86
+ depends on PCI && (X86_32 || COMPILE_TEST)
select GENERIC_IRQ_CHIP
help
This driver is for PCH(Platform controller Hub) GPIO of Intel Topcliff
@@ -739,7 +772,7 @@ config GPIO_SODAVILLE
config GPIO_TIMBERDALE
bool "Support for timberdale GPIO IP"
- depends on MFD_TIMBERDALE && HAS_IOMEM
+ depends on MFD_TIMBERDALE
---help---
Add support for the GPIO IP in the timberdale FPGA.
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 6309aff1d806..5d024e396622 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -4,7 +4,9 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG
obj-$(CONFIG_GPIO_DEVRES) += devres.o
obj-$(CONFIG_GPIOLIB) += gpiolib.o
+obj-$(CONFIG_GPIOLIB) += gpiolib-legacy.o
obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
+obj-$(CONFIG_GPIO_SYSFS) += gpiolib-sysfs.o
obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
# Device drivers. Generally keep list sorted alphabetically
@@ -20,6 +22,7 @@ obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
+obj-$(CONFIG_GPIO_CRYSTAL_COVE) += gpio-crystalcove.o
obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o
obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o
obj-$(CONFIG_GPIO_DAVINCI) += gpio-davinci.o
@@ -58,7 +61,7 @@ obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o
obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o
obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o
obj-$(CONFIG_GPIO_OCTEON) += gpio-octeon.o
-obj-$(CONFIG_ARCH_OMAP) += gpio-omap.o
+obj-$(CONFIG_GPIO_OMAP) += gpio-omap.o
obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o
obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o
obj-$(CONFIG_GPIO_PCH) += gpio-pch.o
@@ -101,3 +104,4 @@ obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o
obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o
obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o
obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o
+obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o
diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c
index 307464fd015f..41b2f40578d5 100644
--- a/drivers/gpio/devres.c
+++ b/drivers/gpio/devres.c
@@ -39,31 +39,53 @@ static int devm_gpiod_match(struct device *dev, void *res, void *data)
* devm_gpiod_get - Resource-managed gpiod_get()
* @dev: GPIO consumer
* @con_id: function within the GPIO consumer
+ * @flags: optional GPIO initialization flags
*
* Managed gpiod_get(). GPIO descriptors returned from this function are
* automatically disposed on driver detach. See gpiod_get() for detailed
* information about behavior and return values.
*/
-struct gpio_desc *__must_check devm_gpiod_get(struct device *dev,
- const char *con_id)
+struct gpio_desc *__must_check __devm_gpiod_get(struct device *dev,
+ const char *con_id,
+ enum gpiod_flags flags)
{
- return devm_gpiod_get_index(dev, con_id, 0);
+ return devm_gpiod_get_index(dev, con_id, 0, flags);
}
-EXPORT_SYMBOL(devm_gpiod_get);
+EXPORT_SYMBOL(__devm_gpiod_get);
+
+/**
+ * devm_gpiod_get_optional - Resource-managed gpiod_get_optional()
+ * @dev: GPIO consumer
+ * @con_id: function within the GPIO consumer
+ * @flags: optional GPIO initialization flags
+ *
+ * Managed gpiod_get_optional(). GPIO descriptors returned from this function
+ * are automatically disposed on driver detach. See gpiod_get_optional() for
+ * detailed information about behavior and return values.
+ */
+struct gpio_desc *__must_check __devm_gpiod_get_optional(struct device *dev,
+ const char *con_id,
+ enum gpiod_flags flags)
+{
+ return devm_gpiod_get_index_optional(dev, con_id, 0, flags);
+}
+EXPORT_SYMBOL(__devm_gpiod_get_optional);
/**
* devm_gpiod_get_index - Resource-managed gpiod_get_index()
* @dev: GPIO consumer
* @con_id: function within the GPIO consumer
* @idx: index of the GPIO to obtain in the consumer
+ * @flags: optional GPIO initialization flags
*
* Managed gpiod_get_index(). GPIO descriptors returned from this function are
* automatically disposed on driver detach. See gpiod_get_index() for detailed
* information about behavior and return values.
*/
-struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
+struct gpio_desc *__must_check __devm_gpiod_get_index(struct device *dev,
const char *con_id,
- unsigned int idx)
+ unsigned int idx,
+ enum gpiod_flags flags)
{
struct gpio_desc **dr;
struct gpio_desc *desc;
@@ -73,7 +95,7 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
if (!dr)
return ERR_PTR(-ENOMEM);
- desc = gpiod_get_index(dev, con_id, idx);
+ desc = gpiod_get_index(dev, con_id, idx, flags);
if (IS_ERR(desc)) {
devres_free(dr);
return desc;
@@ -84,7 +106,36 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
return desc;
}
-EXPORT_SYMBOL(devm_gpiod_get_index);
+EXPORT_SYMBOL(__devm_gpiod_get_index);
+
+/**
+ * devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional()
+ * @dev: GPIO consumer
+ * @con_id: function within the GPIO consumer
+ * @index: index of the GPIO to obtain in the consumer
+ * @flags: optional GPIO initialization flags
+ *
+ * Managed gpiod_get_index_optional(). GPIO descriptors returned from this
+ * function are automatically disposed on driver detach. See
+ * gpiod_get_index_optional() for detailed information about behavior and
+ * return values.
+ */
+struct gpio_desc *__must_check __devm_gpiod_get_index_optional(struct device *dev,
+ const char *con_id,
+ unsigned int index,
+ enum gpiod_flags flags)
+{
+ struct gpio_desc *desc;
+
+ desc = devm_gpiod_get_index(dev, con_id, index, flags);
+ if (IS_ERR(desc)) {
+ if (PTR_ERR(desc) == -ENOENT)
+ return NULL;
+ }
+
+ return desc;
+}
+EXPORT_SYMBOL(__devm_gpiod_get_index_optional);
/**
* devm_gpiod_put - Resource-managed gpiod_put()
diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c
index e4ae29824c32..e3d968f751f1 100644
--- a/drivers/gpio/gpio-74x164.c
+++ b/drivers/gpio/gpio-74x164.c
@@ -167,13 +167,11 @@ exit_destroy:
static int gen_74x164_remove(struct spi_device *spi)
{
struct gen_74x164_chip *chip = spi_get_drvdata(spi);
- int ret;
- ret = gpiochip_remove(&chip->gpio_chip);
- if (!ret)
- mutex_destroy(&chip->lock);
+ gpiochip_remove(&chip->gpio_chip);
+ mutex_destroy(&chip->lock);
- return ret;
+ return 0;
}
static const struct of_device_id gen_74x164_dt_ids[] = {
diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c
index b2239d678d01..416b2200d4f1 100644
--- a/drivers/gpio/gpio-adnp.c
+++ b/drivers/gpio/gpio-adnp.c
@@ -585,15 +585,8 @@ static int adnp_i2c_remove(struct i2c_client *client)
{
struct adnp *adnp = i2c_get_clientdata(client);
struct device_node *np = client->dev.of_node;
- int err;
-
- err = gpiochip_remove(&adnp->gpio);
- if (err < 0) {
- dev_err(&client->dev, "%s failed: %d\n", "gpiochip_remove()",
- err);
- return err;
- }
+ gpiochip_remove(&adnp->gpio);
if (of_find_property(np, "interrupt-controller", NULL))
adnp_irq_teardown(adnp);
diff --git a/drivers/gpio/gpio-adp5520.c b/drivers/gpio/gpio-adp5520.c
index 613265944e2e..b08bd169e568 100644
--- a/drivers/gpio/gpio-adp5520.c
+++ b/drivers/gpio/gpio-adp5520.c
@@ -106,10 +106,8 @@ static int adp5520_gpio_probe(struct platform_device *pdev)
}
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
- if (dev == NULL) {
- dev_err(&pdev->dev, "failed to alloc memory\n");
+ if (dev == NULL)
return -ENOMEM;
- }
dev->master = pdev->dev.parent;
@@ -169,15 +167,9 @@ err:
static int adp5520_gpio_remove(struct platform_device *pdev)
{
struct adp5520_gpio *dev;
- int ret;
dev = platform_get_drvdata(pdev);
- ret = gpiochip_remove(&dev->gpio_chip);
- if (ret) {
- dev_err(&pdev->dev, "%s failed, %d\n",
- "gpiochip_remove()", ret);
- return ret;
- }
+ gpiochip_remove(&dev->gpio_chip);
return 0;
}
diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c
index d974020b78bb..3beed6ea8c65 100644
--- a/drivers/gpio/gpio-adp5588.c
+++ b/drivers/gpio/gpio-adp5588.c
@@ -379,10 +379,8 @@ static int adp5588_gpio_probe(struct i2c_client *client,
}
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (dev == NULL) {
- dev_err(&client->dev, "failed to alloc memory\n");
+ if (dev == NULL)
return -ENOMEM;
- }
dev->client = client;
@@ -472,11 +470,7 @@ static int adp5588_gpio_remove(struct i2c_client *client)
if (dev->irq_base)
free_irq(dev->client->irq, dev);
- ret = gpiochip_remove(&dev->gpio_chip);
- if (ret) {
- dev_err(&client->dev, "gpiochip_remove failed %d\n", ret);
- return ret;
- }
+ gpiochip_remove(&dev->gpio_chip);
kfree(dev);
return 0;
diff --git a/drivers/gpio/gpio-amd8111.c b/drivers/gpio/gpio-amd8111.c
index 94e9992f8904..3c09f1a6872a 100644
--- a/drivers/gpio/gpio-amd8111.c
+++ b/drivers/gpio/gpio-amd8111.c
@@ -232,8 +232,7 @@ out:
static void __exit amd_gpio_exit(void)
{
- int err = gpiochip_remove(&gp.chip);
- WARN_ON(err);
+ gpiochip_remove(&gp.chip);
ioport_unmap(gp.pm);
release_region(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE);
}
diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c
index 29bdff558981..fe369f5c7fa6 100644
--- a/drivers/gpio/gpio-arizona.c
+++ b/drivers/gpio/gpio-arizona.c
@@ -149,7 +149,8 @@ static int arizona_gpio_remove(struct platform_device *pdev)
{
struct arizona_gpio *arizona_gpio = platform_get_drvdata(pdev);
- return gpiochip_remove(&arizona_gpio->gpio_chip);
+ gpiochip_remove(&arizona_gpio->gpio_chip);
+ return 0;
}
static struct platform_driver arizona_gpio_driver = {
diff --git a/drivers/gpio/gpio-bt8xx.c b/drivers/gpio/gpio-bt8xx.c
index ecb3ca2d1d10..6557147d9331 100644
--- a/drivers/gpio/gpio-bt8xx.c
+++ b/drivers/gpio/gpio-bt8xx.c
@@ -178,7 +178,7 @@ static int bt8xxgpio_probe(struct pci_dev *dev,
struct bt8xxgpio *bg;
int err;
- bg = kzalloc(sizeof(*bg), GFP_KERNEL);
+ bg = devm_kzalloc(&dev->dev, sizeof(struct bt8xxgpio), GFP_KERNEL);
if (!bg)
return -ENOMEM;
@@ -188,9 +188,9 @@ static int bt8xxgpio_probe(struct pci_dev *dev,
err = pci_enable_device(dev);
if (err) {
printk(KERN_ERR "bt8xxgpio: Can't enable device.\n");
- goto err_freebg;
+ return err;
}
- if (!request_mem_region(pci_resource_start(dev, 0),
+ if (!devm_request_mem_region(&dev->dev, pci_resource_start(dev, 0),
pci_resource_len(dev, 0),
"bt8xxgpio")) {
printk(KERN_WARNING "bt8xxgpio: Can't request iomem (0x%llx).\n",
@@ -201,11 +201,11 @@ static int bt8xxgpio_probe(struct pci_dev *dev,
pci_set_master(dev);
pci_set_drvdata(dev, bg);
- bg->mmio = ioremap(pci_resource_start(dev, 0), 0x1000);
+ bg->mmio = devm_ioremap(&dev->dev, pci_resource_start(dev, 0), 0x1000);
if (!bg->mmio) {
printk(KERN_ERR "bt8xxgpio: ioremap() failed\n");
err = -EIO;
- goto err_release_mem;
+ goto err_disable;
}
/* Disable interrupts */
@@ -220,18 +220,13 @@ static int bt8xxgpio_probe(struct pci_dev *dev,
err = gpiochip_add(&bg->gpio);
if (err) {
printk(KERN_ERR "bt8xxgpio: Failed to register GPIOs\n");
- goto err_release_mem;
+ goto err_disable;
}
return 0;
-err_release_mem:
- release_mem_region(pci_resource_start(dev, 0),
- pci_resource_len(dev, 0));
err_disable:
pci_disable_device(dev);
-err_freebg:
- kfree(bg);
return err;
}
@@ -250,8 +245,6 @@ static void bt8xxgpio_remove(struct pci_dev *pdev)
release_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
pci_disable_device(pdev);
-
- kfree(bg);
}
#ifdef CONFIG_PM
diff --git a/drivers/gpio/gpio-crystalcove.c b/drivers/gpio/gpio-crystalcove.c
new file mode 100644
index 000000000000..934462f5bd22
--- /dev/null
+++ b/drivers/gpio/gpio-crystalcove.c
@@ -0,0 +1,380 @@
+/*
+ * gpio-crystalcove.c - Intel Crystal Cove GPIO Driver
+ *
+ * Copyright (C) 2012, 2014 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Author: Yang, Bin <bin.yang@intel.com>
+ */
+
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/seq_file.h>
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <linux/mfd/intel_soc_pmic.h>
+
+#define CRYSTALCOVE_GPIO_NUM 16
+
+#define UPDATE_IRQ_TYPE BIT(0)
+#define UPDATE_IRQ_MASK BIT(1)
+
+#define GPIO0IRQ 0x0b
+#define GPIO1IRQ 0x0c
+#define MGPIO0IRQS0 0x19
+#define MGPIO1IRQS0 0x1a
+#define MGPIO0IRQSX 0x1b
+#define MGPIO1IRQSX 0x1c
+#define GPIO0P0CTLO 0x2b
+#define GPIO0P0CTLI 0x33
+#define GPIO1P0CTLO 0x3b
+#define GPIO1P0CTLI 0x43
+
+#define CTLI_INTCNT_DIS (0)
+#define CTLI_INTCNT_NE (1 << 1)
+#define CTLI_INTCNT_PE (2 << 1)
+#define CTLI_INTCNT_BE (3 << 1)
+
+#define CTLO_DIR_IN (0)
+#define CTLO_DIR_OUT (1 << 5)
+
+#define CTLO_DRV_CMOS (0)
+#define CTLO_DRV_OD (1 << 4)
+
+#define CTLO_DRV_REN (1 << 3)
+
+#define CTLO_RVAL_2KDW (0)
+#define CTLO_RVAL_2KUP (1 << 1)
+#define CTLO_RVAL_50KDW (2 << 1)
+#define CTLO_RVAL_50KUP (3 << 1)
+
+#define CTLO_INPUT_SET (CTLO_DRV_CMOS | CTLO_DRV_REN | CTLO_RVAL_2KUP)
+#define CTLO_OUTPUT_SET (CTLO_DIR_OUT | CTLO_INPUT_SET)
+
+enum ctrl_register {
+ CTRL_IN,
+ CTRL_OUT,
+};
+
+/**
+ * struct crystalcove_gpio - Crystal Cove GPIO controller
+ * @buslock: for bus lock/sync and unlock.
+ * @chip: the abstract gpio_chip structure.
+ * @regmap: the regmap from the parent device.
+ * @update: pending IRQ setting update, to be written to the chip upon unlock.
+ * @intcnt_value: the Interrupt Detect value to be written.
+ * @set_irq_mask: true if the IRQ mask needs to be set, false to clear.
+ */
+struct crystalcove_gpio {
+ struct mutex buslock; /* irq_bus_lock */
+ struct gpio_chip chip;
+ struct regmap *regmap;
+ int update;
+ int intcnt_value;
+ bool set_irq_mask;
+};
+
+static inline struct crystalcove_gpio *to_cg(struct gpio_chip *gc)
+{
+ return container_of(gc, struct crystalcove_gpio, chip);
+}
+
+static inline int to_reg(int gpio, enum ctrl_register reg_type)
+{
+ int reg;
+
+ if (reg_type == CTRL_IN) {
+ if (gpio < 8)
+ reg = GPIO0P0CTLI;
+ else
+ reg = GPIO1P0CTLI;
+ } else {
+ if (gpio < 8)
+ reg = GPIO0P0CTLO;
+ else
+ reg = GPIO1P0CTLO;
+ }
+
+ return reg + gpio % 8;
+}
+
+static void crystalcove_update_irq_mask(struct crystalcove_gpio *cg,
+ int gpio)
+{
+ u8 mirqs0 = gpio < 8 ? MGPIO0IRQS0 : MGPIO1IRQS0;
+ int mask = BIT(gpio % 8);
+
+ if (cg->set_irq_mask)
+ regmap_update_bits(cg->regmap, mirqs0, mask, mask);
+ else
+ regmap_update_bits(cg->regmap, mirqs0, mask, 0);
+}
+
+static void crystalcove_update_irq_ctrl(struct crystalcove_gpio *cg, int gpio)
+{
+ int reg = to_reg(gpio, CTRL_IN);
+
+ regmap_update_bits(cg->regmap, reg, CTLI_INTCNT_BE, cg->intcnt_value);
+}
+
+static int crystalcove_gpio_dir_in(struct gpio_chip *chip, unsigned gpio)
+{
+ struct crystalcove_gpio *cg = to_cg(chip);
+
+ return regmap_write(cg->regmap, to_reg(gpio, CTRL_OUT),
+ CTLO_INPUT_SET);
+}
+
+static int crystalcove_gpio_dir_out(struct gpio_chip *chip, unsigned gpio,
+ int value)
+{
+ struct crystalcove_gpio *cg = to_cg(chip);
+
+ return regmap_write(cg->regmap, to_reg(gpio, CTRL_OUT),
+ CTLO_OUTPUT_SET | value);
+}
+
+static int crystalcove_gpio_get(struct gpio_chip *chip, unsigned gpio)
+{
+ struct crystalcove_gpio *cg = to_cg(chip);
+ int ret;
+ unsigned int val;
+
+ ret = regmap_read(cg->regmap, to_reg(gpio, CTRL_IN), &val);
+ if (ret)
+ return ret;
+
+ return val & 0x1;
+}
+
+static void crystalcove_gpio_set(struct gpio_chip *chip,
+ unsigned gpio, int value)
+{
+ struct crystalcove_gpio *cg = to_cg(chip);
+
+ if (value)
+ regmap_update_bits(cg->regmap, to_reg(gpio, CTRL_OUT), 1, 1);
+ else
+ regmap_update_bits(cg->regmap, to_reg(gpio, CTRL_OUT), 1, 0);
+}
+
+static int crystalcove_irq_type(struct irq_data *data, unsigned type)
+{
+ struct crystalcove_gpio *cg = to_cg(irq_data_get_irq_chip_data(data));
+
+ switch (type) {
+ case IRQ_TYPE_NONE:
+ cg->intcnt_value = CTLI_INTCNT_DIS;
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ cg->intcnt_value = CTLI_INTCNT_BE;
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ cg->intcnt_value = CTLI_INTCNT_PE;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ cg->intcnt_value = CTLI_INTCNT_NE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ cg->update |= UPDATE_IRQ_TYPE;
+
+ return 0;
+}
+
+static void crystalcove_bus_lock(struct irq_data *data)
+{
+ struct crystalcove_gpio *cg = to_cg(irq_data_get_irq_chip_data(data));
+
+ mutex_lock(&cg->buslock);
+}
+
+static void crystalcove_bus_sync_unlock(struct irq_data *data)
+{
+ struct crystalcove_gpio *cg = to_cg(irq_data_get_irq_chip_data(data));
+ int gpio = data->hwirq;
+
+ if (cg->update & UPDATE_IRQ_TYPE)
+ crystalcove_update_irq_ctrl(cg, gpio);
+ if (cg->update & UPDATE_IRQ_MASK)
+ crystalcove_update_irq_mask(cg, gpio);
+ cg->update = 0;
+
+ mutex_unlock(&cg->buslock);
+}
+
+static void crystalcove_irq_unmask(struct irq_data *data)
+{
+ struct crystalcove_gpio *cg = to_cg(irq_data_get_irq_chip_data(data));
+
+ cg->set_irq_mask = false;
+ cg->update |= UPDATE_IRQ_MASK;
+}
+
+static void crystalcove_irq_mask(struct irq_data *data)
+{
+ struct crystalcove_gpio *cg = to_cg(irq_data_get_irq_chip_data(data));
+
+ cg->set_irq_mask = true;
+ cg->update |= UPDATE_IRQ_MASK;
+}
+
+static struct irq_chip crystalcove_irqchip = {
+ .name = "Crystal Cove",
+ .irq_mask = crystalcove_irq_mask,
+ .irq_unmask = crystalcove_irq_unmask,
+ .irq_set_type = crystalcove_irq_type,
+ .irq_bus_lock = crystalcove_bus_lock,
+ .irq_bus_sync_unlock = crystalcove_bus_sync_unlock,
+};
+
+static irqreturn_t crystalcove_gpio_irq_handler(int irq, void *data)
+{
+ struct crystalcove_gpio *cg = data;
+ unsigned int p0, p1;
+ int pending;
+ int gpio;
+ unsigned int virq;
+
+ if (regmap_read(cg->regmap, GPIO0IRQ, &p0) ||
+ regmap_read(cg->regmap, GPIO1IRQ, &p1))
+ return IRQ_NONE;
+
+ regmap_write(cg->regmap, GPIO0IRQ, p0);
+ regmap_write(cg->regmap, GPIO1IRQ, p1);
+
+ pending = p0 | p1 << 8;
+
+ for (gpio = 0; gpio < cg->chip.ngpio; gpio++) {
+ if (pending & BIT(gpio)) {
+ virq = irq_find_mapping(cg->chip.irqdomain, gpio);
+ generic_handle_irq(virq);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void crystalcove_gpio_dbg_show(struct seq_file *s,
+ struct gpio_chip *chip)
+{
+ struct crystalcove_gpio *cg = to_cg(chip);
+ int gpio, offset;
+ unsigned int ctlo, ctli, mirqs0, mirqsx, irq;
+
+ for (gpio = 0; gpio < cg->chip.ngpio; gpio++) {
+ regmap_read(cg->regmap, to_reg(gpio, CTRL_OUT), &ctlo);
+ regmap_read(cg->regmap, to_reg(gpio, CTRL_IN), &ctli);
+ regmap_read(cg->regmap, gpio < 8 ? MGPIO0IRQS0 : MGPIO1IRQS0,
+ &mirqs0);
+ regmap_read(cg->regmap, gpio < 8 ? MGPIO0IRQSX : MGPIO1IRQSX,
+ &mirqsx);
+ regmap_read(cg->regmap, gpio < 8 ? GPIO0IRQ : GPIO1IRQ,
+ &irq);
+
+ offset = gpio % 8;
+ seq_printf(s, " gpio-%-2d %s %s %s %s ctlo=%2x,%s %s %s\n",
+ gpio, ctlo & CTLO_DIR_OUT ? "out" : "in ",
+ ctli & 0x1 ? "hi" : "lo",
+ ctli & CTLI_INTCNT_NE ? "fall" : " ",
+ ctli & CTLI_INTCNT_PE ? "rise" : " ",
+ ctlo,
+ mirqs0 & BIT(offset) ? "s0 mask " : "s0 unmask",
+ mirqsx & BIT(offset) ? "sx mask " : "sx unmask",
+ irq & BIT(offset) ? "pending" : " ");
+ }
+}
+
+static int crystalcove_gpio_probe(struct platform_device *pdev)
+{
+ int irq = platform_get_irq(pdev, 0);
+ struct crystalcove_gpio *cg;
+ int retval;
+ struct device *dev = pdev->dev.parent;
+ struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
+
+ if (irq < 0)
+ return irq;
+
+ cg = devm_kzalloc(&pdev->dev, sizeof(*cg), GFP_KERNEL);
+ if (!cg)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, cg);
+
+ mutex_init(&cg->buslock);
+ cg->chip.label = KBUILD_MODNAME;
+ cg->chip.direction_input = crystalcove_gpio_dir_in;
+ cg->chip.direction_output = crystalcove_gpio_dir_out;
+ cg->chip.get = crystalcove_gpio_get;
+ cg->chip.set = crystalcove_gpio_set;
+ cg->chip.base = -1;
+ cg->chip.ngpio = CRYSTALCOVE_GPIO_NUM;
+ cg->chip.can_sleep = true;
+ cg->chip.dev = dev;
+ cg->chip.dbg_show = crystalcove_gpio_dbg_show;
+ cg->regmap = pmic->regmap;
+
+ retval = gpiochip_add(&cg->chip);
+ if (retval) {
+ dev_warn(&pdev->dev, "add gpio chip error: %d\n", retval);
+ return retval;
+ }
+
+ gpiochip_irqchip_add(&cg->chip, &crystalcove_irqchip, 0,
+ handle_simple_irq, IRQ_TYPE_NONE);
+
+ retval = request_threaded_irq(irq, NULL, crystalcove_gpio_irq_handler,
+ IRQF_ONESHOT, KBUILD_MODNAME, cg);
+
+ if (retval) {
+ dev_warn(&pdev->dev, "request irq failed: %d\n", retval);
+ goto out_remove_gpio;
+ }
+
+ return 0;
+
+out_remove_gpio:
+ WARN_ON(gpiochip_remove(&cg->chip));
+ return retval;
+}
+
+static int crystalcove_gpio_remove(struct platform_device *pdev)
+{
+ struct crystalcove_gpio *cg = platform_get_drvdata(pdev);
+ int irq = platform_get_irq(pdev, 0);
+ int err;
+
+ err = gpiochip_remove(&cg->chip);
+
+ if (irq >= 0)
+ free_irq(irq, cg);
+
+ return err;
+}
+
+static struct platform_driver crystalcove_gpio_driver = {
+ .probe = crystalcove_gpio_probe,
+ .remove = crystalcove_gpio_remove,
+ .driver = {
+ .name = "crystal_cove_gpio",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(crystalcove_gpio_driver);
+
+MODULE_AUTHOR("Yang, Bin <bin.yang@intel.com>");
+MODULE_DESCRIPTION("Intel Crystal Cove GPIO Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-cs5535.c b/drivers/gpio/gpio-cs5535.c
index c0a3aeba6f21..92ec58fa9236 100644
--- a/drivers/gpio/gpio-cs5535.c
+++ b/drivers/gpio/gpio-cs5535.c
@@ -358,14 +358,8 @@ done:
static int cs5535_gpio_remove(struct platform_device *pdev)
{
struct resource *r;
- int err;
- err = gpiochip_remove(&cs5535_gpio_chip.chip);
- if (err) {
- /* uhh? */
- dev_err(&pdev->dev, "unable to remove gpio_chip?\n");
- return err;
- }
+ gpiochip_remove(&cs5535_gpio_chip.chip);
r = platform_get_resource(pdev, IORESOURCE_IO, 0);
release_region(r->start, resource_size(r));
diff --git a/drivers/gpio/gpio-da9052.c b/drivers/gpio/gpio-da9052.c
index 416cdf786b05..c5bccd4dec96 100644
--- a/drivers/gpio/gpio-da9052.c
+++ b/drivers/gpio/gpio-da9052.c
@@ -237,7 +237,8 @@ static int da9052_gpio_remove(struct platform_device *pdev)
{
struct da9052_gpio *gpio = platform_get_drvdata(pdev);
- return gpiochip_remove(&gpio->gp);
+ gpiochip_remove(&gpio->gp);
+ return 0;
}
static struct platform_driver da9052_gpio_driver = {
diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c
index f992997bc301..9167c4331081 100644
--- a/drivers/gpio/gpio-da9055.c
+++ b/drivers/gpio/gpio-da9055.c
@@ -174,7 +174,8 @@ static int da9055_gpio_remove(struct platform_device *pdev)
{
struct da9055_gpio *gpio = platform_get_drvdata(pdev);
- return gpiochip_remove(&gpio->gp);
+ gpiochip_remove(&gpio->gp);
+ return 0;
}
static struct platform_driver da9055_gpio_driver = {
diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c
index 339f9dac591b..9f0682534e2f 100644
--- a/drivers/gpio/gpio-davinci.c
+++ b/drivers/gpio/gpio-davinci.c
@@ -230,10 +230,8 @@ static int davinci_gpio_probe(struct platform_device *pdev)
chips = devm_kzalloc(dev,
ngpio * sizeof(struct davinci_gpio_controller),
GFP_KERNEL);
- if (!chips) {
- dev_err(dev, "Memory allocation failed\n");
+ if (!chips)
return -ENOMEM;
- }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c
index ed5711f77e2d..d6618a6e2399 100644
--- a/drivers/gpio/gpio-dwapb.c
+++ b/drivers/gpio/gpio-dwapb.c
@@ -198,6 +198,8 @@ static int dwapb_irq_set_type(struct irq_data *d, u32 type)
break;
}
+ irq_setup_alt_chip(d, type);
+
writel(level, gpio->regs + GPIO_INTTYPE_LEVEL);
writel(polarity, gpio->regs + GPIO_INT_POLARITY);
spin_unlock_irqrestore(&bgc->lock, flags);
@@ -213,7 +215,7 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
struct irq_chip_generic *irq_gc;
unsigned int hwirq, ngpio = gc->ngpio;
struct irq_chip_type *ct;
- int err, irq;
+ int err, irq, i;
irq = irq_of_parse_and_map(node, 0);
if (!irq) {
@@ -227,7 +229,7 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
if (!gpio->domain)
return;
- err = irq_alloc_domain_generic_chips(gpio->domain, ngpio, 1,
+ err = irq_alloc_domain_generic_chips(gpio->domain, ngpio, 2,
"gpio-dwapb", handle_level_irq,
IRQ_NOREQUEST, 0,
IRQ_GC_INIT_NESTED_LOCK);
@@ -248,20 +250,24 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
irq_gc->reg_base = gpio->regs;
irq_gc->private = gpio;
- ct = irq_gc->chip_types;
- ct->chip.irq_ack = irq_gc_ack_set_bit;
- ct->chip.irq_mask = irq_gc_mask_set_bit;
- ct->chip.irq_unmask = irq_gc_mask_clr_bit;
- ct->chip.irq_set_type = dwapb_irq_set_type;
- ct->chip.irq_enable = dwapb_irq_enable;
- ct->chip.irq_disable = dwapb_irq_disable;
- ct->chip.irq_request_resources = dwapb_irq_reqres;
- ct->chip.irq_release_resources = dwapb_irq_relres;
- ct->regs.ack = GPIO_PORTA_EOI;
- ct->regs.mask = GPIO_INTMASK;
-
- irq_setup_generic_chip(irq_gc, IRQ_MSK(port->bgc.gc.ngpio),
- IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0);
+ for (i = 0; i < 2; i++) {
+ ct = &irq_gc->chip_types[i];
+ ct->chip.irq_ack = irq_gc_ack_set_bit;
+ ct->chip.irq_mask = irq_gc_mask_set_bit;
+ ct->chip.irq_unmask = irq_gc_mask_clr_bit;
+ ct->chip.irq_set_type = dwapb_irq_set_type;
+ ct->chip.irq_enable = dwapb_irq_enable;
+ ct->chip.irq_disable = dwapb_irq_disable;
+ ct->chip.irq_request_resources = dwapb_irq_reqres;
+ ct->chip.irq_release_resources = dwapb_irq_relres;
+ ct->regs.ack = GPIO_PORTA_EOI;
+ ct->regs.mask = GPIO_INTMASK;
+ ct->type = IRQ_TYPE_LEVEL_MASK;
+ }
+
+ irq_gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK;
+ irq_gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH;
+ irq_gc->chip_types[1].handler = handle_edge_irq;
irq_set_chained_handler(irq, dwapb_irq_handler);
irq_set_handler_data(irq, gpio);
@@ -353,7 +359,7 @@ static void dwapb_gpio_unregister(struct dwapb_gpio *gpio)
for (m = 0; m < gpio->nr_ports; ++m)
if (gpio->ports[m].is_registered)
- WARN_ON(gpiochip_remove(&gpio->ports[m].bgc.gc));
+ gpiochip_remove(&gpio->ports[m].bgc.gc);
}
static int dwapb_gpio_probe(struct platform_device *pdev)
diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c
index 8765bd6f48e1..fe49ec3cdb7d 100644
--- a/drivers/gpio/gpio-em.c
+++ b/drivers/gpio/gpio-em.c
@@ -212,7 +212,7 @@ static void __em_gio_set(struct gpio_chip *chip, unsigned int reg,
{
/* upper 16 bits contains mask and lower 16 actual value */
em_gio_write(gpio_to_priv(chip), reg,
- (1 << (shift + 16)) | (value << shift));
+ (BIT(shift + 16)) | (value << shift));
}
static void em_gio_set(struct gpio_chip *chip, unsigned offset, int value)
@@ -284,7 +284,6 @@ static int em_gio_probe(struct platform_device *pdev)
p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
if (!p) {
- dev_err(&pdev->dev, "failed to allocate driver data\n");
ret = -ENOMEM;
goto err0;
}
@@ -410,11 +409,8 @@ err0:
static int em_gio_remove(struct platform_device *pdev)
{
struct em_gio_priv *p = platform_get_drvdata(pdev);
- int ret;
- ret = gpiochip_remove(&p->gpio_chip);
- if (ret)
- return ret;
+ gpiochip_remove(&p->gpio_chip);
irq_domain_remove(p->irq_domain);
return 0;
diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c
index 80829f3c6543..dcc2bb4074ef 100644
--- a/drivers/gpio/gpio-ep93xx.c
+++ b/drivers/gpio/gpio-ep93xx.c
@@ -344,37 +344,24 @@ static int ep93xx_gpio_probe(struct platform_device *pdev)
{
struct ep93xx_gpio *ep93xx_gpio;
struct resource *res;
- void __iomem *mmio;
int i;
- int ret;
+ struct device *dev = &pdev->dev;
- ep93xx_gpio = kzalloc(sizeof(*ep93xx_gpio), GFP_KERNEL);
+ ep93xx_gpio = devm_kzalloc(dev, sizeof(struct ep93xx_gpio), GFP_KERNEL);
if (!ep93xx_gpio)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- ret = -ENXIO;
- goto exit_free;
- }
-
- if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
- ret = -EBUSY;
- goto exit_free;
- }
-
- mmio = ioremap(res->start, resource_size(res));
- if (!mmio) {
- ret = -ENXIO;
- goto exit_release;
- }
- ep93xx_gpio->mmio_base = mmio;
+ ep93xx_gpio->mmio_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ep93xx_gpio->mmio_base))
+ return PTR_ERR(ep93xx_gpio->mmio_base);
for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++) {
struct bgpio_chip *bgc = &ep93xx_gpio->bgc[i];
struct ep93xx_gpio_bank *bank = &ep93xx_gpio_banks[i];
- if (ep93xx_gpio_add_bank(bgc, &pdev->dev, mmio, bank))
+ if (ep93xx_gpio_add_bank(bgc, &pdev->dev,
+ ep93xx_gpio->mmio_base, bank))
dev_warn(&pdev->dev, "Unable to add gpio bank %s\n",
bank->label);
}
@@ -382,13 +369,6 @@ static int ep93xx_gpio_probe(struct platform_device *pdev)
ep93xx_gpio_init_irq();
return 0;
-
-exit_release:
- release_mem_region(res->start, resource_size(res));
-exit_free:
- kfree(ep93xx_gpio);
- dev_info(&pdev->dev, "%s failed with errno %d\n", __func__, ret);
- return ret;
}
static struct platform_driver ep93xx_gpio_driver = {
diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c
index 8f73ee093739..fd3202f968ff 100644
--- a/drivers/gpio/gpio-f7188x.c
+++ b/drivers/gpio/gpio-f7188x.c
@@ -317,13 +317,7 @@ static int f7188x_gpio_probe(struct platform_device *pdev)
err_gpiochip:
for (i = i - 1; i >= 0; i--) {
struct f7188x_gpio_bank *bank = &data->bank[i];
- int tmp;
-
- tmp = gpiochip_remove(&bank->chip);
- if (tmp < 0)
- dev_err(&pdev->dev,
- "Failed to remove gpiochip %d: %d\n",
- i, tmp);
+ gpiochip_remove(&bank->chip);
}
return err;
@@ -331,20 +325,12 @@ err_gpiochip:
static int f7188x_gpio_remove(struct platform_device *pdev)
{
- int err;
int i;
struct f7188x_gpio_data *data = platform_get_drvdata(pdev);
for (i = 0; i < data->nr_bank; i++) {
struct f7188x_gpio_bank *bank = &data->bank[i];
-
- err = gpiochip_remove(&bank->chip);
- if (err) {
- dev_err(&pdev->dev,
- "Failed to remove GPIO gpiochip %d: %d\n",
- i, err);
- return err;
- }
+ gpiochip_remove(&bank->chip);
}
return 0;
diff --git a/drivers/gpio/gpio-ge.c b/drivers/gpio/gpio-ge.c
index 7b95a4a8318c..1237a73c3c91 100644
--- a/drivers/gpio/gpio-ge.c
+++ b/drivers/gpio/gpio-ge.c
@@ -18,15 +18,9 @@
*/
#include <linux/kernel.h>
-#include <linux/compiler.h>
-#include <linux/init.h>
#include <linux/io.h>
-#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/of_platform.h>
#include <linux/of_gpio.h>
-#include <linux/gpio.h>
-#include <linux/slab.h>
#include <linux/module.h>
#define GEF_GPIO_DIRECT 0x00
@@ -39,28 +33,26 @@
#define GEF_GPIO_OVERRUN 0x1C
#define GEF_GPIO_MODE 0x20
-static void _gef_gpio_set(void __iomem *reg, unsigned int offset, int value)
+static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
+ struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
unsigned int data;
- data = ioread32be(reg);
- /* value: 0=low; 1=high */
- if (value & 0x1)
- data = data | (0x1 << offset);
+ data = ioread32be(mmchip->regs + GEF_GPIO_OUT);
+ if (value)
+ data = data | BIT(offset);
else
- data = data & ~(0x1 << offset);
-
- iowrite32be(data, reg);
+ data = data & ~BIT(offset);
+ iowrite32be(data, mmchip->regs + GEF_GPIO_OUT);
}
-
static int gef_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
{
unsigned int data;
struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT);
- data = data | (0x1 << offset);
+ data = data | BIT(offset);
iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT);
return 0;
@@ -71,11 +63,11 @@ static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value)
unsigned int data;
struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
- /* Set direction before switching to input */
- _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value);
+ /* Set value before switching to output */
+ gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value);
data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT);
- data = data & ~(0x1 << offset);
+ data = data & ~BIT(offset);
iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT);
return 0;
@@ -83,116 +75,56 @@ static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value)
static int gef_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- unsigned int data;
- int state = 0;
struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
- data = ioread32be(mmchip->regs + GEF_GPIO_IN);
- state = (int)((data >> offset) & 0x1);
-
- return state;
+ return !!(ioread32be(mmchip->regs + GEF_GPIO_IN) & BIT(offset));
}
-static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
- struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
-
- _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value);
-}
+static const struct of_device_id gef_gpio_ids[] = {
+ {
+ .compatible = "gef,sbc610-gpio",
+ .data = (void *)19,
+ }, {
+ .compatible = "gef,sbc310-gpio",
+ .data = (void *)6,
+ }, {
+ .compatible = "ge,imp3a-gpio",
+ .data = (void *)16,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, gef_gpio_ids);
-static int __init gef_gpio_init(void)
+static int __init gef_gpio_probe(struct platform_device *pdev)
{
- struct device_node *np;
- int retval;
- struct of_mm_gpio_chip *gef_gpio_chip;
-
- for_each_compatible_node(np, NULL, "gef,sbc610-gpio") {
-
- pr_debug("%s: Initialising GEF GPIO\n", np->full_name);
-
- /* Allocate chip structure */
- gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL);
- if (!gef_gpio_chip) {
- pr_err("%s: Unable to allocate structure\n",
- np->full_name);
- continue;
- }
-
- /* Setup pointers to chip functions */
- gef_gpio_chip->gc.of_gpio_n_cells = 2;
- gef_gpio_chip->gc.ngpio = 19;
- gef_gpio_chip->gc.direction_input = gef_gpio_dir_in;
- gef_gpio_chip->gc.direction_output = gef_gpio_dir_out;
- gef_gpio_chip->gc.get = gef_gpio_get;
- gef_gpio_chip->gc.set = gef_gpio_set;
-
- /* This function adds a memory mapped GPIO chip */
- retval = of_mm_gpiochip_add(np, gef_gpio_chip);
- if (retval) {
- kfree(gef_gpio_chip);
- pr_err("%s: Unable to add GPIO\n", np->full_name);
- }
- }
-
- for_each_compatible_node(np, NULL, "gef,sbc310-gpio") {
-
- pr_debug("%s: Initialising GEF GPIO\n", np->full_name);
-
- /* Allocate chip structure */
- gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL);
- if (!gef_gpio_chip) {
- pr_err("%s: Unable to allocate structure\n",
- np->full_name);
- continue;
- }
-
- /* Setup pointers to chip functions */
- gef_gpio_chip->gc.of_gpio_n_cells = 2;
- gef_gpio_chip->gc.ngpio = 6;
- gef_gpio_chip->gc.direction_input = gef_gpio_dir_in;
- gef_gpio_chip->gc.direction_output = gef_gpio_dir_out;
- gef_gpio_chip->gc.get = gef_gpio_get;
- gef_gpio_chip->gc.set = gef_gpio_set;
-
- /* This function adds a memory mapped GPIO chip */
- retval = of_mm_gpiochip_add(np, gef_gpio_chip);
- if (retval) {
- kfree(gef_gpio_chip);
- pr_err("%s: Unable to add GPIO\n", np->full_name);
- }
- }
-
- for_each_compatible_node(np, NULL, "ge,imp3a-gpio") {
-
- pr_debug("%s: Initialising GE GPIO\n", np->full_name);
-
- /* Allocate chip structure */
- gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL);
- if (!gef_gpio_chip) {
- pr_err("%s: Unable to allocate structure\n",
- np->full_name);
- continue;
- }
-
- /* Setup pointers to chip functions */
- gef_gpio_chip->gc.of_gpio_n_cells = 2;
- gef_gpio_chip->gc.ngpio = 16;
- gef_gpio_chip->gc.direction_input = gef_gpio_dir_in;
- gef_gpio_chip->gc.direction_output = gef_gpio_dir_out;
- gef_gpio_chip->gc.get = gef_gpio_get;
- gef_gpio_chip->gc.set = gef_gpio_set;
-
- /* This function adds a memory mapped GPIO chip */
- retval = of_mm_gpiochip_add(np, gef_gpio_chip);
- if (retval) {
- kfree(gef_gpio_chip);
- pr_err("%s: Unable to add GPIO\n", np->full_name);
- }
- }
+ const struct of_device_id *of_id =
+ of_match_device(gef_gpio_ids, &pdev->dev);
+ struct of_mm_gpio_chip *mmchip;
+
+ mmchip = devm_kzalloc(&pdev->dev, sizeof(*mmchip), GFP_KERNEL);
+ if (!mmchip)
+ return -ENOMEM;
+
+ /* Setup pointers to chip functions */
+ mmchip->gc.ngpio = (u16)(uintptr_t)of_id->data;
+ mmchip->gc.of_gpio_n_cells = 2;
+ mmchip->gc.direction_input = gef_gpio_dir_in;
+ mmchip->gc.direction_output = gef_gpio_dir_out;
+ mmchip->gc.get = gef_gpio_get;
+ mmchip->gc.set = gef_gpio_set;
+
+ /* This function adds a memory mapped GPIO chip */
+ return of_mm_gpiochip_add(pdev->dev.of_node, mmchip);
+};
- return 0;
+static struct platform_driver gef_gpio_driver = {
+ .driver = {
+ .name = "gef-gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = gef_gpio_ids,
+ },
};
-arch_initcall(gef_gpio_init);
+module_platform_driver_probe(gef_gpio_driver, gef_gpio_probe);
MODULE_DESCRIPTION("GE I/O FPGA GPIO driver");
MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com");
diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c
index b5dff9e742f8..16f6115e5bdb 100644
--- a/drivers/gpio/gpio-generic.c
+++ b/drivers/gpio/gpio-generic.c
@@ -388,9 +388,18 @@ static int bgpio_setup_direction(struct bgpio_chip *bgc,
return 0;
}
+static int bgpio_request(struct gpio_chip *chip, unsigned gpio_pin)
+{
+ if (gpio_pin < chip->ngpio)
+ return 0;
+
+ return -EINVAL;
+}
+
int bgpio_remove(struct bgpio_chip *bgc)
{
- return gpiochip_remove(&bgc->gc);
+ gpiochip_remove(&bgc->gc);
+ return 0;
}
EXPORT_SYMBOL_GPL(bgpio_remove);
@@ -413,6 +422,7 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
bgc->gc.label = dev_name(dev);
bgc->gc.base = -1;
bgc->gc.ngpio = bgc->bits;
+ bgc->gc.request = bgpio_request;
ret = bgpio_setup_io(bgc, dat, set, clr);
if (ret)
diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c
index 84d2478ec294..66ad3df9d9cf 100644
--- a/drivers/gpio/gpio-grgpio.c
+++ b/drivers/gpio/gpio-grgpio.c
@@ -468,9 +468,7 @@ static int grgpio_remove(struct platform_device *ofdev)
}
}
- ret = gpiochip_remove(&priv->bgc.gc);
- if (ret)
- goto out;
+ gpiochip_remove(&priv->bgc.gc);
if (priv->domain)
irq_domain_remove(priv->domain);
@@ -481,7 +479,7 @@ out:
return ret;
}
-static struct of_device_id grgpio_match[] = {
+static const struct of_device_id grgpio_match[] = {
{.name = "GAISLER_GPIO"},
{.name = "01_01a"},
{},
diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c
index 70304220a479..3784e81e7762 100644
--- a/drivers/gpio/gpio-ich.c
+++ b/drivers/gpio/gpio-ich.c
@@ -514,14 +514,7 @@ add_err:
static int ichx_gpio_remove(struct platform_device *pdev)
{
- int err;
-
- err = gpiochip_remove(&ichx_priv.chip);
- if (err) {
- dev_err(&pdev->dev, "%s failed, %d\n",
- "gpiochip_remove()", err);
- return err;
- }
+ gpiochip_remove(&ichx_priv.chip);
ichx_gpio_release_regions(ichx_priv.gpio_base, ichx_priv.use_gpio);
if (ichx_priv.pm_base)
diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c
index 118a6bf455d9..aa28c65eb6b4 100644
--- a/drivers/gpio/gpio-intel-mid.c
+++ b/drivers/gpio/gpio-intel-mid.c
@@ -28,12 +28,10 @@
#include <linux/stddef.h>
#include <linux/interrupt.h>
#include <linux/init.h>
-#include <linux/irq.h>
#include <linux/io.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
-#include <linux/irqdomain.h>
#define INTEL_MID_IRQ_TYPE_EDGE (1 << 0)
#define INTEL_MID_IRQ_TYPE_LEVEL (1 << 1)
@@ -78,10 +76,12 @@ struct intel_mid_gpio {
void __iomem *reg_base;
spinlock_t lock;
struct pci_dev *pdev;
- struct irq_domain *domain;
};
-#define to_intel_gpio_priv(chip) container_of(chip, struct intel_mid_gpio, chip)
+static inline struct intel_mid_gpio *to_intel_gpio_priv(struct gpio_chip *gc)
+{
+ return container_of(gc, struct intel_mid_gpio, chip);
+}
static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset,
enum GPIO_REG reg_type)
@@ -182,15 +182,10 @@ static int intel_gpio_direction_output(struct gpio_chip *chip,
return 0;
}
-static int intel_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- struct intel_mid_gpio *priv = to_intel_gpio_priv(chip);
- return irq_create_mapping(priv->domain, offset);
-}
-
static int intel_mid_irq_type(struct irq_data *d, unsigned type)
{
- struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct intel_mid_gpio *priv = to_intel_gpio_priv(gc);
u32 gpio = irqd_to_hwirq(d);
unsigned long flags;
u32 value;
@@ -231,33 +226,11 @@ static void intel_mid_irq_mask(struct irq_data *d)
{
}
-static int intel_mid_irq_reqres(struct irq_data *d)
-{
- struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d);
-
- if (gpio_lock_as_irq(&priv->chip, irqd_to_hwirq(d))) {
- dev_err(priv->chip.dev,
- "unable to lock HW IRQ %lu for IRQ\n",
- irqd_to_hwirq(d));
- return -EINVAL;
- }
- return 0;
-}
-
-static void intel_mid_irq_relres(struct irq_data *d)
-{
- struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d);
-
- gpio_unlock_as_irq(&priv->chip, irqd_to_hwirq(d));
-}
-
static struct irq_chip intel_mid_irqchip = {
.name = "INTEL_MID-GPIO",
.irq_mask = intel_mid_irq_mask,
.irq_unmask = intel_mid_irq_unmask,
.irq_set_type = intel_mid_irq_type,
- .irq_request_resources = intel_mid_irq_reqres,
- .irq_release_resources = intel_mid_irq_relres,
};
static const struct intel_mid_gpio_ddata gpio_lincroft = {
@@ -330,8 +303,9 @@ MODULE_DEVICE_TABLE(pci, intel_gpio_ids);
static void intel_mid_irq_handler(unsigned irq, struct irq_desc *desc)
{
+ struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+ struct intel_mid_gpio *priv = to_intel_gpio_priv(gc);
struct irq_data *data = irq_desc_get_irq_data(desc);
- struct intel_mid_gpio *priv = irq_data_get_irq_handler_data(data);
struct irq_chip *chip = irq_data_get_irq_chip(data);
u32 base, gpio, mask;
unsigned long pending;
@@ -345,7 +319,7 @@ static void intel_mid_irq_handler(unsigned irq, struct irq_desc *desc)
mask = BIT(gpio);
/* Clear before handling so we can't lose an edge */
writel(mask, gedr);
- generic_handle_irq(irq_find_mapping(priv->domain,
+ generic_handle_irq(irq_find_mapping(gc->irqdomain,
base + gpio));
}
}
@@ -371,23 +345,6 @@ static void intel_mid_irq_init_hw(struct intel_mid_gpio *priv)
}
}
-static int intel_gpio_irq_map(struct irq_domain *d, unsigned int irq,
- irq_hw_number_t hwirq)
-{
- struct intel_mid_gpio *priv = d->host_data;
-
- irq_set_chip_and_handler(irq, &intel_mid_irqchip, handle_simple_irq);
- irq_set_chip_data(irq, priv);
- irq_set_irq_type(irq, IRQ_TYPE_NONE);
-
- return 0;
-}
-
-static const struct irq_domain_ops intel_gpio_irq_ops = {
- .map = intel_gpio_irq_map,
- .xlate = irq_domain_xlate_twocell,
-};
-
static int intel_gpio_runtime_idle(struct device *dev)
{
int err = pm_schedule_suspend(dev, 500);
@@ -441,7 +398,6 @@ static int intel_gpio_probe(struct pci_dev *pdev,
priv->chip.direction_output = intel_gpio_direction_output;
priv->chip.get = intel_gpio_get;
priv->chip.set = intel_gpio_set;
- priv->chip.to_irq = intel_gpio_to_irq;
priv->chip.base = gpio_base;
priv->chip.ngpio = ddata->ngpio;
priv->chip.can_sleep = false;
@@ -449,11 +405,6 @@ static int intel_gpio_probe(struct pci_dev *pdev,
spin_lock_init(&priv->lock);
- priv->domain = irq_domain_add_simple(pdev->dev.of_node, ddata->ngpio,
- irq_base, &intel_gpio_irq_ops, priv);
- if (!priv->domain)
- return -ENOMEM;
-
pci_set_drvdata(pdev, priv);
retval = gpiochip_add(&priv->chip);
if (retval) {
@@ -461,10 +412,23 @@ static int intel_gpio_probe(struct pci_dev *pdev,
return retval;
}
+ retval = gpiochip_irqchip_add(&priv->chip,
+ &intel_mid_irqchip,
+ irq_base,
+ handle_simple_irq,
+ IRQ_TYPE_NONE);
+ if (retval) {
+ dev_err(&pdev->dev,
+ "could not connect irqchip to gpiochip\n");
+ return retval;
+ }
+
intel_mid_irq_init_hw(priv);
- irq_set_handler_data(pdev->irq, priv);
- irq_set_chained_handler(pdev->irq, intel_mid_irq_handler);
+ gpiochip_set_chained_irqchip(&priv->chip,
+ &intel_mid_irqchip,
+ pdev->irq,
+ intel_mid_irq_handler);
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_allow(&pdev->dev);
diff --git a/drivers/gpio/gpio-it8761e.c b/drivers/gpio/gpio-it8761e.c
index 278b81317010..dadfc245cf09 100644
--- a/drivers/gpio/gpio-it8761e.c
+++ b/drivers/gpio/gpio-it8761e.c
@@ -217,11 +217,7 @@ gpiochip_add_err:
static void __exit it8761e_gpio_exit(void)
{
if (gpio_ba) {
- int ret = gpiochip_remove(&it8761e_gpio_chip);
-
- WARN(ret, "%s(): gpiochip_remove() failed, ret=%d\n",
- __func__, ret);
-
+ gpiochip_remove(&it8761e_gpio_chip);
release_region(gpio_ba, GPIO_IOSIZE);
gpio_ba = 0;
}
diff --git a/drivers/gpio/gpio-janz-ttl.c b/drivers/gpio/gpio-janz-ttl.c
index 2ecd3a09c743..29ffe22ad97a 100644
--- a/drivers/gpio/gpio-janz-ttl.c
+++ b/drivers/gpio/gpio-janz-ttl.c
@@ -152,34 +152,21 @@ static int ttl_probe(struct platform_device *pdev)
pdata = dev_get_platdata(&pdev->dev);
if (!pdata) {
dev_err(dev, "no platform data\n");
- ret = -ENXIO;
- goto out_return;
+ return -ENXIO;
}
- mod = kzalloc(sizeof(*mod), GFP_KERNEL);
- if (!mod) {
- dev_err(dev, "unable to allocate private data\n");
- ret = -ENOMEM;
- goto out_return;
- }
+ mod = devm_kzalloc(dev, sizeof(*mod), GFP_KERNEL);
+ if (!mod)
+ return -ENOMEM;
platform_set_drvdata(pdev, mod);
spin_lock_init(&mod->lock);
/* get access to the MODULbus registers for this module */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "MODULbus registers not found\n");
- ret = -ENODEV;
- goto out_free_mod;
- }
-
- mod->regs = ioremap(res->start, resource_size(res));
- if (!mod->regs) {
- dev_err(dev, "MODULbus registers not ioremap\n");
- ret = -ENOMEM;
- goto out_free_mod;
- }
+ mod->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(mod->regs))
+ return PTR_ERR(mod->regs);
ttl_setup_device(mod);
@@ -198,33 +185,18 @@ static int ttl_probe(struct platform_device *pdev)
ret = gpiochip_add(gpio);
if (ret) {
dev_err(dev, "unable to add GPIO chip\n");
- goto out_iounmap_regs;
+ return ret;
}
return 0;
-
-out_iounmap_regs:
- iounmap(mod->regs);
-out_free_mod:
- kfree(mod);
-out_return:
- return ret;
}
static int ttl_remove(struct platform_device *pdev)
{
struct ttl_module *mod = platform_get_drvdata(pdev);
- struct device *dev = &pdev->dev;
- int ret;
- ret = gpiochip_remove(&mod->gpio);
- if (ret) {
- dev_err(dev, "unable to remove GPIO chip\n");
- return ret;
- }
+ gpiochip_remove(&mod->gpio);
- iounmap(mod->regs);
- kfree(mod);
return 0;
}
diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c
index c6d88173f5a2..fd150adeebf9 100644
--- a/drivers/gpio/gpio-kempld.c
+++ b/drivers/gpio/gpio-kempld.c
@@ -24,7 +24,7 @@
#include <linux/mfd/kempld.h>
#define KEMPLD_GPIO_MAX_NUM 16
-#define KEMPLD_GPIO_MASK(x) (1 << ((x) % 8))
+#define KEMPLD_GPIO_MASK(x) (BIT((x) % 8))
#define KEMPLD_GPIO_DIR_NUM(x) (0x40 + (x) / 8)
#define KEMPLD_GPIO_LVL_NUM(x) (0x42 + (x) / 8)
#define KEMPLD_GPIO_EVT_LVL_EDGE 0x46
@@ -199,7 +199,8 @@ static int kempld_gpio_remove(struct platform_device *pdev)
{
struct kempld_gpio_data *gpio = platform_get_drvdata(pdev);
- return gpiochip_remove(&gpio->chip);
+ gpiochip_remove(&gpio->chip);
+ return 0;
}
static struct platform_driver kempld_gpio_driver = {
@@ -216,4 +217,4 @@ module_platform_driver(kempld_gpio_driver);
MODULE_DESCRIPTION("KEM PLD GPIO Driver");
MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:gpio-kempld");
+MODULE_ALIAS("platform:kempld-gpio");
diff --git a/drivers/gpio/gpio-lp3943.c b/drivers/gpio/gpio-lp3943.c
index a0341c92bcb4..6bbdad805b78 100644
--- a/drivers/gpio/gpio-lp3943.c
+++ b/drivers/gpio/gpio-lp3943.c
@@ -216,7 +216,8 @@ static int lp3943_gpio_remove(struct platform_device *pdev)
{
struct lp3943_gpio *lp3943_gpio = platform_get_drvdata(pdev);
- return gpiochip_remove(&lp3943_gpio->chip);
+ gpiochip_remove(&lp3943_gpio->chip);
+ return 0;
}
static const struct of_device_id lp3943_gpio_of_match[] = {
diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c
index 225344d66404..b9b9799b368b 100644
--- a/drivers/gpio/gpio-lpc32xx.c
+++ b/drivers/gpio/gpio-lpc32xx.c
@@ -560,7 +560,7 @@ static int lpc32xx_gpio_probe(struct platform_device *pdev)
}
#ifdef CONFIG_OF
-static struct of_device_id lpc32xx_gpio_of_match[] = {
+static const struct of_device_id lpc32xx_gpio_of_match[] = {
{ .compatible = "nxp,lpc3220-gpio", },
{ },
};
diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c
index 9a82a9074a2c..ff9eb911b5e4 100644
--- a/drivers/gpio/gpio-lynxpoint.c
+++ b/drivers/gpio/gpio-lynxpoint.c
@@ -25,9 +25,7 @@
#include <linux/types.h>
#include <linux/bitops.h>
#include <linux/interrupt.h>
-#include <linux/irq.h>
#include <linux/gpio.h>
-#include <linux/irqdomain.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/platform_device.h>
@@ -62,7 +60,6 @@
struct lp_gpio {
struct gpio_chip chip;
- struct irq_domain *domain;
struct platform_device *pdev;
spinlock_t lock;
unsigned long reg_base;
@@ -151,7 +148,8 @@ static void lp_gpio_free(struct gpio_chip *chip, unsigned offset)
static int lp_irq_type(struct irq_data *d, unsigned type)
{
- struct lp_gpio *lg = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct lp_gpio *lg = container_of(gc, struct lp_gpio, chip);
u32 hwirq = irqd_to_hwirq(d);
unsigned long flags;
u32 value;
@@ -236,16 +234,11 @@ static int lp_gpio_direction_output(struct gpio_chip *chip,
return 0;
}
-static int lp_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
- return irq_create_mapping(lg->domain, offset);
-}
-
static void lp_gpio_irq_handler(unsigned hwirq, struct irq_desc *desc)
{
struct irq_data *data = irq_desc_get_irq_data(desc);
- struct lp_gpio *lg = irq_data_get_irq_handler_data(data);
+ struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+ struct lp_gpio *lg = container_of(gc, struct lp_gpio, chip);
struct irq_chip *chip = irq_data_get_irq_chip(data);
u32 base, pin, mask;
unsigned long reg, ena, pending;
@@ -262,7 +255,7 @@ static void lp_gpio_irq_handler(unsigned hwirq, struct irq_desc *desc)
mask = BIT(pin);
/* Clear before handling so we don't lose an edge */
outl(mask, reg);
- irq = irq_find_mapping(lg->domain, base + pin);
+ irq = irq_find_mapping(lg->chip.irqdomain, base + pin);
generic_handle_irq(irq);
}
}
@@ -279,7 +272,8 @@ static void lp_irq_mask(struct irq_data *d)
static void lp_irq_enable(struct irq_data *d)
{
- struct lp_gpio *lg = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct lp_gpio *lg = container_of(gc, struct lp_gpio, chip);
u32 hwirq = irqd_to_hwirq(d);
unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE);
unsigned long flags;
@@ -291,7 +285,8 @@ static void lp_irq_enable(struct irq_data *d)
static void lp_irq_disable(struct irq_data *d)
{
- struct lp_gpio *lg = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct lp_gpio *lg = container_of(gc, struct lp_gpio, chip);
u32 hwirq = irqd_to_hwirq(d);
unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE);
unsigned long flags;
@@ -301,26 +296,6 @@ static void lp_irq_disable(struct irq_data *d)
spin_unlock_irqrestore(&lg->lock, flags);
}
-static int lp_irq_reqres(struct irq_data *d)
-{
- struct lp_gpio *lg = irq_data_get_irq_chip_data(d);
-
- if (gpio_lock_as_irq(&lg->chip, irqd_to_hwirq(d))) {
- dev_err(lg->chip.dev,
- "unable to lock HW IRQ %lu for IRQ\n",
- irqd_to_hwirq(d));
- return -EINVAL;
- }
- return 0;
-}
-
-static void lp_irq_relres(struct irq_data *d)
-{
- struct lp_gpio *lg = irq_data_get_irq_chip_data(d);
-
- gpio_unlock_as_irq(&lg->chip, irqd_to_hwirq(d));
-}
-
static struct irq_chip lp_irqchip = {
.name = "LP-GPIO",
.irq_mask = lp_irq_mask,
@@ -328,8 +303,6 @@ static struct irq_chip lp_irqchip = {
.irq_enable = lp_irq_enable,
.irq_disable = lp_irq_disable,
.irq_set_type = lp_irq_type,
- .irq_request_resources = lp_irq_reqres,
- .irq_release_resources = lp_irq_relres,
.flags = IRQCHIP_SKIP_SET_WAKE,
};
@@ -348,22 +321,6 @@ static void lp_gpio_irq_init_hw(struct lp_gpio *lg)
}
}
-static int lp_gpio_irq_map(struct irq_domain *d, unsigned int irq,
- irq_hw_number_t hwirq)
-{
- struct lp_gpio *lg = d->host_data;
-
- irq_set_chip_and_handler(irq, &lp_irqchip, handle_simple_irq);
- irq_set_chip_data(irq, lg);
- irq_set_irq_type(irq, IRQ_TYPE_NONE);
-
- return 0;
-}
-
-static const struct irq_domain_ops lp_gpio_irq_ops = {
- .map = lp_gpio_irq_map,
-};
-
static int lp_gpio_probe(struct platform_device *pdev)
{
struct lp_gpio *lg;
@@ -371,14 +328,11 @@ static int lp_gpio_probe(struct platform_device *pdev)
struct resource *io_rc, *irq_rc;
struct device *dev = &pdev->dev;
unsigned long reg_len;
- unsigned hwirq;
int ret = -ENODEV;
lg = devm_kzalloc(dev, sizeof(struct lp_gpio), GFP_KERNEL);
- if (!lg) {
- dev_err(dev, "can't allocate lp_gpio chip data\n");
+ if (!lg)
return -ENOMEM;
- }
lg->pdev = pdev;
platform_set_drvdata(pdev, lg);
@@ -416,27 +370,28 @@ static int lp_gpio_probe(struct platform_device *pdev)
gc->can_sleep = false;
gc->dev = dev;
+ ret = gpiochip_add(gc);
+ if (ret) {
+ dev_err(dev, "failed adding lp-gpio chip\n");
+ return ret;
+ }
+
/* set up interrupts */
if (irq_rc && irq_rc->start) {
- hwirq = irq_rc->start;
- gc->to_irq = lp_gpio_to_irq;
-
- lg->domain = irq_domain_add_linear(NULL, LP_NUM_GPIO,
- &lp_gpio_irq_ops, lg);
- if (!lg->domain)
- return -ENXIO;
-
lp_gpio_irq_init_hw(lg);
+ ret = gpiochip_irqchip_add(gc, &lp_irqchip, 0,
+ handle_simple_irq, IRQ_TYPE_NONE);
+ if (ret) {
+ dev_err(dev, "failed to add irqchip\n");
+ gpiochip_remove(gc);
+ return ret;
+ }
- irq_set_handler_data(hwirq, lg);
- irq_set_chained_handler(hwirq, lp_gpio_irq_handler);
+ gpiochip_set_chained_irqchip(gc, &lp_irqchip,
+ (unsigned)irq_rc->start,
+ lp_gpio_irq_handler);
}
- ret = gpiochip_add(gc);
- if (ret) {
- dev_err(dev, "failed adding lp-gpio chip\n");
- return ret;
- }
pm_runtime_enable(dev);
return 0;
@@ -467,11 +422,8 @@ MODULE_DEVICE_TABLE(acpi, lynxpoint_gpio_acpi_match);
static int lp_gpio_remove(struct platform_device *pdev)
{
struct lp_gpio *lg = platform_get_drvdata(pdev);
- int err;
pm_runtime_disable(&pdev->dev);
- err = gpiochip_remove(&lg->chip);
- if (err)
- dev_warn(&pdev->dev, "failed to remove gpio_chip.\n");
+ gpiochip_remove(&lg->chip);
return 0;
}
diff --git a/drivers/gpio/gpio-max730x.c b/drivers/gpio/gpio-max730x.c
index 8672755f95c9..18ab89e20806 100644
--- a/drivers/gpio/gpio-max730x.c
+++ b/drivers/gpio/gpio-max730x.c
@@ -228,22 +228,16 @@ EXPORT_SYMBOL_GPL(__max730x_probe);
int __max730x_remove(struct device *dev)
{
struct max7301 *ts = dev_get_drvdata(dev);
- int ret;
if (ts == NULL)
return -ENODEV;
/* Power down the chip and disable IRQ output */
ts->write(dev, 0x04, 0x00);
-
- ret = gpiochip_remove(&ts->chip);
- if (!ret) {
- mutex_destroy(&ts->lock);
- kfree(ts);
- } else
- dev_err(dev, "Failed to remove GPIO controller: %d\n", ret);
-
- return ret;
+ gpiochip_remove(&ts->chip);
+ mutex_destroy(&ts->lock);
+ kfree(ts);
+ return 0;
}
EXPORT_SYMBOL_GPL(__max730x_remove);
diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c
index 7c36f2b0983d..6c676225b886 100644
--- a/drivers/gpio/gpio-max732x.c
+++ b/drivers/gpio/gpio-max732x.c
@@ -676,12 +676,7 @@ static int max732x_remove(struct i2c_client *client)
}
}
- ret = gpiochip_remove(&chip->gpio_chip);
- if (ret) {
- dev_err(&client->dev, "%s failed, %d\n",
- "gpiochip_remove()", ret);
- return ret;
- }
+ gpiochip_remove(&chip->gpio_chip);
max732x_irq_teardown(chip);
diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c
index 553a80a5eaf3..4e3e160e5db2 100644
--- a/drivers/gpio/gpio-mc33880.c
+++ b/drivers/gpio/gpio-mc33880.c
@@ -149,20 +149,15 @@ exit_destroy:
static int mc33880_remove(struct spi_device *spi)
{
struct mc33880 *mc;
- int ret;
mc = spi_get_drvdata(spi);
if (mc == NULL)
return -ENODEV;
- ret = gpiochip_remove(&mc->chip);
- if (!ret)
- mutex_destroy(&mc->lock);
- else
- dev_err(&spi->dev, "Failed to remove the GPIO controller: %d\n",
- ret);
+ gpiochip_remove(&mc->chip);
+ mutex_destroy(&mc->lock);
- return ret;
+ return 0;
}
static struct spi_driver mc33880_driver = {
diff --git a/drivers/gpio/gpio-mc9s08dz60.c b/drivers/gpio/gpio-mc9s08dz60.c
index dce35ff00db7..d62b4f8182bf 100644
--- a/drivers/gpio/gpio-mc9s08dz60.c
+++ b/drivers/gpio/gpio-mc9s08dz60.c
@@ -118,7 +118,8 @@ static int mc9s08dz60_remove(struct i2c_client *client)
mc9s = i2c_get_clientdata(client);
- return gpiochip_remove(&mc9s->chip);
+ gpiochip_remove(&mc9s->chip);
+ return 0;
}
static const struct i2c_device_id mc9s08dz60_id[] = {
diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c
index 3d53fd6880d1..6f183d9b487e 100644
--- a/drivers/gpio/gpio-mcp23s08.c
+++ b/drivers/gpio/gpio-mcp23s08.c
@@ -714,7 +714,7 @@ fail:
#ifdef CONFIG_OF
#ifdef CONFIG_SPI_MASTER
-static struct of_device_id mcp23s08_spi_of_match[] = {
+static const struct of_device_id mcp23s08_spi_of_match[] = {
{
.compatible = "microchip,mcp23s08",
.data = (void *) MCP_TYPE_S08,
@@ -738,7 +738,7 @@ MODULE_DEVICE_TABLE(of, mcp23s08_spi_of_match);
#endif
#if IS_ENABLED(CONFIG_I2C)
-static struct of_device_id mcp23s08_i2c_of_match[] = {
+static const struct of_device_id mcp23s08_i2c_of_match[] = {
{
.compatible = "microchip,mcp23008",
.data = (void *) MCP_TYPE_008,
@@ -812,16 +812,14 @@ fail:
static int mcp230xx_remove(struct i2c_client *client)
{
struct mcp23s08 *mcp = i2c_get_clientdata(client);
- int status;
if (client->irq && mcp->irq_controller)
mcp23s08_irq_teardown(mcp);
- status = gpiochip_remove(&mcp->chip);
- if (status == 0)
- kfree(mcp);
+ gpiochip_remove(&mcp->chip);
+ kfree(mcp);
- return status;
+ return 0;
}
static const struct i2c_device_id mcp230xx_id[] = {
@@ -867,7 +865,7 @@ static int mcp23s08_probe(struct spi_device *spi)
{
struct mcp23s08_platform_data *pdata;
unsigned addr;
- unsigned chips = 0;
+ int chips = 0;
struct mcp23s08_driver_data *data;
int status, type;
unsigned base = -1,
@@ -894,10 +892,11 @@ static int mcp23s08_probe(struct spi_device *spi)
dev_err(&spi->dev, "invalid spi-present-mask\n");
return -ENODEV;
}
+
for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) {
- if ((spi_present_mask & (1 << addr)))
- chips++;
pullups[addr] = 0;
+ if (spi_present_mask & (1 << addr))
+ chips++;
}
} else {
type = spi_get_device_id(spi)->driver_data;
@@ -959,13 +958,10 @@ static int mcp23s08_probe(struct spi_device *spi)
fail:
for (addr = 0; addr < ARRAY_SIZE(data->mcp); addr++) {
- int tmp;
if (!data->mcp[addr])
continue;
- tmp = gpiochip_remove(&data->mcp[addr]->chip);
- if (tmp < 0)
- dev_err(&spi->dev, "%s --> %d\n", "remove", tmp);
+ gpiochip_remove(&data->mcp[addr]->chip);
}
kfree(data);
return status;
@@ -975,23 +971,16 @@ static int mcp23s08_remove(struct spi_device *spi)
{
struct mcp23s08_driver_data *data = spi_get_drvdata(spi);
unsigned addr;
- int status = 0;
for (addr = 0; addr < ARRAY_SIZE(data->mcp); addr++) {
- int tmp;
if (!data->mcp[addr])
continue;
- tmp = gpiochip_remove(&data->mcp[addr]->chip);
- if (tmp < 0) {
- dev_err(&spi->dev, "%s --> %d\n", "remove", tmp);
- status = tmp;
- }
+ gpiochip_remove(&data->mcp[addr]->chip);
}
- if (status == 0)
- kfree(data);
- return status;
+ kfree(data);
+ return 0;
}
static const struct spi_device_id mcp23s08_ids[] = {
diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c
index d51329d23d38..5536108aa9db 100644
--- a/drivers/gpio/gpio-ml-ioh.c
+++ b/drivers/gpio/gpio-ml-ioh.c
@@ -497,8 +497,7 @@ err_irq_alloc_descs:
err_gpiochip_add:
while (--i >= 0) {
chip--;
- if (gpiochip_remove(&chip->gpio))
- dev_err(&pdev->dev, "Failed gpiochip_remove(%d)\n", i);
+ gpiochip_remove(&chip->gpio);
}
kfree(chip_save);
@@ -519,7 +518,6 @@ err_pci_enable:
static void ioh_gpio_remove(struct pci_dev *pdev)
{
- int err;
int i;
struct ioh_gpio *chip = pci_get_drvdata(pdev);
void *chip_save;
@@ -530,9 +528,7 @@ static void ioh_gpio_remove(struct pci_dev *pdev)
for (i = 0; i < 8; i++, chip++) {
irq_free_descs(chip->irq_base, num_ports[i]);
- err = gpiochip_remove(&chip->gpio);
- if (err)
- dev_err(&pdev->dev, "Failed gpiochip_remove\n");
+ gpiochip_remove(&chip->gpio);
}
chip = chip_save;
diff --git a/drivers/gpio/gpio-moxart.c b/drivers/gpio/gpio-moxart.c
index ccd45704e5fd..4661e181be04 100644
--- a/drivers/gpio/gpio-moxart.c
+++ b/drivers/gpio/gpio-moxart.c
@@ -113,10 +113,8 @@ static int moxart_gpio_probe(struct platform_device *pdev)
int ret;
mgc = devm_kzalloc(dev, sizeof(*mgc), GFP_KERNEL);
- if (!mgc) {
- dev_err(dev, "can't allocate GPIO chip container\n");
+ if (!mgc)
return -ENOMEM;
- }
mgc->gpio = moxart_template_chip;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c
index a3351acd4963..94f57670df9a 100644
--- a/drivers/gpio/gpio-msm-v2.c
+++ b/drivers/gpio/gpio-msm-v2.c
@@ -438,10 +438,7 @@ MODULE_DEVICE_TABLE(of, msm_gpio_of_match);
static int msm_gpio_remove(struct platform_device *dev)
{
- int ret = gpiochip_remove(&msm_gpio.gpio_chip);
-
- if (ret < 0)
- return ret;
+ gpiochip_remove(&msm_gpio.gpio_chip);
irq_set_handler(msm_gpio.summary_irq, NULL);
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index d42509422394..418e38650363 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -535,7 +535,7 @@ static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
#define mvebu_gpio_dbg_show NULL
#endif
-static struct of_device_id mvebu_gpio_of_match[] = {
+static const struct of_device_id mvebu_gpio_of_match[] = {
{
.compatible = "marvell,orion-gpio",
.data = (void *) MVEBU_GPIO_SOC_VARIANT_ORION,
@@ -574,10 +574,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION;
mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip), GFP_KERNEL);
- if (!mvchip) {
- dev_err(&pdev->dev, "Cannot allocate memory\n");
+ if (!mvchip)
return -ENOMEM;
- }
if (of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios)) {
dev_err(&pdev->dev, "Missing ngpios OF property\n");
@@ -738,9 +736,4 @@ static struct platform_driver mvebu_gpio_driver = {
},
.probe = mvebu_gpio_probe,
};
-
-static int __init mvebu_gpio_init(void)
-{
- return platform_driver_register(&mvebu_gpio_driver);
-}
-postcore_initcall(mvebu_gpio_init);
+module_platform_driver(mvebu_gpio_driver);
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index db83b3c0a449..f4e54a92e04a 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -485,7 +485,7 @@ static int mxc_gpio_probe(struct platform_device *pdev)
out_irqdesc_free:
irq_free_descs(irq_base, 32);
out_gpiochip_remove:
- WARN_ON(gpiochip_remove(&port->bgc.gc) < 0);
+ gpiochip_remove(&port->bgc.gc);
out_bgpio_remove:
bgpio_remove(&port->bgc);
out_bgio:
diff --git a/drivers/gpio/gpio-octeon.c b/drivers/gpio/gpio-octeon.c
index dbb08546b9ec..5c5770c99c80 100644
--- a/drivers/gpio/gpio-octeon.c
+++ b/drivers/gpio/gpio-octeon.c
@@ -129,7 +129,8 @@ out:
static int octeon_gpio_remove(struct platform_device *pdev)
{
struct gpio_chip *chip = pdev->dev.platform_data;
- return gpiochip_remove(chip);
+ gpiochip_remove(chip);
+ return 0;
}
static struct of_device_id octeon_gpio_match[] = {
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 19b886c21b1d..174932165fcb 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -24,9 +24,8 @@
#include <linux/pm.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/irqdomain.h>
-#include <linux/irqchip/chained_irq.h>
#include <linux/gpio.h>
+#include <linux/bitops.h>
#include <linux/platform_data/gpio-omap.h>
#define OFF_MODE 1
@@ -52,7 +51,6 @@ struct gpio_bank {
struct list_head node;
void __iomem *base;
u16 irq;
- struct irq_domain *domain;
u32 non_wakeup_gpios;
u32 enabled_non_wakeup_gpios;
struct gpio_regs context;
@@ -84,25 +82,25 @@ struct gpio_bank {
};
#define GPIO_INDEX(bank, gpio) (gpio % bank->width)
-#define GPIO_BIT(bank, gpio) (1 << GPIO_INDEX(bank, gpio))
+#define GPIO_BIT(bank, gpio) (BIT(GPIO_INDEX(bank, gpio)))
#define GPIO_MOD_CTRL_BIT BIT(0)
#define BANK_USED(bank) (bank->mod_usage || bank->irq_usage)
-#define LINE_USED(line, offset) (line & (1 << offset))
+#define LINE_USED(line, offset) (line & (BIT(offset)))
-static int irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq)
+static int omap_irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq)
{
return bank->chip.base + gpio_irq;
}
-static int omap_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+static inline struct gpio_bank *omap_irq_data_get_bank(struct irq_data *d)
{
- struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
-
- return irq_find_mapping(bank->domain, offset);
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+ return container_of(chip, struct gpio_bank, chip);
}
-static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
+static void omap_set_gpio_direction(struct gpio_bank *bank, int gpio,
+ int is_input)
{
void __iomem *reg = bank->base;
u32 l;
@@ -110,16 +108,17 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
reg += bank->regs->direction;
l = readl_relaxed(reg);
if (is_input)
- l |= 1 << gpio;
+ l |= BIT(gpio);
else
- l &= ~(1 << gpio);
+ l &= ~(BIT(gpio));
writel_relaxed(l, reg);
bank->context.oe = l;
}
/* set data out value using dedicate set/clear register */
-static void _set_gpio_dataout_reg(struct gpio_bank *bank, int gpio, int enable)
+static void omap_set_gpio_dataout_reg(struct gpio_bank *bank, int gpio,
+ int enable)
{
void __iomem *reg = bank->base;
u32 l = GPIO_BIT(bank, gpio);
@@ -136,7 +135,8 @@ static void _set_gpio_dataout_reg(struct gpio_bank *bank, int gpio, int enable)
}
/* set data out value using mask register */
-static void _set_gpio_dataout_mask(struct gpio_bank *bank, int gpio, int enable)
+static void omap_set_gpio_dataout_mask(struct gpio_bank *bank, int gpio,
+ int enable)
{
void __iomem *reg = bank->base + bank->regs->dataout;
u32 gpio_bit = GPIO_BIT(bank, gpio);
@@ -151,21 +151,21 @@ static void _set_gpio_dataout_mask(struct gpio_bank *bank, int gpio, int enable)
bank->context.dataout = l;
}
-static int _get_gpio_datain(struct gpio_bank *bank, int offset)
+static int omap_get_gpio_datain(struct gpio_bank *bank, int offset)
{
void __iomem *reg = bank->base + bank->regs->datain;
- return (readl_relaxed(reg) & (1 << offset)) != 0;
+ return (readl_relaxed(reg) & (BIT(offset))) != 0;
}
-static int _get_gpio_dataout(struct gpio_bank *bank, int offset)
+static int omap_get_gpio_dataout(struct gpio_bank *bank, int offset)
{
void __iomem *reg = bank->base + bank->regs->dataout;
- return (readl_relaxed(reg) & (1 << offset)) != 0;
+ return (readl_relaxed(reg) & (BIT(offset))) != 0;
}
-static inline void _gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set)
+static inline void omap_gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set)
{
int l = readl_relaxed(base + reg);
@@ -177,10 +177,10 @@ static inline void _gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set)
writel_relaxed(l, base + reg);
}
-static inline void _gpio_dbck_enable(struct gpio_bank *bank)
+static inline void omap_gpio_dbck_enable(struct gpio_bank *bank)
{
if (bank->dbck_enable_mask && !bank->dbck_enabled) {
- clk_enable(bank->dbck);
+ clk_prepare_enable(bank->dbck);
bank->dbck_enabled = true;
writel_relaxed(bank->dbck_enable_mask,
@@ -188,7 +188,7 @@ static inline void _gpio_dbck_enable(struct gpio_bank *bank)
}
}
-static inline void _gpio_dbck_disable(struct gpio_bank *bank)
+static inline void omap_gpio_dbck_disable(struct gpio_bank *bank)
{
if (bank->dbck_enable_mask && bank->dbck_enabled) {
/*
@@ -198,13 +198,13 @@ static inline void _gpio_dbck_disable(struct gpio_bank *bank)
*/
writel_relaxed(0, bank->base + bank->regs->debounce_en);
- clk_disable(bank->dbck);
+ clk_disable_unprepare(bank->dbck);
bank->dbck_enabled = false;
}
}
/**
- * _set_gpio_debounce - low level gpio debounce time
+ * omap2_set_gpio_debounce - low level gpio debounce time
* @bank: the gpio bank we're acting upon
* @gpio: the gpio number on this @gpio
* @debounce: debounce time to use
@@ -212,8 +212,8 @@ static inline void _gpio_dbck_disable(struct gpio_bank *bank)
* OMAP's debounce time is in 31us steps so we need
* to convert and round up to the closest unit.
*/
-static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
- unsigned debounce)
+static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
+ unsigned debounce)
{
void __iomem *reg;
u32 val;
@@ -231,7 +231,7 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
l = GPIO_BIT(bank, gpio);
- clk_enable(bank->dbck);
+ clk_prepare_enable(bank->dbck);
reg = bank->base + bank->regs->debounce;
writel_relaxed(debounce, reg);
@@ -245,7 +245,7 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
bank->dbck_enable_mask = val;
writel_relaxed(val, reg);
- clk_disable(bank->dbck);
+ clk_disable_unprepare(bank->dbck);
/*
* Enable debounce clock per module.
* This call is mandatory because in omap_gpio_request() when
@@ -254,7 +254,7 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
* used within _gpio_dbck_enable() is still not initialized at
* that point. Therefore we have to enable dbck here.
*/
- _gpio_dbck_enable(bank);
+ omap_gpio_dbck_enable(bank);
if (bank->dbck_enable_mask) {
bank->context.debounce = debounce;
bank->context.debounce_en = val;
@@ -262,7 +262,7 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
}
/**
- * _clear_gpio_debounce - clear debounce settings for a gpio
+ * omap_clear_gpio_debounce - clear debounce settings for a gpio
* @bank: the gpio bank we're acting upon
* @gpio: the gpio number on this @gpio
*
@@ -271,7 +271,7 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
* time too. The debounce clock will also be disabled when calling this function
* if this is the only gpio in the bank using debounce.
*/
-static void _clear_gpio_debounce(struct gpio_bank *bank, unsigned gpio)
+static void omap_clear_gpio_debounce(struct gpio_bank *bank, unsigned gpio)
{
u32 gpio_bit = GPIO_BIT(bank, gpio);
@@ -290,25 +290,25 @@ static void _clear_gpio_debounce(struct gpio_bank *bank, unsigned gpio)
bank->context.debounce = 0;
writel_relaxed(bank->context.debounce, bank->base +
bank->regs->debounce);
- clk_disable(bank->dbck);
+ clk_disable_unprepare(bank->dbck);
bank->dbck_enabled = false;
}
}
-static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio,
+static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
unsigned trigger)
{
void __iomem *base = bank->base;
- u32 gpio_bit = 1 << gpio;
+ u32 gpio_bit = BIT(gpio);
- _gpio_rmw(base, bank->regs->leveldetect0, gpio_bit,
- trigger & IRQ_TYPE_LEVEL_LOW);
- _gpio_rmw(base, bank->regs->leveldetect1, gpio_bit,
- trigger & IRQ_TYPE_LEVEL_HIGH);
- _gpio_rmw(base, bank->regs->risingdetect, gpio_bit,
- trigger & IRQ_TYPE_EDGE_RISING);
- _gpio_rmw(base, bank->regs->fallingdetect, gpio_bit,
- trigger & IRQ_TYPE_EDGE_FALLING);
+ omap_gpio_rmw(base, bank->regs->leveldetect0, gpio_bit,
+ trigger & IRQ_TYPE_LEVEL_LOW);
+ omap_gpio_rmw(base, bank->regs->leveldetect1, gpio_bit,
+ trigger & IRQ_TYPE_LEVEL_HIGH);
+ omap_gpio_rmw(base, bank->regs->risingdetect, gpio_bit,
+ trigger & IRQ_TYPE_EDGE_RISING);
+ omap_gpio_rmw(base, bank->regs->fallingdetect, gpio_bit,
+ trigger & IRQ_TYPE_EDGE_FALLING);
bank->context.leveldetect0 =
readl_relaxed(bank->base + bank->regs->leveldetect0);
@@ -320,7 +320,7 @@ static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio,
readl_relaxed(bank->base + bank->regs->fallingdetect);
if (likely(!(bank->non_wakeup_gpios & gpio_bit))) {
- _gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0);
+ omap_gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0);
bank->context.wake_en =
readl_relaxed(bank->base + bank->regs->wkup_en);
}
@@ -356,7 +356,7 @@ exit:
* This only applies to chips that can't do both rising and falling edge
* detection at once. For all other chips, this function is a noop.
*/
-static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio)
+static void omap_toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio)
{
void __iomem *reg = bank->base;
u32 l = 0;
@@ -368,35 +368,35 @@ static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio)
l = readl_relaxed(reg);
if ((l >> gpio) & 1)
- l &= ~(1 << gpio);
+ l &= ~(BIT(gpio));
else
- l |= 1 << gpio;
+ l |= BIT(gpio);
writel_relaxed(l, reg);
}
#else
-static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) {}
+static void omap_toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) {}
#endif
-static int _set_gpio_triggering(struct gpio_bank *bank, int gpio,
- unsigned trigger)
+static int omap_set_gpio_triggering(struct gpio_bank *bank, int gpio,
+ unsigned trigger)
{
void __iomem *reg = bank->base;
void __iomem *base = bank->base;
u32 l = 0;
if (bank->regs->leveldetect0 && bank->regs->wkup_en) {
- set_gpio_trigger(bank, gpio, trigger);
+ omap_set_gpio_trigger(bank, gpio, trigger);
} else if (bank->regs->irqctrl) {
reg += bank->regs->irqctrl;
l = readl_relaxed(reg);
if ((trigger & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH)
- bank->toggle_mask |= 1 << gpio;
+ bank->toggle_mask |= BIT(gpio);
if (trigger & IRQ_TYPE_EDGE_RISING)
- l |= 1 << gpio;
+ l |= BIT(gpio);
else if (trigger & IRQ_TYPE_EDGE_FALLING)
- l &= ~(1 << gpio);
+ l &= ~(BIT(gpio));
else
return -EINVAL;
@@ -413,10 +413,10 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio,
if (trigger & IRQ_TYPE_EDGE_RISING)
l |= 2 << (gpio << 1);
if (trigger & IRQ_TYPE_EDGE_FALLING)
- l |= 1 << (gpio << 1);
+ l |= BIT(gpio << 1);
/* Enable wake-up during idle for dynamic tick */
- _gpio_rmw(base, bank->regs->wkup_en, 1 << gpio, trigger);
+ omap_gpio_rmw(base, bank->regs->wkup_en, BIT(gpio), trigger);
bank->context.wake_en =
readl_relaxed(bank->base + bank->regs->wkup_en);
writel_relaxed(l, reg);
@@ -424,13 +424,13 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio,
return 0;
}
-static void _enable_gpio_module(struct gpio_bank *bank, unsigned offset)
+static void omap_enable_gpio_module(struct gpio_bank *bank, unsigned offset)
{
if (bank->regs->pinctrl) {
void __iomem *reg = bank->base + bank->regs->pinctrl;
/* Claim the pin for MPU */
- writel_relaxed(readl_relaxed(reg) | (1 << offset), reg);
+ writel_relaxed(readl_relaxed(reg) | (BIT(offset)), reg);
}
if (bank->regs->ctrl && !BANK_USED(bank)) {
@@ -445,7 +445,7 @@ static void _enable_gpio_module(struct gpio_bank *bank, unsigned offset)
}
}
-static void _disable_gpio_module(struct gpio_bank *bank, unsigned offset)
+static void omap_disable_gpio_module(struct gpio_bank *bank, unsigned offset)
{
void __iomem *base = bank->base;
@@ -453,7 +453,7 @@ static void _disable_gpio_module(struct gpio_bank *bank, unsigned offset)
!LINE_USED(bank->mod_usage, offset) &&
!LINE_USED(bank->irq_usage, offset)) {
/* Disable wake-up during idle for dynamic tick */
- _gpio_rmw(base, bank->regs->wkup_en, 1 << offset, 0);
+ omap_gpio_rmw(base, bank->regs->wkup_en, BIT(offset), 0);
bank->context.wake_en =
readl_relaxed(bank->base + bank->regs->wkup_en);
}
@@ -470,16 +470,16 @@ static void _disable_gpio_module(struct gpio_bank *bank, unsigned offset)
}
}
-static int gpio_is_input(struct gpio_bank *bank, int mask)
+static int omap_gpio_is_input(struct gpio_bank *bank, int mask)
{
void __iomem *reg = bank->base + bank->regs->direction;
return readl_relaxed(reg) & mask;
}
-static int gpio_irq_type(struct irq_data *d, unsigned type)
+static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
{
- struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
+ struct gpio_bank *bank = omap_irq_data_get_bank(d);
unsigned gpio = 0;
int retval;
unsigned long flags;
@@ -494,7 +494,7 @@ static int gpio_irq_type(struct irq_data *d, unsigned type)
#endif
if (!gpio)
- gpio = irq_to_gpio(bank, d->hwirq);
+ gpio = omap_irq_to_gpio(bank, d->hwirq);
if (type & ~IRQ_TYPE_SENSE_MASK)
return -EINVAL;
@@ -505,24 +505,16 @@ static int gpio_irq_type(struct irq_data *d, unsigned type)
spin_lock_irqsave(&bank->lock, flags);
offset = GPIO_INDEX(bank, gpio);
- retval = _set_gpio_triggering(bank, offset, type);
+ retval = omap_set_gpio_triggering(bank, offset, type);
if (!LINE_USED(bank->mod_usage, offset)) {
- _enable_gpio_module(bank, offset);
- _set_gpio_direction(bank, offset, 1);
- } else if (!gpio_is_input(bank, 1 << offset)) {
+ omap_enable_gpio_module(bank, offset);
+ omap_set_gpio_direction(bank, offset, 1);
+ } else if (!omap_gpio_is_input(bank, BIT(offset))) {
spin_unlock_irqrestore(&bank->lock, flags);
return -EINVAL;
}
- retval = gpio_lock_as_irq(&bank->chip, offset);
- if (retval) {
- dev_err(bank->dev, "unable to lock offset %d for IRQ\n",
- offset);
- spin_unlock_irqrestore(&bank->lock, flags);
- return retval;
- }
-
- bank->irq_usage |= 1 << GPIO_INDEX(bank, gpio);
+ bank->irq_usage |= BIT(GPIO_INDEX(bank, gpio));
spin_unlock_irqrestore(&bank->lock, flags);
if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
@@ -533,7 +525,7 @@ static int gpio_irq_type(struct irq_data *d, unsigned type)
return retval;
}
-static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
+static void omap_clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
{
void __iomem *reg = bank->base;
@@ -550,16 +542,16 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
readl_relaxed(reg);
}
-static inline void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio)
+static inline void omap_clear_gpio_irqstatus(struct gpio_bank *bank, int gpio)
{
- _clear_gpio_irqbank(bank, GPIO_BIT(bank, gpio));
+ omap_clear_gpio_irqbank(bank, GPIO_BIT(bank, gpio));
}
-static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank)
+static u32 omap_get_gpio_irqbank_mask(struct gpio_bank *bank)
{
void __iomem *reg = bank->base;
u32 l;
- u32 mask = (1 << bank->width) - 1;
+ u32 mask = (BIT(bank->width)) - 1;
reg += bank->regs->irqenable;
l = readl_relaxed(reg);
@@ -569,7 +561,7 @@ static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank)
return l;
}
-static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
+static void omap_enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
{
void __iomem *reg = bank->base;
u32 l;
@@ -591,7 +583,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
writel_relaxed(l, reg);
}
-static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
+static void omap_disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
{
void __iomem *reg = bank->base;
u32 l;
@@ -613,12 +605,13 @@ static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
writel_relaxed(l, reg);
}
-static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable)
+static inline void omap_set_gpio_irqenable(struct gpio_bank *bank, int gpio,
+ int enable)
{
if (enable)
- _enable_gpio_irqbank(bank, GPIO_BIT(bank, gpio));
+ omap_enable_gpio_irqbank(bank, GPIO_BIT(bank, gpio));
else
- _disable_gpio_irqbank(bank, GPIO_BIT(bank, gpio));
+ omap_disable_gpio_irqbank(bank, GPIO_BIT(bank, gpio));
}
/*
@@ -629,7 +622,7 @@ static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int ena
* enabled. When system is suspended, only selected GPIO interrupts need
* to have wake-up enabled.
*/
-static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
+static int omap_set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
{
u32 gpio_bit = GPIO_BIT(bank, gpio);
unsigned long flags;
@@ -652,22 +645,22 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
return 0;
}
-static void _reset_gpio(struct gpio_bank *bank, int gpio)
+static void omap_reset_gpio(struct gpio_bank *bank, int gpio)
{
- _set_gpio_direction(bank, GPIO_INDEX(bank, gpio), 1);
- _set_gpio_irqenable(bank, gpio, 0);
- _clear_gpio_irqstatus(bank, gpio);
- _set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), IRQ_TYPE_NONE);
- _clear_gpio_debounce(bank, gpio);
+ omap_set_gpio_direction(bank, GPIO_INDEX(bank, gpio), 1);
+ omap_set_gpio_irqenable(bank, gpio, 0);
+ omap_clear_gpio_irqstatus(bank, gpio);
+ omap_set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), IRQ_TYPE_NONE);
+ omap_clear_gpio_debounce(bank, gpio);
}
/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
-static int gpio_wake_enable(struct irq_data *d, unsigned int enable)
+static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable)
{
- struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
- unsigned int gpio = irq_to_gpio(bank, d->hwirq);
+ struct gpio_bank *bank = omap_irq_data_get_bank(d);
+ unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq);
- return _set_gpio_wakeup(bank, gpio, enable);
+ return omap_set_gpio_wakeup(bank, gpio, enable);
}
static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
@@ -688,10 +681,10 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
* not already been requested.
*/
if (!LINE_USED(bank->irq_usage, offset)) {
- _set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
- _enable_gpio_module(bank, offset);
+ omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
+ omap_enable_gpio_module(bank, offset);
}
- bank->mod_usage |= 1 << offset;
+ bank->mod_usage |= BIT(offset);
spin_unlock_irqrestore(&bank->lock, flags);
return 0;
@@ -703,9 +696,9 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
unsigned long flags;
spin_lock_irqsave(&bank->lock, flags);
- bank->mod_usage &= ~(1 << offset);
- _disable_gpio_module(bank, offset);
- _reset_gpio(bank, bank->chip.base + offset);
+ bank->mod_usage &= ~(BIT(offset));
+ omap_disable_gpio_module(bank, offset);
+ omap_reset_gpio(bank, bank->chip.base + offset);
spin_unlock_irqrestore(&bank->lock, flags);
/*
@@ -725,18 +718,19 @@ 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 gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+static void omap_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
{
void __iomem *isr_reg = NULL;
u32 isr;
unsigned int bit;
struct gpio_bank *bank;
int unmasked = 0;
- struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct irq_chip *irqchip = irq_desc_get_chip(desc);
+ struct gpio_chip *chip = irq_get_handler_data(irq);
- chained_irq_enter(chip, desc);
+ chained_irq_enter(irqchip, desc);
- bank = irq_get_handler_data(irq);
+ bank = container_of(chip, struct gpio_bank, chip);
isr_reg = bank->base + bank->regs->irqstatus;
pm_runtime_get_sync(bank->dev);
@@ -747,7 +741,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
u32 isr_saved, level_mask = 0;
u32 enabled;
- enabled = _get_gpio_irqbank_mask(bank);
+ enabled = omap_get_gpio_irqbank_mask(bank);
isr_saved = isr = readl_relaxed(isr_reg) & enabled;
if (bank->level_mask)
@@ -756,15 +750,15 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
/* clear edge sensitive interrupts before handler(s) are
called so that we don't miss any interrupt occurred while
executing them */
- _disable_gpio_irqbank(bank, isr_saved & ~level_mask);
- _clear_gpio_irqbank(bank, isr_saved & ~level_mask);
- _enable_gpio_irqbank(bank, isr_saved & ~level_mask);
+ omap_disable_gpio_irqbank(bank, isr_saved & ~level_mask);
+ omap_clear_gpio_irqbank(bank, isr_saved & ~level_mask);
+ omap_enable_gpio_irqbank(bank, isr_saved & ~level_mask);
/* if there is only edge sensitive GPIO pin interrupts
configured, we could unmask GPIO bank interrupt immediately */
if (!level_mask && !unmasked) {
unmasked = 1;
- chained_irq_exit(chip, desc);
+ chained_irq_exit(irqchip, desc);
}
if (!isr)
@@ -772,7 +766,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
while (isr) {
bit = __ffs(isr);
- isr &= ~(1 << bit);
+ isr &= ~(BIT(bit));
/*
* Some chips can't respond to both rising and falling
@@ -781,10 +775,11 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
* to respond to the IRQ for the opposite direction.
* This will be indicated in the bank toggle_mask.
*/
- if (bank->toggle_mask & (1 << bit))
- _toggle_gpio_edge_triggering(bank, bit);
+ if (bank->toggle_mask & (BIT(bit)))
+ omap_toggle_gpio_edge_triggering(bank, bit);
- generic_handle_irq(irq_find_mapping(bank->domain, bit));
+ generic_handle_irq(irq_find_mapping(bank->chip.irqdomain,
+ bit));
}
}
/* if bank has any level sensitive GPIO pin interrupt
@@ -793,22 +788,22 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
interrupt */
exit:
if (!unmasked)
- chained_irq_exit(chip, desc);
+ chained_irq_exit(irqchip, desc);
pm_runtime_put(bank->dev);
}
-static void gpio_irq_shutdown(struct irq_data *d)
+static void omap_gpio_irq_shutdown(struct irq_data *d)
{
- struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
- unsigned int gpio = irq_to_gpio(bank, d->hwirq);
+ struct gpio_bank *bank = omap_irq_data_get_bank(d);
+ unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq);
unsigned long flags;
unsigned offset = GPIO_INDEX(bank, gpio);
spin_lock_irqsave(&bank->lock, flags);
gpio_unlock_as_irq(&bank->chip, offset);
- bank->irq_usage &= ~(1 << offset);
- _disable_gpio_module(bank, offset);
- _reset_gpio(bank, gpio);
+ bank->irq_usage &= ~(BIT(offset));
+ omap_disable_gpio_module(bank, offset);
+ omap_reset_gpio(bank, gpio);
spin_unlock_irqrestore(&bank->lock, flags);
/*
@@ -819,57 +814,57 @@ static void gpio_irq_shutdown(struct irq_data *d)
pm_runtime_put(bank->dev);
}
-static void gpio_ack_irq(struct irq_data *d)
+static void omap_gpio_ack_irq(struct irq_data *d)
{
- struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
- unsigned int gpio = irq_to_gpio(bank, d->hwirq);
+ struct gpio_bank *bank = omap_irq_data_get_bank(d);
+ unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq);
- _clear_gpio_irqstatus(bank, gpio);
+ omap_clear_gpio_irqstatus(bank, gpio);
}
-static void gpio_mask_irq(struct irq_data *d)
+static void omap_gpio_mask_irq(struct irq_data *d)
{
- struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
- unsigned int gpio = irq_to_gpio(bank, d->hwirq);
+ struct gpio_bank *bank = omap_irq_data_get_bank(d);
+ unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq);
unsigned long flags;
spin_lock_irqsave(&bank->lock, flags);
- _set_gpio_irqenable(bank, gpio, 0);
- _set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), IRQ_TYPE_NONE);
+ omap_set_gpio_irqenable(bank, gpio, 0);
+ omap_set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), IRQ_TYPE_NONE);
spin_unlock_irqrestore(&bank->lock, flags);
}
-static void gpio_unmask_irq(struct irq_data *d)
+static void omap_gpio_unmask_irq(struct irq_data *d)
{
- struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
- unsigned int gpio = irq_to_gpio(bank, d->hwirq);
+ struct gpio_bank *bank = omap_irq_data_get_bank(d);
+ unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq);
unsigned int irq_mask = GPIO_BIT(bank, gpio);
u32 trigger = irqd_get_trigger_type(d);
unsigned long flags;
spin_lock_irqsave(&bank->lock, flags);
if (trigger)
- _set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), trigger);
+ omap_set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), trigger);
/* For level-triggered GPIOs, the clearing must be done after
* the HW source is cleared, thus after the handler has run */
if (bank->level_mask & irq_mask) {
- _set_gpio_irqenable(bank, gpio, 0);
- _clear_gpio_irqstatus(bank, gpio);
+ omap_set_gpio_irqenable(bank, gpio, 0);
+ omap_clear_gpio_irqstatus(bank, gpio);
}
- _set_gpio_irqenable(bank, gpio, 1);
+ omap_set_gpio_irqenable(bank, gpio, 1);
spin_unlock_irqrestore(&bank->lock, flags);
}
static struct irq_chip gpio_irq_chip = {
.name = "GPIO",
- .irq_shutdown = gpio_irq_shutdown,
- .irq_ack = gpio_ack_irq,
- .irq_mask = gpio_mask_irq,
- .irq_unmask = gpio_unmask_irq,
- .irq_set_type = gpio_irq_type,
- .irq_set_wake = gpio_wake_enable,
+ .irq_shutdown = omap_gpio_irq_shutdown,
+ .irq_ack = omap_gpio_ack_irq,
+ .irq_mask = omap_gpio_mask_irq,
+ .irq_unmask = omap_gpio_unmask_irq,
+ .irq_set_type = omap_gpio_irq_type,
+ .irq_set_wake = omap_gpio_wake_enable,
};
/*---------------------------------------------------------------------*/
@@ -926,7 +921,7 @@ static struct platform_device omap_mpuio_device = {
/* could list the /proc/iomem resources */
};
-static inline void mpuio_init(struct gpio_bank *bank)
+static inline void omap_mpuio_init(struct gpio_bank *bank)
{
platform_set_drvdata(&omap_mpuio_device, bank);
@@ -936,33 +931,48 @@ static inline void mpuio_init(struct gpio_bank *bank)
/*---------------------------------------------------------------------*/
-static int gpio_input(struct gpio_chip *chip, unsigned offset)
+static int omap_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
{
struct gpio_bank *bank;
unsigned long flags;
+ void __iomem *reg;
+ int dir;
bank = container_of(chip, struct gpio_bank, chip);
+ reg = bank->base + bank->regs->direction;
spin_lock_irqsave(&bank->lock, flags);
- _set_gpio_direction(bank, offset, 1);
+ dir = !!(readl_relaxed(reg) & BIT(offset));
+ spin_unlock_irqrestore(&bank->lock, flags);
+ return dir;
+}
+
+static int omap_gpio_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct gpio_bank *bank;
+ unsigned long flags;
+
+ bank = container_of(chip, struct gpio_bank, chip);
+ spin_lock_irqsave(&bank->lock, flags);
+ omap_set_gpio_direction(bank, offset, 1);
spin_unlock_irqrestore(&bank->lock, flags);
return 0;
}
-static int gpio_get(struct gpio_chip *chip, unsigned offset)
+static int omap_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct gpio_bank *bank;
u32 mask;
bank = container_of(chip, struct gpio_bank, chip);
- mask = (1 << offset);
+ mask = (BIT(offset));
- if (gpio_is_input(bank, mask))
- return _get_gpio_datain(bank, offset);
+ if (omap_gpio_is_input(bank, mask))
+ return omap_get_gpio_datain(bank, offset);
else
- return _get_gpio_dataout(bank, offset);
+ return omap_get_gpio_dataout(bank, offset);
}
-static int gpio_output(struct gpio_chip *chip, unsigned offset, int value)
+static int omap_gpio_output(struct gpio_chip *chip, unsigned offset, int value)
{
struct gpio_bank *bank;
unsigned long flags;
@@ -970,13 +980,13 @@ static int gpio_output(struct gpio_chip *chip, unsigned offset, int value)
bank = container_of(chip, struct gpio_bank, chip);
spin_lock_irqsave(&bank->lock, flags);
bank->set_dataout(bank, offset, value);
- _set_gpio_direction(bank, offset, 0);
+ omap_set_gpio_direction(bank, offset, 0);
spin_unlock_irqrestore(&bank->lock, flags);
return 0;
}
-static int gpio_debounce(struct gpio_chip *chip, unsigned offset,
- unsigned debounce)
+static int omap_gpio_debounce(struct gpio_chip *chip, unsigned offset,
+ unsigned debounce)
{
struct gpio_bank *bank;
unsigned long flags;
@@ -984,13 +994,13 @@ static int gpio_debounce(struct gpio_chip *chip, unsigned offset,
bank = container_of(chip, struct gpio_bank, chip);
spin_lock_irqsave(&bank->lock, flags);
- _set_gpio_debounce(bank, offset, debounce);
+ omap2_set_gpio_debounce(bank, offset, debounce);
spin_unlock_irqrestore(&bank->lock, flags);
return 0;
}
-static void gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+static void omap_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct gpio_bank *bank;
unsigned long flags;
@@ -1018,11 +1028,6 @@ static void __init omap_gpio_show_rev(struct gpio_bank *bank)
called = true;
}
-/* This lock class tells lockdep that GPIO irqs are in a different
- * category than their parents, so it won't report false recursion.
- */
-static struct lock_class_key gpio_lock_class;
-
static void omap_gpio_mod_init(struct gpio_bank *bank)
{
void __iomem *base = bank->base;
@@ -1036,8 +1041,10 @@ static void omap_gpio_mod_init(struct gpio_bank *bank)
return;
}
- _gpio_rmw(base, bank->regs->irqenable, l, bank->regs->irqenable_inv);
- _gpio_rmw(base, bank->regs->irqstatus, l, !bank->regs->irqenable_inv);
+ omap_gpio_rmw(base, bank->regs->irqenable, l,
+ bank->regs->irqenable_inv);
+ omap_gpio_rmw(base, bank->regs->irqstatus, l,
+ !bank->regs->irqenable_inv);
if (bank->regs->debounce_en)
writel_relaxed(0, base + bank->regs->debounce_en);
@@ -1071,20 +1078,22 @@ omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start,
/* NOTE: No ack required, reading IRQ status clears it. */
ct->chip.irq_mask = irq_gc_mask_set_bit;
ct->chip.irq_unmask = irq_gc_mask_clr_bit;
- ct->chip.irq_set_type = gpio_irq_type;
+ ct->chip.irq_set_type = omap_gpio_irq_type;
if (bank->regs->wkup_en)
- ct->chip.irq_set_wake = gpio_wake_enable;
+ ct->chip.irq_set_wake = omap_gpio_wake_enable;
ct->regs.mask = OMAP_MPUIO_GPIO_INT / bank->stride;
irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
IRQ_NOREQUEST | IRQ_NOPROBE, 0);
}
-static void omap_gpio_chip_init(struct gpio_bank *bank)
+static int omap_gpio_chip_init(struct gpio_bank *bank)
{
int j;
static int gpio;
+ int irq_base = 0;
+ int ret;
/*
* REVISIT eventually switch from OMAP-specific gpio structs
@@ -1092,12 +1101,12 @@ static void omap_gpio_chip_init(struct gpio_bank *bank)
*/
bank->chip.request = omap_gpio_request;
bank->chip.free = omap_gpio_free;
- bank->chip.direction_input = gpio_input;
- bank->chip.get = gpio_get;
- bank->chip.direction_output = gpio_output;
- bank->chip.set_debounce = gpio_debounce;
- bank->chip.set = gpio_set;
- bank->chip.to_irq = omap_gpio_to_irq;
+ bank->chip.get_direction = omap_gpio_get_direction;
+ bank->chip.direction_input = omap_gpio_input;
+ bank->chip.get = omap_gpio_get;
+ bank->chip.direction_output = omap_gpio_output;
+ bank->chip.set_debounce = omap_gpio_debounce;
+ bank->chip.set = omap_gpio_set;
if (bank->is_mpuio) {
bank->chip.label = "mpuio";
if (bank->regs->wkup_en)
@@ -1110,22 +1119,47 @@ static void omap_gpio_chip_init(struct gpio_bank *bank)
}
bank->chip.ngpio = bank->width;
- gpiochip_add(&bank->chip);
+ ret = gpiochip_add(&bank->chip);
+ if (ret) {
+ dev_err(bank->dev, "Could not register gpio chip %d\n", ret);
+ return ret;
+ }
+
+#ifdef CONFIG_ARCH_OMAP1
+ /*
+ * REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop
+ * irq_alloc_descs() since a base IRQ offset will no longer be needed.
+ */
+ irq_base = irq_alloc_descs(-1, 0, bank->width, 0);
+ if (irq_base < 0) {
+ dev_err(bank->dev, "Couldn't allocate IRQ numbers\n");
+ return -ENODEV;
+ }
+#endif
+
+ ret = gpiochip_irqchip_add(&bank->chip, &gpio_irq_chip,
+ irq_base, omap_gpio_irq_handler,
+ IRQ_TYPE_NONE);
+
+ if (ret) {
+ dev_err(bank->dev, "Couldn't add irqchip to gpiochip %d\n", ret);
+ ret = gpiochip_remove(&bank->chip);
+ return -ENODEV;
+ }
+
+ gpiochip_set_chained_irqchip(&bank->chip, &gpio_irq_chip,
+ bank->irq, omap_gpio_irq_handler);
for (j = 0; j < bank->width; j++) {
- int irq = irq_create_mapping(bank->domain, j);
- irq_set_lockdep_class(irq, &gpio_lock_class);
- irq_set_chip_data(irq, bank);
+ int irq = irq_find_mapping(bank->chip.irqdomain, j);
if (bank->is_mpuio) {
omap_mpuio_alloc_gc(bank, irq, bank->width);
- } else {
- irq_set_chip_and_handler(irq, &gpio_irq_chip,
- handle_simple_irq);
- set_irq_flags(irq, IRQF_VALID);
+ irq_set_chip_and_handler(irq, NULL, NULL);
+ set_irq_flags(irq, 0);
}
}
- irq_set_chained_handler(bank->irq, gpio_irq_handler);
- irq_set_handler_data(bank->irq, bank);
+
+ return 0;
}
static const struct of_device_id omap_gpio_match[];
@@ -1138,9 +1172,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
const struct omap_gpio_platform_data *pdata;
struct resource *res;
struct gpio_bank *bank;
-#ifdef CONFIG_ARCH_OMAP1
- int irq_base;
-#endif
+ int ret;
match = of_match_device(of_match_ptr(omap_gpio_match), dev);
@@ -1162,6 +1194,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
bank->irq = res->start;
bank->dev = dev;
+ bank->chip.dev = dev;
bank->dbck_flag = pdata->dbck_flag;
bank->stride = pdata->bank_stride;
bank->width = pdata->bank_width;
@@ -1182,33 +1215,10 @@ static int omap_gpio_probe(struct platform_device *pdev)
pdata->get_context_loss_count;
}
-#ifdef CONFIG_ARCH_OMAP1
- /*
- * REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop
- * irq_alloc_descs() and irq_domain_add_legacy() and just use a
- * linear IRQ domain mapping for all OMAP platforms.
- */
- irq_base = irq_alloc_descs(-1, 0, bank->width, 0);
- if (irq_base < 0) {
- dev_err(dev, "Couldn't allocate IRQ numbers\n");
- return -ENODEV;
- }
-
- bank->domain = irq_domain_add_legacy(node, bank->width, irq_base,
- 0, &irq_domain_simple_ops, NULL);
-#else
- bank->domain = irq_domain_add_linear(node, bank->width,
- &irq_domain_simple_ops, NULL);
-#endif
- if (!bank->domain) {
- dev_err(dev, "Couldn't register an IRQ domain\n");
- return -ENODEV;
- }
-
if (bank->regs->set_dataout && bank->regs->clr_dataout)
- bank->set_dataout = _set_gpio_dataout_reg;
+ bank->set_dataout = omap_set_gpio_dataout_reg;
else
- bank->set_dataout = _set_gpio_dataout_mask;
+ bank->set_dataout = omap_set_gpio_dataout_mask;
spin_lock_init(&bank->lock);
@@ -1216,7 +1226,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
bank->base = devm_ioremap_resource(dev, res);
if (IS_ERR(bank->base)) {
- irq_domain_remove(bank->domain);
+ irq_domain_remove(bank->chip.irqdomain);
return PTR_ERR(bank->base);
}
@@ -1227,10 +1237,14 @@ static int omap_gpio_probe(struct platform_device *pdev)
pm_runtime_get_sync(bank->dev);
if (bank->is_mpuio)
- mpuio_init(bank);
+ omap_mpuio_init(bank);
omap_gpio_mod_init(bank);
- omap_gpio_chip_init(bank);
+
+ ret = omap_gpio_chip_init(bank);
+ if (ret)
+ return ret;
+
omap_gpio_show_rev(bank);
pm_runtime_put(bank->dev);
@@ -1305,7 +1319,7 @@ update_gpio_context_count:
bank->context_loss_count =
bank->get_context_loss_count(bank->dev);
- _gpio_dbck_disable(bank);
+ omap_gpio_dbck_disable(bank);
spin_unlock_irqrestore(&bank->lock, flags);
return 0;
@@ -1336,7 +1350,7 @@ static int omap_gpio_runtime_resume(struct device *dev)
bank->get_context_loss_count(bank->dev);
}
- _gpio_dbck_enable(bank);
+ omap_gpio_dbck_enable(bank);
/*
* In ->runtime_suspend(), level-triggered, wakeup-enabled
diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c
index da9d33252e56..171a6389f9ce 100644
--- a/drivers/gpio/gpio-palmas.c
+++ b/drivers/gpio/gpio-palmas.c
@@ -148,7 +148,7 @@ static const struct palmas_device_data tps80036_dev_data = {
.ngpio = 16,
};
-static struct of_device_id of_palmas_gpio_match[] = {
+static const struct of_device_id of_palmas_gpio_match[] = {
{ .compatible = "ti,palmas-gpio", .data = &palmas_dev_data,},
{ .compatible = "ti,tps65913-gpio", .data = &palmas_dev_data,},
{ .compatible = "ti,tps65914-gpio", .data = &palmas_dev_data,},
@@ -173,10 +173,8 @@ static int palmas_gpio_probe(struct platform_device *pdev)
palmas_gpio = devm_kzalloc(&pdev->dev,
sizeof(*palmas_gpio), GFP_KERNEL);
- if (!palmas_gpio) {
- dev_err(&pdev->dev, "Could not allocate palmas_gpio\n");
+ if (!palmas_gpio)
return -ENOMEM;
- }
palmas_gpio->palmas = palmas;
palmas_gpio->gpio_chip.owner = THIS_MODULE;
@@ -212,7 +210,8 @@ static int palmas_gpio_remove(struct platform_device *pdev)
{
struct palmas_gpio *palmas_gpio = platform_get_drvdata(pdev);
- return gpiochip_remove(&palmas_gpio->gpio_chip);
+ gpiochip_remove(&palmas_gpio->gpio_chip);
+ return 0;
}
static struct platform_driver palmas_gpio_driver = {
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index d550d8e58705..f9961eea2120 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -15,8 +15,6 @@
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/irqdomain.h>
#include <linux/i2c.h>
#include <linux/platform_data/pca953x.h>
#include <linux/slab.h>
@@ -91,7 +89,6 @@ struct pca953x_chip {
u8 irq_stat[MAX_BANK];
u8 irq_trig_raise[MAX_BANK];
u8 irq_trig_fall[MAX_BANK];
- struct irq_domain *domain;
#endif
struct i2c_client *client;
@@ -100,6 +97,11 @@ struct pca953x_chip {
int chip_type;
};
+static inline struct pca953x_chip *to_pca(struct gpio_chip *gc)
+{
+ return container_of(gc, struct pca953x_chip, gpio_chip);
+}
+
static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val,
int off)
{
@@ -202,12 +204,10 @@ static int pca953x_read_regs(struct pca953x_chip *chip, int reg, u8 *val)
static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
{
- struct pca953x_chip *chip;
+ struct pca953x_chip *chip = to_pca(gc);
u8 reg_val;
int ret, offset = 0;
- chip = container_of(gc, struct pca953x_chip, gpio_chip);
-
mutex_lock(&chip->i2c_lock);
reg_val = chip->reg_direction[off / BANK_SZ] | (1u << (off % BANK_SZ));
@@ -233,12 +233,10 @@ exit:
static int pca953x_gpio_direction_output(struct gpio_chip *gc,
unsigned off, int val)
{
- struct pca953x_chip *chip;
+ struct pca953x_chip *chip = to_pca(gc);
u8 reg_val;
int ret, offset = 0;
- chip = container_of(gc, struct pca953x_chip, gpio_chip);
-
mutex_lock(&chip->i2c_lock);
/* set output level */
if (val)
@@ -285,12 +283,10 @@ exit:
static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
{
- struct pca953x_chip *chip;
+ struct pca953x_chip *chip = to_pca(gc);
u32 reg_val;
int ret, offset = 0;
- chip = container_of(gc, struct pca953x_chip, gpio_chip);
-
mutex_lock(&chip->i2c_lock);
switch (chip->chip_type) {
case PCA953X_TYPE:
@@ -315,12 +311,10 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
{
- struct pca953x_chip *chip;
+ struct pca953x_chip *chip = to_pca(gc);
u8 reg_val;
int ret, offset = 0;
- chip = container_of(gc, struct pca953x_chip, gpio_chip);
-
mutex_lock(&chip->i2c_lock);
if (val)
reg_val = chip->reg_output[off / BANK_SZ]
@@ -367,38 +361,34 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
}
#ifdef CONFIG_GPIO_PCA953X_IRQ
-static int pca953x_gpio_to_irq(struct gpio_chip *gc, unsigned off)
-{
- struct pca953x_chip *chip;
-
- chip = container_of(gc, struct pca953x_chip, gpio_chip);
- return irq_create_mapping(chip->domain, off);
-}
-
static void pca953x_irq_mask(struct irq_data *d)
{
- struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct pca953x_chip *chip = to_pca(gc);
chip->irq_mask[d->hwirq / BANK_SZ] &= ~(1 << (d->hwirq % BANK_SZ));
}
static void pca953x_irq_unmask(struct irq_data *d)
{
- struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct pca953x_chip *chip = to_pca(gc);
chip->irq_mask[d->hwirq / BANK_SZ] |= 1 << (d->hwirq % BANK_SZ);
}
static void pca953x_irq_bus_lock(struct irq_data *d)
{
- struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct pca953x_chip *chip = to_pca(gc);
mutex_lock(&chip->irq_lock);
}
static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
{
- struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct pca953x_chip *chip = to_pca(gc);
u8 new_irqs;
int level, i;
@@ -420,7 +410,8 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
{
- struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct pca953x_chip *chip = to_pca(gc);
int bank_nb = d->hwirq / BANK_SZ;
u8 mask = 1 << (d->hwirq % BANK_SZ);
@@ -503,44 +494,25 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid)
struct pca953x_chip *chip = devid;
u8 pending[MAX_BANK];
u8 level;
+ unsigned nhandled = 0;
int i;
if (!pca953x_irq_pending(chip, pending))
- return IRQ_HANDLED;
+ return IRQ_NONE;
for (i = 0; i < NBANK(chip); i++) {
while (pending[i]) {
level = __ffs(pending[i]);
- handle_nested_irq(irq_find_mapping(chip->domain,
+ handle_nested_irq(irq_find_mapping(chip->gpio_chip.irqdomain,
level + (BANK_SZ * i)));
pending[i] &= ~(1 << level);
+ nhandled++;
}
}
- return IRQ_HANDLED;
+ return (nhandled > 0) ? IRQ_HANDLED : IRQ_NONE;
}
-static int pca953x_gpio_irq_map(struct irq_domain *d, unsigned int irq,
- irq_hw_number_t hwirq)
-{
- irq_clear_status_flags(irq, IRQ_NOREQUEST);
- irq_set_chip_data(irq, d->host_data);
- irq_set_chip(irq, &pca953x_irq_chip);
- irq_set_nested_thread(irq, true);
-#ifdef CONFIG_ARM
- set_irq_flags(irq, IRQF_VALID);
-#else
- irq_set_noprobe(irq);
-#endif
-
- return 0;
-}
-
-static const struct irq_domain_ops pca953x_irq_simple_ops = {
- .map = pca953x_gpio_irq_map,
- .xlate = irq_domain_xlate_twocell,
-};
-
static int pca953x_irq_setup(struct pca953x_chip *chip,
const struct i2c_device_id *id,
int irq_base)
@@ -572,19 +544,12 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
chip->irq_stat[i] &= chip->reg_direction[i];
mutex_init(&chip->irq_lock);
- chip->domain = irq_domain_add_simple(client->dev.of_node,
- chip->gpio_chip.ngpio,
- irq_base,
- &pca953x_irq_simple_ops,
- chip);
- if (!chip->domain)
- return -ENODEV;
-
ret = devm_request_threaded_irq(&client->dev,
client->irq,
NULL,
pca953x_irq_handler,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT |
+ IRQF_SHARED,
dev_name(&client->dev), chip);
if (ret) {
dev_err(&client->dev, "failed to request irq %d\n",
@@ -592,7 +557,16 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
return ret;
}
- chip->gpio_chip.to_irq = pca953x_gpio_to_irq;
+ ret = gpiochip_irqchip_add(&chip->gpio_chip,
+ &pca953x_irq_chip,
+ irq_base,
+ handle_simple_irq,
+ IRQ_TYPE_NONE);
+ if (ret) {
+ dev_err(&client->dev,
+ "could not connect irqchip to gpiochip\n");
+ return ret;
+ }
}
return 0;
@@ -756,11 +730,11 @@ static int pca953x_probe(struct i2c_client *client,
if (ret)
return ret;
- ret = pca953x_irq_setup(chip, id, irq_base);
+ ret = gpiochip_add(&chip->gpio_chip);
if (ret)
return ret;
- ret = gpiochip_add(&chip->gpio_chip);
+ ret = pca953x_irq_setup(chip, id, irq_base);
if (ret)
return ret;
@@ -791,12 +765,7 @@ static int pca953x_remove(struct i2c_client *client)
}
}
- ret = gpiochip_remove(&chip->gpio_chip);
- if (ret) {
- dev_err(&client->dev, "%s failed, %d\n",
- "gpiochip_remove()", ret);
- return ret;
- }
+ gpiochip_remove(&chip->gpio_chip);
return 0;
}
diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c
index 82735822bc9d..236708ad0a5b 100644
--- a/drivers/gpio/gpio-pcf857x.c
+++ b/drivers/gpio/gpio-pcf857x.c
@@ -262,7 +262,7 @@ static int pcf857x_irq_domain_init(struct pcf857x *gpio,
/* enable real irq */
status = devm_request_threaded_irq(&client->dev, client->irq,
NULL, pcf857x_irq, IRQF_ONESHOT |
- IRQF_TRIGGER_FALLING,
+ IRQF_TRIGGER_FALLING | IRQF_SHARED,
dev_name(&client->dev), gpio);
if (status)
@@ -319,7 +319,7 @@ static int pcf857x_probe(struct i2c_client *client,
status = pcf857x_irq_domain_init(gpio, client);
if (status < 0) {
dev_err(&client->dev, "irq_domain init failed\n");
- goto fail;
+ goto fail_irq_domain;
}
}
@@ -414,12 +414,13 @@ static int pcf857x_probe(struct i2c_client *client,
return 0;
fail:
- dev_dbg(&client->dev, "probe error %d for '%s'\n",
- status, client->name);
-
if (client->irq)
pcf857x_irq_domain_cleanup(gpio);
+fail_irq_domain:
+ dev_dbg(&client->dev, "probe error %d for '%s'\n",
+ status, client->name);
+
return status;
}
@@ -443,9 +444,7 @@ static int pcf857x_remove(struct i2c_client *client)
if (client->irq)
pcf857x_irq_domain_cleanup(gpio);
- status = gpiochip_remove(&gpio->chip);
- if (status)
- dev_err(&client->dev, "%s --> %d\n", "remove", status);
+ gpiochip_remove(&gpio->chip);
return status;
}
diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c
index 83a156397474..e0ac549dccb5 100644
--- a/drivers/gpio/gpio-pch.c
+++ b/drivers/gpio/gpio-pch.c
@@ -20,6 +20,7 @@
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/slab.h>
#define PCH_EDGE_FALLING 0
#define PCH_EDGE_RISING BIT(0)
@@ -425,9 +426,7 @@ end:
err_request_irq:
irq_free_descs(irq_base, gpio_pins[chip->ioh]);
-
- if (gpiochip_remove(&chip->gpio))
- dev_err(&pdev->dev, "%s gpiochip_remove failed\n", __func__);
+ gpiochip_remove(&chip->gpio);
err_gpiochip_add:
pci_iounmap(pdev, chip->base);
@@ -446,7 +445,6 @@ err_pci_enable:
static void pch_gpio_remove(struct pci_dev *pdev)
{
- int err;
struct pch_gpio *chip = pci_get_drvdata(pdev);
if (chip->irq_base != -1) {
@@ -455,10 +453,7 @@ static void pch_gpio_remove(struct pci_dev *pdev)
irq_free_descs(chip->irq_base, gpio_pins[chip->ioh]);
}
- err = gpiochip_remove(&chip->gpio);
- if (err)
- dev_err(&pdev->dev, "Failed gpiochip_remove\n");
-
+ gpiochip_remove(&chip->gpio);
pci_iounmap(pdev, chip->base);
pci_release_regions(pdev);
pci_disable_device(pdev);
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index b0f475243cef..84b49cfb81a8 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -17,7 +17,6 @@
#include <linux/irq.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/bitops.h>
-#include <linux/workqueue.h>
#include <linux/gpio.h>
#include <linux/device.h>
#include <linux/amba/bus.h>
@@ -88,7 +87,7 @@ static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
spin_lock_irqsave(&chip->lock, flags);
gpiodir = readb(chip->base + GPIODIR);
- gpiodir &= ~(1 << offset);
+ gpiodir &= ~(BIT(offset));
writeb(gpiodir, chip->base + GPIODIR);
spin_unlock_irqrestore(&chip->lock, flags);
@@ -106,16 +105,16 @@ static int pl061_direction_output(struct gpio_chip *gc, unsigned offset,
return -EINVAL;
spin_lock_irqsave(&chip->lock, flags);
- writeb(!!value << offset, chip->base + (1 << (offset + 2)));
+ writeb(!!value << offset, chip->base + (BIT(offset + 2)));
gpiodir = readb(chip->base + GPIODIR);
- gpiodir |= 1 << offset;
+ gpiodir |= BIT(offset);
writeb(gpiodir, chip->base + GPIODIR);
/*
* gpio value is set again, because pl061 doesn't allow to set value of
* a gpio pin before configuring it in OUT mode.
*/
- writeb(!!value << offset, chip->base + (1 << (offset + 2)));
+ writeb(!!value << offset, chip->base + (BIT(offset + 2)));
spin_unlock_irqrestore(&chip->lock, flags);
return 0;
@@ -125,14 +124,14 @@ static int pl061_get_value(struct gpio_chip *gc, unsigned offset)
{
struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
- return !!readb(chip->base + (1 << (offset + 2)));
+ return !!readb(chip->base + (BIT(offset + 2)));
}
static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value)
{
struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
- writeb(!!value << offset, chip->base + (1 << (offset + 2)));
+ writeb(!!value << offset, chip->base + (BIT(offset + 2)));
}
static int pl061_irq_type(struct irq_data *d, unsigned trigger)
@@ -207,7 +206,7 @@ static void pl061_irq_mask(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 = 1 << (irqd_to_hwirq(d) % PL061_GPIO_NR);
+ u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
u8 gpioie;
spin_lock(&chip->lock);
@@ -220,7 +219,7 @@ static void pl061_irq_unmask(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 = 1 << (irqd_to_hwirq(d) % PL061_GPIO_NR);
+ u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
u8 gpioie;
spin_lock(&chip->lock);
@@ -302,9 +301,9 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
for (i = 0; i < PL061_GPIO_NR; i++) {
if (pdata) {
- if (pdata->directions & (1 << i))
+ if (pdata->directions & (BIT(i)))
pl061_direction_output(&chip->gc, i,
- pdata->values & (1 << i));
+ pdata->values & (BIT(i)));
else
pl061_direction_input(&chip->gc, i);
}
@@ -331,7 +330,7 @@ static int pl061_suspend(struct device *dev)
chip->csave_regs.gpio_ie = readb(chip->base + GPIOIE);
for (offset = 0; offset < PL061_GPIO_NR; offset++) {
- if (chip->csave_regs.gpio_dir & (1 << offset))
+ if (chip->csave_regs.gpio_dir & (BIT(offset)))
chip->csave_regs.gpio_data |=
pl061_get_value(&chip->gc, offset) << offset;
}
@@ -345,10 +344,10 @@ static int pl061_resume(struct device *dev)
int offset;
for (offset = 0; offset < PL061_GPIO_NR; offset++) {
- if (chip->csave_regs.gpio_dir & (1 << offset))
+ if (chip->csave_regs.gpio_dir & (BIT(offset)))
pl061_direction_output(&chip->gc, offset,
chip->csave_regs.gpio_data &
- (1 << offset));
+ (BIT(offset)));
else
pl061_direction_input(&chip->gc, offset);
}
diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
index 42e6e64f2120..ad3feec0075e 100644
--- a/drivers/gpio/gpio-pxa.c
+++ b/drivers/gpio/gpio-pxa.c
@@ -498,7 +498,7 @@ static int pxa_gpio_nums(struct platform_device *pdev)
}
#ifdef CONFIG_OF
-static struct of_device_id pxa_gpio_dt_ids[] = {
+static const struct of_device_id pxa_gpio_dt_ids[] = {
{ .compatible = "intel,pxa25x-gpio", .data = &pxa25x_id, },
{ .compatible = "intel,pxa26x-gpio", .data = &pxa26x_id, },
{ .compatible = "intel,pxa27x-gpio", .data = &pxa27x_id, },
@@ -649,6 +649,11 @@ static int pxa_gpio_probe(struct platform_device *pdev)
handle_edge_irq);
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
}
+ } else {
+ if (irq0 > 0)
+ irq_set_chained_handler(irq0, pxa_gpio_demux_handler);
+ if (irq1 > 0)
+ irq_set_chained_handler(irq1, pxa_gpio_demux_handler);
}
irq_set_chained_handler(irq_mux, pxa_gpio_demux_handler);
diff --git a/drivers/gpio/gpio-rc5t583.c b/drivers/gpio/gpio-rc5t583.c
index 9b423173ab50..769233d2da6d 100644
--- a/drivers/gpio/gpio-rc5t583.c
+++ b/drivers/gpio/gpio-rc5t583.c
@@ -119,10 +119,8 @@ static int rc5t583_gpio_probe(struct platform_device *pdev)
rc5t583_gpio = devm_kzalloc(&pdev->dev, sizeof(*rc5t583_gpio),
GFP_KERNEL);
- if (!rc5t583_gpio) {
- dev_warn(&pdev->dev, "Mem allocation for rc5t583_gpio failed");
+ if (!rc5t583_gpio)
return -ENOMEM;
- }
rc5t583_gpio->gpio_chip.label = "gpio-rc5t583",
rc5t583_gpio->gpio_chip.owner = THIS_MODULE,
@@ -150,7 +148,8 @@ static int rc5t583_gpio_remove(struct platform_device *pdev)
{
struct rc5t583_gpio *rc5t583_gpio = platform_get_drvdata(pdev);
- return gpiochip_remove(&rc5t583_gpio->gpio_chip);
+ gpiochip_remove(&rc5t583_gpio->gpio_chip);
+ return 0;
}
static struct platform_driver rc5t583_gpio_driver = {
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index 03c91482432c..bf6c09450fee 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -26,6 +26,7 @@
#include <linux/pinctrl/consumer.h>
#include <linux/platform_data/gpio-rcar.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@@ -239,9 +240,9 @@ static int gpio_rcar_get(struct gpio_chip *chip, unsigned offset)
/* testing on r8a7790 shows that INDT does not show correct pin state
* when configured as output, so use OUTDT in case of output pins */
if (gpio_rcar_read(gpio_to_priv(chip), INOUTSEL) & bit)
- return (int)(gpio_rcar_read(gpio_to_priv(chip), OUTDT) & bit);
+ return !!(gpio_rcar_read(gpio_to_priv(chip), OUTDT) & bit);
else
- return (int)(gpio_rcar_read(gpio_to_priv(chip), INDT) & bit);
+ return !!(gpio_rcar_read(gpio_to_priv(chip), INDT) & bit);
}
static void gpio_rcar_set(struct gpio_chip *chip, unsigned offset, int value)
@@ -283,6 +284,7 @@ static int gpio_rcar_irq_domain_map(struct irq_domain *h, unsigned int irq,
static struct irq_domain_ops gpio_rcar_irq_domain_ops = {
.map = gpio_rcar_irq_domain_map,
+ .xlate = irq_domain_xlate_twocell,
};
struct gpio_rcar_info {
@@ -362,7 +364,6 @@ static int gpio_rcar_probe(struct platform_device *pdev)
p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);
if (!p) {
- dev_err(dev, "failed to allocate driver data\n");
ret = -ENOMEM;
goto err0;
}
@@ -377,6 +378,9 @@ static int gpio_rcar_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, p);
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+
io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
@@ -460,19 +464,20 @@ static int gpio_rcar_probe(struct platform_device *pdev)
err1:
irq_domain_remove(p->irq_domain);
err0:
+ pm_runtime_put(dev);
+ pm_runtime_disable(dev);
return ret;
}
static int gpio_rcar_remove(struct platform_device *pdev)
{
struct gpio_rcar_priv *p = platform_get_drvdata(pdev);
- int ret;
- ret = gpiochip_remove(&p->gpio_chip);
- if (ret)
- return ret;
+ gpiochip_remove(&p->gpio_chip);
irq_domain_remove(p->irq_domain);
+ pm_runtime_put(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
return 0;
}
diff --git a/drivers/gpio/gpio-rdc321x.c b/drivers/gpio/gpio-rdc321x.c
index 88577c3272a5..d729bc8a554d 100644
--- a/drivers/gpio/gpio-rdc321x.c
+++ b/drivers/gpio/gpio-rdc321x.c
@@ -141,17 +141,15 @@ static int rdc321x_gpio_probe(struct platform_device *pdev)
return -ENODEV;
}
- rdc321x_gpio_dev = kzalloc(sizeof(struct rdc321x_gpio), GFP_KERNEL);
- if (!rdc321x_gpio_dev) {
- dev_err(&pdev->dev, "failed to allocate private data\n");
+ rdc321x_gpio_dev = devm_kzalloc(&pdev->dev, sizeof(struct rdc321x_gpio),
+ GFP_KERNEL);
+ if (!rdc321x_gpio_dev)
return -ENOMEM;
- }
r = platform_get_resource_byname(pdev, IORESOURCE_IO, "gpio-reg1");
if (!r) {
dev_err(&pdev->dev, "failed to get gpio-reg1 resource\n");
- err = -ENODEV;
- goto out_free;
+ return -ENODEV;
}
spin_lock_init(&rdc321x_gpio_dev->lock);
@@ -162,8 +160,7 @@ static int rdc321x_gpio_probe(struct platform_device *pdev)
r = platform_get_resource_byname(pdev, IORESOURCE_IO, "gpio-reg2");
if (!r) {
dev_err(&pdev->dev, "failed to get gpio-reg2 resource\n");
- err = -ENODEV;
- goto out_free;
+ return -ENODEV;
}
rdc321x_gpio_dev->reg2_ctrl_base = r->start;
@@ -187,35 +184,26 @@ static int rdc321x_gpio_probe(struct platform_device *pdev)
rdc321x_gpio_dev->reg1_data_base,
&rdc321x_gpio_dev->data_reg[0]);
if (err)
- goto out_free;
+ return err;
err = pci_read_config_dword(rdc321x_gpio_dev->sb_pdev,
rdc321x_gpio_dev->reg2_data_base,
&rdc321x_gpio_dev->data_reg[1]);
if (err)
- goto out_free;
+ return err;
dev_info(&pdev->dev, "registering %d GPIOs\n",
rdc321x_gpio_dev->chip.ngpio);
return gpiochip_add(&rdc321x_gpio_dev->chip);
-
-out_free:
- kfree(rdc321x_gpio_dev);
- return err;
}
static int rdc321x_gpio_remove(struct platform_device *pdev)
{
- int ret;
struct rdc321x_gpio *rdc321x_gpio_dev = platform_get_drvdata(pdev);
- ret = gpiochip_remove(&rdc321x_gpio_dev->chip);
- if (ret)
- dev_err(&pdev->dev, "failed to unregister chip\n");
-
- kfree(rdc321x_gpio_dev);
+ gpiochip_remove(&rdc321x_gpio_dev->chip);
- return ret;
+ return 0;
}
static struct platform_driver rdc321x_gpio_driver = {
diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c
index 07105ee5c9ae..3810da47043f 100644
--- a/drivers/gpio/gpio-samsung.c
+++ b/drivers/gpio/gpio-samsung.c
@@ -32,10 +32,7 @@
#include <mach/map.h>
#include <mach/regs-gpio.h>
-
-#if defined(CONFIG_ARCH_S3C24XX) || defined(CONFIG_ARCH_S3C64XX)
#include <mach/gpio-samsung.h>
-#endif
#include <plat/cpu.h>
#include <plat/gpio-core.h>
@@ -358,47 +355,6 @@ static unsigned s3c24xx_gpio_getcfg_abank(struct samsung_gpio_chip *chip,
}
#endif
-#if defined(CONFIG_CPU_S5P6440) || defined(CONFIG_CPU_S5P6450)
-static int s5p64x0_gpio_setcfg_rbank(struct samsung_gpio_chip *chip,
- unsigned int off, unsigned int cfg)
-{
- void __iomem *reg = chip->base;
- unsigned int shift;
- u32 con;
-
- switch (off) {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- shift = (off & 7) * 4;
- reg -= 4;
- break;
- case 6:
- shift = ((off + 1) & 7) * 4;
- reg -= 4;
- break;
- default:
- shift = ((off + 1) & 7) * 4;
- break;
- }
-
- if (samsung_gpio_is_cfg_special(cfg)) {
- cfg &= 0xf;
- cfg <<= shift;
- }
-
- con = __raw_readl(reg);
- con &= ~(0xf << shift);
- con |= cfg;
- __raw_writel(con, reg);
-
- return 0;
-}
-#endif
-
static void __init samsung_gpiolib_set_cfg(struct samsung_gpio_cfg *chipcfg,
int nr_chips)
{
@@ -426,16 +382,6 @@ static struct samsung_gpio_cfg s3c24xx_gpiocfg_banka = {
};
#endif
-#if defined(CONFIG_CPU_S5P6440) || defined(CONFIG_CPU_S5P6450)
-static struct samsung_gpio_cfg s5p64x0_gpio_cfg_rbank = {
- .cfg_eint = 0x3,
- .set_config = s5p64x0_gpio_setcfg_rbank,
- .get_config = samsung_gpio_getcfg_4bit,
- .set_pull = samsung_gpio_setpull_updown,
- .get_pull = samsung_gpio_getpull_updown,
-};
-#endif
-
static struct samsung_gpio_cfg samsung_gpio_cfgs[] = {
[0] = {
.cfg_eint = 0x0,
@@ -708,91 +654,6 @@ static int s3c24xx_gpiolib_banka_output(struct gpio_chip *chip,
}
#endif
-/* The next set of routines are for the case of s5p64x0 bank r */
-
-static int s5p64x0_gpiolib_rbank_input(struct gpio_chip *chip,
- unsigned int offset)
-{
- struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip);
- void __iomem *base = ourchip->base;
- void __iomem *regcon = base;
- unsigned long con;
- unsigned long flags;
-
- switch (offset) {
- case 6:
- offset += 1;
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- regcon -= 4;
- break;
- default:
- offset -= 7;
- break;
- }
-
- samsung_gpio_lock(ourchip, flags);
-
- con = __raw_readl(regcon);
- con &= ~(0xf << con_4bit_shift(offset));
- __raw_writel(con, regcon);
-
- samsung_gpio_unlock(ourchip, flags);
-
- return 0;
-}
-
-static int s5p64x0_gpiolib_rbank_output(struct gpio_chip *chip,
- unsigned int offset, int value)
-{
- struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip);
- void __iomem *base = ourchip->base;
- void __iomem *regcon = base;
- unsigned long con;
- unsigned long dat;
- unsigned long flags;
- unsigned con_offset = offset;
-
- switch (con_offset) {
- case 6:
- con_offset += 1;
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- regcon -= 4;
- break;
- default:
- con_offset -= 7;
- break;
- }
-
- samsung_gpio_lock(ourchip, flags);
-
- con = __raw_readl(regcon);
- con &= ~(0xf << con_4bit_shift(con_offset));
- con |= 0x1 << con_4bit_shift(con_offset);
-
- dat = __raw_readl(base + GPIODAT_OFF);
- if (value)
- dat |= 1 << offset;
- else
- dat &= ~(1 << offset);
-
- __raw_writel(con, regcon);
- __raw_writel(dat, base + GPIODAT_OFF);
-
- samsung_gpio_unlock(ourchip, flags);
-
- return 0;
-}
-
static void samsung_gpiolib_set(struct gpio_chip *chip,
unsigned offset, int value)
{
@@ -999,20 +860,6 @@ static void __init samsung_gpiolib_add_4bit2_chips(struct samsung_gpio_chip *chi
}
}
-static void __init s5p64x0_gpiolib_add_rbank(struct samsung_gpio_chip *chip,
- int nr_chips)
-{
- for (; nr_chips > 0; nr_chips--, chip++) {
- chip->chip.direction_input = s5p64x0_gpiolib_rbank_input;
- chip->chip.direction_output = s5p64x0_gpiolib_rbank_output;
-
- if (!chip->pm)
- chip->pm = __gpio_pm(&samsung_gpio_pm_4bit);
-
- samsung_gpiolib_add(chip);
- }
-}
-
int samsung_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset)
{
struct samsung_gpio_chip *samsung_chip = container_of(chip, struct samsung_gpio_chip, chip);
@@ -1319,773 +1166,9 @@ static struct samsung_gpio_chip s3c64xx_gpios_2bit[] = {
#endif
};
-/*
- * S5P6440 GPIO bank summary:
- *
- * Bank GPIOs Style SlpCon ExtInt Group
- * A 6 4Bit Yes 1
- * B 7 4Bit Yes 1
- * C 8 4Bit Yes 2
- * F 2 2Bit Yes 4 [1]
- * G 7 4Bit Yes 5
- * H 10 4Bit[2] Yes 6
- * I 16 2Bit Yes None
- * J 12 2Bit Yes None
- * N 16 2Bit No IRQ_EINT
- * P 8 2Bit Yes 8
- * R 15 4Bit[2] Yes 8
- */
-
-static struct samsung_gpio_chip s5p6440_gpios_4bit[] = {
-#ifdef CONFIG_CPU_S5P6440
- {
- .chip = {
- .base = S5P6440_GPA(0),
- .ngpio = S5P6440_GPIO_A_NR,
- .label = "GPA",
- },
- }, {
- .chip = {
- .base = S5P6440_GPB(0),
- .ngpio = S5P6440_GPIO_B_NR,
- .label = "GPB",
- },
- }, {
- .chip = {
- .base = S5P6440_GPC(0),
- .ngpio = S5P6440_GPIO_C_NR,
- .label = "GPC",
- },
- }, {
- .base = S5P64X0_GPG_BASE,
- .chip = {
- .base = S5P6440_GPG(0),
- .ngpio = S5P6440_GPIO_G_NR,
- .label = "GPG",
- },
- },
-#endif
-};
-
-static struct samsung_gpio_chip s5p6440_gpios_4bit2[] = {
-#ifdef CONFIG_CPU_S5P6440
- {
- .base = S5P64X0_GPH_BASE + 0x4,
- .chip = {
- .base = S5P6440_GPH(0),
- .ngpio = S5P6440_GPIO_H_NR,
- .label = "GPH",
- },
- },
-#endif
-};
-
-static struct samsung_gpio_chip s5p6440_gpios_rbank[] = {
-#ifdef CONFIG_CPU_S5P6440
- {
- .base = S5P64X0_GPR_BASE + 0x4,
- .config = &s5p64x0_gpio_cfg_rbank,
- .chip = {
- .base = S5P6440_GPR(0),
- .ngpio = S5P6440_GPIO_R_NR,
- .label = "GPR",
- },
- },
-#endif
-};
-
-static struct samsung_gpio_chip s5p6440_gpios_2bit[] = {
-#ifdef CONFIG_CPU_S5P6440
- {
- .base = S5P64X0_GPF_BASE,
- .config = &samsung_gpio_cfgs[6],
- .chip = {
- .base = S5P6440_GPF(0),
- .ngpio = S5P6440_GPIO_F_NR,
- .label = "GPF",
- },
- }, {
- .base = S5P64X0_GPI_BASE,
- .config = &samsung_gpio_cfgs[4],
- .chip = {
- .base = S5P6440_GPI(0),
- .ngpio = S5P6440_GPIO_I_NR,
- .label = "GPI",
- },
- }, {
- .base = S5P64X0_GPJ_BASE,
- .config = &samsung_gpio_cfgs[4],
- .chip = {
- .base = S5P6440_GPJ(0),
- .ngpio = S5P6440_GPIO_J_NR,
- .label = "GPJ",
- },
- }, {
- .base = S5P64X0_GPN_BASE,
- .config = &samsung_gpio_cfgs[5],
- .chip = {
- .base = S5P6440_GPN(0),
- .ngpio = S5P6440_GPIO_N_NR,
- .label = "GPN",
- },
- }, {
- .base = S5P64X0_GPP_BASE,
- .config = &samsung_gpio_cfgs[6],
- .chip = {
- .base = S5P6440_GPP(0),
- .ngpio = S5P6440_GPIO_P_NR,
- .label = "GPP",
- },
- },
-#endif
-};
-
-/*
- * S5P6450 GPIO bank summary:
- *
- * Bank GPIOs Style SlpCon ExtInt Group
- * A 6 4Bit Yes 1
- * B 7 4Bit Yes 1
- * C 8 4Bit Yes 2
- * D 8 4Bit Yes None
- * F 2 2Bit Yes None
- * G 14 4Bit[2] Yes 5
- * H 10 4Bit[2] Yes 6
- * I 16 2Bit Yes None
- * J 12 2Bit Yes None
- * K 5 4Bit Yes None
- * N 16 2Bit No IRQ_EINT
- * P 11 2Bit Yes 8
- * Q 14 2Bit Yes None
- * R 15 4Bit[2] Yes None
- * S 8 2Bit Yes None
- *
- * [1] BANKF pins 14,15 do not form part of the external interrupt sources
- * [2] BANK has two control registers, GPxCON0 and GPxCON1
- */
-
-static struct samsung_gpio_chip s5p6450_gpios_4bit[] = {
-#ifdef CONFIG_CPU_S5P6450
- {
- .chip = {
- .base = S5P6450_GPA(0),
- .ngpio = S5P6450_GPIO_A_NR,
- .label = "GPA",
- },
- }, {
- .chip = {
- .base = S5P6450_GPB(0),
- .ngpio = S5P6450_GPIO_B_NR,
- .label = "GPB",
- },
- }, {
- .chip = {
- .base = S5P6450_GPC(0),
- .ngpio = S5P6450_GPIO_C_NR,
- .label = "GPC",
- },
- }, {
- .chip = {
- .base = S5P6450_GPD(0),
- .ngpio = S5P6450_GPIO_D_NR,
- .label = "GPD",
- },
- }, {
- .base = S5P6450_GPK_BASE,
- .chip = {
- .base = S5P6450_GPK(0),
- .ngpio = S5P6450_GPIO_K_NR,
- .label = "GPK",
- },
- },
-#endif
-};
-
-static struct samsung_gpio_chip s5p6450_gpios_4bit2[] = {
-#ifdef CONFIG_CPU_S5P6450
- {
- .base = S5P64X0_GPG_BASE + 0x4,
- .chip = {
- .base = S5P6450_GPG(0),
- .ngpio = S5P6450_GPIO_G_NR,
- .label = "GPG",
- },
- }, {
- .base = S5P64X0_GPH_BASE + 0x4,
- .chip = {
- .base = S5P6450_GPH(0),
- .ngpio = S5P6450_GPIO_H_NR,
- .label = "GPH",
- },
- },
-#endif
-};
-
-static struct samsung_gpio_chip s5p6450_gpios_rbank[] = {
-#ifdef CONFIG_CPU_S5P6450
- {
- .base = S5P64X0_GPR_BASE + 0x4,
- .config = &s5p64x0_gpio_cfg_rbank,
- .chip = {
- .base = S5P6450_GPR(0),
- .ngpio = S5P6450_GPIO_R_NR,
- .label = "GPR",
- },
- },
-#endif
-};
-
-static struct samsung_gpio_chip s5p6450_gpios_2bit[] = {
-#ifdef CONFIG_CPU_S5P6450
- {
- .base = S5P64X0_GPF_BASE,
- .config = &samsung_gpio_cfgs[6],
- .chip = {
- .base = S5P6450_GPF(0),
- .ngpio = S5P6450_GPIO_F_NR,
- .label = "GPF",
- },
- }, {
- .base = S5P64X0_GPI_BASE,
- .config = &samsung_gpio_cfgs[4],
- .chip = {
- .base = S5P6450_GPI(0),
- .ngpio = S5P6450_GPIO_I_NR,
- .label = "GPI",
- },
- }, {
- .base = S5P64X0_GPJ_BASE,
- .config = &samsung_gpio_cfgs[4],
- .chip = {
- .base = S5P6450_GPJ(0),
- .ngpio = S5P6450_GPIO_J_NR,
- .label = "GPJ",
- },
- }, {
- .base = S5P64X0_GPN_BASE,
- .config = &samsung_gpio_cfgs[5],
- .chip = {
- .base = S5P6450_GPN(0),
- .ngpio = S5P6450_GPIO_N_NR,
- .label = "GPN",
- },
- }, {
- .base = S5P64X0_GPP_BASE,
- .config = &samsung_gpio_cfgs[6],
- .chip = {
- .base = S5P6450_GPP(0),
- .ngpio = S5P6450_GPIO_P_NR,
- .label = "GPP",
- },
- }, {
- .base = S5P6450_GPQ_BASE,
- .config = &samsung_gpio_cfgs[5],
- .chip = {
- .base = S5P6450_GPQ(0),
- .ngpio = S5P6450_GPIO_Q_NR,
- .label = "GPQ",
- },
- }, {
- .base = S5P6450_GPS_BASE,
- .config = &samsung_gpio_cfgs[6],
- .chip = {
- .base = S5P6450_GPS(0),
- .ngpio = S5P6450_GPIO_S_NR,
- .label = "GPS",
- },
- },
-#endif
-};
-
-/*
- * S5PC100 GPIO bank summary:
- *
- * Bank GPIOs Style INT Type
- * A0 8 4Bit GPIO_INT0
- * A1 5 4Bit GPIO_INT1
- * B 8 4Bit GPIO_INT2
- * C 5 4Bit GPIO_INT3
- * D 7 4Bit GPIO_INT4
- * E0 8 4Bit GPIO_INT5
- * E1 6 4Bit GPIO_INT6
- * F0 8 4Bit GPIO_INT7
- * F1 8 4Bit GPIO_INT8
- * F2 8 4Bit GPIO_INT9
- * F3 4 4Bit GPIO_INT10
- * G0 8 4Bit GPIO_INT11
- * G1 3 4Bit GPIO_INT12
- * G2 7 4Bit GPIO_INT13
- * G3 7 4Bit GPIO_INT14
- * H0 8 4Bit WKUP_INT
- * H1 8 4Bit WKUP_INT
- * H2 8 4Bit WKUP_INT
- * H3 8 4Bit WKUP_INT
- * I 8 4Bit GPIO_INT15
- * J0 8 4Bit GPIO_INT16
- * J1 5 4Bit GPIO_INT17
- * J2 8 4Bit GPIO_INT18
- * J3 8 4Bit GPIO_INT19
- * J4 4 4Bit GPIO_INT20
- * K0 8 4Bit None
- * K1 6 4Bit None
- * K2 8 4Bit None
- * K3 8 4Bit None
- * L0 8 4Bit None
- * L1 8 4Bit None
- * L2 8 4Bit None
- * L3 8 4Bit None
- */
-
-static struct samsung_gpio_chip s5pc100_gpios_4bit[] = {
-#ifdef CONFIG_CPU_S5PC100
- {
- .chip = {
- .base = S5PC100_GPA0(0),
- .ngpio = S5PC100_GPIO_A0_NR,
- .label = "GPA0",
- },
- }, {
- .chip = {
- .base = S5PC100_GPA1(0),
- .ngpio = S5PC100_GPIO_A1_NR,
- .label = "GPA1",
- },
- }, {
- .chip = {
- .base = S5PC100_GPB(0),
- .ngpio = S5PC100_GPIO_B_NR,
- .label = "GPB",
- },
- }, {
- .chip = {
- .base = S5PC100_GPC(0),
- .ngpio = S5PC100_GPIO_C_NR,
- .label = "GPC",
- },
- }, {
- .chip = {
- .base = S5PC100_GPD(0),
- .ngpio = S5PC100_GPIO_D_NR,
- .label = "GPD",
- },
- }, {
- .chip = {
- .base = S5PC100_GPE0(0),
- .ngpio = S5PC100_GPIO_E0_NR,
- .label = "GPE0",
- },
- }, {
- .chip = {
- .base = S5PC100_GPE1(0),
- .ngpio = S5PC100_GPIO_E1_NR,
- .label = "GPE1",
- },
- }, {
- .chip = {
- .base = S5PC100_GPF0(0),
- .ngpio = S5PC100_GPIO_F0_NR,
- .label = "GPF0",
- },
- }, {
- .chip = {
- .base = S5PC100_GPF1(0),
- .ngpio = S5PC100_GPIO_F1_NR,
- .label = "GPF1",
- },
- }, {
- .chip = {
- .base = S5PC100_GPF2(0),
- .ngpio = S5PC100_GPIO_F2_NR,
- .label = "GPF2",
- },
- }, {
- .chip = {
- .base = S5PC100_GPF3(0),
- .ngpio = S5PC100_GPIO_F3_NR,
- .label = "GPF3",
- },
- }, {
- .chip = {
- .base = S5PC100_GPG0(0),
- .ngpio = S5PC100_GPIO_G0_NR,
- .label = "GPG0",
- },
- }, {
- .chip = {
- .base = S5PC100_GPG1(0),
- .ngpio = S5PC100_GPIO_G1_NR,
- .label = "GPG1",
- },
- }, {
- .chip = {
- .base = S5PC100_GPG2(0),
- .ngpio = S5PC100_GPIO_G2_NR,
- .label = "GPG2",
- },
- }, {
- .chip = {
- .base = S5PC100_GPG3(0),
- .ngpio = S5PC100_GPIO_G3_NR,
- .label = "GPG3",
- },
- }, {
- .chip = {
- .base = S5PC100_GPI(0),
- .ngpio = S5PC100_GPIO_I_NR,
- .label = "GPI",
- },
- }, {
- .chip = {
- .base = S5PC100_GPJ0(0),
- .ngpio = S5PC100_GPIO_J0_NR,
- .label = "GPJ0",
- },
- }, {
- .chip = {
- .base = S5PC100_GPJ1(0),
- .ngpio = S5PC100_GPIO_J1_NR,
- .label = "GPJ1",
- },
- }, {
- .chip = {
- .base = S5PC100_GPJ2(0),
- .ngpio = S5PC100_GPIO_J2_NR,
- .label = "GPJ2",
- },
- }, {
- .chip = {
- .base = S5PC100_GPJ3(0),
- .ngpio = S5PC100_GPIO_J3_NR,
- .label = "GPJ3",
- },
- }, {
- .chip = {
- .base = S5PC100_GPJ4(0),
- .ngpio = S5PC100_GPIO_J4_NR,
- .label = "GPJ4",
- },
- }, {
- .chip = {
- .base = S5PC100_GPK0(0),
- .ngpio = S5PC100_GPIO_K0_NR,
- .label = "GPK0",
- },
- }, {
- .chip = {
- .base = S5PC100_GPK1(0),
- .ngpio = S5PC100_GPIO_K1_NR,
- .label = "GPK1",
- },
- }, {
- .chip = {
- .base = S5PC100_GPK2(0),
- .ngpio = S5PC100_GPIO_K2_NR,
- .label = "GPK2",
- },
- }, {
- .chip = {
- .base = S5PC100_GPK3(0),
- .ngpio = S5PC100_GPIO_K3_NR,
- .label = "GPK3",
- },
- }, {
- .chip = {
- .base = S5PC100_GPL0(0),
- .ngpio = S5PC100_GPIO_L0_NR,
- .label = "GPL0",
- },
- }, {
- .chip = {
- .base = S5PC100_GPL1(0),
- .ngpio = S5PC100_GPIO_L1_NR,
- .label = "GPL1",
- },
- }, {
- .chip = {
- .base = S5PC100_GPL2(0),
- .ngpio = S5PC100_GPIO_L2_NR,
- .label = "GPL2",
- },
- }, {
- .chip = {
- .base = S5PC100_GPL3(0),
- .ngpio = S5PC100_GPIO_L3_NR,
- .label = "GPL3",
- },
- }, {
- .chip = {
- .base = S5PC100_GPL4(0),
- .ngpio = S5PC100_GPIO_L4_NR,
- .label = "GPL4",
- },
- }, {
- .base = (S5P_VA_GPIO + 0xC00),
- .irq_base = IRQ_EINT(0),
- .chip = {
- .base = S5PC100_GPH0(0),
- .ngpio = S5PC100_GPIO_H0_NR,
- .label = "GPH0",
- .to_irq = samsung_gpiolib_to_irq,
- },
- }, {
- .base = (S5P_VA_GPIO + 0xC20),
- .irq_base = IRQ_EINT(8),
- .chip = {
- .base = S5PC100_GPH1(0),
- .ngpio = S5PC100_GPIO_H1_NR,
- .label = "GPH1",
- .to_irq = samsung_gpiolib_to_irq,
- },
- }, {
- .base = (S5P_VA_GPIO + 0xC40),
- .irq_base = IRQ_EINT(16),
- .chip = {
- .base = S5PC100_GPH2(0),
- .ngpio = S5PC100_GPIO_H2_NR,
- .label = "GPH2",
- .to_irq = samsung_gpiolib_to_irq,
- },
- }, {
- .base = (S5P_VA_GPIO + 0xC60),
- .irq_base = IRQ_EINT(24),
- .chip = {
- .base = S5PC100_GPH3(0),
- .ngpio = S5PC100_GPIO_H3_NR,
- .label = "GPH3",
- .to_irq = samsung_gpiolib_to_irq,
- },
- },
-#endif
-};
-
-/*
- * Followings are the gpio banks in S5PV210/S5PC110
- *
- * The 'config' member when left to NULL, is initialized to the default
- * structure samsung_gpio_cfgs[3] in the init function below.
- *
- * The 'base' member is also initialized in the init function below.
- * Note: The initialization of 'base' member of samsung_gpio_chip structure
- * uses the above macro and depends on the banks being listed in order here.
- */
-
-static struct samsung_gpio_chip s5pv210_gpios_4bit[] = {
-#ifdef CONFIG_CPU_S5PV210
- {
- .chip = {
- .base = S5PV210_GPA0(0),
- .ngpio = S5PV210_GPIO_A0_NR,
- .label = "GPA0",
- },
- }, {
- .chip = {
- .base = S5PV210_GPA1(0),
- .ngpio = S5PV210_GPIO_A1_NR,
- .label = "GPA1",
- },
- }, {
- .chip = {
- .base = S5PV210_GPB(0),
- .ngpio = S5PV210_GPIO_B_NR,
- .label = "GPB",
- },
- }, {
- .chip = {
- .base = S5PV210_GPC0(0),
- .ngpio = S5PV210_GPIO_C0_NR,
- .label = "GPC0",
- },
- }, {
- .chip = {
- .base = S5PV210_GPC1(0),
- .ngpio = S5PV210_GPIO_C1_NR,
- .label = "GPC1",
- },
- }, {
- .chip = {
- .base = S5PV210_GPD0(0),
- .ngpio = S5PV210_GPIO_D0_NR,
- .label = "GPD0",
- },
- }, {
- .chip = {
- .base = S5PV210_GPD1(0),
- .ngpio = S5PV210_GPIO_D1_NR,
- .label = "GPD1",
- },
- }, {
- .chip = {
- .base = S5PV210_GPE0(0),
- .ngpio = S5PV210_GPIO_E0_NR,
- .label = "GPE0",
- },
- }, {
- .chip = {
- .base = S5PV210_GPE1(0),
- .ngpio = S5PV210_GPIO_E1_NR,
- .label = "GPE1",
- },
- }, {
- .chip = {
- .base = S5PV210_GPF0(0),
- .ngpio = S5PV210_GPIO_F0_NR,
- .label = "GPF0",
- },
- }, {
- .chip = {
- .base = S5PV210_GPF1(0),
- .ngpio = S5PV210_GPIO_F1_NR,
- .label = "GPF1",
- },
- }, {
- .chip = {
- .base = S5PV210_GPF2(0),
- .ngpio = S5PV210_GPIO_F2_NR,
- .label = "GPF2",
- },
- }, {
- .chip = {
- .base = S5PV210_GPF3(0),
- .ngpio = S5PV210_GPIO_F3_NR,
- .label = "GPF3",
- },
- }, {
- .chip = {
- .base = S5PV210_GPG0(0),
- .ngpio = S5PV210_GPIO_G0_NR,
- .label = "GPG0",
- },
- }, {
- .chip = {
- .base = S5PV210_GPG1(0),
- .ngpio = S5PV210_GPIO_G1_NR,
- .label = "GPG1",
- },
- }, {
- .chip = {
- .base = S5PV210_GPG2(0),
- .ngpio = S5PV210_GPIO_G2_NR,
- .label = "GPG2",
- },
- }, {
- .chip = {
- .base = S5PV210_GPG3(0),
- .ngpio = S5PV210_GPIO_G3_NR,
- .label = "GPG3",
- },
- }, {
- .chip = {
- .base = S5PV210_GPI(0),
- .ngpio = S5PV210_GPIO_I_NR,
- .label = "GPI",
- },
- }, {
- .chip = {
- .base = S5PV210_GPJ0(0),
- .ngpio = S5PV210_GPIO_J0_NR,
- .label = "GPJ0",
- },
- }, {
- .chip = {
- .base = S5PV210_GPJ1(0),
- .ngpio = S5PV210_GPIO_J1_NR,
- .label = "GPJ1",
- },
- }, {
- .chip = {
- .base = S5PV210_GPJ2(0),
- .ngpio = S5PV210_GPIO_J2_NR,
- .label = "GPJ2",
- },
- }, {
- .chip = {
- .base = S5PV210_GPJ3(0),
- .ngpio = S5PV210_GPIO_J3_NR,
- .label = "GPJ3",
- },
- }, {
- .chip = {
- .base = S5PV210_GPJ4(0),
- .ngpio = S5PV210_GPIO_J4_NR,
- .label = "GPJ4",
- },
- }, {
- .chip = {
- .base = S5PV210_MP01(0),
- .ngpio = S5PV210_GPIO_MP01_NR,
- .label = "MP01",
- },
- }, {
- .chip = {
- .base = S5PV210_MP02(0),
- .ngpio = S5PV210_GPIO_MP02_NR,
- .label = "MP02",
- },
- }, {
- .chip = {
- .base = S5PV210_MP03(0),
- .ngpio = S5PV210_GPIO_MP03_NR,
- .label = "MP03",
- },
- }, {
- .chip = {
- .base = S5PV210_MP04(0),
- .ngpio = S5PV210_GPIO_MP04_NR,
- .label = "MP04",
- },
- }, {
- .chip = {
- .base = S5PV210_MP05(0),
- .ngpio = S5PV210_GPIO_MP05_NR,
- .label = "MP05",
- },
- }, {
- .base = (S5P_VA_GPIO + 0xC00),
- .irq_base = IRQ_EINT(0),
- .chip = {
- .base = S5PV210_GPH0(0),
- .ngpio = S5PV210_GPIO_H0_NR,
- .label = "GPH0",
- .to_irq = samsung_gpiolib_to_irq,
- },
- }, {
- .base = (S5P_VA_GPIO + 0xC20),
- .irq_base = IRQ_EINT(8),
- .chip = {
- .base = S5PV210_GPH1(0),
- .ngpio = S5PV210_GPIO_H1_NR,
- .label = "GPH1",
- .to_irq = samsung_gpiolib_to_irq,
- },
- }, {
- .base = (S5P_VA_GPIO + 0xC40),
- .irq_base = IRQ_EINT(16),
- .chip = {
- .base = S5PV210_GPH2(0),
- .ngpio = S5PV210_GPIO_H2_NR,
- .label = "GPH2",
- .to_irq = samsung_gpiolib_to_irq,
- },
- }, {
- .base = (S5P_VA_GPIO + 0xC60),
- .irq_base = IRQ_EINT(24),
- .chip = {
- .base = S5PV210_GPH3(0),
- .ngpio = S5PV210_GPIO_H3_NR,
- .label = "GPH3",
- .to_irq = samsung_gpiolib_to_irq,
- },
- },
-#endif
-};
-
/* TODO: cleanup soc_is_* */
static __init int samsung_gpiolib_init(void)
{
- struct samsung_gpio_chip *chip;
- int i, nr_chips;
- int group = 0;
-
/*
* Currently there are two drivers that can provide GPIO support for
* Samsung SoCs. For device tree enabled platforms, the new
@@ -2109,54 +1192,6 @@ static __init int samsung_gpiolib_init(void)
S3C64XX_VA_GPIO);
samsung_gpiolib_add_4bit2_chips(s3c64xx_gpios_4bit2,
ARRAY_SIZE(s3c64xx_gpios_4bit2));
- } else if (soc_is_s5p6440()) {
- samsung_gpiolib_add_2bit_chips(s5p6440_gpios_2bit,
- ARRAY_SIZE(s5p6440_gpios_2bit), NULL, 0x0);
- samsung_gpiolib_add_4bit_chips(s5p6440_gpios_4bit,
- ARRAY_SIZE(s5p6440_gpios_4bit), S5P_VA_GPIO);
- samsung_gpiolib_add_4bit2_chips(s5p6440_gpios_4bit2,
- ARRAY_SIZE(s5p6440_gpios_4bit2));
- s5p64x0_gpiolib_add_rbank(s5p6440_gpios_rbank,
- ARRAY_SIZE(s5p6440_gpios_rbank));
- } else if (soc_is_s5p6450()) {
- samsung_gpiolib_add_2bit_chips(s5p6450_gpios_2bit,
- ARRAY_SIZE(s5p6450_gpios_2bit), NULL, 0x0);
- samsung_gpiolib_add_4bit_chips(s5p6450_gpios_4bit,
- ARRAY_SIZE(s5p6450_gpios_4bit), S5P_VA_GPIO);
- samsung_gpiolib_add_4bit2_chips(s5p6450_gpios_4bit2,
- ARRAY_SIZE(s5p6450_gpios_4bit2));
- s5p64x0_gpiolib_add_rbank(s5p6450_gpios_rbank,
- ARRAY_SIZE(s5p6450_gpios_rbank));
- } else if (soc_is_s5pc100()) {
- group = 0;
- chip = s5pc100_gpios_4bit;
- nr_chips = ARRAY_SIZE(s5pc100_gpios_4bit);
-
- for (i = 0; i < nr_chips; i++, chip++) {
- if (!chip->config) {
- chip->config = &samsung_gpio_cfgs[3];
- chip->group = group++;
- }
- }
- samsung_gpiolib_add_4bit_chips(s5pc100_gpios_4bit, nr_chips, S5P_VA_GPIO);
-#if defined(CONFIG_CPU_S5PC100) && defined(CONFIG_S5P_GPIO_INT)
- s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR);
-#endif
- } else if (soc_is_s5pv210()) {
- group = 0;
- chip = s5pv210_gpios_4bit;
- nr_chips = ARRAY_SIZE(s5pv210_gpios_4bit);
-
- for (i = 0; i < nr_chips; i++, chip++) {
- if (!chip->config) {
- chip->config = &samsung_gpio_cfgs[3];
- chip->group = group++;
- }
- }
- samsung_gpiolib_add_4bit_chips(s5pv210_gpios_4bit, nr_chips, S5P_VA_GPIO);
-#if defined(CONFIG_CPU_S5PV210) && defined(CONFIG_S5P_GPIO_INT)
- s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR);
-#endif
} else {
WARN(1, "Unknown SoC in gpio-samsung, no GPIOs added\n");
return -ENODEV;
diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c
index 5af65719b95d..41e91d70301e 100644
--- a/drivers/gpio/gpio-sch.c
+++ b/drivers/gpio/gpio-sch.c
@@ -97,8 +97,6 @@ static int sch_gpio_core_direction_out(struct gpio_chip *gc,
u8 curr_dirs;
unsigned short offset, bit;
- sch_gpio_core_set(gc, gpio_num, val);
-
spin_lock(&gpio_lock);
offset = CGIO + gpio_num / 8;
@@ -109,6 +107,17 @@ static int sch_gpio_core_direction_out(struct gpio_chip *gc,
outb(curr_dirs & ~(1 << bit), gpio_ba + offset);
spin_unlock(&gpio_lock);
+
+ /*
+ * according to the datasheet, writing to the level register has no
+ * effect when GPIO is programmed as input.
+ * Actually the the level register is read-only when configured as input.
+ * Thus presetting the output level before switching to output is _NOT_ possible.
+ * Hence we set the level after configuring the GPIO as output.
+ * But we cannot prevent a short low pulse if direction is set to high
+ * and an external pull-up is connected.
+ */
+ sch_gpio_core_set(gc, gpio_num, val);
return 0;
}
@@ -178,8 +187,6 @@ static int sch_gpio_resume_direction_out(struct gpio_chip *gc,
u8 curr_dirs;
unsigned short offset, bit;
- sch_gpio_resume_set(gc, gpio_num, val);
-
offset = RGIO + gpio_num / 8;
bit = gpio_num % 8;
@@ -190,6 +197,17 @@ static int sch_gpio_resume_direction_out(struct gpio_chip *gc,
outb(curr_dirs & ~(1 << bit), gpio_ba + offset);
spin_unlock(&gpio_lock);
+
+ /*
+ * according to the datasheet, writing to the level register has no
+ * effect when GPIO is programmed as input.
+ * Actually the the level register is read-only when configured as input.
+ * Thus presetting the output level before switching to output is _NOT_ possible.
+ * Hence we set the level after configuring the GPIO as output.
+ * But we cannot prevent a short low pulse if direction is set to high
+ * and an external pull-up is connected.
+ */
+ sch_gpio_resume_set(gc, gpio_num, val);
return 0;
}
@@ -272,8 +290,7 @@ static int sch_gpio_probe(struct platform_device *pdev)
return 0;
err_sch_gpio_resume:
- if (gpiochip_remove(&sch_gpio_core))
- dev_err(&pdev->dev, "%s gpiochip_remove failed\n", __func__);
+ gpiochip_remove(&sch_gpio_core);
err_sch_gpio_core:
release_region(res->start, resource_size(res));
@@ -286,23 +303,14 @@ static int sch_gpio_remove(struct platform_device *pdev)
{
struct resource *res;
if (gpio_ba) {
- int err;
- err = gpiochip_remove(&sch_gpio_core);
- if (err)
- dev_err(&pdev->dev, "%s failed, %d\n",
- "gpiochip_remove()", err);
- err = gpiochip_remove(&sch_gpio_resume);
- if (err)
- dev_err(&pdev->dev, "%s failed, %d\n",
- "gpiochip_remove()", err);
+ gpiochip_remove(&sch_gpio_core);
+ gpiochip_remove(&sch_gpio_resume);
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
release_region(res->start, resource_size(res));
gpio_ba = 0;
-
- return err;
}
return 0;
diff --git a/drivers/gpio/gpio-sch311x.c b/drivers/gpio/gpio-sch311x.c
index 0357387b3645..0cb11413e814 100644
--- a/drivers/gpio/gpio-sch311x.c
+++ b/drivers/gpio/gpio-sch311x.c
@@ -291,14 +291,12 @@ static int sch311x_gpio_remove(struct platform_device *pdev)
{
struct sch311x_pdev_data *pdata = pdev->dev.platform_data;
struct sch311x_gpio_priv *priv = platform_get_drvdata(pdev);
- int err, i;
+ int i;
release_region(pdata->runtime_reg + GP1, 6);
for (i = 0; i < ARRAY_SIZE(priv->blocks); i++) {
- err = gpiochip_remove(&priv->blocks[i].chip);
- if (err)
- return err;
+ gpiochip_remove(&priv->blocks[i].chip);
dev_info(&pdev->dev,
"SMSC SCH311x GPIO block %d unregistered.\n", i);
}
@@ -327,14 +325,22 @@ static int __init sch311x_detect(int sio_config_port, unsigned short *addr)
if (err)
return err;
- /* Check device ID. We currently know about:
- * SCH3112 (0x7c), SCH3114 (0x7d), and SCH3116 (0x7f). */
+ /* Check device ID. */
reg = sch311x_sio_inb(sio_config_port, 0x20);
- if (!(reg == 0x7c || reg == 0x7d || reg == 0x7f)) {
+ switch (reg) {
+ case 0x7c: /* SCH3112 */
+ dev_id = 2;
+ break;
+ case 0x7d: /* SCH3114 */
+ dev_id = 4;
+ break;
+ case 0x7f: /* SCH3116 */
+ dev_id = 6;
+ break;
+ default:
err = -ENODEV;
goto exit;
}
- dev_id = reg == 0x7c ? 2 : reg == 0x7d ? 4 : 6;
/* Select logical device A (runtime registers) */
sch311x_sio_outb(sio_config_port, 0x07, 0x0a);
diff --git a/drivers/gpio/gpio-sodaville.c b/drivers/gpio/gpio-sodaville.c
index 7c6c518929bc..d8da36cd8123 100644
--- a/drivers/gpio/gpio-sodaville.c
+++ b/drivers/gpio/gpio-sodaville.c
@@ -265,9 +265,7 @@ static void sdv_gpio_remove(struct pci_dev *pdev)
free_irq(pdev->irq, sd);
irq_free_descs(sd->irq_base, SDV_NUM_PUB_GPIOS);
- if (gpiochip_remove(&sd->bgpio.gc))
- dev_err(&pdev->dev, "gpiochip_remove() failed.\n");
-
+ gpiochip_remove(&sd->bgpio.gc);
pci_release_region(pdev, GPIO_BAR);
iounmap(sd->gpio_pub_base);
pci_disable_device(pdev);
diff --git a/drivers/gpio/gpio-spear-spics.c b/drivers/gpio/gpio-spear-spics.c
index 30bcc539425d..353263c85d26 100644
--- a/drivers/gpio/gpio-spear-spics.c
+++ b/drivers/gpio/gpio-spear-spics.c
@@ -129,10 +129,8 @@ static int spics_gpio_probe(struct platform_device *pdev)
int ret;
spics = devm_kzalloc(&pdev->dev, sizeof(*spics), GFP_KERNEL);
- if (!spics) {
- dev_err(&pdev->dev, "memory allocation fail\n");
+ if (!spics)
return -ENOMEM;
- }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
spics->base = devm_ioremap_resource(&pdev->dev, res);
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
index 2776a09bee58..845025a57240 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -10,8 +10,6 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/gpio.h>
-#include <linux/irq.h>
-#include <linux/irqdomain.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/mfd/stmpe.h>
@@ -23,18 +21,15 @@
enum { REG_RE, REG_FE, REG_IE };
#define CACHE_NR_REGS 3
-#define CACHE_NR_BANKS (STMPE_NR_GPIOS / 8)
+/* No variant has more than 24 GPIOs */
+#define CACHE_NR_BANKS (24 / 8)
struct stmpe_gpio {
struct gpio_chip chip;
struct stmpe *stmpe;
struct device *dev;
struct mutex irq_lock;
- struct irq_domain *domain;
-
- int irq_base;
unsigned norequest_mask;
-
/* Caches of interrupt control registers for bus_lock */
u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS];
u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS];
@@ -102,13 +97,6 @@ static int stmpe_gpio_direction_input(struct gpio_chip *chip,
return stmpe_set_bits(stmpe, reg, mask, 0);
}
-static int stmpe_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
-
- return irq_create_mapping(stmpe_gpio->domain, offset);
-}
-
static int stmpe_gpio_request(struct gpio_chip *chip, unsigned offset)
{
struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
@@ -127,14 +115,14 @@ static struct gpio_chip template_chip = {
.get = stmpe_gpio_get,
.direction_output = stmpe_gpio_direction_output,
.set = stmpe_gpio_set,
- .to_irq = stmpe_gpio_to_irq,
.request = stmpe_gpio_request,
.can_sleep = true,
};
static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type)
{
- struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc);
int offset = d->hwirq;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
@@ -161,14 +149,16 @@ static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type)
static void stmpe_gpio_irq_lock(struct irq_data *d)
{
- struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc);
mutex_lock(&stmpe_gpio->irq_lock);
}
static void stmpe_gpio_irq_sync_unlock(struct irq_data *d)
{
- struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc);
struct stmpe *stmpe = stmpe_gpio->stmpe;
int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
static const u8 regmap[] = {
@@ -201,7 +191,8 @@ static void stmpe_gpio_irq_sync_unlock(struct irq_data *d)
static void stmpe_gpio_irq_mask(struct irq_data *d)
{
- struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc);
int offset = d->hwirq;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
@@ -211,7 +202,8 @@ static void stmpe_gpio_irq_mask(struct irq_data *d)
static void stmpe_gpio_irq_unmask(struct irq_data *d)
{
- struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc);
int offset = d->hwirq;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
@@ -254,7 +246,7 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
while (stat) {
int bit = __ffs(stat);
int line = bank * 8 + bit;
- int child_irq = irq_find_mapping(stmpe_gpio->domain,
+ int child_irq = irq_find_mapping(stmpe_gpio->chip.irqdomain,
line);
handle_nested_irq(child_irq);
@@ -272,61 +264,6 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
return IRQ_HANDLED;
}
-static int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int irq,
- irq_hw_number_t hwirq)
-{
- struct stmpe_gpio *stmpe_gpio = d->host_data;
-
- if (!stmpe_gpio)
- return -EINVAL;
-
- irq_set_chip_data(irq, stmpe_gpio);
- irq_set_chip_and_handler(irq, &stmpe_gpio_irq_chip,
- handle_simple_irq);
- irq_set_nested_thread(irq, 1);
-#ifdef CONFIG_ARM
- set_irq_flags(irq, IRQF_VALID);
-#else
- irq_set_noprobe(irq);
-#endif
-
- return 0;
-}
-
-static void stmpe_gpio_irq_unmap(struct irq_domain *d, unsigned int irq)
-{
-#ifdef CONFIG_ARM
- set_irq_flags(irq, 0);
-#endif
- irq_set_chip_and_handler(irq, NULL, NULL);
- irq_set_chip_data(irq, NULL);
-}
-
-static const struct irq_domain_ops stmpe_gpio_irq_simple_ops = {
- .unmap = stmpe_gpio_irq_unmap,
- .map = stmpe_gpio_irq_map,
- .xlate = irq_domain_xlate_twocell,
-};
-
-static int stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio,
- struct device_node *np)
-{
- int base = 0;
-
- if (!np)
- base = stmpe_gpio->irq_base;
-
- stmpe_gpio->domain = irq_domain_add_simple(np,
- stmpe_gpio->chip.ngpio, base,
- &stmpe_gpio_irq_simple_ops, stmpe_gpio);
- if (!stmpe_gpio->domain) {
- dev_err(stmpe_gpio->dev, "failed to create irqdomain\n");
- return -ENOSYS;
- }
-
- return 0;
-}
-
static int stmpe_gpio_probe(struct platform_device *pdev)
{
struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
@@ -354,7 +291,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
#ifdef CONFIG_OF
stmpe_gpio->chip.of_node = np;
#endif
- stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1;
+ stmpe_gpio->chip.base = -1;
if (pdata)
stmpe_gpio->norequest_mask = pdata->norequest_mask;
@@ -362,34 +299,39 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
of_property_read_u32(np, "st,norequest-mask",
&stmpe_gpio->norequest_mask);
- if (irq >= 0)
- stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0);
- else
+ if (irq < 0)
dev_info(&pdev->dev,
- "device configured in no-irq mode; "
+ "device configured in no-irq mode: "
"irqs are not available\n");
ret = stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
if (ret)
goto out_free;
- if (irq >= 0) {
- ret = stmpe_gpio_irq_init(stmpe_gpio, np);
- if (ret)
- goto out_disable;
-
- ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq,
- IRQF_ONESHOT, "stmpe-gpio", stmpe_gpio);
+ if (irq > 0) {
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ stmpe_gpio_irq, IRQF_ONESHOT,
+ "stmpe-gpio", stmpe_gpio);
if (ret) {
dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
goto out_disable;
}
+ ret = gpiochip_irqchip_add(&stmpe_gpio->chip,
+ &stmpe_gpio_irq_chip,
+ 0,
+ handle_simple_irq,
+ IRQ_TYPE_NONE);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "could not connect irqchip to gpiochip\n");
+ return ret;
+ }
}
ret = gpiochip_add(&stmpe_gpio->chip);
if (ret) {
dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
- goto out_freeirq;
+ goto out_disable;
}
if (pdata && pdata->setup)
@@ -399,9 +341,6 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
return 0;
-out_freeirq:
- if (irq >= 0)
- free_irq(irq, stmpe_gpio);
out_disable:
stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
out_free:
@@ -414,24 +353,14 @@ static int stmpe_gpio_remove(struct platform_device *pdev)
struct stmpe_gpio *stmpe_gpio = platform_get_drvdata(pdev);
struct stmpe *stmpe = stmpe_gpio->stmpe;
struct stmpe_gpio_platform_data *pdata = stmpe->pdata->gpio;
- int irq = platform_get_irq(pdev, 0);
- int ret;
if (pdata && pdata->remove)
pdata->remove(stmpe, stmpe_gpio->chip.base);
- ret = gpiochip_remove(&stmpe_gpio->chip);
- if (ret < 0) {
- dev_err(stmpe_gpio->dev,
- "unable to remove gpiochip: %d\n", ret);
- return ret;
- }
+ gpiochip_remove(&stmpe_gpio->chip);
stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
- if (irq >= 0)
- free_irq(irq, stmpe_gpio);
-
kfree(stmpe_gpio);
return 0;
diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c
index 13d73fb2b5e1..bce6c6108f20 100644
--- a/drivers/gpio/gpio-sx150x.c
+++ b/drivers/gpio/gpio-sx150x.c
@@ -22,7 +22,6 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
-#include <linux/workqueue.h>
#include <linux/i2c/sx150x.h>
#define NO_UPDATE_PENDING -1
@@ -616,19 +615,16 @@ static int sx150x_probe(struct i2c_client *client,
return 0;
probe_fail_post_gpiochip_add:
- WARN_ON(gpiochip_remove(&chip->gpio_chip) < 0);
+ gpiochip_remove(&chip->gpio_chip);
return rc;
}
static int sx150x_remove(struct i2c_client *client)
{
struct sx150x_chip *chip;
- int rc;
chip = i2c_get_clientdata(client);
- rc = gpiochip_remove(&chip->gpio_chip);
- if (rc < 0)
- return rc;
+ gpiochip_remove(&chip->gpio_chip);
if (chip->irq_summary >= 0)
sx150x_remove_irq_chip(chip);
diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c
index b50fe1297748..30884fbc750d 100644
--- a/drivers/gpio/gpio-syscon.c
+++ b/drivers/gpio/gpio-syscon.c
@@ -172,7 +172,8 @@ static int syscon_gpio_remove(struct platform_device *pdev)
{
struct syscon_gpio_priv *priv = platform_get_drvdata(pdev);
- return gpiochip_remove(&priv->chip);
+ gpiochip_remove(&priv->chip);
+ return 0;
}
static struct platform_driver syscon_gpio_driver = {
diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c
index 07bce97647a6..9e615be8032c 100644
--- a/drivers/gpio/gpio-tb10x.c
+++ b/drivers/gpio/gpio-tb10x.c
@@ -291,7 +291,6 @@ fail_ioremap:
static int __exit tb10x_gpio_remove(struct platform_device *pdev)
{
struct tb10x_gpio *tb10x_gpio = platform_get_drvdata(pdev);
- int ret;
if (tb10x_gpio->gc.to_irq) {
irq_remove_generic_chip(tb10x_gpio->domain->gc->gc[0],
@@ -300,9 +299,7 @@ static int __exit tb10x_gpio_remove(struct platform_device *pdev)
irq_domain_remove(tb10x_gpio->domain);
free_irq(tb10x_gpio->irq, tb10x_gpio);
}
- ret = gpiochip_remove(&tb10x_gpio->gc);
- if (ret)
- return ret;
+ gpiochip_remove(&tb10x_gpio->gc);
return 0;
}
diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c
index 1019320984d7..7324869c38e0 100644
--- a/drivers/gpio/gpio-tc3589x.c
+++ b/drivers/gpio/gpio-tc3589x.c
@@ -12,8 +12,6 @@
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/of.h>
-#include <linux/irq.h>
-#include <linux/irqdomain.h>
#include <linux/interrupt.h>
#include <linux/mfd/tc3589x.h>
@@ -31,10 +29,6 @@ struct tc3589x_gpio {
struct tc3589x *tc3589x;
struct device *dev;
struct mutex irq_lock;
- struct irq_domain *domain;
-
- int irq_base;
-
/* Caches of interrupt control registers for bus_lock */
u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS];
u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS];
@@ -95,30 +89,6 @@ static int tc3589x_gpio_direction_input(struct gpio_chip *chip,
return tc3589x_set_bits(tc3589x, reg, 1 << pos, 0);
}
-/**
- * tc3589x_gpio_irq_get_irq(): Map a hardware IRQ on a chip to a Linux IRQ
- *
- * @tc3589x_gpio: tc3589x_gpio_irq controller to operate on.
- * @irq: index of the hardware interrupt requested in the chip IRQs
- *
- * Useful for drivers to request their own IRQs.
- */
-static int tc3589x_gpio_irq_get_irq(struct tc3589x_gpio *tc3589x_gpio,
- int hwirq)
-{
- if (!tc3589x_gpio)
- return -EINVAL;
-
- return irq_create_mapping(tc3589x_gpio->domain, hwirq);
-}
-
-static int tc3589x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
-
- return tc3589x_gpio_irq_get_irq(tc3589x_gpio, offset);
-}
-
static struct gpio_chip template_chip = {
.label = "tc3589x",
.owner = THIS_MODULE,
@@ -126,13 +96,13 @@ static struct gpio_chip template_chip = {
.get = tc3589x_gpio_get,
.direction_output = tc3589x_gpio_direction_output,
.set = tc3589x_gpio_set,
- .to_irq = tc3589x_gpio_to_irq,
.can_sleep = true,
};
static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type)
{
- struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip);
int offset = d->hwirq;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
@@ -159,14 +129,16 @@ static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type)
static void tc3589x_gpio_irq_lock(struct irq_data *d)
{
- struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip);
mutex_lock(&tc3589x_gpio->irq_lock);
}
static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d)
{
- struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip);
struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
static const u8 regmap[] = {
[REG_IBE] = TC3589x_GPIOIBE0,
@@ -194,7 +166,8 @@ static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d)
static void tc3589x_gpio_irq_mask(struct irq_data *d)
{
- struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip);
int offset = d->hwirq;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
@@ -204,7 +177,8 @@ static void tc3589x_gpio_irq_mask(struct irq_data *d)
static void tc3589x_gpio_irq_unmask(struct irq_data *d)
{
- struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip);
int offset = d->hwirq;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
@@ -242,7 +216,8 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev)
while (stat) {
int bit = __ffs(stat);
int line = i * 8 + bit;
- int irq = tc3589x_gpio_irq_get_irq(tc3589x_gpio, line);
+ int irq = irq_find_mapping(tc3589x_gpio->chip.irqdomain,
+ line);
handle_nested_irq(irq);
stat &= ~(1 << bit);
@@ -254,61 +229,6 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev)
return IRQ_HANDLED;
}
-static int tc3589x_gpio_irq_map(struct irq_domain *d, unsigned int irq,
- irq_hw_number_t hwirq)
-{
- struct tc3589x *tc3589x_gpio = d->host_data;
-
- irq_set_chip_data(irq, tc3589x_gpio);
- irq_set_chip_and_handler(irq, &tc3589x_gpio_irq_chip,
- handle_simple_irq);
- irq_set_nested_thread(irq, 1);
-#ifdef CONFIG_ARM
- set_irq_flags(irq, IRQF_VALID);
-#else
- irq_set_noprobe(irq);
-#endif
-
- return 0;
-}
-
-static void tc3589x_gpio_irq_unmap(struct irq_domain *d, unsigned int irq)
-{
-#ifdef CONFIG_ARM
- set_irq_flags(irq, 0);
-#endif
- irq_set_chip_and_handler(irq, NULL, NULL);
- irq_set_chip_data(irq, NULL);
-}
-
-static struct irq_domain_ops tc3589x_irq_ops = {
- .map = tc3589x_gpio_irq_map,
- .unmap = tc3589x_gpio_irq_unmap,
- .xlate = irq_domain_xlate_twocell,
-};
-
-static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio,
- struct device_node *np)
-{
- int base = tc3589x_gpio->irq_base;
-
- /*
- * If this results in a linear domain, irq_create_mapping() will
- * take care of allocating IRQ descriptors at runtime. When a base
- * is provided, the IRQ descriptors will be allocated when the
- * domain is instantiated.
- */
- tc3589x_gpio->domain = irq_domain_add_simple(np,
- tc3589x_gpio->chip.ngpio, base, &tc3589x_irq_ops,
- tc3589x_gpio);
- if (!tc3589x_gpio->domain) {
- dev_err(tc3589x_gpio->dev, "Failed to create irqdomain\n");
- return -ENOSYS;
- }
-
- return 0;
-}
-
static int tc3589x_gpio_probe(struct platform_device *pdev)
{
struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent);
@@ -329,7 +249,8 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- tc3589x_gpio = kzalloc(sizeof(struct tc3589x_gpio), GFP_KERNEL);
+ tc3589x_gpio = devm_kzalloc(&pdev->dev, sizeof(struct tc3589x_gpio),
+ GFP_KERNEL);
if (!tc3589x_gpio)
return -ENOMEM;
@@ -347,30 +268,36 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
tc3589x_gpio->chip.of_node = np;
#endif
- tc3589x_gpio->irq_base = tc3589x->irq_base ?
- tc3589x->irq_base + TC3589x_INT_GPIO(0) : 0;
-
/* Bring the GPIO module out of reset */
ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL,
TC3589x_RSTCTRL_GPIRST, 0);
if (ret < 0)
- goto out_free;
-
- ret = tc3589x_gpio_irq_init(tc3589x_gpio, np);
- if (ret)
- goto out_free;
+ return ret;
- ret = request_threaded_irq(irq, NULL, tc3589x_gpio_irq, IRQF_ONESHOT,
- "tc3589x-gpio", tc3589x_gpio);
+ ret = devm_request_threaded_irq(&pdev->dev,
+ irq, NULL, tc3589x_gpio_irq,
+ IRQF_ONESHOT, "tc3589x-gpio",
+ tc3589x_gpio);
if (ret) {
dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
- goto out_free;
+ return ret;
}
ret = gpiochip_add(&tc3589x_gpio->chip);
if (ret) {
dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
- goto out_freeirq;
+ return ret;
+ }
+
+ ret = gpiochip_irqchip_add(&tc3589x_gpio->chip,
+ &tc3589x_gpio_irq_chip,
+ 0,
+ handle_simple_irq,
+ IRQ_TYPE_NONE);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "could not connect irqchip to gpiochip\n");
+ return ret;
}
if (pdata && pdata->setup)
@@ -379,12 +306,6 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, tc3589x_gpio);
return 0;
-
-out_freeirq:
- free_irq(irq, tc3589x_gpio);
-out_free:
- kfree(tc3589x_gpio);
- return ret;
}
static int tc3589x_gpio_remove(struct platform_device *pdev)
@@ -392,22 +313,11 @@ static int tc3589x_gpio_remove(struct platform_device *pdev)
struct tc3589x_gpio *tc3589x_gpio = platform_get_drvdata(pdev);
struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
struct tc3589x_gpio_platform_data *pdata = tc3589x->pdata->gpio;
- int irq = platform_get_irq(pdev, 0);
- int ret;
if (pdata && pdata->remove)
pdata->remove(tc3589x, tc3589x_gpio->chip.base);
- ret = gpiochip_remove(&tc3589x_gpio->chip);
- if (ret < 0) {
- dev_err(tc3589x_gpio->dev,
- "unable to remove gpiochip: %d\n", ret);
- return ret;
- }
-
- free_irq(irq, tc3589x_gpio);
-
- kfree(tc3589x_gpio);
+ gpiochip_remove(&tc3589x_gpio->chip);
return 0;
}
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 2b49f878b56c..4e8fb8261a87 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -408,7 +408,7 @@ static struct tegra_gpio_soc_config tegra30_gpio_config = {
.upper_offset = 0x80,
};
-static struct of_device_id tegra_gpio_of_match[] = {
+static const struct of_device_id tegra_gpio_of_match[] = {
{ .compatible = "nvidia,tegra30-gpio", .data = &tegra30_gpio_config },
{ .compatible = "nvidia,tegra20-gpio", .data = &tegra20_gpio_config },
{ },
@@ -458,10 +458,8 @@ static int tegra_gpio_probe(struct platform_device *pdev)
tegra_gpio_banks = devm_kzalloc(&pdev->dev,
tegra_gpio_bank_count * sizeof(*tegra_gpio_banks),
GFP_KERNEL);
- if (!tegra_gpio_banks) {
- dev_err(&pdev->dev, "Couldn't allocate bank structure\n");
+ if (!tegra_gpio_banks)
return -ENODEV;
- }
irq_domain = irq_domain_add_linear(pdev->dev.of_node,
tegra_gpio_chip.ngpio,
diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c
index f9a8fbde108e..a685a3cbbc81 100644
--- a/drivers/gpio/gpio-timberdale.c
+++ b/drivers/gpio/gpio-timberdale.c
@@ -224,6 +224,7 @@ static struct irq_chip timbgpio_irqchip = {
static int timbgpio_probe(struct platform_device *pdev)
{
int err, i;
+ struct device *dev = &pdev->dev;
struct gpio_chip *gc;
struct timbgpio *tgpio;
struct resource *iomem;
@@ -231,35 +232,35 @@ static int timbgpio_probe(struct platform_device *pdev)
int irq = platform_get_irq(pdev, 0);
if (!pdata || pdata->nr_pins > 32) {
- err = -EINVAL;
- goto err_mem;
+ dev_err(dev, "Invalid platform data\n");
+ return -EINVAL;
}
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!iomem) {
- err = -EINVAL;
- goto err_mem;
+ dev_err(dev, "Unable to get resource\n");
+ return -EINVAL;
}
- tgpio = kzalloc(sizeof(*tgpio), GFP_KERNEL);
+ tgpio = devm_kzalloc(dev, sizeof(struct timbgpio), GFP_KERNEL);
if (!tgpio) {
- err = -EINVAL;
- goto err_mem;
+ dev_err(dev, "Memory alloc failed\n");
+ return -EINVAL;
}
tgpio->irq_base = pdata->irq_base;
spin_lock_init(&tgpio->lock);
- if (!request_mem_region(iomem->start, resource_size(iomem),
- DRIVER_NAME)) {
- err = -EBUSY;
- goto err_request;
+ if (!devm_request_mem_region(dev, iomem->start, resource_size(iomem),
+ DRIVER_NAME)) {
+ dev_err(dev, "Region already claimed\n");
+ return -EBUSY;
}
- tgpio->membase = ioremap(iomem->start, resource_size(iomem));
+ tgpio->membase = devm_ioremap(dev, iomem->start, resource_size(iomem));
if (!tgpio->membase) {
- err = -ENOMEM;
- goto err_ioremap;
+ dev_err(dev, "Cannot ioremap\n");
+ return -ENOMEM;
}
gc = &tgpio->gpio;
@@ -279,7 +280,7 @@ static int timbgpio_probe(struct platform_device *pdev)
err = gpiochip_add(gc);
if (err)
- goto err_chipadd;
+ return err;
platform_set_drvdata(pdev, tgpio);
@@ -302,25 +303,12 @@ static int timbgpio_probe(struct platform_device *pdev)
irq_set_chained_handler(irq, timbgpio_irq);
return 0;
-
-err_chipadd:
- iounmap(tgpio->membase);
-err_ioremap:
- release_mem_region(iomem->start, resource_size(iomem));
-err_request:
- kfree(tgpio);
-err_mem:
- printk(KERN_ERR DRIVER_NAME": Failed to register GPIOs: %d\n", err);
-
- return err;
}
static int timbgpio_remove(struct platform_device *pdev)
{
- int err;
struct timbgpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct timbgpio *tgpio = platform_get_drvdata(pdev);
- struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
int irq = platform_get_irq(pdev, 0);
if (irq >= 0 && tgpio->irq_base > 0) {
@@ -334,13 +322,7 @@ static int timbgpio_remove(struct platform_device *pdev)
irq_set_handler_data(irq, NULL);
}
- err = gpiochip_remove(&tgpio->gpio);
- if (err)
- printk(KERN_ERR DRIVER_NAME": failed to remove gpio_chip\n");
-
- iounmap(tgpio->membase);
- release_mem_region(iomem->start, resource_size(iomem));
- kfree(tgpio);
+ gpiochip_remove(&tgpio->gpio);
return 0;
}
diff --git a/drivers/gpio/gpio-tps6586x.c b/drivers/gpio/gpio-tps6586x.c
index 8994dfa13491..9c9238e838a9 100644
--- a/drivers/gpio/gpio-tps6586x.c
+++ b/drivers/gpio/gpio-tps6586x.c
@@ -97,10 +97,8 @@ static int tps6586x_gpio_probe(struct platform_device *pdev)
pdata = dev_get_platdata(pdev->dev.parent);
tps6586x_gpio = devm_kzalloc(&pdev->dev,
sizeof(*tps6586x_gpio), GFP_KERNEL);
- if (!tps6586x_gpio) {
- dev_err(&pdev->dev, "Could not allocate tps6586x_gpio\n");
+ if (!tps6586x_gpio)
return -ENOMEM;
- }
tps6586x_gpio->parent = pdev->dev.parent;
@@ -139,7 +137,8 @@ static int tps6586x_gpio_remove(struct platform_device *pdev)
{
struct tps6586x_gpio *tps6586x_gpio = platform_get_drvdata(pdev);
- return gpiochip_remove(&tps6586x_gpio->gpio_chip);
+ gpiochip_remove(&tps6586x_gpio->gpio_chip);
+ return 0;
}
static struct platform_driver tps6586x_gpio_driver = {
diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c
index b6e818e68007..88f1f5ff4e96 100644
--- a/drivers/gpio/gpio-tps65910.c
+++ b/drivers/gpio/gpio-tps65910.c
@@ -123,10 +123,8 @@ static int tps65910_gpio_probe(struct platform_device *pdev)
tps65910_gpio = devm_kzalloc(&pdev->dev,
sizeof(*tps65910_gpio), GFP_KERNEL);
- if (!tps65910_gpio) {
- dev_err(&pdev->dev, "Could not allocate tps65910_gpio\n");
+ if (!tps65910_gpio)
return -ENOMEM;
- }
tps65910_gpio->tps65910 = tps65910;
@@ -192,7 +190,8 @@ static int tps65910_gpio_remove(struct platform_device *pdev)
{
struct tps65910_gpio *tps65910_gpio = platform_get_drvdata(pdev);
- return gpiochip_remove(&tps65910_gpio->gpio_chip);
+ gpiochip_remove(&tps65910_gpio->gpio_chip);
+ return 0;
}
static struct platform_driver tps65910_gpio_driver = {
diff --git a/drivers/gpio/gpio-tps65912.c b/drivers/gpio/gpio-tps65912.c
index 59ee486cb8b9..22052d84c63b 100644
--- a/drivers/gpio/gpio-tps65912.c
+++ b/drivers/gpio/gpio-tps65912.c
@@ -117,7 +117,8 @@ static int tps65912_gpio_remove(struct platform_device *pdev)
{
struct tps65912_gpio_data *tps65912_gpio = platform_get_drvdata(pdev);
- return gpiochip_remove(&tps65912_gpio->gpio_chip);
+ gpiochip_remove(&tps65912_gpio->gpio_chip);
+ return 0;
}
static struct platform_driver tps65912_gpio_driver = {
diff --git a/drivers/gpio/gpio-ts5500.c b/drivers/gpio/gpio-ts5500.c
index 3df3ebdb3e52..de18591ff11e 100644
--- a/drivers/gpio/gpio-ts5500.c
+++ b/drivers/gpio/gpio-ts5500.c
@@ -427,8 +427,7 @@ static int ts5500_dio_probe(struct platform_device *pdev)
return 0;
cleanup:
- if (gpiochip_remove(&priv->gpio_chip))
- dev_err(dev, "failed to remove gpio chip\n");
+ gpiochip_remove(&priv->gpio_chip);
return ret;
}
@@ -437,7 +436,8 @@ static int ts5500_dio_remove(struct platform_device *pdev)
struct ts5500_priv *priv = platform_get_drvdata(pdev);
ts5500_disable_irq(priv);
- return gpiochip_remove(&priv->gpio_chip);
+ gpiochip_remove(&priv->gpio_chip);
+ return 0;
}
static struct platform_device_id ts5500_dio_ids[] = {
diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c
index 3ebb1a5ff22e..118828b3736f 100644
--- a/drivers/gpio/gpio-twl4030.c
+++ b/drivers/gpio/gpio-twl4030.c
@@ -554,7 +554,7 @@ no_irqs:
platform_set_drvdata(pdev, priv);
- if (pdata && pdata->setup) {
+ if (pdata->setup) {
int status;
status = pdata->setup(&pdev->dev, priv->gpio_chip.base,
@@ -583,9 +583,7 @@ static int gpio_twl4030_remove(struct platform_device *pdev)
}
}
- status = gpiochip_remove(&priv->gpio_chip);
- if (status < 0)
- return status;
+ gpiochip_remove(&priv->gpio_chip);
if (is_module())
return 0;
diff --git a/drivers/gpio/gpio-twl6040.c b/drivers/gpio/gpio-twl6040.c
index 0caf5cd1b47d..f28e04b88aa9 100644
--- a/drivers/gpio/gpio-twl6040.c
+++ b/drivers/gpio/gpio-twl6040.c
@@ -111,7 +111,8 @@ static int gpo_twl6040_probe(struct platform_device *pdev)
static int gpo_twl6040_remove(struct platform_device *pdev)
{
- return gpiochip_remove(&twl6040gpo_chip);
+ gpiochip_remove(&twl6040gpo_chip);
+ return 0;
}
/* Note: this hardware lives inside an I2C-based multi-function device. */
diff --git a/drivers/gpio/gpio-ucb1400.c b/drivers/gpio/gpio-ucb1400.c
index 2445fe771179..d502825159b9 100644
--- a/drivers/gpio/gpio-ucb1400.c
+++ b/drivers/gpio/gpio-ucb1400.c
@@ -70,7 +70,7 @@ static int ucb1400_gpio_probe(struct platform_device *dev)
if (err)
goto err;
- if (ucb && ucb->gpio_setup)
+ if (ucb->gpio_setup)
err = ucb->gpio_setup(&dev->dev, ucb->gc.ngpio);
err:
@@ -89,7 +89,7 @@ static int ucb1400_gpio_remove(struct platform_device *dev)
return err;
}
- err = gpiochip_remove(&ucb->gc);
+ gpiochip_remove(&ucb->gc);
return err;
}
diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c
index 79e3b5836712..e2a11f27807f 100644
--- a/drivers/gpio/gpio-viperboard.c
+++ b/drivers/gpio/gpio-viperboard.c
@@ -446,8 +446,7 @@ static int vprbrd_gpio_probe(struct platform_device *pdev)
return ret;
err_gpiob:
- if (gpiochip_remove(&vb_gpio->gpioa))
- dev_err(&pdev->dev, "%s gpiochip_remove failed\n", __func__);
+ gpiochip_remove(&vb_gpio->gpioa);
err_gpioa:
return ret;
@@ -456,13 +455,10 @@ err_gpioa:
static int vprbrd_gpio_remove(struct platform_device *pdev)
{
struct vprbrd_gpio *vb_gpio = platform_get_drvdata(pdev);
- int ret;
- ret = gpiochip_remove(&vb_gpio->gpiob);
- if (ret == 0)
- ret = gpiochip_remove(&vb_gpio->gpioa);
+ gpiochip_remove(&vb_gpio->gpiob);
- return ret;
+ return 0;
}
static struct platform_driver vprbrd_gpio_driver = {
diff --git a/drivers/gpio/gpio-vr41xx.c b/drivers/gpio/gpio-vr41xx.c
index 66cbcc108e62..dbf28fa03f67 100644
--- a/drivers/gpio/gpio-vr41xx.c
+++ b/drivers/gpio/gpio-vr41xx.c
@@ -515,7 +515,7 @@ static int giu_probe(struct platform_device *pdev)
struct resource *res;
unsigned int trigger, i, pin;
struct irq_chip *chip;
- int irq, retval;
+ int irq, ret;
switch (pdev->id) {
case GPIO_50PINS_PULLUPDOWN:
@@ -544,7 +544,11 @@ static int giu_probe(struct platform_device *pdev)
vr41xx_gpio_chip.dev = &pdev->dev;
- retval = gpiochip_add(&vr41xx_gpio_chip);
+ ret = gpiochip_add(&vr41xx_gpio_chip);
+ if (!ret) {
+ iounmap(giu_base);
+ return -ENODEV;
+ }
giu_write(GIUINTENL, 0);
giu_write(GIUINTENH, 0);
diff --git a/drivers/gpio/gpio-vx855.c b/drivers/gpio/gpio-vx855.c
index 0fd23b6a753d..85971d4e23c1 100644
--- a/drivers/gpio/gpio-vx855.c
+++ b/drivers/gpio/gpio-vx855.c
@@ -288,8 +288,7 @@ static int vx855gpio_remove(struct platform_device *pdev)
struct vx855_gpio *vg = platform_get_drvdata(pdev);
struct resource *res;
- if (gpiochip_remove(&vg->gpio))
- dev_err(&pdev->dev, "unable to remove gpio_chip?\n");
+ gpiochip_remove(&vg->gpio);
if (vg->gpi_reserved) {
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c
index b18a1a26425e..58ce75c188b7 100644
--- a/drivers/gpio/gpio-wm831x.c
+++ b/drivers/gpio/gpio-wm831x.c
@@ -279,7 +279,8 @@ static int wm831x_gpio_remove(struct platform_device *pdev)
{
struct wm831x_gpio *wm831x_gpio = platform_get_drvdata(pdev);
- return gpiochip_remove(&wm831x_gpio->gpio_chip);
+ gpiochip_remove(&wm831x_gpio->gpio_chip);
+ return 0;
}
static struct platform_driver wm831x_gpio_driver = {
diff --git a/drivers/gpio/gpio-wm8350.c b/drivers/gpio/gpio-wm8350.c
index 2487f9d575d3..060b89303bb6 100644
--- a/drivers/gpio/gpio-wm8350.c
+++ b/drivers/gpio/gpio-wm8350.c
@@ -145,7 +145,8 @@ static int wm8350_gpio_remove(struct platform_device *pdev)
{
struct wm8350_gpio_data *wm8350_gpio = platform_get_drvdata(pdev);
- return gpiochip_remove(&wm8350_gpio->gpio_chip);
+ gpiochip_remove(&wm8350_gpio->gpio_chip);
+ return 0;
}
static struct platform_driver wm8350_gpio_driver = {
diff --git a/drivers/gpio/gpio-wm8994.c b/drivers/gpio/gpio-wm8994.c
index d93b6b581677..6f5e42db4b9e 100644
--- a/drivers/gpio/gpio-wm8994.c
+++ b/drivers/gpio/gpio-wm8994.c
@@ -285,7 +285,8 @@ static int wm8994_gpio_remove(struct platform_device *pdev)
{
struct wm8994_gpio *wm8994_gpio = platform_get_drvdata(pdev);
- return gpiochip_remove(&wm8994_gpio->gpio_chip);
+ gpiochip_remove(&wm8994_gpio->gpio_chip);
+ return 0;
}
static struct platform_driver wm8994_gpio_driver = {
diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c
index 792a05ad4649..12481867daf1 100644
--- a/drivers/gpio/gpio-xilinx.c
+++ b/drivers/gpio/gpio-xilinx.c
@@ -289,7 +289,7 @@ static int xgpio_of_probe(struct device_node *np)
return 0;
}
-static struct of_device_id xgpio_of_match[] = {
+static const struct of_device_id xgpio_of_match[] = {
{ .compatible = "xlnx,xps-gpio-1.00.a", },
{ /* end of list */ },
};
diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c
index 9bf5034b6cdb..54e54e4cc6c4 100644
--- a/drivers/gpio/gpio-zevio.c
+++ b/drivers/gpio/gpio-zevio.c
@@ -81,9 +81,15 @@ static inline void zevio_gpio_port_set(struct zevio_gpio *c, unsigned pin,
static int zevio_gpio_get(struct gpio_chip *chip, unsigned pin)
{
struct zevio_gpio *controller = to_zevio_gpio(chip);
+ u32 val, dir;
- /* Only reading allowed, so no spinlock needed */
- u32 val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_INPUT);
+ spin_lock(&controller->lock);
+ dir = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION);
+ if (dir & BIT(ZEVIO_GPIO_BIT(pin)))
+ val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_INPUT);
+ else
+ val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT);
+ spin_unlock(&controller->lock);
return (val >> ZEVIO_GPIO_BIT(pin)) & 0x1;
}
@@ -172,10 +178,8 @@ static int zevio_gpio_probe(struct platform_device *pdev)
int status, i;
controller = devm_kzalloc(&pdev->dev, sizeof(*controller), GFP_KERNEL);
- if (!controller) {
- dev_err(&pdev->dev, "not enough free memory\n");
+ if (!controller)
return -ENOMEM;
- }
/* Copy our reference */
controller->chip.gc = zevio_gpio_chip;
@@ -198,7 +202,7 @@ static int zevio_gpio_probe(struct platform_device *pdev)
return 0;
}
-static struct of_device_id zevio_gpio_of_match[] = {
+static const struct of_device_id zevio_gpio_of_match[] = {
{ .compatible = "lsi,zevio-gpio", },
{ },
};
@@ -209,7 +213,7 @@ static struct platform_driver zevio_gpio_driver = {
.driver = {
.name = "gpio-zevio",
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(zevio_gpio_of_match),
+ .of_match_table = zevio_gpio_of_match,
},
.probe = zevio_gpio_probe,
};
diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c
new file mode 100644
index 000000000000..c3145f91fda3
--- /dev/null
+++ b/drivers/gpio/gpio-zynq.c
@@ -0,0 +1,692 @@
+/*
+ * Xilinx Zynq GPIO device driver
+ *
+ * Copyright (C) 2009 - 2014 Xilinx, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/gpio/driver.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#define DRIVER_NAME "zynq-gpio"
+
+/* Maximum banks */
+#define ZYNQ_GPIO_MAX_BANK 4
+
+#define ZYNQ_GPIO_BANK0_NGPIO 32
+#define ZYNQ_GPIO_BANK1_NGPIO 22
+#define ZYNQ_GPIO_BANK2_NGPIO 32
+#define ZYNQ_GPIO_BANK3_NGPIO 32
+
+#define ZYNQ_GPIO_NR_GPIOS (ZYNQ_GPIO_BANK0_NGPIO + \
+ ZYNQ_GPIO_BANK1_NGPIO + \
+ ZYNQ_GPIO_BANK2_NGPIO + \
+ ZYNQ_GPIO_BANK3_NGPIO)
+
+#define ZYNQ_GPIO_BANK0_PIN_MIN 0
+#define ZYNQ_GPIO_BANK0_PIN_MAX (ZYNQ_GPIO_BANK0_PIN_MIN + \
+ ZYNQ_GPIO_BANK0_NGPIO - 1)
+#define ZYNQ_GPIO_BANK1_PIN_MIN (ZYNQ_GPIO_BANK0_PIN_MAX + 1)
+#define ZYNQ_GPIO_BANK1_PIN_MAX (ZYNQ_GPIO_BANK1_PIN_MIN + \
+ ZYNQ_GPIO_BANK1_NGPIO - 1)
+#define ZYNQ_GPIO_BANK2_PIN_MIN (ZYNQ_GPIO_BANK1_PIN_MAX + 1)
+#define ZYNQ_GPIO_BANK2_PIN_MAX (ZYNQ_GPIO_BANK2_PIN_MIN + \
+ ZYNQ_GPIO_BANK2_NGPIO - 1)
+#define ZYNQ_GPIO_BANK3_PIN_MIN (ZYNQ_GPIO_BANK2_PIN_MAX + 1)
+#define ZYNQ_GPIO_BANK3_PIN_MAX (ZYNQ_GPIO_BANK3_PIN_MIN + \
+ ZYNQ_GPIO_BANK3_NGPIO - 1)
+
+
+/* Register offsets for the GPIO device */
+/* LSW Mask & Data -WO */
+#define ZYNQ_GPIO_DATA_LSW_OFFSET(BANK) (0x000 + (8 * BANK))
+/* MSW Mask & Data -WO */
+#define ZYNQ_GPIO_DATA_MSW_OFFSET(BANK) (0x004 + (8 * BANK))
+/* Data Register-RW */
+#define ZYNQ_GPIO_DATA_RO_OFFSET(BANK) (0x060 + (4 * BANK))
+/* Direction mode reg-RW */
+#define ZYNQ_GPIO_DIRM_OFFSET(BANK) (0x204 + (0x40 * BANK))
+/* Output enable reg-RW */
+#define ZYNQ_GPIO_OUTEN_OFFSET(BANK) (0x208 + (0x40 * BANK))
+/* Interrupt mask reg-RO */
+#define ZYNQ_GPIO_INTMASK_OFFSET(BANK) (0x20C + (0x40 * BANK))
+/* Interrupt enable reg-WO */
+#define ZYNQ_GPIO_INTEN_OFFSET(BANK) (0x210 + (0x40 * BANK))
+/* Interrupt disable reg-WO */
+#define ZYNQ_GPIO_INTDIS_OFFSET(BANK) (0x214 + (0x40 * BANK))
+/* Interrupt status reg-RO */
+#define ZYNQ_GPIO_INTSTS_OFFSET(BANK) (0x218 + (0x40 * BANK))
+/* Interrupt type reg-RW */
+#define ZYNQ_GPIO_INTTYPE_OFFSET(BANK) (0x21C + (0x40 * BANK))
+/* Interrupt polarity reg-RW */
+#define ZYNQ_GPIO_INTPOL_OFFSET(BANK) (0x220 + (0x40 * BANK))
+/* Interrupt on any, reg-RW */
+#define ZYNQ_GPIO_INTANY_OFFSET(BANK) (0x224 + (0x40 * BANK))
+
+/* Disable all interrupts mask */
+#define ZYNQ_GPIO_IXR_DISABLE_ALL 0xFFFFFFFF
+
+/* Mid pin number of a bank */
+#define ZYNQ_GPIO_MID_PIN_NUM 16
+
+/* GPIO upper 16 bit mask */
+#define ZYNQ_GPIO_UPPER_MASK 0xFFFF0000
+
+/**
+ * struct zynq_gpio - gpio device private data structure
+ * @chip: instance of the gpio_chip
+ * @base_addr: base address of the GPIO device
+ * @clk: clock resource for this controller
+ */
+struct zynq_gpio {
+ struct gpio_chip chip;
+ void __iomem *base_addr;
+ struct clk *clk;
+};
+
+/**
+ * zynq_gpio_get_bank_pin - Get the bank number and pin number within that bank
+ * for a given pin in the GPIO device
+ * @pin_num: gpio pin number within the device
+ * @bank_num: an output parameter used to return the bank number of the gpio
+ * pin
+ * @bank_pin_num: an output parameter used to return pin number within a bank
+ * for the given gpio pin
+ *
+ * Returns the bank number and pin offset within the bank.
+ */
+static inline void zynq_gpio_get_bank_pin(unsigned int pin_num,
+ unsigned int *bank_num,
+ unsigned int *bank_pin_num)
+{
+ switch (pin_num) {
+ case ZYNQ_GPIO_BANK0_PIN_MIN ... ZYNQ_GPIO_BANK0_PIN_MAX:
+ *bank_num = 0;
+ *bank_pin_num = pin_num;
+ break;
+ case ZYNQ_GPIO_BANK1_PIN_MIN ... ZYNQ_GPIO_BANK1_PIN_MAX:
+ *bank_num = 1;
+ *bank_pin_num = pin_num - ZYNQ_GPIO_BANK1_PIN_MIN;
+ break;
+ case ZYNQ_GPIO_BANK2_PIN_MIN ... ZYNQ_GPIO_BANK2_PIN_MAX:
+ *bank_num = 2;
+ *bank_pin_num = pin_num - ZYNQ_GPIO_BANK2_PIN_MIN;
+ break;
+ case ZYNQ_GPIO_BANK3_PIN_MIN ... ZYNQ_GPIO_BANK3_PIN_MAX:
+ *bank_num = 3;
+ *bank_pin_num = pin_num - ZYNQ_GPIO_BANK3_PIN_MIN;
+ break;
+ default:
+ WARN(true, "invalid GPIO pin number: %u", pin_num);
+ *bank_num = 0;
+ *bank_pin_num = 0;
+ break;
+ }
+}
+
+/**
+ * zynq_gpio_get_value - Get the state of the specified pin of GPIO device
+ * @chip: gpio_chip instance to be worked on
+ * @pin: gpio pin number within the device
+ *
+ * This function reads the state of the specified pin of the GPIO device.
+ *
+ * Return: 0 if the pin is low, 1 if pin is high.
+ */
+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);
+
+ zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num);
+
+ data = readl_relaxed(gpio->base_addr +
+ ZYNQ_GPIO_DATA_RO_OFFSET(bank_num));
+
+ return (data >> bank_pin_num) & 1;
+}
+
+/**
+ * zynq_gpio_set_value - Modify the state of the pin with specified value
+ * @chip: gpio_chip instance to be worked on
+ * @pin: gpio pin number within the device
+ * @state: value used to modify the state of the specified pin
+ *
+ * This function calculates the register offset (i.e to lower 16 bits or
+ * upper 16 bits) based on the given pin number and sets the state of a
+ * gpio pin to the specified value. The state is either 0 or non-zero.
+ */
+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);
+
+ zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num);
+
+ if (bank_pin_num >= ZYNQ_GPIO_MID_PIN_NUM) {
+ /* only 16 data bits in bit maskable reg */
+ bank_pin_num -= ZYNQ_GPIO_MID_PIN_NUM;
+ reg_offset = ZYNQ_GPIO_DATA_MSW_OFFSET(bank_num);
+ } else {
+ reg_offset = ZYNQ_GPIO_DATA_LSW_OFFSET(bank_num);
+ }
+
+ /*
+ * get the 32 bit value to be written to the mask/data register where
+ * the upper 16 bits is the mask and lower 16 bits is the data
+ */
+ state = !!state;
+ state = ~(1 << (bank_pin_num + ZYNQ_GPIO_MID_PIN_NUM)) &
+ ((state << bank_pin_num) | ZYNQ_GPIO_UPPER_MASK);
+
+ writel_relaxed(state, gpio->base_addr + reg_offset);
+}
+
+/**
+ * zynq_gpio_dir_in - Set the direction of the specified GPIO pin as input
+ * @chip: gpio_chip instance to be worked on
+ * @pin: gpio pin number within the device
+ *
+ * This function uses the read-modify-write sequence to set the direction of
+ * the gpio pin as input.
+ *
+ * Return: 0 always
+ */
+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);
+
+ zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num);
+
+ /* bank 0 pins 7 and 8 are special and cannot be used as inputs */
+ if (bank_num == 0 && (bank_pin_num == 7 || bank_pin_num == 8))
+ return -EINVAL;
+
+ /* clear the bit in direction mode reg to set the pin as input */
+ reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
+ reg &= ~BIT(bank_pin_num);
+ writel_relaxed(reg, gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
+
+ return 0;
+}
+
+/**
+ * zynq_gpio_dir_out - Set the direction of the specified GPIO pin as output
+ * @chip: gpio_chip instance to be worked on
+ * @pin: gpio pin number within the device
+ * @state: value to be written to specified pin
+ *
+ * This function sets the direction of specified GPIO pin as output, configures
+ * the Output Enable register for the pin and uses zynq_gpio_set to set
+ * the state of the pin to the value specified.
+ *
+ * Return: 0 always
+ */
+static int zynq_gpio_dir_out(struct gpio_chip *chip, unsigned int pin,
+ int state)
+{
+ u32 reg;
+ unsigned int bank_num, bank_pin_num;
+ struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
+
+ zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num);
+
+ /* set the GPIO pin as output */
+ reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
+ reg |= BIT(bank_pin_num);
+ writel_relaxed(reg, gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
+
+ /* configure the output enable reg for the pin */
+ reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_OUTEN_OFFSET(bank_num));
+ reg |= BIT(bank_pin_num);
+ writel_relaxed(reg, gpio->base_addr + ZYNQ_GPIO_OUTEN_OFFSET(bank_num));
+
+ /* set the state of the pin */
+ zynq_gpio_set_value(chip, pin, state);
+ return 0;
+}
+
+/**
+ * zynq_gpio_irq_mask - Disable the interrupts for a gpio pin
+ * @irq_data: per irq and chip data passed down to chip functions
+ *
+ * This function calculates gpio pin number from irq number and sets the
+ * bit in the Interrupt Disable register of the corresponding bank to disable
+ * interrupts for that 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);
+
+ device_pin_num = irq_data->hwirq;
+ zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num);
+ writel_relaxed(BIT(bank_pin_num),
+ gpio->base_addr + ZYNQ_GPIO_INTDIS_OFFSET(bank_num));
+}
+
+/**
+ * zynq_gpio_irq_unmask - Enable the interrupts for a gpio pin
+ * @irq_data: irq data containing irq number of gpio pin for the interrupt
+ * to enable
+ *
+ * This function calculates the gpio pin number from irq number and sets the
+ * bit in the Interrupt Enable register of the corresponding bank to enable
+ * interrupts for that pin.
+ */
+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);
+
+ device_pin_num = irq_data->hwirq;
+ zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num);
+ writel_relaxed(BIT(bank_pin_num),
+ gpio->base_addr + ZYNQ_GPIO_INTEN_OFFSET(bank_num));
+}
+
+/**
+ * zynq_gpio_irq_ack - Acknowledge the interrupt of a gpio pin
+ * @irq_data: irq data containing irq number of gpio pin for the interrupt
+ * to ack
+ *
+ * This function calculates gpio pin number from irq number and sets the bit
+ * in the Interrupt Status Register of the corresponding bank, to ACK the irq.
+ */
+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);
+
+ device_pin_num = irq_data->hwirq;
+ zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num);
+ writel_relaxed(BIT(bank_pin_num),
+ gpio->base_addr + ZYNQ_GPIO_INTSTS_OFFSET(bank_num));
+}
+
+/**
+ * zynq_gpio_irq_enable - Enable the interrupts for a gpio pin
+ * @irq_data: irq data containing irq number of gpio pin for the interrupt
+ * to enable
+ *
+ * Clears the INTSTS bit and unmasks the given interrrupt.
+ */
+static void zynq_gpio_irq_enable(struct irq_data *irq_data)
+{
+ /*
+ * The Zynq GPIO controller does not disable interrupt detection when
+ * the interrupt is masked and only disables the propagation of the
+ * interrupt. This means when the controller detects an interrupt
+ * condition while the interrupt is logically disabled it will propagate
+ * that interrupt event once the interrupt is enabled. This will cause
+ * the interrupt consumer to see spurious interrupts to prevent this
+ * first make sure that the interrupt is not asserted and then enable
+ * it.
+ */
+ zynq_gpio_irq_ack(irq_data);
+ zynq_gpio_irq_unmask(irq_data);
+}
+
+/**
+ * zynq_gpio_set_irq_type - Set the irq type for a gpio pin
+ * @irq_data: irq data containing irq number of gpio pin
+ * @type: interrupt type that is to be set for the gpio pin
+ *
+ * This function gets the gpio pin number and its bank from the gpio pin number
+ * and configures the INT_TYPE, INT_POLARITY and INT_ANY registers.
+ *
+ * Return: 0, negative error otherwise.
+ * TYPE-EDGE_RISING, INT_TYPE - 1, INT_POLARITY - 1, INT_ANY - 0;
+ * TYPE-EDGE_FALLING, INT_TYPE - 1, INT_POLARITY - 0, INT_ANY - 0;
+ * TYPE-EDGE_BOTH, INT_TYPE - 1, INT_POLARITY - NA, INT_ANY - 1;
+ * TYPE-LEVEL_HIGH, INT_TYPE - 0, INT_POLARITY - 1, INT_ANY - NA;
+ * TYPE-LEVEL_LOW, INT_TYPE - 0, INT_POLARITY - 0, INT_ANY - NA
+ */
+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);
+
+ device_pin_num = irq_data->hwirq;
+ zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num);
+
+ int_type = readl_relaxed(gpio->base_addr +
+ ZYNQ_GPIO_INTTYPE_OFFSET(bank_num));
+ int_pol = readl_relaxed(gpio->base_addr +
+ ZYNQ_GPIO_INTPOL_OFFSET(bank_num));
+ int_any = readl_relaxed(gpio->base_addr +
+ ZYNQ_GPIO_INTANY_OFFSET(bank_num));
+
+ /*
+ * based on the type requested, configure the INT_TYPE, INT_POLARITY
+ * and INT_ANY registers
+ */
+ switch (type) {
+ case IRQ_TYPE_EDGE_RISING:
+ int_type |= BIT(bank_pin_num);
+ int_pol |= BIT(bank_pin_num);
+ int_any &= ~BIT(bank_pin_num);
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ int_type |= BIT(bank_pin_num);
+ int_pol &= ~BIT(bank_pin_num);
+ int_any &= ~BIT(bank_pin_num);
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ int_type |= BIT(bank_pin_num);
+ int_any |= BIT(bank_pin_num);
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ int_type &= ~BIT(bank_pin_num);
+ int_pol |= BIT(bank_pin_num);
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ int_type &= ~BIT(bank_pin_num);
+ int_pol &= ~BIT(bank_pin_num);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ writel_relaxed(int_type,
+ gpio->base_addr + ZYNQ_GPIO_INTTYPE_OFFSET(bank_num));
+ writel_relaxed(int_pol,
+ gpio->base_addr + ZYNQ_GPIO_INTPOL_OFFSET(bank_num));
+ writel_relaxed(int_any,
+ gpio->base_addr + ZYNQ_GPIO_INTANY_OFFSET(bank_num));
+ return 0;
+}
+
+static int zynq_gpio_set_wake(struct irq_data *data, unsigned int on)
+{
+ if (on)
+ zynq_gpio_irq_unmask(data);
+ else
+ zynq_gpio_irq_mask(data);
+
+ return 0;
+}
+
+/* irq chip descriptor */
+static struct irq_chip zynq_gpio_irqchip = {
+ .name = DRIVER_NAME,
+ .irq_enable = zynq_gpio_irq_enable,
+ .irq_mask = zynq_gpio_irq_mask,
+ .irq_unmask = zynq_gpio_irq_unmask,
+ .irq_set_type = zynq_gpio_set_irq_type,
+ .irq_set_wake = zynq_gpio_set_wake,
+};
+
+/**
+ * zynq_gpio_irqhandler - IRQ handler for the gpio banks of a gpio device
+ * @irq: irq number of the gpio bank where interrupt has occurred
+ * @desc: irq descriptor instance of the 'irq'
+ *
+ * This function reads the Interrupt Status Register of each bank to get the
+ * gpio pin number which has triggered an interrupt. It then acks the triggered
+ * interrupt and calls the pin specific handler set by the higher layer
+ * application for that pin.
+ * Note: A bug is reported if no handler is set for the gpio pin.
+ */
+static void zynq_gpio_irqhandler(unsigned int irq, struct irq_desc *desc)
+{
+ u32 int_sts, int_enb;
+ unsigned int bank_num;
+ struct zynq_gpio *gpio = irq_get_handler_data(irq);
+ struct irq_chip *irqchip = irq_desc_get_chip(desc);
+
+ chained_irq_enter(irqchip, desc);
+
+ for (bank_num = 0; bank_num < ZYNQ_GPIO_MAX_BANK; bank_num++) {
+ int_sts = readl_relaxed(gpio->base_addr +
+ ZYNQ_GPIO_INTSTS_OFFSET(bank_num));
+ int_enb = readl_relaxed(gpio->base_addr +
+ ZYNQ_GPIO_INTMASK_OFFSET(bank_num));
+ int_sts &= ~int_enb;
+ if (int_sts) {
+ int offset;
+ unsigned long pending = int_sts;
+
+ for_each_set_bit(offset, &pending, 32) {
+ unsigned int gpio_irq =
+ irq_find_mapping(gpio->chip.irqdomain,
+ offset);
+ generic_handle_irq(gpio_irq);
+ }
+
+ /* clear IRQ in HW */
+ writel_relaxed(int_sts, gpio->base_addr +
+ ZYNQ_GPIO_INTSTS_OFFSET(bank_num));
+ }
+ }
+
+ chained_irq_exit(irqchip, desc);
+}
+
+static int __maybe_unused zynq_gpio_suspend(struct device *dev)
+{
+ if (!device_may_wakeup(dev))
+ return pm_runtime_force_suspend(dev);
+
+ return 0;
+}
+
+static int __maybe_unused zynq_gpio_resume(struct device *dev)
+{
+ if (!device_may_wakeup(dev))
+ return pm_runtime_force_resume(dev);
+
+ return 0;
+}
+
+static int __maybe_unused zynq_gpio_runtime_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct zynq_gpio *gpio = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(gpio->clk);
+
+ return 0;
+}
+
+static int __maybe_unused zynq_gpio_runtime_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct zynq_gpio *gpio = platform_get_drvdata(pdev);
+
+ return clk_prepare_enable(gpio->clk);
+}
+
+static int zynq_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ int ret;
+
+ ret = pm_runtime_get_sync(chip->dev);
+
+ /*
+ * If the device is already active pm_runtime_get() will return 1 on
+ * success, but gpio_request still needs to return 0.
+ */
+ return ret < 0 ? ret : 0;
+}
+
+static void zynq_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ pm_runtime_put(chip->dev);
+}
+
+static const struct dev_pm_ops zynq_gpio_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(zynq_gpio_suspend, zynq_gpio_resume)
+ SET_PM_RUNTIME_PM_OPS(zynq_gpio_runtime_suspend,
+ zynq_gpio_runtime_resume, NULL)
+};
+
+/**
+ * zynq_gpio_probe - Initialization method for a zynq_gpio device
+ * @pdev: platform device instance
+ *
+ * This function allocates memory resources for the gpio device and registers
+ * all the banks of the device. It will also set up interrupts for the gpio
+ * pins.
+ * Note: Interrupts are disabled for all the banks during initialization.
+ *
+ * Return: 0 on success, negative error otherwise.
+ */
+static int zynq_gpio_probe(struct platform_device *pdev)
+{
+ int ret, bank_num, irq;
+ struct zynq_gpio *gpio;
+ struct gpio_chip *chip;
+ struct resource *res;
+
+ gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
+ if (!gpio)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, gpio);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ gpio->base_addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(gpio->base_addr))
+ return PTR_ERR(gpio->base_addr);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "invalid IRQ\n");
+ return irq;
+ }
+
+ /* configure the gpio chip */
+ chip = &gpio->chip;
+ chip->label = "zynq_gpio";
+ chip->owner = THIS_MODULE;
+ chip->dev = &pdev->dev;
+ chip->get = zynq_gpio_get_value;
+ chip->set = zynq_gpio_set_value;
+ chip->request = zynq_gpio_request;
+ chip->free = zynq_gpio_free;
+ chip->direction_input = zynq_gpio_dir_in;
+ chip->direction_output = zynq_gpio_dir_out;
+ chip->base = -1;
+ chip->ngpio = ZYNQ_GPIO_NR_GPIOS;
+
+ /* Enable GPIO clock */
+ gpio->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(gpio->clk)) {
+ dev_err(&pdev->dev, "input clock not found.\n");
+ return PTR_ERR(gpio->clk);
+ }
+ ret = clk_prepare_enable(gpio->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to enable clock.\n");
+ return ret;
+ }
+
+ /* report a bug if gpio chip registration fails */
+ ret = gpiochip_add(chip);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to add gpio chip\n");
+ goto err_disable_clk;
+ }
+
+ /* disable interrupts for all banks */
+ for (bank_num = 0; bank_num < ZYNQ_GPIO_MAX_BANK; bank_num++)
+ writel_relaxed(ZYNQ_GPIO_IXR_DISABLE_ALL, gpio->base_addr +
+ ZYNQ_GPIO_INTDIS_OFFSET(bank_num));
+
+ ret = gpiochip_irqchip_add(chip, &zynq_gpio_irqchip, 0,
+ handle_simple_irq, IRQ_TYPE_NONE);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to add irq chip\n");
+ goto err_rm_gpiochip;
+ }
+
+ gpiochip_set_chained_irqchip(chip, &zynq_gpio_irqchip, irq,
+ zynq_gpio_irqhandler);
+
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
+ device_set_wakeup_capable(&pdev->dev, 1);
+
+ return 0;
+
+err_rm_gpiochip:
+ if (gpiochip_remove(chip))
+ dev_err(&pdev->dev, "Failed to remove gpio chip\n");
+err_disable_clk:
+ clk_disable_unprepare(gpio->clk);
+
+ return ret;
+}
+
+/**
+ * zynq_gpio_remove - Driver removal function
+ * @pdev: platform device instance
+ *
+ * Return: 0 always
+ */
+static int zynq_gpio_remove(struct platform_device *pdev)
+{
+ int ret;
+ struct zynq_gpio *gpio = platform_get_drvdata(pdev);
+
+ pm_runtime_get_sync(&pdev->dev);
+
+ ret = gpiochip_remove(&gpio->chip);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to remove gpio chip\n");
+ return ret;
+ }
+ clk_disable_unprepare(gpio->clk);
+ device_set_wakeup_capable(&pdev->dev, 0);
+ return 0;
+}
+
+static struct of_device_id zynq_gpio_of_match[] = {
+ { .compatible = "xlnx,zynq-gpio-1.0", },
+ { /* end of table */ }
+};
+MODULE_DEVICE_TABLE(of, zynq_gpio_of_match);
+
+static struct platform_driver zynq_gpio_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .pm = &zynq_gpio_dev_pm_ops,
+ .of_match_table = zynq_gpio_of_match,
+ },
+ .probe = zynq_gpio_probe,
+ .remove = zynq_gpio_remove,
+};
+
+/**
+ * zynq_gpio_init - Initial driver registration call
+ *
+ * Return: value from platform_driver_register
+ */
+static int __init zynq_gpio_init(void)
+{
+ return platform_driver_register(&zynq_gpio_driver);
+}
+postcore_initcall(zynq_gpio_init);
+
+MODULE_AUTHOR("Xilinx Inc.");
+MODULE_DESCRIPTION("Zynq GPIO driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index 401add28933f..d62eaaa75397 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -157,7 +157,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
gpiod_direction_input(desc);
- ret = gpiod_lock_as_irq(desc);
+ ret = gpio_lock_as_irq(chip, pin);
if (ret) {
dev_err(chip->dev, "Failed to lock GPIO as interrupt\n");
goto fail_free_desc;
@@ -212,7 +212,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
fail_free_event:
kfree(event);
fail_unlock_irq:
- gpiod_unlock_as_irq(desc);
+ gpio_unlock_as_irq(chip, pin);
fail_free_desc:
gpiochip_free_own_desc(desc);
@@ -221,7 +221,7 @@ fail_free_desc:
/**
* acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events
- * @acpi_gpio: ACPI GPIO chip
+ * @chip: GPIO chip
*
* ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are
* handled by ACPI event methods which need to be called from the GPIO
@@ -229,11 +229,21 @@ fail_free_desc:
* gpio pins have acpi event methods and assigns interrupt handlers that calls
* the acpi event methods for those pins.
*/
-static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio)
+void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
{
- struct gpio_chip *chip = acpi_gpio->chip;
+ struct acpi_gpio_chip *acpi_gpio;
+ acpi_handle handle;
+ acpi_status status;
+
+ if (!chip->dev || !chip->to_irq)
+ return;
- if (!chip->to_irq)
+ handle = ACPI_HANDLE(chip->dev);
+ if (!handle)
+ return;
+
+ status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio);
+ if (ACPI_FAILURE(status))
return;
INIT_LIST_HEAD(&acpi_gpio->events);
@@ -243,17 +253,27 @@ static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio)
/**
* acpi_gpiochip_free_interrupts() - Free GPIO ACPI event interrupts.
- * @acpi_gpio: ACPI GPIO chip
+ * @chip: GPIO chip
*
* Free interrupts associated with GPIO ACPI event method for the given
* GPIO chip.
*/
-static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio)
+void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
{
+ struct acpi_gpio_chip *acpi_gpio;
struct acpi_gpio_event *event, *ep;
- struct gpio_chip *chip = acpi_gpio->chip;
+ acpi_handle handle;
+ acpi_status status;
+
+ if (!chip->dev || !chip->to_irq)
+ return;
- if (!chip->to_irq)
+ handle = ACPI_HANDLE(chip->dev);
+ if (!handle)
+ return;
+
+ status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio);
+ if (ACPI_FAILURE(status))
return;
list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) {
@@ -263,7 +283,7 @@ static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio)
desc = gpiochip_get_desc(chip, event->pin);
if (WARN_ON(IS_ERR(desc)))
continue;
- gpiod_unlock_as_irq(desc);
+ gpio_unlock_as_irq(chip, event->pin);
gpiochip_free_own_desc(desc);
list_del(&event->node);
kfree(event);
@@ -449,9 +469,10 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
mutex_unlock(&achip->conn_lock);
if (function == ACPI_WRITE)
- gpiod_set_raw_value(desc, !!((1 << i) & *value));
+ gpiod_set_raw_value_cansleep(desc,
+ !!((1 << i) & *value));
else
- *value |= (u64)gpiod_get_raw_value(desc) << i;
+ *value |= (u64)gpiod_get_raw_value_cansleep(desc) << i;
}
out:
@@ -524,7 +545,6 @@ void acpi_gpiochip_add(struct gpio_chip *chip)
return;
}
- acpi_gpiochip_request_interrupts(acpi_gpio);
acpi_gpiochip_request_regions(acpi_gpio);
}
@@ -548,7 +568,6 @@ void acpi_gpiochip_remove(struct gpio_chip *chip)
}
acpi_gpiochip_free_regions(acpi_gpio);
- acpi_gpiochip_free_interrupts(acpi_gpio);
acpi_detach_data(handle, acpi_gpio_chip_dh);
kfree(acpi_gpio);
diff --git a/drivers/gpio/gpiolib-legacy.c b/drivers/gpio/gpiolib-legacy.c
new file mode 100644
index 000000000000..078ae6c2df79
--- /dev/null
+++ b/drivers/gpio/gpiolib-legacy.c
@@ -0,0 +1,102 @@
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+
+#include <linux/gpio.h>
+
+#include "gpiolib.h"
+
+void gpio_free(unsigned gpio)
+{
+ gpiod_free(gpio_to_desc(gpio));
+}
+EXPORT_SYMBOL_GPL(gpio_free);
+
+/**
+ * gpio_request_one - request a single GPIO with initial configuration
+ * @gpio: the GPIO number
+ * @flags: GPIO configuration as specified by GPIOF_*
+ * @label: a literal description string of this GPIO
+ */
+int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
+{
+ struct gpio_desc *desc;
+ int err;
+
+ desc = gpio_to_desc(gpio);
+
+ err = gpiod_request(desc, label);
+ if (err)
+ return err;
+
+ if (flags & GPIOF_OPEN_DRAIN)
+ set_bit(FLAG_OPEN_DRAIN, &desc->flags);
+
+ if (flags & GPIOF_OPEN_SOURCE)
+ set_bit(FLAG_OPEN_SOURCE, &desc->flags);
+
+ if (flags & GPIOF_ACTIVE_LOW)
+ set_bit(FLAG_ACTIVE_LOW, &desc->flags);
+
+ if (flags & GPIOF_DIR_IN)
+ err = gpiod_direction_input(desc);
+ else
+ err = gpiod_direction_output_raw(desc,
+ (flags & GPIOF_INIT_HIGH) ? 1 : 0);
+
+ if (err)
+ goto free_gpio;
+
+ if (flags & GPIOF_EXPORT) {
+ err = gpiod_export(desc, flags & GPIOF_EXPORT_CHANGEABLE);
+ if (err)
+ goto free_gpio;
+ }
+
+ return 0;
+
+ free_gpio:
+ gpiod_free(desc);
+ return err;
+}
+EXPORT_SYMBOL_GPL(gpio_request_one);
+
+int gpio_request(unsigned gpio, const char *label)
+{
+ return gpiod_request(gpio_to_desc(gpio), label);
+}
+EXPORT_SYMBOL_GPL(gpio_request);
+
+/**
+ * gpio_request_array - request multiple GPIOs in a single call
+ * @array: array of the 'struct gpio'
+ * @num: how many GPIOs in the array
+ */
+int gpio_request_array(const struct gpio *array, size_t num)
+{
+ int i, err;
+
+ for (i = 0; i < num; i++, array++) {
+ err = gpio_request_one(array->gpio, array->flags, array->label);
+ if (err)
+ goto err_free;
+ }
+ return 0;
+
+err_free:
+ while (i--)
+ gpio_free((--array)->gpio);
+ return err;
+}
+EXPORT_SYMBOL_GPL(gpio_request_array);
+
+/**
+ * gpio_free_array - release multiple GPIOs in a single call
+ * @array: array of the 'struct gpio'
+ * @num: how many GPIOs in the array
+ */
+void gpio_free_array(const struct gpio *array, size_t num)
+{
+ while (num--)
+ gpio_free((array++)->gpio);
+}
+EXPORT_SYMBOL_GPL(gpio_free_array);
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 2024d45e5503..7cfdc2278905 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -23,7 +23,7 @@
#include <linux/pinctrl/pinctrl.h>
#include <linux/slab.h>
-struct gpio_desc;
+#include "gpiolib.h"
/* Private data structure for of_gpiochip_find_and_xlate */
struct gg_data {
@@ -48,7 +48,7 @@ static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data)
if (ret < 0)
return false;
- gg_data->out_gpio = gpio_to_desc(ret + gc->base);
+ gg_data->out_gpio = gpiochip_get_desc(gc, ret);
return true;
}
@@ -82,19 +82,33 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index,
&gg_data.gpiospec);
if (ret) {
- pr_debug("%s: can't parse gpios property of node '%s[%d]'\n",
- __func__, np->full_name, index);
+ pr_debug("%s: can't parse '%s' property of node '%s[%d]'\n",
+ __func__, propname, np->full_name, index);
return ERR_PTR(ret);
}
gpiochip_find(&gg_data, of_gpiochip_find_and_xlate);
of_node_put(gg_data.gpiospec.np);
- pr_debug("%s exited with status %d\n", __func__,
+ pr_debug("%s: parsed '%s' property of node '%s[%d]' - status (%d)\n",
+ __func__, propname, np->full_name, index,
PTR_ERR_OR_ZERO(gg_data.out_gpio));
return gg_data.out_gpio;
}
-EXPORT_SYMBOL(of_get_named_gpiod_flags);
+
+int of_get_named_gpio_flags(struct device_node *np, const char *list_name,
+ int index, enum of_gpio_flags *flags)
+{
+ struct gpio_desc *desc;
+
+ desc = of_get_named_gpiod_flags(np, list_name, index, flags);
+
+ if (IS_ERR(desc))
+ return PTR_ERR(desc);
+ else
+ return desc_to_gpio(desc);
+}
+EXPORT_SYMBOL(of_get_named_gpio_flags);
/**
* of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
new file mode 100644
index 000000000000..5f2150b619a7
--- /dev/null
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -0,0 +1,827 @@
+#include <linux/idr.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/sysfs.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/kdev_t.h>
+
+#include "gpiolib.h"
+
+static DEFINE_IDR(dirent_idr);
+
+
+/* lock protects against unexport_gpio() being called while
+ * sysfs files are active.
+ */
+static DEFINE_MUTEX(sysfs_lock);
+
+/*
+ * /sys/class/gpio/gpioN... only for GPIOs that are exported
+ * /direction
+ * * MAY BE OMITTED if kernel won't allow direction changes
+ * * is read/write as "in" or "out"
+ * * may also be written as "high" or "low", initializing
+ * output value as specified ("out" implies "low")
+ * /value
+ * * always readable, subject to hardware behavior
+ * * may be writable, as zero/nonzero
+ * /edge
+ * * configures behavior of poll(2) on /value
+ * * available only if pin can generate IRQs on input
+ * * is read/write as "none", "falling", "rising", or "both"
+ * /active_low
+ * * configures polarity of /value
+ * * is read/write as zero/nonzero
+ * * also affects existing and subsequent "falling" and "rising"
+ * /edge configuration
+ */
+
+static ssize_t gpio_direction_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ const struct gpio_desc *desc = dev_get_drvdata(dev);
+ ssize_t status;
+
+ mutex_lock(&sysfs_lock);
+
+ if (!test_bit(FLAG_EXPORT, &desc->flags)) {
+ status = -EIO;
+ } else {
+ gpiod_get_direction(desc);
+ status = sprintf(buf, "%s\n",
+ test_bit(FLAG_IS_OUT, &desc->flags)
+ ? "out" : "in");
+ }
+
+ mutex_unlock(&sysfs_lock);
+ return status;
+}
+
+static ssize_t gpio_direction_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct gpio_desc *desc = dev_get_drvdata(dev);
+ ssize_t status;
+
+ mutex_lock(&sysfs_lock);
+
+ if (!test_bit(FLAG_EXPORT, &desc->flags))
+ status = -EIO;
+ else if (sysfs_streq(buf, "high"))
+ status = gpiod_direction_output_raw(desc, 1);
+ else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low"))
+ status = gpiod_direction_output_raw(desc, 0);
+ else if (sysfs_streq(buf, "in"))
+ status = gpiod_direction_input(desc);
+ else
+ status = -EINVAL;
+
+ mutex_unlock(&sysfs_lock);
+ return status ? : size;
+}
+
+static /* const */ DEVICE_ATTR(direction, 0644,
+ gpio_direction_show, gpio_direction_store);
+
+static ssize_t gpio_value_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct gpio_desc *desc = dev_get_drvdata(dev);
+ ssize_t status;
+
+ mutex_lock(&sysfs_lock);
+
+ if (!test_bit(FLAG_EXPORT, &desc->flags))
+ status = -EIO;
+ else
+ status = sprintf(buf, "%d\n", gpiod_get_value_cansleep(desc));
+
+ mutex_unlock(&sysfs_lock);
+ return status;
+}
+
+static ssize_t gpio_value_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct gpio_desc *desc = dev_get_drvdata(dev);
+ ssize_t status;
+
+ mutex_lock(&sysfs_lock);
+
+ if (!test_bit(FLAG_EXPORT, &desc->flags))
+ status = -EIO;
+ else if (!test_bit(FLAG_IS_OUT, &desc->flags))
+ status = -EPERM;
+ else {
+ long value;
+
+ status = kstrtol(buf, 0, &value);
+ if (status == 0) {
+ gpiod_set_value_cansleep(desc, value);
+ status = size;
+ }
+ }
+
+ mutex_unlock(&sysfs_lock);
+ return status;
+}
+
+static const DEVICE_ATTR(value, 0644,
+ gpio_value_show, gpio_value_store);
+
+static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
+{
+ struct kernfs_node *value_sd = priv;
+
+ sysfs_notify_dirent(value_sd);
+ return IRQ_HANDLED;
+}
+
+static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
+ unsigned long gpio_flags)
+{
+ struct kernfs_node *value_sd;
+ unsigned long irq_flags;
+ int ret, irq, id;
+
+ if ((desc->flags & GPIO_TRIGGER_MASK) == gpio_flags)
+ return 0;
+
+ irq = gpiod_to_irq(desc);
+ if (irq < 0)
+ return -EIO;
+
+ id = desc->flags >> ID_SHIFT;
+ value_sd = idr_find(&dirent_idr, id);
+ if (value_sd)
+ free_irq(irq, value_sd);
+
+ desc->flags &= ~GPIO_TRIGGER_MASK;
+
+ if (!gpio_flags) {
+ gpio_unlock_as_irq(desc->chip, gpio_chip_hwgpio(desc));
+ ret = 0;
+ goto free_id;
+ }
+
+ irq_flags = IRQF_SHARED;
+ if (test_bit(FLAG_TRIG_FALL, &gpio_flags))
+ irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
+ IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
+ if (test_bit(FLAG_TRIG_RISE, &gpio_flags))
+ irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
+ IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
+
+ if (!value_sd) {
+ value_sd = sysfs_get_dirent(dev->kobj.sd, "value");
+ if (!value_sd) {
+ ret = -ENODEV;
+ goto err_out;
+ }
+
+ ret = idr_alloc(&dirent_idr, value_sd, 1, 0, GFP_KERNEL);
+ if (ret < 0)
+ goto free_sd;
+ id = ret;
+
+ desc->flags &= GPIO_FLAGS_MASK;
+ desc->flags |= (unsigned long)id << ID_SHIFT;
+
+ if (desc->flags >> ID_SHIFT != id) {
+ ret = -ERANGE;
+ goto free_id;
+ }
+ }
+
+ ret = request_any_context_irq(irq, gpio_sysfs_irq, irq_flags,
+ "gpiolib", value_sd);
+ if (ret < 0)
+ goto free_id;
+
+ ret = gpio_lock_as_irq(desc->chip, gpio_chip_hwgpio(desc));
+ if (ret < 0) {
+ gpiod_warn(desc, "failed to flag the GPIO for IRQ\n");
+ goto free_id;
+ }
+
+ desc->flags |= gpio_flags;
+ return 0;
+
+free_id:
+ idr_remove(&dirent_idr, id);
+ desc->flags &= GPIO_FLAGS_MASK;
+free_sd:
+ if (value_sd)
+ sysfs_put(value_sd);
+err_out:
+ return ret;
+}
+
+static const struct {
+ const char *name;
+ unsigned long flags;
+} trigger_types[] = {
+ { "none", 0 },
+ { "falling", BIT(FLAG_TRIG_FALL) },
+ { "rising", BIT(FLAG_TRIG_RISE) },
+ { "both", BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE) },
+};
+
+static ssize_t gpio_edge_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ const struct gpio_desc *desc = dev_get_drvdata(dev);
+ ssize_t status;
+
+ mutex_lock(&sysfs_lock);
+
+ if (!test_bit(FLAG_EXPORT, &desc->flags))
+ status = -EIO;
+ else {
+ int i;
+
+ status = 0;
+ for (i = 0; i < ARRAY_SIZE(trigger_types); i++)
+ if ((desc->flags & GPIO_TRIGGER_MASK)
+ == trigger_types[i].flags) {
+ status = sprintf(buf, "%s\n",
+ trigger_types[i].name);
+ break;
+ }
+ }
+
+ mutex_unlock(&sysfs_lock);
+ return status;
+}
+
+static ssize_t gpio_edge_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct gpio_desc *desc = dev_get_drvdata(dev);
+ ssize_t status;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(trigger_types); i++)
+ if (sysfs_streq(trigger_types[i].name, buf))
+ goto found;
+ return -EINVAL;
+
+found:
+ mutex_lock(&sysfs_lock);
+
+ if (!test_bit(FLAG_EXPORT, &desc->flags))
+ status = -EIO;
+ else {
+ status = gpio_setup_irq(desc, dev, trigger_types[i].flags);
+ if (!status)
+ status = size;
+ }
+
+ mutex_unlock(&sysfs_lock);
+
+ return status;
+}
+
+static DEVICE_ATTR(edge, 0644, gpio_edge_show, gpio_edge_store);
+
+static int sysfs_set_active_low(struct gpio_desc *desc, struct device *dev,
+ int value)
+{
+ int status = 0;
+
+ if (!!test_bit(FLAG_ACTIVE_LOW, &desc->flags) == !!value)
+ return 0;
+
+ if (value)
+ set_bit(FLAG_ACTIVE_LOW, &desc->flags);
+ else
+ clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
+
+ /* reconfigure poll(2) support if enabled on one edge only */
+ if (dev != NULL && (!!test_bit(FLAG_TRIG_RISE, &desc->flags) ^
+ !!test_bit(FLAG_TRIG_FALL, &desc->flags))) {
+ unsigned long trigger_flags = desc->flags & GPIO_TRIGGER_MASK;
+
+ gpio_setup_irq(desc, dev, 0);
+ status = gpio_setup_irq(desc, dev, trigger_flags);
+ }
+
+ return status;
+}
+
+static ssize_t gpio_active_low_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ const struct gpio_desc *desc = dev_get_drvdata(dev);
+ ssize_t status;
+
+ mutex_lock(&sysfs_lock);
+
+ if (!test_bit(FLAG_EXPORT, &desc->flags))
+ status = -EIO;
+ else
+ status = sprintf(buf, "%d\n",
+ !!test_bit(FLAG_ACTIVE_LOW, &desc->flags));
+
+ mutex_unlock(&sysfs_lock);
+
+ return status;
+}
+
+static ssize_t gpio_active_low_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct gpio_desc *desc = dev_get_drvdata(dev);
+ ssize_t status;
+
+ mutex_lock(&sysfs_lock);
+
+ if (!test_bit(FLAG_EXPORT, &desc->flags)) {
+ status = -EIO;
+ } else {
+ long value;
+
+ status = kstrtol(buf, 0, &value);
+ if (status == 0)
+ status = sysfs_set_active_low(desc, dev, value != 0);
+ }
+
+ mutex_unlock(&sysfs_lock);
+
+ return status ? : size;
+}
+
+static const DEVICE_ATTR(active_low, 0644,
+ gpio_active_low_show, gpio_active_low_store);
+
+static const struct attribute *gpio_attrs[] = {
+ &dev_attr_value.attr,
+ &dev_attr_active_low.attr,
+ NULL,
+};
+
+static const struct attribute_group gpio_attr_group = {
+ .attrs = (struct attribute **) gpio_attrs,
+};
+
+/*
+ * /sys/class/gpio/gpiochipN/
+ * /base ... matching gpio_chip.base (N)
+ * /label ... matching gpio_chip.label
+ * /ngpio ... matching gpio_chip.ngpio
+ */
+
+static ssize_t chip_base_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ const struct gpio_chip *chip = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", chip->base);
+}
+static DEVICE_ATTR(base, 0444, chip_base_show, NULL);
+
+static ssize_t chip_label_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ const struct gpio_chip *chip = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", chip->label ? : "");
+}
+static DEVICE_ATTR(label, 0444, chip_label_show, NULL);
+
+static ssize_t chip_ngpio_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ const struct gpio_chip *chip = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", chip->ngpio);
+}
+static DEVICE_ATTR(ngpio, 0444, chip_ngpio_show, NULL);
+
+static const struct attribute *gpiochip_attrs[] = {
+ &dev_attr_base.attr,
+ &dev_attr_label.attr,
+ &dev_attr_ngpio.attr,
+ NULL,
+};
+
+static const struct attribute_group gpiochip_attr_group = {
+ .attrs = (struct attribute **) gpiochip_attrs,
+};
+
+/*
+ * /sys/class/gpio/export ... write-only
+ * integer N ... number of GPIO to export (full access)
+ * /sys/class/gpio/unexport ... write-only
+ * integer N ... number of GPIO to unexport
+ */
+static ssize_t export_store(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t len)
+{
+ long gpio;
+ struct gpio_desc *desc;
+ int status;
+
+ status = kstrtol(buf, 0, &gpio);
+ if (status < 0)
+ goto done;
+
+ desc = gpio_to_desc(gpio);
+ /* reject invalid GPIOs */
+ if (!desc) {
+ pr_warn("%s: invalid GPIO %ld\n", __func__, gpio);
+ return -EINVAL;
+ }
+
+ /* No extra locking here; FLAG_SYSFS just signifies that the
+ * request and export were done by on behalf of userspace, so
+ * they may be undone on its behalf too.
+ */
+
+ status = gpiod_request(desc, "sysfs");
+ if (status < 0) {
+ if (status == -EPROBE_DEFER)
+ status = -ENODEV;
+ goto done;
+ }
+ status = gpiod_export(desc, true);
+ if (status < 0)
+ gpiod_free(desc);
+ else
+ set_bit(FLAG_SYSFS, &desc->flags);
+
+done:
+ if (status)
+ pr_debug("%s: status %d\n", __func__, status);
+ return status ? : len;
+}
+
+static ssize_t unexport_store(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t len)
+{
+ long gpio;
+ struct gpio_desc *desc;
+ int status;
+
+ status = kstrtol(buf, 0, &gpio);
+ if (status < 0)
+ goto done;
+
+ desc = gpio_to_desc(gpio);
+ /* reject bogus commands (gpio_unexport ignores them) */
+ if (!desc) {
+ pr_warn("%s: invalid GPIO %ld\n", __func__, gpio);
+ return -EINVAL;
+ }
+
+ status = -EINVAL;
+
+ /* No extra locking here; FLAG_SYSFS just signifies that the
+ * request and export were done by on behalf of userspace, so
+ * they may be undone on its behalf too.
+ */
+ if (test_and_clear_bit(FLAG_SYSFS, &desc->flags)) {
+ status = 0;
+ gpiod_free(desc);
+ }
+done:
+ if (status)
+ pr_debug("%s: status %d\n", __func__, status);
+ return status ? : len;
+}
+
+static struct class_attribute gpio_class_attrs[] = {
+ __ATTR(export, 0200, NULL, export_store),
+ __ATTR(unexport, 0200, NULL, unexport_store),
+ __ATTR_NULL,
+};
+
+static struct class gpio_class = {
+ .name = "gpio",
+ .owner = THIS_MODULE,
+
+ .class_attrs = gpio_class_attrs,
+};
+
+
+/**
+ * gpiod_export - export a GPIO through sysfs
+ * @gpio: gpio to make available, already requested
+ * @direction_may_change: true if userspace may change gpio direction
+ * Context: arch_initcall or later
+ *
+ * When drivers want to make a GPIO accessible to userspace after they
+ * have requested it -- perhaps while debugging, or as part of their
+ * public interface -- they may use this routine. If the GPIO can
+ * change direction (some can't) and the caller allows it, userspace
+ * will see "direction" sysfs attribute which may be used to change
+ * the gpio's direction. A "value" attribute will always be provided.
+ *
+ * Returns zero on success, else an error.
+ */
+int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
+{
+ unsigned long flags;
+ int status;
+ const char *ioname = NULL;
+ struct device *dev;
+ int offset;
+
+ /* can't export until sysfs is available ... */
+ if (!gpio_class.p) {
+ pr_debug("%s: called too early!\n", __func__);
+ return -ENOENT;
+ }
+
+ if (!desc) {
+ pr_debug("%s: invalid gpio descriptor\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&sysfs_lock);
+
+ spin_lock_irqsave(&gpio_lock, flags);
+ if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
+ test_bit(FLAG_EXPORT, &desc->flags)) {
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ gpiod_dbg(desc, "%s: unavailable (requested=%d, exported=%d)\n",
+ __func__,
+ test_bit(FLAG_REQUESTED, &desc->flags),
+ test_bit(FLAG_EXPORT, &desc->flags));
+ status = -EPERM;
+ goto fail_unlock;
+ }
+
+ if (!desc->chip->direction_input || !desc->chip->direction_output)
+ direction_may_change = false;
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+ offset = gpio_chip_hwgpio(desc);
+ if (desc->chip->names && desc->chip->names[offset])
+ ioname = desc->chip->names[offset];
+
+ dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
+ desc, ioname ? ioname : "gpio%u",
+ desc_to_gpio(desc));
+ if (IS_ERR(dev)) {
+ status = PTR_ERR(dev);
+ goto fail_unlock;
+ }
+
+ status = sysfs_create_group(&dev->kobj, &gpio_attr_group);
+ if (status)
+ goto fail_unregister_device;
+
+ if (direction_may_change) {
+ status = device_create_file(dev, &dev_attr_direction);
+ if (status)
+ goto fail_unregister_device;
+ }
+
+ if (gpiod_to_irq(desc) >= 0 && (direction_may_change ||
+ !test_bit(FLAG_IS_OUT, &desc->flags))) {
+ status = device_create_file(dev, &dev_attr_edge);
+ if (status)
+ goto fail_unregister_device;
+ }
+
+ set_bit(FLAG_EXPORT, &desc->flags);
+ mutex_unlock(&sysfs_lock);
+ return 0;
+
+fail_unregister_device:
+ device_unregister(dev);
+fail_unlock:
+ mutex_unlock(&sysfs_lock);
+ gpiod_dbg(desc, "%s: status %d\n", __func__, status);
+ return status;
+}
+EXPORT_SYMBOL_GPL(gpiod_export);
+
+static int match_export(struct device *dev, const void *data)
+{
+ return dev_get_drvdata(dev) == data;
+}
+
+/**
+ * gpiod_export_link - create a sysfs link to an exported GPIO node
+ * @dev: device under which to create symlink
+ * @name: name of the symlink
+ * @gpio: gpio to create symlink to, already exported
+ *
+ * Set up a symlink from /sys/.../dev/name to /sys/class/gpio/gpioN
+ * node. Caller is responsible for unlinking.
+ *
+ * Returns zero on success, else an error.
+ */
+int gpiod_export_link(struct device *dev, const char *name,
+ struct gpio_desc *desc)
+{
+ int status = -EINVAL;
+
+ if (!desc) {
+ pr_warn("%s: invalid GPIO\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&sysfs_lock);
+
+ if (test_bit(FLAG_EXPORT, &desc->flags)) {
+ struct device *tdev;
+
+ tdev = class_find_device(&gpio_class, NULL, desc, match_export);
+ if (tdev != NULL) {
+ status = sysfs_create_link(&dev->kobj, &tdev->kobj,
+ name);
+ } else {
+ status = -ENODEV;
+ }
+ }
+
+ mutex_unlock(&sysfs_lock);
+
+ if (status)
+ gpiod_dbg(desc, "%s: status %d\n", __func__, status);
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(gpiod_export_link);
+
+/**
+ * gpiod_sysfs_set_active_low - set the polarity of gpio sysfs value
+ * @gpio: gpio to change
+ * @value: non-zero to use active low, i.e. inverted values
+ *
+ * Set the polarity of /sys/class/gpio/gpioN/value sysfs attribute.
+ * The GPIO does not have to be exported yet. If poll(2) support has
+ * been enabled for either rising or falling edge, it will be
+ * reconfigured to follow the new polarity.
+ *
+ * Returns zero on success, else an error.
+ */
+int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value)
+{
+ struct device *dev = NULL;
+ int status = -EINVAL;
+
+ if (!desc) {
+ pr_warn("%s: invalid GPIO\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&sysfs_lock);
+
+ if (test_bit(FLAG_EXPORT, &desc->flags)) {
+ dev = class_find_device(&gpio_class, NULL, desc, match_export);
+ if (dev == NULL) {
+ status = -ENODEV;
+ goto unlock;
+ }
+ }
+
+ status = sysfs_set_active_low(desc, dev, value);
+
+unlock:
+ mutex_unlock(&sysfs_lock);
+
+ if (status)
+ gpiod_dbg(desc, "%s: status %d\n", __func__, status);
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(gpiod_sysfs_set_active_low);
+
+/**
+ * gpiod_unexport - reverse effect of gpio_export()
+ * @gpio: gpio to make unavailable
+ *
+ * This is implicit on gpio_free().
+ */
+void gpiod_unexport(struct gpio_desc *desc)
+{
+ int status = 0;
+ struct device *dev = NULL;
+
+ if (!desc) {
+ pr_warn("%s: invalid GPIO\n", __func__);
+ return;
+ }
+
+ mutex_lock(&sysfs_lock);
+
+ if (test_bit(FLAG_EXPORT, &desc->flags)) {
+
+ dev = class_find_device(&gpio_class, NULL, desc, match_export);
+ if (dev) {
+ gpio_setup_irq(desc, dev, 0);
+ clear_bit(FLAG_EXPORT, &desc->flags);
+ } else
+ status = -ENODEV;
+ }
+
+ mutex_unlock(&sysfs_lock);
+
+ if (dev) {
+ device_unregister(dev);
+ put_device(dev);
+ }
+
+ if (status)
+ gpiod_dbg(desc, "%s: status %d\n", __func__, status);
+}
+EXPORT_SYMBOL_GPL(gpiod_unexport);
+
+int gpiochip_export(struct gpio_chip *chip)
+{
+ int status;
+ struct device *dev;
+
+ /* Many systems register gpio chips for SOC support very early,
+ * before driver model support is available. In those cases we
+ * export this later, in gpiolib_sysfs_init() ... here we just
+ * verify that _some_ field of gpio_class got initialized.
+ */
+ if (!gpio_class.p)
+ return 0;
+
+ /* use chip->base for the ID; it's already known to be unique */
+ mutex_lock(&sysfs_lock);
+ dev = device_create(&gpio_class, chip->dev, MKDEV(0, 0), chip,
+ "gpiochip%d", chip->base);
+ if (!IS_ERR(dev)) {
+ status = sysfs_create_group(&dev->kobj,
+ &gpiochip_attr_group);
+ } else
+ status = PTR_ERR(dev);
+ chip->exported = (status == 0);
+ mutex_unlock(&sysfs_lock);
+
+ if (status)
+ chip_dbg(chip, "%s: status %d\n", __func__, status);
+
+ return status;
+}
+
+void gpiochip_unexport(struct gpio_chip *chip)
+{
+ int status;
+ struct device *dev;
+
+ mutex_lock(&sysfs_lock);
+ dev = class_find_device(&gpio_class, NULL, chip, match_export);
+ if (dev) {
+ put_device(dev);
+ device_unregister(dev);
+ chip->exported = false;
+ status = 0;
+ } else
+ status = -ENODEV;
+ mutex_unlock(&sysfs_lock);
+
+ if (status)
+ chip_dbg(chip, "%s: status %d\n", __func__, status);
+}
+
+static int __init gpiolib_sysfs_init(void)
+{
+ int status;
+ unsigned long flags;
+ struct gpio_chip *chip;
+
+ status = class_register(&gpio_class);
+ if (status < 0)
+ return status;
+
+ /* Scan and register the gpio_chips which registered very
+ * early (e.g. before the class_register above was called).
+ *
+ * We run before arch_initcall() so chip->dev nodes can have
+ * registered, and so arch_initcall() can always gpio_export().
+ */
+ spin_lock_irqsave(&gpio_lock, flags);
+ list_for_each_entry(chip, &gpio_chips, list) {
+ if (chip->exported)
+ continue;
+
+ /*
+ * TODO we yield gpio_lock here because gpiochip_export()
+ * acquires a mutex. This is unsafe and needs to be fixed.
+ *
+ * Also it would be nice to use gpiochip_find() here so we
+ * can keep gpio_chips local to gpiolib.c, but the yield of
+ * gpio_lock prevents us from doing this.
+ */
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ status = gpiochip_export(chip);
+ spin_lock_irqsave(&gpio_lock, flags);
+ }
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+
+ return status;
+}
+postcore_initcall(gpiolib_sysfs_init);
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index f48817d97480..15cc0bb65dda 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -14,6 +14,7 @@
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/gpio/driver.h>
+#include <linux/gpio/machine.h>
#include "gpiolib.h"
@@ -44,111 +45,19 @@
* While any GPIO is requested, its gpio_chip is not removable;
* each GPIO's "requested" flag serves as a lock and refcount.
*/
-static DEFINE_SPINLOCK(gpio_lock);
+DEFINE_SPINLOCK(gpio_lock);
-struct gpio_desc {
- struct gpio_chip *chip;
- unsigned long flags;
-/* flag symbols are bit numbers */
-#define FLAG_REQUESTED 0
-#define FLAG_IS_OUT 1
-#define FLAG_EXPORT 2 /* protected by sysfs_lock */
-#define FLAG_SYSFS 3 /* exported via /sys/class/gpio/control */
-#define FLAG_TRIG_FALL 4 /* trigger on falling edge */
-#define FLAG_TRIG_RISE 5 /* trigger on rising edge */
-#define FLAG_ACTIVE_LOW 6 /* value has active low */
-#define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */
-#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */
-#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */
-
-#define ID_SHIFT 16 /* add new flags before this one */
-
-#define GPIO_FLAGS_MASK ((1 << ID_SHIFT) - 1)
-#define GPIO_TRIGGER_MASK (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))
-
-#ifdef CONFIG_DEBUG_FS
- const char *label;
-#endif
-};
static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
#define GPIO_OFFSET_VALID(chip, offset) (offset >= 0 && offset < chip->ngpio)
static DEFINE_MUTEX(gpio_lookup_lock);
static LIST_HEAD(gpio_lookup_list);
-static LIST_HEAD(gpio_chips);
-
-#ifdef CONFIG_GPIO_SYSFS
-static DEFINE_IDR(dirent_idr);
-#endif
-
-static int gpiod_request(struct gpio_desc *desc, const char *label);
-static void gpiod_free(struct gpio_desc *desc);
-
-/* With descriptor prefix */
-
-#ifdef CONFIG_DEBUG_FS
-#define gpiod_emerg(desc, fmt, ...) \
- pr_emerg("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",\
- ##__VA_ARGS__)
-#define gpiod_crit(desc, fmt, ...) \
- pr_crit("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \
- ##__VA_ARGS__)
-#define gpiod_err(desc, fmt, ...) \
- pr_err("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \
- ##__VA_ARGS__)
-#define gpiod_warn(desc, fmt, ...) \
- pr_warn("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \
- ##__VA_ARGS__)
-#define gpiod_info(desc, fmt, ...) \
- pr_info("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \
- ##__VA_ARGS__)
-#define gpiod_dbg(desc, fmt, ...) \
- pr_debug("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",\
- ##__VA_ARGS__)
-#else
-#define gpiod_emerg(desc, fmt, ...) \
- pr_emerg("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__)
-#define gpiod_crit(desc, fmt, ...) \
- pr_crit("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__)
-#define gpiod_err(desc, fmt, ...) \
- pr_err("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__)
-#define gpiod_warn(desc, fmt, ...) \
- pr_warn("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__)
-#define gpiod_info(desc, fmt, ...) \
- pr_info("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__)
-#define gpiod_dbg(desc, fmt, ...) \
- pr_debug("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__)
-#endif
-
-/* With chip prefix */
-
-#define chip_emerg(chip, fmt, ...) \
- pr_emerg("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
-#define chip_crit(chip, fmt, ...) \
- pr_crit("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
-#define chip_err(chip, fmt, ...) \
- pr_err("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
-#define chip_warn(chip, fmt, ...) \
- pr_warn("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
-#define chip_info(chip, fmt, ...) \
- pr_info("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
-#define chip_dbg(chip, fmt, ...) \
- pr_debug("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
+LIST_HEAD(gpio_chips);
static inline void desc_set_label(struct gpio_desc *d, const char *label)
{
-#ifdef CONFIG_DEBUG_FS
d->label = label;
-#endif
-}
-
-/*
- * Return the GPIO number of the passed descriptor relative to its chip
- */
-static int gpio_chip_hwgpio(const struct gpio_desc *desc)
-{
- return desc - &desc->chip->desc[0];
}
/**
@@ -174,7 +83,6 @@ struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip,
return &chip->desc[hwnum];
}
-EXPORT_SYMBOL_GPL(gpiochip_get_desc);
/**
* Convert a GPIO descriptor to the integer namespace.
@@ -188,39 +96,6 @@ int desc_to_gpio(const struct gpio_desc *desc)
EXPORT_SYMBOL_GPL(desc_to_gpio);
-/* Warn when drivers omit gpio_request() calls -- legal but ill-advised
- * when setting direction, and otherwise illegal. Until board setup code
- * and drivers use explicit requests everywhere (which won't happen when
- * those calls have no teeth) we can't avoid autorequesting. This nag
- * message should motivate switching to explicit requests... so should
- * the weaker cleanup after faults, compared to gpio_request().
- *
- * NOTE: the autorequest mechanism is going away; at this point it's
- * only "legal" in the sense that (old) code using it won't break yet,
- * but instead only triggers a WARN() stack dump.
- */
-static int gpio_ensure_requested(struct gpio_desc *desc)
-{
- const struct gpio_chip *chip = desc->chip;
- const int gpio = desc_to_gpio(desc);
-
- if (WARN(test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0,
- "autorequest GPIO-%d\n", gpio)) {
- if (!try_module_get(chip->owner)) {
- gpiod_err(desc, "%s: module can't be gotten\n",
- __func__);
- clear_bit(FLAG_REQUESTED, &desc->flags);
- /* lose */
- return -EIO;
- }
- desc_set_label(desc, "[auto]");
- /* caller must chip->request() w/o spinlock */
- if (chip->request)
- return 1;
- }
- return 0;
-}
-
/**
* gpiod_to_chip - Return the GPIO chip to which a GPIO descriptor belongs
* @desc: descriptor to return the chip of
@@ -291,836 +166,6 @@ int gpiod_get_direction(const struct gpio_desc *desc)
}
EXPORT_SYMBOL_GPL(gpiod_get_direction);
-#ifdef CONFIG_GPIO_SYSFS
-
-/* lock protects against unexport_gpio() being called while
- * sysfs files are active.
- */
-static DEFINE_MUTEX(sysfs_lock);
-
-/*
- * /sys/class/gpio/gpioN... only for GPIOs that are exported
- * /direction
- * * MAY BE OMITTED if kernel won't allow direction changes
- * * is read/write as "in" or "out"
- * * may also be written as "high" or "low", initializing
- * output value as specified ("out" implies "low")
- * /value
- * * always readable, subject to hardware behavior
- * * may be writable, as zero/nonzero
- * /edge
- * * configures behavior of poll(2) on /value
- * * available only if pin can generate IRQs on input
- * * is read/write as "none", "falling", "rising", or "both"
- * /active_low
- * * configures polarity of /value
- * * is read/write as zero/nonzero
- * * also affects existing and subsequent "falling" and "rising"
- * /edge configuration
- */
-
-static ssize_t gpio_direction_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- const struct gpio_desc *desc = dev_get_drvdata(dev);
- ssize_t status;
-
- mutex_lock(&sysfs_lock);
-
- if (!test_bit(FLAG_EXPORT, &desc->flags)) {
- status = -EIO;
- } else {
- gpiod_get_direction(desc);
- status = sprintf(buf, "%s\n",
- test_bit(FLAG_IS_OUT, &desc->flags)
- ? "out" : "in");
- }
-
- mutex_unlock(&sysfs_lock);
- return status;
-}
-
-static ssize_t gpio_direction_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t size)
-{
- struct gpio_desc *desc = dev_get_drvdata(dev);
- ssize_t status;
-
- mutex_lock(&sysfs_lock);
-
- if (!test_bit(FLAG_EXPORT, &desc->flags))
- status = -EIO;
- else if (sysfs_streq(buf, "high"))
- status = gpiod_direction_output_raw(desc, 1);
- else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low"))
- status = gpiod_direction_output_raw(desc, 0);
- else if (sysfs_streq(buf, "in"))
- status = gpiod_direction_input(desc);
- else
- status = -EINVAL;
-
- mutex_unlock(&sysfs_lock);
- return status ? : size;
-}
-
-static /* const */ DEVICE_ATTR(direction, 0644,
- gpio_direction_show, gpio_direction_store);
-
-static ssize_t gpio_value_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct gpio_desc *desc = dev_get_drvdata(dev);
- ssize_t status;
-
- mutex_lock(&sysfs_lock);
-
- if (!test_bit(FLAG_EXPORT, &desc->flags))
- status = -EIO;
- else
- status = sprintf(buf, "%d\n", gpiod_get_value_cansleep(desc));
-
- mutex_unlock(&sysfs_lock);
- return status;
-}
-
-static ssize_t gpio_value_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t size)
-{
- struct gpio_desc *desc = dev_get_drvdata(dev);
- ssize_t status;
-
- mutex_lock(&sysfs_lock);
-
- if (!test_bit(FLAG_EXPORT, &desc->flags))
- status = -EIO;
- else if (!test_bit(FLAG_IS_OUT, &desc->flags))
- status = -EPERM;
- else {
- long value;
-
- status = kstrtol(buf, 0, &value);
- if (status == 0) {
- gpiod_set_value_cansleep(desc, value);
- status = size;
- }
- }
-
- mutex_unlock(&sysfs_lock);
- return status;
-}
-
-static const DEVICE_ATTR(value, 0644,
- gpio_value_show, gpio_value_store);
-
-static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
-{
- struct kernfs_node *value_sd = priv;
-
- sysfs_notify_dirent(value_sd);
- return IRQ_HANDLED;
-}
-
-static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
- unsigned long gpio_flags)
-{
- struct kernfs_node *value_sd;
- unsigned long irq_flags;
- int ret, irq, id;
-
- if ((desc->flags & GPIO_TRIGGER_MASK) == gpio_flags)
- return 0;
-
- irq = gpiod_to_irq(desc);
- if (irq < 0)
- return -EIO;
-
- id = desc->flags >> ID_SHIFT;
- value_sd = idr_find(&dirent_idr, id);
- if (value_sd)
- free_irq(irq, value_sd);
-
- desc->flags &= ~GPIO_TRIGGER_MASK;
-
- if (!gpio_flags) {
- gpiod_unlock_as_irq(desc);
- ret = 0;
- goto free_id;
- }
-
- irq_flags = IRQF_SHARED;
- if (test_bit(FLAG_TRIG_FALL, &gpio_flags))
- irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
- IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
- if (test_bit(FLAG_TRIG_RISE, &gpio_flags))
- irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
- IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
-
- if (!value_sd) {
- value_sd = sysfs_get_dirent(dev->kobj.sd, "value");
- if (!value_sd) {
- ret = -ENODEV;
- goto err_out;
- }
-
- ret = idr_alloc(&dirent_idr, value_sd, 1, 0, GFP_KERNEL);
- if (ret < 0)
- goto free_sd;
- id = ret;
-
- desc->flags &= GPIO_FLAGS_MASK;
- desc->flags |= (unsigned long)id << ID_SHIFT;
-
- if (desc->flags >> ID_SHIFT != id) {
- ret = -ERANGE;
- goto free_id;
- }
- }
-
- ret = request_any_context_irq(irq, gpio_sysfs_irq, irq_flags,
- "gpiolib", value_sd);
- if (ret < 0)
- goto free_id;
-
- ret = gpiod_lock_as_irq(desc);
- if (ret < 0) {
- gpiod_warn(desc, "failed to flag the GPIO for IRQ\n");
- goto free_id;
- }
-
- desc->flags |= gpio_flags;
- return 0;
-
-free_id:
- idr_remove(&dirent_idr, id);
- desc->flags &= GPIO_FLAGS_MASK;
-free_sd:
- if (value_sd)
- sysfs_put(value_sd);
-err_out:
- return ret;
-}
-
-static const struct {
- const char *name;
- unsigned long flags;
-} trigger_types[] = {
- { "none", 0 },
- { "falling", BIT(FLAG_TRIG_FALL) },
- { "rising", BIT(FLAG_TRIG_RISE) },
- { "both", BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE) },
-};
-
-static ssize_t gpio_edge_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- const struct gpio_desc *desc = dev_get_drvdata(dev);
- ssize_t status;
-
- mutex_lock(&sysfs_lock);
-
- if (!test_bit(FLAG_EXPORT, &desc->flags))
- status = -EIO;
- else {
- int i;
-
- status = 0;
- for (i = 0; i < ARRAY_SIZE(trigger_types); i++)
- if ((desc->flags & GPIO_TRIGGER_MASK)
- == trigger_types[i].flags) {
- status = sprintf(buf, "%s\n",
- trigger_types[i].name);
- break;
- }
- }
-
- mutex_unlock(&sysfs_lock);
- return status;
-}
-
-static ssize_t gpio_edge_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t size)
-{
- struct gpio_desc *desc = dev_get_drvdata(dev);
- ssize_t status;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(trigger_types); i++)
- if (sysfs_streq(trigger_types[i].name, buf))
- goto found;
- return -EINVAL;
-
-found:
- mutex_lock(&sysfs_lock);
-
- if (!test_bit(FLAG_EXPORT, &desc->flags))
- status = -EIO;
- else {
- status = gpio_setup_irq(desc, dev, trigger_types[i].flags);
- if (!status)
- status = size;
- }
-
- mutex_unlock(&sysfs_lock);
-
- return status;
-}
-
-static DEVICE_ATTR(edge, 0644, gpio_edge_show, gpio_edge_store);
-
-static int sysfs_set_active_low(struct gpio_desc *desc, struct device *dev,
- int value)
-{
- int status = 0;
-
- if (!!test_bit(FLAG_ACTIVE_LOW, &desc->flags) == !!value)
- return 0;
-
- if (value)
- set_bit(FLAG_ACTIVE_LOW, &desc->flags);
- else
- clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
-
- /* reconfigure poll(2) support if enabled on one edge only */
- if (dev != NULL && (!!test_bit(FLAG_TRIG_RISE, &desc->flags) ^
- !!test_bit(FLAG_TRIG_FALL, &desc->flags))) {
- unsigned long trigger_flags = desc->flags & GPIO_TRIGGER_MASK;
-
- gpio_setup_irq(desc, dev, 0);
- status = gpio_setup_irq(desc, dev, trigger_flags);
- }
-
- return status;
-}
-
-static ssize_t gpio_active_low_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- const struct gpio_desc *desc = dev_get_drvdata(dev);
- ssize_t status;
-
- mutex_lock(&sysfs_lock);
-
- if (!test_bit(FLAG_EXPORT, &desc->flags))
- status = -EIO;
- else
- status = sprintf(buf, "%d\n",
- !!test_bit(FLAG_ACTIVE_LOW, &desc->flags));
-
- mutex_unlock(&sysfs_lock);
-
- return status;
-}
-
-static ssize_t gpio_active_low_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t size)
-{
- struct gpio_desc *desc = dev_get_drvdata(dev);
- ssize_t status;
-
- mutex_lock(&sysfs_lock);
-
- if (!test_bit(FLAG_EXPORT, &desc->flags)) {
- status = -EIO;
- } else {
- long value;
-
- status = kstrtol(buf, 0, &value);
- if (status == 0)
- status = sysfs_set_active_low(desc, dev, value != 0);
- }
-
- mutex_unlock(&sysfs_lock);
-
- return status ? : size;
-}
-
-static const DEVICE_ATTR(active_low, 0644,
- gpio_active_low_show, gpio_active_low_store);
-
-static const struct attribute *gpio_attrs[] = {
- &dev_attr_value.attr,
- &dev_attr_active_low.attr,
- NULL,
-};
-
-static const struct attribute_group gpio_attr_group = {
- .attrs = (struct attribute **) gpio_attrs,
-};
-
-/*
- * /sys/class/gpio/gpiochipN/
- * /base ... matching gpio_chip.base (N)
- * /label ... matching gpio_chip.label
- * /ngpio ... matching gpio_chip.ngpio
- */
-
-static ssize_t chip_base_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- const struct gpio_chip *chip = dev_get_drvdata(dev);
-
- return sprintf(buf, "%d\n", chip->base);
-}
-static DEVICE_ATTR(base, 0444, chip_base_show, NULL);
-
-static ssize_t chip_label_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- const struct gpio_chip *chip = dev_get_drvdata(dev);
-
- return sprintf(buf, "%s\n", chip->label ? : "");
-}
-static DEVICE_ATTR(label, 0444, chip_label_show, NULL);
-
-static ssize_t chip_ngpio_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- const struct gpio_chip *chip = dev_get_drvdata(dev);
-
- return sprintf(buf, "%u\n", chip->ngpio);
-}
-static DEVICE_ATTR(ngpio, 0444, chip_ngpio_show, NULL);
-
-static const struct attribute *gpiochip_attrs[] = {
- &dev_attr_base.attr,
- &dev_attr_label.attr,
- &dev_attr_ngpio.attr,
- NULL,
-};
-
-static const struct attribute_group gpiochip_attr_group = {
- .attrs = (struct attribute **) gpiochip_attrs,
-};
-
-/*
- * /sys/class/gpio/export ... write-only
- * integer N ... number of GPIO to export (full access)
- * /sys/class/gpio/unexport ... write-only
- * integer N ... number of GPIO to unexport
- */
-static ssize_t export_store(struct class *class,
- struct class_attribute *attr,
- const char *buf, size_t len)
-{
- long gpio;
- struct gpio_desc *desc;
- int status;
-
- status = kstrtol(buf, 0, &gpio);
- if (status < 0)
- goto done;
-
- desc = gpio_to_desc(gpio);
- /* reject invalid GPIOs */
- if (!desc) {
- pr_warn("%s: invalid GPIO %ld\n", __func__, gpio);
- return -EINVAL;
- }
-
- /* No extra locking here; FLAG_SYSFS just signifies that the
- * request and export were done by on behalf of userspace, so
- * they may be undone on its behalf too.
- */
-
- status = gpiod_request(desc, "sysfs");
- if (status < 0) {
- if (status == -EPROBE_DEFER)
- status = -ENODEV;
- goto done;
- }
- status = gpiod_export(desc, true);
- if (status < 0)
- gpiod_free(desc);
- else
- set_bit(FLAG_SYSFS, &desc->flags);
-
-done:
- if (status)
- pr_debug("%s: status %d\n", __func__, status);
- return status ? : len;
-}
-
-static ssize_t unexport_store(struct class *class,
- struct class_attribute *attr,
- const char *buf, size_t len)
-{
- long gpio;
- struct gpio_desc *desc;
- int status;
-
- status = kstrtol(buf, 0, &gpio);
- if (status < 0)
- goto done;
-
- desc = gpio_to_desc(gpio);
- /* reject bogus commands (gpio_unexport ignores them) */
- if (!desc) {
- pr_warn("%s: invalid GPIO %ld\n", __func__, gpio);
- return -EINVAL;
- }
-
- status = -EINVAL;
-
- /* No extra locking here; FLAG_SYSFS just signifies that the
- * request and export were done by on behalf of userspace, so
- * they may be undone on its behalf too.
- */
- if (test_and_clear_bit(FLAG_SYSFS, &desc->flags)) {
- status = 0;
- gpiod_free(desc);
- }
-done:
- if (status)
- pr_debug("%s: status %d\n", __func__, status);
- return status ? : len;
-}
-
-static struct class_attribute gpio_class_attrs[] = {
- __ATTR(export, 0200, NULL, export_store),
- __ATTR(unexport, 0200, NULL, unexport_store),
- __ATTR_NULL,
-};
-
-static struct class gpio_class = {
- .name = "gpio",
- .owner = THIS_MODULE,
-
- .class_attrs = gpio_class_attrs,
-};
-
-
-/**
- * gpiod_export - export a GPIO through sysfs
- * @gpio: gpio to make available, already requested
- * @direction_may_change: true if userspace may change gpio direction
- * Context: arch_initcall or later
- *
- * When drivers want to make a GPIO accessible to userspace after they
- * have requested it -- perhaps while debugging, or as part of their
- * public interface -- they may use this routine. If the GPIO can
- * change direction (some can't) and the caller allows it, userspace
- * will see "direction" sysfs attribute which may be used to change
- * the gpio's direction. A "value" attribute will always be provided.
- *
- * Returns zero on success, else an error.
- */
-int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
-{
- unsigned long flags;
- int status;
- const char *ioname = NULL;
- struct device *dev;
- int offset;
-
- /* can't export until sysfs is available ... */
- if (!gpio_class.p) {
- pr_debug("%s: called too early!\n", __func__);
- return -ENOENT;
- }
-
- if (!desc) {
- pr_debug("%s: invalid gpio descriptor\n", __func__);
- return -EINVAL;
- }
-
- mutex_lock(&sysfs_lock);
-
- spin_lock_irqsave(&gpio_lock, flags);
- if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
- test_bit(FLAG_EXPORT, &desc->flags)) {
- spin_unlock_irqrestore(&gpio_lock, flags);
- gpiod_dbg(desc, "%s: unavailable (requested=%d, exported=%d)\n",
- __func__,
- test_bit(FLAG_REQUESTED, &desc->flags),
- test_bit(FLAG_EXPORT, &desc->flags));
- status = -EPERM;
- goto fail_unlock;
- }
-
- if (!desc->chip->direction_input || !desc->chip->direction_output)
- direction_may_change = false;
- spin_unlock_irqrestore(&gpio_lock, flags);
-
- offset = gpio_chip_hwgpio(desc);
- if (desc->chip->names && desc->chip->names[offset])
- ioname = desc->chip->names[offset];
-
- dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
- desc, ioname ? ioname : "gpio%u",
- desc_to_gpio(desc));
- if (IS_ERR(dev)) {
- status = PTR_ERR(dev);
- goto fail_unlock;
- }
-
- status = sysfs_create_group(&dev->kobj, &gpio_attr_group);
- if (status)
- goto fail_unregister_device;
-
- if (direction_may_change) {
- status = device_create_file(dev, &dev_attr_direction);
- if (status)
- goto fail_unregister_device;
- }
-
- if (gpiod_to_irq(desc) >= 0 && (direction_may_change ||
- !test_bit(FLAG_IS_OUT, &desc->flags))) {
- status = device_create_file(dev, &dev_attr_edge);
- if (status)
- goto fail_unregister_device;
- }
-
- set_bit(FLAG_EXPORT, &desc->flags);
- mutex_unlock(&sysfs_lock);
- return 0;
-
-fail_unregister_device:
- device_unregister(dev);
-fail_unlock:
- mutex_unlock(&sysfs_lock);
- gpiod_dbg(desc, "%s: status %d\n", __func__, status);
- return status;
-}
-EXPORT_SYMBOL_GPL(gpiod_export);
-
-static int match_export(struct device *dev, const void *data)
-{
- return dev_get_drvdata(dev) == data;
-}
-
-/**
- * gpiod_export_link - create a sysfs link to an exported GPIO node
- * @dev: device under which to create symlink
- * @name: name of the symlink
- * @gpio: gpio to create symlink to, already exported
- *
- * Set up a symlink from /sys/.../dev/name to /sys/class/gpio/gpioN
- * node. Caller is responsible for unlinking.
- *
- * Returns zero on success, else an error.
- */
-int gpiod_export_link(struct device *dev, const char *name,
- struct gpio_desc *desc)
-{
- int status = -EINVAL;
-
- if (!desc) {
- pr_warn("%s: invalid GPIO\n", __func__);
- return -EINVAL;
- }
-
- mutex_lock(&sysfs_lock);
-
- if (test_bit(FLAG_EXPORT, &desc->flags)) {
- struct device *tdev;
-
- tdev = class_find_device(&gpio_class, NULL, desc, match_export);
- if (tdev != NULL) {
- status = sysfs_create_link(&dev->kobj, &tdev->kobj,
- name);
- } else {
- status = -ENODEV;
- }
- }
-
- mutex_unlock(&sysfs_lock);
-
- if (status)
- gpiod_dbg(desc, "%s: status %d\n", __func__, status);
-
- return status;
-}
-EXPORT_SYMBOL_GPL(gpiod_export_link);
-
-/**
- * gpiod_sysfs_set_active_low - set the polarity of gpio sysfs value
- * @gpio: gpio to change
- * @value: non-zero to use active low, i.e. inverted values
- *
- * Set the polarity of /sys/class/gpio/gpioN/value sysfs attribute.
- * The GPIO does not have to be exported yet. If poll(2) support has
- * been enabled for either rising or falling edge, it will be
- * reconfigured to follow the new polarity.
- *
- * Returns zero on success, else an error.
- */
-int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value)
-{
- struct device *dev = NULL;
- int status = -EINVAL;
-
- if (!desc) {
- pr_warn("%s: invalid GPIO\n", __func__);
- return -EINVAL;
- }
-
- mutex_lock(&sysfs_lock);
-
- if (test_bit(FLAG_EXPORT, &desc->flags)) {
- dev = class_find_device(&gpio_class, NULL, desc, match_export);
- if (dev == NULL) {
- status = -ENODEV;
- goto unlock;
- }
- }
-
- status = sysfs_set_active_low(desc, dev, value);
-
-unlock:
- mutex_unlock(&sysfs_lock);
-
- if (status)
- gpiod_dbg(desc, "%s: status %d\n", __func__, status);
-
- return status;
-}
-EXPORT_SYMBOL_GPL(gpiod_sysfs_set_active_low);
-
-/**
- * gpiod_unexport - reverse effect of gpio_export()
- * @gpio: gpio to make unavailable
- *
- * This is implicit on gpio_free().
- */
-void gpiod_unexport(struct gpio_desc *desc)
-{
- int status = 0;
- struct device *dev = NULL;
-
- if (!desc) {
- pr_warn("%s: invalid GPIO\n", __func__);
- return;
- }
-
- mutex_lock(&sysfs_lock);
-
- if (test_bit(FLAG_EXPORT, &desc->flags)) {
-
- dev = class_find_device(&gpio_class, NULL, desc, match_export);
- if (dev) {
- gpio_setup_irq(desc, dev, 0);
- clear_bit(FLAG_EXPORT, &desc->flags);
- } else
- status = -ENODEV;
- }
-
- mutex_unlock(&sysfs_lock);
-
- if (dev) {
- device_unregister(dev);
- put_device(dev);
- }
-
- if (status)
- gpiod_dbg(desc, "%s: status %d\n", __func__, status);
-}
-EXPORT_SYMBOL_GPL(gpiod_unexport);
-
-static int gpiochip_export(struct gpio_chip *chip)
-{
- int status;
- struct device *dev;
-
- /* Many systems register gpio chips for SOC support very early,
- * before driver model support is available. In those cases we
- * export this later, in gpiolib_sysfs_init() ... here we just
- * verify that _some_ field of gpio_class got initialized.
- */
- if (!gpio_class.p)
- return 0;
-
- /* use chip->base for the ID; it's already known to be unique */
- mutex_lock(&sysfs_lock);
- dev = device_create(&gpio_class, chip->dev, MKDEV(0, 0), chip,
- "gpiochip%d", chip->base);
- if (!IS_ERR(dev)) {
- status = sysfs_create_group(&dev->kobj,
- &gpiochip_attr_group);
- } else
- status = PTR_ERR(dev);
- chip->exported = (status == 0);
- mutex_unlock(&sysfs_lock);
-
- if (status) {
- unsigned long flags;
- unsigned gpio;
-
- spin_lock_irqsave(&gpio_lock, flags);
- gpio = 0;
- while (gpio < chip->ngpio)
- chip->desc[gpio++].chip = NULL;
- spin_unlock_irqrestore(&gpio_lock, flags);
-
- chip_dbg(chip, "%s: status %d\n", __func__, status);
- }
-
- return status;
-}
-
-static void gpiochip_unexport(struct gpio_chip *chip)
-{
- int status;
- struct device *dev;
-
- mutex_lock(&sysfs_lock);
- dev = class_find_device(&gpio_class, NULL, chip, match_export);
- if (dev) {
- put_device(dev);
- device_unregister(dev);
- chip->exported = false;
- status = 0;
- } else
- status = -ENODEV;
- mutex_unlock(&sysfs_lock);
-
- if (status)
- chip_dbg(chip, "%s: status %d\n", __func__, status);
-}
-
-static int __init gpiolib_sysfs_init(void)
-{
- int status;
- unsigned long flags;
- struct gpio_chip *chip;
-
- status = class_register(&gpio_class);
- if (status < 0)
- return status;
-
- /* Scan and register the gpio_chips which registered very
- * early (e.g. before the class_register above was called).
- *
- * We run before arch_initcall() so chip->dev nodes can have
- * registered, and so arch_initcall() can always gpio_export().
- */
- spin_lock_irqsave(&gpio_lock, flags);
- list_for_each_entry(chip, &gpio_chips, list) {
- if (!chip || chip->exported)
- continue;
-
- spin_unlock_irqrestore(&gpio_lock, flags);
- status = gpiochip_export(chip);
- spin_lock_irqsave(&gpio_lock, flags);
- }
- spin_unlock_irqrestore(&gpio_lock, flags);
-
-
- return status;
-}
-postcore_initcall(gpiolib_sysfs_init);
-
-#else
-static inline int gpiochip_export(struct gpio_chip *chip)
-{
- return 0;
-}
-
-static inline void gpiochip_unexport(struct gpio_chip *chip)
-{
-}
-
-#endif /* CONFIG_GPIO_SYSFS */
-
/*
* Add a new chip to the global chips list, keeping the list of chips sorted
* by base order.
@@ -1363,6 +408,11 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
int parent_irq,
irq_flow_handler_t parent_handler)
{
+ if (gpiochip->can_sleep) {
+ chip_err(gpiochip, "you cannot have chained interrupts on a chip that may sleep\n");
+ return;
+ }
+
irq_set_chained_handler(parent_irq, parent_handler);
/*
* The parent irqchip is already using the chip_data for this
@@ -1372,6 +422,12 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
}
EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip);
+/*
+ * This lock class tells lockdep that GPIO irqs are in a different
+ * category than their parents, so it won't report false recursion.
+ */
+static struct lock_class_key gpiochip_irq_lock_class;
+
/**
* gpiochip_irq_map() - maps an IRQ into a GPIO irqchip
* @d: the irqdomain used by this irqchip
@@ -1388,22 +444,35 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
struct gpio_chip *chip = d->host_data;
irq_set_chip_data(irq, chip);
+ irq_set_lockdep_class(irq, &gpiochip_irq_lock_class);
irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler);
+ /* Chips that can sleep need nested thread handlers */
+ if (chip->can_sleep)
+ irq_set_nested_thread(irq, 1);
#ifdef CONFIG_ARM
set_irq_flags(irq, IRQF_VALID);
#else
irq_set_noprobe(irq);
#endif
- irq_set_irq_type(irq, chip->irq_default_type);
+ /*
+ * No set-up of the hardware will happen if IRQ_TYPE_NONE
+ * is passed as default type.
+ */
+ if (chip->irq_default_type != IRQ_TYPE_NONE)
+ irq_set_irq_type(irq, chip->irq_default_type);
return 0;
}
static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)
{
+ struct gpio_chip *chip = d->host_data;
+
#ifdef CONFIG_ARM
set_irq_flags(irq, 0);
#endif
+ if (chip->can_sleep)
+ irq_set_nested_thread(irq, 0);
irq_set_chip_and_handler(irq, NULL, NULL);
irq_set_chip_data(irq, NULL);
}
@@ -1450,6 +519,8 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
{
unsigned int offset;
+ acpi_gpiochip_free_interrupts(gpiochip);
+
/* Remove all IRQ mappings and delete the domain */
if (gpiochip->irqdomain) {
for (offset = 0; offset < gpiochip->ngpio; offset++)
@@ -1471,7 +542,8 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
* @first_irq: if not dynamically assigned, the base (first) IRQ to
* allocate gpiochip irqs from
* @handler: the irq handler to use (often a predefined irq core function)
- * @type: the default type for IRQs on this irqchip
+ * @type: the default type for IRQs on this irqchip, pass IRQ_TYPE_NONE
+ * to have the core avoid setting up any default type in the hardware.
*
* This function closely associates a certain irqchip with a certain
* gpiochip, providing an irq domain to translate the local IRQs to
@@ -1542,6 +614,8 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
gpiochip->irq_base = irq_base;
}
+ acpi_gpiochip_request_interrupts(gpiochip);
+
return 0;
}
EXPORT_SYMBOL_GPL(gpiochip_irqchip_add);
@@ -1715,7 +789,7 @@ done:
return status;
}
-static int gpiod_request(struct gpio_desc *desc, const char *label)
+int gpiod_request(struct gpio_desc *desc, const char *label)
{
int status = -EPROBE_DEFER;
struct gpio_chip *chip;
@@ -1742,12 +816,6 @@ done:
return status;
}
-int gpio_request(unsigned gpio, const char *label)
-{
- return gpiod_request(gpio_to_desc(gpio), label);
-}
-EXPORT_SYMBOL_GPL(gpio_request);
-
static bool __gpiod_free(struct gpio_desc *desc)
{
bool ret = false;
@@ -1780,7 +848,7 @@ static bool __gpiod_free(struct gpio_desc *desc)
return ret;
}
-static void gpiod_free(struct gpio_desc *desc)
+void gpiod_free(struct gpio_desc *desc)
{
if (desc && __gpiod_free(desc))
module_put(desc->chip->owner);
@@ -1788,101 +856,14 @@ static void gpiod_free(struct gpio_desc *desc)
WARN_ON(extra_checks);
}
-void gpio_free(unsigned gpio)
-{
- gpiod_free(gpio_to_desc(gpio));
-}
-EXPORT_SYMBOL_GPL(gpio_free);
-
-/**
- * gpio_request_one - request a single GPIO with initial configuration
- * @gpio: the GPIO number
- * @flags: GPIO configuration as specified by GPIOF_*
- * @label: a literal description string of this GPIO
- */
-int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
-{
- struct gpio_desc *desc;
- int err;
-
- desc = gpio_to_desc(gpio);
-
- err = gpiod_request(desc, label);
- if (err)
- return err;
-
- if (flags & GPIOF_OPEN_DRAIN)
- set_bit(FLAG_OPEN_DRAIN, &desc->flags);
-
- if (flags & GPIOF_OPEN_SOURCE)
- set_bit(FLAG_OPEN_SOURCE, &desc->flags);
-
- if (flags & GPIOF_DIR_IN)
- err = gpiod_direction_input(desc);
- else
- err = gpiod_direction_output_raw(desc,
- (flags & GPIOF_INIT_HIGH) ? 1 : 0);
-
- if (err)
- goto free_gpio;
-
- if (flags & GPIOF_EXPORT) {
- err = gpiod_export(desc, flags & GPIOF_EXPORT_CHANGEABLE);
- if (err)
- goto free_gpio;
- }
-
- return 0;
-
- free_gpio:
- gpiod_free(desc);
- return err;
-}
-EXPORT_SYMBOL_GPL(gpio_request_one);
-
-/**
- * gpio_request_array - request multiple GPIOs in a single call
- * @array: array of the 'struct gpio'
- * @num: how many GPIOs in the array
- */
-int gpio_request_array(const struct gpio *array, size_t num)
-{
- int i, err;
-
- for (i = 0; i < num; i++, array++) {
- err = gpio_request_one(array->gpio, array->flags, array->label);
- if (err)
- goto err_free;
- }
- return 0;
-
-err_free:
- while (i--)
- gpio_free((--array)->gpio);
- return err;
-}
-EXPORT_SYMBOL_GPL(gpio_request_array);
-
-/**
- * gpio_free_array - release multiple GPIOs in a single call
- * @array: array of the 'struct gpio'
- * @num: how many GPIOs in the array
- */
-void gpio_free_array(const struct gpio *array, size_t num)
-{
- while (num--)
- gpio_free((array++)->gpio);
-}
-EXPORT_SYMBOL_GPL(gpio_free_array);
-
/**
* gpiochip_is_requested - return string iff signal was requested
* @chip: controller managing the signal
* @offset: of signal within controller's 0..(ngpio - 1) range
*
* Returns NULL if the GPIO is not currently requested, else a string.
- * If debugfs support is enabled, the string returned is the label passed
- * to gpio_request(); otherwise it is a meaningless constant.
+ * The string returned is the label passed to gpio_request(); if none has been
+ * passed it is a meaningless, non-NULL constant.
*
* This function is for use by GPIO controller drivers. The label can
* help with diagnostics, and knowing that the signal is used as a GPIO
@@ -1899,11 +880,7 @@ const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset)
if (test_bit(FLAG_REQUESTED, &desc->flags) == 0)
return NULL;
-#ifdef CONFIG_DEBUG_FS
return desc->label;
-#else
- return "?";
-#endif
}
EXPORT_SYMBOL_GPL(gpiochip_is_requested);
@@ -1925,6 +902,7 @@ int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label)
return __gpiod_request(desc, label);
}
+EXPORT_SYMBOL_GPL(gpiochip_request_own_desc);
/**
* gpiochip_free_own_desc - Free GPIO requested by the chip driver
@@ -1938,6 +916,7 @@ void gpiochip_free_own_desc(struct gpio_desc *desc)
if (desc)
__gpiod_free(desc);
}
+EXPORT_SYMBOL_GPL(gpiochip_free_own_desc);
/* Drivers MUST set GPIO direction before making get/set calls. In
* some cases this is done in early boot, before IRQs are enabled.
@@ -1959,10 +938,8 @@ void gpiochip_free_own_desc(struct gpio_desc *desc)
*/
int gpiod_direction_input(struct gpio_desc *desc)
{
- unsigned long flags;
struct gpio_chip *chip;
int status = -EINVAL;
- int offset;
if (!desc || !desc->chip) {
pr_warn("%s: invalid GPIO\n", __func__);
@@ -1977,52 +954,20 @@ int gpiod_direction_input(struct gpio_desc *desc)
return -EIO;
}
- spin_lock_irqsave(&gpio_lock, flags);
-
- status = gpio_ensure_requested(desc);
- if (status < 0)
- goto fail;
-
- /* now we know the gpio is valid and chip won't vanish */
-
- spin_unlock_irqrestore(&gpio_lock, flags);
-
- might_sleep_if(chip->can_sleep);
-
- offset = gpio_chip_hwgpio(desc);
- if (status) {
- status = chip->request(chip, offset);
- if (status < 0) {
- gpiod_dbg(desc, "%s: chip request fail, %d\n",
- __func__, status);
- /* and it's not available to anyone else ...
- * gpio_request() is the fully clean solution.
- */
- goto lose;
- }
- }
-
- status = chip->direction_input(chip, offset);
+ status = chip->direction_input(chip, gpio_chip_hwgpio(desc));
if (status == 0)
clear_bit(FLAG_IS_OUT, &desc->flags);
trace_gpio_direction(desc_to_gpio(desc), 1, status);
-lose:
- return status;
-fail:
- spin_unlock_irqrestore(&gpio_lock, flags);
- if (status)
- gpiod_dbg(desc, "%s: status %d\n", __func__, status);
+
return status;
}
EXPORT_SYMBOL_GPL(gpiod_direction_input);
static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value)
{
- unsigned long flags;
struct gpio_chip *chip;
int status = -EINVAL;
- int offset;
/* GPIOs used for IRQs shall not be set as output */
if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) {
@@ -2048,42 +993,11 @@ static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value)
return -EIO;
}
- spin_lock_irqsave(&gpio_lock, flags);
-
- status = gpio_ensure_requested(desc);
- if (status < 0)
- goto fail;
-
- /* now we know the gpio is valid and chip won't vanish */
-
- spin_unlock_irqrestore(&gpio_lock, flags);
-
- might_sleep_if(chip->can_sleep);
-
- offset = gpio_chip_hwgpio(desc);
- if (status) {
- status = chip->request(chip, offset);
- if (status < 0) {
- gpiod_dbg(desc, "%s: chip request fail, %d\n",
- __func__, status);
- /* and it's not available to anyone else ...
- * gpio_request() is the fully clean solution.
- */
- goto lose;
- }
- }
-
- status = chip->direction_output(chip, offset, value);
+ status = chip->direction_output(chip, gpio_chip_hwgpio(desc), value);
if (status == 0)
set_bit(FLAG_IS_OUT, &desc->flags);
trace_gpio_value(desc_to_gpio(desc), 0, value);
trace_gpio_direction(desc_to_gpio(desc), 0, status);
-lose:
- return status;
-fail:
- spin_unlock_irqrestore(&gpio_lock, flags);
- if (status)
- gpiod_dbg(desc, "%s: gpio status %d\n", __func__, status);
return status;
}
@@ -2142,10 +1056,7 @@ EXPORT_SYMBOL_GPL(gpiod_direction_output);
*/
int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
{
- unsigned long flags;
struct gpio_chip *chip;
- int status = -EINVAL;
- int offset;
if (!desc || !desc->chip) {
pr_warn("%s: invalid GPIO\n", __func__);
@@ -2160,27 +1071,7 @@ int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
return -ENOTSUPP;
}
- spin_lock_irqsave(&gpio_lock, flags);
-
- status = gpio_ensure_requested(desc);
- if (status < 0)
- goto fail;
-
- /* now we know the gpio is valid and chip won't vanish */
-
- spin_unlock_irqrestore(&gpio_lock, flags);
-
- might_sleep_if(chip->can_sleep);
-
- offset = gpio_chip_hwgpio(desc);
- return chip->set_debounce(chip, offset, debounce);
-
-fail:
- spin_unlock_irqrestore(&gpio_lock, flags);
- if (status)
- gpiod_dbg(desc, "%s: status %d\n", __func__, status);
-
- return status;
+ return chip->set_debounce(chip, gpio_chip_hwgpio(desc), debounce);
}
EXPORT_SYMBOL_GPL(gpiod_set_debounce);
@@ -2423,54 +1314,44 @@ int gpiod_to_irq(const struct gpio_desc *desc)
EXPORT_SYMBOL_GPL(gpiod_to_irq);
/**
- * gpiod_lock_as_irq() - lock a GPIO to be used as IRQ
- * @gpio: the GPIO line to lock as used for IRQ
+ * gpio_lock_as_irq() - lock a GPIO to be used as IRQ
+ * @chip: the chip the GPIO to lock belongs to
+ * @offset: the offset of the GPIO to lock as IRQ
*
* This is used directly by GPIO drivers that want to lock down
* a certain GPIO line to be used for IRQs.
*/
-int gpiod_lock_as_irq(struct gpio_desc *desc)
+int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
{
- if (!desc)
+ if (offset >= chip->ngpio)
return -EINVAL;
- if (test_bit(FLAG_IS_OUT, &desc->flags)) {
- gpiod_err(desc,
+ if (test_bit(FLAG_IS_OUT, &chip->desc[offset].flags)) {
+ chip_err(chip,
"%s: tried to flag a GPIO set as output for IRQ\n",
__func__);
return -EIO;
}
- set_bit(FLAG_USED_AS_IRQ, &desc->flags);
+ set_bit(FLAG_USED_AS_IRQ, &chip->desc[offset].flags);
return 0;
}
-EXPORT_SYMBOL_GPL(gpiod_lock_as_irq);
-
-int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
-{
- return gpiod_lock_as_irq(gpiochip_get_desc(chip, offset));
-}
EXPORT_SYMBOL_GPL(gpio_lock_as_irq);
/**
- * gpiod_unlock_as_irq() - unlock a GPIO used as IRQ
- * @gpio: the GPIO line to unlock from IRQ usage
+ * gpio_unlock_as_irq() - unlock a GPIO used as IRQ
+ * @chip: the chip the GPIO to lock belongs to
+ * @offset: the offset of the GPIO to lock as IRQ
*
* This is used directly by GPIO drivers that want to indicate
* that a certain GPIO is no longer used exclusively for IRQ.
*/
-void gpiod_unlock_as_irq(struct gpio_desc *desc)
+void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset)
{
- if (!desc)
+ if (offset >= chip->ngpio)
return;
- clear_bit(FLAG_USED_AS_IRQ, &desc->flags);
-}
-EXPORT_SYMBOL_GPL(gpiod_unlock_as_irq);
-
-void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset)
-{
- return gpiod_unlock_as_irq(gpiochip_get_desc(chip, offset));
+ clear_bit(FLAG_USED_AS_IRQ, &chip->desc[offset].flags);
}
EXPORT_SYMBOL_GPL(gpio_unlock_as_irq);
@@ -2571,22 +1452,27 @@ void gpiod_add_lookup_table(struct gpiod_lookup_table *table)
mutex_unlock(&gpio_lookup_lock);
}
-#ifdef CONFIG_OF
static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
unsigned int idx,
enum gpio_lookup_flags *flags)
{
+ static const char *suffixes[] = { "gpios", "gpio" };
char prop_name[32]; /* 32 is max size of property name */
enum of_gpio_flags of_flags;
struct gpio_desc *desc;
+ unsigned int i;
- if (con_id)
- snprintf(prop_name, 32, "%s-gpios", con_id);
- else
- snprintf(prop_name, 32, "gpios");
+ for (i = 0; i < ARRAY_SIZE(suffixes); i++) {
+ if (con_id)
+ snprintf(prop_name, 32, "%s-%s", con_id, suffixes[i]);
+ else
+ snprintf(prop_name, 32, "%s", suffixes[i]);
- desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx,
- &of_flags);
+ desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx,
+ &of_flags);
+ if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER))
+ break;
+ }
if (IS_ERR(desc))
return desc;
@@ -2596,14 +1482,6 @@ static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
return desc;
}
-#else
-static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
- unsigned int idx,
- enum gpio_lookup_flags *flags)
-{
- return ERR_PTR(-ENODEV);
-}
-#endif
static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
unsigned int idx,
@@ -2701,25 +1579,46 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
}
/**
- * gpio_get - obtain a GPIO for a given GPIO function
+ * gpiod_get - obtain a GPIO for a given GPIO function
* @dev: GPIO consumer, can be NULL for system-global GPIOs
* @con_id: function within the GPIO consumer
+ * @flags: optional GPIO initialization flags
*
* Return the GPIO descriptor corresponding to the function con_id of device
* dev, -ENOENT if no GPIO has been assigned to the requested function, or
* another IS_ERR() code if an error occured while trying to acquire the GPIO.
*/
-struct gpio_desc *__must_check gpiod_get(struct device *dev, const char *con_id)
+struct gpio_desc *__must_check __gpiod_get(struct device *dev, const char *con_id,
+ enum gpiod_flags flags)
{
- return gpiod_get_index(dev, con_id, 0);
+ return gpiod_get_index(dev, con_id, 0, flags);
}
-EXPORT_SYMBOL_GPL(gpiod_get);
+EXPORT_SYMBOL_GPL(__gpiod_get);
+
+/**
+ * gpiod_get_optional - obtain an optional GPIO for a given GPIO function
+ * @dev: GPIO consumer, can be NULL for system-global GPIOs
+ * @con_id: function within the GPIO consumer
+ * @flags: optional GPIO initialization flags
+ *
+ * This is equivalent to gpiod_get(), except that when no GPIO was assigned to
+ * the requested function it will return NULL. This is convenient for drivers
+ * that need to handle optional GPIOs.
+ */
+struct gpio_desc *__must_check __gpiod_get_optional(struct device *dev,
+ const char *con_id,
+ enum gpiod_flags flags)
+{
+ return gpiod_get_index_optional(dev, con_id, 0, flags);
+}
+EXPORT_SYMBOL_GPL(__gpiod_get_optional);
/**
* gpiod_get_index - obtain a GPIO from a multi-index GPIO function
* @dev: GPIO consumer, can be NULL for system-global GPIOs
* @con_id: function within the GPIO consumer
* @idx: index of the GPIO to obtain in the consumer
+ * @flags: optional GPIO initialization flags
*
* This variant of gpiod_get() allows to access GPIOs other than the first
* defined one for functions that define several GPIOs.
@@ -2728,23 +1627,24 @@ EXPORT_SYMBOL_GPL(gpiod_get);
* requested function and/or index, or another IS_ERR() code if an error
* occured while trying to acquire the GPIO.
*/
-struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
+struct gpio_desc *__must_check __gpiod_get_index(struct device *dev,
const char *con_id,
- unsigned int idx)
+ unsigned int idx,
+ enum gpiod_flags flags)
{
struct gpio_desc *desc = NULL;
int status;
- enum gpio_lookup_flags flags = 0;
+ enum gpio_lookup_flags lookupflags = 0;
dev_dbg(dev, "GPIO lookup for consumer %s\n", con_id);
/* Using device tree? */
if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node) {
dev_dbg(dev, "using device tree for GPIO lookup\n");
- desc = of_find_gpio(dev, con_id, idx, &flags);
+ desc = of_find_gpio(dev, con_id, idx, &lookupflags);
} else if (IS_ENABLED(CONFIG_ACPI) && dev && ACPI_HANDLE(dev)) {
dev_dbg(dev, "using ACPI for GPIO lookup\n");
- desc = acpi_find_gpio(dev, con_id, idx, &flags);
+ desc = acpi_find_gpio(dev, con_id, idx, &lookupflags);
}
/*
@@ -2753,7 +1653,7 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
*/
if (!desc || desc == ERR_PTR(-ENOENT)) {
dev_dbg(dev, "using lookup tables for GPIO lookup");
- desc = gpiod_find(dev, con_id, idx, &flags);
+ desc = gpiod_find(dev, con_id, idx, &lookupflags);
}
if (IS_ERR(desc)) {
@@ -2766,16 +1666,62 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
if (status < 0)
return ERR_PTR(status);
- if (flags & GPIO_ACTIVE_LOW)
+ if (lookupflags & GPIO_ACTIVE_LOW)
set_bit(FLAG_ACTIVE_LOW, &desc->flags);
- if (flags & GPIO_OPEN_DRAIN)
+ if (lookupflags & GPIO_OPEN_DRAIN)
set_bit(FLAG_OPEN_DRAIN, &desc->flags);
- if (flags & GPIO_OPEN_SOURCE)
+ if (lookupflags & GPIO_OPEN_SOURCE)
set_bit(FLAG_OPEN_SOURCE, &desc->flags);
+ /* No particular flag request, return here... */
+ if (flags & GPIOD_FLAGS_BIT_DIR_SET)
+ return desc;
+
+ /* Process flags */
+ if (flags & GPIOD_FLAGS_BIT_DIR_OUT)
+ status = gpiod_direction_output(desc,
+ flags & GPIOD_FLAGS_BIT_DIR_VAL);
+ else
+ status = gpiod_direction_input(desc);
+
+ if (status < 0) {
+ dev_dbg(dev, "setup of GPIO %s failed\n", con_id);
+ gpiod_put(desc);
+ return ERR_PTR(status);
+ }
+
+ return desc;
+}
+EXPORT_SYMBOL_GPL(__gpiod_get_index);
+
+/**
+ * gpiod_get_index_optional - obtain an optional GPIO from a multi-index GPIO
+ * function
+ * @dev: GPIO consumer, can be NULL for system-global GPIOs
+ * @con_id: function within the GPIO consumer
+ * @index: index of the GPIO to obtain in the consumer
+ * @flags: optional GPIO initialization flags
+ *
+ * This is equivalent to gpiod_get_index(), except that when no GPIO with the
+ * specified index was assigned to the requested function it will return NULL.
+ * This is convenient for drivers that need to handle optional GPIOs.
+ */
+struct gpio_desc *__must_check __gpiod_get_index_optional(struct device *dev,
+ const char *con_id,
+ unsigned int index,
+ enum gpiod_flags flags)
+{
+ struct gpio_desc *desc;
+
+ desc = gpiod_get_index(dev, con_id, index, flags);
+ if (IS_ERR(desc)) {
+ if (PTR_ERR(desc) == -ENOENT)
+ return NULL;
+ }
+
return desc;
}
-EXPORT_SYMBOL_GPL(gpiod_get_index);
+EXPORT_SYMBOL_GPL(__gpiod_get_index_optional);
/**
* gpiod_put - dispose of a GPIO descriptor
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index cf092941a9fd..9db2b6a71c5d 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -15,6 +15,8 @@
#include <linux/err.h>
#include <linux/device.h>
+enum of_gpio_flags;
+
/**
* struct acpi_gpio_info - ACPI GPIO specific information
* @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo
@@ -29,12 +31,21 @@ struct acpi_gpio_info {
void acpi_gpiochip_add(struct gpio_chip *chip);
void acpi_gpiochip_remove(struct gpio_chip *chip);
+void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
+void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);
+
struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,
struct acpi_gpio_info *info);
#else
static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { }
+static inline void
+acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { }
+
+static inline void
+acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { }
+
static inline struct gpio_desc *
acpi_get_gpiod_by_index(struct device *dev, int index,
struct acpi_gpio_info *info)
@@ -43,7 +54,100 @@ acpi_get_gpiod_by_index(struct device *dev, int index,
}
#endif
-int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label);
-void gpiochip_free_own_desc(struct gpio_desc *desc);
+struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
+ const char *list_name, int index, enum of_gpio_flags *flags);
+
+struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum);
+
+extern struct spinlock gpio_lock;
+extern struct list_head gpio_chips;
+
+struct gpio_desc {
+ struct gpio_chip *chip;
+ unsigned long flags;
+/* flag symbols are bit numbers */
+#define FLAG_REQUESTED 0
+#define FLAG_IS_OUT 1
+#define FLAG_EXPORT 2 /* protected by sysfs_lock */
+#define FLAG_SYSFS 3 /* exported via /sys/class/gpio/control */
+#define FLAG_TRIG_FALL 4 /* trigger on falling edge */
+#define FLAG_TRIG_RISE 5 /* trigger on rising edge */
+#define FLAG_ACTIVE_LOW 6 /* value has active low */
+#define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */
+#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */
+#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */
+
+#define ID_SHIFT 16 /* add new flags before this one */
+
+#define GPIO_FLAGS_MASK ((1 << ID_SHIFT) - 1)
+#define GPIO_TRIGGER_MASK (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))
+
+ const char *label;
+};
+
+int gpiod_request(struct gpio_desc *desc, const char *label);
+void gpiod_free(struct gpio_desc *desc);
+
+/*
+ * Return the GPIO number of the passed descriptor relative to its chip
+ */
+static int __maybe_unused gpio_chip_hwgpio(const struct gpio_desc *desc)
+{
+ return desc - &desc->chip->desc[0];
+}
+
+/* With descriptor prefix */
+
+#define gpiod_emerg(desc, fmt, ...) \
+ pr_emerg("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",\
+ ##__VA_ARGS__)
+#define gpiod_crit(desc, fmt, ...) \
+ pr_crit("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \
+ ##__VA_ARGS__)
+#define gpiod_err(desc, fmt, ...) \
+ pr_err("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \
+ ##__VA_ARGS__)
+#define gpiod_warn(desc, fmt, ...) \
+ pr_warn("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \
+ ##__VA_ARGS__)
+#define gpiod_info(desc, fmt, ...) \
+ pr_info("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \
+ ##__VA_ARGS__)
+#define gpiod_dbg(desc, fmt, ...) \
+ pr_debug("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",\
+ ##__VA_ARGS__)
+
+/* With chip prefix */
+
+#define chip_emerg(chip, fmt, ...) \
+ pr_emerg("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
+#define chip_crit(chip, fmt, ...) \
+ pr_crit("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
+#define chip_err(chip, fmt, ...) \
+ pr_err("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
+#define chip_warn(chip, fmt, ...) \
+ pr_warn("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
+#define chip_info(chip, fmt, ...) \
+ pr_info("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
+#define chip_dbg(chip, fmt, ...) \
+ pr_debug("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
+
+#ifdef CONFIG_GPIO_SYSFS
+
+int gpiochip_export(struct gpio_chip *chip);
+void gpiochip_unexport(struct gpio_chip *chip);
+
+#else
+
+static inline int gpiochip_export(struct gpio_chip *chip)
+{
+ return 0;
+}
+
+static inline void gpiochip_unexport(struct gpio_chip *chip)
+{
+}
+
+#endif /* CONFIG_GPIO_SYSFS */
#endif /* GPIOLIB_H */
OpenPOWER on IntegriCloud