dect
/
linux-2.6
Archived
13
0
Fork 0

Merge branch 'depends/gpio-devel' into next/soc

This is required for some of the clps711x series, so we're bringing in
the dependency explicitly.

By Linus Walleij (5) and others
via Linus Walleij
* depends/gpio-devel:
  GPIO: clps711x: use platform_device_unregister in gpio_clps711x_init()
  gpio/tc3589x: convert to use the simple irqdomain
  gpio/em: convert to linear IRQ domain
  gpio/mvebu: convert to use irq_domain_add_simple()
  gpio/tegra: convert to use linear irqdomain
  gpiolib: unlock on error in gpio_export()
  gpiolib: add gpio get direction callback support
  GPIO: clps711x: Fix direction logic for PORTD
  GPIO: clps711x: Fix return value for gpio_clps711x_get
  gpiolib: Refactor gpio_export
  GPIO: vt8500: Add extended gpio bank for WM8505/WM8650
  gpio: clps711x: delete local <mach/gpio.h> header
  GPIO: Add support for GPIO on CLPS711X-target platform
  DA9055 GPIO driver
  gpio/gpio-omap: Use existing pointer to struct device
  gpio/gpio-pl061: Covert to use devm_* functions

Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
Olof Johansson 2012-11-21 09:39:13 -08:00
commit cab18d19bb
14 changed files with 558 additions and 140 deletions

View File

@ -367,6 +367,8 @@ config ARCH_CNS3XXX
config ARCH_CLPS711X
bool "Cirrus Logic CLPS711x/EP721x/EP731x-based"
select ARCH_REQUIRE_GPIOLIB
select ARCH_USES_GETTIMEOFFSET
select CLKDEV_LOOKUP
select COMMON_CLK
select CPU_ARM720T

View File

@ -86,11 +86,26 @@ config GPIO_DA9052
help
Say yes here to enable the GPIO driver for the DA9052 chip.
config GPIO_DA9055
tristate "Dialog Semiconductor DA9055 GPIO"
depends on MFD_DA9055
help
Say yes here to enable the GPIO driver for the DA9055 chip.
The Dialog DA9055 PMIC chip has 3 GPIO pins that can be
be controller by this driver.
If driver is built as a module it will be called gpio-da9055.
config GPIO_MAX730X
tristate
comment "Memory mapped GPIO drivers:"
config GPIO_CLPS711X
def_bool y
depends on ARCH_CLPS711X
config GPIO_GENERIC_PLATFORM
tristate "Generic memory-mapped GPIO controller support (MMIO platform device)"
select GPIO_GENERIC

View File

@ -16,8 +16,10 @@ obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o
obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o
obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o
obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o
obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o
obj-$(CONFIG_GPIO_EM) += gpio-em.o
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o

View File

@ -0,0 +1,199 @@
/*
* CLPS711X GPIO driver
*
* Copyright (C) 2012 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/spinlock.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)
{
return !!(readb(clps711x_port(chip)) & (1 << offset));
}
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);
spin_lock_irqsave(&gpio->lock, flags);
tmp = readb(clps711x_pdir(chip)) & ~(1 << offset);
writeb(tmp, clps711x_pdir(chip));
spin_unlock_irqrestore(&gpio->lock, flags);
return 0;
}
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;
}
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);
spin_lock_irqsave(&gpio->lock, flags);
tmp = readb(clps711x_pdir(chip)) | (1 << offset);
writeb(tmp, clps711x_pdir(chip));
spin_unlock_irqrestore(&gpio->lock, flags);
return 0;
}
static int gpio_clps711x_dir_out_inv(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;
}
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 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_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
MODULE_DESCRIPTION("CLPS711X GPIO driver");

204
drivers/gpio/gpio-da9055.c Normal file
View File

@ -0,0 +1,204 @@
/*
* GPIO Driver for Dialog DA9055 PMICs.
*
* Copyright(c) 2012 Dialog Semiconductor Ltd.
*
* Author: David Dajun Chen <dchen@diasemi.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/mfd/da9055/core.h>
#include <linux/mfd/da9055/reg.h>
#include <linux/mfd/da9055/pdata.h>
#define DA9055_VDD_IO 0x0
#define DA9055_PUSH_PULL 0x3
#define DA9055_ACT_LOW 0x0
#define DA9055_GPI 0x1
#define DA9055_PORT_MASK 0x3
#define DA9055_PORT_SHIFT(offset) (4 * (offset % 2))
#define DA9055_INPUT DA9055_GPI
#define DA9055_OUTPUT DA9055_PUSH_PULL
#define DA9055_IRQ_GPI0 3
struct da9055_gpio {
struct da9055 *da9055;
struct gpio_chip gp;
};
static inline struct da9055_gpio *to_da9055_gpio(struct gpio_chip *chip)
{
return container_of(chip, struct da9055_gpio, gp);
}
static int da9055_gpio_get(struct gpio_chip *gc, unsigned offset)
{
struct da9055_gpio *gpio = to_da9055_gpio(gc);
int gpio_direction = 0;
int ret;
/* Get GPIO direction */
ret = da9055_reg_read(gpio->da9055, (offset >> 1) + DA9055_REG_GPIO0_1);
if (ret < 0)
return ret;
gpio_direction = ret & (DA9055_PORT_MASK) << DA9055_PORT_SHIFT(offset);
gpio_direction >>= DA9055_PORT_SHIFT(offset);
switch (gpio_direction) {
case DA9055_INPUT:
ret = da9055_reg_read(gpio->da9055, DA9055_REG_STATUS_B);
if (ret < 0)
return ret;
break;
case DA9055_OUTPUT:
ret = da9055_reg_read(gpio->da9055, DA9055_REG_GPIO_MODE0_2);
if (ret < 0)
return ret;
}
return ret & (1 << offset);
}
static void da9055_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
{
struct da9055_gpio *gpio = to_da9055_gpio(gc);
da9055_reg_update(gpio->da9055,
DA9055_REG_GPIO_MODE0_2,
1 << offset,
value << offset);
}
static int da9055_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
{
struct da9055_gpio *gpio = to_da9055_gpio(gc);
unsigned char reg_byte;
reg_byte = (DA9055_ACT_LOW | DA9055_GPI)
<< DA9055_PORT_SHIFT(offset);
return da9055_reg_update(gpio->da9055, (offset >> 1) +
DA9055_REG_GPIO0_1,
DA9055_PORT_MASK <<
DA9055_PORT_SHIFT(offset),
reg_byte);
}
static int da9055_gpio_direction_output(struct gpio_chip *gc,
unsigned offset, int value)
{
struct da9055_gpio *gpio = to_da9055_gpio(gc);
unsigned char reg_byte;
int ret;
reg_byte = (DA9055_VDD_IO | DA9055_PUSH_PULL)
<< DA9055_PORT_SHIFT(offset);
ret = da9055_reg_update(gpio->da9055, (offset >> 1) +
DA9055_REG_GPIO0_1,
DA9055_PORT_MASK <<
DA9055_PORT_SHIFT(offset),
reg_byte);
if (ret < 0)
return ret;
da9055_gpio_set(gc, offset, value);
return 0;
}
static int da9055_gpio_to_irq(struct gpio_chip *gc, u32 offset)
{
struct da9055_gpio *gpio = to_da9055_gpio(gc);
struct da9055 *da9055 = gpio->da9055;
return regmap_irq_get_virq(da9055->irq_data,
DA9055_IRQ_GPI0 + offset);
}
static struct gpio_chip reference_gp __devinitdata = {
.label = "da9055-gpio",
.owner = THIS_MODULE,
.get = da9055_gpio_get,
.set = da9055_gpio_set,
.direction_input = da9055_gpio_direction_input,
.direction_output = da9055_gpio_direction_output,
.to_irq = da9055_gpio_to_irq,
.can_sleep = 1,
.ngpio = 3,
.base = -1,
};
static int __devinit da9055_gpio_probe(struct platform_device *pdev)
{
struct da9055_gpio *gpio;
struct da9055_pdata *pdata;
int ret;
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
if (gpio == NULL)
return -ENOMEM;
gpio->da9055 = dev_get_drvdata(pdev->dev.parent);
pdata = gpio->da9055->dev->platform_data;
gpio->gp = reference_gp;
if (pdata && pdata->gpio_base)
gpio->gp.base = pdata->gpio_base;
ret = gpiochip_add(&gpio->gp);
if (ret < 0) {
dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
goto err_mem;
}
platform_set_drvdata(pdev, gpio);
return 0;
err_mem:
return ret;
}
static int __devexit da9055_gpio_remove(struct platform_device *pdev)
{
struct da9055_gpio *gpio = platform_get_drvdata(pdev);
return gpiochip_remove(&gpio->gp);
}
static struct platform_driver da9055_gpio_driver = {
.probe = da9055_gpio_probe,
.remove = __devexit_p(da9055_gpio_remove),
.driver = {
.name = "da9055-gpio",
.owner = THIS_MODULE,
},
};
static int __init da9055_gpio_init(void)
{
return platform_driver_register(&da9055_gpio_driver);
}
subsys_initcall(da9055_gpio_init);
static void __exit da9055_gpio_exit(void)
{
platform_driver_unregister(&da9055_gpio_driver);
}
module_exit(da9055_gpio_exit);
MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
MODULE_DESCRIPTION("DA9055 GPIO Device Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:da9055-gpio");

View File

@ -35,7 +35,6 @@
struct em_gio_priv {
void __iomem *base0;
void __iomem *base1;
unsigned int irq_base;
spinlock_t sense_lock;
struct platform_device *pdev;
struct gpio_chip gpio_chip;
@ -214,7 +213,7 @@ static int em_gio_direction_output(struct gpio_chip *chip, unsigned offset,
static int em_gio_to_irq(struct gpio_chip *chip, unsigned offset)
{
return irq_find_mapping(gpio_to_priv(chip)->irq_domain, offset);
return irq_create_mapping(gpio_to_priv(chip)->irq_domain, offset);
}
static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int virq,
@ -234,40 +233,6 @@ static struct irq_domain_ops em_gio_irq_domain_ops = {
.map = em_gio_irq_domain_map,
};
static int __devinit em_gio_irq_domain_init(struct em_gio_priv *p)
{
struct platform_device *pdev = p->pdev;
struct gpio_em_config *pdata = pdev->dev.platform_data;
p->irq_base = irq_alloc_descs(pdata->irq_base, 0,
pdata->number_of_pins, numa_node_id());
if (p->irq_base < 0) {
dev_err(&pdev->dev, "cannot get irq_desc\n");
return p->irq_base;
}
pr_debug("gio: hw base = %d, nr = %d, sw base = %d\n",
pdata->gpio_base, pdata->number_of_pins, p->irq_base);
p->irq_domain = irq_domain_add_legacy(pdev->dev.of_node,
pdata->number_of_pins,
p->irq_base, 0,
&em_gio_irq_domain_ops, p);
if (!p->irq_domain) {
irq_free_descs(p->irq_base, pdata->number_of_pins);
return -ENXIO;
}
return 0;
}
static void em_gio_irq_domain_cleanup(struct em_gio_priv *p)
{
struct gpio_em_config *pdata = p->pdev->dev.platform_data;
irq_free_descs(p->irq_base, pdata->number_of_pins);
/* FIXME: irq domain wants to be freed! */
}
static int __devinit em_gio_probe(struct platform_device *pdev)
{
struct gpio_em_config *pdata = pdev->dev.platform_data;
@ -334,8 +299,11 @@ static int __devinit em_gio_probe(struct platform_device *pdev)
irq_chip->irq_set_type = em_gio_irq_set_type;
irq_chip->flags = IRQCHIP_SKIP_SET_WAKE;
ret = em_gio_irq_domain_init(p);
if (ret) {
p->irq_domain = irq_domain_add_linear(pdev->dev.of_node,
pdata->number_of_pins,
&em_gio_irq_domain_ops, p);
if (!p->irq_domain)
err = -ENXIO;
dev_err(&pdev->dev, "cannot initialize irq domain\n");
goto err3;
}
@ -364,7 +332,7 @@ err6:
err5:
free_irq(irq[0]->start, pdev);
err4:
em_gio_irq_domain_cleanup(p);
irq_domain_remove(p->irq_domain);
err3:
iounmap(p->base1);
err2:

View File

@ -650,8 +650,8 @@ static int __devinit mvebu_gpio_probe(struct platform_device *pdev)
IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE);
/* Setup irq domain on top of the generic chip. */
mvchip->domain = irq_domain_add_legacy(np, mvchip->chip.ngpio,
mvchip->irqbase, 0,
mvchip->domain = irq_domain_add_simple(np, mvchip->chip.ngpio,
mvchip->irqbase,
&irq_domain_simple_ops,
mvchip);
if (!mvchip->domain) {

View File

@ -1105,7 +1105,7 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
if (!pdata)
return -EINVAL;
bank = devm_kzalloc(&pdev->dev, sizeof(struct gpio_bank), GFP_KERNEL);
bank = devm_kzalloc(dev, sizeof(struct gpio_bank), GFP_KERNEL);
if (!bank) {
dev_err(dev, "Memory alloc failed\n");
return -ENOMEM;

View File

@ -216,39 +216,34 @@ static void __init pl061_init_gc(struct pl061_gpio *chip, int irq_base)
IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0);
}
static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
{
struct pl061_platform_data *pdata;
struct device *dev = &adev->dev;
struct pl061_platform_data *pdata = dev->platform_data;
struct pl061_gpio *chip;
int ret, irq, i;
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (chip == NULL)
return -ENOMEM;
pdata = dev->dev.platform_data;
if (pdata) {
chip->gc.base = pdata->gpio_base;
chip->irq_base = pdata->irq_base;
} else if (dev->dev.of_node) {
} else if (adev->dev.of_node) {
chip->gc.base = -1;
chip->irq_base = 0;
} else {
ret = -ENODEV;
goto free_mem;
}
} else
return -ENODEV;
if (!request_mem_region(dev->res.start,
resource_size(&dev->res), "pl061")) {
ret = -EBUSY;
goto free_mem;
}
if (!devm_request_mem_region(dev, adev->res.start,
resource_size(&adev->res), "pl061"))
return -EBUSY;
chip->base = ioremap(dev->res.start, resource_size(&dev->res));
if (chip->base == NULL) {
ret = -ENOMEM;
goto release_region;
}
chip->base = devm_ioremap(dev, adev->res.start,
resource_size(&adev->res));
if (chip->base == NULL)
return -ENOMEM;
spin_lock_init(&chip->lock);
@ -258,13 +253,13 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
chip->gc.set = pl061_set_value;
chip->gc.to_irq = pl061_to_irq;
chip->gc.ngpio = PL061_GPIO_NR;
chip->gc.label = dev_name(&dev->dev);
chip->gc.dev = &dev->dev;
chip->gc.label = dev_name(dev);
chip->gc.dev = dev;
chip->gc.owner = THIS_MODULE;
ret = gpiochip_add(&chip->gc);
if (ret)
goto iounmap;
return ret;
/*
* irq_chip support
@ -276,11 +271,10 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
pl061_init_gc(chip, chip->irq_base);
writeb(0, chip->base + GPIOIE); /* disable irqs */
irq = dev->irq[0];
if (irq < 0) {
ret = -ENODEV;
goto iounmap;
}
irq = adev->irq[0];
if (irq < 0)
return -ENODEV;
irq_set_chained_handler(irq, pl061_irq_handler);
irq_set_handler_data(irq, chip);
@ -294,18 +288,9 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
}
}
amba_set_drvdata(dev, chip);
amba_set_drvdata(adev, chip);
return 0;
iounmap:
iounmap(chip->base);
release_region:
release_mem_region(dev->res.start, resource_size(&dev->res));
free_mem:
kfree(chip);
return ret;
}
#ifdef CONFIG_PM

View File

@ -292,17 +292,15 @@ static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio,
{
int base = tc3589x_gpio->irq_base;
if (base) {
tc3589x_gpio->domain = irq_domain_add_legacy(
NULL, tc3589x_gpio->chip.ngpio, base,
0, &tc3589x_irq_ops, tc3589x_gpio);
}
else {
tc3589x_gpio->domain = irq_domain_add_linear(
np, tc3589x_gpio->chip.ngpio,
&tc3589x_irq_ops, tc3589x_gpio);
}
/*
* If this results in a linear domain, irq_create_mapping() will
* take care of allocating IRQ descriptors at runtime. When a base
* is provided, the IRQ descriptors will be allocated when the
* domain is instantiated.
*/
tc3589x_gpio->domain = irq_domain_add_simple(np,
tc3589x_gpio->chip.ngpio, base, &tc3589x_irq_ops,
tc3589x_gpio);
if (!tc3589x_gpio->domain) {
dev_err(tc3589x_gpio->dev, "Failed to create irqdomain\n");
return -ENOSYS;

View File

@ -380,7 +380,6 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
struct tegra_gpio_soc_config *config;
int irq_base;
struct resource *res;
struct tegra_gpio_bank *bank;
int gpio;
@ -417,14 +416,11 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev)
return -ENODEV;
}
irq_base = irq_alloc_descs(-1, 0, tegra_gpio_chip.ngpio, 0);
if (irq_base < 0) {
dev_err(&pdev->dev, "Couldn't allocate IRQ numbers\n");
return -ENODEV;
}
irq_domain = irq_domain_add_legacy(pdev->dev.of_node,
tegra_gpio_chip.ngpio, irq_base, 0,
irq_domain = irq_domain_add_linear(pdev->dev.of_node,
tegra_gpio_chip.ngpio,
&irq_domain_simple_ops, NULL);
if (!irq_domain)
return -ENODEV;
for (i = 0; i < tegra_gpio_bank_count; i++) {
res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
@ -464,7 +460,7 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev)
gpiochip_add(&tegra_gpio_chip);
for (gpio = 0; gpio < tegra_gpio_chip.ngpio; gpio++) {
int irq = irq_find_mapping(irq_domain, gpio);
int irq = irq_create_mapping(irq_domain, gpio);
/* No validity check; all Tegra GPIOs are valid IRQs */
bank = &tegra_gpio_banks[GPIO_BANK(gpio)];

View File

@ -96,6 +96,7 @@ static struct vt8500_gpio_data wm8505_data = {
VT8500_BANK(0x5C, 0x84, 0xAC, 0xD4, 12),
VT8500_BANK(0x60, 0x88, 0xB0, 0xD8, 16),
VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22),
VT8500_BANK(0x500, 0x504, 0x508, 0x50C, 6),
},
};
@ -115,6 +116,7 @@ static struct vt8500_gpio_data wm8650_data = {
VT8500_BANK(0x58, 0x98, 0xD8, 0x18, 32),
VT8500_BANK(0x5C, 0x9C, 0xDC, 0x1C, 32),
VT8500_BANK(0x7C, 0xBC, 0xFC, 0x3C, 32),
VT8500_BANK(0x500, 0x504, 0x508, 0x50C, 6),
},
};

View File

@ -191,6 +191,32 @@ err:
return ret;
}
/* caller ensures gpio is valid and requested, chip->get_direction may sleep */
static int gpio_get_direction(unsigned gpio)
{
struct gpio_chip *chip;
struct gpio_desc *desc = &gpio_desc[gpio];
int status = -EINVAL;
chip = gpio_to_chip(gpio);
gpio -= chip->base;
if (!chip->get_direction)
return status;
status = chip->get_direction(chip, gpio);
if (status > 0) {
/* GPIOF_DIR_IN, or other positive */
status = 1;
clear_bit(FLAG_IS_OUT, &desc->flags);
}
if (status == 0) {
/* GPIOF_DIR_OUT */
set_bit(FLAG_IS_OUT, &desc->flags);
}
return status;
}
#ifdef CONFIG_GPIO_SYSFS
/* lock protects against unexport_gpio() being called while
@ -223,6 +249,7 @@ static ssize_t gpio_direction_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
const struct gpio_desc *desc = dev_get_drvdata(dev);
unsigned gpio = desc - gpio_desc;
ssize_t status;
mutex_lock(&sysfs_lock);
@ -230,6 +257,7 @@ static ssize_t gpio_direction_show(struct device *dev,
if (!test_bit(FLAG_EXPORT, &desc->flags))
status = -EIO;
else
gpio_get_direction(gpio);
status = sprintf(buf, "%s\n",
test_bit(FLAG_IS_OUT, &desc->flags)
? "out" : "in");
@ -704,8 +732,9 @@ int gpio_export(unsigned gpio, bool direction_may_change)
{
unsigned long flags;
struct gpio_desc *desc;
int status = -EINVAL;
int status;
const char *ioname = NULL;
struct device *dev;
/* can't export until sysfs is available ... */
if (!gpio_class.p) {
@ -713,59 +742,66 @@ int gpio_export(unsigned gpio, bool direction_may_change)
return -ENOENT;
}
if (!gpio_is_valid(gpio))
goto done;
if (!gpio_is_valid(gpio)) {
pr_debug("%s: gpio %d is not valid\n", __func__, gpio);
return -EINVAL;
}
mutex_lock(&sysfs_lock);
spin_lock_irqsave(&gpio_lock, flags);
desc = &gpio_desc[gpio];
if (test_bit(FLAG_REQUESTED, &desc->flags)
&& !test_bit(FLAG_EXPORT, &desc->flags)) {
status = 0;
if (!desc->chip->direction_input
|| !desc->chip->direction_output)
direction_may_change = false;
if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
test_bit(FLAG_EXPORT, &desc->flags)) {
spin_unlock_irqrestore(&gpio_lock, flags);
pr_debug("%s: gpio %d unavailable (requested=%d, exported=%d)\n",
__func__, gpio,
test_bit(FLAG_REQUESTED, &desc->flags),
test_bit(FLAG_EXPORT, &desc->flags));
status = -EPERM;
goto fail_unlock;
}
if (!desc->chip->direction_input || !desc->chip->direction_output)
direction_may_change = false;
spin_unlock_irqrestore(&gpio_lock, flags);
if (desc->chip->names && desc->chip->names[gpio - desc->chip->base])
ioname = desc->chip->names[gpio - desc->chip->base];
if (status == 0) {
struct device *dev;
dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
desc, ioname ? ioname : "gpio%u", gpio);
if (!IS_ERR(dev)) {
status = sysfs_create_group(&dev->kobj,
&gpio_attr_group);
if (!status && direction_may_change)
status = device_create_file(dev,
&dev_attr_direction);
if (!status && gpio_to_irq(gpio) >= 0
&& (direction_may_change
|| !test_bit(FLAG_IS_OUT,
&desc->flags)))
status = device_create_file(dev,
&dev_attr_edge);
if (status != 0)
device_unregister(dev);
} else
status = PTR_ERR(dev);
if (status == 0)
set_bit(FLAG_EXPORT, &desc->flags);
dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
desc, ioname ? ioname : "gpio%u", gpio);
if (IS_ERR(dev)) {
status = PTR_ERR(dev);
goto fail_unlock;
}
mutex_unlock(&sysfs_lock);
done:
status = sysfs_create_group(&dev->kobj, &gpio_attr_group);
if (status)
pr_debug("%s: gpio%d status %d\n", __func__, gpio, status);
goto fail_unregister_device;
if (direction_may_change) {
status = device_create_file(dev, &dev_attr_direction);
if (status)
goto fail_unregister_device;
}
if (gpio_to_irq(gpio) >= 0 && (direction_may_change ||
!test_bit(FLAG_IS_OUT, &desc->flags))) {
status = device_create_file(dev, &dev_attr_edge);
if (status)
goto fail_unregister_device;
}
set_bit(FLAG_EXPORT, &desc->flags);
mutex_unlock(&sysfs_lock);
return 0;
fail_unregister_device:
device_unregister(dev);
fail_unlock:
mutex_unlock(&sysfs_lock);
pr_debug("%s: gpio%d status %d\n", __func__, gpio, status);
return status;
}
EXPORT_SYMBOL_GPL(gpio_export);
@ -1075,6 +1111,7 @@ int gpiochip_add(struct gpio_chip *chip)
* inputs (often with pullups enabled) so power
* usage is minimized. Linux code should set the
* gpio direction first thing; but until it does,
* and in case chip->get_direction is not set,
* we may expose the wrong direction in sysfs.
*/
gpio_desc[id].flags = !chip->direction_input
@ -1228,9 +1265,15 @@ int gpio_request(unsigned gpio, const char *label)
desc_set_label(desc, NULL);
module_put(chip->owner);
clear_bit(FLAG_REQUESTED, &desc->flags);
goto done;
}
}
if (chip->get_direction) {
/* chip->get_direction may sleep */
spin_unlock_irqrestore(&gpio_lock, flags);
gpio_get_direction(gpio);
spin_lock_irqsave(&gpio_lock, flags);
}
done:
if (status)
pr_debug("gpio_request: gpio-%d (%s) status %d\n",
@ -1766,6 +1809,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
if (!test_bit(FLAG_REQUESTED, &gdesc->flags))
continue;
gpio_get_direction(gpio);
is_out = test_bit(FLAG_IS_OUT, &gdesc->flags);
seq_printf(s, " gpio-%-3d (%-20.20s) %s %s",
gpio, gdesc->label,

View File

@ -56,6 +56,8 @@ struct device_node;
* enabling module power and clock; may sleep
* @free: optional hook for chip-specific deactivation, such as
* disabling module power and clock; may sleep
* @get_direction: returns direction for signal "offset", 0=out, 1=in,
* (same as GPIOF_DIR_XXX), or negative error
* @direction_input: configures signal "offset" as input, or returns error
* @get: returns value for signal "offset"; for output signals this
* returns either the value actually sensed, or zero
@ -100,7 +102,8 @@ struct gpio_chip {
unsigned offset);
void (*free)(struct gpio_chip *chip,
unsigned offset);
int (*get_direction)(struct gpio_chip *chip,
unsigned offset);
int (*direction_input)(struct gpio_chip *chip,
unsigned offset);
int (*get)(struct gpio_chip *chip,