Commit 60b5adff authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'gpio-for-v3.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio

Pull GPIO updates from Linus Walleij:
 "Here is a batch of GPIO changes for v3.11.  I have agreed with Grant
  to take care of the pull requests for this development cycle.

  No special things are happening in the GPIO tree this time (nice with
  some calm) and I have been extra careful to do regression builds and
  it's well boiled in -next.

  GPIO changes for the v3.11 development cycle:
   - Incremental development for the Langwell (Atom SoC), Xilinx, ICH
     and RCAR drivers.
   - Cleanups from Jingoo Han, Axel Lin, Wei Jongjun, Wolfram Sang,
     Tushar Behera, Sachin Kamat and Yijing Wang"

* tag 'gpio-for-v3.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (35 commits)
  Gpio/trivial: replace numeric with standard PM state macros
  gpiolib: remove warnning of allocations with IRQs disabled
  gpio: grgpio: Staticize local symbols
  gpio-langwell: remove Withney point support
  gpio: ich: add GPO_BLINK support
  gpio-sta2x11: Convert to use devm_ioremap_resource
  gpio_msm: Convert to use devm_ioremap_resource
  gpio-rcar: Use OUTDT when reading GPIOs configured as output
  gpio-sta2x11: Fix potential NULL pointer dereference
  gpio/omap: omap_gpio_init_context stub must be inline
  gpio: msm-v1: Remove errant __devinit to fix compile
  gpio: devres: make comments proper
  GPIO: xilinx: Enable driver for Xilinx zynq
  DT: Add documentation for gpio-xilinx
  GPIO: xilinx: Use BIT macro
  GPIO: xilinx: Use __raw_readl/__raw_writel IO functions
  GPIO: xilinx: Add support for dual channel
  GPIO: xilinx: Simplify driver probe function
  gpio: sx150x: convert to use devm_* functions
  MAINTAINERS: add linux-gpio mailing list
  ...
parents a9f4a700 038f0bab
Xilinx plb/axi GPIO controller
Dual channel GPIO controller with configurable number of pins
(from 1 to 32 per channel). Every pin can be configured as
input/output/tristate. Both channels share the same global IRQ but
local interrupts can be enabled on channel basis.
Required properties:
- compatible : Should be "xlnx,xps-gpio-1.00.a"
- reg : Address and length of the register set for the device
- #gpio-cells : Should be two. The first cell is the pin number and the
second cell is used to specify optional parameters (currently unused).
- gpio-controller : Marks the device node as a GPIO controller.
Optional properties:
- interrupts : Interrupt mapping for GPIO IRQ.
- interrupt-parent : Phandle for the interrupt controller that
services interrupts for this device.
- xlnx,all-inputs : if n-th bit is setup, GPIO-n is input
- xlnx,dout-default : if n-th bit is 1, GPIO-n default value is 1
- xlnx,gpio-width : gpio width
- xlnx,tri-default : if n-th bit is 1, GPIO-n is in tristate mode
- xlnx,is-dual : if 1, controller also uses the second channel
- xlnx,all-inputs-2 : as above but for the second channel
- xlnx,dout-default-2 : as above but the second channel
- xlnx,gpio2-width : as above but for the second channel
- xlnx,tri-default-2 : as above but for the second channel
Example:
gpio: gpio@40000000 {
#gpio-cells = <2>;
compatible = "xlnx,xps-gpio-1.00.a";
gpio-controller ;
interrupt-parent = <&microblaze_0_intc>;
interrupts = < 6 2 >;
reg = < 0x40000000 0x10000 >;
xlnx,all-inputs = <0x0>;
xlnx,all-inputs-2 = <0x0>;
xlnx,dout-default = <0x0>;
xlnx,dout-default-2 = <0x0>;
xlnx,gpio-width = <0x2>;
xlnx,gpio2-width = <0x2>;
xlnx,interrupt-present = <0x1>;
xlnx,is-dual = <0x1>;
xlnx,tri-default = <0xffffffff>;
xlnx,tri-default-2 = <0xffffffff>;
} ;
...@@ -3587,6 +3587,7 @@ GPIO SUBSYSTEM ...@@ -3587,6 +3587,7 @@ GPIO SUBSYSTEM
M: Grant Likely <grant.likely@linaro.org> M: Grant Likely <grant.likely@linaro.org>
M: Linus Walleij <linus.walleij@linaro.org> M: Linus Walleij <linus.walleij@linaro.org>
S: Maintained S: Maintained
L: linux-gpio@vger.kernel.org
T: git git://git.secretlab.ca/git/linux-2.6.git T: git git://git.secretlab.ca/git/linux-2.6.git
F: Documentation/gpio.txt F: Documentation/gpio.txt
F: drivers/gpio/ F: drivers/gpio/
......
...@@ -244,7 +244,7 @@ config GPIO_TS5500 ...@@ -244,7 +244,7 @@ config GPIO_TS5500
config GPIO_XILINX config GPIO_XILINX
bool "Xilinx GPIO support" bool "Xilinx GPIO support"
depends on PPC_OF || MICROBLAZE depends on PPC_OF || MICROBLAZE || ARCH_ZYNQ
help help
Say yes here to support the Xilinx FPGA GPIO device Say yes here to support the Xilinx FPGA GPIO device
...@@ -340,7 +340,7 @@ config GPIO_MAX7300 ...@@ -340,7 +340,7 @@ config GPIO_MAX7300
depends on I2C depends on I2C
select GPIO_MAX730X select GPIO_MAX730X
help help
GPIO driver for Maxim MAX7301 I2C-based GPIO expander. GPIO driver for Maxim MAX7300 I2C-based GPIO expander.
config GPIO_MAX732X config GPIO_MAX732X
tristate "MAX7319, MAX7320-7327 I2C Port Expanders" tristate "MAX7319, MAX7320-7327 I2C Port Expanders"
......
...@@ -34,10 +34,10 @@ static int devm_gpio_match(struct device *dev, void *res, void *data) ...@@ -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 * devm_gpio_request - request a GPIO for a managed device
* @dev: device to request the gpio for * @dev: device to request the GPIO for
* @gpio: gpio to allocate * @gpio: GPIO to allocate
* @label: the name of the requested gpio * @label: the name of the requested GPIO
* *
* Except for the extra @dev argument, this function takes the * Except for the extra @dev argument, this function takes the
* same arguments and performs the same function as * same arguments and performs the same function as
...@@ -101,9 +101,9 @@ int devm_gpio_request_one(struct device *dev, unsigned gpio, ...@@ -101,9 +101,9 @@ int devm_gpio_request_one(struct device *dev, unsigned gpio,
EXPORT_SYMBOL(devm_gpio_request_one); EXPORT_SYMBOL(devm_gpio_request_one);
/** /**
* devm_gpio_free - free an interrupt * devm_gpio_free - free a GPIO
* @dev: device to free gpio for * @dev: device to free GPIO for
* @gpio: gpio to free * @gpio: GPIO to free
* *
* Except for the extra @dev argument, this function takes the * Except for the extra @dev argument, this function takes the
* same arguments and performs the same function as gpio_free(). * same arguments and performs the same function as gpio_free().
......
...@@ -286,7 +286,7 @@ static int bt8xxgpio_resume(struct pci_dev *pdev) ...@@ -286,7 +286,7 @@ static int bt8xxgpio_resume(struct pci_dev *pdev)
unsigned long flags; unsigned long flags;
int err; int err;
pci_set_power_state(pdev, 0); pci_set_power_state(pdev, PCI_D0);
err = pci_enable_device(pdev); err = pci_enable_device(pdev);
if (err) if (err)
return err; return err;
......
...@@ -235,8 +235,8 @@ static irqreturn_t grgpio_irq_handler(int irq, void *dev) ...@@ -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 * This function will be called as a consequence of the call to
* irq_create_mapping in grgpio_to_irq * irq_create_mapping in grgpio_to_irq
*/ */
int grgpio_irq_map(struct irq_domain *d, unsigned int irq, static int grgpio_irq_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hwirq) irq_hw_number_t hwirq)
{ {
struct grgpio_priv *priv = d->host_data; struct grgpio_priv *priv = d->host_data;
struct grgpio_lirq *lirq; struct grgpio_lirq *lirq;
...@@ -291,7 +291,7 @@ int grgpio_irq_map(struct irq_domain *d, unsigned int irq, ...@@ -291,7 +291,7 @@ int grgpio_irq_map(struct irq_domain *d, unsigned int irq,
return ret; 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; struct grgpio_priv *priv = d->host_data;
int index; int index;
......
...@@ -41,12 +41,14 @@ enum GPIO_REG { ...@@ -41,12 +41,14 @@ enum GPIO_REG {
GPIO_USE_SEL = 0, GPIO_USE_SEL = 0,
GPIO_IO_SEL, GPIO_IO_SEL,
GPIO_LVL, 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 */ {0x00, 0x30, 0x40}, /* USE_SEL[1-3] offsets */
{0x04, 0x34, 0x44}, /* IO_SEL[1-3] offsets */ {0x04, 0x34, 0x44}, /* IO_SEL[1-3] offsets */
{0x0c, 0x38, 0x48}, /* LVL[1-3] offsets */ {0x0c, 0x38, 0x48}, /* LVL[1-3] offsets */
{0x18, 0x18, 0x18}, /* BLINK offset */
}; };
static const u8 ichx_reglen[3] = { static const u8 ichx_reglen[3] = {
...@@ -148,6 +150,10 @@ static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) ...@@ -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, static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
int val) 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. */ /* Set GPIO output value. */
ichx_write_bit(GPIO_LVL, nr, val, 0); ichx_write_bit(GPIO_LVL, nr, val, 0);
......
/* /*
* Moorestown platform Langwell chip GPIO driver * 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 * 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 * it under the terms of the GNU General Public License version 2 as
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
/* Supports: /* Supports:
* Moorestown platform Langwell chip. * Moorestown platform Langwell chip.
* Medfield platform Penwell chip. * Medfield platform Penwell chip.
* Whitney point.
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -65,7 +64,7 @@ enum GPIO_REG { ...@@ -65,7 +64,7 @@ enum GPIO_REG {
struct lnw_gpio { struct lnw_gpio {
struct gpio_chip chip; struct gpio_chip chip;
void *reg_base; void __iomem *reg_base;
spinlock_t lock; spinlock_t lock;
struct pci_dev *pdev; struct pci_dev *pdev;
struct irq_domain *domain; struct irq_domain *domain;
...@@ -74,15 +73,13 @@ struct lnw_gpio { ...@@ -74,15 +73,13 @@ struct lnw_gpio {
#define to_lnw_priv(chip) container_of(chip, struct lnw_gpio, chip) #define to_lnw_priv(chip) container_of(chip, struct lnw_gpio, chip)
static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset, 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); struct lnw_gpio *lnw = to_lnw_priv(chip);
unsigned nreg = chip->ngpio / 32; unsigned nreg = chip->ngpio / 32;
u8 reg = offset / 32; u8 reg = offset / 32;
void __iomem *ptr;
ptr = (void __iomem *)(lnw->reg_base + reg_type * nreg * 4 + reg * 4); return lnw->reg_base + reg_type * nreg * 4 + reg * 4;
return ptr;
} }
static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset, 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, ...@@ -91,10 +88,8 @@ static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset,
struct lnw_gpio *lnw = to_lnw_priv(chip); struct lnw_gpio *lnw = to_lnw_priv(chip);
unsigned nreg = chip->ngpio / 32; unsigned nreg = chip->ngpio / 32;
u8 reg = offset / 16; u8 reg = offset / 16;
void __iomem *ptr;
ptr = (void __iomem *)(lnw->reg_base + reg_type * nreg * 4 + reg * 4); return lnw->reg_base + reg_type * nreg * 4 + reg * 4;
return ptr;
} }
static int lnw_gpio_request(struct gpio_chip *chip, unsigned offset) static int lnw_gpio_request(struct gpio_chip *chip, unsigned offset)
...@@ -318,56 +313,40 @@ static const struct dev_pm_ops lnw_gpio_pm_ops = { ...@@ -318,56 +313,40 @@ static const struct dev_pm_ops lnw_gpio_pm_ops = {
}; };
static int lnw_gpio_probe(struct pci_dev *pdev, static int lnw_gpio_probe(struct pci_dev *pdev,
const struct pci_device_id *id) const struct pci_device_id *id)
{ {
void *base; void __iomem *base;
resource_size_t start, len;
struct lnw_gpio *lnw; struct lnw_gpio *lnw;
u32 gpio_base; u32 gpio_base;
u32 irq_base; u32 irq_base;
int retval; int retval;
int ngpio = id->driver_data; int ngpio = id->driver_data;
retval = pci_enable_device(pdev); retval = pcim_enable_device(pdev);
if (retval) if (retval)
return retval; return retval;
retval = pci_request_regions(pdev, "langwell_gpio"); retval = pcim_iomap_regions(pdev, 1 << 0 | 1 << 1, pci_name(pdev));
if (retval) { if (retval) {
dev_err(&pdev->dev, "error requesting resources\n"); dev_err(&pdev->dev, "I/O memory mapping error\n");
goto err_pci_req_region; return retval;
}
/* 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;
} }
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 */ /* release the IO mapping, since we already get the info from bar1 */
iounmap(base); pcim_iounmap_regions(pdev, 1 << 1);
/* 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;
}
lnw = devm_kzalloc(&pdev->dev, sizeof(*lnw), GFP_KERNEL); lnw = devm_kzalloc(&pdev->dev, sizeof(*lnw), GFP_KERNEL);
if (!lnw) { if (!lnw) {
dev_err(&pdev->dev, "can't allocate langwell_gpio chip data\n"); dev_err(&pdev->dev, "can't allocate chip data\n");
retval = -ENOMEM; return -ENOMEM;
goto err_ioremap;
} }
lnw->reg_base = base; lnw->reg_base = pcim_iomap_table(pdev)[0];
lnw->chip.label = dev_name(&pdev->dev); lnw->chip.label = dev_name(&pdev->dev);
lnw->chip.request = lnw_gpio_request; lnw->chip.request = lnw_gpio_request;
lnw->chip.direction_input = lnw_gpio_direction_input; lnw->chip.direction_input = lnw_gpio_direction_input;
...@@ -380,18 +359,18 @@ static int lnw_gpio_probe(struct pci_dev *pdev, ...@@ -380,18 +359,18 @@ static int lnw_gpio_probe(struct pci_dev *pdev,
lnw->chip.can_sleep = 0; lnw->chip.can_sleep = 0;
lnw->pdev = pdev; lnw->pdev = pdev;
spin_lock_init(&lnw->lock);
lnw->domain = irq_domain_add_simple(pdev->dev.of_node, ngpio, irq_base, lnw->domain = irq_domain_add_simple(pdev->dev.of_node, ngpio, irq_base,
&lnw_gpio_irq_ops, lnw); &lnw_gpio_irq_ops, lnw);
if (!lnw->domain) { if (!lnw->domain)
retval = -ENOMEM; return -ENOMEM;
goto err_ioremap;
}
pci_set_drvdata(pdev, lnw); pci_set_drvdata(pdev, lnw);
retval = gpiochip_add(&lnw->chip); retval = gpiochip_add(&lnw->chip);
if (retval) { if (retval) {
dev_err(&pdev->dev, "langwell gpiochip_add error %d\n", retval); dev_err(&pdev->dev, "gpiochip_add error %d\n", retval);
goto err_ioremap; return retval;
} }
lnw_irq_init_hw(lnw); lnw_irq_init_hw(lnw);
...@@ -399,18 +378,10 @@ static int lnw_gpio_probe(struct pci_dev *pdev, ...@@ -399,18 +378,10 @@ static int lnw_gpio_probe(struct pci_dev *pdev,
irq_set_handler_data(pdev->irq, lnw); irq_set_handler_data(pdev->irq, lnw);
irq_set_chained_handler(pdev->irq, lnw_irq_handler); irq_set_chained_handler(pdev->irq, lnw_irq_handler);
spin_lock_init(&lnw->lock);
pm_runtime_put_noidle(&pdev->dev); pm_runtime_put_noidle(&pdev->dev);
pm_runtime_allow(&pdev->dev); pm_runtime_allow(&pdev->dev);
return 0; 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 = { static struct pci_driver lnw_gpio_driver = {
...@@ -422,88 +393,9 @@ static struct pci_driver lnw_gpio_driver = { ...@@ -422,88 +393,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) static int __init lnw_gpio_init(void)
{ {
int ret; return pci_register_driver(&lnw_gpio_driver);
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;
} }
device_initcall(lnw_gpio_init); device_initcall(lnw_gpio_init);
...@@ -447,7 +447,6 @@ static int lp_gpio_remove(struct platform_device *pdev) ...@@ -447,7 +447,6 @@ static int lp_gpio_remove(struct platform_device *pdev)
err = gpiochip_remove(&lg->chip); err = gpiochip_remove(&lg->chip);
if (err) if (err)
dev_warn(&pdev->dev, "failed to remove gpio_chip.\n"); dev_warn(&pdev->dev, "failed to remove gpio_chip.\n");
platform_set_drvdata(pdev, NULL);
return 0; return 0;
} }
......
...@@ -465,6 +465,7 @@ static int ioh_gpio_probe(struct pci_dev *pdev, ...@@ -465,6 +465,7 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
dev_warn(&pdev->dev, dev_warn(&pdev->dev,
"ml_ioh_gpio: Failed to get IRQ base num\n"); "ml_ioh_gpio: Failed to get IRQ base num\n");
chip->irq_base = -1; chip->irq_base = -1;
ret = irq_base;
goto err_irq_alloc_descs; goto err_irq_alloc_descs;
} }
chip->irq_base = irq_base; chip->irq_base = irq_base;
......
...@@ -652,14 +652,14 @@ static int gpio_msm_v1_probe(struct platform_device *pdev) ...@@ -652,14 +652,14 @@ static int gpio_msm_v1_probe(struct platform_device *pdev)
return irq2; return irq2;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base1 = devm_request_and_ioremap(&pdev->dev, res); base1 = devm_ioremap_resource(&pdev->dev, res);
if (!base1) if (IS_ERR(base1))
return -EADDRNOTAVAIL; return PTR_ERR(base1);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1); res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
base2 = devm_request_and_ioremap(&pdev->dev, res); base2 = devm_ioremap_resource(&pdev->dev, res);
if (!base2) if (IS_ERR(base2))
return -EADDRNOTAVAIL; return PTR_ERR(base2);
for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) { for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
if (i - FIRST_GPIO_IRQ >= if (i - FIRST_GPIO_IRQ >=
......
...@@ -1482,7 +1482,7 @@ static void omap_gpio_restore_context(struct gpio_bank *bank) ...@@ -1482,7 +1482,7 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
#else #else
#define omap_gpio_runtime_suspend NULL #define omap_gpio_runtime_suspend NULL
#define omap_gpio_runtime_resume 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 #endif
static const struct dev_pm_ops gpio_pm_ops = { static const struct dev_pm_ops gpio_pm_ops = {
......
...@@ -232,7 +232,14 @@ static int gpio_rcar_direction_input(struct gpio_chip *chip, unsigned offset) ...@@ -232,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) 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) static void gpio_rcar_set(struct gpio_chip *chip, unsigned offset, int value)
......
...@@ -187,20 +187,18 @@ static int rdc321x_gpio_probe(struct platform_device *pdev) ...@@ -187,20 +187,18 @@ static int rdc321x_gpio_probe(struct platform_device *pdev)
rdc321x_gpio_dev->reg1_data_base, rdc321x_gpio_dev->reg1_data_base,
&rdc321x_gpio_dev->data_reg[0]); &rdc321x_gpio_dev->data_reg[0]);
if (err) if (err)
goto out_drvdata; goto out_free;
err = pci_read_config_dword(rdc321x_gpio_dev->sb_pdev, err = pci_read_config_dword(rdc321x_gpio_dev->sb_pdev,
rdc321x_gpio_dev->reg2_data_base, rdc321x_gpio_dev->reg2_data_base,
&rdc321x_gpio_dev->data_reg[1]); &rdc321x_gpio_dev->data_reg[1]);
if (err) if (err)
goto out_drvdata; goto out_free;
dev_info(&pdev->dev, "registering %d GPIOs\n", dev_info(&pdev->dev, "registering %d GPIOs\n",
rdc321x_gpio_dev->chip.ngpio); rdc321x_gpio_dev->chip.ngpio);
return gpiochip_add(&rdc321x_gpio_dev->chip); return gpiochip_add(&rdc321x_gpio_dev->chip);
out_drvdata:
platform_set_drvdata(pdev, NULL);
out_free: out_free:
kfree(rdc321x_gpio_dev); kfree(rdc321x_gpio_dev);
return err; return err;
...@@ -216,7 +214,6 @@ static int rdc321x_gpio_remove(struct platform_device *pdev) ...@@ -216,7 +214,6 @@ static int rdc321x_gpio_remove(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to unregister chip\n"); dev_err(&pdev->dev, "failed to unregister chip\n");
kfree(rdc321x_gpio_dev); kfree(rdc321x_gpio_dev);
platform_set_drvdata(pdev, NULL);
return ret; return ret;
} }
......
...@@ -371,8 +371,12 @@ static int gsta_probe(struct platform_device *dev) ...@@ -371,8 +371,12 @@ static int gsta_probe(struct platform_device *dev)
res = platform_get_resource(dev, IORESOURCE_MEM, 0); res = platform_get_resource(dev, IORESOURCE_MEM, 0);
chip = devm_kzalloc(&dev->dev, sizeof(*chip), GFP_KERNEL); chip = devm_kzalloc(&dev->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->dev = &dev->dev; 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++) { for (i = 0; i < GSTA_NR_BLOCKS; i++) {
chip->regs[i] = chip->reg_base + i * 4096; chip->regs[i] = chip->reg_base + i * 4096;
......
...@@ -271,8 +271,8 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev) ...@@ -271,8 +271,8 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq, static int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq,
irq_hw_number_t hwirq) irq_hw_number_t hwirq)
{ {
struct stmpe_gpio *stmpe_gpio = d->host_data; struct stmpe_gpio *stmpe_gpio = d->host_data;
...@@ -292,7 +292,7 @@ int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq, ...@@ -292,7 +292,7 @@ int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq,
return 0; 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 #ifdef CONFIG_ARM
set_irq_flags(virq, 0); set_irq_flags(virq, 0);
...@@ -431,7 +431,6 @@ static int stmpe_gpio_remove(struct platform_device *pdev) ...@@ -431,7 +431,6 @@ static int stmpe_gpio_remove(struct platform_device *pdev)
if (irq >= 0) if (irq >= 0)
free_irq(irq, stmpe_gpio); free_irq(irq, stmpe_gpio);
platform_set_drvdata(pdev, NULL);
kfree(stmpe_gpio); kfree(stmpe_gpio);
return 0; return 0;
......
...@@ -548,7 +548,8 @@ static int sx150x_install_irq_chip(struct sx150x_chip *chip, ...@@ -548,7 +548,8 @@ static int sx150x_install_irq_chip(struct sx150x_chip *chip,
#endif #endif
} }
err = request_threaded_irq(irq_summary, err = devm_request_threaded_irq(&chip->client->dev,
irq_summary,
NULL, NULL,
sx150x_irq_thread_fn, sx150x_irq_thread_fn,
IRQF_SHARED | IRQF_TRIGGER_FALLING, IRQF_SHARED | IRQF_TRIGGER_FALLING,
...@@ -567,8 +568,6 @@ static void sx150x_remove_irq_chip(struct sx150x_chip *chip) ...@@ -567,8 +568,6 @@ static void sx150x_remove_irq_chip(struct sx150x_chip *chip)
unsigned n; unsigned n;
unsigned irq; unsigned irq;
free_irq(chip->irq_summary, chip);
for (n = 0; n < chip->dev_cfg->ngpios; ++n) { for (n = 0; n < chip->dev_cfg->ngpios; ++n) {
irq = chip->irq_base + n; irq = chip->irq_base + n;
irq_set_chip_and_handler(irq, NULL, NULL); irq_set_chip_and_handler(irq, NULL, NULL);
...@@ -591,18 +590,19 @@ static int sx150x_probe(struct i2c_client *client, ...@@ -591,18 +590,19 @@ static int sx150x_probe(struct i2c_client *client,
if (!i2c_check_functionality(client->adapter, i2c_funcs)) if (!i2c_check_functionality(client->adapter, i2c_funcs))
return -ENOSYS; return -ENOSYS;
chip = kzalloc(sizeof(struct sx150x_chip), GFP_KERNEL); chip = devm_kzalloc(&client->dev,
sizeof(struct sx150x_chip), GFP_KERNEL);
if (!chip) if (!chip)
return -ENOMEM; return -ENOMEM;
sx150x_init_chip(chip, client, id->driver_data, pdata); sx150x_init_chip(chip, client, id->driver_data, pdata);
rc = sx150x_init_hw(chip, pdata); rc = sx150x_init_hw(chip, pdata);
if (rc < 0) if (rc < 0)
goto probe_fail_pre_gpiochip_add; return rc;
rc = gpiochip_add(&chip->gpio_chip); rc = gpiochip_add(&chip->gpio_chip);
if (rc < 0) if (rc)
goto probe_fail_pre_gpiochip_add; return rc;
if (pdata->irq_summary >= 0) { if (pdata->irq_summary >= 0) {
rc = sx150x_install_irq_chip(chip, rc = sx150x_install_irq_chip(chip,
...@@ -617,8 +617,6 @@ static int sx150x_probe(struct i2c_client *client, ...@@ -617,8 +617,6 @@ static int sx150x_probe(struct i2c_client *client,
return 0; return 0;
probe_fail_post_gpiochip_add: probe_fail_post_gpiochip_add:
WARN_ON(gpiochip_remove(&chip->gpio_chip) < 0); WARN_ON(gpiochip_remove(&chip->gpio_chip) < 0);
probe_fail_pre_gpiochip_add:
kfree(chip);
return rc; return rc;
} }
...@@ -635,8 +633,6 @@ static int sx150x_remove(struct i2c_client *client) ...@@ -635,8 +633,6 @@ static int sx150x_remove(struct i2c_client *client)
if (chip->irq_summary >= 0) if (chip->irq_summary >= 0)
sx150x_remove_irq_chip(chip); sx150x_remove_irq_chip(chip);
kfree(chip);
return 0; return 0;
} }
......
...@@ -407,7 +407,6 @@ static int tc3589x_gpio_remove(struct platform_device *pdev) ...@@ -407,7 +407,6 @@ static int tc3589x_gpio_remove(struct platform_device *pdev)
free_irq(irq, tc3589x_gpio); free_irq(irq, tc3589x_gpio);
platform_set_drvdata(pdev, NULL);
kfree(tc3589x_gpio); kfree(tc3589x_gpio);
return 0; return 0;
......
...@@ -342,8 +342,6 @@ static int timbgpio_remove(struct platform_device *pdev) ...@@ -342,8 +342,6 @@ static int timbgpio_remove(struct platform_device *pdev)
release_mem_region(iomem->start, resource_size(iomem)); release_mem_region(iomem->start, resource_size(iomem));
kfree(tgpio); kfree(tgpio);
platform_set_drvdata(pdev, NULL);
return 0; return 0;
} }
......
...@@ -279,7 +279,6 @@ static int vx855gpio_probe(struct platform_device *pdev) ...@@ -279,7 +279,6 @@ static int vx855gpio_probe(struct platform_device *pdev)
release_region(res_gpi->start, resource_size(res_gpi)); release_region(res_gpi->start, resource_size(res_gpi));
if (vg->gpo_reserved) if (vg->gpo_reserved)
release_region(res_gpi->start, resource_size(res_gpo)); release_region(res_gpi->start, resource_size(res_gpo));
platform_set_drvdata(pdev, NULL);
kfree(vg); kfree(vg);
return ret; return ret;
} }
...@@ -301,7 +300,6 @@ static int vx855gpio_remove(struct platform_device *pdev) ...@@ -301,7 +300,6 @@ static int vx855gpio_remove(struct platform_device *pdev)
release_region(res->start, resource_size(res)); release_region(res->start, resource_size(res));
} }
platform_set_drvdata(pdev, NULL);
kfree(vg); kfree(vg);
return 0; return 0;
} }
......
/* /*
* 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 * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 * it under the terms of the GNU General Public License version 2
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <linux/bitops.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -26,11 +27,31 @@ ...@@ -26,11 +27,31 @@
#define XGPIO_DATA_OFFSET (0x0) /* Data register */ #define XGPIO_DATA_OFFSET (0x0) /* Data register */
#define XGPIO_TRI_OFFSET (0x4) /* I/O direction 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 xgpio_instance {
struct of_mm_gpio_chip mmchip; struct of_mm_gpio_chip mmchip;
u32 gpio_state; /* GPIO state shadow register */ u32 gpio_state;
u32 gpio_dir; /* GPIO direction shadow register */ u32 gpio_dir;
spinlock_t gpio_lock; /* Lock used for synchronization */ u32 offset;
spinlock_t gpio_lock;
}; };
/** /**
...@@ -44,8 +65,12 @@ struct xgpio_instance { ...@@ -44,8 +65,12 @@ struct xgpio_instance {
static int xgpio_get(struct gpio_chip *gc, unsigned int gpio) 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 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) ...@@ -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 of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip = struct xgpio_instance *chip =
container_of(mm_gc, struct xgpio_instance, mmchip); container_of(mm_gc, struct xgpio_instance, mmchip);
void __iomem *regs = mm_gc->regs;
spin_lock_irqsave(&chip->gpio_lock, flags); spin_lock_irqsave(&chip->gpio_lock, flags);
/* Write to GPIO signal and set its direction to output */ /* Write to GPIO signal and set its direction to output */
if (val) if (val)
chip->gpio_state |= 1 << gpio; chip->gpio_state |= BIT(gpio);
else else
chip->gpio_state &= ~(1 << gpio); chip->gpio_state &= ~BIT(gpio);
out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state);
xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET,
chip->gpio_state);
spin_unlock_irqrestore(&chip->gpio_lock, flags); spin_unlock_irqrestore(&chip->gpio_lock, flags);
} }
...@@ -91,12 +119,13 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) ...@@ -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 of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip = struct xgpio_instance *chip =
container_of(mm_gc, struct xgpio_instance, mmchip); container_of(mm_gc, struct xgpio_instance, mmchip);
void __iomem *regs = mm_gc->regs;
spin_lock_irqsave(&chip->gpio_lock, flags); spin_lock_irqsave(&chip->gpio_lock, flags);
/* Set the GPIO bit in shadow register and set direction as input */ /* Set the GPIO bit in shadow register and set direction as input */
chip->gpio_dir |= (1 << gpio); chip->gpio_dir |= BIT(gpio);
out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir); xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir);
spin_unlock_irqrestore(&chip->gpio_lock, flags); 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) ...@@ -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 of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip = struct xgpio_instance *chip =
container_of(mm_gc, struct xgpio_instance, mmchip); container_of(mm_gc, struct xgpio_instance, mmchip);
void __iomem *regs = mm_gc->regs;
spin_lock_irqsave(&chip->gpio_lock, flags); spin_lock_irqsave(&chip->gpio_lock, flags);
/* Write state of GPIO signal */ /* Write state of GPIO signal */
if (val) if (val)
chip->gpio_state |= 1 << gpio; chip->gpio_state |= BIT(gpio);
else else
chip->gpio_state &= ~(1 << gpio); chip->gpio_state &= ~BIT(gpio);
out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state); xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET,
chip->gpio_state);
/* Clear the GPIO bit in shadow register and set direction as output */ /* Clear the GPIO bit in shadow register and set direction as output */
chip->gpio_dir &= (~(1 << gpio)); chip->gpio_dir &= ~BIT(gpio);
out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir); xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir);
spin_unlock_irqrestore(&chip->gpio_lock, flags); spin_unlock_irqrestore(&chip->gpio_lock, flags);
...@@ -147,8 +178,10 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc) ...@@ -147,8 +178,10 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc)
struct xgpio_instance *chip = struct xgpio_instance *chip =
container_of(mm_gc, struct xgpio_instance, mmchip); container_of(mm_gc, struct xgpio_instance, mmchip);
out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state); xgpio_writereg(mm_gc->regs + chip->offset + XGPIO_DATA_OFFSET,
out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir); 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) ...@@ -170,24 +203,20 @@ static int xgpio_of_probe(struct device_node *np)
return -ENOMEM; return -ENOMEM;
/* Update GPIO state shadow register with default value */ /* Update GPIO state shadow register with default value */
tree_info = of_get_property(np, "xlnx,dout-default", NULL); of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state);
if (tree_info)
chip->gpio_state = be32_to_cpup(tree_info); /* By default, all pins are inputs */
chip->gpio_dir = 0xFFFFFFFF;
/* Update GPIO direction shadow register with default value */ /* Update GPIO direction shadow register with default value */
chip->gpio_dir = 0xFFFFFFFF; /* By default, all pins are inputs */ of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir);
tree_info = of_get_property(np, "xlnx,tri-default", NULL);
if (tree_info) /* By default assume full GPIO controller */
chip->gpio_dir = be32_to_cpup(tree_info); chip->mmchip.gc.ngpio = 32;
/* Check device node and parent device node for device width */ /* Check device node and parent device node for device width */
chip->mmchip.gc.ngpio = 32; /* By default assume full GPIO controller */ of_property_read_u32(np, "xlnx,gpio-width",
tree_info = of_get_property(np, "xlnx,gpio-width", NULL); (u32 *)&chip->mmchip.gc.ngpio);
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);
spin_lock_init(&chip->gpio_lock); spin_lock_init(&chip->gpio_lock);
...@@ -206,6 +235,57 @@ static int xgpio_of_probe(struct device_node *np) ...@@ -206,6 +235,57 @@ static int xgpio_of_probe(struct device_node *np)
np->full_name, status); np->full_name, status);
return 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; return 0;
} }
......
...@@ -1214,15 +1214,14 @@ int gpiochip_add(struct gpio_chip *chip) ...@@ -1214,15 +1214,14 @@ int gpiochip_add(struct gpio_chip *chip)
} }
} }
spin_unlock_irqrestore(&gpio_lock, flags);
#ifdef CONFIG_PINCTRL #ifdef CONFIG_PINCTRL
INIT_LIST_HEAD(&chip->pin_ranges); INIT_LIST_HEAD(&chip->pin_ranges);
#endif #endif
of_gpiochip_add(chip); of_gpiochip_add(chip);
unlock:
spin_unlock_irqrestore(&gpio_lock, flags);
if (status) if (status)
goto fail; goto fail;
...@@ -1235,6 +1234,9 @@ int gpiochip_add(struct gpio_chip *chip) ...@@ -1235,6 +1234,9 @@ int gpiochip_add(struct gpio_chip *chip)
chip->label ? : "generic"); chip->label ? : "generic");
return 0; return 0;
unlock:
spin_unlock_irqrestore(&gpio_lock, flags);
fail: fail:
/* failures here can mean systems won't boot... */ /* failures here can mean systems won't boot... */
pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n", pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment