Merge branch 'gpio/next' of git://git.secretlab.ca/git/linux-2.6

* 'gpio/next' of git://git.secretlab.ca/git/linux-2.6:
  gpio/via: rename VIA local config struct
  basic_mmio_gpio: split into a gpio library and platform device
  gpio: remove some legacy comments in build files
  gpio: add trace events for setting direction and value
  gpio/pca953x: Use handle_simple_irq instead of handle_edge_irq
  gpiolib: export gpiochip_find
  gpio: remove redundant Kconfig depends on GPIOLIB
  basic_mmio_gpio: convert to non-__raw* accessors
  basic_mmio_gpio: support direction registers
  basic_mmio_gpio: support different input/output registers
  basic_mmio_gpio: detect output method at probe time
  basic_mmio_gpio: request register regions
  basic_mmio_gpio: allow overriding number of gpio
  basic_mmio_gpio: convert to platform_{get,set}_drvdata()
  basic_mmio_gpio: remove runtime width/endianness evaluation
This commit is contained in:
Linus Torvalds 2011-05-26 12:14:41 -07:00
commit 8b29336fe0
8 changed files with 559 additions and 178 deletions

View file

@ -1,5 +1,5 @@
#
# platform-neutral GPIO infrastructure and expanders
# GPIO infrastructure and drivers
#
config ARCH_WANT_OPTIONAL_GPIOLIB
@ -31,7 +31,7 @@ menuconfig GPIOLIB
help
This enables GPIO support through the generic GPIO library.
You only need to enable this, if you also want to enable
one or more of the GPIO expansion card drivers below.
one or more of the GPIO drivers below.
If unsure, say N.
@ -63,21 +63,26 @@ config GPIO_SYSFS
Kernel drivers may also request that a particular GPIO be
exported to userspace; this can be useful when debugging.
# put expanders in the right section, in alphabetical order
# put drivers in the right section, in alphabetical order
config GPIO_MAX730X
tristate
comment "Memory mapped GPIO expanders:"
comment "Memory mapped GPIO drivers:"
config GPIO_BASIC_MMIO_CORE
tristate
help
Provides core functionality for basic memory-mapped GPIO controllers.
config GPIO_BASIC_MMIO
tristate "Basic memory-mapped GPIO controllers support"
select GPIO_BASIC_MMIO_CORE
help
Say yes here to support basic memory-mapped GPIO controllers.
config GPIO_IT8761E
tristate "IT8761E GPIO support"
depends on GPIOLIB
help
Say yes here to support GPIO functionality of IT8761E super I/O chip.
@ -101,7 +106,7 @@ config GPIO_VR41XX
config GPIO_SCH
tristate "Intel SCH/TunnelCreek GPIO"
depends on GPIOLIB && PCI && X86
depends on PCI && X86
select MFD_CORE
select LPC_SCH
help
@ -121,7 +126,7 @@ config GPIO_SCH
config GPIO_VX855
tristate "VIA VX855/VX875 GPIO"
depends on GPIOLIB && MFD_SUPPORT && PCI
depends on MFD_SUPPORT && PCI
select MFD_CORE
select MFD_VX855
help
@ -347,13 +352,13 @@ config GPIO_ML_IOH
config GPIO_TIMBERDALE
bool "Support for timberdale GPIO IP"
depends on MFD_TIMBERDALE && GPIOLIB && HAS_IOMEM
depends on MFD_TIMBERDALE && HAS_IOMEM
---help---
Add support for the GPIO IP in the timberdale FPGA.
config GPIO_RDC321X
tristate "RDC R-321x GPIO support"
depends on PCI && GPIOLIB
depends on PCI
select MFD_SUPPORT
select MFD_CORE
select MFD_RDC321X

View file

@ -1,8 +1,4 @@
# generic gpio support: dedicated expander chips, etc
#
# NOTE: platform-specific GPIO drivers don't belong in the
# drivers/gpio directory; put them with other platform setup
# code, IRQ controllers, board init, etc.
# generic gpio support: platform drivers, dedicated expander chips, etc
ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG
@ -10,6 +6,7 @@ obj-$(CONFIG_GPIOLIB) += gpiolib.o
obj-$(CONFIG_GPIO_ADP5520) += adp5520-gpio.o
obj-$(CONFIG_GPIO_ADP5588) += adp5588-gpio.o
obj-$(CONFIG_GPIO_BASIC_MMIO_CORE) += basic_mmio_gpio.o
obj-$(CONFIG_GPIO_BASIC_MMIO) += basic_mmio_gpio.o
obj-$(CONFIG_GPIO_LANGWELL) += langwell_gpio.o
obj-$(CONFIG_GPIO_MAX730X) += max730x.o

View file

@ -45,6 +45,7 @@ o ` ~~~~\___/~~~~ ` controller in FPGA is ,.`
*/
#include <linux/init.h>
#include <linux/err.h>
#include <linux/bug.h>
#include <linux/kernel.h>
#include <linux/module.h>
@ -61,103 +62,72 @@ o ` ~~~~\___/~~~~ ` controller in FPGA is ,.`
#include <linux/mod_devicetable.h>
#include <linux/basic_mmio_gpio.h>
struct bgpio_chip {
struct gpio_chip gc;
void __iomem *reg_dat;
void __iomem *reg_set;
void __iomem *reg_clr;
/* Number of bits (GPIOs): <register width> * 8. */
int bits;
/*
* Some GPIO controllers work with the big-endian bits notation,
* e.g. in a 8-bits register, GPIO7 is the least significant bit.
*/
int big_endian_bits;
/*
* Used to lock bgpio_chip->data. Also, this is needed to keep
* shadowed and real data registers writes together.
*/
spinlock_t lock;
/* Shadowed data register to clear/set bits safely. */
unsigned long data;
};
static struct bgpio_chip *to_bgpio_chip(struct gpio_chip *gc)
static void bgpio_write8(void __iomem *reg, unsigned long data)
{
return container_of(gc, struct bgpio_chip, gc);
writeb(data, reg);
}
static unsigned long bgpio_in(struct bgpio_chip *bgc)
static unsigned long bgpio_read8(void __iomem *reg)
{
switch (bgc->bits) {
case 8:
return __raw_readb(bgc->reg_dat);
case 16:
return __raw_readw(bgc->reg_dat);
case 32:
return __raw_readl(bgc->reg_dat);
return readb(reg);
}
static void bgpio_write16(void __iomem *reg, unsigned long data)
{
writew(data, reg);
}
static unsigned long bgpio_read16(void __iomem *reg)
{
return readw(reg);
}
static void bgpio_write32(void __iomem *reg, unsigned long data)
{
writel(data, reg);
}
static unsigned long bgpio_read32(void __iomem *reg)
{
return readl(reg);
}
#if BITS_PER_LONG >= 64
case 64:
return __raw_readq(bgc->reg_dat);
#endif
}
return -EINVAL;
static void bgpio_write64(void __iomem *reg, unsigned long data)
{
writeq(data, reg);
}
static void bgpio_out(struct bgpio_chip *bgc, void __iomem *reg,
unsigned long data)
static unsigned long bgpio_read64(void __iomem *reg)
{
switch (bgc->bits) {
case 8:
__raw_writeb(data, reg);
return;
case 16:
__raw_writew(data, reg);
return;
case 32:
__raw_writel(data, reg);
return;
#if BITS_PER_LONG >= 64
case 64:
__raw_writeq(data, reg);
return;
#endif
}
return readq(reg);
}
#endif /* BITS_PER_LONG >= 64 */
static unsigned long bgpio_pin2mask(struct bgpio_chip *bgc, unsigned int pin)
{
if (bgc->big_endian_bits)
return 1 << (bgc->bits - 1 - pin);
else
return 1 << pin;
return 1 << pin;
}
static unsigned long bgpio_pin2mask_be(struct bgpio_chip *bgc,
unsigned int pin)
{
return 1 << (bgc->bits - 1 - pin);
}
static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
return bgpio_in(bgc) & bgpio_pin2mask(bgc, gpio);
return bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio);
}
static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
unsigned long mask = bgpio_pin2mask(bgc, gpio);
unsigned long mask = bgc->pin2mask(bgc, gpio);
unsigned long flags;
if (bgc->reg_set) {
if (val)
bgpio_out(bgc, bgc->reg_set, mask);
else
bgpio_out(bgc, bgc->reg_clr, mask);
return;
}
spin_lock_irqsave(&bgc->lock, flags);
if (val)
@ -165,103 +135,382 @@ static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
else
bgc->data &= ~mask;
bgpio_out(bgc, bgc->reg_dat, bgc->data);
bgc->write_reg(bgc->reg_dat, bgc->data);
spin_unlock_irqrestore(&bgc->lock, flags);
}
static void bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio,
int val)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
unsigned long mask = bgc->pin2mask(bgc, gpio);
if (val)
bgc->write_reg(bgc->reg_set, mask);
else
bgc->write_reg(bgc->reg_clr, mask);
}
static void bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
unsigned long mask = bgc->pin2mask(bgc, gpio);
unsigned long flags;
spin_lock_irqsave(&bgc->lock, flags);
if (val)
bgc->data |= mask;
else
bgc->data &= ~mask;
bgc->write_reg(bgc->reg_set, bgc->data);
spin_unlock_irqrestore(&bgc->lock, flags);
}
static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
return 0;
}
static int bgpio_simple_dir_out(struct gpio_chip *gc, unsigned int gpio,
int val)
{
gc->set(gc, gpio, val);
return 0;
}
static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
unsigned long flags;
spin_lock_irqsave(&bgc->lock, flags);
bgc->dir &= ~bgc->pin2mask(bgc, gpio);
bgc->write_reg(bgc->reg_dir, bgc->dir);
spin_unlock_irqrestore(&bgc->lock, flags);
return 0;
}
static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
bgpio_set(gc, gpio, val);
struct bgpio_chip *bgc = to_bgpio_chip(gc);
unsigned long flags;
gc->set(gc, gpio, val);
spin_lock_irqsave(&bgc->lock, flags);
bgc->dir |= bgc->pin2mask(bgc, gpio);
bgc->write_reg(bgc->reg_dir, bgc->dir);
spin_unlock_irqrestore(&bgc->lock, flags);
return 0;
}
static int __devinit bgpio_probe(struct platform_device *pdev)
static int bgpio_dir_in_inv(struct gpio_chip *gc, unsigned int gpio)
{
const struct platform_device_id *platid = platform_get_device_id(pdev);
struct device *dev = &pdev->dev;
struct bgpio_pdata *pdata = dev_get_platdata(dev);
struct bgpio_chip *bgc;
struct resource *res_dat;
struct resource *res_set;
struct resource *res_clr;
resource_size_t dat_sz;
int bits;
int ret;
struct bgpio_chip *bgc = to_bgpio_chip(gc);
unsigned long flags;
res_dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
if (!res_dat)
return -EINVAL;
spin_lock_irqsave(&bgc->lock, flags);
dat_sz = resource_size(res_dat);
if (!is_power_of_2(dat_sz))
return -EINVAL;
bgc->dir |= bgc->pin2mask(bgc, gpio);
bgc->write_reg(bgc->reg_dir, bgc->dir);
bits = dat_sz * 8;
if (bits > BITS_PER_LONG)
return -EINVAL;
spin_unlock_irqrestore(&bgc->lock, flags);
bgc = devm_kzalloc(dev, sizeof(*bgc), GFP_KERNEL);
if (!bgc)
return -ENOMEM;
return 0;
}
bgc->reg_dat = devm_ioremap(dev, res_dat->start, dat_sz);
if (!bgc->reg_dat)
return -ENOMEM;
static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
unsigned long flags;
res_set = platform_get_resource_byname(pdev, IORESOURCE_MEM, "set");
res_clr = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clr");
if (res_set && res_clr) {
if (resource_size(res_set) != resource_size(res_clr) ||
resource_size(res_set) != dat_sz)
return -EINVAL;
gc->set(gc, gpio, val);
bgc->reg_set = devm_ioremap(dev, res_set->start, dat_sz);
bgc->reg_clr = devm_ioremap(dev, res_clr->start, dat_sz);
if (!bgc->reg_set || !bgc->reg_clr)
return -ENOMEM;
} else if (res_set || res_clr) {
spin_lock_irqsave(&bgc->lock, flags);
bgc->dir &= ~bgc->pin2mask(bgc, gpio);
bgc->write_reg(bgc->reg_dir, bgc->dir);
spin_unlock_irqrestore(&bgc->lock, flags);
return 0;
}
static int bgpio_setup_accessors(struct device *dev,
struct bgpio_chip *bgc,
bool be)
{
switch (bgc->bits) {
case 8:
bgc->read_reg = bgpio_read8;
bgc->write_reg = bgpio_write8;
break;
case 16:
bgc->read_reg = bgpio_read16;
bgc->write_reg = bgpio_write16;
break;
case 32:
bgc->read_reg = bgpio_read32;
bgc->write_reg = bgpio_write32;
break;
#if BITS_PER_LONG >= 64
case 64:
bgc->read_reg = bgpio_read64;
bgc->write_reg = bgpio_write64;
break;
#endif /* BITS_PER_LONG >= 64 */
default:
dev_err(dev, "unsupported data width %u bits\n", bgc->bits);
return -EINVAL;
}
spin_lock_init(&bgc->lock);
bgc->pin2mask = be ? bgpio_pin2mask_be : bgpio_pin2mask;
bgc->bits = bits;
bgc->big_endian_bits = !strcmp(platid->name, "basic-mmio-gpio-be");
bgc->data = bgpio_in(bgc);
return 0;
}
/*
* Create the device and allocate the resources. For setting GPIO's there are
* three supported configurations:
*
* - single input/output register resource (named "dat").
* - set/clear pair (named "set" and "clr").
* - single output register resource and single input resource ("set" and
* dat").
*
* For the single output register, this drives a 1 by setting a bit and a zero
* by clearing a bit. For the set clr pair, this drives a 1 by setting a bit
* in the set register and clears it by setting a bit in the clear register.
* The configuration is detected by which resources are present.
*
* For setting the GPIO direction, there are three supported configurations:
*
* - simple bidirection GPIO that requires no configuration.
* - an output direction register (named "dirout") where a 1 bit
* indicates the GPIO is an output.
* - an input direction register (named "dirin") where a 1 bit indicates
* the GPIO is an input.
*/
static int bgpio_setup_io(struct bgpio_chip *bgc,
void __iomem *dat,
void __iomem *set,
void __iomem *clr)
{
bgc->reg_dat = dat;
if (!bgc->reg_dat)
return -EINVAL;
if (set && clr) {
bgc->reg_set = set;
bgc->reg_clr = clr;
bgc->gc.set = bgpio_set_with_clear;
} else if (set && !clr) {
bgc->reg_set = set;
bgc->gc.set = bgpio_set_set;
} else {
bgc->gc.set = bgpio_set;
}
bgc->gc.ngpio = bits;
bgc->gc.direction_input = bgpio_dir_in;
bgc->gc.direction_output = bgpio_dir_out;
bgc->gc.get = bgpio_get;
bgc->gc.set = bgpio_set;
return 0;
}
static int bgpio_setup_direction(struct bgpio_chip *bgc,
void __iomem *dirout,
void __iomem *dirin)
{
if (dirout && dirin) {
return -EINVAL;
} else if (dirout) {
bgc->reg_dir = dirout;
bgc->gc.direction_output = bgpio_dir_out;
bgc->gc.direction_input = bgpio_dir_in;
} else if (dirin) {
bgc->reg_dir = dirin;
bgc->gc.direction_output = bgpio_dir_out_inv;
bgc->gc.direction_input = bgpio_dir_in_inv;
} else {
bgc->gc.direction_output = bgpio_simple_dir_out;
bgc->gc.direction_input = bgpio_simple_dir_in;
}
return 0;
}
int __devexit bgpio_remove(struct bgpio_chip *bgc)
{
int err = gpiochip_remove(&bgc->gc);
kfree(bgc);
return err;
}
EXPORT_SYMBOL_GPL(bgpio_remove);
int __devinit bgpio_init(struct bgpio_chip *bgc,
struct device *dev,
unsigned long sz,
void __iomem *dat,
void __iomem *set,
void __iomem *clr,
void __iomem *dirout,
void __iomem *dirin,
bool big_endian)
{
int ret;
if (!is_power_of_2(sz))
return -EINVAL;
bgc->bits = sz * 8;
if (bgc->bits > BITS_PER_LONG)
return -EINVAL;
spin_lock_init(&bgc->lock);
bgc->gc.dev = dev;
bgc->gc.label = dev_name(dev);
bgc->gc.base = -1;
bgc->gc.ngpio = bgc->bits;
if (pdata)
bgc->gc.base = pdata->base;
else
bgc->gc.base = -1;
dev_set_drvdata(dev, bgc);
ret = gpiochip_add(&bgc->gc);
ret = bgpio_setup_io(bgc, dat, set, clr);
if (ret)
dev_err(dev, "gpiochip_add() failed: %d\n", ret);
return ret;
ret = bgpio_setup_accessors(dev, bgc, big_endian);
if (ret)
return ret;
ret = bgpio_setup_direction(bgc, dirout, dirin);
if (ret)
return ret;
bgc->data = bgc->read_reg(bgc->reg_dat);
return ret;
}
EXPORT_SYMBOL_GPL(bgpio_init);
#ifdef CONFIG_GPIO_BASIC_MMIO
static void __iomem *bgpio_map(struct platform_device *pdev,
const char *name,
resource_size_t sane_sz,
int *err)
{
struct device *dev = &pdev->dev;
struct resource *r;
resource_size_t start;
resource_size_t sz;
void __iomem *ret;
*err = 0;
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
if (!r)
return NULL;
sz = resource_size(r);
if (sz != sane_sz) {
*err = -EINVAL;
return NULL;
}
start = r->start;
if (!devm_request_mem_region(dev, start, sz, r->name)) {
*err = -EBUSY;
return NULL;
}
ret = devm_ioremap(dev, start, sz);
if (!ret) {
*err = -ENOMEM;
return NULL;
}
return ret;
}
static int __devexit bgpio_remove(struct platform_device *pdev)
static int __devinit bgpio_pdev_probe(struct platform_device *pdev)
{
struct bgpio_chip *bgc = dev_get_drvdata(&pdev->dev);
struct device *dev = &pdev->dev;
struct resource *r;
void __iomem *dat;
void __iomem *set;
void __iomem *clr;
void __iomem *dirout;
void __iomem *dirin;
unsigned long sz;
bool be;
int err;
struct bgpio_chip *bgc;
struct bgpio_pdata *pdata = dev_get_platdata(dev);
return gpiochip_remove(&bgc->gc);
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
if (!r)
return -EINVAL;
sz = resource_size(r);
dat = bgpio_map(pdev, "dat", sz, &err);
if (!dat)
return err ? err : -EINVAL;
set = bgpio_map(pdev, "set", sz, &err);
if (err)
return err;
clr = bgpio_map(pdev, "clr", sz, &err);
if (err)
return err;
dirout = bgpio_map(pdev, "dirout", sz, &err);
if (err)
return err;
dirin = bgpio_map(pdev, "dirin", sz, &err);
if (err)
return err;
be = !strcmp(platform_get_device_id(pdev)->name, "basic-mmio-gpio-be");
bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL);
if (!bgc)
return -ENOMEM;
err = bgpio_init(bgc, dev, sz, dat, set, clr, dirout, dirin, be);
if (err)
return err;
if (pdata) {
bgc->gc.base = pdata->base;
if (pdata->ngpio > 0)
bgc->gc.ngpio = pdata->ngpio;
}
platform_set_drvdata(pdev, bgc);
return gpiochip_add(&bgc->gc);
}
static int __devexit bgpio_pdev_remove(struct platform_device *pdev)
{
struct bgpio_chip *bgc = platform_get_drvdata(pdev);
return bgpio_remove(bgc);
}
static const struct platform_device_id bgpio_id_table[] = {
@ -276,21 +525,23 @@ static struct platform_driver bgpio_driver = {
.name = "basic-mmio-gpio",
},
.id_table = bgpio_id_table,
.probe = bgpio_probe,
.remove = __devexit_p(bgpio_remove),
.probe = bgpio_pdev_probe,
.remove = __devexit_p(bgpio_pdev_remove),
};
static int __init bgpio_init(void)
static int __init bgpio_platform_init(void)
{
return platform_driver_register(&bgpio_driver);
}
module_init(bgpio_init);
module_init(bgpio_platform_init);
static void __exit bgpio_exit(void)
static void __exit bgpio_platform_exit(void)
{
platform_driver_unregister(&bgpio_driver);
}
module_exit(bgpio_exit);
module_exit(bgpio_platform_exit);
#endif /* CONFIG_GPIO_BASIC_MMIO */
MODULE_DESCRIPTION("Driver for basic memory-mapped GPIO controllers");
MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>");

View file

@ -12,6 +12,8 @@
#include <linux/idr.h>
#include <linux/slab.h>
#define CREATE_TRACE_POINTS
#include <trace/events/gpio.h>
/* Optional implementation infrastructure for GPIO interfaces.
*
@ -1165,6 +1167,7 @@ struct gpio_chip *gpiochip_find(void *data,
return chip;
}
EXPORT_SYMBOL_GPL(gpiochip_find);
/* These "optional" allocation calls help prevent drivers from stomping
* on each other, and help provide better diagnostics in debugfs.
@ -1404,6 +1407,8 @@ int gpio_direction_input(unsigned gpio)
status = chip->direction_input(chip, gpio);
if (status == 0)
clear_bit(FLAG_IS_OUT, &desc->flags);
trace_gpio_direction(chip->base + gpio, 1, status);
lose:
return status;
fail:
@ -1457,6 +1462,8 @@ int gpio_direction_output(unsigned gpio, int value)
status = chip->direction_output(chip, gpio, value);
if (status == 0)
set_bit(FLAG_IS_OUT, &desc->flags);
trace_gpio_value(chip->base + gpio, 0, value);
trace_gpio_direction(chip->base + gpio, 0, status);
lose:
return status;
fail:
@ -1546,10 +1553,13 @@ EXPORT_SYMBOL_GPL(gpio_set_debounce);
int __gpio_get_value(unsigned gpio)
{
struct gpio_chip *chip;
int value;
chip = gpio_to_chip(gpio);
WARN_ON(chip->can_sleep);
return chip->get ? chip->get(chip, gpio - chip->base) : 0;
value = chip->get ? chip->get(chip, gpio - chip->base) : 0;
trace_gpio_value(gpio, 1, value);
return value;
}
EXPORT_SYMBOL_GPL(__gpio_get_value);
@ -1568,6 +1578,7 @@ void __gpio_set_value(unsigned gpio, int value)
chip = gpio_to_chip(gpio);
WARN_ON(chip->can_sleep);
trace_gpio_value(gpio, 0, value);
chip->set(chip, gpio - chip->base, value);
}
EXPORT_SYMBOL_GPL(__gpio_set_value);
@ -1618,10 +1629,13 @@ EXPORT_SYMBOL_GPL(__gpio_to_irq);
int gpio_get_value_cansleep(unsigned gpio)
{
struct gpio_chip *chip;
int value;
might_sleep_if(extra_checks);
chip = gpio_to_chip(gpio);
return chip->get ? chip->get(chip, gpio - chip->base) : 0;
value = chip->get ? chip->get(chip, gpio - chip->base) : 0;
trace_gpio_value(gpio, 1, value);
return value;
}
EXPORT_SYMBOL_GPL(gpio_get_value_cansleep);
@ -1631,6 +1645,7 @@ void gpio_set_value_cansleep(unsigned gpio, int value)
might_sleep_if(extra_checks);
chip = gpio_to_chip(gpio);
trace_gpio_value(gpio, 0, value);
chip->set(chip, gpio - chip->base, value);
}
EXPORT_SYMBOL_GPL(gpio_set_value_cansleep);

View file

@ -397,7 +397,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
irq_set_chip_data(irq, chip);
irq_set_chip_and_handler(irq, &pca953x_irq_chip,
handle_edge_irq);
handle_simple_irq);
#ifdef CONFIG_ARM
set_irq_flags(irq, IRQF_VALID);
#else

View file

@ -145,7 +145,7 @@ static int via_gpio_get(struct gpio_chip *chip, unsigned int nr)
}
static struct viafb_gpio_cfg gpio_config = {
static struct viafb_gpio_cfg viafb_gpio_config = {
.gpio_chip = {
.label = "VIAFB onboard GPIO",
.owner = THIS_MODULE,
@ -183,8 +183,8 @@ static int viafb_gpio_resume(void *private)
{
int i;
for (i = 0; i < gpio_config.gpio_chip.ngpio; i += 2)
viafb_gpio_enable(gpio_config.active_gpios[i]);
for (i = 0; i < viafb_gpio_config.gpio_chip.ngpio; i += 2)
viafb_gpio_enable(viafb_gpio_config.active_gpios[i]);
return 0;
}
@ -201,9 +201,9 @@ int viafb_gpio_lookup(const char *name)
{
int i;
for (i = 0; i < gpio_config.gpio_chip.ngpio; i++)
if (!strcmp(name, gpio_config.active_gpios[i]->vg_name))
return gpio_config.gpio_chip.base + i;
for (i = 0; i < viafb_gpio_config.gpio_chip.ngpio; i++)
if (!strcmp(name, viafb_gpio_config.active_gpios[i]->vg_name))
return viafb_gpio_config.gpio_chip.base + i;
return -1;
}
EXPORT_SYMBOL_GPL(viafb_gpio_lookup);
@ -229,14 +229,15 @@ static __devinit int viafb_gpio_probe(struct platform_device *platdev)
for (gpio = viafb_all_gpios;
gpio < viafb_all_gpios + VIAFB_NUM_GPIOS; gpio++)
if (gpio->vg_port_index == port_cfg[i].ioport_index) {
gpio_config.active_gpios[ngpio] = gpio;
gpio_config.gpio_names[ngpio] = gpio->vg_name;
viafb_gpio_config.active_gpios[ngpio] = gpio;
viafb_gpio_config.gpio_names[ngpio] =
gpio->vg_name;
ngpio++;
}
}
gpio_config.gpio_chip.ngpio = ngpio;
gpio_config.gpio_chip.names = gpio_config.gpio_names;
gpio_config.vdev = vdev;
viafb_gpio_config.gpio_chip.ngpio = ngpio;
viafb_gpio_config.gpio_chip.names = viafb_gpio_config.gpio_names;
viafb_gpio_config.vdev = vdev;
if (ngpio == 0) {
printk(KERN_INFO "viafb: no GPIOs configured\n");
return 0;
@ -245,18 +246,18 @@ static __devinit int viafb_gpio_probe(struct platform_device *platdev)
* Enable the ports. They come in pairs, with a single
* enable bit for both.
*/
spin_lock_irqsave(&gpio_config.vdev->reg_lock, flags);
spin_lock_irqsave(&viafb_gpio_config.vdev->reg_lock, flags);
for (i = 0; i < ngpio; i += 2)
viafb_gpio_enable(gpio_config.active_gpios[i]);
spin_unlock_irqrestore(&gpio_config.vdev->reg_lock, flags);
viafb_gpio_enable(viafb_gpio_config.active_gpios[i]);
spin_unlock_irqrestore(&viafb_gpio_config.vdev->reg_lock, flags);
/*
* Get registered.
*/
gpio_config.gpio_chip.base = -1; /* Dynamic */
ret = gpiochip_add(&gpio_config.gpio_chip);
viafb_gpio_config.gpio_chip.base = -1; /* Dynamic */
ret = gpiochip_add(&viafb_gpio_config.gpio_chip);
if (ret) {
printk(KERN_ERR "viafb: failed to add gpios (%d)\n", ret);
gpio_config.gpio_chip.ngpio = 0;
viafb_gpio_config.gpio_chip.ngpio = 0;
}
#ifdef CONFIG_PM
viafb_pm_register(&viafb_gpio_pm_hooks);
@ -277,8 +278,8 @@ static int viafb_gpio_remove(struct platform_device *platdev)
/*
* Get unregistered.
*/
if (gpio_config.gpio_chip.ngpio > 0) {
ret = gpiochip_remove(&gpio_config.gpio_chip);
if (viafb_gpio_config.gpio_chip.ngpio > 0) {
ret = gpiochip_remove(&viafb_gpio_config.gpio_chip);
if (ret) { /* Somebody still using it? */
printk(KERN_ERR "Viafb: GPIO remove failed\n");
return ret;
@ -287,11 +288,11 @@ static int viafb_gpio_remove(struct platform_device *platdev)
/*
* Disable the ports.
*/
spin_lock_irqsave(&gpio_config.vdev->reg_lock, flags);
for (i = 0; i < gpio_config.gpio_chip.ngpio; i += 2)
viafb_gpio_disable(gpio_config.active_gpios[i]);
gpio_config.gpio_chip.ngpio = 0;
spin_unlock_irqrestore(&gpio_config.vdev->reg_lock, flags);
spin_lock_irqsave(&viafb_gpio_config.vdev->reg_lock, flags);
for (i = 0; i < viafb_gpio_config.gpio_chip.ngpio; i += 2)
viafb_gpio_disable(viafb_gpio_config.active_gpios[i]);
viafb_gpio_config.gpio_chip.ngpio = 0;
spin_unlock_irqrestore(&viafb_gpio_config.vdev->reg_lock, flags);
return ret;
}

View file

@ -13,8 +13,64 @@
#ifndef __BASIC_MMIO_GPIO_H
#define __BASIC_MMIO_GPIO_H
#include <linux/gpio.h>
#include <linux/types.h>
#include <linux/compiler.h>
struct bgpio_pdata {
int base;
int ngpio;
};
struct device;
struct bgpio_chip {
struct gpio_chip gc;
unsigned long (*read_reg)(void __iomem *reg);
void (*write_reg)(void __iomem *reg, unsigned long data);
void __iomem *reg_dat;
void __iomem *reg_set;
void __iomem *reg_clr;
void __iomem *reg_dir;
/* Number of bits (GPIOs): <register width> * 8. */
int bits;
/*
* Some GPIO controllers work with the big-endian bits notation,
* e.g. in a 8-bits register, GPIO7 is the least significant bit.
*/
unsigned long (*pin2mask)(struct bgpio_chip *bgc, unsigned int pin);
/*
* Used to lock bgpio_chip->data. Also, this is needed to keep
* shadowed and real data registers writes together.
*/
spinlock_t lock;
/* Shadowed data register to clear/set bits safely. */
unsigned long data;
/* Shadowed direction registers to clear/set direction safely. */
unsigned long dir;
};
static inline struct bgpio_chip *to_bgpio_chip(struct gpio_chip *gc)
{
return container_of(gc, struct bgpio_chip, gc);
}
int __devexit bgpio_remove(struct bgpio_chip *bgc);
int __devinit bgpio_init(struct bgpio_chip *bgc,
struct device *dev,
unsigned long sz,
void __iomem *dat,
void __iomem *set,
void __iomem *clr,
void __iomem *dirout,
void __iomem *dirin,
bool big_endian);
#endif /* __BASIC_MMIO_GPIO_H */

View file

@ -0,0 +1,56 @@
#undef TRACE_SYSTEM
#define TRACE_SYSTEM gpio
#if !defined(_TRACE_GPIO_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_GPIO_H
#include <linux/tracepoint.h>
TRACE_EVENT(gpio_direction,
TP_PROTO(unsigned gpio, int in, int err),
TP_ARGS(gpio, in, err),
TP_STRUCT__entry(
__field(unsigned, gpio)
__field(int, in)
__field(int, err)
),
TP_fast_assign(
__entry->gpio = gpio;
__entry->in = in;
__entry->err = err;
),
TP_printk("%u %3s (%d)", __entry->gpio,
__entry->in ? "in" : "out", __entry->err)
);
TRACE_EVENT(gpio_value,
TP_PROTO(unsigned gpio, int get, int value),
TP_ARGS(gpio, get, value),
TP_STRUCT__entry(
__field(unsigned, gpio)
__field(int, get)
__field(int, value)
),
TP_fast_assign(
__entry->gpio = gpio;
__entry->get = get;
__entry->value = value;
),
TP_printk("%u %3s %d", __entry->gpio,
__entry->get ? "get" : "set", __entry->value)
);
#endif /* if !defined(_TRACE_GPIO_H) || defined(TRACE_HEADER_MULTI_READ) */
/* This part must be outside protection */
#include <trace/define_trace.h>