summaryrefslogtreecommitdiffstats
path: root/drivers/gpio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/Kconfig18
-rw-r--r--drivers/gpio/Makefile2
-rw-r--r--drivers/gpio/devres.c14
-rw-r--r--drivers/gpio/gpio-bt8xx.c2
-rw-r--r--drivers/gpio/gpio-clps711x.c236
-rw-r--r--drivers/gpio/gpio-grgpio.c6
-rw-r--r--drivers/gpio/gpio-ich.c8
-rw-r--r--drivers/gpio/gpio-langwell.c170
-rw-r--r--drivers/gpio/gpio-lynxpoint.c1
-rw-r--r--drivers/gpio/gpio-ml-ioh.c1
-rw-r--r--drivers/gpio/gpio-msm-v1.c15
-rw-r--r--drivers/gpio/gpio-msm-v2.c195
-rw-r--r--drivers/gpio/gpio-mvebu.c2
-rw-r--r--drivers/gpio/gpio-omap.c2
-rw-r--r--drivers/gpio/gpio-rcar.c100
-rw-r--r--drivers/gpio/gpio-rdc321x.c7
-rw-r--r--drivers/gpio/gpio-samsung.c67
-rw-r--r--drivers/gpio/gpio-sta2x11.c6
-rw-r--r--drivers/gpio/gpio-stmpe.c7
-rw-r--r--drivers/gpio/gpio-sx150x.c18
-rw-r--r--drivers/gpio/gpio-tc3589x.c1
-rw-r--r--drivers/gpio/gpio-timberdale.c2
-rw-r--r--drivers/gpio/gpio-vx855.c2
-rw-r--r--drivers/gpio/gpio-xilinx.c144
-rw-r--r--drivers/gpio/gpiolib.c8
25 files changed, 477 insertions, 557 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 573c449c49b..b2450ba1413 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -109,8 +109,11 @@ config GPIO_MAX730X
comment "Memory mapped GPIO drivers:"
config GPIO_CLPS711X
- def_bool y
+ tristate "CLPS711X GPIO support"
depends on ARCH_CLPS711X
+ select GPIO_GENERIC
+ help
+ Say yes here to support GPIO on CLPS711X SoCs.
config GPIO_GENERIC_PLATFORM
tristate "Generic memory-mapped GPIO controller support (MMIO platform device)"
@@ -165,7 +168,7 @@ config GPIO_MSM_V1
config GPIO_MSM_V2
tristate "Qualcomm MSM GPIO v2"
- depends on GPIOLIB && ARCH_MSM
+ depends on GPIOLIB && OF && ARCH_MSM
help
Say yes here to support the GPIO interface on ARM v7 based
Qualcomm MSM chips. Most of the pins on the MSM can be
@@ -209,6 +212,13 @@ config GPIO_RCAR
help
Say yes here to support GPIO on Renesas R-Car SoCs.
+config GPIO_SAMSUNG
+ bool
+ depends on PLAT_SAMSUNG
+ help
+ Legacy GPIO support. Use only for platforms without support for
+ pinctrl.
+
config GPIO_SPEAR_SPICS
bool "ST SPEAr13xx SPI Chip Select as GPIO support"
depends on PLAT_SPEAR
@@ -234,7 +244,7 @@ config GPIO_TS5500
config GPIO_XILINX
bool "Xilinx GPIO support"
- depends on PPC_OF || MICROBLAZE
+ depends on PPC_OF || MICROBLAZE || ARCH_ZYNQ
help
Say yes here to support the Xilinx FPGA GPIO device
@@ -330,7 +340,7 @@ config GPIO_MAX7300
depends on I2C
select GPIO_MAX730X
help
- GPIO driver for Maxim MAX7301 I2C-based GPIO expander.
+ GPIO driver for Maxim MAX7300 I2C-based GPIO expander.
config GPIO_MAX732X
tristate "MAX7319, MAX7320-7327 I2C Port Expanders"
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 0cb2d656ad1..ef3e983a2f1 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -59,7 +59,7 @@ 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_GPIO_SAMSUNG) += gpio-samsung.o
obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
obj-$(CONFIG_GPIO_SCH) += gpio-sch.o
obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o
diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c
index 1077754f828..3e7812f0405 100644
--- a/drivers/gpio/devres.c
+++ b/drivers/gpio/devres.c
@@ -34,10 +34,10 @@ static int devm_gpio_match(struct device *dev, void *res, void *data)
}
/**
- * devm_gpio_request - request a gpio for a managed device
- * @dev: device to request the gpio for
- * @gpio: gpio to allocate
- * @label: the name of the requested gpio
+ * devm_gpio_request - request a GPIO for a managed device
+ * @dev: device to request the GPIO for
+ * @gpio: GPIO to allocate
+ * @label: the name of the requested GPIO
*
* Except for the extra @dev argument, this function takes the
* same arguments and performs the same function as
@@ -101,9 +101,9 @@ int devm_gpio_request_one(struct device *dev, unsigned gpio,
EXPORT_SYMBOL(devm_gpio_request_one);
/**
- * devm_gpio_free - free an interrupt
- * @dev: device to free gpio for
- * @gpio: gpio to free
+ * devm_gpio_free - free a GPIO
+ * @dev: device to free GPIO for
+ * @gpio: GPIO to free
*
* Except for the extra @dev argument, this function takes the
* same arguments and performs the same function as gpio_free().
diff --git a/drivers/gpio/gpio-bt8xx.c b/drivers/gpio/gpio-bt8xx.c
index 7d9d7cb35f2..8369e71ebe4 100644
--- a/drivers/gpio/gpio-bt8xx.c
+++ b/drivers/gpio/gpio-bt8xx.c
@@ -286,7 +286,7 @@ static int bt8xxgpio_resume(struct pci_dev *pdev)
unsigned long flags;
int err;
- pci_set_power_state(pdev, 0);
+ pci_set_power_state(pdev, PCI_D0);
err = pci_enable_device(pdev);
if (err)
return err;
diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c
index ce63b75b13f..0edaf2ce926 100644
--- a/drivers/gpio/gpio-clps711x.c
+++ b/drivers/gpio/gpio-clps711x.c
@@ -1,7 +1,7 @@
/*
* CLPS711X GPIO driver
*
- * Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru>
+ * Copyright (C) 2012,2013 Alexander Shiyan <shc_work@mail.ru>
*
* 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
@@ -9,191 +9,91 @@
* (at your option) any later version.
*/
-#include <linux/io.h>
-#include <linux/slab.h>
+#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/module.h>
-#include <linux/spinlock.h>
+#include <linux/basic_mmio_gpio.h>
#include <linux/platform_device.h>
-#include <mach/hardware.h>
-
-#define CLPS711X_GPIO_PORTS 5
-#define CLPS711X_GPIO_NAME "gpio-clps711x"
-
-struct clps711x_gpio {
- struct gpio_chip chip[CLPS711X_GPIO_PORTS];
- spinlock_t lock;
-};
-
-static void __iomem *clps711x_ports[] = {
- CLPS711X_VIRT_BASE + PADR,
- CLPS711X_VIRT_BASE + PBDR,
- CLPS711X_VIRT_BASE + PCDR,
- CLPS711X_VIRT_BASE + PDDR,
- CLPS711X_VIRT_BASE + PEDR,
-};
-
-static void __iomem *clps711x_pdirs[] = {
- CLPS711X_VIRT_BASE + PADDR,
- CLPS711X_VIRT_BASE + PBDDR,
- CLPS711X_VIRT_BASE + PCDDR,
- CLPS711X_VIRT_BASE + PDDDR,
- CLPS711X_VIRT_BASE + PEDDR,
-};
-
-#define clps711x_port(x) clps711x_ports[x->base / 8]
-#define clps711x_pdir(x) clps711x_pdirs[x->base / 8]
-
-static int gpio_clps711x_get(struct gpio_chip *chip, unsigned offset)
+static int clps711x_gpio_probe(struct platform_device *pdev)
{
- return !!(readb(clps711x_port(chip)) & (1 << offset));
-}
+ struct device_node *np = pdev->dev.of_node;
+ void __iomem *dat, *dir;
+ struct bgpio_chip *bgc;
+ struct resource *res;
+ int err, id = np ? of_alias_get_id(np, "gpio") : pdev->id;
-static void gpio_clps711x_set(struct gpio_chip *chip, unsigned offset,
- int value)
-{
- int tmp;
- unsigned long flags;
- struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);
-
- spin_lock_irqsave(&gpio->lock, flags);
- tmp = readb(clps711x_port(chip)) & ~(1 << offset);
- if (value)
- tmp |= 1 << offset;
- writeb(tmp, clps711x_port(chip));
- spin_unlock_irqrestore(&gpio->lock, flags);
-}
-
-static int gpio_clps711x_dir_in(struct gpio_chip *chip, unsigned offset)
-{
- int tmp;
- unsigned long flags;
- struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);
+ if ((id < 0) || (id > 4))
+ return -ENODEV;
- spin_lock_irqsave(&gpio->lock, flags);
- tmp = readb(clps711x_pdir(chip)) & ~(1 << offset);
- writeb(tmp, clps711x_pdir(chip));
- spin_unlock_irqrestore(&gpio->lock, flags);
+ bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL);
+ if (!bgc)
+ return -ENOMEM;
- return 0;
-}
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dat = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(dat))
+ return PTR_ERR(dat);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ dir = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(dir))
+ return PTR_ERR(dir);
+
+ switch (id) {
+ case 3:
+ /* PORTD is inverted logic for direction register */
+ err = bgpio_init(bgc, &pdev->dev, 1, dat, NULL, NULL,
+ NULL, dir, 0);
+ break;
+ default:
+ err = bgpio_init(bgc, &pdev->dev, 1, dat, NULL, NULL,
+ dir, NULL, 0);
+ break;
+ }
-static int gpio_clps711x_dir_out(struct gpio_chip *chip, unsigned offset,
- int value)
-{
- int tmp;
- unsigned long flags;
- struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);
-
- spin_lock_irqsave(&gpio->lock, flags);
- tmp = readb(clps711x_pdir(chip)) | (1 << offset);
- writeb(tmp, clps711x_pdir(chip));
- tmp = readb(clps711x_port(chip)) & ~(1 << offset);
- if (value)
- tmp |= 1 << offset;
- writeb(tmp, clps711x_port(chip));
- spin_unlock_irqrestore(&gpio->lock, flags);
-
- return 0;
-}
+ if (err)
+ return err;
-static int gpio_clps711x_dir_in_inv(struct gpio_chip *chip, unsigned offset)
-{
- int tmp;
- unsigned long flags;
- struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);
+ switch (id) {
+ case 4:
+ /* PORTE is 3 lines only */
+ bgc->gc.ngpio = 3;
+ break;
+ default:
+ break;
+ }
- spin_lock_irqsave(&gpio->lock, flags);
- tmp = readb(clps711x_pdir(chip)) | (1 << offset);
- writeb(tmp, clps711x_pdir(chip));
- spin_unlock_irqrestore(&gpio->lock, flags);
+ bgc->gc.base = id * 8;
+ platform_set_drvdata(pdev, bgc);
- return 0;
+ return gpiochip_add(&bgc->gc);
}
-static int gpio_clps711x_dir_out_inv(struct gpio_chip *chip, unsigned offset,
- int value)
+static int clps711x_gpio_remove(struct platform_device *pdev)
{
- int tmp;
- unsigned long flags;
- struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);
-
- spin_lock_irqsave(&gpio->lock, flags);
- tmp = readb(clps711x_pdir(chip)) & ~(1 << offset);
- writeb(tmp, clps711x_pdir(chip));
- tmp = readb(clps711x_port(chip)) & ~(1 << offset);
- if (value)
- tmp |= 1 << offset;
- writeb(tmp, clps711x_port(chip));
- spin_unlock_irqrestore(&gpio->lock, flags);
-
- return 0;
+ struct bgpio_chip *bgc = platform_get_drvdata(pdev);
+
+ return bgpio_remove(bgc);
}
-static struct {
- char *name;
- int nr;
- int inv_dir;
-} clps711x_gpio_ports[] __initconst = {
- { "PORTA", 8, 0, },
- { "PORTB", 8, 0, },
- { "PORTC", 8, 0, },
- { "PORTD", 8, 1, },
- { "PORTE", 3, 0, },
+static const struct of_device_id clps711x_gpio_ids[] = {
+ { .compatible = "cirrus,clps711x-gpio" },
+ { }
};
+MODULE_DEVICE_TABLE(of, clps711x_gpio_ids);
+
+static struct platform_driver clps711x_gpio_driver = {
+ .driver = {
+ .name = "clps711x-gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(clps711x_gpio_ids),
+ },
+ .probe = clps711x_gpio_probe,
+ .remove = clps711x_gpio_remove,
+};
+module_platform_driver(clps711x_gpio_driver);
-static int __init gpio_clps711x_init(void)
-{
- int i;
- struct platform_device *pdev;
- struct clps711x_gpio *gpio;
-
- pdev = platform_device_alloc(CLPS711X_GPIO_NAME, 0);
- if (!pdev) {
- pr_err("Cannot create platform device: %s\n",
- CLPS711X_GPIO_NAME);
- return -ENOMEM;
- }
-
- platform_device_add(pdev);
-
- gpio = devm_kzalloc(&pdev->dev, sizeof(struct clps711x_gpio),
- GFP_KERNEL);
- if (!gpio) {
- dev_err(&pdev->dev, "GPIO allocating memory error\n");
- platform_device_unregister(pdev);
- return -ENOMEM;
- }
-
- platform_set_drvdata(pdev, gpio);
-
- spin_lock_init(&gpio->lock);
-
- for (i = 0; i < CLPS711X_GPIO_PORTS; i++) {
- gpio->chip[i].owner = THIS_MODULE;
- gpio->chip[i].dev = &pdev->dev;
- gpio->chip[i].label = clps711x_gpio_ports[i].name;
- gpio->chip[i].base = i * 8;
- gpio->chip[i].ngpio = clps711x_gpio_ports[i].nr;
- gpio->chip[i].get = gpio_clps711x_get;
- gpio->chip[i].set = gpio_clps711x_set;
- if (!clps711x_gpio_ports[i].inv_dir) {
- gpio->chip[i].direction_input = gpio_clps711x_dir_in;
- gpio->chip[i].direction_output = gpio_clps711x_dir_out;
- } else {
- gpio->chip[i].direction_input = gpio_clps711x_dir_in_inv;
- gpio->chip[i].direction_output = gpio_clps711x_dir_out_inv;
- }
- WARN_ON(gpiochip_add(&gpio->chip[i]));
- }
-
- dev_info(&pdev->dev, "GPIO driver initialized\n");
-
- return 0;
-}
-arch_initcall(gpio_clps711x_init);
-
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
MODULE_DESCRIPTION("CLPS711X GPIO driver");
diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c
index 8e08b864765..84d2478ec29 100644
--- a/drivers/gpio/gpio-grgpio.c
+++ b/drivers/gpio/gpio-grgpio.c
@@ -235,8 +235,8 @@ static irqreturn_t grgpio_irq_handler(int irq, void *dev)
* 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)
+static 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;
@@ -291,7 +291,7 @@ int grgpio_irq_map(struct irq_domain *d, unsigned int irq,
return ret;
}
-void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq)
+static void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq)
{
struct grgpio_priv *priv = d->host_data;
int index;
diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c
index e16d932fd44..2729e3d2d5b 100644
--- a/drivers/gpio/gpio-ich.c
+++ b/drivers/gpio/gpio-ich.c
@@ -41,12 +41,14 @@ enum GPIO_REG {
GPIO_USE_SEL = 0,
GPIO_IO_SEL,
GPIO_LVL,
+ GPO_BLINK
};
-static const u8 ichx_regs[3][3] = {
+static const u8 ichx_regs[4][3] = {
{0x00, 0x30, 0x40}, /* USE_SEL[1-3] offsets */
{0x04, 0x34, 0x44}, /* IO_SEL[1-3] offsets */
{0x0c, 0x38, 0x48}, /* LVL[1-3] offsets */
+ {0x18, 0x18, 0x18}, /* BLINK offset */
};
static const u8 ichx_reglen[3] = {
@@ -148,6 +150,10 @@ 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)
{
+ /* Disable blink hardware which is available for GPIOs from 0 to 31. */
+ if (nr < 32)
+ ichx_write_bit(GPO_BLINK, nr, 0, 0);
+
/* Set GPIO output value. */
ichx_write_bit(GPIO_LVL, nr, val, 0);
diff --git a/drivers/gpio/gpio-langwell.c b/drivers/gpio/gpio-langwell.c
index 62ef10a641c..bfa1af1b519 100644
--- a/drivers/gpio/gpio-langwell.c
+++ b/drivers/gpio/gpio-langwell.c
@@ -1,7 +1,7 @@
/*
* Moorestown platform Langwell chip GPIO driver
*
- * Copyright (c) 2008 - 2009, Intel Corporation.
+ * Copyright (c) 2008, 2009, 2013, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -20,7 +20,6 @@
/* Supports:
* Moorestown platform Langwell chip.
* Medfield platform Penwell chip.
- * Whitney point.
*/
#include <linux/module.h>
@@ -65,7 +64,7 @@ enum GPIO_REG {
struct lnw_gpio {
struct gpio_chip chip;
- void *reg_base;
+ void __iomem *reg_base;
spinlock_t lock;
struct pci_dev *pdev;
struct irq_domain *domain;
@@ -74,15 +73,13 @@ struct lnw_gpio {
#define to_lnw_priv(chip) container_of(chip, struct lnw_gpio, chip)
static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset,
- enum GPIO_REG reg_type)
+ enum GPIO_REG reg_type)
{
struct lnw_gpio *lnw = to_lnw_priv(chip);
unsigned nreg = chip->ngpio / 32;
u8 reg = offset / 32;
- void __iomem *ptr;
- ptr = (void __iomem *)(lnw->reg_base + reg_type * nreg * 4 + reg * 4);
- return ptr;
+ return lnw->reg_base + reg_type * nreg * 4 + reg * 4;
}
static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset,
@@ -91,10 +88,8 @@ static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset,
struct lnw_gpio *lnw = to_lnw_priv(chip);
unsigned nreg = chip->ngpio / 32;
u8 reg = offset / 16;
- void __iomem *ptr;
- ptr = (void __iomem *)(lnw->reg_base + reg_type * nreg * 4 + reg * 4);
- return ptr;
+ return lnw->reg_base + reg_type * nreg * 4 + reg * 4;
}
static int lnw_gpio_request(struct gpio_chip *chip, unsigned offset)
@@ -305,11 +300,7 @@ static const struct irq_domain_ops lnw_gpio_irq_ops = {
static int lnw_gpio_runtime_idle(struct device *dev)
{
- int err = pm_schedule_suspend(dev, 500);
-
- if (!err)
- return 0;
-
+ pm_schedule_suspend(dev, 500);
return -EBUSY;
}
@@ -318,56 +309,40 @@ static const struct dev_pm_ops lnw_gpio_pm_ops = {
};
static int lnw_gpio_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
+ const struct pci_device_id *id)
{
- void *base;
- resource_size_t start, len;
+ void __iomem *base;
struct lnw_gpio *lnw;
u32 gpio_base;
u32 irq_base;
int retval;
int ngpio = id->driver_data;
- retval = pci_enable_device(pdev);
+ retval = pcim_enable_device(pdev);
if (retval)
return retval;
- retval = pci_request_regions(pdev, "langwell_gpio");
+ retval = pcim_iomap_regions(pdev, 1 << 0 | 1 << 1, pci_name(pdev));
if (retval) {
- dev_err(&pdev->dev, "error requesting resources\n");
- goto err_pci_req_region;
- }
- /* get the gpio_base from bar1 */
- start = pci_resource_start(pdev, 1);
- len = pci_resource_len(pdev, 1);
- base = ioremap_nocache(start, len);
- if (!base) {
- dev_err(&pdev->dev, "error mapping bar1\n");
- retval = -EFAULT;
- goto err_ioremap;
+ dev_err(&pdev->dev, "I/O memory mapping error\n");
+ return retval;
}
- irq_base = *(u32 *)base;
- gpio_base = *((u32 *)base + 1);
+
+ base = pcim_iomap_table(pdev)[1];
+
+ irq_base = readl(base);
+ gpio_base = readl(sizeof(u32) + base);
+
/* release the IO mapping, since we already get the info from bar1 */
- iounmap(base);
- /* get the register base from bar0 */
- start = pci_resource_start(pdev, 0);
- len = pci_resource_len(pdev, 0);
- base = devm_ioremap_nocache(&pdev->dev, start, len);
- if (!base) {
- dev_err(&pdev->dev, "error mapping bar0\n");
- retval = -EFAULT;
- goto err_ioremap;
- }
+ pcim_iounmap_regions(pdev, 1 << 1);
lnw = devm_kzalloc(&pdev->dev, sizeof(*lnw), GFP_KERNEL);
if (!lnw) {
- dev_err(&pdev->dev, "can't allocate langwell_gpio chip data\n");
- retval = -ENOMEM;
- goto err_ioremap;
+ dev_err(&pdev->dev, "can't allocate chip data\n");
+ return -ENOMEM;
}
- lnw->reg_base = base;
+ lnw->reg_base = pcim_iomap_table(pdev)[0];
lnw->chip.label = dev_name(&pdev->dev);
lnw->chip.request = lnw_gpio_request;
lnw->chip.direction_input = lnw_gpio_direction_input;
@@ -380,18 +355,18 @@ static int lnw_gpio_probe(struct pci_dev *pdev,
lnw->chip.can_sleep = 0;
lnw->pdev = pdev;
+ spin_lock_init(&lnw->lock);
+
lnw->domain = irq_domain_add_simple(pdev->dev.of_node, ngpio, irq_base,
&lnw_gpio_irq_ops, lnw);
- if (!lnw->domain) {
- retval = -ENOMEM;
- goto err_ioremap;
- }
+ if (!lnw->domain)
+ return -ENOMEM;
pci_set_drvdata(pdev, lnw);
retval = gpiochip_add(&lnw->chip);
if (retval) {
- dev_err(&pdev->dev, "langwell gpiochip_add error %d\n", retval);
- goto err_ioremap;
+ dev_err(&pdev->dev, "gpiochip_add error %d\n", retval);
+ return retval;
}
lnw_irq_init_hw(lnw);
@@ -399,18 +374,10 @@ static int lnw_gpio_probe(struct pci_dev *pdev,
irq_set_handler_data(pdev->irq, lnw);
irq_set_chained_handler(pdev->irq, lnw_irq_handler);
- spin_lock_init(&lnw->lock);
-
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_allow(&pdev->dev);
return 0;
-
-err_ioremap:
- pci_release_regions(pdev);
-err_pci_req_region:
- pci_disable_device(pdev);
- return retval;
}
static struct pci_driver lnw_gpio_driver = {
@@ -422,88 +389,9 @@ static struct pci_driver lnw_gpio_driver = {
},
};
-
-static int wp_gpio_probe(struct platform_device *pdev)
-{
- struct lnw_gpio *lnw;
- struct gpio_chip *gc;
- struct resource *rc;
- int retval = 0;
-
- rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!rc)
- return -EINVAL;
-
- lnw = kzalloc(sizeof(struct lnw_gpio), GFP_KERNEL);
- if (!lnw) {
- dev_err(&pdev->dev,
- "can't allocate whitneypoint_gpio chip data\n");
- return -ENOMEM;
- }
- lnw->reg_base = ioremap_nocache(rc->start, resource_size(rc));
- if (lnw->reg_base == NULL) {
- retval = -EINVAL;
- goto err_kmalloc;
- }
- spin_lock_init(&lnw->lock);
- gc = &lnw->chip;
- gc->label = dev_name(&pdev->dev);
- gc->owner = THIS_MODULE;
- gc->direction_input = lnw_gpio_direction_input;
- gc->direction_output = lnw_gpio_direction_output;
- gc->get = lnw_gpio_get;
- gc->set = lnw_gpio_set;
- gc->to_irq = NULL;
- gc->base = 0;
- gc->ngpio = 64;
- gc->can_sleep = 0;
- retval = gpiochip_add(gc);
- if (retval) {
- dev_err(&pdev->dev, "whitneypoint gpiochip_add error %d\n",
- retval);
- goto err_ioremap;
- }
- platform_set_drvdata(pdev, lnw);
- return 0;
-err_ioremap:
- iounmap(lnw->reg_base);
-err_kmalloc:
- kfree(lnw);
- return retval;
-}
-
-static int wp_gpio_remove(struct platform_device *pdev)
-{
- struct lnw_gpio *lnw = platform_get_drvdata(pdev);
- int err;
- err = gpiochip_remove(&lnw->chip);
- if (err)
- dev_err(&pdev->dev, "failed to remove gpio_chip.\n");
- iounmap(lnw->reg_base);
- kfree(lnw);
- platform_set_drvdata(pdev, NULL);
- return 0;
-}
-
-static struct platform_driver wp_gpio_driver = {
- .probe = wp_gpio_probe,
- .remove = wp_gpio_remove,
- .driver = {
- .name = "wp_gpio",
- .owner = THIS_MODULE,
- },
-};
-
static int __init lnw_gpio_init(void)
{
- int ret;
- ret = pci_register_driver(&lnw_gpio_driver);
- if (ret < 0)
- return ret;
- ret = platform_driver_register(&wp_gpio_driver);
- if (ret < 0)
- pci_unregister_driver(&lnw_gpio_driver);
- return ret;
+ return pci_register_driver(&lnw_gpio_driver);
}
device_initcall(lnw_gpio_init);
diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c
index 86c17de8769..761c4705dfb 100644
--- a/drivers/gpio/gpio-lynxpoint.c
+++ b/drivers/gpio/gpio-lynxpoint.c
@@ -447,7 +447,6 @@ static int lp_gpio_remove(struct platform_device *pdev)
err = gpiochip_remove(&lg->chip);
if (err)
dev_warn(&pdev->dev, "failed to remove gpio_chip.\n");
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c
index 0966f2637ad..6da6d7667c6 100644
--- a/drivers/gpio/gpio-ml-ioh.c
+++ b/drivers/gpio/gpio-ml-ioh.c
@@ -465,6 +465,7 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
dev_warn(&pdev->dev,
"ml_ioh_gpio: Failed to get IRQ base num\n");
chip->irq_base = -1;
+ ret = irq_base;
goto err_irq_alloc_descs;
}
chip->irq_base = irq_base;
diff --git a/drivers/gpio/gpio-msm-v1.c b/drivers/gpio/gpio-msm-v1.c
index c798585a3fe..73b73969d36 100644
--- a/drivers/gpio/gpio-msm-v1.c
+++ b/drivers/gpio/gpio-msm-v1.c
@@ -21,6 +21,7 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
+#include <linux/err.h>
#include <mach/msm_gpiomux.h>
@@ -630,7 +631,7 @@ static struct irq_chip msm_gpio_irq_chip = {
.irq_set_type = msm_gpio_irq_set_type,
};
-static int __devinit gpio_msm_v1_probe(struct platform_device *pdev)
+static int gpio_msm_v1_probe(struct platform_device *pdev)
{
int i, j = 0;
const struct platform_device_id *dev_id = platform_get_device_id(pdev);
@@ -652,14 +653,14 @@ static int __devinit gpio_msm_v1_probe(struct platform_device *pdev)
return irq2;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base1 = devm_request_and_ioremap(&pdev->dev, res);
- if (!base1)
- return -EADDRNOTAVAIL;
+ base1 = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base1))
+ return PTR_ERR(base1);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- base2 = devm_request_and_ioremap(&pdev->dev, res);
- if (!base2)
- return -EADDRNOTAVAIL;
+ base2 = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base2))
+ return PTR_ERR(base2);
for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
if (i - FIRST_GPIO_IRQ >=
diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c
index dd2eddeb1e0..c2fa77086eb 100644
--- a/drivers/gpio/gpio-msm-v2.c
+++ b/drivers/gpio/gpio-msm-v2.c
@@ -19,18 +19,21 @@
#include <linux/bitmap.h>
#include <linux/bitops.h>
+#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/module.h>
+#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
+#include <linux/slab.h>
-#include <mach/msm_gpiomux.h>
-#include <mach/msm_iomap.h>
+#define MAX_NR_GPIO 300
/* Bits of interest in the GPIO_IN_OUT register.
*/
@@ -77,13 +80,6 @@ enum {
TARGET_PROC_NONE = 7,
};
-
-#define GPIO_INTR_CFG_SU(gpio) (MSM_TLMM_BASE + 0x0400 + (0x04 * (gpio)))
-#define GPIO_CONFIG(gpio) (MSM_TLMM_BASE + 0x1000 + (0x10 * (gpio)))
-#define GPIO_IN_OUT(gpio) (MSM_TLMM_BASE + 0x1004 + (0x10 * (gpio)))
-#define GPIO_INTR_CFG(gpio) (MSM_TLMM_BASE + 0x1008 + (0x10 * (gpio)))
-#define GPIO_INTR_STATUS(gpio) (MSM_TLMM_BASE + 0x100c + (0x10 * (gpio)))
-
/**
* struct msm_gpio_dev: the MSM8660 SoC GPIO device structure
*
@@ -102,11 +98,27 @@ enum {
*/
struct msm_gpio_dev {
struct gpio_chip gpio_chip;
- DECLARE_BITMAP(enabled_irqs, NR_GPIO_IRQS);
- DECLARE_BITMAP(wake_irqs, NR_GPIO_IRQS);
- DECLARE_BITMAP(dual_edge_irqs, NR_GPIO_IRQS);
+ DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO);
+ DECLARE_BITMAP(wake_irqs, MAX_NR_GPIO);
+ DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO);
+ struct irq_domain *domain;
+ unsigned int summary_irq;
+ void __iomem *msm_tlmm_base;
};
+struct msm_gpio_dev msm_gpio;
+
+#define GPIO_INTR_CFG_SU(gpio) (msm_gpio.msm_tlmm_base + 0x0400 + \
+ (0x04 * (gpio)))
+#define GPIO_CONFIG(gpio) (msm_gpio.msm_tlmm_base + 0x1000 + \
+ (0x10 * (gpio)))
+#define GPIO_IN_OUT(gpio) (msm_gpio.msm_tlmm_base + 0x1004 + \
+ (0x10 * (gpio)))
+#define GPIO_INTR_CFG(gpio) (msm_gpio.msm_tlmm_base + 0x1008 + \
+ (0x10 * (gpio)))
+#define GPIO_INTR_STATUS(gpio) (msm_gpio.msm_tlmm_base + 0x100c + \
+ (0x10 * (gpio)))
+
static DEFINE_SPINLOCK(tlmm_lock);
static inline struct msm_gpio_dev *to_msm_gpio_dev(struct gpio_chip *chip)
@@ -159,37 +171,29 @@ static int msm_gpio_direction_output(struct gpio_chip *chip,
static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
{
- return msm_gpiomux_get(chip->base + offset);
+ return 0;
}
static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
{
- msm_gpiomux_put(chip->base + offset);
+ return;
}
static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
- return MSM_GPIO_TO_INT(chip->base + offset);
+ struct msm_gpio_dev *g_dev = to_msm_gpio_dev(chip);
+ struct irq_domain *domain = g_dev->domain;
+
+ return irq_create_mapping(domain, offset);
}
static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq)
{
- return irq - MSM_GPIO_TO_INT(chip->base);
+ struct irq_data *irq_data = irq_get_irq_data(irq);
+
+ return irq_data->hwirq;
}
-static struct msm_gpio_dev msm_gpio = {
- .gpio_chip = {
- .base = 0,
- .ngpio = NR_GPIO_IRQS,
- .direction_input = msm_gpio_direction_input,
- .direction_output = msm_gpio_direction_output,
- .get = msm_gpio_get,
- .set = msm_gpio_set,
- .to_irq = msm_gpio_to_irq,
- .request = msm_gpio_request,
- .free = msm_gpio_free,
- },
-};
/* For dual-edge interrupts in software, since the hardware has no
* such support:
@@ -227,9 +231,9 @@ static void msm_gpio_update_dual_edge_pos(unsigned gpio)
if (intstat || val == val2)
return;
} while (loop_limit-- > 0);
- pr_err("dual-edge irq failed to stabilize, "
+ pr_err("%s: dual-edge irq failed to stabilize, "
"interrupts dropped. %#08x != %#08x\n",
- val, val2);
+ __func__, val, val2);
}
static void msm_gpio_irq_ack(struct irq_data *d)
@@ -316,10 +320,10 @@ static void msm_summary_irq_handler(unsigned int irq, struct irq_desc *desc)
chained_irq_enter(chip, desc);
- for_each_set_bit(i, msm_gpio.enabled_irqs, NR_GPIO_IRQS) {
+ for_each_set_bit(i, msm_gpio.enabled_irqs, MAX_NR_GPIO) {
if (readl(GPIO_INTR_STATUS(i)) & BIT(INTR_STATUS))
- generic_handle_irq(msm_gpio_to_irq(&msm_gpio.gpio_chip,
- i));
+ generic_handle_irq(irq_find_mapping(msm_gpio.domain,
+ i));
}
chained_irq_exit(chip, desc);
@@ -330,13 +334,13 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
if (on) {
- if (bitmap_empty(msm_gpio.wake_irqs, NR_GPIO_IRQS))
- irq_set_irq_wake(TLMM_SCSS_SUMMARY_IRQ, 1);
+ if (bitmap_empty(msm_gpio.wake_irqs, MAX_NR_GPIO))
+ irq_set_irq_wake(msm_gpio.summary_irq, 1);
set_bit(gpio, msm_gpio.wake_irqs);
} else {
clear_bit(gpio, msm_gpio.wake_irqs);
- if (bitmap_empty(msm_gpio.wake_irqs, NR_GPIO_IRQS))
- irq_set_irq_wake(TLMM_SCSS_SUMMARY_IRQ, 0);
+ if (bitmap_empty(msm_gpio.wake_irqs, MAX_NR_GPIO))
+ irq_set_irq_wake(msm_gpio.summary_irq, 0);
}
return 0;
@@ -351,30 +355,86 @@ static struct irq_chip msm_gpio_irq_chip = {
.irq_set_wake = msm_gpio_irq_set_wake,
};
-static int msm_gpio_probe(struct platform_device *dev)
+static struct lock_class_key msm_gpio_lock_class;
+
+static int msm_gpio_irq_domain_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
{
- int i, irq, ret;
+ irq_set_lockdep_class(irq, &msm_gpio_lock_class);
+ irq_set_chip_and_handler(irq, &msm_gpio_irq_chip,
+ handle_level_irq);
+ set_irq_flags(irq, IRQF_VALID);
+
+ return 0;
+}
+
+static const struct irq_domain_ops msm_gpio_irq_domain_ops = {
+ .xlate = irq_domain_xlate_twocell,
+ .map = msm_gpio_irq_domain_map,
+};
+
+static int msm_gpio_probe(struct platform_device *pdev)
+{
+ int ret, ngpio;
+ struct resource *res;
+
+ if (of_property_read_u32(pdev->dev.of_node, "ngpio", &ngpio)) {
+ dev_err(&pdev->dev, "%s: ngpio property missing\n", __func__);
+ return -EINVAL;
+ }
+
+ if (ngpio > MAX_NR_GPIO)
+ WARN(1, "ngpio exceeds the MAX_NR_GPIO. Increase MAX_NR_GPIO\n");
+
+ bitmap_zero(msm_gpio.enabled_irqs, MAX_NR_GPIO);
+ bitmap_zero(msm_gpio.wake_irqs, MAX_NR_GPIO);
+ bitmap_zero(msm_gpio.dual_edge_irqs, MAX_NR_GPIO);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ msm_gpio.msm_tlmm_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(msm_gpio.msm_tlmm_base))
+ return PTR_ERR(msm_gpio.msm_tlmm_base);
+
+ msm_gpio.gpio_chip.ngpio = ngpio;
+ msm_gpio.gpio_chip.label = pdev->name;
+ msm_gpio.gpio_chip.dev = &pdev->dev;
+ msm_gpio.gpio_chip.base = 0;
+ msm_gpio.gpio_chip.direction_input = msm_gpio_direction_input;
+ msm_gpio.gpio_chip.direction_output = msm_gpio_direction_output;
+ msm_gpio.gpio_chip.get = msm_gpio_get;
+ msm_gpio.gpio_chip.set = msm_gpio_set;
+ msm_gpio.gpio_chip.to_irq = msm_gpio_to_irq;
+ msm_gpio.gpio_chip.request = msm_gpio_request;
+ msm_gpio.gpio_chip.free = msm_gpio_free;
- bitmap_zero(msm_gpio.enabled_irqs, NR_GPIO_IRQS);
- bitmap_zero(msm_gpio.wake_irqs, NR_GPIO_IRQS);
- bitmap_zero(msm_gpio.dual_edge_irqs, NR_GPIO_IRQS);
- msm_gpio.gpio_chip.label = dev->name;
ret = gpiochip_add(&msm_gpio.gpio_chip);
- if (ret < 0)
+ if (ret < 0) {
+ dev_err(&pdev->dev, "gpiochip_add failed with error %d\n", ret);
return ret;
+ }
- for (i = 0; i < msm_gpio.gpio_chip.ngpio; ++i) {
- irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
- irq_set_chip_and_handler(irq, &msm_gpio_irq_chip,
- handle_level_irq);
- set_irq_flags(irq, IRQF_VALID);
+ msm_gpio.summary_irq = platform_get_irq(pdev, 0);
+ if (msm_gpio.summary_irq < 0) {
+ dev_err(&pdev->dev, "No Summary irq defined for msmgpio\n");
+ return msm_gpio.summary_irq;
}
- irq_set_chained_handler(TLMM_SCSS_SUMMARY_IRQ,
- msm_summary_irq_handler);
+ msm_gpio.domain = irq_domain_add_linear(pdev->dev.of_node, ngpio,
+ &msm_gpio_irq_domain_ops,
+ &msm_gpio);
+ if (!msm_gpio.domain)
+ return -ENODEV;
+
+ irq_set_chained_handler(msm_gpio.summary_irq, msm_summary_irq_handler);
+
return 0;
}
+static struct of_device_id msm_gpio_of_match[] = {
+ { .compatible = "qcom,msm-gpio", },
+ { },
+};
+
static int msm_gpio_remove(struct platform_device *dev)
{
int ret = gpiochip_remove(&msm_gpio.gpio_chip);
@@ -382,7 +442,7 @@ static int msm_gpio_remove(struct platform_device *dev)
if (ret < 0)
return ret;
- irq_set_handler(TLMM_SCSS_SUMMARY_IRQ, NULL);
+ irq_set_handler(msm_gpio.summary_irq, NULL);
return 0;
}
@@ -393,36 +453,11 @@ static struct platform_driver msm_gpio_driver = {
.driver = {
.name = "msmgpio",
.owner = THIS_MODULE,
+ .of_match_table = msm_gpio_of_match,
},
};
-static struct platform_device msm_device_gpio = {
- .name = "msmgpio",
- .id = -1,
-};
-
-static int __init msm_gpio_init(void)
-{
- int rc;
-
- rc = platform_driver_register(&msm_gpio_driver);
- if (!rc) {
- rc = platform_device_register(&msm_device_gpio);
- if (rc)
- platform_driver_unregister(&msm_gpio_driver);
- }
-
- return rc;
-}
-
-static void __exit msm_gpio_exit(void)
-{
- platform_device_unregister(&msm_device_gpio);
- platform_driver_unregister(&msm_gpio_driver);
-}
-
-postcore_initcall(msm_gpio_init);
-module_exit(msm_gpio_exit);
+module_platform_driver(msm_gpio_driver)
MODULE_AUTHOR("Gregory Bean <gbean@codeaurora.org>");
MODULE_DESCRIPTION("Driver for Qualcomm MSM TLMMv2 SoC GPIOs");
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index 3a4816adc13..80ad35e2a8c 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -457,7 +457,7 @@ static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
if (!(cause & (1 << i)))
continue;
- type = irqd_get_trigger_type(irq_get_irq_data(irq));
+ type = irq_get_trigger_type(irq);
if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
/* Swap polarity (race with GPIO line) */
u32 polarity;
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 4a430360af5..dfeb3a3a8f2 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -1482,7 +1482,7 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
#else
#define omap_gpio_runtime_suspend NULL
#define omap_gpio_runtime_resume NULL
-static void omap_gpio_init_context(struct gpio_bank *p) {}
+static inline void omap_gpio_init_context(struct gpio_bank *p) {}
#endif
static const struct dev_pm_ops gpio_pm_ops = {
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index b4ca450947b..e8198dd6861 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -49,6 +49,9 @@ struct gpio_rcar_priv {
#define POSNEG 0x20
#define EDGLEVEL 0x24
#define FILONOFF 0x28
+#define BOTHEDGE 0x4c
+
+#define RCAR_MAX_GPIO_PER_BANK 32
static inline u32 gpio_rcar_read(struct gpio_rcar_priv *p, int offs)
{
@@ -91,7 +94,8 @@ static void gpio_rcar_irq_enable(struct irq_data *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)
+ bool level_trigger,
+ bool both)
{
unsigned long flags;
@@ -108,6 +112,10 @@ static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p,
/* Configure edge or level trigger in EDGLEVEL */
gpio_rcar_modify_bit(p, EDGLEVEL, hwirq, !level_trigger);
+ /* Select one edge or both edges in BOTHEDGE */
+ if (p->config.has_both_edge_trigger)
+ gpio_rcar_modify_bit(p, BOTHEDGE, hwirq, both);
+
/* Select "Interrupt Input Mode" in IOINTSEL */
gpio_rcar_modify_bit(p, IOINTSEL, hwirq, true);
@@ -127,16 +135,26 @@ static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type)
switch (type & IRQ_TYPE_SENSE_MASK) {
case IRQ_TYPE_LEVEL_HIGH:
- gpio_rcar_config_interrupt_input_mode(p, hwirq, true, true);
+ gpio_rcar_config_interrupt_input_mode(p, hwirq, true, true,
+ false);
break;
case IRQ_TYPE_LEVEL_LOW:
- gpio_rcar_config_interrupt_input_mode(p, hwirq, false, true);
+ gpio_rcar_config_interrupt_input_mode(p, hwirq, false, true,
+ false);
break;
case IRQ_TYPE_EDGE_RISING:
- gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false);
+ gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false,
+ false);
break;
case IRQ_TYPE_EDGE_FALLING:
- gpio_rcar_config_interrupt_input_mode(p, hwirq, false, false);
+ gpio_rcar_config_interrupt_input_mode(p, hwirq, false, false,
+ false);
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ if (!p->config.has_both_edge_trigger)
+ return -EINVAL;
+ gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false,
+ true);
break;
default:
return -EINVAL;
@@ -214,7 +232,14 @@ static int gpio_rcar_direction_input(struct gpio_chip *chip, unsigned offset)
static int gpio_rcar_get(struct gpio_chip *chip, unsigned offset)
{
- return (int)(gpio_rcar_read(gpio_to_priv(chip), INDT) & BIT(offset));
+ u32 bit = BIT(offset);
+
+ /* testing on r8a7790 shows that INDT does not show correct pin state
+ * when configured as output, so use OUTDT in case of output pins */
+ if (gpio_rcar_read(gpio_to_priv(chip), INOUTSEL) & bit)
+ return (int)(gpio_rcar_read(gpio_to_priv(chip), OUTDT) & bit);
+ else
+ return (int)(gpio_rcar_read(gpio_to_priv(chip), INDT) & bit);
}
static void gpio_rcar_set(struct gpio_chip *chip, unsigned offset, int value)
@@ -258,9 +283,35 @@ static struct irq_domain_ops gpio_rcar_irq_domain_ops = {
.map = gpio_rcar_irq_domain_map,
};
+static void gpio_rcar_parse_pdata(struct gpio_rcar_priv *p)
+{
+ struct gpio_rcar_config *pdata = p->pdev->dev.platform_data;
+ struct device_node *np = p->pdev->dev.of_node;
+ struct of_phandle_args args;
+ int ret;
+
+ if (pdata) {
+ p->config = *pdata;
+ } else if (IS_ENABLED(CONFIG_OF) && np) {
+ ret = of_parse_phandle_with_args(np, "gpio-ranges",
+ "#gpio-range-cells", 0, &args);
+ p->config.number_of_pins = ret == 0 && args.args_count == 3
+ ? args.args[2]
+ : RCAR_MAX_GPIO_PER_BANK;
+ p->config.gpio_base = -1;
+ }
+
+ if (p->config.number_of_pins == 0 ||
+ p->config.number_of_pins > RCAR_MAX_GPIO_PER_BANK) {
+ dev_warn(&p->pdev->dev,
+ "Invalid number of gpio lines %u, using %u\n",
+ p->config.number_of_pins, RCAR_MAX_GPIO_PER_BANK);
+ p->config.number_of_pins = RCAR_MAX_GPIO_PER_BANK;
+ }
+}
+
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;
@@ -275,14 +326,14 @@ static int gpio_rcar_probe(struct platform_device *pdev)
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);
+ /* Get device configuration from DT node or platform data. */
+ gpio_rcar_parse_pdata(p);
+
+ platform_set_drvdata(pdev, p);
+
io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
@@ -309,6 +360,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
gpio_chip->set = gpio_rcar_set;
gpio_chip->to_irq = gpio_rcar_to_irq;
gpio_chip->label = name;
+ gpio_chip->dev = &pdev->dev;
gpio_chip->owner = THIS_MODULE;
gpio_chip->base = p->config.gpio_base;
gpio_chip->ngpio = p->config.number_of_pins;
@@ -333,7 +385,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
}
if (devm_request_irq(&pdev->dev, irq->start,
- gpio_rcar_irq_handler, 0, name, p)) {
+ gpio_rcar_irq_handler, IRQF_SHARED, name, p)) {
dev_err(&pdev->dev, "failed to request IRQ\n");
ret = -ENOENT;
goto err1;
@@ -355,10 +407,12 @@ static int gpio_rcar_probe(struct platform_device *pdev)
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");
+ if (p->config.pctl_name) {
+ 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;
@@ -381,11 +435,23 @@ static int gpio_rcar_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id gpio_rcar_of_table[] = {
+ {
+ .compatible = "renesas,gpio-rcar",
+ },
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, gpio_rcar_of_table);
+#endif
+
static struct platform_driver gpio_rcar_device_driver = {
.probe = gpio_rcar_probe,
.remove = gpio_rcar_remove,
.driver = {
.name = "gpio_rcar",
+ .of_match_table = of_match_ptr(gpio_rcar_of_table),
}
};
diff --git a/drivers/gpio/gpio-rdc321x.c b/drivers/gpio/gpio-rdc321x.c
index 1bf55f67f7a..368c3c00fca 100644
--- a/drivers/gpio/gpio-rdc321x.c
+++ b/drivers/gpio/gpio-rdc321x.c
@@ -187,20 +187,18 @@ static int rdc321x_gpio_probe(struct platform_device *pdev)
rdc321x_gpio_dev->reg1_data_base,
&rdc321x_gpio_dev->data_reg[0]);
if (err)
- goto out_drvdata;
+ goto out_free;
err = pci_read_config_dword(rdc321x_gpio_dev->sb_pdev,
rdc321x_gpio_dev->reg2_data_base,
&rdc321x_gpio_dev->data_reg[1]);
if (err)
- goto out_drvdata;
+ goto out_free;
dev_info(&pdev->dev, "registering %d GPIOs\n",
rdc321x_gpio_dev->chip.ngpio);
return gpiochip_add(&rdc321x_gpio_dev->chip);
-out_drvdata:
- platform_set_drvdata(pdev, NULL);
out_free:
kfree(rdc321x_gpio_dev);
return err;
@@ -216,7 +214,6 @@ static int rdc321x_gpio_remove(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to unregister chip\n");
kfree(rdc321x_gpio_dev);
- platform_set_drvdata(pdev, NULL);
return ret;
}
diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c
index b22ca793374..a1392f47bbd 100644
--- a/drivers/gpio/gpio-samsung.c
+++ b/drivers/gpio/gpio-samsung.c
@@ -933,67 +933,6 @@ static void __init samsung_gpiolib_add(struct samsung_gpio_chip *chip)
s3c_gpiolib_track(chip);
}
-#if defined(CONFIG_PLAT_S3C24XX) && defined(CONFIG_OF)
-static int s3c24xx_gpio_xlate(struct gpio_chip *gc,
- const struct of_phandle_args *gpiospec, u32 *flags)
-{
- unsigned int pin;
-
- if (WARN_ON(gc->of_gpio_n_cells < 3))
- return -EINVAL;
-
- if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
- return -EINVAL;
-
- if (gpiospec->args[0] > gc->ngpio)
- return -EINVAL;
-
- pin = gc->base + gpiospec->args[0];
-
- if (s3c_gpio_cfgpin(pin, S3C_GPIO_SFN(gpiospec->args[1])))
- pr_warn("gpio_xlate: failed to set pin function\n");
- if (s3c_gpio_setpull(pin, gpiospec->args[2] & 0xffff))
- pr_warn("gpio_xlate: failed to set pin pull up/down\n");
-
- if (flags)
- *flags = gpiospec->args[2] >> 16;
-
- return gpiospec->args[0];
-}
-
-static const struct of_device_id s3c24xx_gpio_dt_match[] __initdata = {
- { .compatible = "samsung,s3c24xx-gpio", },
- {}
-};
-
-static __init void s3c24xx_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
- u64 base, u64 offset)
-{
- struct gpio_chip *gc = &chip->chip;
- u64 address;
-
- if (!of_have_populated_dt())
- return;
-
- address = chip->base ? base + ((u32)chip->base & 0xfff) : base + offset;
- gc->of_node = of_find_matching_node_by_address(NULL,
- s3c24xx_gpio_dt_match, address);
- if (!gc->of_node) {
- pr_info("gpio: device tree node not found for gpio controller"
- " with base address %08llx\n", address);
- return;
- }
- gc->of_gpio_n_cells = 3;
- gc->of_xlate = s3c24xx_gpio_xlate;
-}
-#else
-static __init void s3c24xx_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
- u64 base, u64 offset)
-{
- return;
-}
-#endif /* defined(CONFIG_PLAT_S3C24XX) && defined(CONFIG_OF) */
-
static void __init s3c24xx_gpiolib_add_chips(struct samsung_gpio_chip *chip,
int nr_chips, void __iomem *base)
{
@@ -1018,8 +957,6 @@ static void __init s3c24xx_gpiolib_add_chips(struct samsung_gpio_chip *chip,
gc->direction_output = samsung_gpiolib_2bit_output;
samsung_gpiolib_add(chip);
-
- s3c24xx_gpiolib_attach_ofnode(chip, S3C24XX_PA_GPIO, i * 0x10);
}
}
@@ -3026,6 +2963,10 @@ static __init int samsung_gpiolib_init(void)
*/
struct device_node *pctrl_np;
static const struct of_device_id exynos_pinctrl_ids[] = {
+ { .compatible = "samsung,s3c2412-pinctrl", },
+ { .compatible = "samsung,s3c2416-pinctrl", },
+ { .compatible = "samsung,s3c2440-pinctrl", },
+ { .compatible = "samsung,s3c2450-pinctrl", },
{ .compatible = "samsung,exynos4210-pinctrl", },
{ .compatible = "samsung,exynos4x12-pinctrl", },
{ .compatible = "samsung,exynos5250-pinctrl", },
diff --git a/drivers/gpio/gpio-sta2x11.c b/drivers/gpio/gpio-sta2x11.c
index 558542552aa..f43ab6aea28 100644
--- a/drivers/gpio/gpio-sta2x11.c
+++ b/drivers/gpio/gpio-sta2x11.c
@@ -371,8 +371,12 @@ static int gsta_probe(struct platform_device *dev)
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
chip = devm_kzalloc(&dev->dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
chip->dev = &dev->dev;
- chip->reg_base = devm_request_and_ioremap(&dev->dev, res);
+ chip->reg_base = devm_ioremap_resource(&dev->dev, res);
+ if (IS_ERR(chip->reg_base))
+ return PTR_ERR(chip->reg_base);
for (i = 0; i < GSTA_NR_BLOCKS; i++) {
chip->regs[i] = chip->reg_base + i * 4096;
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
index 3ce5bc38ac3..b33bad1bb4d 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -271,8 +271,8 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
return IRQ_HANDLED;
}
-int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq,
- irq_hw_number_t hwirq)
+static int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq,
+ irq_hw_number_t hwirq)
{
struct stmpe_gpio *stmpe_gpio = d->host_data;
@@ -292,7 +292,7 @@ int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq,
return 0;
}
-void stmpe_gpio_irq_unmap(struct irq_domain *d, unsigned int virq)
+static void stmpe_gpio_irq_unmap(struct irq_domain *d, unsigned int virq)
{
#ifdef CONFIG_ARM
set_irq_flags(virq, 0);
@@ -431,7 +431,6 @@ static int stmpe_gpio_remove(struct platform_device *pdev)
if (irq >= 0)
free_irq(irq, stmpe_gpio);
- platform_set_drvdata(pdev, NULL);
kfree(stmpe_gpio);
return 0;
diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c
index 796b6c42fa7..f371732591d 100644
--- a/drivers/gpio/gpio-sx150x.c
+++ b/drivers/gpio/gpio-sx150x.c
@@ -548,7 +548,8 @@ static int sx150x_install_irq_chip(struct sx150x_chip *chip,
#endif
}
- err = request_threaded_irq(irq_summary,
+ err = devm_request_threaded_irq(&chip->client->dev,
+ irq_summary,
NULL,
sx150x_irq_thread_fn,
IRQF_SHARED | IRQF_TRIGGER_FALLING,
@@ -567,8 +568,6 @@ static void sx150x_remove_irq_chip(struct sx150x_chip *chip)
unsigned n;
unsigned irq;
- free_irq(chip->irq_summary, chip);
-
for (n = 0; n < chip->dev_cfg->ngpios; ++n) {
irq = chip->irq_base + n;
irq_set_chip_and_handler(irq, NULL, NULL);
@@ -591,18 +590,19 @@ static int sx150x_probe(struct i2c_client *client,
if (!i2c_check_functionality(client->adapter, i2c_funcs))
return -ENOSYS;
- chip = kzalloc(sizeof(struct sx150x_chip), GFP_KERNEL);
+ chip = devm_kzalloc(&client->dev,
+ sizeof(struct sx150x_chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
sx150x_init_chip(chip, client, id->driver_data, pdata);
rc = sx150x_init_hw(chip, pdata);
if (rc < 0)
- goto probe_fail_pre_gpiochip_add;
+ return rc;
rc = gpiochip_add(&chip->gpio_chip);
- if (rc < 0)
- goto probe_fail_pre_gpiochip_add;
+ if (rc)
+ return rc;
if (pdata->irq_summary >= 0) {
rc = sx150x_install_irq_chip(chip,
@@ -617,8 +617,6 @@ static int sx150x_probe(struct i2c_client *client,
return 0;
probe_fail_post_gpiochip_add:
WARN_ON(gpiochip_remove(&chip->gpio_chip) < 0);
-probe_fail_pre_gpiochip_add:
- kfree(chip);
return rc;
}
@@ -635,8 +633,6 @@ static int sx150x_remove(struct i2c_client *client)
if (chip->irq_summary >= 0)
sx150x_remove_irq_chip(chip);
- kfree(chip);
-
return 0;
}
diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c
index d34d80dfb08..4a5de273c23 100644
--- a/drivers/gpio/gpio-tc3589x.c
+++ b/drivers/gpio/gpio-tc3589x.c
@@ -407,7 +407,6 @@ static int tc3589x_gpio_remove(struct platform_device *pdev)
free_irq(irq, tc3589x_gpio);
- platform_set_drvdata(pdev, NULL);
kfree(tc3589x_gpio);
return 0;
diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c
index 43774058b69..4c65f888320 100644
--- a/drivers/gpio/gpio-timberdale.c
+++ b/drivers/gpio/gpio-timberdale.c
@@ -342,8 +342,6 @@ static int timbgpio_remove(struct platform_device *pdev)
release_mem_region(iomem->start, resource_size(iomem));
kfree(tgpio);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/gpio/gpio-vx855.c b/drivers/gpio/gpio-vx855.c
index 2b7252cb242..cddfa22edb4 100644
--- a/drivers/gpio/gpio-vx855.c
+++ b/drivers/gpio/gpio-vx855.c
@@ -279,7 +279,6 @@ out_release:
release_region(res_gpi->start, resource_size(res_gpi));
if (vg->gpo_reserved)
release_region(res_gpi->start, resource_size(res_gpo));
- platform_set_drvdata(pdev, NULL);
kfree(vg);
return ret;
}
@@ -301,7 +300,6 @@ static int vx855gpio_remove(struct platform_device *pdev)
release_region(res->start, resource_size(res));
}
- platform_set_drvdata(pdev, NULL);
kfree(vg);
return 0;
}
diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c
index 9ae7aa8ca48..792a05ad464 100644
--- a/drivers/gpio/gpio-xilinx.c
+++ b/drivers/gpio/gpio-xilinx.c
@@ -1,7 +1,7 @@
/*
- * Xilinx gpio driver
+ * Xilinx gpio driver for xps/axi_gpio IP.
*
- * Copyright 2008 Xilinx, Inc.
+ * Copyright 2008 - 2013 Xilinx, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
@@ -12,6 +12,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <linux/bitops.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/module.h>
@@ -26,11 +27,31 @@
#define XGPIO_DATA_OFFSET (0x0) /* Data register */
#define XGPIO_TRI_OFFSET (0x4) /* I/O direction register */
+#define XGPIO_CHANNEL_OFFSET 0x8
+
+/* Read/Write access to the GPIO registers */
+#ifdef CONFIG_ARCH_ZYNQ
+# define xgpio_readreg(offset) readl(offset)
+# define xgpio_writereg(offset, val) writel(val, offset)
+#else
+# define xgpio_readreg(offset) __raw_readl(offset)
+# define xgpio_writereg(offset, val) __raw_writel(val, offset)
+#endif
+
+/**
+ * struct xgpio_instance - Stores information about GPIO device
+ * struct of_mm_gpio_chip mmchip: OF GPIO chip for memory mapped banks
+ * gpio_state: GPIO state shadow register
+ * gpio_dir: GPIO direction shadow register
+ * offset: GPIO channel offset
+ * gpio_lock: Lock used for synchronization
+ */
struct xgpio_instance {
struct of_mm_gpio_chip mmchip;
- u32 gpio_state; /* GPIO state shadow register */
- u32 gpio_dir; /* GPIO direction shadow register */
- spinlock_t gpio_lock; /* Lock used for synchronization */
+ u32 gpio_state;
+ u32 gpio_dir;
+ u32 offset;
+ spinlock_t gpio_lock;
};
/**
@@ -44,8 +65,12 @@ struct xgpio_instance {
static int xgpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct xgpio_instance *chip =
+ container_of(mm_gc, struct xgpio_instance, mmchip);
- return (in_be32(mm_gc->regs + XGPIO_DATA_OFFSET) >> gpio) & 1;
+ void __iomem *regs = mm_gc->regs + chip->offset;
+
+ return !!(xgpio_readreg(regs + XGPIO_DATA_OFFSET) & BIT(gpio));
}
/**
@@ -63,15 +88,18 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip =
container_of(mm_gc, struct xgpio_instance, mmchip);
+ void __iomem *regs = mm_gc->regs;
spin_lock_irqsave(&chip->gpio_lock, flags);
/* Write to GPIO signal and set its direction to output */
if (val)
- chip->gpio_state |= 1 << gpio;
+ chip->gpio_state |= BIT(gpio);
else
- chip->gpio_state &= ~(1 << gpio);
- out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state);
+ chip->gpio_state &= ~BIT(gpio);
+
+ xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET,
+ chip->gpio_state);
spin_unlock_irqrestore(&chip->gpio_lock, flags);
}
@@ -91,12 +119,13 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip =
container_of(mm_gc, struct xgpio_instance, mmchip);
+ void __iomem *regs = mm_gc->regs;
spin_lock_irqsave(&chip->gpio_lock, flags);
/* Set the GPIO bit in shadow register and set direction as input */
- chip->gpio_dir |= (1 << gpio);
- out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir);
+ chip->gpio_dir |= BIT(gpio);
+ xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir);
spin_unlock_irqrestore(&chip->gpio_lock, flags);
@@ -119,19 +148,21 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip =
container_of(mm_gc, struct xgpio_instance, mmchip);
+ void __iomem *regs = mm_gc->regs;
spin_lock_irqsave(&chip->gpio_lock, flags);
/* Write state of GPIO signal */
if (val)
- chip->gpio_state |= 1 << gpio;
+ chip->gpio_state |= BIT(gpio);
else
- chip->gpio_state &= ~(1 << gpio);
- out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state);
+ chip->gpio_state &= ~BIT(gpio);
+ xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET,
+ chip->gpio_state);
/* Clear the GPIO bit in shadow register and set direction as output */
- chip->gpio_dir &= (~(1 << gpio));
- out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir);
+ chip->gpio_dir &= ~BIT(gpio);
+ xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir);
spin_unlock_irqrestore(&chip->gpio_lock, flags);
@@ -147,8 +178,10 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc)
struct xgpio_instance *chip =
container_of(mm_gc, struct xgpio_instance, mmchip);
- out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state);
- out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir);
+ xgpio_writereg(mm_gc->regs + chip->offset + XGPIO_DATA_OFFSET,
+ chip->gpio_state);
+ xgpio_writereg(mm_gc->regs + chip->offset + XGPIO_TRI_OFFSET,
+ chip->gpio_dir);
}
/**
@@ -170,24 +203,20 @@ static int xgpio_of_probe(struct device_node *np)
return -ENOMEM;
/* Update GPIO state shadow register with default value */
- tree_info = of_get_property(np, "xlnx,dout-default", NULL);
- if (tree_info)
- chip->gpio_state = be32_to_cpup(tree_info);
+ of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state);
+
+ /* By default, all pins are inputs */
+ chip->gpio_dir = 0xFFFFFFFF;
/* Update GPIO direction shadow register with default value */
- chip->gpio_dir = 0xFFFFFFFF; /* By default, all pins are inputs */
- tree_info = of_get_property(np, "xlnx,tri-default", NULL);
- if (tree_info)
- chip->gpio_dir = be32_to_cpup(tree_info);
+ of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir);
+
+ /* By default assume full GPIO controller */
+ chip->mmchip.gc.ngpio = 32;
/* Check device node and parent device node for device width */
- chip->mmchip.gc.ngpio = 32; /* By default assume full GPIO controller */
- tree_info = of_get_property(np, "xlnx,gpio-width", NULL);
- if (!tree_info)
- tree_info = of_get_property(np->parent,
- "xlnx,gpio-width", NULL);
- if (tree_info)
- chip->mmchip.gc.ngpio = be32_to_cpup(tree_info);
+ of_property_read_u32(np, "xlnx,gpio-width",
+ (u32 *)&chip->mmchip.gc.ngpio);
spin_lock_init(&chip->gpio_lock);
@@ -206,6 +235,57 @@ static int xgpio_of_probe(struct device_node *np)
np->full_name, status);
return status;
}
+
+ pr_info("XGpio: %s: registered, base is %d\n", np->full_name,
+ chip->mmchip.gc.base);
+
+ tree_info = of_get_property(np, "xlnx,is-dual", NULL);
+ if (tree_info && be32_to_cpup(tree_info)) {
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ /* Add dual channel offset */
+ chip->offset = XGPIO_CHANNEL_OFFSET;
+
+ /* Update GPIO state shadow register with default value */
+ of_property_read_u32(np, "xlnx,dout-default-2",
+ &chip->gpio_state);
+
+ /* By default, all pins are inputs */
+ chip->gpio_dir = 0xFFFFFFFF;
+
+ /* Update GPIO direction shadow register with default value */
+ of_property_read_u32(np, "xlnx,tri-default-2", &chip->gpio_dir);
+
+ /* By default assume full GPIO controller */
+ chip->mmchip.gc.ngpio = 32;
+
+ /* Check device node and parent device node for device width */
+ of_property_read_u32(np, "xlnx,gpio2-width",
+ (u32 *)&chip->mmchip.gc.ngpio);
+
+ spin_lock_init(&chip->gpio_lock);
+
+ chip->mmchip.gc.direction_input = xgpio_dir_in;
+ chip->mmchip.gc.direction_output = xgpio_dir_out;
+ chip->mmchip.gc.get = xgpio_get;
+ chip->mmchip.gc.set = xgpio_set;
+
+ chip->mmchip.save_regs = xgpio_save_regs;
+
+ /* Call the OF gpio helper to setup and register the GPIO dev */
+ status = of_mm_gpiochip_add(np, &chip->mmchip);
+ if (status) {
+ kfree(chip);
+ pr_err("%s: error in probe function with status %d\n",
+ np->full_name, status);
+ return status;
+ }
+ pr_info("XGpio: %s: dual channel registered, base is %d\n",
+ np->full_name, chip->mmchip.gc.base);
+ }
+
return 0;
}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index c2534d62911..ff0fd655729 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1214,15 +1214,14 @@ int gpiochip_add(struct gpio_chip *chip)
}
}
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
#ifdef CONFIG_PINCTRL
INIT_LIST_HEAD(&chip->pin_ranges);
#endif
of_gpiochip_add(chip);
-unlock:
- spin_unlock_irqrestore(&gpio_lock, flags);
-
if (status)
goto fail;
@@ -1235,6 +1234,9 @@ unlock:
chip->label ? : "generic");
return 0;
+
+unlock:
+ spin_unlock_irqrestore(&gpio_lock, flags);
fail:
/* failures here can mean systems won't boot... */
pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n",