summaryrefslogtreecommitdiff
path: root/drivers/gpio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/Kconfig23
-rw-r--r--drivers/gpio/Makefile3
-rw-r--r--drivers/gpio/gpio-74x164.c8
-rw-r--r--drivers/gpio/gpio-adp5520.c4
-rw-r--r--drivers/gpio/gpio-em.c94
-rw-r--r--drivers/gpio/gpio-generic.c62
-rw-r--r--drivers/gpio/gpio-grgpio.c505
-rw-r--r--drivers/gpio/gpio-ich.c19
-rw-r--r--drivers/gpio/gpio-lpc32xx.c2
-rw-r--r--drivers/gpio/gpio-lynxpoint.c1
-rw-r--r--drivers/gpio/gpio-max7300.c4
-rw-r--r--drivers/gpio/gpio-max7301.c7
-rw-r--r--drivers/gpio/gpio-max732x.c5
-rw-r--r--drivers/gpio/gpio-mc33880.c19
-rw-r--r--drivers/gpio/gpio-mcp23s08.c137
-rw-r--r--drivers/gpio/gpio-msm-v1.c220
-rw-r--r--drivers/gpio/gpio-msm-v2.c3
-rw-r--r--drivers/gpio/gpio-mvebu.c85
-rw-r--r--drivers/gpio/gpio-mxc.c2
-rw-r--r--drivers/gpio/gpio-omap.c119
-rw-r--r--drivers/gpio/gpio-pca953x.c5
-rw-r--r--drivers/gpio/gpio-pcf857x.c8
-rw-r--r--drivers/gpio/gpio-pl061.c127
-rw-r--r--drivers/gpio/gpio-pxa.c165
-rw-r--r--drivers/gpio/gpio-rcar.c396
-rw-r--r--drivers/gpio/gpio-samsung.c10
-rw-r--r--drivers/gpio/gpio-sch.c111
-rw-r--r--drivers/gpio/gpio-stmpe.c15
-rw-r--r--drivers/gpio/gpio-stp-xway.c2
-rw-r--r--drivers/gpio/gpio-tc3589x.c8
-rw-r--r--drivers/gpio/gpio-tegra.c35
-rw-r--r--drivers/gpio/gpio-timberdale.c3
-rw-r--r--drivers/gpio/gpio-tps65910.c2
-rw-r--r--drivers/gpio/gpio-ucb1400.c19
-rw-r--r--drivers/gpio/gpio-viperboard.c4
-rw-r--r--drivers/gpio/gpio-vt8500.c355
-rw-r--r--drivers/gpio/gpiolib-acpi.c217
-rw-r--r--drivers/gpio/gpiolib-of.c22
38 files changed, 1958 insertions, 868 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 5d53aba8e1c6..87d567089f13 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -203,6 +203,12 @@ config GPIO_PXA
help
Say yes here to support the PXA GPIO device
+config GPIO_RCAR
+ tristate "Renesas R-Car GPIO"
+ depends on ARM
+ help
+ Say yes here to support GPIO on Renesas R-Car SoCs.
+
config GPIO_SPEAR_SPICS
bool "ST SPEAr13xx SPI Chip Select as GPIO support"
depends on PLAT_SPEAR
@@ -226,12 +232,6 @@ config GPIO_TS5500
blocks of the TS-5500: DIO1, DIO2 and the LCD port, and the TS-5600
LCD port.
-config GPIO_VT8500
- bool "VIA/Wondermedia SoC GPIO Support"
- depends on ARCH_VT8500
- help
- Say yes here to support the VT8500/WM8505/WM8650 GPIO controller.
-
config GPIO_XILINX
bool "Xilinx GPIO support"
depends on PPC_OF || MICROBLAZE
@@ -302,12 +302,21 @@ config GPIO_GE_FPGA
config GPIO_LYNXPOINT
bool "Intel Lynxpoint GPIO support"
- depends on ACPI
+ depends on ACPI && X86
select IRQ_DOMAIN
help
driver for GPIO functionality on Intel Lynxpoint PCH chipset
Requires ACPI device enumeration code to set up a platform device.
+config GPIO_GRGPIO
+ tristate "Aeroflex Gaisler GRGPIO support"
+ depends on OF
+ select GPIO_GENERIC
+ select IRQ_DOMAIN
+ help
+ Select this to support Aeroflex Gaisler GRGPIO cores from the GRLIB
+ VHDL IP core library.
+
comment "I2C GPIO expanders:"
config GPIO_ARIZONA
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 22e07bc9fcb5..0cb2d656ad16 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o
obj-$(CONFIG_GPIO_EM) += gpio-em.o
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
+obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o
obj-$(CONFIG_GPIO_ICH) += gpio-ich.o
obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o
obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o
@@ -57,6 +58,7 @@ obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o
obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o
+obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o
obj-$(CONFIG_PLAT_SAMSUNG) += gpio-samsung.o
obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
obj-$(CONFIG_GPIO_SCH) += gpio-sch.o
@@ -80,7 +82,6 @@ obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o
obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o
obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o
obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o
-obj-$(CONFIG_GPIO_VT8500) += gpio-vt8500.o
obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o
obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o
obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o
diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c
index 464be961f605..721607904d0a 100644
--- a/drivers/gpio/gpio-74x164.c
+++ b/drivers/gpio/gpio-74x164.c
@@ -137,7 +137,7 @@ static int gen_74x164_probe(struct spi_device *spi)
mutex_init(&chip->lock);
- dev_set_drvdata(&spi->dev, chip);
+ spi_set_drvdata(spi, chip);
chip->spi = spi;
@@ -176,7 +176,7 @@ static int gen_74x164_probe(struct spi_device *spi)
return ret;
exit_destroy:
- dev_set_drvdata(&spi->dev, NULL);
+ spi_set_drvdata(spi, NULL);
mutex_destroy(&chip->lock);
return ret;
}
@@ -186,11 +186,11 @@ static int gen_74x164_remove(struct spi_device *spi)
struct gen_74x164_chip *chip;
int ret;
- chip = dev_get_drvdata(&spi->dev);
+ chip = spi_get_drvdata(spi);
if (chip == NULL)
return -ENODEV;
- dev_set_drvdata(&spi->dev, NULL);
+ spi_set_drvdata(spi, NULL);
ret = gpiochip_remove(&chip->gpio_chip);
if (!ret)
diff --git a/drivers/gpio/gpio-adp5520.c b/drivers/gpio/gpio-adp5520.c
index 8afa95f831b1..f33f78dcadaa 100644
--- a/drivers/gpio/gpio-adp5520.c
+++ b/drivers/gpio/gpio-adp5520.c
@@ -105,7 +105,7 @@ static int adp5520_gpio_probe(struct platform_device *pdev)
return -ENODEV;
}
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
dev_err(&pdev->dev, "failed to alloc memory\n");
return -ENOMEM;
@@ -163,7 +163,6 @@ static int adp5520_gpio_probe(struct platform_device *pdev)
return 0;
err:
- kfree(dev);
return ret;
}
@@ -180,7 +179,6 @@ static int adp5520_gpio_remove(struct platform_device *pdev)
return ret;
}
- kfree(dev);
return 0;
}
diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c
index deca78f99316..5cba855638bf 100644
--- a/drivers/gpio/gpio-em.c
+++ b/drivers/gpio/gpio-em.c
@@ -231,10 +231,12 @@ static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int virq,
static struct irq_domain_ops em_gio_irq_domain_ops = {
.map = em_gio_irq_domain_map,
+ .xlate = irq_domain_xlate_twocell,
};
static int em_gio_probe(struct platform_device *pdev)
{
+ struct gpio_em_config pdata_dt;
struct gpio_em_config *pdata = pdev->dev.platform_data;
struct em_gio_priv *p;
struct resource *io[2], *irq[2];
@@ -243,7 +245,7 @@ static int em_gio_probe(struct platform_device *pdev)
const char *name = dev_name(&pdev->dev);
int ret;
- p = kzalloc(sizeof(*p), GFP_KERNEL);
+ p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
if (!p) {
dev_err(&pdev->dev, "failed to allocate driver data\n");
ret = -ENOMEM;
@@ -259,24 +261,45 @@ static int em_gio_probe(struct platform_device *pdev)
irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
- if (!io[0] || !io[1] || !irq[0] || !irq[1] || !pdata) {
- dev_err(&pdev->dev, "missing IRQ, IOMEM or configuration\n");
+ if (!io[0] || !io[1] || !irq[0] || !irq[1]) {
+ dev_err(&pdev->dev, "missing IRQ or IOMEM\n");
ret = -EINVAL;
- goto err1;
+ goto err0;
}
- p->base0 = ioremap_nocache(io[0]->start, resource_size(io[0]));
+ p->base0 = devm_ioremap_nocache(&pdev->dev, io[0]->start,
+ resource_size(io[0]));
if (!p->base0) {
dev_err(&pdev->dev, "failed to remap low I/O memory\n");
ret = -ENXIO;
- goto err1;
+ goto err0;
}
- p->base1 = ioremap_nocache(io[1]->start, resource_size(io[1]));
+ p->base1 = devm_ioremap_nocache(&pdev->dev, io[1]->start,
+ resource_size(io[1]));
if (!p->base1) {
dev_err(&pdev->dev, "failed to remap high I/O memory\n");
ret = -ENXIO;
- goto err2;
+ goto err0;
+ }
+
+ if (!pdata) {
+ memset(&pdata_dt, 0, sizeof(pdata_dt));
+ pdata = &pdata_dt;
+
+ if (of_property_read_u32(pdev->dev.of_node, "ngpios",
+ &pdata->number_of_pins)) {
+ dev_err(&pdev->dev, "Missing ngpios OF property\n");
+ ret = -EINVAL;
+ goto err0;
+ }
+
+ ret = of_alias_get_id(pdev->dev.of_node, "gpio");
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Couldn't get OF id\n");
+ goto err0;
+ }
+ pdata->gpio_base = ret * 32; /* 32 GPIOs per instance */
}
gpio_chip = &p->gpio_chip;
@@ -306,40 +329,32 @@ static int em_gio_probe(struct platform_device *pdev)
if (!p->irq_domain) {
ret = -ENXIO;
dev_err(&pdev->dev, "cannot initialize irq domain\n");
- goto err3;
+ goto err0;
}
- if (request_irq(irq[0]->start, em_gio_irq_handler, 0, name, p)) {
+ if (devm_request_irq(&pdev->dev, irq[0]->start,
+ em_gio_irq_handler, 0, name, p)) {
dev_err(&pdev->dev, "failed to request low IRQ\n");
ret = -ENOENT;
- goto err4;
+ goto err1;
}
- if (request_irq(irq[1]->start, em_gio_irq_handler, 0, name, p)) {
+ if (devm_request_irq(&pdev->dev, irq[1]->start,
+ em_gio_irq_handler, 0, name, p)) {
dev_err(&pdev->dev, "failed to request high IRQ\n");
ret = -ENOENT;
- goto err5;
+ goto err1;
}
ret = gpiochip_add(gpio_chip);
if (ret) {
dev_err(&pdev->dev, "failed to add GPIO controller\n");
- goto err6;
+ goto err1;
}
return 0;
-err6:
- free_irq(irq[1]->start, pdev);
-err5:
- free_irq(irq[0]->start, pdev);
-err4:
- irq_domain_remove(p->irq_domain);
-err3:
- iounmap(p->base1);
-err2:
- iounmap(p->base0);
err1:
- kfree(p);
+ irq_domain_remove(p->irq_domain);
err0:
return ret;
}
@@ -347,34 +362,43 @@ err0:
static int em_gio_remove(struct platform_device *pdev)
{
struct em_gio_priv *p = platform_get_drvdata(pdev);
- struct resource *irq[2];
int ret;
ret = gpiochip_remove(&p->gpio_chip);
if (ret)
return ret;
- irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
-
- free_irq(irq[1]->start, pdev);
- free_irq(irq[0]->start, pdev);
irq_domain_remove(p->irq_domain);
- iounmap(p->base1);
- iounmap(p->base0);
- kfree(p);
return 0;
}
+static const struct of_device_id em_gio_dt_ids[] = {
+ { .compatible = "renesas,em-gio", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, em_gio_dt_ids);
+
static struct platform_driver em_gio_device_driver = {
.probe = em_gio_probe,
.remove = em_gio_remove,
.driver = {
.name = "em_gio",
+ .of_match_table = em_gio_dt_ids,
+ .owner = THIS_MODULE,
}
};
-module_platform_driver(em_gio_device_driver);
+static int __init em_gio_init(void)
+{
+ return platform_driver_register(&em_gio_device_driver);
+}
+postcore_initcall(em_gio_init);
+
+static void __exit em_gio_exit(void)
+{
+ platform_driver_unregister(&em_gio_device_driver);
+}
+module_exit(em_gio_exit);
MODULE_AUTHOR("Magnus Damm");
MODULE_DESCRIPTION("Renesas Emma Mobile GIO Driver");
diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c
index 05fcc0f247ca..d2196bf73847 100644
--- a/drivers/gpio/gpio-generic.c
+++ b/drivers/gpio/gpio-generic.c
@@ -104,6 +104,26 @@ static unsigned long bgpio_read64(void __iomem *reg)
}
#endif /* BITS_PER_LONG >= 64 */
+static void bgpio_write16be(void __iomem *reg, unsigned long data)
+{
+ iowrite16be(data, reg);
+}
+
+static unsigned long bgpio_read16be(void __iomem *reg)
+{
+ return ioread16be(reg);
+}
+
+static void bgpio_write32be(void __iomem *reg, unsigned long data)
+{
+ iowrite32be(data, reg);
+}
+
+static unsigned long bgpio_read32be(void __iomem *reg)
+{
+ return ioread32be(reg);
+}
+
static unsigned long bgpio_pin2mask(struct bgpio_chip *bgc, unsigned int pin)
{
return 1 << pin;
@@ -249,7 +269,8 @@ static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val)
static int bgpio_setup_accessors(struct device *dev,
struct bgpio_chip *bgc,
- bool be)
+ bool bit_be,
+ bool byte_be)
{
switch (bgc->bits) {
@@ -258,17 +279,33 @@ static int bgpio_setup_accessors(struct device *dev,
bgc->write_reg = bgpio_write8;
break;
case 16:
- bgc->read_reg = bgpio_read16;
- bgc->write_reg = bgpio_write16;
+ if (byte_be) {
+ bgc->read_reg = bgpio_read16be;
+ bgc->write_reg = bgpio_write16be;
+ } else {
+ bgc->read_reg = bgpio_read16;
+ bgc->write_reg = bgpio_write16;
+ }
break;
case 32:
- bgc->read_reg = bgpio_read32;
- bgc->write_reg = bgpio_write32;
+ if (byte_be) {
+ bgc->read_reg = bgpio_read32be;
+ bgc->write_reg = bgpio_write32be;
+ } else {
+ bgc->read_reg = bgpio_read32;
+ bgc->write_reg = bgpio_write32;
+ }
break;
#if BITS_PER_LONG >= 64
case 64:
- bgc->read_reg = bgpio_read64;
- bgc->write_reg = bgpio_write64;
+ if (byte_be) {
+ dev_err(dev,
+ "64 bit big endian byte order unsupported\n");
+ return -EINVAL;
+ } else {
+ bgc->read_reg = bgpio_read64;
+ bgc->write_reg = bgpio_write64;
+ }
break;
#endif /* BITS_PER_LONG >= 64 */
default:
@@ -276,7 +313,7 @@ static int bgpio_setup_accessors(struct device *dev,
return -EINVAL;
}
- bgc->pin2mask = be ? bgpio_pin2mask_be : bgpio_pin2mask;
+ bgc->pin2mask = bit_be ? bgpio_pin2mask_be : bgpio_pin2mask;
return 0;
}
@@ -353,11 +390,7 @@ static int bgpio_setup_direction(struct bgpio_chip *bgc,
int bgpio_remove(struct bgpio_chip *bgc)
{
- int err = gpiochip_remove(&bgc->gc);
-
- kfree(bgc);
-
- return err;
+ return gpiochip_remove(&bgc->gc);
}
EXPORT_SYMBOL_GPL(bgpio_remove);
@@ -385,7 +418,8 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
if (ret)
return ret;
- ret = bgpio_setup_accessors(dev, bgc, flags & BGPIOF_BIG_ENDIAN);
+ ret = bgpio_setup_accessors(dev, bgc, flags & BGPIOF_BIG_ENDIAN,
+ flags & BGPIOF_BIG_ENDIAN_BYTE_ORDER);
if (ret)
return ret;
diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c
new file mode 100644
index 000000000000..8e08b8647655
--- /dev/null
+++ b/drivers/gpio/gpio-grgpio.c
@@ -0,0 +1,505 @@
+/*
+ * Driver for Aeroflex Gaisler GRGPIO General Purpose I/O cores.
+ *
+ * 2013 (c) Aeroflex Gaisler AB
+ *
+ * This driver supports the GRGPIO GPIO core available in the GRLIB VHDL
+ * IP core library.
+ *
+ * Full documentation of the GRGPIO core can be found here:
+ * http://www.gaisler.com/products/grlib/grip.pdf
+ *
+ * See "Documentation/devicetree/bindings/gpio/gpio-grgpio.txt" for
+ * information on open firmware properties.
+ *
+ * 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.
+ *
+ * Contributors: Andreas Larsson <andreas@gaisler.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/basic_mmio_gpio.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+
+#define GRGPIO_MAX_NGPIO 32
+
+#define GRGPIO_DATA 0x00
+#define GRGPIO_OUTPUT 0x04
+#define GRGPIO_DIR 0x08
+#define GRGPIO_IMASK 0x0c
+#define GRGPIO_IPOL 0x10
+#define GRGPIO_IEDGE 0x14
+#define GRGPIO_BYPASS 0x18
+#define GRGPIO_IMAP_BASE 0x20
+
+/* Structure for an irq of the core - called an underlying irq */
+struct grgpio_uirq {
+ u8 refcnt; /* Reference counter to manage requesting/freeing of uirq */
+ u8 uirq; /* Underlying irq of the gpio driver */
+};
+
+/*
+ * Structure for an irq of a gpio line handed out by this driver. The index is
+ * used to map to the corresponding underlying irq.
+ */
+struct grgpio_lirq {
+ s8 index; /* Index into struct grgpio_priv's uirqs, or -1 */
+ u8 irq; /* irq for the gpio line */
+};
+
+struct grgpio_priv {
+ struct bgpio_chip bgc;
+ void __iomem *regs;
+ struct device *dev;
+
+ u32 imask; /* irq mask shadow register */
+
+ /*
+ * The grgpio core can have multiple "underlying" irqs. The gpio lines
+ * can be mapped to any one or none of these underlying irqs
+ * independently of each other. This driver sets up an irq domain and
+ * hands out separate irqs to each gpio line
+ */
+ struct irq_domain *domain;
+
+ /*
+ * This array contains information on each underlying irq, each
+ * irq of the grgpio core itself.
+ */
+ struct grgpio_uirq uirqs[GRGPIO_MAX_NGPIO];
+
+ /*
+ * This array contains information for each gpio line on the irqs
+ * obtains from this driver. An index value of -1 for a certain gpio
+ * line indicates that the line has no irq. Otherwise the index connects
+ * the irq to the underlying irq by pointing into the uirqs array.
+ */
+ struct grgpio_lirq lirqs[GRGPIO_MAX_NGPIO];
+};
+
+static inline struct grgpio_priv *grgpio_gc_to_priv(struct gpio_chip *gc)
+{
+ struct bgpio_chip *bgc = to_bgpio_chip(gc);
+
+ return container_of(bgc, struct grgpio_priv, bgc);
+}
+
+static void grgpio_set_imask(struct grgpio_priv *priv, unsigned int offset,
+ int val)
+{
+ struct bgpio_chip *bgc = &priv->bgc;
+ unsigned long mask = bgc->pin2mask(bgc, offset);
+ unsigned long flags;
+
+ spin_lock_irqsave(&bgc->lock, flags);
+
+ if (val)
+ priv->imask |= mask;
+ else
+ priv->imask &= ~mask;
+ bgc->write_reg(priv->regs + GRGPIO_IMASK, priv->imask);
+
+ spin_unlock_irqrestore(&bgc->lock, flags);
+}
+
+static int grgpio_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+ struct grgpio_priv *priv = grgpio_gc_to_priv(gc);
+
+ if (offset > gc->ngpio)
+ return -ENXIO;
+
+ if (priv->lirqs[offset].index < 0)
+ return -ENXIO;
+
+ return irq_create_mapping(priv->domain, offset);
+}
+
+/* -------------------- IRQ chip functions -------------------- */
+
+static int grgpio_irq_set_type(struct irq_data *d, unsigned int type)
+{
+ struct grgpio_priv *priv = irq_data_get_irq_chip_data(d);
+ unsigned long flags;
+ u32 mask = BIT(d->hwirq);
+ u32 ipol;
+ u32 iedge;
+ u32 pol;
+ u32 edge;
+
+ switch (type) {
+ case IRQ_TYPE_LEVEL_LOW:
+ pol = 0;
+ edge = 0;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ pol = mask;
+ edge = 0;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ pol = 0;
+ edge = mask;
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ pol = mask;
+ edge = mask;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&priv->bgc.lock, flags);
+
+ ipol = priv->bgc.read_reg(priv->regs + GRGPIO_IPOL) & ~mask;
+ iedge = priv->bgc.read_reg(priv->regs + GRGPIO_IEDGE) & ~mask;
+
+ priv->bgc.write_reg(priv->regs + GRGPIO_IPOL, ipol | pol);
+ priv->bgc.write_reg(priv->regs + GRGPIO_IEDGE, iedge | edge);
+
+ spin_unlock_irqrestore(&priv->bgc.lock, flags);
+
+ return 0;
+}
+
+static void grgpio_irq_mask(struct irq_data *d)
+{
+ struct grgpio_priv *priv = irq_data_get_irq_chip_data(d);
+ int offset = d->hwirq;
+
+ grgpio_set_imask(priv, offset, 0);
+}
+
+static void grgpio_irq_unmask(struct irq_data *d)
+{
+ struct grgpio_priv *priv = irq_data_get_irq_chip_data(d);
+ int offset = d->hwirq;
+
+ grgpio_set_imask(priv, offset, 1);
+}
+
+static struct irq_chip grgpio_irq_chip = {
+ .name = "grgpio",
+ .irq_mask = grgpio_irq_mask,
+ .irq_unmask = grgpio_irq_unmask,
+ .irq_set_type = grgpio_irq_set_type,
+};
+
+static irqreturn_t grgpio_irq_handler(int irq, void *dev)
+{
+ struct grgpio_priv *priv = dev;
+ int ngpio = priv->bgc.gc.ngpio;
+ unsigned long flags;
+ int i;
+ int match = 0;
+
+ spin_lock_irqsave(&priv->bgc.lock, flags);
+
+ /*
+ * For each gpio line, call its interrupt handler if it its underlying
+ * irq matches the current irq that is handled.
+ */
+ for (i = 0; i < ngpio; i++) {
+ struct grgpio_lirq *lirq = &priv->lirqs[i];
+
+ if (priv->imask & BIT(i) && lirq->index >= 0 &&
+ priv->uirqs[lirq->index].uirq == irq) {
+ generic_handle_irq(lirq->irq);
+ match = 1;
+ }
+ }
+
+ spin_unlock_irqrestore(&priv->bgc.lock, flags);
+
+ if (!match)
+ dev_warn(priv->dev, "No gpio line matched irq %d\n", irq);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * This function will be called as a consequence of the call to
+ * irq_create_mapping in grgpio_to_irq
+ */
+int grgpio_irq_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ struct grgpio_priv *priv = d->host_data;
+ struct grgpio_lirq *lirq;
+ struct grgpio_uirq *uirq;
+ unsigned long flags;
+ int offset = hwirq;
+ int ret = 0;
+
+ if (!priv)
+ return -EINVAL;
+
+ lirq = &priv->lirqs[offset];
+ if (lirq->index < 0)
+ return -EINVAL;
+
+ dev_dbg(priv->dev, "Mapping irq %d for gpio line %d\n",
+ irq, offset);
+
+ spin_lock_irqsave(&priv->bgc.lock, flags);
+
+ /* Request underlying irq if not already requested */
+ lirq->irq = irq;
+ uirq = &priv->uirqs[lirq->index];
+ if (uirq->refcnt == 0) {
+ ret = request_irq(uirq->uirq, grgpio_irq_handler, 0,
+ dev_name(priv->dev), priv);
+ if (ret) {
+ dev_err(priv->dev,
+ "Could not request underlying irq %d\n",
+ uirq->uirq);
+
+ spin_unlock_irqrestore(&priv->bgc.lock, flags);
+
+ return ret;
+ }
+ }
+ uirq->refcnt++;
+
+ spin_unlock_irqrestore(&priv->bgc.lock, flags);
+
+ /* Setup irq */
+ irq_set_chip_data(irq, priv);
+ irq_set_chip_and_handler(irq, &grgpio_irq_chip,
+ handle_simple_irq);
+ irq_clear_status_flags(irq, IRQ_NOREQUEST);
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, IRQF_VALID);
+#else
+ irq_set_noprobe(irq);
+#endif
+
+ return ret;
+}
+
+void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq)
+{
+ struct grgpio_priv *priv = d->host_data;
+ int index;
+ struct grgpio_lirq *lirq;
+ struct grgpio_uirq *uirq;
+ unsigned long flags;
+ int ngpio = priv->bgc.gc.ngpio;
+ int i;
+
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, 0);
+#endif
+ irq_set_chip_and_handler(irq, NULL, NULL);
+ irq_set_chip_data(irq, NULL);
+
+ spin_lock_irqsave(&priv->bgc.lock, flags);
+
+ /* Free underlying irq if last user unmapped */
+ index = -1;
+ for (i = 0; i < ngpio; i++) {
+ lirq = &priv->lirqs[i];
+ if (lirq->irq == irq) {
+ grgpio_set_imask(priv, i, 0);
+ lirq->irq = 0;
+ index = lirq->index;
+ break;
+ }
+ }
+ WARN_ON(index < 0);
+
+ if (index >= 0) {
+ uirq = &priv->uirqs[lirq->index];
+ uirq->refcnt--;
+ if (uirq->refcnt == 0)
+ free_irq(uirq->uirq, priv);
+ }
+
+ spin_unlock_irqrestore(&priv->bgc.lock, flags);
+}
+
+static struct irq_domain_ops grgpio_irq_domain_ops = {
+ .map = grgpio_irq_map,
+ .unmap = grgpio_irq_unmap,
+};
+
+/* ------------------------------------------------------------ */
+
+static int grgpio_probe(struct platform_device *ofdev)
+{
+ struct device_node *np = ofdev->dev.of_node;
+ void __iomem *regs;
+ struct gpio_chip *gc;
+ struct bgpio_chip *bgc;
+ struct grgpio_priv *priv;
+ struct resource *res;
+ int err;
+ u32 prop;
+ s32 *irqmap;
+ int size;
+ int i;
+
+ priv = devm_kzalloc(&ofdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
+ regs = devm_ioremap_resource(&ofdev->dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ bgc = &priv->bgc;
+ err = bgpio_init(bgc, &ofdev->dev, 4, regs + GRGPIO_DATA,
+ regs + GRGPIO_OUTPUT, NULL, regs + GRGPIO_DIR, NULL,
+ BGPIOF_BIG_ENDIAN_BYTE_ORDER);
+ if (err) {
+ dev_err(&ofdev->dev, "bgpio_init() failed\n");
+ return err;
+ }
+
+ priv->regs = regs;
+ priv->imask = bgc->read_reg(regs + GRGPIO_IMASK);
+ priv->dev = &ofdev->dev;
+
+ gc = &bgc->gc;
+ gc->of_node = np;
+ gc->owner = THIS_MODULE;
+ gc->to_irq = grgpio_to_irq;
+ gc->label = np->full_name;
+ gc->base = -1;
+
+ err = of_property_read_u32(np, "nbits", &prop);
+ if (err || prop <= 0 || prop > GRGPIO_MAX_NGPIO) {
+ gc->ngpio = GRGPIO_MAX_NGPIO;
+ dev_dbg(&ofdev->dev,
+ "No or invalid nbits property: assume %d\n", gc->ngpio);
+ } else {
+ gc->ngpio = prop;
+ }
+
+ /*
+ * The irqmap contains the index values indicating which underlying irq,
+ * if anyone, is connected to that line
+ */
+ irqmap = (s32 *)of_get_property(np, "irqmap", &size);
+ if (irqmap) {
+ if (size < gc->ngpio) {
+ dev_err(&ofdev->dev,
+ "irqmap shorter than ngpio (%d < %d)\n",
+ size, gc->ngpio);
+ return -EINVAL;
+ }
+
+ priv->domain = irq_domain_add_linear(np, gc->ngpio,
+ &grgpio_irq_domain_ops,
+ priv);
+ if (!priv->domain) {
+ dev_err(&ofdev->dev, "Could not add irq domain\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < gc->ngpio; i++) {
+ struct grgpio_lirq *lirq;
+ int ret;
+
+ lirq = &priv->lirqs[i];
+ lirq->index = irqmap[i];
+
+ if (lirq->index < 0)
+ continue;
+
+ ret = platform_get_irq(ofdev, lirq->index);
+ if (ret <= 0) {
+ /*
+ * Continue without irq functionality for that
+ * gpio line
+ */
+ dev_err(priv->dev,
+ "Failed to get irq for offset %d\n", i);
+ continue;
+ }
+ priv->uirqs[lirq->index].uirq = ret;
+ }
+ }
+
+ platform_set_drvdata(ofdev, priv);
+
+ err = gpiochip_add(gc);
+ if (err) {
+ dev_err(&ofdev->dev, "Could not add gpiochip\n");
+ return err;
+ }
+
+ dev_info(&ofdev->dev, "regs=0x%p, base=%d, ngpio=%d, irqs=%s\n",
+ priv->regs, gc->base, gc->ngpio, priv->domain ? "on" : "off");
+
+ return 0;
+}
+
+static int grgpio_remove(struct platform_device *ofdev)
+{
+ struct grgpio_priv *priv = platform_get_drvdata(ofdev);
+ unsigned long flags;
+ int i;
+ int ret = 0;
+
+ spin_lock_irqsave(&priv->bgc.lock, flags);
+
+ if (priv->domain) {
+ for (i = 0; i < GRGPIO_MAX_NGPIO; i++) {
+ if (priv->uirqs[i].refcnt != 0) {
+ ret = -EBUSY;
+ goto out;
+ }
+ }
+ }
+
+ ret = gpiochip_remove(&priv->bgc.gc);
+ if (ret)
+ goto out;
+
+ if (priv->domain)
+ irq_domain_remove(priv->domain);
+
+out:
+ spin_unlock_irqrestore(&priv->bgc.lock, flags);
+
+ return ret;
+}
+
+static struct of_device_id grgpio_match[] = {
+ {.name = "GAISLER_GPIO"},
+ {.name = "01_01a"},
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, grgpio_match);
+
+static struct platform_driver grgpio_driver = {
+ .driver = {
+ .name = "grgpio",
+ .owner = THIS_MODULE,
+ .of_match_table = grgpio_match,
+ },
+ .probe = grgpio_probe,
+ .remove = grgpio_remove,
+};
+module_platform_driver(grgpio_driver);
+
+MODULE_AUTHOR("Aeroflex Gaisler AB.");
+MODULE_DESCRIPTION("Driver for Aeroflex Gaisler GRGPIO");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c
index f9dbd503fc40..e16d932fd444 100644
--- a/drivers/gpio/gpio-ich.c
+++ b/drivers/gpio/gpio-ich.c
@@ -130,14 +130,11 @@ static int ichx_read_bit(int reg, unsigned nr)
static bool ichx_gpio_check_available(struct gpio_chip *gpio, unsigned nr)
{
- return ichx_priv.use_gpio & (1 << (nr / 32));
+ return !!(ichx_priv.use_gpio & (1 << (nr / 32)));
}
static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
{
- if (!ichx_gpio_check_available(gpio, nr))
- return -ENXIO;
-
/*
* Try setting pin as an input and verify it worked since many pins
* are output-only.
@@ -151,9 +148,6 @@ static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
int val)
{
- if (!ichx_gpio_check_available(gpio, nr))
- return -ENXIO;
-
/* Set GPIO output value. */
ichx_write_bit(GPIO_LVL, nr, val, 0);
@@ -169,9 +163,6 @@ static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
static int ichx_gpio_get(struct gpio_chip *chip, unsigned nr)
{
- if (!ichx_gpio_check_available(chip, nr))
- return -ENXIO;
-
return ichx_read_bit(GPIO_LVL, nr);
}
@@ -180,9 +171,6 @@ static int ich6_gpio_get(struct gpio_chip *chip, unsigned nr)
unsigned long flags;
u32 data;
- if (!ichx_gpio_check_available(chip, nr))
- return -ENXIO;
-
/*
* GPI 0 - 15 need to be read from the power management registers on
* a ICH6/3100 bridge.
@@ -207,6 +195,9 @@ static int ich6_gpio_get(struct gpio_chip *chip, unsigned nr)
static int ichx_gpio_request(struct gpio_chip *chip, unsigned nr)
{
+ if (!ichx_gpio_check_available(chip, nr))
+ return -ENXIO;
+
/*
* Note we assume the BIOS properly set a bridge's USE value. Some
* chips (eg Intel 3100) have bogus USE values though, so first see if
@@ -214,7 +205,7 @@ static int ichx_gpio_request(struct gpio_chip *chip, unsigned nr)
* If it can't be trusted, assume that the pin can be used as a GPIO.
*/
if (ichx_priv.desc->use_sel_ignore[nr / 32] & (1 << (nr & 0x1f)))
- return 1;
+ return 0;
return ichx_read_bit(GPIO_USE_SEL, nr) ? 0 : -ENODEV;
}
diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c
index 4ad9c6b6a134..90a80eb688a9 100644
--- a/drivers/gpio/gpio-lpc32xx.c
+++ b/drivers/gpio/gpio-lpc32xx.c
@@ -533,7 +533,7 @@ static int lpc32xx_of_xlate(struct gpio_chip *gc,
{
/* Is this the correct bank? */
u32 bank = gpiospec->args[0];
- if ((bank > ARRAY_SIZE(lpc32xx_gpiochip) ||
+ if ((bank >= ARRAY_SIZE(lpc32xx_gpiochip) ||
(gc != &lpc32xx_gpiochip[bank].chip)))
return -EINVAL;
diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c
index 3472b05ac512..86c17de87692 100644
--- a/drivers/gpio/gpio-lynxpoint.c
+++ b/drivers/gpio/gpio-lynxpoint.c
@@ -32,6 +32,7 @@
#include <linux/acpi.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/io.h>
/* LynxPoint chipset has support for 94 gpio pins */
diff --git a/drivers/gpio/gpio-max7300.c b/drivers/gpio/gpio-max7300.c
index 4b6b9a04e326..40ab6dfb6021 100644
--- a/drivers/gpio/gpio-max7300.c
+++ b/drivers/gpio/gpio-max7300.c
@@ -41,7 +41,7 @@ static int max7300_probe(struct i2c_client *client,
I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
- ts = kzalloc(sizeof(struct max7301), GFP_KERNEL);
+ ts = devm_kzalloc(&client->dev, sizeof(struct max7301), GFP_KERNEL);
if (!ts)
return -ENOMEM;
@@ -50,8 +50,6 @@ static int max7300_probe(struct i2c_client *client,
ts->dev = &client->dev;
ret = __max730x_probe(ts);
- if (ret)
- kfree(ts);
return ret;
}
diff --git a/drivers/gpio/gpio-max7301.c b/drivers/gpio/gpio-max7301.c
index c6c535c1310e..3b16ab701630 100644
--- a/drivers/gpio/gpio-max7301.c
+++ b/drivers/gpio/gpio-max7301.c
@@ -56,12 +56,13 @@ static int max7301_probe(struct spi_device *spi)
int ret;
/* bits_per_word cannot be configured in platform data */
- spi->bits_per_word = 16;
+ if (spi->dev.platform_data)
+ spi->bits_per_word = 16;
ret = spi_setup(spi);
if (ret < 0)
return ret;
- ts = kzalloc(sizeof(struct max7301), GFP_KERNEL);
+ ts = devm_kzalloc(&spi->dev, sizeof(struct max7301), GFP_KERNEL);
if (!ts)
return -ENOMEM;
@@ -70,8 +71,6 @@ static int max7301_probe(struct spi_device *spi)
ts->dev = &spi->dev;
ret = __max730x_probe(ts);
- if (ret)
- kfree(ts);
return ret;
}
diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c
index 1e0467ce4c37..d4b51b163b03 100644
--- a/drivers/gpio/gpio-max732x.c
+++ b/drivers/gpio/gpio-max732x.c
@@ -589,7 +589,8 @@ static int max732x_probe(struct i2c_client *client,
return -EINVAL;
}
- chip = kzalloc(sizeof(struct max732x_chip), GFP_KERNEL);
+ chip = devm_kzalloc(&client->dev, sizeof(struct max732x_chip),
+ GFP_KERNEL);
if (chip == NULL)
return -ENOMEM;
chip->client = client;
@@ -647,7 +648,6 @@ static int max732x_probe(struct i2c_client *client,
out_failed:
max732x_irq_teardown(chip);
- kfree(chip);
return ret;
}
@@ -680,7 +680,6 @@ static int max732x_remove(struct i2c_client *client)
if (chip->client_dummy)
i2c_unregister_device(chip->client_dummy);
- kfree(chip);
return 0;
}
diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c
index 6a8fdc26ae6a..63a7a1bfb2d9 100644
--- a/drivers/gpio/gpio-mc33880.c
+++ b/drivers/gpio/gpio-mc33880.c
@@ -101,13 +101,13 @@ static int mc33880_probe(struct spi_device *spi)
if (ret < 0)
return ret;
- mc = kzalloc(sizeof(struct mc33880), GFP_KERNEL);
+ mc = devm_kzalloc(&spi->dev, sizeof(struct mc33880), GFP_KERNEL);
if (!mc)
return -ENOMEM;
mutex_init(&mc->lock);
- dev_set_drvdata(&spi->dev, mc);
+ spi_set_drvdata(spi, mc);
mc->spi = spi;
@@ -130,7 +130,8 @@ static int mc33880_probe(struct spi_device *spi)
ret = mc33880_write_config(mc);
if (ret) {
- printk(KERN_ERR "Failed writing to " DRIVER_NAME ": %d\n", ret);
+ dev_err(&spi->dev, "Failed writing to " DRIVER_NAME ": %d\n",
+ ret);
goto exit_destroy;
}
@@ -141,9 +142,8 @@ static int mc33880_probe(struct spi_device *spi)
return ret;
exit_destroy:
- dev_set_drvdata(&spi->dev, NULL);
+ spi_set_drvdata(spi, NULL);
mutex_destroy(&mc->lock);
- kfree(mc);
return ret;
}
@@ -152,17 +152,16 @@ static int mc33880_remove(struct spi_device *spi)
struct mc33880 *mc;
int ret;
- mc = dev_get_drvdata(&spi->dev);
+ mc = spi_get_drvdata(spi);
if (mc == NULL)
return -ENODEV;
- dev_set_drvdata(&spi->dev, NULL);
+ spi_set_drvdata(spi, NULL);
ret = gpiochip_remove(&mc->chip);
- if (!ret) {
+ if (!ret)
mutex_destroy(&mc->lock);
- kfree(mc);
- } else
+ else
dev_err(&spi->dev, "Failed to remove the GPIO controller: %d\n",
ret);
diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c
index 3cea0ea79e80..6a4470b84488 100644
--- a/drivers/gpio/gpio-mcp23s08.c
+++ b/drivers/gpio/gpio-mcp23s08.c
@@ -12,6 +12,8 @@
#include <linux/spi/mcp23s08.h>
#include <linux/slab.h>
#include <asm/byteorder.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
/**
* MCP types supported by driver
@@ -383,6 +385,10 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
mcp->chip.direction_output = mcp23s08_direction_output;
mcp->chip.set = mcp23s08_set;
mcp->chip.dbg_show = mcp23s08_dbg_show;
+#ifdef CONFIG_OF
+ mcp->chip.of_gpio_n_cells = 2;
+ mcp->chip.of_node = dev->of_node;
+#endif
switch (type) {
#ifdef CONFIG_SPI_MASTER
@@ -473,6 +479,35 @@ fail:
/*----------------------------------------------------------------------*/
+#ifdef CONFIG_OF
+#ifdef CONFIG_SPI_MASTER
+static struct of_device_id mcp23s08_spi_of_match[] = {
+ {
+ .compatible = "mcp,mcp23s08", .data = (void *) MCP_TYPE_S08,
+ },
+ {
+ .compatible = "mcp,mcp23s17", .data = (void *) MCP_TYPE_S17,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, mcp23s08_spi_of_match);
+#endif
+
+#if IS_ENABLED(CONFIG_I2C)
+static struct of_device_id mcp23s08_i2c_of_match[] = {
+ {
+ .compatible = "mcp,mcp23008", .data = (void *) MCP_TYPE_008,
+ },
+ {
+ .compatible = "mcp,mcp23017", .data = (void *) MCP_TYPE_017,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, mcp23s08_i2c_of_match);
+#endif
+#endif /* CONFIG_OF */
+
+
#if IS_ENABLED(CONFIG_I2C)
static int mcp230xx_probe(struct i2c_client *client,
@@ -480,12 +515,23 @@ static int mcp230xx_probe(struct i2c_client *client,
{
struct mcp23s08_platform_data *pdata;
struct mcp23s08 *mcp;
- int status;
-
- pdata = client->dev.platform_data;
- if (!pdata || !gpio_is_valid(pdata->base)) {
- dev_dbg(&client->dev, "invalid or missing platform data\n");
- return -EINVAL;
+ int status, base, pullups;
+ const struct of_device_id *match;
+
+ match = of_match_device(of_match_ptr(mcp23s08_i2c_of_match),
+ &client->dev);
+ if (match) {
+ base = -1;
+ pullups = 0;
+ } else {
+ pdata = client->dev.platform_data;
+ if (!pdata || !gpio_is_valid(pdata->base)) {
+ dev_dbg(&client->dev,
+ "invalid or missing platform data\n");
+ return -EINVAL;
+ }
+ base = pdata->base;
+ pullups = pdata->chip[0].pullups;
}
mcp = kzalloc(sizeof *mcp, GFP_KERNEL);
@@ -493,8 +539,7 @@ static int mcp230xx_probe(struct i2c_client *client,
return -ENOMEM;
status = mcp23s08_probe_one(mcp, &client->dev, client, client->addr,
- id->driver_data, pdata->base,
- pdata->chip[0].pullups);
+ id->driver_data, base, pullups);
if (status)
goto fail;
@@ -531,6 +576,7 @@ static struct i2c_driver mcp230xx_driver = {
.driver = {
.name = "mcp230xx",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(mcp23s08_i2c_of_match),
},
.probe = mcp230xx_probe,
.remove = mcp230xx_remove,
@@ -565,28 +611,55 @@ static int mcp23s08_probe(struct spi_device *spi)
unsigned chips = 0;
struct mcp23s08_driver_data *data;
int status, type;
- unsigned base;
-
- type = spi_get_device_id(spi)->driver_data;
-
- pdata = spi->dev.platform_data;
- if (!pdata || !gpio_is_valid(pdata->base)) {
- dev_dbg(&spi->dev, "invalid or missing platform data\n");
- return -EINVAL;
- }
+ unsigned base = -1,
+ ngpio = 0,
+ pullups[ARRAY_SIZE(pdata->chip)];
+ const struct of_device_id *match;
+ u32 spi_present_mask = 0;
+
+ match = of_match_device(of_match_ptr(mcp23s08_spi_of_match), &spi->dev);
+ if (match) {
+ type = (int)match->data;
+ status = of_property_read_u32(spi->dev.of_node,
+ "mcp,spi-present-mask", &spi_present_mask);
+ if (status) {
+ dev_err(&spi->dev, "DT has no spi-present-mask\n");
+ return -ENODEV;
+ }
+ if ((spi_present_mask <= 0) || (spi_present_mask >= 256)) {
+ dev_err(&spi->dev, "invalid spi-present-mask\n");
+ return -ENODEV;
+ }
- for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) {
- if (!pdata->chip[addr].is_present)
- continue;
- chips++;
- if ((type == MCP_TYPE_S08) && (addr > 3)) {
- dev_err(&spi->dev,
- "mcp23s08 only supports address 0..3\n");
+ for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++)
+ pullups[addr] = 0;
+ } else {
+ type = spi_get_device_id(spi)->driver_data;
+ pdata = spi->dev.platform_data;
+ if (!pdata || !gpio_is_valid(pdata->base)) {
+ dev_dbg(&spi->dev,
+ "invalid or missing platform data\n");
return -EINVAL;
}
+
+ for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) {
+ if (!pdata->chip[addr].is_present)
+ continue;
+ chips++;
+ if ((type == MCP_TYPE_S08) && (addr > 3)) {
+ dev_err(&spi->dev,
+ "mcp23s08 only supports address 0..3\n");
+ return -EINVAL;
+ }
+ spi_present_mask |= 1 << addr;
+ pullups[addr] = pdata->chip[addr].pullups;
+ }
+
+ if (!chips)
+ return -ENODEV;
+
+ base = pdata->base;
}
- if (!chips)
- return -ENODEV;
data = kzalloc(sizeof *data + chips * sizeof(struct mcp23s08),
GFP_KERNEL);
@@ -594,21 +667,22 @@ static int mcp23s08_probe(struct spi_device *spi)
return -ENOMEM;
spi_set_drvdata(spi, data);
- base = pdata->base;
for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) {
- if (!pdata->chip[addr].is_present)
+ if (!(spi_present_mask & (1 << addr)))
continue;
chips--;
data->mcp[addr] = &data->chip[chips];
status = mcp23s08_probe_one(data->mcp[addr], &spi->dev, spi,
0x40 | (addr << 1), type, base,
- pdata->chip[addr].pullups);
+ pullups[addr]);
if (status < 0)
goto fail;
- base += (type == MCP_TYPE_S17) ? 16 : 8;
+ if (base != -1)
+ base += (type == MCP_TYPE_S17) ? 16 : 8;
+ ngpio += (type == MCP_TYPE_S17) ? 16 : 8;
}
- data->ngpio = base - pdata->base;
+ data->ngpio = ngpio;
/* NOTE: these chips have a relatively sane IRQ framework, with
* per-signal masking and level/edge triggering. It's not yet
@@ -668,6 +742,7 @@ static struct spi_driver mcp23s08_driver = {
.driver = {
.name = "mcp23s08",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(mcp23s08_spi_of_match),
},
};
diff --git a/drivers/gpio/gpio-msm-v1.c b/drivers/gpio/gpio-msm-v1.c
index 52a4d4286eba..c798585a3fe5 100644
--- a/drivers/gpio/gpio-msm-v1.c
+++ b/drivers/gpio/gpio-msm-v1.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -19,9 +19,10 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/module.h>
-#include <mach/cpu.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
#include <mach/msm_gpiomux.h>
-#include <mach/msm_iomap.h>
/* see 80-VA736-2 Rev C pp 695-751
**
@@ -34,10 +35,10 @@
** macros.
*/
-#define MSM_GPIO1_REG(off) (MSM_GPIO1_BASE + (off))
-#define MSM_GPIO2_REG(off) (MSM_GPIO2_BASE + 0x400 + (off))
-#define MSM_GPIO1_SHADOW_REG(off) (MSM_GPIO1_BASE + 0x800 + (off))
-#define MSM_GPIO2_SHADOW_REG(off) (MSM_GPIO2_BASE + 0xC00 + (off))
+#define MSM_GPIO1_REG(off) (off)
+#define MSM_GPIO2_REG(off) (off)
+#define MSM_GPIO1_SHADOW_REG(off) (off)
+#define MSM_GPIO2_SHADOW_REG(off) (off)
/*
* MSM7X00 registers
@@ -276,16 +277,14 @@
#define MSM_GPIO_BANK(soc, bank, first, last) \
{ \
- .regs = { \
- .out = soc##_GPIO_OUT_##bank, \
- .in = soc##_GPIO_IN_##bank, \
- .int_status = soc##_GPIO_INT_STATUS_##bank, \
- .int_clear = soc##_GPIO_INT_CLEAR_##bank, \
- .int_en = soc##_GPIO_INT_EN_##bank, \
- .int_edge = soc##_GPIO_INT_EDGE_##bank, \
- .int_pos = soc##_GPIO_INT_POS_##bank, \
- .oe = soc##_GPIO_OE_##bank, \
- }, \
+ .regs[MSM_GPIO_OUT] = soc##_GPIO_OUT_##bank, \
+ .regs[MSM_GPIO_IN] = soc##_GPIO_IN_##bank, \
+ .regs[MSM_GPIO_INT_STATUS] = soc##_GPIO_INT_STATUS_##bank, \
+ .regs[MSM_GPIO_INT_CLEAR] = soc##_GPIO_INT_CLEAR_##bank, \
+ .regs[MSM_GPIO_INT_EN] = soc##_GPIO_INT_EN_##bank, \
+ .regs[MSM_GPIO_INT_EDGE] = soc##_GPIO_INT_EDGE_##bank, \
+ .regs[MSM_GPIO_INT_POS] = soc##_GPIO_INT_POS_##bank, \
+ .regs[MSM_GPIO_OE] = soc##_GPIO_OE_##bank, \
.chip = { \
.base = (first), \
.ngpio = (last) - (first) + 1, \
@@ -301,39 +300,57 @@
#define MSM_GPIO_BROKEN_INT_CLEAR 1
-struct msm_gpio_regs {
- void __iomem *out;
- void __iomem *in;
- void __iomem *int_status;
- void __iomem *int_clear;
- void __iomem *int_en;
- void __iomem *int_edge;
- void __iomem *int_pos;
- void __iomem *oe;
+enum msm_gpio_reg {
+ MSM_GPIO_IN,
+ MSM_GPIO_OUT,
+ MSM_GPIO_INT_STATUS,
+ MSM_GPIO_INT_CLEAR,
+ MSM_GPIO_INT_EN,
+ MSM_GPIO_INT_EDGE,
+ MSM_GPIO_INT_POS,
+ MSM_GPIO_OE,
+ MSM_GPIO_REG_NR
};
struct msm_gpio_chip {
spinlock_t lock;
struct gpio_chip chip;
- struct msm_gpio_regs regs;
+ unsigned long regs[MSM_GPIO_REG_NR];
#if MSM_GPIO_BROKEN_INT_CLEAR
unsigned int_status_copy;
#endif
unsigned int both_edge_detect;
unsigned int int_enable[2]; /* 0: awake, 1: sleep */
+ void __iomem *base;
+};
+
+struct msm_gpio_initdata {
+ struct msm_gpio_chip *chips;
+ int count;
};
+static void msm_gpio_writel(struct msm_gpio_chip *chip, u32 val,
+ enum msm_gpio_reg reg)
+{
+ writel(val, chip->base + chip->regs[reg]);
+}
+
+static u32 msm_gpio_readl(struct msm_gpio_chip *chip, enum msm_gpio_reg reg)
+{
+ return readl(chip->base + chip->regs[reg]);
+}
+
static int msm_gpio_write(struct msm_gpio_chip *msm_chip,
unsigned offset, unsigned on)
{
unsigned mask = BIT(offset);
unsigned val;
- val = readl(msm_chip->regs.out);
+ val = msm_gpio_readl(msm_chip, MSM_GPIO_OUT);
if (on)
- writel(val | mask, msm_chip->regs.out);
+ msm_gpio_writel(msm_chip, val | mask, MSM_GPIO_OUT);
else
- writel(val & ~mask, msm_chip->regs.out);
+ msm_gpio_writel(msm_chip, val & ~mask, MSM_GPIO_OUT);
return 0;
}
@@ -342,13 +359,13 @@ static void msm_gpio_update_both_edge_detect(struct msm_gpio_chip *msm_chip)
int loop_limit = 100;
unsigned pol, val, val2, intstat;
do {
- val = readl(msm_chip->regs.in);
- pol = readl(msm_chip->regs.int_pos);
+ val = msm_gpio_readl(msm_chip, MSM_GPIO_IN);
+ pol = msm_gpio_readl(msm_chip, MSM_GPIO_INT_POS);
pol = (pol & ~msm_chip->both_edge_detect) |
(~val & msm_chip->both_edge_detect);
- writel(pol, msm_chip->regs.int_pos);
- intstat = readl(msm_chip->regs.int_status);
- val2 = readl(msm_chip->regs.in);
+ msm_gpio_writel(msm_chip, pol, MSM_GPIO_INT_POS);
+ intstat = msm_gpio_readl(msm_chip, MSM_GPIO_INT_STATUS);
+ val2 = msm_gpio_readl(msm_chip, MSM_GPIO_IN);
if (((val ^ val2) & msm_chip->both_edge_detect & ~intstat) == 0)
return;
} while (loop_limit-- > 0);
@@ -365,10 +382,11 @@ static int msm_gpio_clear_detect_status(struct msm_gpio_chip *msm_chip,
/* Save interrupts that already triggered before we loose them. */
/* Any interrupt that triggers between the read of int_status */
/* and the write to int_clear will still be lost though. */
- msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
+ msm_chip->int_status_copy |=
+ msm_gpio_readl(msm_chip, MSM_GPIO_INT_STATUS);
msm_chip->int_status_copy &= ~bit;
#endif
- writel(bit, msm_chip->regs.int_clear);
+ msm_gpio_writel(msm_chip, bit, MSM_GPIO_INT_CLEAR);
msm_gpio_update_both_edge_detect(msm_chip);
return 0;
}
@@ -377,10 +395,12 @@ static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
struct msm_gpio_chip *msm_chip;
unsigned long irq_flags;
+ u32 val;
msm_chip = container_of(chip, struct msm_gpio_chip, chip);
spin_lock_irqsave(&msm_chip->lock, irq_flags);
- writel(readl(msm_chip->regs.oe) & ~BIT(offset), msm_chip->regs.oe);
+ val = msm_gpio_readl(msm_chip, MSM_GPIO_OE) & ~BIT(offset);
+ msm_gpio_writel(msm_chip, val, MSM_GPIO_OE);
spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
return 0;
}
@@ -390,11 +410,13 @@ msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value)
{
struct msm_gpio_chip *msm_chip;
unsigned long irq_flags;
+ u32 val;
msm_chip = container_of(chip, struct msm_gpio_chip, chip);
spin_lock_irqsave(&msm_chip->lock, irq_flags);
msm_gpio_write(msm_chip, offset, value);
- writel(readl(msm_chip->regs.oe) | BIT(offset), msm_chip->regs.oe);
+ val = msm_gpio_readl(msm_chip, MSM_GPIO_OE) | BIT(offset);
+ msm_gpio_writel(msm_chip, val, MSM_GPIO_OE);
spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
return 0;
}
@@ -404,7 +426,7 @@ static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
struct msm_gpio_chip *msm_chip;
msm_chip = container_of(chip, struct msm_gpio_chip, chip);
- return (readl(msm_chip->regs.in) & (1U << offset)) ? 1 : 0;
+ return (msm_gpio_readl(msm_chip, MSM_GPIO_IN) & (1U << offset)) ? 1 : 0;
}
static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
@@ -450,6 +472,11 @@ static struct msm_gpio_chip msm_gpio_chips_msm7x01[] = {
MSM_GPIO_BANK(MSM7X00, 5, 107, 121),
};
+static struct msm_gpio_initdata msm_gpio_7x01_init = {
+ .chips = msm_gpio_chips_msm7x01,
+ .count = ARRAY_SIZE(msm_gpio_chips_msm7x01),
+};
+
static struct msm_gpio_chip msm_gpio_chips_msm7x30[] = {
MSM_GPIO_BANK(MSM7X30, 0, 0, 15),
MSM_GPIO_BANK(MSM7X30, 1, 16, 43),
@@ -461,6 +488,11 @@ static struct msm_gpio_chip msm_gpio_chips_msm7x30[] = {
MSM_GPIO_BANK(MSM7X30, 7, 151, 181),
};
+static struct msm_gpio_initdata msm_gpio_7x30_init = {
+ .chips = msm_gpio_chips_msm7x30,
+ .count = ARRAY_SIZE(msm_gpio_chips_msm7x30),
+};
+
static struct msm_gpio_chip msm_gpio_chips_qsd8x50[] = {
MSM_GPIO_BANK(QSD8X50, 0, 0, 15),
MSM_GPIO_BANK(QSD8X50, 1, 16, 42),
@@ -472,6 +504,11 @@ static struct msm_gpio_chip msm_gpio_chips_qsd8x50[] = {
MSM_GPIO_BANK(QSD8X50, 7, 153, 164),
};
+static struct msm_gpio_initdata msm_gpio_8x50_init = {
+ .chips = msm_gpio_chips_qsd8x50,
+ .count = ARRAY_SIZE(msm_gpio_chips_qsd8x50),
+};
+
static void msm_gpio_irq_ack(struct irq_data *d)
{
unsigned long irq_flags;
@@ -490,10 +527,10 @@ static void msm_gpio_irq_mask(struct irq_data *d)
spin_lock_irqsave(&msm_chip->lock, irq_flags);
/* level triggered interrupts are also latched */
- if (!(readl(msm_chip->regs.int_edge) & BIT(offset)))
+ if (!(msm_gpio_readl(msm_chip, MSM_GPIO_INT_EDGE) & BIT(offset)))
msm_gpio_clear_detect_status(msm_chip, offset);
msm_chip->int_enable[0] &= ~BIT(offset);
- writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
+ msm_gpio_writel(msm_chip, msm_chip->int_enable[0], MSM_GPIO_INT_EN);
spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
}
@@ -505,10 +542,10 @@ static void msm_gpio_irq_unmask(struct irq_data *d)
spin_lock_irqsave(&msm_chip->lock, irq_flags);
/* level triggered interrupts are also latched */
- if (!(readl(msm_chip->regs.int_edge) & BIT(offset)))
+ if (!(msm_gpio_readl(msm_chip, MSM_GPIO_INT_EDGE) & BIT(offset)))
msm_gpio_clear_detect_status(msm_chip, offset);
msm_chip->int_enable[0] |= BIT(offset);
- writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
+ msm_gpio_writel(msm_chip, msm_chip->int_enable[0], MSM_GPIO_INT_EN);
spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
}
@@ -537,12 +574,12 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
unsigned val, mask = BIT(offset);
spin_lock_irqsave(&msm_chip->lock, irq_flags);
- val = readl(msm_chip->regs.int_edge);
+ val = msm_gpio_readl(msm_chip, MSM_GPIO_INT_EDGE);
if (flow_type & IRQ_TYPE_EDGE_BOTH) {
- writel(val | mask, msm_chip->regs.int_edge);
+ msm_gpio_writel(msm_chip, val | mask, MSM_GPIO_INT_EDGE);
__irq_set_handler_locked(d->irq, handle_edge_irq);
} else {
- writel(val & ~mask, msm_chip->regs.int_edge);
+ msm_gpio_writel(msm_chip, val & ~mask, MSM_GPIO_INT_EDGE);
__irq_set_handler_locked(d->irq, handle_level_irq);
}
if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
@@ -550,11 +587,12 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
msm_gpio_update_both_edge_detect(msm_chip);
} else {
msm_chip->both_edge_detect &= ~mask;
- val = readl(msm_chip->regs.int_pos);
+ val = msm_gpio_readl(msm_chip, MSM_GPIO_INT_POS);
if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
- writel(val | mask, msm_chip->regs.int_pos);
+ val |= mask;
else
- writel(val & ~mask, msm_chip->regs.int_pos);
+ val &= ~mask;
+ msm_gpio_writel(msm_chip, val, MSM_GPIO_INT_POS);
}
spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
return 0;
@@ -567,7 +605,7 @@ static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
for (i = 0; i < msm_gpio_count; i++) {
struct msm_gpio_chip *msm_chip = &msm_gpio_chips[i];
- val = readl(msm_chip->regs.int_status);
+ val = msm_gpio_readl(msm_chip, MSM_GPIO_INT_STATUS);
val &= msm_chip->int_enable[0];
while (val) {
mask = val & -val;
@@ -592,22 +630,36 @@ static struct irq_chip msm_gpio_irq_chip = {
.irq_set_type = msm_gpio_irq_set_type,
};
-static int __init msm_init_gpio(void)
+static int __devinit gpio_msm_v1_probe(struct platform_device *pdev)
{
int i, j = 0;
-
- if (cpu_is_msm7x01()) {
- msm_gpio_chips = msm_gpio_chips_msm7x01;
- msm_gpio_count = ARRAY_SIZE(msm_gpio_chips_msm7x01);
- } else if (cpu_is_msm7x30()) {
- msm_gpio_chips = msm_gpio_chips_msm7x30;
- msm_gpio_count = ARRAY_SIZE(msm_gpio_chips_msm7x30);
- } else if (cpu_is_qsd8x50()) {
- msm_gpio_chips = msm_gpio_chips_qsd8x50;
- msm_gpio_count = ARRAY_SIZE(msm_gpio_chips_qsd8x50);
- } else {
- return 0;
- }
+ const struct platform_device_id *dev_id = platform_get_device_id(pdev);
+ struct msm_gpio_initdata *data;
+ int irq1, irq2;
+ struct resource *res;
+ void __iomem *base1, __iomem *base2;
+
+ data = (struct msm_gpio_initdata *)dev_id->driver_data;
+ msm_gpio_chips = data->chips;
+ msm_gpio_count = data->count;
+
+ irq1 = platform_get_irq(pdev, 0);
+ if (irq1 < 0)
+ return irq1;
+
+ irq2 = platform_get_irq(pdev, 1);
+ if (irq2 < 0)
+ return irq2;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base1 = devm_request_and_ioremap(&pdev->dev, res);
+ if (!base1)
+ return -EADDRNOTAVAIL;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ base2 = devm_request_and_ioremap(&pdev->dev, res);
+ if (!base2)
+ return -EADDRNOTAVAIL;
for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
if (i - FIRST_GPIO_IRQ >=
@@ -621,16 +673,42 @@ static int __init msm_init_gpio(void)
}
for (i = 0; i < msm_gpio_count; i++) {
+ if (i == 1)
+ msm_gpio_chips[i].base = base2;
+ else
+ msm_gpio_chips[i].base = base1;
spin_lock_init(&msm_gpio_chips[i].lock);
- writel(0, msm_gpio_chips[i].regs.int_en);
+ msm_gpio_writel(&msm_gpio_chips[i], 0, MSM_GPIO_INT_EN);
gpiochip_add(&msm_gpio_chips[i].chip);
}
- irq_set_chained_handler(INT_GPIO_GROUP1, msm_gpio_irq_handler);
- irq_set_chained_handler(INT_GPIO_GROUP2, msm_gpio_irq_handler);
- irq_set_irq_wake(INT_GPIO_GROUP1, 1);
- irq_set_irq_wake(INT_GPIO_GROUP2, 2);
+ irq_set_chained_handler(irq1, msm_gpio_irq_handler);
+ irq_set_chained_handler(irq2, msm_gpio_irq_handler);
+ irq_set_irq_wake(irq1, 1);
+ irq_set_irq_wake(irq2, 2);
return 0;
}
-postcore_initcall(msm_init_gpio);
+static struct platform_device_id gpio_msm_v1_device_ids[] = {
+ { "gpio-msm-7201", (unsigned long)&msm_gpio_7x01_init },
+ { "gpio-msm-7x30", (unsigned long)&msm_gpio_7x30_init },
+ { "gpio-msm-8x50", (unsigned long)&msm_gpio_8x50_init },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, gpio_msm_v1_device_ids);
+
+static struct platform_driver gpio_msm_v1_driver = {
+ .driver = {
+ .name = "gpio-msm-v1",
+ .owner = THIS_MODULE,
+ },
+ .probe = gpio_msm_v1_probe,
+ .id_table = gpio_msm_v1_device_ids,
+};
+
+static int __init gpio_msm_v1_init(void)
+{
+ return platform_driver_register(&gpio_msm_v1_driver);
+}
+postcore_initcall(gpio_msm_v1_init);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c
index 55a7e7769af6..dd2eddeb1e0c 100644
--- a/drivers/gpio/gpio-msm-v2.c
+++ b/drivers/gpio/gpio-msm-v2.c
@@ -23,13 +23,12 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
-#include <asm/mach/irq.h>
-
#include <mach/msm_gpiomux.h>
#include <mach/msm_iomap.h>
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index 61a6fde6c089..bf69a7eff370 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -117,7 +117,7 @@ static inline void __iomem *mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvc
{
int cpu;
- switch(mvchip->soc_variant) {
+ switch (mvchip->soc_variant) {
case MVEBU_GPIO_SOC_VARIANT_ORION:
case MVEBU_GPIO_SOC_VARIANT_MV78200:
return mvchip->membase + GPIO_EDGE_CAUSE_OFF;
@@ -133,7 +133,7 @@ static inline void __iomem *mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvch
{
int cpu;
- switch(mvchip->soc_variant) {
+ switch (mvchip->soc_variant) {
case MVEBU_GPIO_SOC_VARIANT_ORION:
return mvchip->membase + GPIO_EDGE_MASK_OFF;
case MVEBU_GPIO_SOC_VARIANT_MV78200:
@@ -151,7 +151,7 @@ static void __iomem *mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip)
{
int cpu;
- switch(mvchip->soc_variant) {
+ switch (mvchip->soc_variant) {
case MVEBU_GPIO_SOC_VARIANT_ORION:
return mvchip->membase + GPIO_LEVEL_MASK_OFF;
case MVEBU_GPIO_SOC_VARIANT_MV78200:
@@ -401,7 +401,7 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type)
/*
* Configure interrupt polarity.
*/
- switch(type) {
+ switch (type) {
case IRQ_TYPE_EDGE_RISING:
case IRQ_TYPE_LEVEL_HIGH:
u = readl_relaxed(mvebu_gpioreg_in_pol(mvchip));
@@ -470,18 +470,76 @@ static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
}
}
+#ifdef CONFIG_DEBUG_FS
+#include <linux/seq_file.h>
+
+static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+ struct mvebu_gpio_chip *mvchip =
+ container_of(chip, struct mvebu_gpio_chip, chip);
+ u32 out, io_conf, blink, in_pol, data_in, cause, edg_msk, lvl_msk;
+ int i;
+
+ out = readl_relaxed(mvebu_gpioreg_out(mvchip));
+ io_conf = readl_relaxed(mvebu_gpioreg_io_conf(mvchip));
+ blink = readl_relaxed(mvebu_gpioreg_blink(mvchip));
+ in_pol = readl_relaxed(mvebu_gpioreg_in_pol(mvchip));
+ data_in = readl_relaxed(mvebu_gpioreg_data_in(mvchip));
+ cause = readl_relaxed(mvebu_gpioreg_edge_cause(mvchip));
+ edg_msk = readl_relaxed(mvebu_gpioreg_edge_mask(mvchip));
+ lvl_msk = readl_relaxed(mvebu_gpioreg_level_mask(mvchip));
+
+ for (i = 0; i < chip->ngpio; i++) {
+ const char *label;
+ u32 msk;
+ bool is_out;
+
+ label = gpiochip_is_requested(chip, i);
+ if (!label)
+ continue;
+
+ msk = 1 << i;
+ is_out = !(io_conf & msk);
+
+ seq_printf(s, " gpio-%-3d (%-20.20s)", chip->base + i, label);
+
+ if (is_out) {
+ seq_printf(s, " out %s %s\n",
+ out & msk ? "hi" : "lo",
+ blink & msk ? "(blink )" : "");
+ continue;
+ }
+
+ seq_printf(s, " in %s (act %s) - IRQ",
+ (data_in ^ in_pol) & msk ? "hi" : "lo",
+ in_pol & msk ? "lo" : "hi");
+ if (!((edg_msk | lvl_msk) & msk)) {
+ seq_printf(s, " disabled\n");
+ continue;
+ }
+ if (edg_msk & msk)
+ seq_printf(s, " edge ");
+ if (lvl_msk & msk)
+ seq_printf(s, " level");
+ seq_printf(s, " (%s)\n", cause & msk ? "pending" : "clear ");
+ }
+}
+#else
+#define mvebu_gpio_dbg_show NULL
+#endif
+
static struct of_device_id mvebu_gpio_of_match[] = {
{
.compatible = "marvell,orion-gpio",
- .data = (void*) MVEBU_GPIO_SOC_VARIANT_ORION,
+ .data = (void *) MVEBU_GPIO_SOC_VARIANT_ORION,
},
{
.compatible = "marvell,mv78200-gpio",
- .data = (void*) MVEBU_GPIO_SOC_VARIANT_MV78200,
+ .data = (void *) MVEBU_GPIO_SOC_VARIANT_MV78200,
},
{
.compatible = "marvell,armadaxp-gpio",
- .data = (void*) MVEBU_GPIO_SOC_VARIANT_ARMADAXP,
+ .data = (void *) MVEBU_GPIO_SOC_VARIANT_ARMADAXP,
},
{
/* sentinel */
@@ -509,13 +567,13 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (! res) {
+ if (!res) {
dev_err(&pdev->dev, "Cannot get memory resource\n");
return -ENODEV;
}
mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip), GFP_KERNEL);
- if (! mvchip){
+ if (!mvchip) {
dev_err(&pdev->dev, "Cannot allocate memory\n");
return -ENOMEM;
}
@@ -550,6 +608,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
mvchip->chip.ngpio = ngpios;
mvchip->chip.can_sleep = 0;
mvchip->chip.of_node = np;
+ mvchip->chip.dbg_show = mvebu_gpio_dbg_show;
spin_lock_init(&mvchip->lock);
mvchip->membase = devm_ioremap_resource(&pdev->dev, res);
@@ -560,21 +619,21 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
* per-CPU registers */
if (soc_variant == MVEBU_GPIO_SOC_VARIANT_ARMADAXP) {
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (! res) {
+ if (!res) {
dev_err(&pdev->dev, "Cannot get memory resource\n");
return -ENODEV;
}
mvchip->percpu_membase = devm_ioremap_resource(&pdev->dev,
res);
- if (IS_ERR(mvchip->percpu_membase))
+ if (IS_ERR(mvchip->percpu_membase))
return PTR_ERR(mvchip->percpu_membase);
}
/*
* Mask and clear GPIO interrupts.
*/
- switch(soc_variant) {
+ switch (soc_variant) {
case MVEBU_GPIO_SOC_VARIANT_ORION:
writel_relaxed(0, mvchip->membase + GPIO_EDGE_CAUSE_OFF);
writel_relaxed(0, mvchip->membase + GPIO_EDGE_MASK_OFF);
@@ -632,7 +691,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
gc = irq_alloc_generic_chip("mvebu_gpio_irq", 2, mvchip->irqbase,
mvchip->membase, handle_level_irq);
- if (! gc) {
+ if (!gc) {
dev_err(&pdev->dev, "Cannot allocate generic irq_chip\n");
return -ENOMEM;
}
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index 7877335c4cc8..7176743915d3 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -24,6 +24,7 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -32,7 +33,6 @@
#include <linux/of_device.h>
#include <linux/module.h>
#include <asm-generic/bug.h>
-#include <asm/mach/irq.h>
enum mxc_gpio_hwtype {
IMX1_GPIO, /* runs on i.mx1 */
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 159f5c57eb45..2050891d9c65 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -25,11 +25,10 @@
#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/platform_data/gpio-omap.h>
-#include <asm/mach/irq.h>
-
#define OFF_MODE 1
static LIST_HEAD(omap_gpio_list);
@@ -53,7 +52,6 @@ struct gpio_bank {
struct list_head node;
void __iomem *base;
u16 irq;
- int irq_base;
struct irq_domain *domain;
u32 non_wakeup_gpios;
u32 enabled_non_wakeup_gpios;
@@ -89,7 +87,14 @@ struct gpio_bank {
static int irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq)
{
- return gpio_irq - bank->irq_base + bank->chip.base;
+ return bank->chip.base + gpio_irq;
+}
+
+static int omap_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
+
+ return irq_find_mapping(bank->domain, offset);
}
static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
@@ -421,13 +426,16 @@ static int gpio_irq_type(struct irq_data *d, unsigned type)
int retval;
unsigned long flags;
+ if (WARN_ON(!bank->mod_usage))
+ return -EINVAL;
+
#ifdef CONFIG_ARCH_OMAP1
if (d->irq > IH_MPUIO_BASE)
gpio = OMAP_MPUIO(d->irq - IH_MPUIO_BASE);
#endif
if (!gpio)
- gpio = irq_to_gpio(bank, d->irq);
+ gpio = irq_to_gpio(bank, d->hwirq);
if (type & ~IRQ_TYPE_SENSE_MASK)
return -EINVAL;
@@ -580,7 +588,7 @@ static void _reset_gpio(struct gpio_bank *bank, int gpio)
static int 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->irq);
+ unsigned int gpio = irq_to_gpio(bank, d->hwirq);
return _set_gpio_wakeup(bank, gpio, enable);
}
@@ -680,7 +688,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
{
void __iomem *isr_reg = NULL;
u32 isr;
- unsigned int gpio_irq, gpio_index;
+ unsigned int bit;
struct gpio_bank *bank;
int unmasked = 0;
struct irq_chip *chip = irq_desc_get_chip(desc);
@@ -694,7 +702,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
if (WARN_ON(!isr_reg))
goto exit;
- while(1) {
+ while (1) {
u32 isr_saved, level_mask = 0;
u32 enabled;
@@ -721,14 +729,9 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
if (!isr)
break;
- gpio_irq = bank->irq_base;
- for (; isr != 0; isr >>= 1, gpio_irq++) {
- int gpio = irq_to_gpio(bank, gpio_irq);
-
- if (!(isr & 1))
- continue;
-
- gpio_index = GPIO_INDEX(bank, gpio);
+ while (isr) {
+ bit = __ffs(isr);
+ isr &= ~(1 << bit);
/*
* Some chips can't respond to both rising and falling
@@ -737,10 +740,10 @@ 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 << gpio_index))
- _toggle_gpio_edge_triggering(bank, gpio_index);
+ if (bank->toggle_mask & (1 << bit))
+ _toggle_gpio_edge_triggering(bank, bit);
- generic_handle_irq(gpio_irq);
+ generic_handle_irq(irq_find_mapping(bank->domain, bit));
}
}
/* if bank has any level sensitive GPIO pin interrupt
@@ -756,7 +759,7 @@ exit:
static void 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->irq);
+ unsigned int gpio = irq_to_gpio(bank, d->hwirq);
unsigned long flags;
spin_lock_irqsave(&bank->lock, flags);
@@ -767,7 +770,7 @@ static void gpio_irq_shutdown(struct irq_data *d)
static void 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->irq);
+ unsigned int gpio = irq_to_gpio(bank, d->hwirq);
_clear_gpio_irqstatus(bank, gpio);
}
@@ -775,7 +778,7 @@ static void gpio_ack_irq(struct irq_data *d)
static void 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->irq);
+ unsigned int gpio = irq_to_gpio(bank, d->hwirq);
unsigned long flags;
spin_lock_irqsave(&bank->lock, flags);
@@ -787,7 +790,7 @@ static void gpio_mask_irq(struct irq_data *d)
static void 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->irq);
+ unsigned int gpio = irq_to_gpio(bank, d->hwirq);
unsigned int irq_mask = GPIO_BIT(bank, gpio);
u32 trigger = irqd_get_trigger_type(d);
unsigned long flags;
@@ -953,14 +956,6 @@ static void gpio_set(struct gpio_chip *chip, unsigned offset, int value)
spin_unlock_irqrestore(&bank->lock, flags);
}
-static int gpio_2irq(struct gpio_chip *chip, unsigned offset)
-{
- struct gpio_bank *bank;
-
- bank = container_of(chip, struct gpio_bank, chip);
- return bank->irq_base + offset;
-}
-
/*---------------------------------------------------------------------*/
static void __init omap_gpio_show_rev(struct gpio_bank *bank)
@@ -1057,7 +1052,7 @@ static void omap_gpio_chip_init(struct gpio_bank *bank)
bank->chip.direction_output = gpio_output;
bank->chip.set_debounce = gpio_debounce;
bank->chip.set = gpio_set;
- bank->chip.to_irq = gpio_2irq;
+ bank->chip.to_irq = omap_gpio_to_irq;
if (bank->is_mpuio) {
bank->chip.label = "mpuio";
if (bank->regs->wkup_en)
@@ -1072,15 +1067,16 @@ static void omap_gpio_chip_init(struct gpio_bank *bank)
gpiochip_add(&bank->chip);
- for (j = bank->irq_base; j < bank->irq_base + bank->width; j++) {
- irq_set_lockdep_class(j, &gpio_lock_class);
- irq_set_chip_data(j, bank);
+ 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);
if (bank->is_mpuio) {
- omap_mpuio_alloc_gc(bank, j, bank->width);
+ omap_mpuio_alloc_gc(bank, irq, bank->width);
} else {
- irq_set_chip(j, &gpio_irq_chip);
- irq_set_handler(j, handle_simple_irq);
- set_irq_flags(j, IRQF_VALID);
+ irq_set_chip_and_handler(irq, &gpio_irq_chip,
+ handle_simple_irq);
+ set_irq_flags(irq, IRQF_VALID);
}
}
irq_set_chained_handler(bank->irq, gpio_irq_handler);
@@ -1097,7 +1093,6 @@ static int omap_gpio_probe(struct platform_device *pdev)
const struct omap_gpio_platform_data *pdata;
struct resource *res;
struct gpio_bank *bank;
- int ret = 0;
match = of_match_device(of_match_ptr(omap_gpio_match), dev);
@@ -1124,20 +1119,22 @@ static int omap_gpio_probe(struct platform_device *pdev)
bank->width = pdata->bank_width;
bank->is_mpuio = pdata->is_mpuio;
bank->non_wakeup_gpios = pdata->non_wakeup_gpios;
- bank->loses_context = pdata->loses_context;
bank->regs = pdata->regs;
#ifdef CONFIG_OF_GPIO
bank->chip.of_node = of_node_get(node);
#endif
-
- bank->irq_base = irq_alloc_descs(-1, 0, bank->width, 0);
- if (bank->irq_base < 0) {
- dev_err(dev, "Couldn't allocate IRQ numbers\n");
- return -ENODEV;
+ if (node) {
+ if (!of_property_read_bool(node, "ti,gpio-always-on"))
+ bank->loses_context = true;
+ } else {
+ bank->loses_context = pdata->loses_context;
}
- bank->domain = irq_domain_add_legacy(node, bank->width, bank->irq_base,
- 0, &irq_domain_simple_ops, NULL);
+
+ bank->domain = irq_domain_add_linear(node, bank->width,
+ &irq_domain_simple_ops, NULL);
+ if (!bank->domain)
+ return -ENODEV;
if (bank->regs->set_dataout && bank->regs->clr_dataout)
bank->set_dataout = _set_gpio_dataout_reg;
@@ -1150,18 +1147,21 @@ static int omap_gpio_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (unlikely(!res)) {
dev_err(dev, "Invalid mem resource\n");
+ irq_domain_remove(bank->domain);
return -ENODEV;
}
if (!devm_request_mem_region(dev, res->start, resource_size(res),
pdev->name)) {
dev_err(dev, "Region already claimed\n");
+ irq_domain_remove(bank->domain);
return -EBUSY;
}
bank->base = devm_ioremap(dev, res->start, resource_size(res));
if (!bank->base) {
dev_err(dev, "Could not ioremap\n");
+ irq_domain_remove(bank->domain);
return -ENOMEM;
}
@@ -1185,7 +1185,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
list_add_tail(&bank->node, &omap_gpio_list);
- return ret;
+ return 0;
}
#ifdef CONFIG_ARCH_OMAP2PLUS
@@ -1263,9 +1263,9 @@ static int omap_gpio_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct gpio_bank *bank = platform_get_drvdata(pdev);
- int context_lost_cnt_after;
u32 l = 0, gen, gen0, gen1;
unsigned long flags;
+ int c;
spin_lock_irqsave(&bank->lock, flags);
_gpio_dbck_enable(bank);
@@ -1281,14 +1281,17 @@ static int omap_gpio_runtime_resume(struct device *dev)
__raw_writel(bank->context.risingdetect,
bank->base + bank->regs->risingdetect);
- if (bank->get_context_loss_count) {
- context_lost_cnt_after =
- bank->get_context_loss_count(bank->dev);
- if (context_lost_cnt_after != bank->context_loss_count) {
+ if (bank->loses_context) {
+ if (!bank->get_context_loss_count) {
omap_gpio_restore_context(bank);
} else {
- spin_unlock_irqrestore(&bank->lock, flags);
- return 0;
+ c = bank->get_context_loss_count(bank->dev);
+ if (c != bank->context_loss_count) {
+ omap_gpio_restore_context(bank);
+ } else {
+ spin_unlock_irqrestore(&bank->lock, flags);
+ return 0;
+ }
}
}
@@ -1297,10 +1300,6 @@ static int omap_gpio_runtime_resume(struct device *dev)
return 0;
}
- __raw_writel(bank->context.fallingdetect,
- bank->base + bank->regs->fallingdetect);
- __raw_writel(bank->context.risingdetect,
- bank->base + bank->regs->risingdetect);
l = __raw_readl(bank->base + bank->regs->datain);
/*
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 24059462c87f..426c51dd420c 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -146,8 +146,7 @@ static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val)
ret = i2c_smbus_write_i2c_block_data(chip->client,
(reg << bank_shift) | REG_ADDR_AI,
NBANK(chip), val);
- }
- else {
+ } else {
switch (chip->chip_type) {
case PCA953X_TYPE:
ret = i2c_smbus_write_word_data(chip->client,
@@ -575,7 +574,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
chip->gpio_chip.ngpio,
irq_base,
&pca953x_irq_simple_ops,
- NULL);
+ chip);
if (!chip->domain)
return -ENODEV;
diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c
index a19b7457a726..e8faf53f3875 100644
--- a/drivers/gpio/gpio-pcf857x.c
+++ b/drivers/gpio/gpio-pcf857x.c
@@ -45,6 +45,7 @@ static const struct i2c_device_id pcf857x_id[] = {
{ "pca9675", 16 },
{ "max7328", 8 },
{ "max7329", 8 },
+ { "tca9554", 8 },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcf857x_id);
@@ -267,7 +268,7 @@ static int pcf857x_probe(struct i2c_client *client,
}
/* Allocate, initialize, and register this gpio_chip. */
- gpio = kzalloc(sizeof *gpio, GFP_KERNEL);
+ gpio = devm_kzalloc(&client->dev, sizeof(*gpio), GFP_KERNEL);
if (!gpio)
return -ENOMEM;
@@ -390,7 +391,6 @@ fail:
if (pdata && client->irq)
pcf857x_irq_domain_cleanup(gpio);
- kfree(gpio);
return status;
}
@@ -415,9 +415,7 @@ static int pcf857x_remove(struct i2c_client *client)
pcf857x_irq_domain_cleanup(gpio);
status = gpiochip_remove(&gpio->chip);
- if (status == 0)
- kfree(gpio);
- else
+ if (status)
dev_err(&client->dev, "%s --> %d\n", "remove", status);
return status;
}
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index b820869ca93c..6a4bd0dae0ce 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -15,6 +15,8 @@
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/bitops.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>
@@ -22,8 +24,8 @@
#include <linux/amba/bus.h>
#include <linux/amba/pl061.h>
#include <linux/slab.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/pm.h>
-#include <asm/mach/irq.h>
#define GPIODIR 0x400
#define GPIOIS 0x404
@@ -51,8 +53,7 @@ struct pl061_gpio {
spinlock_t lock;
void __iomem *base;
- int irq_base;
- struct irq_chip_generic *irq_gc;
+ struct irq_domain *domain;
struct gpio_chip gc;
#ifdef CONFIG_PM
@@ -60,6 +61,24 @@ struct pl061_gpio {
#endif
};
+static int pl061_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ /*
+ * Map back to global GPIO space and request muxing, the direction
+ * parameter does not matter for this controller.
+ */
+ int gpio = chip->base + offset;
+
+ return pinctrl_request_gpio(gpio);
+}
+
+static void pl061_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ int gpio = chip->base + offset;
+
+ pinctrl_free_gpio(gpio);
+}
+
static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
{
struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
@@ -122,24 +141,20 @@ static int pl061_to_irq(struct gpio_chip *gc, unsigned offset)
{
struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
- if (chip->irq_base <= 0)
- return -EINVAL;
-
- return chip->irq_base + offset;
+ return irq_create_mapping(chip->domain, offset);
}
static int pl061_irq_type(struct irq_data *d, unsigned trigger)
{
- struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
- struct pl061_gpio *chip = gc->private;
- int offset = d->irq - chip->irq_base;
+ struct pl061_gpio *chip = irq_data_get_irq_chip_data(d);
+ int offset = irqd_to_hwirq(d);
unsigned long flags;
u8 gpiois, gpioibe, gpioiev;
if (offset < 0 || offset >= PL061_GPIO_NR)
return -EINVAL;
- raw_spin_lock_irqsave(&gc->lock, flags);
+ spin_lock_irqsave(&chip->lock, flags);
gpioiev = readb(chip->base + GPIOIEV);
@@ -168,7 +183,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
writeb(gpioiev, chip->base + GPIOIEV);
- raw_spin_unlock_irqrestore(&gc->lock, flags);
+ spin_unlock_irqrestore(&chip->lock, flags);
return 0;
}
@@ -192,31 +207,61 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
chained_irq_exit(irqchip, desc);
}
-static void __init pl061_init_gc(struct pl061_gpio *chip, int irq_base)
+static void pl061_irq_mask(struct irq_data *d)
+{
+ struct pl061_gpio *chip = irq_data_get_irq_chip_data(d);
+ u8 mask = 1 << (irqd_to_hwirq(d) % PL061_GPIO_NR);
+ u8 gpioie;
+
+ spin_lock(&chip->lock);
+ gpioie = readb(chip->base + GPIOIE) & ~mask;
+ writeb(gpioie, chip->base + GPIOIE);
+ spin_unlock(&chip->lock);
+}
+
+static void pl061_irq_unmask(struct irq_data *d)
{
- struct irq_chip_type *ct;
+ struct pl061_gpio *chip = irq_data_get_irq_chip_data(d);
+ u8 mask = 1 << (irqd_to_hwirq(d) % PL061_GPIO_NR);
+ u8 gpioie;
+
+ spin_lock(&chip->lock);
+ gpioie = readb(chip->base + GPIOIE) | mask;
+ writeb(gpioie, chip->base + GPIOIE);
+ spin_unlock(&chip->lock);
+}
+
+static struct irq_chip pl061_irqchip = {
+ .name = "pl061 gpio",
+ .irq_mask = pl061_irq_mask,
+ .irq_unmask = pl061_irq_unmask,
+ .irq_set_type = pl061_irq_type,
+};
- chip->irq_gc = irq_alloc_generic_chip("gpio-pl061", 1, irq_base,
- chip->base, handle_simple_irq);
- chip->irq_gc->private = chip;
+static int pl061_irq_map(struct irq_domain *d, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct pl061_gpio *chip = d->host_data;
- ct = chip->irq_gc->chip_types;
- ct->chip.irq_mask = irq_gc_mask_clr_bit;
- ct->chip.irq_unmask = irq_gc_mask_set_bit;
- ct->chip.irq_set_type = pl061_irq_type;
- ct->chip.irq_set_wake = irq_gc_set_wake;
- ct->regs.mask = GPIOIE;
+ irq_set_chip_and_handler_name(virq, &pl061_irqchip, handle_simple_irq,
+ "pl061");
+ irq_set_chip_data(virq, chip);
+ irq_set_irq_type(virq, IRQ_TYPE_NONE);
- irq_setup_generic_chip(chip->irq_gc, IRQ_MSK(PL061_GPIO_NR),
- IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0);
+ return 0;
}
+static const struct irq_domain_ops pl061_domain_ops = {
+ .map = pl061_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
{
struct device *dev = &adev->dev;
struct pl061_platform_data *pdata = dev->platform_data;
struct pl061_gpio *chip;
- int ret, irq, i;
+ int ret, irq, i, irq_base;
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (chip == NULL)
@@ -224,24 +269,32 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
if (pdata) {
chip->gc.base = pdata->gpio_base;
- chip->irq_base = pdata->irq_base;
- } else if (adev->dev.of_node) {
+ irq_base = pdata->irq_base;
+ if (irq_base <= 0)
+ return -ENODEV;
+ } else {
chip->gc.base = -1;
- chip->irq_base = 0;
- } else
- return -ENODEV;
+ irq_base = 0;
+ }
if (!devm_request_mem_region(dev, adev->res.start,
- resource_size(&adev->res), "pl061"))
+ resource_size(&adev->res), "pl061"))
return -EBUSY;
chip->base = devm_ioremap(dev, adev->res.start,
- resource_size(&adev->res));
- if (chip->base == NULL)
+ resource_size(&adev->res));
+ if (!chip->base)
return -ENOMEM;
+ chip->domain = irq_domain_add_simple(adev->dev.of_node, PL061_GPIO_NR,
+ irq_base, &pl061_domain_ops, chip);
+ if (!chip->domain)
+ return -ENODEV;
+
spin_lock_init(&chip->lock);
+ chip->gc.request = pl061_gpio_request;
+ chip->gc.free = pl061_gpio_free;
chip->gc.direction_input = pl061_direction_input;
chip->gc.direction_output = pl061_direction_output;
chip->gc.get = pl061_get_value;
@@ -259,12 +312,6 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
/*
* irq_chip support
*/
-
- if (chip->irq_base <= 0)
- return 0;
-
- pl061_init_gc(chip, chip->irq_base);
-
writeb(0, chip->base + GPIOIE); /* disable irqs */
irq = adev->irq[0];
if (irq < 0)
diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
index 9cc108d2b770..df2199dd1499 100644
--- a/drivers/gpio/gpio-pxa.c
+++ b/drivers/gpio/gpio-pxa.c
@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -26,8 +27,6 @@
#include <linux/syscore_ops.h>
#include <linux/slab.h>
-#include <asm/mach/irq.h>
-
#include <mach/irqs.h>
/*
@@ -86,20 +85,61 @@ struct pxa_gpio_chip {
#endif
};
-enum {
+enum pxa_gpio_type {
PXA25X_GPIO = 0,
PXA26X_GPIO,
PXA27X_GPIO,
PXA3XX_GPIO,
PXA93X_GPIO,
MMP_GPIO = 0x10,
+ MMP2_GPIO,
+};
+
+struct pxa_gpio_id {
+ enum pxa_gpio_type type;
+ int gpio_nums;
};
static DEFINE_SPINLOCK(gpio_lock);
static struct pxa_gpio_chip *pxa_gpio_chips;
-static int gpio_type;
+static enum pxa_gpio_type gpio_type;
static void __iomem *gpio_reg_base;
+static struct pxa_gpio_id pxa25x_id = {
+ .type = PXA25X_GPIO,
+ .gpio_nums = 85,
+};
+
+static struct pxa_gpio_id pxa26x_id = {
+ .type = PXA26X_GPIO,
+ .gpio_nums = 90,
+};
+
+static struct pxa_gpio_id pxa27x_id = {
+ .type = PXA27X_GPIO,
+ .gpio_nums = 121,
+};
+
+static struct pxa_gpio_id pxa3xx_id = {
+ .type = PXA3XX_GPIO,
+ .gpio_nums = 128,
+};
+
+static struct pxa_gpio_id pxa93x_id = {
+ .type = PXA93X_GPIO,
+ .gpio_nums = 192,
+};
+
+static struct pxa_gpio_id mmp_id = {
+ .type = MMP_GPIO,
+ .gpio_nums = 128,
+};
+
+static struct pxa_gpio_id mmp2_id = {
+ .type = MMP2_GPIO,
+ .gpio_nums = 192,
+};
+
#define for_each_gpio_chip(i, c) \
for (i = 0, c = &pxa_gpio_chips[0]; i <= pxa_last_gpio; i += 32, c++)
@@ -432,47 +472,39 @@ static struct irq_chip pxa_muxed_gpio_chip = {
.irq_set_wake = pxa_gpio_set_wake,
};
-static int pxa_gpio_nums(void)
+static int pxa_gpio_nums(struct platform_device *pdev)
{
+ const struct platform_device_id *id = platform_get_device_id(pdev);
+ struct pxa_gpio_id *pxa_id = (struct pxa_gpio_id *)id->driver_data;
int count = 0;
-#ifdef CONFIG_ARCH_PXA
- if (cpu_is_pxa25x()) {
-#ifdef CONFIG_CPU_PXA26x
- count = 89;
- gpio_type = PXA26X_GPIO;
-#elif defined(CONFIG_PXA25x)
- count = 84;
- gpio_type = PXA26X_GPIO;
-#endif /* CONFIG_CPU_PXA26x */
- } else if (cpu_is_pxa27x()) {
- count = 120;
- gpio_type = PXA27X_GPIO;
- } else if (cpu_is_pxa93x()) {
- count = 191;
- gpio_type = PXA93X_GPIO;
- } else if (cpu_is_pxa3xx()) {
- count = 127;
- gpio_type = PXA3XX_GPIO;
- }
-#endif /* CONFIG_ARCH_PXA */
-
-#ifdef CONFIG_ARCH_MMP
- if (cpu_is_pxa168() || cpu_is_pxa910()) {
- count = 127;
- gpio_type = MMP_GPIO;
- } else if (cpu_is_mmp2()) {
- count = 191;
- gpio_type = MMP_GPIO;
+ switch (pxa_id->type) {
+ case PXA25X_GPIO:
+ case PXA26X_GPIO:
+ case PXA27X_GPIO:
+ case PXA3XX_GPIO:
+ case PXA93X_GPIO:
+ case MMP_GPIO:
+ case MMP2_GPIO:
+ gpio_type = pxa_id->type;
+ count = pxa_id->gpio_nums - 1;
+ break;
+ default:
+ count = -EINVAL;
+ break;
}
-#endif /* CONFIG_ARCH_MMP */
return count;
}
#ifdef CONFIG_OF
static struct of_device_id pxa_gpio_dt_ids[] = {
- { .compatible = "mrvl,pxa-gpio" },
- { .compatible = "mrvl,mmp-gpio", .data = (void *)MMP_GPIO },
+ { .compatible = "intel,pxa25x-gpio", .data = &pxa25x_id, },
+ { .compatible = "intel,pxa26x-gpio", .data = &pxa26x_id, },
+ { .compatible = "intel,pxa27x-gpio", .data = &pxa27x_id, },
+ { .compatible = "intel,pxa3xx-gpio", .data = &pxa3xx_id, },
+ { .compatible = "marvell,pxa93x-gpio", .data = &pxa93x_id, },
+ { .compatible = "marvell,mmp-gpio", .data = &mmp_id, },
+ { .compatible = "marvell,mmp2-gpio", .data = &mmp2_id, },
{}
};
@@ -492,16 +524,18 @@ const struct irq_domain_ops pxa_irq_domain_ops = {
static int pxa_gpio_probe_dt(struct platform_device *pdev)
{
- int ret, nr_banks, nr_gpios;
+ int ret, nr_gpios;
struct device_node *prev, *next, *np = pdev->dev.of_node;
const struct of_device_id *of_id =
of_match_device(pxa_gpio_dt_ids, &pdev->dev);
+ const struct pxa_gpio_id *gpio_id;
- if (!of_id) {
+ if (!of_id || !of_id->data) {
dev_err(&pdev->dev, "Failed to find gpio controller\n");
return -EFAULT;
}
- gpio_type = (int)of_id->data;
+ gpio_id = of_id->data;
+ gpio_type = gpio_id->type;
next = of_get_next_child(np, NULL);
prev = next;
@@ -510,14 +544,8 @@ static int pxa_gpio_probe_dt(struct platform_device *pdev)
ret = -EINVAL;
goto err;
}
- for (nr_banks = 1; ; nr_banks++) {
- next = of_get_next_child(np, prev);
- if (!next)
- break;
- prev = next;
- }
of_node_put(prev);
- nr_gpios = nr_banks << 5;
+ nr_gpios = gpio_id->gpio_nums;
pxa_last_gpio = nr_gpios - 1;
irq_base = irq_alloc_descs(-1, 0, nr_gpios, 0);
@@ -546,19 +574,18 @@ static int pxa_gpio_probe(struct platform_device *pdev)
int gpio, irq, ret, use_of = 0;
int irq0 = 0, irq1 = 0, irq_mux, gpio_offset = 0;
- ret = pxa_gpio_probe_dt(pdev);
- if (ret < 0) {
- pxa_last_gpio = pxa_gpio_nums();
-#ifdef CONFIG_ARCH_PXA
- if (gpio_is_pxa_type(gpio_type))
- irq_base = PXA_GPIO_TO_IRQ(0);
-#endif
-#ifdef CONFIG_ARCH_MMP
- if (gpio_is_mmp_type(gpio_type))
- irq_base = MMP_GPIO_TO_IRQ(0);
-#endif
+ info = dev_get_platdata(&pdev->dev);
+ if (info) {
+ irq_base = info->irq_base;
+ if (irq_base <= 0)
+ return -EINVAL;
+ pxa_last_gpio = pxa_gpio_nums(pdev);
} else {
+ irq_base = 0;
use_of = 1;
+ ret = pxa_gpio_probe_dt(pdev);
+ if (ret < 0)
+ return -EINVAL;
}
if (!pxa_last_gpio)
@@ -595,14 +622,13 @@ static int pxa_gpio_probe(struct platform_device *pdev)
}
/* Initialize GPIO chips */
- info = dev_get_platdata(&pdev->dev);
pxa_init_gpio_chip(pxa_last_gpio, info ? info->gpio_set_wake : NULL);
/* clear all GPIO edge detects */
for_each_gpio_chip(gpio, c) {
writel_relaxed(0, c->regbase + GFER_OFFSET);
writel_relaxed(0, c->regbase + GRER_OFFSET);
- writel_relaxed(~0,c->regbase + GEDR_OFFSET);
+ writel_relaxed(~0, c->regbase + GEDR_OFFSET);
/* unmask GPIO edge detect for AP side */
if (gpio_is_mmp_type(gpio_type))
writel_relaxed(~0, c->regbase + ED_MASK_OFFSET);
@@ -635,14 +661,31 @@ static int pxa_gpio_probe(struct platform_device *pdev)
return 0;
}
+static const struct platform_device_id gpio_id_table[] = {
+ { "pxa25x-gpio", (unsigned long)&pxa25x_id },
+ { "pxa26x-gpio", (unsigned long)&pxa26x_id },
+ { "pxa27x-gpio", (unsigned long)&pxa27x_id },
+ { "pxa3xx-gpio", (unsigned long)&pxa3xx_id },
+ { "pxa93x-gpio", (unsigned long)&pxa93x_id },
+ { "mmp-gpio", (unsigned long)&mmp_id },
+ { "mmp2-gpio", (unsigned long)&mmp2_id },
+ { },
+};
+
static struct platform_driver pxa_gpio_driver = {
.probe = pxa_gpio_probe,
.driver = {
.name = "pxa-gpio",
.of_match_table = of_match_ptr(pxa_gpio_dt_ids),
},
+ .id_table = gpio_id_table,
};
-module_platform_driver(pxa_gpio_driver);
+
+static int __init pxa_gpio_init(void)
+{
+ return platform_driver_register(&pxa_gpio_driver);
+}
+postcore_initcall(pxa_gpio_init);
#ifdef CONFIG_PM
static int pxa_gpio_suspend(void)
@@ -669,7 +712,7 @@ static void pxa_gpio_resume(void)
for_each_gpio_chip(gpio, c) {
/* restore level with set/clear */
- writel_relaxed( c->saved_gplr, c->regbase + GPSR_OFFSET);
+ writel_relaxed(c->saved_gplr, c->regbase + GPSR_OFFSET);
writel_relaxed(~c->saved_gplr, c->regbase + GPCR_OFFSET);
writel_relaxed(c->saved_grer, c->regbase + GRER_OFFSET);
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
new file mode 100644
index 000000000000..b4ca450947b8
--- /dev/null
+++ b/drivers/gpio/gpio-rcar.c
@@ -0,0 +1,396 @@
+/*
+ * Renesas R-Car GPIO Support
+ *
+ * Copyright (C) 2013 Magnus Damm
+ *
+ * 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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_data/gpio-rcar.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+
+struct gpio_rcar_priv {
+ void __iomem *base;
+ spinlock_t lock;
+ struct gpio_rcar_config config;
+ struct platform_device *pdev;
+ struct gpio_chip gpio_chip;
+ struct irq_chip irq_chip;
+ struct irq_domain *irq_domain;
+};
+
+#define IOINTSEL 0x00
+#define INOUTSEL 0x04
+#define OUTDT 0x08
+#define INDT 0x0c
+#define INTDT 0x10
+#define INTCLR 0x14
+#define INTMSK 0x18
+#define MSKCLR 0x1c
+#define POSNEG 0x20
+#define EDGLEVEL 0x24
+#define FILONOFF 0x28
+
+static inline u32 gpio_rcar_read(struct gpio_rcar_priv *p, int offs)
+{
+ return ioread32(p->base + offs);
+}
+
+static inline void gpio_rcar_write(struct gpio_rcar_priv *p, int offs,
+ u32 value)
+{
+ iowrite32(value, p->base + offs);
+}
+
+static void gpio_rcar_modify_bit(struct gpio_rcar_priv *p, int offs,
+ int bit, bool value)
+{
+ u32 tmp = gpio_rcar_read(p, offs);
+
+ if (value)
+ tmp |= BIT(bit);
+ else
+ tmp &= ~BIT(bit);
+
+ gpio_rcar_write(p, offs, tmp);
+}
+
+static void gpio_rcar_irq_disable(struct irq_data *d)
+{
+ struct gpio_rcar_priv *p = irq_data_get_irq_chip_data(d);
+
+ gpio_rcar_write(p, INTMSK, ~BIT(irqd_to_hwirq(d)));
+}
+
+static void gpio_rcar_irq_enable(struct irq_data *d)
+{
+ struct gpio_rcar_priv *p = irq_data_get_irq_chip_data(d);
+
+ gpio_rcar_write(p, MSKCLR, BIT(irqd_to_hwirq(d)));
+}
+
+static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p,
+ unsigned int hwirq,
+ bool active_high_rising_edge,
+ bool level_trigger)
+{
+ unsigned long flags;
+
+ /* follow steps in the GPIO documentation for
+ * "Setting Edge-Sensitive Interrupt Input Mode" and
+ * "Setting Level-Sensitive Interrupt Input Mode"
+ */
+
+ spin_lock_irqsave(&p->lock, flags);
+
+ /* Configure postive or negative logic in POSNEG */
+ gpio_rcar_modify_bit(p, POSNEG, hwirq, !active_high_rising_edge);
+
+ /* Configure edge or level trigger in EDGLEVEL */
+ gpio_rcar_modify_bit(p, EDGLEVEL, hwirq, !level_trigger);
+
+ /* Select "Interrupt Input Mode" in IOINTSEL */
+ gpio_rcar_modify_bit(p, IOINTSEL, hwirq, true);
+
+ /* Write INTCLR in case of edge trigger */
+ if (!level_trigger)
+ gpio_rcar_write(p, INTCLR, BIT(hwirq));
+
+ spin_unlock_irqrestore(&p->lock, flags);
+}
+
+static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type)
+{
+ struct gpio_rcar_priv *p = irq_data_get_irq_chip_data(d);
+ unsigned int hwirq = irqd_to_hwirq(d);
+
+ dev_dbg(&p->pdev->dev, "sense irq = %d, type = %d\n", hwirq, type);
+
+ switch (type & IRQ_TYPE_SENSE_MASK) {
+ case IRQ_TYPE_LEVEL_HIGH:
+ gpio_rcar_config_interrupt_input_mode(p, hwirq, true, true);
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ gpio_rcar_config_interrupt_input_mode(p, hwirq, false, true);
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false);
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ gpio_rcar_config_interrupt_input_mode(p, hwirq, false, false);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id)
+{
+ struct gpio_rcar_priv *p = dev_id;
+ u32 pending;
+ unsigned int offset, irqs_handled = 0;
+
+ while ((pending = gpio_rcar_read(p, INTDT))) {
+ offset = __ffs(pending);
+ gpio_rcar_write(p, INTCLR, BIT(offset));
+ generic_handle_irq(irq_find_mapping(p->irq_domain, offset));
+ irqs_handled++;
+ }
+
+ return irqs_handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static inline struct gpio_rcar_priv *gpio_to_priv(struct gpio_chip *chip)
+{
+ return container_of(chip, struct gpio_rcar_priv, gpio_chip);
+}
+
+static void gpio_rcar_config_general_input_output_mode(struct gpio_chip *chip,
+ unsigned int gpio,
+ bool output)
+{
+ struct gpio_rcar_priv *p = gpio_to_priv(chip);
+ unsigned long flags;
+
+ /* follow steps in the GPIO documentation for
+ * "Setting General Output Mode" and
+ * "Setting General Input Mode"
+ */
+
+ spin_lock_irqsave(&p->lock, flags);
+
+ /* Configure postive logic in POSNEG */
+ gpio_rcar_modify_bit(p, POSNEG, gpio, false);
+
+ /* Select "General Input/Output Mode" in IOINTSEL */
+ gpio_rcar_modify_bit(p, IOINTSEL, gpio, false);
+
+ /* Select Input Mode or Output Mode in INOUTSEL */
+ gpio_rcar_modify_bit(p, INOUTSEL, gpio, output);
+
+ spin_unlock_irqrestore(&p->lock, flags);
+}
+
+static int gpio_rcar_request(struct gpio_chip *chip, unsigned offset)
+{
+ return pinctrl_request_gpio(chip->base + offset);
+}
+
+static void gpio_rcar_free(struct gpio_chip *chip, unsigned offset)
+{
+ pinctrl_free_gpio(chip->base + offset);
+
+ /* Set the GPIO as an input to ensure that the next GPIO request won't
+ * drive the GPIO pin as an output.
+ */
+ gpio_rcar_config_general_input_output_mode(chip, offset, false);
+}
+
+static int gpio_rcar_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ gpio_rcar_config_general_input_output_mode(chip, offset, false);
+ return 0;
+}
+
+static int gpio_rcar_get(struct gpio_chip *chip, unsigned offset)
+{
+ return (int)(gpio_rcar_read(gpio_to_priv(chip), INDT) & BIT(offset));
+}
+
+static void gpio_rcar_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct gpio_rcar_priv *p = gpio_to_priv(chip);
+ unsigned long flags;
+
+ spin_lock_irqsave(&p->lock, flags);
+ gpio_rcar_modify_bit(p, OUTDT, offset, value);
+ spin_unlock_irqrestore(&p->lock, flags);
+}
+
+static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ /* write GPIO value to output before selecting output mode of pin */
+ gpio_rcar_set(chip, offset, value);
+ gpio_rcar_config_general_input_output_mode(chip, offset, true);
+ return 0;
+}
+
+static int gpio_rcar_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ return irq_create_mapping(gpio_to_priv(chip)->irq_domain, offset);
+}
+
+static int gpio_rcar_irq_domain_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct gpio_rcar_priv *p = h->host_data;
+
+ dev_dbg(&p->pdev->dev, "map hw irq = %d, virq = %d\n", (int)hw, virq);
+
+ irq_set_chip_data(virq, h->host_data);
+ irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq);
+ set_irq_flags(virq, IRQF_VALID); /* kill me now */
+ return 0;
+}
+
+static struct irq_domain_ops gpio_rcar_irq_domain_ops = {
+ .map = gpio_rcar_irq_domain_map,
+};
+
+static int gpio_rcar_probe(struct platform_device *pdev)
+{
+ struct gpio_rcar_config *pdata = pdev->dev.platform_data;
+ struct gpio_rcar_priv *p;
+ struct resource *io, *irq;
+ struct gpio_chip *gpio_chip;
+ struct irq_chip *irq_chip;
+ const char *name = dev_name(&pdev->dev);
+ int ret;
+
+ 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;
+ }
+
+ /* deal with driver instance configuration */
+ if (pdata)
+ p->config = *pdata;
+
+ p->pdev = pdev;
+ platform_set_drvdata(pdev, p);
+ spin_lock_init(&p->lock);
+
+ io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+
+ if (!io || !irq) {
+ dev_err(&pdev->dev, "missing IRQ or IOMEM\n");
+ ret = -EINVAL;
+ goto err0;
+ }
+
+ p->base = devm_ioremap_nocache(&pdev->dev, io->start,
+ resource_size(io));
+ if (!p->base) {
+ dev_err(&pdev->dev, "failed to remap I/O memory\n");
+ ret = -ENXIO;
+ goto err0;
+ }
+
+ gpio_chip = &p->gpio_chip;
+ gpio_chip->request = gpio_rcar_request;
+ gpio_chip->free = gpio_rcar_free;
+ gpio_chip->direction_input = gpio_rcar_direction_input;
+ gpio_chip->get = gpio_rcar_get;
+ gpio_chip->direction_output = gpio_rcar_direction_output;
+ gpio_chip->set = gpio_rcar_set;
+ gpio_chip->to_irq = gpio_rcar_to_irq;
+ gpio_chip->label = name;
+ gpio_chip->owner = THIS_MODULE;
+ gpio_chip->base = p->config.gpio_base;
+ gpio_chip->ngpio = p->config.number_of_pins;
+
+ irq_chip = &p->irq_chip;
+ irq_chip->name = name;
+ irq_chip->irq_mask = gpio_rcar_irq_disable;
+ irq_chip->irq_unmask = gpio_rcar_irq_enable;
+ irq_chip->irq_enable = gpio_rcar_irq_enable;
+ irq_chip->irq_disable = gpio_rcar_irq_disable;
+ irq_chip->irq_set_type = gpio_rcar_irq_set_type;
+ irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_SET_TYPE_MASKED;
+
+ p->irq_domain = irq_domain_add_simple(pdev->dev.of_node,
+ p->config.number_of_pins,
+ p->config.irq_base,
+ &gpio_rcar_irq_domain_ops, p);
+ if (!p->irq_domain) {
+ ret = -ENXIO;
+ dev_err(&pdev->dev, "cannot initialize irq domain\n");
+ goto err1;
+ }
+
+ if (devm_request_irq(&pdev->dev, irq->start,
+ gpio_rcar_irq_handler, 0, name, p)) {
+ dev_err(&pdev->dev, "failed to request IRQ\n");
+ ret = -ENOENT;
+ goto err1;
+ }
+
+ ret = gpiochip_add(gpio_chip);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add GPIO controller\n");
+ goto err1;
+ }
+
+ dev_info(&pdev->dev, "driving %d GPIOs\n", p->config.number_of_pins);
+
+ /* warn in case of mismatch if irq base is specified */
+ if (p->config.irq_base) {
+ ret = irq_find_mapping(p->irq_domain, 0);
+ if (p->config.irq_base != ret)
+ dev_warn(&pdev->dev, "irq base mismatch (%u/%u)\n",
+ p->config.irq_base, ret);
+ }
+
+ ret = gpiochip_add_pin_range(gpio_chip, p->config.pctl_name, 0,
+ gpio_chip->base, gpio_chip->ngpio);
+ if (ret < 0)
+ dev_warn(&pdev->dev, "failed to add pin range\n");
+
+ return 0;
+
+err1:
+ irq_domain_remove(p->irq_domain);
+err0:
+ 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;
+
+ irq_domain_remove(p->irq_domain);
+ return 0;
+}
+
+static struct platform_driver gpio_rcar_device_driver = {
+ .probe = gpio_rcar_probe,
+ .remove = gpio_rcar_remove,
+ .driver = {
+ .name = "gpio_rcar",
+ }
+};
+
+module_platform_driver(gpio_rcar_device_driver);
+
+MODULE_AUTHOR("Magnus Damm");
+MODULE_DESCRIPTION("Renesas R-Car GPIO Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c
index b3643ff007e4..b22ca7933745 100644
--- a/drivers/gpio/gpio-samsung.c
+++ b/drivers/gpio/gpio-samsung.c
@@ -1122,8 +1122,12 @@ int samsung_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset)
#ifdef CONFIG_PLAT_S3C24XX
static int s3c24xx_gpiolib_fbank_to_irq(struct gpio_chip *chip, unsigned offset)
{
- if (offset < 4)
- return IRQ_EINT0 + offset;
+ if (offset < 4) {
+ if (soc_is_s3c2412())
+ return IRQ_EINT0_2412 + offset;
+ else
+ return IRQ_EINT0 + offset;
+ }
if (offset < 8)
return IRQ_EINT4 + offset - 4;
@@ -3024,7 +3028,9 @@ static __init int samsung_gpiolib_init(void)
static const struct of_device_id exynos_pinctrl_ids[] = {
{ .compatible = "samsung,exynos4210-pinctrl", },
{ .compatible = "samsung,exynos4x12-pinctrl", },
+ { .compatible = "samsung,exynos5250-pinctrl", },
{ .compatible = "samsung,exynos5440-pinctrl", },
+ { }
};
for_each_matching_node(pctrl_np, exynos_pinctrl_ids)
if (pctrl_np && of_device_is_available(pctrl_np))
diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c
index edae963f4625..1e4de16ceb41 100644
--- a/drivers/gpio/gpio-sch.c
+++ b/drivers/gpio/gpio-sch.c
@@ -125,13 +125,17 @@ static int sch_gpio_resume_direction_in(struct gpio_chip *gc,
unsigned gpio_num)
{
u8 curr_dirs;
+ unsigned short offset, bit;
spin_lock(&gpio_lock);
- curr_dirs = inb(gpio_ba + RGIO);
+ offset = RGIO + gpio_num / 8;
+ bit = gpio_num % 8;
+
+ curr_dirs = inb(gpio_ba + offset);
- if (!(curr_dirs & (1 << gpio_num)))
- outb(curr_dirs | (1 << gpio_num) , gpio_ba + RGIO);
+ if (!(curr_dirs & (1 << bit)))
+ outb(curr_dirs | (1 << bit), gpio_ba + offset);
spin_unlock(&gpio_lock);
return 0;
@@ -139,22 +143,31 @@ static int sch_gpio_resume_direction_in(struct gpio_chip *gc,
static int sch_gpio_resume_get(struct gpio_chip *gc, unsigned gpio_num)
{
- return !!(inb(gpio_ba + RGLV) & (1 << gpio_num));
+ unsigned short offset, bit;
+
+ offset = RGLV + gpio_num / 8;
+ bit = gpio_num % 8;
+
+ return !!(inb(gpio_ba + offset) & (1 << bit));
}
static void sch_gpio_resume_set(struct gpio_chip *gc,
unsigned gpio_num, int val)
{
u8 curr_vals;
+ unsigned short offset, bit;
spin_lock(&gpio_lock);
- curr_vals = inb(gpio_ba + RGLV);
+ offset = RGLV + gpio_num / 8;
+ bit = gpio_num % 8;
+
+ curr_vals = inb(gpio_ba + offset);
if (val)
- outb(curr_vals | (1 << gpio_num), gpio_ba + RGLV);
+ outb(curr_vals | (1 << bit), gpio_ba + offset);
else
- outb((curr_vals & ~(1 << gpio_num)), gpio_ba + RGLV);
+ outb((curr_vals & ~(1 << bit)), gpio_ba + offset);
spin_unlock(&gpio_lock);
}
@@ -163,14 +176,18 @@ static int sch_gpio_resume_direction_out(struct gpio_chip *gc,
unsigned gpio_num, int val)
{
u8 curr_dirs;
+ unsigned short offset, bit;
sch_gpio_resume_set(gc, gpio_num, val);
+ offset = RGIO + gpio_num / 8;
+ bit = gpio_num % 8;
+
spin_lock(&gpio_lock);
- curr_dirs = inb(gpio_ba + RGIO);
- if (curr_dirs & (1 << gpio_num))
- outb(curr_dirs & ~(1 << gpio_num), gpio_ba + RGIO);
+ curr_dirs = inb(gpio_ba + offset);
+ if (curr_dirs & (1 << bit))
+ outb(curr_dirs & ~(1 << bit), gpio_ba + offset);
spin_unlock(&gpio_lock);
return 0;
@@ -204,45 +221,41 @@ static int sch_gpio_probe(struct platform_device *pdev)
gpio_ba = res->start;
switch (id) {
- case PCI_DEVICE_ID_INTEL_SCH_LPC:
- sch_gpio_core.base = 0;
- sch_gpio_core.ngpio = 10;
-
- sch_gpio_resume.base = 10;
- sch_gpio_resume.ngpio = 4;
-
- /*
- * GPIO[6:0] enabled by default
- * GPIO7 is configured by the CMC as SLPIOVR
- * Enable GPIO[9:8] core powered gpios explicitly
- */
- outb(0x3, gpio_ba + CGEN + 1);
- /*
- * SUS_GPIO[2:0] enabled by default
- * Enable SUS_GPIO3 resume powered gpio explicitly
- */
- outb(0x8, gpio_ba + RGEN);
- break;
-
- case PCI_DEVICE_ID_INTEL_ITC_LPC:
- sch_gpio_core.base = 0;
- sch_gpio_core.ngpio = 5;
-
- sch_gpio_resume.base = 5;
- sch_gpio_resume.ngpio = 9;
- break;
-
- case PCI_DEVICE_ID_INTEL_CENTERTON_ILB:
- sch_gpio_core.base = 0;
- sch_gpio_core.ngpio = 21;
-
- sch_gpio_resume.base = 21;
- sch_gpio_resume.ngpio = 9;
- break;
-
- default:
- err = -ENODEV;
- goto err_sch_gpio_core;
+ case PCI_DEVICE_ID_INTEL_SCH_LPC:
+ sch_gpio_core.base = 0;
+ sch_gpio_core.ngpio = 10;
+ sch_gpio_resume.base = 10;
+ sch_gpio_resume.ngpio = 4;
+ /*
+ * GPIO[6:0] enabled by default
+ * GPIO7 is configured by the CMC as SLPIOVR
+ * Enable GPIO[9:8] core powered gpios explicitly
+ */
+ outb(0x3, gpio_ba + CGEN + 1);
+ /*
+ * SUS_GPIO[2:0] enabled by default
+ * Enable SUS_GPIO3 resume powered gpio explicitly
+ */
+ outb(0x8, gpio_ba + RGEN);
+ break;
+
+ case PCI_DEVICE_ID_INTEL_ITC_LPC:
+ sch_gpio_core.base = 0;
+ sch_gpio_core.ngpio = 5;
+ sch_gpio_resume.base = 5;
+ sch_gpio_resume.ngpio = 9;
+ break;
+
+ case PCI_DEVICE_ID_INTEL_CENTERTON_ILB:
+ sch_gpio_core.base = 0;
+ sch_gpio_core.ngpio = 21;
+ sch_gpio_resume.base = 21;
+ sch_gpio_resume.ngpio = 9;
+ break;
+
+ default:
+ err = -ENODEV;
+ goto err_sch_gpio_core;
}
sch_gpio_core.dev = &pdev->dev;
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
index 770476a9da87..3ce5bc38ac31 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -307,11 +307,15 @@ static const struct irq_domain_ops stmpe_gpio_irq_simple_ops = {
.xlate = irq_domain_xlate_twocell,
};
-static int stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio)
+static int stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio,
+ struct device_node *np)
{
- int base = stmpe_gpio->irq_base;
+ int base = 0;
- stmpe_gpio->domain = irq_domain_add_simple(NULL,
+ 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) {
@@ -346,6 +350,9 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
stmpe_gpio->chip = template_chip;
stmpe_gpio->chip.ngpio = stmpe->num_gpios;
stmpe_gpio->chip.dev = &pdev->dev;
+#ifdef CONFIG_OF
+ stmpe_gpio->chip.of_node = np;
+#endif
stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1;
if (pdata)
@@ -366,7 +373,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
goto out_free;
if (irq >= 0) {
- ret = stmpe_gpio_irq_init(stmpe_gpio);
+ ret = stmpe_gpio_irq_init(stmpe_gpio, np);
if (ret)
goto out_disable;
diff --git a/drivers/gpio/gpio-stp-xway.c b/drivers/gpio/gpio-stp-xway.c
index c20e05151212..04882a911b65 100644
--- a/drivers/gpio/gpio-stp-xway.c
+++ b/drivers/gpio/gpio-stp-xway.c
@@ -217,7 +217,7 @@ static int xway_stp_probe(struct platform_device *pdev)
chip->virt = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(chip->virt))
return PTR_ERR(chip->virt);
-
+
chip->gc.dev = &pdev->dev;
chip->gc.label = "stp-xway";
chip->gc.direction_output = xway_stp_dir_out;
diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c
index c0595bbf3268..d34d80dfb083 100644
--- a/drivers/gpio/gpio-tc3589x.c
+++ b/drivers/gpio/gpio-tc3589x.c
@@ -282,9 +282,9 @@ static void tc3589x_gpio_irq_unmap(struct irq_domain *d, unsigned int virq)
}
static struct irq_domain_ops tc3589x_irq_ops = {
- .map = tc3589x_gpio_irq_map,
- .unmap = tc3589x_gpio_irq_unmap,
- .xlate = irq_domain_xlate_twocell,
+ .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,
@@ -344,7 +344,7 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
tc3589x_gpio->chip.base = (pdata) ? pdata->gpio_base : -1;
#ifdef CONFIG_OF_GPIO
- tc3589x_gpio->chip.of_node = np;
+ tc3589x_gpio->chip.of_node = np;
#endif
tc3589x_gpio->irq_base = tc3589x->irq_base ?
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 414ad912232f..da4cb5b0cb87 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -27,11 +27,10 @@
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm.h>
-#include <asm/mach/irq.h>
-
#define GPIO_BANK(x) ((x) >> 5)
#define GPIO_PORT(x) (((x) >> 3) & 0x3)
#define GPIO_BIT(x) ((x) & 0x7)
@@ -72,6 +71,7 @@ struct tegra_gpio_bank {
u32 oe[4];
u32 int_enb[4];
u32 int_lvl[4];
+ u32 wake_enb[4];
#endif
};
@@ -333,15 +333,31 @@ static int tegra_gpio_suspend(struct device *dev)
bank->oe[p] = tegra_gpio_readl(GPIO_OE(gpio));
bank->int_enb[p] = tegra_gpio_readl(GPIO_INT_ENB(gpio));
bank->int_lvl[p] = tegra_gpio_readl(GPIO_INT_LVL(gpio));
+
+ /* Enable gpio irq for wake up source */
+ tegra_gpio_writel(bank->wake_enb[p],
+ GPIO_INT_ENB(gpio));
}
}
local_irq_restore(flags);
return 0;
}
-static int tegra_gpio_wake_enable(struct irq_data *d, unsigned int enable)
+static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable)
{
struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+ int gpio = d->hwirq;
+ u32 port, bit, mask;
+
+ port = GPIO_PORT(gpio);
+ bit = GPIO_BIT(gpio);
+ mask = BIT(bit);
+
+ if (enable)
+ bank->wake_enb[port] |= mask;
+ else
+ bank->wake_enb[port] &= ~mask;
+
return irq_set_irq_wake(bank->irq, enable);
}
#endif
@@ -353,7 +369,7 @@ static struct irq_chip tegra_gpio_irq_chip = {
.irq_unmask = tegra_gpio_irq_unmask,
.irq_set_type = tegra_gpio_irq_set_type,
#ifdef CONFIG_PM_SLEEP
- .irq_set_wake = tegra_gpio_wake_enable,
+ .irq_set_wake = tegra_gpio_irq_set_wake,
#endif
};
@@ -398,10 +414,11 @@ static int tegra_gpio_probe(struct platform_device *pdev)
int j;
match = of_match_device(tegra_gpio_of_match, &pdev->dev);
- if (match)
- config = (struct tegra_gpio_soc_config *)match->data;
- else
- config = &tegra20_gpio_config;
+ if (!match) {
+ dev_err(&pdev->dev, "Error: No device match found\n");
+ return -ENODEV;
+ }
+ config = (struct tegra_gpio_soc_config *)match->data;
tegra_gpio_bank_stride = config->bank_stride;
tegra_gpio_upper_offset = config->upper_offset;
@@ -462,9 +479,7 @@ static int tegra_gpio_probe(struct platform_device *pdev)
}
}
-#ifdef CONFIG_OF_GPIO
tegra_gpio_chip.of_node = pdev->dev.of_node;
-#endif
gpiochip_add(&tegra_gpio_chip);
diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c
index 702cca9284f1..43774058b693 100644
--- a/drivers/gpio/gpio-timberdale.c
+++ b/drivers/gpio/gpio-timberdale.c
@@ -167,8 +167,7 @@ static int timbgpio_irq_type(struct irq_data *d, unsigned trigger)
if (ver < 3) {
ret = -EINVAL;
goto out;
- }
- else {
+ } else {
flr |= 1 << offset;
bflr |= 1 << offset;
}
diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c
index 5083825a0348..06146219d9d2 100644
--- a/drivers/gpio/gpio-tps65910.c
+++ b/drivers/gpio/gpio-tps65910.c
@@ -133,7 +133,7 @@ static int tps65910_gpio_probe(struct platform_device *pdev)
tps65910_gpio->gpio_chip.owner = THIS_MODULE;
tps65910_gpio->gpio_chip.label = tps65910->i2c_client->name;
- switch(tps65910_chip_id(tps65910)) {
+ switch (tps65910_chip_id(tps65910)) {
case TPS65910:
tps65910_gpio->gpio_chip.ngpio = TPS65910_NUM_GPIO;
break;
diff --git a/drivers/gpio/gpio-ucb1400.c b/drivers/gpio/gpio-ucb1400.c
index 26405efe0f9f..6d0feb234d3c 100644
--- a/drivers/gpio/gpio-ucb1400.c
+++ b/drivers/gpio/gpio-ucb1400.c
@@ -12,8 +12,6 @@
#include <linux/module.h>
#include <linux/ucb1400.h>
-struct ucb1400_gpio_data *ucbdata;
-
static int ucb1400_gpio_dir_in(struct gpio_chip *gc, unsigned off)
{
struct ucb1400_gpio *gpio;
@@ -50,7 +48,7 @@ static int ucb1400_gpio_probe(struct platform_device *dev)
struct ucb1400_gpio *ucb = dev->dev.platform_data;
int err = 0;
- if (!(ucbdata && ucbdata->gpio_offset)) {
+ if (!(ucb && ucb->gpio_offset)) {
err = -EINVAL;
goto err;
}
@@ -58,7 +56,7 @@ static int ucb1400_gpio_probe(struct platform_device *dev)
platform_set_drvdata(dev, ucb);
ucb->gc.label = "ucb1400_gpio";
- ucb->gc.base = ucbdata->gpio_offset;
+ ucb->gc.base = ucb->gpio_offset;
ucb->gc.ngpio = 10;
ucb->gc.owner = THIS_MODULE;
@@ -72,8 +70,8 @@ static int ucb1400_gpio_probe(struct platform_device *dev)
if (err)
goto err;
- if (ucbdata && ucbdata->gpio_setup)
- err = ucbdata->gpio_setup(&dev->dev, ucb->gc.ngpio);
+ if (ucb && ucb->gpio_setup)
+ err = ucb->gpio_setup(&dev->dev, ucb->gc.ngpio);
err:
return err;
@@ -85,8 +83,8 @@ static int ucb1400_gpio_remove(struct platform_device *dev)
int err = 0;
struct ucb1400_gpio *ucb = platform_get_drvdata(dev);
- if (ucbdata && ucbdata->gpio_teardown) {
- err = ucbdata->gpio_teardown(&dev->dev, ucb->gc.ngpio);
+ if (ucb && ucb->gpio_teardown) {
+ err = ucb->gpio_teardown(&dev->dev, ucb->gc.ngpio);
if (err)
return err;
}
@@ -103,11 +101,6 @@ static struct platform_driver ucb1400_gpio_driver = {
},
};
-void __init ucb1400_gpio_set_data(struct ucb1400_gpio_data *data)
-{
- ucbdata = data;
-}
-
module_platform_driver(ucb1400_gpio_driver);
MODULE_DESCRIPTION("Philips UCB1400 GPIO driver");
diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c
index 59d72391de26..095ab14cea4d 100644
--- a/drivers/gpio/gpio-viperboard.c
+++ b/drivers/gpio/gpio-viperboard.c
@@ -380,10 +380,6 @@ static int vprbrd_gpiob_direction_output(struct gpio_chip *chip,
struct vprbrd *vb = gpio->vb;
gpio->gpiob_out |= (1 << offset);
- if (value)
- gpio->gpiob_val |= (1 << offset);
- else
- gpio->gpiob_val &= ~(1 << offset);
mutex_lock(&vb->lock);
diff --git a/drivers/gpio/gpio-vt8500.c b/drivers/gpio/gpio-vt8500.c
deleted file mode 100644
index 81683ca35ac1..000000000000
--- a/drivers/gpio/gpio-vt8500.c
+++ /dev/null
@@ -1,355 +0,0 @@
-/* drivers/gpio/gpio-vt8500.c
- *
- * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
- * Based on arch/arm/mach-vt8500/gpio.c:
- * - Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/bitops.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_device.h>
-
-/*
- We handle GPIOs by bank, each bank containing up to 32 GPIOs covered
- by one set of registers (although not all may be valid).
-
- Because different SoC's have different register offsets, we pass the
- register offsets as data in vt8500_gpio_dt_ids[].
-
- A value of NO_REG is used to indicate that this register is not
- supported. Only used for ->en at the moment.
-*/
-
-#define NO_REG 0xFFFF
-
-/*
- * struct vt8500_gpio_bank_regoffsets
- * @en: offset to enable register of the bank
- * @dir: offset to direction register of the bank
- * @data_out: offset to the data out register of the bank
- * @data_in: offset to the data in register of the bank
- * @ngpio: highest valid pin in this bank
- */
-
-struct vt8500_gpio_bank_regoffsets {
- unsigned int en;
- unsigned int dir;
- unsigned int data_out;
- unsigned int data_in;
- unsigned char ngpio;
-};
-
-struct vt8500_gpio_data {
- unsigned int num_banks;
- struct vt8500_gpio_bank_regoffsets banks[];
-};
-
-#define VT8500_BANK(__en, __dir, __out, __in, __ngpio) \
-{ \
- .en = __en, \
- .dir = __dir, \
- .data_out = __out, \
- .data_in = __in, \
- .ngpio = __ngpio, \
-}
-
-static struct vt8500_gpio_data vt8500_data = {
- .num_banks = 7,
- .banks = {
- VT8500_BANK(NO_REG, 0x3C, 0x5C, 0x7C, 9),
- VT8500_BANK(0x00, 0x20, 0x40, 0x60, 26),
- VT8500_BANK(0x04, 0x24, 0x44, 0x64, 28),
- VT8500_BANK(0x08, 0x28, 0x48, 0x68, 31),
- VT8500_BANK(0x0C, 0x2C, 0x4C, 0x6C, 19),
- VT8500_BANK(0x10, 0x30, 0x50, 0x70, 19),
- VT8500_BANK(0x14, 0x34, 0x54, 0x74, 23),
- },
-};
-
-static struct vt8500_gpio_data wm8505_data = {
- .num_banks = 10,
- .banks = {
- VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22),
- VT8500_BANK(0x40, 0x68, 0x90, 0xB8, 8),
- VT8500_BANK(0x44, 0x6C, 0x94, 0xBC, 32),
- VT8500_BANK(0x48, 0x70, 0x98, 0xC0, 6),
- VT8500_BANK(0x4C, 0x74, 0x9C, 0xC4, 16),
- VT8500_BANK(0x50, 0x78, 0xA0, 0xC8, 25),
- VT8500_BANK(0x54, 0x7C, 0xA4, 0xCC, 5),
- VT8500_BANK(0x58, 0x80, 0xA8, 0xD0, 5),
- VT8500_BANK(0x5C, 0x84, 0xAC, 0xD4, 12),
- VT8500_BANK(0x60, 0x88, 0xB0, 0xD8, 16),
- VT8500_BANK(0x500, 0x504, 0x508, 0x50C, 6),
- },
-};
-
-/*
- * No information about which bits are valid so we just make
- * them all available until its figured out.
- */
-static struct vt8500_gpio_data wm8650_data = {
- .num_banks = 9,
- .banks = {
- VT8500_BANK(0x40, 0x80, 0xC0, 0x00, 32),
- VT8500_BANK(0x44, 0x84, 0xC4, 0x04, 32),
- VT8500_BANK(0x48, 0x88, 0xC8, 0x08, 32),
- VT8500_BANK(0x4C, 0x8C, 0xCC, 0x0C, 32),
- VT8500_BANK(0x50, 0x90, 0xD0, 0x10, 32),
- VT8500_BANK(0x54, 0x94, 0xD4, 0x14, 32),
- VT8500_BANK(0x58, 0x98, 0xD8, 0x18, 32),
- VT8500_BANK(0x5C, 0x9C, 0xDC, 0x1C, 32),
- VT8500_BANK(0x7C, 0xBC, 0xFC, 0x3C, 32),
- VT8500_BANK(0x500, 0x504, 0x508, 0x50C, 6),
- },
-};
-
-struct vt8500_gpio_chip {
- struct gpio_chip chip;
-
- const struct vt8500_gpio_bank_regoffsets *regs;
- void __iomem *base;
-};
-
-struct vt8500_data {
- struct vt8500_gpio_chip *chip;
- void __iomem *iobase;
- int num_banks;
-};
-
-
-#define to_vt8500(__chip) container_of(__chip, struct vt8500_gpio_chip, chip)
-
-static int vt8500_gpio_request(struct gpio_chip *chip, unsigned offset)
-{
- u32 val;
- struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
-
- if (vt8500_chip->regs->en == NO_REG)
- return 0;
-
- val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->en);
- val |= BIT(offset);
- writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->en);
-
- return 0;
-}
-
-static void vt8500_gpio_free(struct gpio_chip *chip, unsigned offset)
-{
- struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
- u32 val;
-
- if (vt8500_chip->regs->en == NO_REG)
- return;
-
- val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->en);
- val &= ~BIT(offset);
- writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->en);
-}
-
-static int vt8500_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
-{
- struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
-
- u32 val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->dir);
- val &= ~BIT(offset);
- writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->dir);
-
- return 0;
-}
-
-static int vt8500_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
- int value)
-{
- struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
-
- u32 val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->dir);
- val |= BIT(offset);
- writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->dir);
-
- if (value) {
- val = readl_relaxed(vt8500_chip->base +
- vt8500_chip->regs->data_out);
- val |= BIT(offset);
- writel_relaxed(val, vt8500_chip->base +
- vt8500_chip->regs->data_out);
- }
- return 0;
-}
-
-static int vt8500_gpio_get_value(struct gpio_chip *chip, unsigned offset)
-{
- struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
-
- return (readl_relaxed(vt8500_chip->base + vt8500_chip->regs->data_in) >>
- offset) & 1;
-}
-
-static void vt8500_gpio_set_value(struct gpio_chip *chip, unsigned offset,
- int value)
-{
- struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
-
- u32 val = readl_relaxed(vt8500_chip->base +
- vt8500_chip->regs->data_out);
- if (value)
- val |= BIT(offset);
- else
- val &= ~BIT(offset);
-
- writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->data_out);
-}
-
-static int vt8500_of_xlate(struct gpio_chip *gc,
- const struct of_phandle_args *gpiospec, u32 *flags)
-{
- /* bank if specificed in gpiospec->args[0] */
- if (flags)
- *flags = gpiospec->args[2];
-
- return gpiospec->args[1];
-}
-
-static int vt8500_add_chips(struct platform_device *pdev, void __iomem *base,
- const struct vt8500_gpio_data *data)
-{
- struct vt8500_data *priv;
- struct vt8500_gpio_chip *vtchip;
- struct gpio_chip *chip;
- int i;
- int pin_cnt = 0;
-
- priv = devm_kzalloc(&pdev->dev, sizeof(struct vt8500_data), GFP_KERNEL);
- if (!priv) {
- dev_err(&pdev->dev, "failed to allocate memory\n");
- return -ENOMEM;
- }
-
- priv->chip = devm_kzalloc(&pdev->dev,
- sizeof(struct vt8500_gpio_chip) * data->num_banks,
- GFP_KERNEL);
- if (!priv->chip) {
- dev_err(&pdev->dev, "failed to allocate chip memory\n");
- return -ENOMEM;
- }
-
- priv->iobase = base;
- priv->num_banks = data->num_banks;
- platform_set_drvdata(pdev, priv);
-
- vtchip = priv->chip;
-
- for (i = 0; i < data->num_banks; i++) {
- vtchip[i].base = base;
- vtchip[i].regs = &data->banks[i];
-
- chip = &vtchip[i].chip;
-
- chip->of_xlate = vt8500_of_xlate;
- chip->of_gpio_n_cells = 3;
- chip->of_node = pdev->dev.of_node;
-
- chip->request = vt8500_gpio_request;
- chip->free = vt8500_gpio_free;
- chip->direction_input = vt8500_gpio_direction_input;
- chip->direction_output = vt8500_gpio_direction_output;
- chip->get = vt8500_gpio_get_value;
- chip->set = vt8500_gpio_set_value;
- chip->can_sleep = 0;
- chip->base = pin_cnt;
- chip->ngpio = data->banks[i].ngpio;
-
- pin_cnt += data->banks[i].ngpio;
-
- gpiochip_add(chip);
- }
- return 0;
-}
-
-static struct of_device_id vt8500_gpio_dt_ids[] = {
- { .compatible = "via,vt8500-gpio", .data = &vt8500_data, },
- { .compatible = "wm,wm8505-gpio", .data = &wm8505_data, },
- { .compatible = "wm,wm8650-gpio", .data = &wm8650_data, },
- { /* Sentinel */ },
-};
-
-static int vt8500_gpio_probe(struct platform_device *pdev)
-{
- int ret;
- void __iomem *gpio_base;
- struct resource *res;
- const struct of_device_id *of_id =
- of_match_device(vt8500_gpio_dt_ids, &pdev->dev);
-
- if (!of_id) {
- dev_err(&pdev->dev, "No matching driver data\n");
- return -ENODEV;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Unable to get IO resource\n");
- return -ENODEV;
- }
-
- gpio_base = devm_request_and_ioremap(&pdev->dev, res);
- if (!gpio_base) {
- dev_err(&pdev->dev, "Unable to map GPIO registers\n");
- return -ENOMEM;
- }
-
- ret = vt8500_add_chips(pdev, gpio_base, of_id->data);
-
- return ret;
-}
-
-static int vt8500_gpio_remove(struct platform_device *pdev)
-{
- int i;
- int ret;
- struct vt8500_data *priv = platform_get_drvdata(pdev);
- struct vt8500_gpio_chip *vtchip = priv->chip;
-
- for (i = 0; i < priv->num_banks; i++) {
- ret = gpiochip_remove(&vtchip[i].chip);
- if (ret)
- dev_warn(&pdev->dev, "gpiochip_remove returned %d\n",
- ret);
- }
-
- return 0;
-}
-
-static struct platform_driver vt8500_gpio_driver = {
- .probe = vt8500_gpio_probe,
- .remove = vt8500_gpio_remove,
- .driver = {
- .name = "vt8500-gpio",
- .owner = THIS_MODULE,
- .of_match_table = vt8500_gpio_dt_ids,
- },
-};
-
-module_platform_driver(vt8500_gpio_driver);
-
-MODULE_DESCRIPTION("VT8500 GPIO Driver");
-MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
-MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, vt8500_gpio_dt_ids);
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index a063eb04b6ce..5c1ef2b3ef18 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -17,6 +17,13 @@
#include <linux/acpi.h>
#include <linux/interrupt.h>
+struct acpi_gpio_evt_pin {
+ struct list_head node;
+ acpi_handle *evt_handle;
+ unsigned int pin;
+ unsigned int irq;
+};
+
static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
{
if (!gc->dev)
@@ -54,7 +61,6 @@ int acpi_get_gpio(char *path, int pin)
}
EXPORT_SYMBOL_GPL(acpi_get_gpio);
-
static irqreturn_t acpi_gpio_irq_handler(int irq, void *data)
{
acpi_handle handle = data;
@@ -64,6 +70,27 @@ static irqreturn_t acpi_gpio_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
+static irqreturn_t acpi_gpio_irq_handler_evt(int irq, void *data)
+{
+ struct acpi_gpio_evt_pin *evt_pin = data;
+ struct acpi_object_list args;
+ union acpi_object arg;
+
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = evt_pin->pin;
+ args.count = 1;
+ args.pointer = &arg;
+
+ acpi_evaluate_object(evt_pin->evt_handle, NULL, &args, NULL);
+
+ return IRQ_HANDLED;
+}
+
+static void acpi_gpio_evt_dh(acpi_handle handle, void *data)
+{
+ /* The address of this function is used as a key. */
+}
+
/**
* acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events
* @chip: gpio chip
@@ -73,15 +100,13 @@ static irqreturn_t acpi_gpio_irq_handler(int irq, void *data)
* chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which
* gpio pins have acpi event methods and assigns interrupt handlers that calls
* the acpi event methods for those pins.
- *
- * Interrupts are automatically freed on driver detach
*/
-
void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
{
struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
struct acpi_resource *res;
- acpi_handle handle, ev_handle;
+ acpi_handle handle, evt_handle;
+ struct list_head *evt_pins = NULL;
acpi_status status;
unsigned int pin;
int irq, ret;
@@ -98,13 +123,30 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
if (ACPI_FAILURE(status))
return;
- /* If a gpio interrupt has an acpi event handler method, then
- * set up an interrupt handler that calls the acpi event handler
- */
+ status = acpi_get_handle(handle, "_EVT", &evt_handle);
+ if (ACPI_SUCCESS(status)) {
+ evt_pins = kzalloc(sizeof(*evt_pins), GFP_KERNEL);
+ if (evt_pins) {
+ INIT_LIST_HEAD(evt_pins);
+ status = acpi_attach_data(handle, acpi_gpio_evt_dh,
+ evt_pins);
+ if (ACPI_FAILURE(status)) {
+ kfree(evt_pins);
+ evt_pins = NULL;
+ }
+ }
+ }
+ /*
+ * If a GPIO interrupt has an ACPI event handler method, or _EVT is
+ * present, set up an interrupt handler that calls the ACPI event
+ * handler.
+ */
for (res = buf.pointer;
res && (res->type != ACPI_RESOURCE_TYPE_END_TAG);
res = ACPI_NEXT_RESOURCE(res)) {
+ irq_handler_t handler = NULL;
+ void *data;
if (res->type != ACPI_RESOURCE_TYPE_GPIO ||
res->data.gpio.connection_type !=
@@ -115,23 +157,42 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
if (pin > chip->ngpio)
continue;
- sprintf(ev_name, "_%c%02X",
- res->data.gpio.triggering ? 'E' : 'L', pin);
-
- status = acpi_get_handle(handle, ev_name, &ev_handle);
- if (ACPI_FAILURE(status))
- continue;
-
irq = chip->to_irq(chip, pin);
if (irq < 0)
continue;
+ if (pin <= 255) {
+ acpi_handle ev_handle;
+
+ sprintf(ev_name, "_%c%02X",
+ res->data.gpio.triggering ? 'E' : 'L', pin);
+ status = acpi_get_handle(handle, ev_name, &ev_handle);
+ if (ACPI_SUCCESS(status)) {
+ handler = acpi_gpio_irq_handler;
+ data = ev_handle;
+ }
+ }
+ if (!handler && evt_pins) {
+ struct acpi_gpio_evt_pin *evt_pin;
+
+ evt_pin = kzalloc(sizeof(*evt_pin), GFP_KERNEL);
+ if (!evt_pin)
+ continue;
+
+ list_add_tail(&evt_pin->node, evt_pins);
+ evt_pin->evt_handle = evt_handle;
+ evt_pin->pin = pin;
+ evt_pin->irq = irq;
+ handler = acpi_gpio_irq_handler_evt;
+ data = evt_pin;
+ }
+ if (!handler)
+ continue;
+
/* Assume BIOS sets the triggering, so no flags */
- ret = devm_request_threaded_irq(chip->dev, irq, NULL,
- acpi_gpio_irq_handler,
- 0,
- "GPIO-signaled-ACPI-event",
- ev_handle);
+ ret = devm_request_threaded_irq(chip->dev, irq, NULL, handler,
+ 0, "GPIO-signaled-ACPI-event",
+ data);
if (ret)
dev_err(chip->dev,
"Failed to request IRQ %d ACPI event handler\n",
@@ -139,3 +200,119 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
}
}
EXPORT_SYMBOL(acpi_gpiochip_request_interrupts);
+
+struct acpi_gpio_lookup {
+ struct acpi_gpio_info info;
+ int index;
+ int gpio;
+ int n;
+};
+
+static int acpi_find_gpio(struct acpi_resource *ares, void *data)
+{
+ struct acpi_gpio_lookup *lookup = data;
+
+ if (ares->type != ACPI_RESOURCE_TYPE_GPIO)
+ return 1;
+
+ if (lookup->n++ == lookup->index && lookup->gpio < 0) {
+ const struct acpi_resource_gpio *agpio = &ares->data.gpio;
+
+ lookup->gpio = acpi_get_gpio(agpio->resource_source.string_ptr,
+ agpio->pin_table[0]);
+ lookup->info.gpioint =
+ agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT;
+ }
+
+ return 1;
+}
+
+/**
+ * acpi_get_gpio_by_index() - get a GPIO number from device resources
+ * @dev: pointer to a device to get GPIO from
+ * @index: index of GpioIo/GpioInt resource (starting from %0)
+ * @info: info pointer to fill in (optional)
+ *
+ * Function goes through ACPI resources for @dev and based on @index looks
+ * up a GpioIo/GpioInt resource, translates it to the Linux GPIO number,
+ * and returns it. @index matches GpioIo/GpioInt resources only so if there
+ * are total %3 GPIO resources, the index goes from %0 to %2.
+ *
+ * If the GPIO cannot be translated or there is an error, negative errno is
+ * returned.
+ *
+ * Note: if the GPIO resource has multiple entries in the pin list, this
+ * function only returns the first.
+ */
+int acpi_get_gpio_by_index(struct device *dev, int index,
+ struct acpi_gpio_info *info)
+{
+ struct acpi_gpio_lookup lookup;
+ struct list_head resource_list;
+ struct acpi_device *adev;
+ acpi_handle handle;
+ int ret;
+
+ if (!dev)
+ return -EINVAL;
+
+ handle = ACPI_HANDLE(dev);
+ if (!handle || acpi_bus_get_device(handle, &adev))
+ return -ENODEV;
+
+ memset(&lookup, 0, sizeof(lookup));
+ lookup.index = index;
+ lookup.gpio = -ENODEV;
+
+ INIT_LIST_HEAD(&resource_list);
+ ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio,
+ &lookup);
+ if (ret < 0)
+ return ret;
+
+ acpi_dev_free_resource_list(&resource_list);
+
+ if (lookup.gpio >= 0 && info)
+ *info = lookup.info;
+
+ return lookup.gpio;
+}
+EXPORT_SYMBOL_GPL(acpi_get_gpio_by_index);
+
+/**
+ * acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts.
+ * @chip: gpio chip
+ *
+ * Free interrupts associated with the _EVT method for the given GPIO chip.
+ *
+ * The remaining ACPI event interrupts associated with the chip are freed
+ * automatically.
+ */
+void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
+{
+ acpi_handle handle;
+ acpi_status status;
+ struct list_head *evt_pins;
+ struct acpi_gpio_evt_pin *evt_pin, *ep;
+
+ if (!chip->dev || !chip->to_irq)
+ return;
+
+ handle = ACPI_HANDLE(chip->dev);
+ if (!handle)
+ return;
+
+ status = acpi_get_data(handle, acpi_gpio_evt_dh, (void **)&evt_pins);
+ if (ACPI_FAILURE(status))
+ return;
+
+ list_for_each_entry_safe_reverse(evt_pin, ep, evt_pins, node) {
+ devm_free_irq(chip->dev, evt_pin->irq, evt_pin);
+ list_del(&evt_pin->node);
+ kfree(evt_pin);
+ }
+
+ acpi_detach_data(handle, acpi_gpio_evt_dh);
+ kfree(evt_pins);
+}
+EXPORT_SYMBOL(acpi_gpiochip_free_interrupts);
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index a71a54a3e3f7..665f9530c950 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -61,7 +61,7 @@ static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data)
* in flags for the GPIO.
*/
int of_get_named_gpio_flags(struct device_node *np, const char *propname,
- int index, enum of_gpio_flags *flags)
+ int index, enum of_gpio_flags *flags)
{
/* Return -EPROBE_DEFER to support probe() functions to be called
* later when the GPIO actually becomes available
@@ -193,7 +193,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
if (!np)
return;
- do {
+ for (;; index++) {
ret = of_parse_phandle_with_args(np, "gpio-ranges",
"#gpio-range-cells", index, &pinspec);
if (ret)
@@ -203,27 +203,15 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
if (!pctldev)
break;
- /*
- * This assumes that the n GPIO pins are consecutive in the
- * GPIO number space, and that the pins are also consecutive
- * in their local number space. Currently it is not possible
- * to add different ranges for one and the same GPIO chip,
- * as the code assumes that we have one consecutive range
- * on both, mapping 1-to-1.
- *
- * TODO: make the OF bindings handle multiple sparse ranges
- * on the same GPIO chip.
- */
ret = gpiochip_add_pin_range(chip,
pinctrl_dev_get_devname(pctldev),
- 0, /* offset in gpiochip */
pinspec.args[0],
- pinspec.args[1]);
+ pinspec.args[1],
+ pinspec.args[2]);
if (ret)
break;
-
- } while (index++);
+ }
}
#else