diff options
author | Arnd Bergmann <arnd@arndb.de> | 2012-10-04 22:57:00 +0200 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2012-10-04 22:57:51 +0200 |
commit | c37d6154c0b9163c27e53cc1d0be3867b4abd760 (patch) | |
tree | 7a24522c56d1cb284dff1d3c225bbdaba0901bb5 /drivers/gpio | |
parent | e7a570ff7dff9af6e54ff5e580a61ec7652137a0 (diff) | |
parent | 8a1ab3155c2ac7fbe5f2038d6e26efeb607a1498 (diff) |
Merge branch 'disintegrate-asm-generic' of git://git.infradead.org/users/dhowells/linux-headers into asm-generic
Patches from David Howells <dhowells@redhat.com>:
This is to complete part of the UAPI disintegration for which the
preparatory patches were pulled recently.
Note that there are some fixup patches which are at the base of the
branch aimed at you, plus all arches get the asm-generic branch merged in too.
* 'disintegrate-asm-generic' of git://git.infradead.org/users/dhowells/linux-headers:
UAPI: (Scripted) Disintegrate include/asm-generic
UAPI: Fix conditional header installation handling (notably kvm_para.h on m68k)
c6x: remove c6x signal.h
UAPI: Split compound conditionals containing __KERNEL__ in Arm64
UAPI: Fix the guards on various asm/unistd.h files
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'drivers/gpio')
30 files changed, 1573 insertions, 399 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index ba7926f5c099..8382dc832929 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -82,7 +82,7 @@ config GPIO_GENERIC config GPIO_DA9052 tristate "Dialog DA9052 GPIO" - depends on PMIC_DA9052 && BROKEN + depends on PMIC_DA9052 help Say yes here to enable the GPIO driver for the DA9052 chip. @@ -183,6 +183,12 @@ config GPIO_STA2X11 Say yes here to support the STA2x11/ConneXt GPIO device. The GPIO module has 128 GPIO pins with alternate functions. +config GPIO_VT8500 + bool "VIA/Wondermedia SoC GPIO Support" + depends on ARCH_VT8500 + help + Say yes here to support the VT8500/WM8505/WM8650 GPIO controller. + config GPIO_XILINX bool "Xilinx GPIO support" depends on PPC_OF || MICROBLAZE @@ -324,6 +330,7 @@ config GPIO_PCA953X_IRQ config GPIO_PCF857X tristate "PCF857x, PCA{85,96}7x, and MAX732[89] I2C GPIO expanders" depends on I2C + select IRQ_DOMAIN help Say yes here to provide access to most "quasi-bidirectional" I2C GPIO expanders used for additional digital outputs or inputs. @@ -444,6 +451,17 @@ config GPIO_ADP5588_IRQ Say yes here to enable the adp5588 to be used as an interrupt controller. It requires the driver to be built in the kernel. +config GPIO_ADNP + tristate "Avionic Design N-bit GPIO expander" + depends on I2C && OF + help + This option enables support for N GPIOs found on Avionic Design + I2C GPIO expanders. The register space will be extended by powers + of two, so the controller will need to accomodate for that. For + example: if a controller provides 48 pins, 6 registers will be + enough to represent all pins, but the driver will assume a + register layout for 64 pins (8 registers). + comment "PCI GPIO expanders:" config GPIO_CS5535 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 153caceeb053..0ffaa8423e87 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o obj-$(CONFIG_GPIO_74X164) += gpio-74x164.o obj-$(CONFIG_GPIO_AB8500) += gpio-ab8500.o +obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o @@ -69,6 +70,7 @@ obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o +obj-$(CONFIG_GPIO_VT8500) += gpio-vt8500.o obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index a31ad6f5d910..ed3e55161bdc 100644 --- a/drivers/gpio/gpio-74x164.c +++ b/drivers/gpio/gpio-74x164.c @@ -14,14 +14,18 @@ #include <linux/spi/spi.h> #include <linux/spi/74x164.h> #include <linux/gpio.h> +#include <linux/of_gpio.h> #include <linux/slab.h> #include <linux/module.h> +#define GEN_74X164_NUMBER_GPIOS 8 + struct gen_74x164_chip { struct spi_device *spi; + u8 *buffer; struct gpio_chip gpio_chip; struct mutex lock; - u8 port_config; + u32 registers; }; static struct gen_74x164_chip *gpio_to_74x164_chip(struct gpio_chip *gc) @@ -31,17 +35,47 @@ static struct gen_74x164_chip *gpio_to_74x164_chip(struct gpio_chip *gc) static int __gen_74x164_write_config(struct gen_74x164_chip *chip) { - return spi_write(chip->spi, - &chip->port_config, sizeof(chip->port_config)); + struct spi_message message; + struct spi_transfer *msg_buf; + int i, ret = 0; + + msg_buf = kzalloc(chip->registers * sizeof(struct spi_transfer), + GFP_KERNEL); + if (!msg_buf) + return -ENOMEM; + + spi_message_init(&message); + + /* + * Since the registers are chained, every byte sent will make + * the previous byte shift to the next register in the + * chain. Thus, the first byte send will end up in the last + * register at the end of the transfer. So, to have a logical + * numbering, send the bytes in reverse order so that the last + * byte of the buffer will end up in the last register. + */ + for (i = chip->registers - 1; i >= 0; i--) { + msg_buf[i].tx_buf = chip->buffer +i; + msg_buf[i].len = sizeof(u8); + spi_message_add_tail(msg_buf + i, &message); + } + + ret = spi_sync(chip->spi, &message); + + kfree(msg_buf); + + return ret; } static int gen_74x164_get_value(struct gpio_chip *gc, unsigned offset) { struct gen_74x164_chip *chip = gpio_to_74x164_chip(gc); + u8 bank = offset / 8; + u8 pin = offset % 8; int ret; mutex_lock(&chip->lock); - ret = (chip->port_config >> offset) & 0x1; + ret = (chip->buffer[bank] >> pin) & 0x1; mutex_unlock(&chip->lock); return ret; @@ -51,12 +85,14 @@ static void gen_74x164_set_value(struct gpio_chip *gc, unsigned offset, int val) { struct gen_74x164_chip *chip = gpio_to_74x164_chip(gc); + u8 bank = offset / 8; + u8 pin = offset % 8; mutex_lock(&chip->lock); if (val) - chip->port_config |= (1 << offset); + chip->buffer[bank] |= (1 << pin); else - chip->port_config &= ~(1 << offset); + chip->buffer[bank] &= ~(1 << pin); __gen_74x164_write_config(chip); mutex_unlock(&chip->lock); @@ -75,9 +111,8 @@ static int __devinit gen_74x164_probe(struct spi_device *spi) struct gen_74x164_chip_platform_data *pdata; int ret; - pdata = spi->dev.platform_data; - if (!pdata || !pdata->base) { - dev_dbg(&spi->dev, "incorrect or missing platform data\n"); + if (!spi->dev.of_node) { + dev_err(&spi->dev, "No device tree data available.\n"); return -EINVAL; } @@ -90,10 +125,16 @@ static int __devinit gen_74x164_probe(struct spi_device *spi) if (ret < 0) return ret; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(&spi->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; + pdata = spi->dev.platform_data; + if (pdata && pdata->base) + chip->gpio_chip.base = pdata->base; + else + chip->gpio_chip.base = -1; + mutex_init(&chip->lock); dev_set_drvdata(&spi->dev, chip); @@ -104,8 +145,20 @@ static int __devinit gen_74x164_probe(struct spi_device *spi) chip->gpio_chip.direction_output = gen_74x164_direction_output; chip->gpio_chip.get = gen_74x164_get_value; chip->gpio_chip.set = gen_74x164_set_value; - chip->gpio_chip.base = pdata->base; - chip->gpio_chip.ngpio = 8; + + if (of_property_read_u32(spi->dev.of_node, "registers-number", &chip->registers)) { + dev_err(&spi->dev, "Missing registers-number property in the DT.\n"); + ret = -EINVAL; + goto exit_destroy; + } + + chip->gpio_chip.ngpio = GEN_74X164_NUMBER_GPIOS * chip->registers; + chip->buffer = devm_kzalloc(&spi->dev, chip->gpio_chip.ngpio, GFP_KERNEL); + if (!chip->buffer) { + ret = -ENOMEM; + goto exit_destroy; + } + chip->gpio_chip.can_sleep = 1; chip->gpio_chip.dev = &spi->dev; chip->gpio_chip.owner = THIS_MODULE; @@ -125,7 +178,6 @@ static int __devinit gen_74x164_probe(struct spi_device *spi) exit_destroy: dev_set_drvdata(&spi->dev, NULL); mutex_destroy(&chip->lock); - kfree(chip); return ret; } @@ -141,36 +193,31 @@ static int __devexit gen_74x164_remove(struct spi_device *spi) dev_set_drvdata(&spi->dev, NULL); ret = gpiochip_remove(&chip->gpio_chip); - if (!ret) { + if (!ret) mutex_destroy(&chip->lock); - kfree(chip); - } else + else dev_err(&spi->dev, "Failed to remove the GPIO controller: %d\n", ret); return ret; } +static const struct of_device_id gen_74x164_dt_ids[] = { + { .compatible = "fairchild,74hc595" }, + {}, +}; +MODULE_DEVICE_TABLE(of, gen_74x164_dt_ids); + static struct spi_driver gen_74x164_driver = { .driver = { .name = "74x164", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(gen_74x164_dt_ids), }, .probe = gen_74x164_probe, .remove = __devexit_p(gen_74x164_remove), }; - -static int __init gen_74x164_init(void) -{ - return spi_register_driver(&gen_74x164_driver); -} -subsys_initcall(gen_74x164_init); - -static void __exit gen_74x164_exit(void) -{ - spi_unregister_driver(&gen_74x164_driver); -} -module_exit(gen_74x164_exit); +module_spi_driver(gen_74x164_driver); MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); MODULE_AUTHOR("Miguel Gaio <miguel.gaio@efixo.com>"); diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c new file mode 100644 index 000000000000..3df88336415e --- /dev/null +++ b/drivers/gpio/gpio-adnp.c @@ -0,0 +1,611 @@ +/* + * Copyright (C) 2011-2012 Avionic Design GmbH + * + * 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 + * published by the Free Software Foundation. + */ + +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/irqdomain.h> +#include <linux/module.h> +#include <linux/of_irq.h> +#include <linux/seq_file.h> +#include <linux/slab.h> + +#define GPIO_DDR(gpio) (0x00 << (gpio)->reg_shift) +#define GPIO_PLR(gpio) (0x01 << (gpio)->reg_shift) +#define GPIO_IER(gpio) (0x02 << (gpio)->reg_shift) +#define GPIO_ISR(gpio) (0x03 << (gpio)->reg_shift) +#define GPIO_PTR(gpio) (0x04 << (gpio)->reg_shift) + +struct adnp { + struct i2c_client *client; + struct gpio_chip gpio; + unsigned int reg_shift; + + struct mutex i2c_lock; + + struct irq_domain *domain; + struct mutex irq_lock; + + u8 *irq_enable; + u8 *irq_level; + u8 *irq_rise; + u8 *irq_fall; + u8 *irq_high; + u8 *irq_low; +}; + +static inline struct adnp *to_adnp(struct gpio_chip *chip) +{ + return container_of(chip, struct adnp, gpio); +} + +static int adnp_read(struct adnp *adnp, unsigned offset, uint8_t *value) +{ + int err; + + err = i2c_smbus_read_byte_data(adnp->client, offset); + if (err < 0) { + dev_err(adnp->gpio.dev, "%s failed: %d\n", + "i2c_smbus_read_byte_data()", err); + return err; + } + + *value = err; + return 0; +} + +static int adnp_write(struct adnp *adnp, unsigned offset, uint8_t value) +{ + int err; + + err = i2c_smbus_write_byte_data(adnp->client, offset, value); + if (err < 0) { + dev_err(adnp->gpio.dev, "%s failed: %d\n", + "i2c_smbus_write_byte_data()", err); + return err; + } + + return 0; +} + +static int adnp_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct adnp *adnp = to_adnp(chip); + unsigned int reg = offset >> adnp->reg_shift; + unsigned int pos = offset & 7; + u8 value; + int err; + + err = adnp_read(adnp, GPIO_PLR(adnp) + reg, &value); + if (err < 0) + return err; + + return (value & BIT(pos)) ? 1 : 0; +} + +static void __adnp_gpio_set(struct adnp *adnp, unsigned offset, int value) +{ + unsigned int reg = offset >> adnp->reg_shift; + unsigned int pos = offset & 7; + int err; + u8 val; + + err = adnp_read(adnp, GPIO_PLR(adnp) + reg, &val); + if (err < 0) + return; + + if (value) + val |= BIT(pos); + else + val &= ~BIT(pos); + + adnp_write(adnp, GPIO_PLR(adnp) + reg, val); +} + +static void adnp_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct adnp *adnp = to_adnp(chip); + + mutex_lock(&adnp->i2c_lock); + __adnp_gpio_set(adnp, offset, value); + mutex_unlock(&adnp->i2c_lock); +} + +static int adnp_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct adnp *adnp = to_adnp(chip); + unsigned int reg = offset >> adnp->reg_shift; + unsigned int pos = offset & 7; + u8 value; + int err; + + mutex_lock(&adnp->i2c_lock); + + err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &value); + if (err < 0) + goto out; + + value &= ~BIT(pos); + + err = adnp_write(adnp, GPIO_DDR(adnp) + reg, value); + if (err < 0) + goto out; + + err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &value); + if (err < 0) + goto out; + + if (err & BIT(pos)) + err = -EACCES; + + err = 0; + +out: + mutex_unlock(&adnp->i2c_lock); + return err; +} + +static int adnp_gpio_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct adnp *adnp = to_adnp(chip); + unsigned int reg = offset >> adnp->reg_shift; + unsigned int pos = offset & 7; + int err; + u8 val; + + mutex_lock(&adnp->i2c_lock); + + err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &val); + if (err < 0) + goto out; + + val |= BIT(pos); + + err = adnp_write(adnp, GPIO_DDR(adnp) + reg, val); + if (err < 0) + goto out; + + err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &val); + if (err < 0) + goto out; + + if (!(val & BIT(pos))) { + err = -EPERM; + goto out; + } + + __adnp_gpio_set(adnp, offset, value); + err = 0; + +out: + mutex_unlock(&adnp->i2c_lock); + return err; +} + +static void adnp_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + struct adnp *adnp = to_adnp(chip); + unsigned int num_regs = 1 << adnp->reg_shift, i, j; + int err; + + for (i = 0; i < num_regs; i++) { + u8 ddr, plr, ier, isr; + + mutex_lock(&adnp->i2c_lock); + + err = adnp_read(adnp, GPIO_DDR(adnp) + i, &ddr); + if (err < 0) { + mutex_unlock(&adnp->i2c_lock); + return; + } + + err = adnp_read(adnp, GPIO_PLR(adnp) + i, &plr); + if (err < 0) { + mutex_unlock(&adnp->i2c_lock); + return; + } + + err = adnp_read(adnp, GPIO_IER(adnp) + i, &ier); + if (err < 0) { + mutex_unlock(&adnp->i2c_lock); + return; + } + + err = adnp_read(adnp, GPIO_ISR(adnp) + i, &isr); + if (err < 0) { + mutex_unlock(&adnp->i2c_lock); + return; + } + + mutex_unlock(&adnp->i2c_lock); + + for (j = 0; j < 8; j++) { + unsigned int bit = (i << adnp->reg_shift) + j; + const char *direction = "input "; + const char *level = "low "; + const char *interrupt = "disabled"; + const char *pending = ""; + + if (ddr & BIT(j)) + direction = "output"; + + if (plr & BIT(j)) + level = "high"; + + if (ier & BIT(j)) + interrupt = "enabled "; + + if (isr & BIT(j)) + pending = "pending"; + + seq_printf(s, "%2u: %s %s IRQ %s %s\n", bit, + direction, level, interrupt, pending); + } + } +} + +static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios) +{ + struct gpio_chip *chip = &adnp->gpio; + + adnp->reg_shift = get_count_order(num_gpios) - 3; + + chip->direction_input = adnp_gpio_direction_input; + chip->direction_output = adnp_gpio_direction_output; + chip->get = adnp_gpio_get; + chip->set = adnp_gpio_set; + chip->can_sleep = 1; + + if (IS_ENABLED(CONFIG_DEBUG_FS)) + chip->dbg_show = adnp_gpio_dbg_show; + + chip->base = -1; + chip->ngpio = num_gpios; + chip->label = adnp->client->name; + chip->dev = &adnp->client->dev; + chip->of_node = chip->dev->of_node; + chip->owner = THIS_MODULE; + + return 0; +} + +static irqreturn_t adnp_irq(int irq, void *data) +{ + struct adnp *adnp = data; + unsigned int num_regs, i; + + num_regs = 1 << adnp->reg_shift; + + for (i = 0; i < num_regs; i++) { + unsigned int base = i << adnp->reg_shift, bit; + u8 changed, level, isr, ier; + unsigned long pending; + int err; + + mutex_lock(&adnp->i2c_lock); + + err = adnp_read(adnp, GPIO_PLR(adnp) + i, &level); + if (err < 0) { + mutex_unlock(&adnp->i2c_lock); + continue; + } + + err = adnp_read(adnp, GPIO_ISR(adnp) + i, &isr); + if (err < 0) { + mutex_unlock(&adnp->i2c_lock); + continue; + } + + err = adnp_read(adnp, GPIO_IER(adnp) + i, &ier); + if (err < 0) { + mutex_unlock(&adnp->i2c_lock); + continue; + } + + mutex_unlock(&adnp->i2c_lock); + + /* determine pins that changed levels */ + changed = level ^ adnp->irq_level[i]; + + /* compute edge-triggered interrupts */ + pending = changed & ((adnp->irq_fall[i] & ~level) | + (adnp->irq_rise[i] & level)); + + /* add in level-triggered interrupts */ + pending |= (adnp->irq_high[i] & level) | + (adnp->irq_low[i] & ~level); + + /* mask out non-pending and disabled interrupts */ + pending &= isr & ier; + + for_each_set_bit(bit, &pending, 8) { + unsigned int virq; + virq = irq_find_mapping(adnp->domain, base + bit); + handle_nested_irq(virq); + } + } + + return IRQ_HANDLED; +} + +static int adnp_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct adnp *adnp = to_adnp(chip); + return irq_create_mapping(adnp->domain, offset); +} + +static void adnp_irq_mask(struct irq_data *data) +{ + struct adnp *adnp = irq_data_get_irq_chip_data(data); + unsigned int reg = data->hwirq >> adnp->reg_shift; + unsigned int pos = data->hwirq & 7; + + adnp->irq_enable[reg] &= ~BIT(pos); +} + +static void adnp_irq_unmask(struct irq_data *data) +{ + struct adnp *adnp = irq_data_get_irq_chip_data(data); + unsigned int reg = data->hwirq >> adnp->reg_shift; + unsigned int pos = data->hwirq & 7; + + adnp->irq_enable[reg] |= BIT(pos); +} + +static int adnp_irq_set_type(struct irq_data *data, unsigned int type) +{ + struct adnp *adnp = irq_data_get_irq_chip_data(data); + unsigned int reg = data->hwirq >> adnp->reg_shift; + unsigned int pos = data->hwirq & 7; + + if (type & IRQ_TYPE_EDGE_RISING) + adnp->irq_rise[reg] |= BIT(pos); + else + adnp->irq_rise[reg] &= ~BIT(pos); + + if (type & IRQ_TYPE_EDGE_FALLING) + adnp->irq_fall[reg] |= BIT(pos); + else + adnp->irq_fall[reg] &= ~BIT(pos); + + if (type & IRQ_TYPE_LEVEL_HIGH) + adnp->irq_high[reg] |= BIT(pos); + else + adnp->irq_high[reg] &= ~BIT(pos); + + if (type & IRQ_TYPE_LEVEL_LOW) + adnp->irq_low[reg] |= BIT(pos); + else + adnp->irq_low[reg] &= ~BIT(pos); + + return 0; +} + +static void adnp_irq_bus_lock(struct irq_data *data) +{ + struct adnp *adnp = irq_data_get_irq_chip_data(data); + + mutex_lock(&adnp->irq_lock); +} + +static void adnp_irq_bus_unlock(struct irq_data *data) +{ + struct adnp *adnp = irq_data_get_irq_chip_data(data); + unsigned int num_regs = 1 << adnp->reg_shift, i; + + mutex_lock(&adnp->i2c_lock); + + for (i = 0; i < num_regs; i++) + adnp_write(adnp, GPIO_IER(adnp) + i, adnp->irq_enable[i]); + + mutex_unlock(&adnp->i2c_lock); + mutex_unlock(&adnp->irq_lock); +} + +static struct irq_chip adnp_irq_chip = { + .name = "gpio-adnp", + .irq_mask = adnp_irq_mask, + .irq_unmask = adnp_irq_unmask, + .irq_set_type = adnp_irq_set_type, + .irq_bus_lock = adnp_irq_bus_lock, + .irq_bus_sync_unlock = adnp_irq_bus_unlock, +}; + +static int adnp_irq_map(struct irq_domain *domain, unsigned int irq, + irq_hw_number_t hwirq) +{ + irq_set_chip_data(irq, domain->host_data); + irq_set_chip(irq, &adnp_irq_chip); + irq_set_nested_thread(irq, true); + +#ifdef CONFIG_ARM + set_irq_flags(irq, IRQF_VALID); +#else + irq_set_noprobe(irq); +#endif + + return 0; +} + +static const struct irq_domain_ops adnp_irq_domain_ops = { + .map = adnp_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + +static int adnp_irq_setup(struct adnp *adnp) +{ + unsigned int num_regs = 1 << adnp->reg_shift, i; + struct gpio_chip *chip = &adnp->gpio; + int err; + + mutex_init(&adnp->irq_lock); + + /* + * Allocate memory to keep track of the current level and trigger + * modes of the interrupts. To avoid multiple allocations, a single + * large buffer is allocated and pointers are setup to point at the + * corresponding offsets. For consistency, the layout of the buffer + * is chosen to match the register layout of the hardware in that + * each segment contains the corresponding bits for all interrupts. + */ + adnp->irq_enable = devm_kzalloc(chip->dev, num_regs * 6, GFP_KERNEL); + if (!adnp->irq_enable) + return -ENOMEM; + + adnp->irq_level = adnp->irq_enable + (num_regs * 1); + adnp->irq_rise = adnp->irq_enable + (num_regs * 2); + adnp->irq_fall = adnp->irq_enable + (num_regs * 3); + adnp->irq_high = adnp->irq_enable + (num_regs * 4); + adnp->irq_low = adnp->irq_enable + (num_regs * 5); + + for (i = 0; i < num_regs; i++) { + /* + * Read the initial level of all pins to allow the emulation + * of edge triggered interrupts. + */ + err = adnp_read(adnp, GPIO_PLR(adnp) + i, &adnp->irq_level[i]); + if (err < 0) + return err; + + /* disable all interrupts */ + err = adnp_write(adnp, GPIO_IER(adnp) + i, 0); + if (err < 0) + return err; + + adnp->irq_enable[i] = 0x00; + } + + adnp->domain = irq_domain_add_linear(chip->of_node, chip->ngpio, + &adnp_irq_domain_ops, adnp); + + err = request_threaded_irq(adnp->client->irq, NULL, adnp_irq, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + dev_name(chip->dev), adnp); + if (err != 0) { + dev_err(chip->dev, "can't request IRQ#%d: %d\n", + adnp->client->irq, err); + goto error; + } + + chip->to_irq = adnp_gpio_to_irq; + return 0; + +error: + irq_domain_remove(adnp->domain); + return err; +} + +static void adnp_irq_teardown(struct adnp *adnp) +{ + unsigned int irq, i; + + free_irq(adnp->client->irq, adnp); + + for (i = 0; i < adnp->gpio.ngpio; i++) { + irq = irq_find_mapping(adnp->domain, i); + if (irq > 0) + irq_dispose_mapping(irq); + } + + irq_domain_remove(adnp->domain); +} + +static __devinit int adnp_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device_node *np = client->dev.of_node; + struct adnp *adnp; + u32 num_gpios; + int err; + + err = of_property_read_u32(np, "nr-gpios", &num_gpios); + if (err < 0) + return err; + + client->irq = irq_of_parse_and_map(np, 0); + if (!client->irq) + return -EPROBE_DEFER; + + adnp = devm_kzalloc(&client->dev, sizeof(*adnp), GFP_KERNEL); + if (!adnp) + return -ENOMEM; + + mutex_init(&adnp->i2c_lock); + adnp->client = client; + + err = adnp_gpio_setup(adnp, num_gpios); + if (err < 0) + return err; + + if (of_find_property(np, "interrupt-controller", NULL)) { + err = adnp_irq_setup(adnp); + if (err < 0) + goto teardown; + } + + err = gpiochip_add(&adnp->gpio); + if (err < 0) + goto teardown; + + i2c_set_clientdata(client, adnp); + return 0; + +teardown: + if (of_find_property(np, "interrupt-controller", NULL)) + adnp_irq_teardown(adnp); + + return err; +} + +static __devexit int adnp_i2c_remove(struct i2c_client *client) +{ + struct adnp *adnp = i2c_get_clientdata(client); + struct device_node *np = client->dev.of_node; + int err; + + err = gpiochip_remove(&adnp->gpio); + if (err < 0) { + dev_err(&client->dev, "%s failed: %d\n", "gpiochip_remove()", + err); + return err; + } + + if (of_find_property(np, "interrupt-controller", NULL)) + adnp_irq_teardown(adnp); + + return 0; +} + +static const struct i2c_device_id adnp_i2c_id[] __devinitconst = { + { "gpio-adnp" }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, adnp_i2c_id); + +static const struct of_device_id adnp_of_match[] __devinitconst = { + { .compatible = "ad,gpio-adnp", }, + { }, +}; +MODULE_DEVICE_TABLE(of, adnp_of_match); + +static struct i2c_driver adnp_i2c_driver = { + .driver = { + .name = "gpio-adnp", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(adnp_of_match), + }, + .probe = adnp_i2c_probe, + .remove = __devexit_p(adnp_i2c_remove), + .id_table = adnp_i2c_id, +}; +module_i2c_driver(adnp_i2c_driver); + +MODULE_DESCRIPTION("Avionic Design N-bit GPIO expander"); +MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index ae5d7f12ce66..eeedad42913e 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -483,19 +483,7 @@ static struct i2c_driver adp5588_gpio_driver = { .id_table = adp5588_gpio_id, }; -static int __init adp5588_gpio_init(void) -{ - return i2c_add_driver(&adp5588_gpio_driver); -} - -module_init(adp5588_gpio_init); - -static void __exit adp5588_gpio_exit(void) -{ - i2c_del_driver(&adp5588_gpio_driver); -} - -module_exit(adp5588_gpio_exit); +module_i2c_driver(adp5588_gpio_driver); MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); MODULE_DESCRIPTION("GPIO ADP5588 Driver"); diff --git a/drivers/gpio/gpio-bt8xx.c b/drivers/gpio/gpio-bt8xx.c index e4cc7eb69bb2..aba97abda77c 100644 --- a/drivers/gpio/gpio-bt8xx.c +++ b/drivers/gpio/gpio-bt8xx.c @@ -310,7 +310,7 @@ static int bt8xxgpio_resume(struct pci_dev *pdev) #define bt8xxgpio_resume NULL #endif /* CONFIG_PM */ -static struct pci_device_id bt8xxgpio_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(bt8xxgpio_pci_tbl) = { { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848) }, { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849) }, { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878) }, diff --git a/drivers/gpio/gpio-da9052.c b/drivers/gpio/gpio-da9052.c index 56dd047d5844..24b8c2974047 100644 --- a/drivers/gpio/gpio-da9052.c +++ b/drivers/gpio/gpio-da9052.c @@ -207,7 +207,7 @@ static int __devinit da9052_gpio_probe(struct platform_device *pdev) struct da9052_pdata *pdata; int ret; - gpio = kzalloc(sizeof(*gpio), GFP_KERNEL); + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); if (gpio == NULL) return -ENOMEM; @@ -221,28 +221,19 @@ static int __devinit da9052_gpio_probe(struct platform_device *pdev) ret = gpiochip_add(&gpio->gp); if (ret < 0) { dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); - goto err_mem; + return ret; } platform_set_drvdata(pdev, gpio); return 0; - -err_mem: - kfree(gpio); - return ret; } static int __devexit da9052_gpio_remove(struct platform_device *pdev) { struct da9052_gpio *gpio = platform_get_drvdata(pdev); - int ret; - - ret = gpiochip_remove(&gpio->gp); - if (ret == 0) - kfree(gpio); - return ret; + return gpiochip_remove(&gpio->gp); } static struct platform_driver da9052_gpio_driver = { diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 3d000169285d..17df6db5dca7 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -366,7 +366,7 @@ static int __init davinci_gpio_irq_setup(void) PTR_ERR(clk)); return PTR_ERR(clk); } - clk_enable(clk); + clk_prepare_enable(clk); /* Arrange gpio_to_irq() support, handling either direct IRQs or * banked IRQs. Having GPIOs in the first GPIO bank use direct diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index ec48ed512628..efb4c2d0d132 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -85,22 +85,16 @@ static inline void em_gio_write(struct em_gio_priv *p, int offs, iowrite32(value, p->base1 + (offs - GIO_IDT0)); } -static inline struct em_gio_priv *irq_to_priv(struct irq_data *d) -{ - struct irq_chip *chip = irq_data_get_irq_chip(d); - return container_of(chip, struct em_gio_priv, irq_chip); -} - static void em_gio_irq_disable(struct irq_data *d) { - struct em_gio_priv *p = irq_to_priv(d); + struct em_gio_priv *p = irq_data_get_irq_chip_data(d); em_gio_write(p, GIO_IDS, BIT(irqd_to_hwirq(d))); } static void em_gio_irq_enable(struct irq_data *d) { - struct em_gio_priv *p = irq_to_priv(d); + struct em_gio_priv *p = irq_data_get_irq_chip_data(d); em_gio_write(p, GIO_IEN, BIT(irqd_to_hwirq(d))); } @@ -118,7 +112,7 @@ static unsigned char em_gio_sense_table[IRQ_TYPE_SENSE_MASK + 1] = { static int em_gio_irq_set_type(struct irq_data *d, unsigned int type) { unsigned char value = em_gio_sense_table[type & IRQ_TYPE_SENSE_MASK]; - struct em_gio_priv *p = irq_to_priv(d); + struct em_gio_priv *p = irq_data_get_irq_chip_data(d); unsigned int reg, offset, shift; unsigned long flags; unsigned long tmp; diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index ed94b4ea72e9..3644e0dcb3dd 100644 --- a/drivers/gpio/gpio-lpc32xx.c +++ b/drivers/gpio/gpio-lpc32xx.c @@ -113,7 +113,8 @@ static const char *gpi_p3_names[LPC32XX_GPI_P3_MAX] = { NULL, NULL, NULL, "gpi15", "gpi16", "gpi17", "gpi18", "gpi19", "gpi20", "gpi21", "gpi22", "gpi23", - "gpi24", "gpi25", "gpi26", "gpi27" + "gpi24", "gpi25", "gpi26", "gpi27", + "gpi28" }; static const char *gpo_p3_names[LPC32XX_GPO_P3_MAX] = { diff --git a/drivers/gpio/gpio-mc9s08dz60.c b/drivers/gpio/gpio-mc9s08dz60.c index 2738cc44d636..0ab700046a23 100644 --- a/drivers/gpio/gpio-mc9s08dz60.c +++ b/drivers/gpio/gpio-mc9s08dz60.c @@ -91,10 +91,9 @@ static int mc9s08dz60_direction_output(struct gpio_chip *gc, static int mc9s08dz60_probe(struct i2c_client *client, const struct i2c_device_id *id) { - int ret = 0; struct mc9s08dz60 *mc9s; - mc9s = kzalloc(sizeof(*mc9s), GFP_KERNEL); + mc9s = devm_kzalloc(&client->dev, sizeof(*mc9s), GFP_KERNEL); if (!mc9s) return -ENOMEM; @@ -110,30 +109,16 @@ static int mc9s08dz60_probe(struct i2c_client *client, mc9s->client = client; i2c_set_clientdata(client, mc9s); - ret = gpiochip_add(&mc9s->chip); - if (ret) - goto error; - - return 0; - - error: - kfree(mc9s); - return ret; + return gpiochip_add(&mc9s->chip); } static int mc9s08dz60_remove(struct i2c_client *client) { struct mc9s08dz60 *mc9s; - int ret; mc9s = i2c_get_clientdata(client); - ret = gpiochip_remove(&mc9s->chip); - if (!ret) - kfree(mc9s); - - return ret; - + return gpiochip_remove(&mc9s->chip); } static const struct i2c_device_id mc9s08dz60_id[] = { diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index db01f151d41c..6a29ee1847be 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -87,8 +87,7 @@ struct ioh_gpio_reg_data { * @gpio_use_sel: Save GPIO_USE_SEL1~4 register for PM * @ch: Indicate GPIO channel * @irq_base: Save base of IRQ number for interrupt - * @spinlock: Used for register access protection in - * interrupt context ioh_irq_type and PM; + * @spinlock: Used for register access protection */ struct ioh_gpio { void __iomem *base; @@ -97,7 +96,6 @@ struct ioh_gpio { struct gpio_chip gpio; struct ioh_gpio_reg_data ioh_gpio_reg; u32 gpio_use_sel; - struct mutex lock; int ch; int irq_base; spinlock_t spinlock; @@ -109,8 +107,9 @@ static void ioh_gpio_set(struct gpio_chip *gpio, unsigned nr, int val) { u32 reg_val; struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio); + unsigned long flags; - mutex_lock(&chip->lock); + spin_lock_irqsave(&chip->spinlock, flags); reg_val = ioread32(&chip->reg->regs[chip->ch].po); if (val) reg_val |= (1 << nr); @@ -118,7 +117,7 @@ static void ioh_gpio_set(struct gpio_chip *gpio, unsigned nr, int val) reg_val &= ~(1 << nr); iowrite32(reg_val, &chip->reg->regs[chip->ch].po); - mutex_unlock(&chip->lock); + spin_unlock_irqrestore(&chip->spinlock, flags); } static int ioh_gpio_get(struct gpio_chip *gpio, unsigned nr) @@ -134,8 +133,9 @@ static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio); u32 pm; u32 reg_val; + unsigned long flags; - mutex_lock(&chip->lock); + spin_lock_irqsave(&chip->spinlock, flags); pm = ioread32(&chip->reg->regs[chip->ch].pm) & ((1 << num_ports[chip->ch]) - 1); pm |= (1 << nr); @@ -148,7 +148,7 @@ static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, reg_val &= ~(1 << nr); iowrite32(reg_val, &chip->reg->regs[chip->ch].po); - mutex_unlock(&chip->lock); + spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } @@ -157,13 +157,14 @@ static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) { struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio); u32 pm; + unsigned long flags; - mutex_lock(&chip->lock); + spin_lock_irqsave(&chip->spinlock, flags); pm = ioread32(&chip->reg->regs[chip->ch].pm) & ((1 << num_ports[chip->ch]) - 1); pm &= ~(1 << nr); iowrite32(pm, &chip->reg->regs[chip->ch].pm); - mutex_unlock(&chip->lock); + spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } @@ -447,7 +448,6 @@ static int __devinit ioh_gpio_probe(struct pci_dev *pdev, chip->base = base; chip->reg = chip->base; chip->ch = i; - mutex_init(&chip->lock); spin_lock_init(&chip->spinlock); ioh_gpio_setup(chip, num_ports[i]); ret = gpiochip_add(&chip->gpio); diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index 5a1817eedd1b..9ae29cc0d17f 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -38,7 +38,7 @@ struct mpc8xxx_gpio_chip { */ u32 data; struct irq_domain *irq; - void *of_dev_id_data; + const void *of_dev_id_data; }; static inline u32 mpc8xxx_gpio2mask(unsigned int gpio) diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c index 5cb1227d69cf..38305beb4375 100644 --- a/drivers/gpio/gpio-msm-v2.c +++ b/drivers/gpio/gpio-msm-v2.c @@ -317,9 +317,7 @@ static void msm_summary_irq_handler(unsigned int irq, struct irq_desc *desc) chained_irq_enter(chip, desc); - for (i = find_first_bit(msm_gpio.enabled_irqs, NR_GPIO_IRQS); - i < NR_GPIO_IRQS; - i = find_next_bit(msm_gpio.enabled_irqs, NR_GPIO_IRQS, i + 1)) { + for_each_set_bit(i, msm_gpio.enabled_irqs, NR_GPIO_IRQS) { if (readl(GPIO_INTR_STATUS(i)) & BIT(INTR_STATUS)) generic_handle_irq(msm_gpio_to_irq(&msm_gpio.gpio_chip, i)); diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index 39e495669961..796fb13e4815 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -24,6 +24,7 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/irq.h> +#include <linux/irqdomain.h> #include <linux/gpio.h> #include <linux/of.h> #include <linux/of_address.h> @@ -52,8 +53,6 @@ #define GPIO_INT_LEV_MASK (1 << 0) #define GPIO_INT_POL_MASK (1 << 1) -#define irq_to_gpio(irq) ((irq) - MXS_GPIO_IRQ_START) - enum mxs_gpio_id { IMX23_GPIO, IMX28_GPIO, @@ -63,7 +62,7 @@ struct mxs_gpio_port { void __iomem *base; int id; int irq; - int virtual_irq_start; + struct irq_domain *domain; struct bgpio_chip bgc; enum mxs_gpio_id devid; }; @@ -82,8 +81,7 @@ static inline int is_imx28_gpio(struct mxs_gpio_port *port) static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type) { - u32 gpio = irq_to_gpio(d->irq); - u32 pin_mask = 1 << (gpio & 31); + u32 pin_mask = 1 << d->hwirq; struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct mxs_gpio_port *port = gc->private; void __iomem *pin_addr; @@ -120,7 +118,7 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type) else writel(pin_mask, pin_addr + MXS_CLR); - writel(1 << (gpio & 0x1f), + writel(pin_mask, port->base + PINCTRL_IRQSTAT(port) + MXS_CLR); return 0; @@ -131,7 +129,6 @@ static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc) { u32 irq_stat; struct mxs_gpio_port *port = irq_get_handler_data(irq); - u32 gpio_irq_no_base = port->virtual_irq_start; desc->irq_data.chip->irq_ack(&desc->irq_data); @@ -140,7 +137,7 @@ static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc) while (irq_stat != 0) { int irqoffset = fls(irq_stat) - 1; - generic_handle_irq(gpio_irq_no_base + irqoffset); + generic_handle_irq(irq_find_mapping(port->domain, irqoffset)); irq_stat &= ~(1 << irqoffset); } } @@ -167,12 +164,12 @@ static int mxs_gpio_set_wake_irq(struct irq_data *d, unsigned int enable) return 0; } -static void __init mxs_gpio_init_gc(struct mxs_gpio_port *port) +static void __init mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base) { struct irq_chip_generic *gc; struct irq_chip_type *ct; - gc = irq_alloc_generic_chip("gpio-mxs", 1, port->virtual_irq_start, + gc = irq_alloc_generic_chip("gpio-mxs", 1, irq_base, port->base, handle_level_irq); gc->private = port; @@ -194,7 +191,7 @@ static int mxs_gpio_to_irq(struct gpio_chip *gc, unsigned offset) struct mxs_gpio_port *port = container_of(bgc, struct mxs_gpio_port, bgc); - return port->virtual_irq_start + offset; + return irq_find_mapping(port->domain, offset); } static struct platform_device_id mxs_gpio_ids[] = { @@ -226,6 +223,7 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev) static void __iomem *base; struct mxs_gpio_port *port; struct resource *iores = NULL; + int irq_base; int err; port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL); @@ -241,7 +239,6 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev) port->id = pdev->id; port->devid = pdev->id_entry->driver_data; } - port->virtual_irq_start = MXS_GPIO_IRQ_START + port->id * 32; port->irq = platform_get_irq(pdev, 0); if (port->irq < 0) @@ -275,8 +272,19 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev) /* clear address has to be used to clear IRQSTAT bits */ writel(~0U, port->base + PINCTRL_IRQSTAT(port) + MXS_CLR); + irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id()); + if (irq_base < 0) + return irq_base; + + port->domain = irq_domain_add_legacy(np, 32, irq_base, 0, + &irq_domain_simple_ops, NULL); + if (!port->domain) { + err = -ENODEV; + goto out_irqdesc_free; + } + /* gpio-mxs can be a generic irq chip */ - mxs_gpio_init_gc(port); + mxs_gpio_init_gc(port, irq_base); /* setup one handler for each entry */ irq_set_chained_handler(port->irq, mxs_gpio_irq_handler); @@ -287,18 +295,22 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev) port->base + PINCTRL_DOUT(port), NULL, port->base + PINCTRL_DOE(port), NULL, 0); if (err) - return err; + goto out_irqdesc_free; port->bgc.gc.to_irq = mxs_gpio_to_irq; port->bgc.gc.base = port->id * 32; err = gpiochip_add(&port->bgc.gc); - if (err) { - bgpio_remove(&port->bgc); - return err; - } + if (err) + goto out_bgpio_remove; return 0; + +out_bgpio_remove: + bgpio_remove(&port->bgc); +out_irqdesc_free: + irq_free_descs(irq_base, 32); + return err; } static struct platform_driver mxs_gpio_driver = { diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index e6efd77668f0..94cbc842fbc3 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -25,11 +25,9 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/irqdomain.h> +#include <linux/gpio.h> +#include <linux/platform_data/gpio-omap.h> -#include <mach/hardware.h> -#include <asm/irq.h> -#include <mach/irqs.h> -#include <asm/gpio.h> #include <asm/mach/irq.h> #define OFF_MODE 1 @@ -385,13 +383,16 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, static int gpio_irq_type(struct irq_data *d, unsigned type) { struct gpio_bank *bank = irq_data_get_irq_chip_data(d); - unsigned gpio; + unsigned gpio = 0; int retval; unsigned long flags; - if (!cpu_class_is_omap2() && d->irq > IH_MPUIO_BASE) +#ifdef CONFIG_ARCH_OMAP1 + if (d->irq > IH_MPUIO_BASE) gpio = OMAP_MPUIO(d->irq - IH_MPUIO_BASE); - else +#endif + + if (!gpio) gpio = irq_to_gpio(bank, d->irq); if (type & ~IRQ_TYPE_SENSE_MASK) @@ -1058,7 +1059,7 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; const struct of_device_id *match; - struct omap_gpio_platform_data *pdata; + const struct omap_gpio_platform_data *pdata; struct resource *res; struct gpio_bank *bank; int ret = 0; @@ -1440,19 +1441,19 @@ static struct omap_gpio_reg_offs omap4_gpio_regs = { .fallingdetect = OMAP4_GPIO_FALLINGDETECT, }; -static struct omap_gpio_platform_data omap2_pdata = { +const static struct omap_gpio_platform_data omap2_pdata = { .regs = &omap2_gpio_regs, .bank_width = 32, .dbck_flag = false, }; -static struct omap_gpio_platform_data omap3_pdata = { +const static struct omap_gpio_platform_data omap3_pdata = { .regs = &omap2_gpio_regs, .bank_width = 32, .dbck_flag = true, }; -static struct omap_gpio_platform_data omap4_pdata = { +const static struct omap_gpio_platform_data omap4_pdata = { .regs = &omap4_gpio_regs, .bank_width = 32, .dbck_flag = true, diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 076e236d0da7..16af35cd2b10 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -23,7 +23,12 @@ #include <linux/gpio.h> #include <linux/i2c.h> #include <linux/i2c/pcf857x.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> #include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/workqueue.h> static const struct i2c_device_id pcf857x_id[] = { @@ -60,7 +65,12 @@ struct pcf857x { struct gpio_chip chip; struct i2c_client *client; struct mutex lock; /* protect 'out' */ + struct work_struct work; /* irq demux work */ + struct irq_domain *irq_domain; /* for irq demux */ + spinlock_t slock; /* protect irq demux */ unsigned out; /* software latch */ + unsigned status; /* current status */ + int irq; /* real irq number */ int (*write)(struct i2c_client *client, unsigned data); int (*read)(struct i2c_client *client); @@ -150,6 +160,100 @@ static void pcf857x_set(struct gpio_chip *chip, unsigned offset, int value) /*-------------------------------------------------------------------------*/ +static int pcf857x_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct pcf857x *gpio = container_of(chip, struct pcf857x, chip); + + return irq_create_mapping(gpio->irq_domain, offset); +} + +static void pcf857x_irq_demux_work(struct work_struct *work) +{ + struct pcf857x *gpio = container_of(work, + struct pcf857x, + work); + unsigned long change, i, status, flags; + + status = gpio->read(gpio->client); + + spin_lock_irqsave(&gpio->slock, flags); + + change = gpio->status ^ status; + for_each_set_bit(i, &change, gpio->chip.ngpio) + generic_handle_irq(irq_find_mapping(gpio->irq_domain, i)); + gpio->status = status; + + spin_unlock_irqrestore(&gpio->slock, flags); +} + +static irqreturn_t pcf857x_irq_demux(int irq, void *data) +{ + struct pcf857x *gpio = data; + + /* + * pcf857x can't read/write data here, + * since i2c data access might go to sleep. + */ + schedule_work(&gpio->work); + + return IRQ_HANDLED; +} + +static int pcf857x_irq_domain_map(struct irq_domain *domain, unsigned int virq, + irq_hw_number_t hw) +{ + irq_set_chip_and_handler(virq, + &dummy_irq_chip, + handle_level_irq); + return 0; +} + +static struct irq_domain_ops pcf857x_irq_domain_ops = { + .map = pcf857x_irq_domain_map, +}; + +static void pcf857x_irq_domain_cleanup(struct pcf857x *gpio) +{ + if (gpio->irq_domain) + irq_domain_remove(gpio->irq_domain); + + if (gpio->irq) + free_irq(gpio->irq, gpio); +} + +static int pcf857x_irq_domain_init(struct pcf857x *gpio, + struct pcf857x_platform_data *pdata, + struct device *dev) +{ + int status; + + gpio->irq_domain = irq_domain_add_linear(dev->of_node, + gpio->chip.ngpio, + &pcf857x_irq_domain_ops, + NULL); + if (!gpio->irq_domain) + goto fail; + + /* enable real irq */ + status = request_irq(pdata->irq, pcf857x_irq_demux, 0, + dev_name(dev), gpio); + if (status) + goto fail; + + /* enable gpio_to_irq() */ + INIT_WORK(&gpio->work, pcf857x_irq_demux_work); + gpio->chip.to_irq = pcf857x_to_irq; + gpio->irq = pdata->irq; + + return 0; + +fail: + pcf857x_irq_domain_cleanup(gpio); + return -EINVAL; +} + +/*-------------------------------------------------------------------------*/ + static int pcf857x_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -168,6 +272,7 @@ static int pcf857x_probe(struct i2c_client *client, return -ENOMEM; mutex_init(&gpio->lock); + spin_lock_init(&gpio->slock); gpio->chip.base = pdata ? pdata->gpio_base : -1; gpio->chip.can_sleep = 1; @@ -179,6 +284,15 @@ static int pcf857x_probe(struct i2c_client *client, gpio->chip.direction_output = pcf857x_output; gpio->chip.ngpio = id->driver_data; + /* enable gpio_to_irq() if platform has settings */ + if (pdata && pdata->irq) { + status = pcf857x_irq_domain_init(gpio, pdata, &client->dev); + if (status < 0) { + dev_err(&client->dev, "irq_domain init failed\n"); + goto fail; + } + } + /* NOTE: the OnSemi jlc1562b is also largely compatible with * these parts, notably for output. It has a low-resolution * DAC instead of pin change IRQs; and its inputs can be the @@ -248,6 +362,7 @@ static int pcf857x_probe(struct i2c_client *client, * all-ones reset state. Otherwise it flags pins to be driven low. */ gpio->out = pdata ? ~pdata->n_latch : ~0; + gpio->status = gpio->out; status = gpiochip_add(&gpio->chip); if (status < 0) @@ -278,6 +393,10 @@ static int pcf857x_probe(struct i2c_client *client, fail: dev_dbg(&client->dev, "probe error %d for '%s'\n", status, client->name); + + if (pdata && pdata->irq) + pcf857x_irq_domain_cleanup(gpio); + kfree(gpio); return status; } @@ -299,6 +418,9 @@ static int pcf857x_remove(struct i2c_client *client) } } + if (pdata && pdata->irq) + pcf857x_irq_domain_cleanup(gpio); + status = gpiochip_remove(&gpio->chip); if (status == 0) kfree(gpio); diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 139ad3e20011..4ad0c4f9171c 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -92,9 +92,7 @@ struct pch_gpio_reg_data { * @lock: Used for register access protection * @irq_base: Save base of IRQ number for interrupt * @ioh: IOH ID - * @spinlock: Used for register access protection in - * interrupt context pch_irq_mask, - * pch_irq_unmask and pch_irq_type; + * @spinlock: Used for register access protection */ struct pch_gpio { void __iomem *base; @@ -102,7 +100,6 @@ struct pch_gpio { struct device *dev; struct gpio_chip gpio; struct pch_gpio_reg_data pch_gpio_reg; - struct mutex lock; int irq_base; enum pch_type_t ioh; spinlock_t spinlock; @@ -112,8 +109,9 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned nr, int val) { u32 reg_val; struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio); + unsigned long flags; - mutex_lock(&chip->lock); + spin_lock_irqsave(&chip->spinlock, flags); reg_val = ioread32(&chip->reg->po); if (val) reg_val |= (1 << nr); @@ -121,7 +119,7 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned nr, int val) reg_val &= ~(1 << nr); iowrite32(reg_val, &chip->reg->po); - mutex_unlock(&chip->lock); + spin_unlock_irqrestore(&chip->spinlock, flags); } static int pch_gpio_get(struct gpio_chip *gpio, unsigned nr) @@ -137,8 +135,9 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio); u32 pm; u32 reg_val; + unsigned long flags; - mutex_lock(&chip->lock); + spin_lock_irqsave(&chip->spinlock, flags); pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1); pm |= (1 << nr); iowrite32(pm, &chip->reg->pm); @@ -149,8 +148,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, else reg_val &= ~(1 << nr); iowrite32(reg_val, &chip->reg->po); - - mutex_unlock(&chip->lock); + spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } @@ -159,12 +157,13 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) { struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio); u32 pm; + unsigned long flags; - mutex_lock(&chip->lock); + spin_lock_irqsave(&chip->spinlock, flags); pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1); pm &= ~(1 << nr); iowrite32(pm, &chip->reg->pm); - mutex_unlock(&chip->lock); + spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } @@ -387,7 +386,6 @@ static int __devinit pch_gpio_probe(struct pci_dev *pdev, chip->reg = chip->base; pci_set_drvdata(pdev, chip); - mutex_init(&chip->lock); spin_lock_init(&chip->spinlock); pch_gpio_setup(chip); ret = gpiochip_add(&chip->gpio); diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index 9cac88a65f78..98d52cb3fd1a 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -26,6 +26,8 @@ #include <linux/syscore_ops.h> #include <linux/slab.h> +#include <asm/mach/irq.h> + #include <mach/irqs.h> /* @@ -59,6 +61,7 @@ #define BANK_OFF(n) (((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2)) int pxa_last_gpio; +static int irq_base; #ifdef CONFIG_OF static struct irq_domain *domain; @@ -167,63 +170,14 @@ static inline int __gpio_is_occupied(unsigned gpio) return ret; } -#ifdef CONFIG_ARCH_PXA -static inline int __pxa_gpio_to_irq(int gpio) -{ - if (gpio_is_pxa_type(gpio_type)) - return PXA_GPIO_TO_IRQ(gpio); - return -1; -} - -static inline int __pxa_irq_to_gpio(int irq) -{ - if (gpio_is_pxa_type(gpio_type)) - return irq - PXA_GPIO_TO_IRQ(0); - return -1; -} -#else -static inline int __pxa_gpio_to_irq(int gpio) { return -1; } -static inline int __pxa_irq_to_gpio(int irq) { return -1; } -#endif - -#ifdef CONFIG_ARCH_MMP -static inline int __mmp_gpio_to_irq(int gpio) -{ - if (gpio_is_mmp_type(gpio_type)) - return MMP_GPIO_TO_IRQ(gpio); - return -1; -} - -static inline int __mmp_irq_to_gpio(int irq) -{ - if (gpio_is_mmp_type(gpio_type)) - return irq - MMP_GPIO_TO_IRQ(0); - return -1; -} -#else -static inline int __mmp_gpio_to_irq(int gpio) { return -1; } -static inline int __mmp_irq_to_gpio(int irq) { return -1; } -#endif - static int pxa_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { - int gpio, ret; - - gpio = chip->base + offset; - ret = __pxa_gpio_to_irq(gpio); - if (ret >= 0) - return ret; - return __mmp_gpio_to_irq(gpio); + return chip->base + offset + irq_base; } int pxa_irq_to_gpio(int irq) { - int ret; - - ret = __pxa_irq_to_gpio(irq); - if (ret >= 0) - return ret; - return __mmp_irq_to_gpio(irq); + return irq - irq_base; } static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset) @@ -403,6 +357,9 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) struct pxa_gpio_chip *c; int loop, gpio, gpio_base, n; unsigned long gedr; + struct irq_chip *chip = irq_desc_get_chip(desc); + + chained_irq_enter(chip, desc); do { loop = 0; @@ -413,15 +370,15 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) gedr = gedr & c->irq_mask; writel_relaxed(gedr, c->regbase + GEDR_OFFSET); - n = find_first_bit(&gedr, BITS_PER_LONG); - while (n < BITS_PER_LONG) { + for_each_set_bit(n, &gedr, BITS_PER_LONG) { loop = 1; generic_handle_irq(gpio_to_irq(gpio_base + n)); - n = find_next_bit(&gedr, BITS_PER_LONG, n + 1); } } } while (loop); + + chained_irq_exit(chip, desc); } static void pxa_ack_muxed_gpio(struct irq_data *d) @@ -535,7 +492,7 @@ const struct irq_domain_ops pxa_irq_domain_ops = { static int __devinit pxa_gpio_probe_dt(struct platform_device *pdev) { - int ret, nr_banks, nr_gpios, irq_base; + int ret, nr_banks, nr_gpios; struct device_node *prev, *next, *np = pdev->dev.of_node; const struct of_device_id *of_id = of_match_device(pxa_gpio_dt_ids, &pdev->dev); @@ -590,10 +547,20 @@ static int __devinit pxa_gpio_probe(struct platform_device *pdev) int irq0 = 0, irq1 = 0, irq_mux, gpio_offset = 0; ret = pxa_gpio_probe_dt(pdev); - if (ret < 0) + if (ret < 0) { pxa_last_gpio = pxa_gpio_nums(); - else +#ifdef CONFIG_ARCH_PXA + if (gpio_is_pxa_type(gpio_type)) + irq_base = PXA_GPIO_TO_IRQ(0); +#endif +#ifdef CONFIG_ARCH_MMP + if (gpio_is_mmp_type(gpio_type)) + irq_base = MMP_GPIO_TO_IRQ(0); +#endif + } else { use_of = 1; + } + if (!pxa_last_gpio) return -EINVAL; @@ -620,15 +587,8 @@ static int __devinit pxa_gpio_probe(struct platform_device *pdev) iounmap(gpio_reg_base); return PTR_ERR(clk); } - ret = clk_prepare(clk); - if (ret) { - clk_put(clk); - iounmap(gpio_reg_base); - return ret; - } - ret = clk_enable(clk); + ret = clk_prepare_enable(clk); if (ret) { - clk_unprepare(clk); clk_put(clk); iounmap(gpio_reg_base); return ret; diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index ba126cc04073..a006f0db15af 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -938,6 +938,67 @@ static void __init samsung_gpiolib_add(struct samsung_gpio_chip *chip) s3c_gpiolib_track(chip); } +#if defined(CONFIG_PLAT_S3C24XX) && defined(CONFIG_OF) +static int s3c24xx_gpio_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, u32 *flags) +{ + unsigned int pin; + + if (WARN_ON(gc->of_gpio_n_cells < 3)) + return -EINVAL; + + if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells)) + return -EINVAL; + + if (gpiospec->args[0] > gc->ngpio) + return -EINVAL; + + pin = gc->base + gpiospec->args[0]; + + if (s3c_gpio_cfgpin(pin, S3C_GPIO_SFN(gpiospec->args[1]))) + pr_warn("gpio_xlate: failed to set pin function\n"); + if (s3c_gpio_setpull(pin, gpiospec->args[2] & 0xffff)) + pr_warn("gpio_xlate: failed to set pin pull up/down\n"); + + if (flags) + *flags = gpiospec->args[2] >> 16; + + return gpiospec->args[0]; +} + +static const struct of_device_id s3c24xx_gpio_dt_match[] __initdata = { + { .compatible = "samsung,s3c24xx-gpio", }, + {} +}; + +static __init void s3c24xx_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, + u64 base, u64 offset) +{ + struct gpio_chip *gc = &chip->chip; + u64 address; + + if (!of_have_populated_dt()) + return; + + address = chip->base ? base + ((u32)chip->base & 0xfff) : base + offset; + gc->of_node = of_find_matching_node_by_address(NULL, + s3c24xx_gpio_dt_match, address); + if (!gc->of_node) { + pr_info("gpio: device tree node not found for gpio controller" + " with base address %08llx\n", address); + return; + } + gc->of_gpio_n_cells = 3; + gc->of_xlate = s3c24xx_gpio_xlate; +} +#else +static __init void s3c24xx_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, + u64 base, u64 offset) +{ + return; +} +#endif /* defined(CONFIG_PLAT_S3C24XX) && defined(CONFIG_OF) */ + static void __init s3c24xx_gpiolib_add_chips(struct samsung_gpio_chip *chip, int nr_chips, void __iomem *base) { @@ -962,6 +1023,8 @@ static void __init s3c24xx_gpiolib_add_chips(struct samsung_gpio_chip *chip, gc->direction_output = samsung_gpiolib_2bit_output; samsung_gpiolib_add(chip); + + s3c24xx_gpiolib_attach_ofnode(chip, S3C24XX_PA_GPIO, i * 0x10); } } @@ -2734,6 +2797,27 @@ static __init void exynos4_gpiolib_init(void) int group = 0; void __iomem *gpx_base; +#ifdef CONFIG_PINCTRL_SAMSUNG + /* + * This gpio driver includes support for device tree support and + * there are platforms using it. In order to maintain + * compatibility with those platforms, and to allow non-dt + * Exynos4210 platforms to use this gpiolib support, a check + * is added to find out if there is a active pin-controller + * driver support available. If it is available, this gpiolib + * support is ignored and the gpiolib support available in + * pin-controller driver is used. This is a temporary check and + * will go away when all of the Exynos4210 platforms have + * switched to using device tree and the pin-ctrl driver. + */ + struct device_node *pctrl_np; + const char *pctrl_compat = "samsung,pinctrl-exynos4210"; + pctrl_np = of_find_compatible_node(NULL, NULL, pctrl_compat); + if (pctrl_np) + if (of_device_is_available(pctrl_np)) + return; +#endif + /* gpio part1 */ gpio_base1 = ioremap(EXYNOS4_PA_GPIO1, SZ_4K); if (gpio_base1 == NULL) { @@ -3131,46 +3215,6 @@ samsung_gpio_pull_t s3c_gpio_getpull(unsigned int pin) } EXPORT_SYMBOL(s3c_gpio_getpull); -/* gpiolib wrappers until these are totally eliminated */ - -void s3c2410_gpio_pullup(unsigned int pin, unsigned int to) -{ - int ret; - - WARN_ON(to); /* should be none of these left */ - - if (!to) { - /* if pull is enabled, try first with up, and if that - * fails, try using down */ - - ret = s3c_gpio_setpull(pin, S3C_GPIO_PULL_UP); - if (ret) - s3c_gpio_setpull(pin, S3C_GPIO_PULL_DOWN); - } else { - s3c_gpio_setpull(pin, S3C_GPIO_PULL_NONE); - } -} -EXPORT_SYMBOL(s3c2410_gpio_pullup); - -void s3c2410_gpio_setpin(unsigned int pin, unsigned int to) -{ - /* do this via gpiolib until all users removed */ - - gpio_request(pin, "temporary"); - gpio_set_value(pin, to); - gpio_free(pin); -} -EXPORT_SYMBOL(s3c2410_gpio_setpin); - -unsigned int s3c2410_gpio_getpin(unsigned int pin) -{ - struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); - unsigned long offs = pin - chip->chip.base; - - return __raw_readl(chip->base + 0x04) & (1 << offs); -} -EXPORT_SYMBOL(s3c2410_gpio_getpin); - #ifdef CONFIG_S5P_GPIO_DRVSTR s5p_gpio_drvstr_t s5p_gpio_get_drvstr(unsigned int pin) { diff --git a/drivers/gpio/gpio-sodaville.c b/drivers/gpio/gpio-sodaville.c index 9d9891f7a607..e25f73130b40 100644 --- a/drivers/gpio/gpio-sodaville.c +++ b/drivers/gpio/gpio-sodaville.c @@ -270,7 +270,7 @@ static void sdv_gpio_remove(struct pci_dev *pdev) kfree(sd); } -static struct pci_device_id sdv_gpio_pci_ids[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(sdv_gpio_pci_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_SDV_GPIO) }, { 0, }, }; diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c index a4f73534394e..eb3e215d2396 100644 --- a/drivers/gpio/gpio-sx150x.c +++ b/drivers/gpio/gpio-sx150x.c @@ -311,11 +311,9 @@ static int sx150x_gpio_to_irq(struct gpio_chip *gc, unsigned offset) static void sx150x_irq_mask(struct irq_data *d) { - struct irq_chip *ic = irq_data_get_irq_chip(d); - struct sx150x_chip *chip; + struct sx150x_chip *chip = irq_data_get_irq_chip_data(d); unsigned n; - chip = container_of(ic, struct sx150x_chip, irq_chip); n = d->irq - chip->irq_base; chip->irq_masked |= (1 << n); chip->irq_update = n; @@ -323,27 +321,22 @@ static void sx150x_irq_mask(struct irq_data *d) static void sx150x_irq_unmask(struct irq_data *d) { - struct irq_chip *ic = irq_data_get_irq_chip(d); - struct sx150x_chip *chip; + struct sx150x_chip *chip = irq_data_get_irq_chip_data(d); unsigned n; - chip = container_of(ic, struct sx150x_chip, irq_chip); n = d->irq - chip->irq_base; - chip->irq_masked &= ~(1 << n); chip->irq_update = n; } static int sx150x_irq_set_type(struct irq_data *d, unsigned int flow_type) { - struct irq_chip *ic = irq_data_get_irq_chip(d); - struct sx150x_chip *chip; + struct sx150x_chip *chip = irq_data_get_irq_chip_data(d); unsigned n, val = 0; if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) return -EINVAL; - chip = container_of(ic, struct sx150x_chip, irq_chip); n = d->irq - chip->irq_base; if (flow_type & IRQ_TYPE_EDGE_RISING) @@ -391,22 +384,16 @@ static irqreturn_t sx150x_irq_thread_fn(int irq, void *dev_id) static void sx150x_irq_bus_lock(struct irq_data *d) { - struct irq_chip *ic = irq_data_get_irq_chip(d); - struct sx150x_chip *chip; - - chip = container_of(ic, struct sx150x_chip, irq_chip); + struct sx150x_chip *chip = irq_data_get_irq_chip_data(d); mutex_lock(&chip->lock); } static void sx150x_irq_bus_sync_unlock(struct irq_data *d) { - struct irq_chip *ic = irq_data_get_irq_chip(d); - struct sx150x_chip *chip; + struct sx150x_chip *chip = irq_data_get_irq_chip_data(d); unsigned n; - chip = container_of(ic, struct sx150x_chip, irq_chip); - if (chip->irq_update == NO_UPDATE_PENDING) goto out; @@ -551,6 +538,7 @@ static int sx150x_install_irq_chip(struct sx150x_chip *chip, for (n = 0; n < chip->dev_cfg->ngpios; ++n) { irq = irq_base + n; + irq_set_chip_data(irq, chip); irq_set_chip_and_handler(irq, &chip->irq_chip, handle_edge_irq); irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index 2a82e8999a42..1e48317e70fb 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -11,7 +11,9 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/gpio.h> +#include <linux/of.h> #include <linux/irq.h> +#include <linux/irqdomain.h> #include <linux/interrupt.h> #include <linux/mfd/tc3589x.h> @@ -29,6 +31,7 @@ struct tc3589x_gpio { struct tc3589x *tc3589x; struct device *dev; struct mutex irq_lock; + struct irq_domain *domain; int irq_base; @@ -92,11 +95,28 @@ static int tc3589x_gpio_direction_input(struct gpio_chip *chip, return tc3589x_set_bits(tc3589x, reg, 1 << pos, 0); } +/** + * tc3589x_gpio_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ + * + * @tc3589x_gpio: tc3589x_gpio_irq controller to operate on. + * @irq: index of the interrupt requested in the chip IRQs + * + * Useful for drivers to request their own IRQs. + */ +static int tc3589x_gpio_irq_get_virq(struct tc3589x_gpio *tc3589x_gpio, + int irq) +{ + if (!tc3589x_gpio) + return -EINVAL; + + return irq_create_mapping(tc3589x_gpio->domain, irq); +} + static int tc3589x_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip); - return tc3589x_gpio->irq_base + offset; + return tc3589x_gpio_irq_get_virq(tc3589x_gpio, offset); } static struct gpio_chip template_chip = { @@ -113,7 +133,7 @@ static struct gpio_chip template_chip = { static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type) { struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); - int offset = d->irq - tc3589x_gpio->irq_base; + int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -175,7 +195,7 @@ static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d) static void tc3589x_gpio_irq_mask(struct irq_data *d) { struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); - int offset = d->irq - tc3589x_gpio->irq_base; + int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -185,7 +205,7 @@ static void tc3589x_gpio_irq_mask(struct irq_data *d) static void tc3589x_gpio_irq_unmask(struct irq_data *d) { struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); - int offset = d->irq - tc3589x_gpio->irq_base; + int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -222,8 +242,9 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) while (stat) { int bit = __ffs(stat); int line = i * 8 + bit; + int virq = tc3589x_gpio_irq_get_virq(tc3589x_gpio, line); - handle_nested_irq(tc3589x_gpio->irq_base + line); + handle_nested_irq(virq); stat &= ~(1 << bit); } @@ -233,51 +254,78 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) return IRQ_HANDLED; } -static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio) +static int tc3589x_gpio_irq_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hwirq) { - int base = tc3589x_gpio->irq_base; - int irq; + struct tc3589x *tc3589x_gpio = d->host_data; - for (irq = base; irq < base + tc3589x_gpio->chip.ngpio; irq++) { - irq_set_chip_data(irq, tc3589x_gpio); - irq_set_chip_and_handler(irq, &tc3589x_gpio_irq_chip, - handle_simple_irq); - irq_set_nested_thread(irq, 1); + irq_set_chip_data(virq, tc3589x_gpio); + irq_set_chip_and_handler(virq, &tc3589x_gpio_irq_chip, + handle_simple_irq); + irq_set_nested_thread(virq, 1); #ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); + set_irq_flags(virq, IRQF_VALID); #else - irq_set_noprobe(irq); + irq_set_noprobe(virq); #endif - } return 0; } -static void tc3589x_gpio_irq_remove(struct tc3589x_gpio *tc3589x_gpio) +static void tc3589x_gpio_irq_unmap(struct irq_domain *d, unsigned int virq) { - int base = tc3589x_gpio->irq_base; - int irq; - - for (irq = base; irq < base + tc3589x_gpio->chip.ngpio; irq++) { #ifdef CONFIG_ARM - set_irq_flags(irq, 0); + set_irq_flags(virq, 0); #endif - irq_set_chip_and_handler(irq, NULL, NULL); - irq_set_chip_data(irq, NULL); + irq_set_chip_and_handler(virq, NULL, NULL); + irq_set_chip_data(virq, NULL); +} + +static struct irq_domain_ops tc3589x_irq_ops = { + .map = tc3589x_gpio_irq_map, + .unmap = tc3589x_gpio_irq_unmap, + .xlate = irq_domain_xlate_twocell, +}; + +static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio, + struct device_node *np) +{ + 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 (!tc3589x_gpio->domain) { + dev_err(tc3589x_gpio->dev, "Failed to create irqdomain\n"); + return -ENOSYS; } + + return 0; } static int __devinit tc3589x_gpio_probe(struct platform_device *pdev) { struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent); struct tc3589x_gpio_platform_data *pdata; + struct device_node *np = pdev->dev.of_node; struct tc3589x_gpio *tc3589x_gpio; int ret; int irq; pdata = tc3589x->pdata->gpio; - if (!pdata) - return -ENODEV; + + if (!(pdata || np)) { + dev_err(&pdev->dev, "No platform data or Device Tree found\n"); + return -EINVAL; + } irq = platform_get_irq(pdev, 0); if (irq < 0) @@ -295,9 +343,14 @@ static int __devinit tc3589x_gpio_probe(struct platform_device *pdev) tc3589x_gpio->chip = template_chip; tc3589x_gpio->chip.ngpio = tc3589x->num_gpio; tc3589x_gpio->chip.dev = &pdev->dev; - tc3589x_gpio->chip.base = pdata->gpio_base; + tc3589x_gpio->chip.base = (pdata) ? pdata->gpio_base : -1; - tc3589x_gpio->irq_base = tc3589x->irq_base + TC3589x_INT_GPIO(0); +#ifdef CONFIG_OF_GPIO + tc3589x_gpio->chip.of_node = np; +#endif + + tc3589x_gpio->irq_base = tc3589x->irq_base ? + tc3589x->irq_base + TC3589x_INT_GPIO(0) : 0; /* Bring the GPIO module out of reset */ ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL, @@ -305,7 +358,7 @@ static int __devinit tc3589x_gpio_probe(struct platform_device *pdev) if (ret < 0) goto out_free; - ret = tc3589x_gpio_irq_init(tc3589x_gpio); + ret = tc3589x_gpio_irq_init(tc3589x_gpio, np); if (ret) goto out_free; @@ -313,7 +366,7 @@ static int __devinit tc3589x_gpio_probe(struct platform_device *pdev) "tc3589x-gpio", tc3589x_gpio); if (ret) { dev_err(&pdev->dev, "unable to get irq: %d\n", ret); - goto out_removeirq; + goto out_free; } ret = gpiochip_add(&tc3589x_gpio->chip); @@ -322,7 +375,7 @@ static int __devinit tc3589x_gpio_probe(struct platform_device *pdev) goto out_freeirq; } - if (pdata->setup) + if (pdata && pdata->setup) pdata->setup(tc3589x, tc3589x_gpio->chip.base); platform_set_drvdata(pdev, tc3589x_gpio); @@ -331,8 +384,6 @@ static int __devinit tc3589x_gpio_probe(struct platform_device *pdev) out_freeirq: free_irq(irq, tc3589x_gpio); -out_removeirq: - tc3589x_gpio_irq_remove(tc3589x_gpio); out_free: kfree(tc3589x_gpio); return ret; @@ -346,7 +397,7 @@ static int __devexit tc3589x_gpio_remove(struct platform_device *pdev) int irq = platform_get_irq(pdev, 0); int ret; - if (pdata->remove) + if (pdata && pdata->remove) pdata->remove(tc3589x, tc3589x_gpio->chip.base); ret = gpiochip_remove(&tc3589x_gpio->chip); @@ -357,7 +408,6 @@ static int __devexit tc3589x_gpio_remove(struct platform_device *pdev) } free_irq(irq, tc3589x_gpio); - tc3589x_gpio_irq_remove(tc3589x_gpio); platform_set_drvdata(pdev, NULL); kfree(tc3589x_gpio); diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index dc5184d57892..d982593d7563 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -30,9 +30,6 @@ #include <asm/mach/irq.h> -#include <mach/iomap.h> -#include <mach/suspend.h> - #define GPIO_BANK(x) ((x) >> 5) #define GPIO_PORT(x) (((x) >> 3) & 0x3) #define GPIO_BIT(x) ((x) & 0x7) diff --git a/drivers/gpio/gpio-tps65912.c b/drivers/gpio/gpio-tps65912.c index 79e66c002350..99106d1e2e55 100644 --- a/drivers/gpio/gpio-tps65912.c +++ b/drivers/gpio/gpio-tps65912.c @@ -70,7 +70,6 @@ static int tps65912_gpio_input(struct gpio_chip *gc, unsigned offset) return tps65912_clear_bits(tps65912, TPS65912_GPIO1 + offset, GPIO_CFG_MASK); - } static struct gpio_chip template_chip = { @@ -92,7 +91,8 @@ static int __devinit tps65912_gpio_probe(struct platform_device *pdev) struct tps65912_gpio_data *tps65912_gpio; int ret; - tps65912_gpio = kzalloc(sizeof(*tps65912_gpio), GFP_KERNEL); + tps65912_gpio = devm_kzalloc(&pdev->dev, sizeof(*tps65912_gpio), + GFP_KERNEL); if (tps65912_gpio == NULL) return -ENOMEM; @@ -105,28 +105,19 @@ static int __devinit tps65912_gpio_probe(struct platform_device *pdev) ret = gpiochip_add(&tps65912_gpio->gpio_chip); if (ret < 0) { dev_err(&pdev->dev, "Failed to register gpiochip, %d\n", ret); - goto err; + return ret; } platform_set_drvdata(pdev, tps65912_gpio); return ret; - -err: - kfree(tps65912_gpio); - return ret; } static int __devexit tps65912_gpio_remove(struct platform_device *pdev) { struct tps65912_gpio_data *tps65912_gpio = platform_get_drvdata(pdev); - int ret; - - ret = gpiochip_remove(&tps65912_gpio->gpio_chip); - if (ret == 0) - kfree(tps65912_gpio); - return ret; + return gpiochip_remove(&tps65912_gpio->gpio_chip); } static struct platform_driver tps65912_gpio_driver = { diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index 94256fe7bf36..c5f8ca233e1f 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -51,6 +51,7 @@ static struct gpio_chip twl_gpiochip; +static int twl4030_gpio_base; static int twl4030_gpio_irq_base; /* genirq interfaces are not available to modules */ @@ -395,6 +396,29 @@ static int __devinit gpio_twl4030_debounce(u32 debounce, u8 mmc_cd) static int gpio_twl4030_remove(struct platform_device *pdev); +static struct twl4030_gpio_platform_data *of_gpio_twl4030(struct device *dev) +{ + struct twl4030_gpio_platform_data *omap_twl_info; + + omap_twl_info = devm_kzalloc(dev, sizeof(*omap_twl_info), GFP_KERNEL); + if (!omap_twl_info) + return NULL; + + omap_twl_info->use_leds = of_property_read_bool(dev->of_node, + "ti,use-leds"); + + of_property_read_u32(dev->of_node, "ti,debounce", + &omap_twl_info->debounce); + of_property_read_u32(dev->of_node, "ti,mmc-cd", + (u32 *)&omap_twl_info->mmc_cd); + of_property_read_u32(dev->of_node, "ti,pullups", + &omap_twl_info->pullups); + of_property_read_u32(dev->of_node, "ti,pulldowns", + &omap_twl_info->pulldowns); + + return omap_twl_info; +} + static int __devinit gpio_twl4030_probe(struct platform_device *pdev) { struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; @@ -427,49 +451,57 @@ no_irqs: twl_gpiochip.ngpio = TWL4030_GPIO_MAX; twl_gpiochip.dev = &pdev->dev; - if (pdata) { - twl_gpiochip.base = pdata->gpio_base; + if (node) + pdata = of_gpio_twl4030(&pdev->dev); - /* - * NOTE: boards may waste power if they don't set pullups - * and pulldowns correctly ... default for non-ULPI pins is - * pulldown, and some other pins may have external pullups - * or pulldowns. Careful! - */ - ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns); - if (ret) - dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n", - pdata->pullups, pdata->pulldowns, - ret); - - ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd); - if (ret) - dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n", - pdata->debounce, pdata->mmc_cd, - ret); - - /* - * NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE, - * is (still) clear if use_leds is set. - */ - if (pdata->use_leds) - twl_gpiochip.ngpio += 2; + if (pdata == NULL) { + dev_err(&pdev->dev, "Platform data is missing\n"); + return -ENXIO; } + /* + * NOTE: boards may waste power if they don't set pullups + * and pulldowns correctly ... default for non-ULPI pins is + * pulldown, and some other pins may have external pullups + * or pulldowns. Careful! + */ + ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns); + if (ret) + dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n", + pdata->pullups, pdata->pulldowns, ret); + + ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd); + if (ret) + dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n", + pdata->debounce, pdata->mmc_cd, ret); + + /* + * NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE, + * is (still) clear if use_leds is set. + */ + if (pdata->use_leds) + twl_gpiochip.ngpio += 2; + ret = gpiochip_add(&twl_gpiochip); if (ret < 0) { dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret); twl_gpiochip.ngpio = 0; gpio_twl4030_remove(pdev); - } else if (pdata && pdata->setup) { + goto out; + } + + twl4030_gpio_base = twl_gpiochip.base; + + if (pdata && pdata->setup) { int status; status = pdata->setup(&pdev->dev, - pdata->gpio_base, TWL4030_GPIO_MAX); + twl4030_gpio_base, TWL4030_GPIO_MAX); if (status) dev_dbg(&pdev->dev, "setup --> %d\n", status); } +out: return ret; } @@ -481,7 +513,7 @@ static int gpio_twl4030_remove(struct platform_device *pdev) if (pdata && pdata->teardown) { status = pdata->teardown(&pdev->dev, - pdata->gpio_base, TWL4030_GPIO_MAX); + twl4030_gpio_base, TWL4030_GPIO_MAX); if (status) { dev_dbg(&pdev->dev, "teardown --> %d\n", status); return status; diff --git a/drivers/gpio/gpio-vt8500.c b/drivers/gpio/gpio-vt8500.c new file mode 100644 index 000000000000..bcd8e4aa7c7d --- /dev/null +++ b/drivers/gpio/gpio-vt8500.c @@ -0,0 +1,316 @@ +/* drivers/gpio/gpio-vt8500.c + * + * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz> + * Based on arch/arm/mach-vt8500/gpio.c: + * - Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/module.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/bitops.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/of_device.h> + +/* + We handle GPIOs by bank, each bank containing up to 32 GPIOs covered + by one set of registers (although not all may be valid). + + Because different SoC's have different register offsets, we pass the + register offsets as data in vt8500_gpio_dt_ids[]. + + A value of NO_REG is used to indicate that this register is not + supported. Only used for ->en at the moment. +*/ + +#define NO_REG 0xFFFF + +/* + * struct vt8500_gpio_bank_regoffsets + * @en: offset to enable register of the bank + * @dir: offset to direction register of the bank + * @data_out: offset to the data out register of the bank + * @data_in: offset to the data in register of the bank + * @ngpio: highest valid pin in this bank + */ + +struct vt8500_gpio_bank_regoffsets { + unsigned int en; + unsigned int dir; + unsigned int data_out; + unsigned int data_in; + unsigned char ngpio; +}; + +struct vt8500_gpio_data { + unsigned int num_banks; + struct vt8500_gpio_bank_regoffsets banks[]; +}; + +#define VT8500_BANK(__en, __dir, __out, __in, __ngpio) \ +{ \ + .en = __en, \ + .dir = __dir, \ + .data_out = __out, \ + .data_in = __in, \ + .ngpio = __ngpio, \ +} + +static struct vt8500_gpio_data vt8500_data = { + .num_banks = 7, + .banks = { + VT8500_BANK(0x00, 0x20, 0x40, 0x60, 26), + VT8500_BANK(0x04, 0x24, 0x44, 0x64, 28), + VT8500_BANK(0x08, 0x28, 0x48, 0x68, 31), + VT8500_BANK(0x0C, 0x2C, 0x4C, 0x6C, 19), + VT8500_BANK(0x10, 0x30, 0x50, 0x70, 19), + VT8500_BANK(0x14, 0x34, 0x54, 0x74, 23), + VT8500_BANK(NO_REG, 0x3C, 0x5C, 0x7C, 9), + }, +}; + +static struct vt8500_gpio_data wm8505_data = { + .num_banks = 10, + .banks = { + VT8500_BANK(0x40, 0x68, 0x90, 0xB8, 8), + VT8500_BANK(0x44, 0x6C, 0x94, 0xBC, 32), + VT8500_BANK(0x48, 0x70, 0x98, 0xC0, 6), + VT8500_BANK(0x4C, 0x74, 0x9C, 0xC4, 16), + VT8500_BANK(0x50, 0x78, 0xA0, 0xC8, 25), + VT8500_BANK(0x54, 0x7C, 0xA4, 0xCC, 5), + VT8500_BANK(0x58, 0x80, 0xA8, 0xD0, 5), + VT8500_BANK(0x5C, 0x84, 0xAC, 0xD4, 12), + VT8500_BANK(0x60, 0x88, 0xB0, 0xD8, 16), + VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22), + }, +}; + +/* + * No information about which bits are valid so we just make + * them all available until its figured out. + */ +static struct vt8500_gpio_data wm8650_data = { + .num_banks = 9, + .banks = { + VT8500_BANK(0x40, 0x80, 0xC0, 0x00, 32), + VT8500_BANK(0x44, 0x84, 0xC4, 0x04, 32), + VT8500_BANK(0x48, 0x88, 0xC8, 0x08, 32), + VT8500_BANK(0x4C, 0x8C, 0xCC, 0x0C, 32), + VT8500_BANK(0x50, 0x90, 0xD0, 0x10, 32), + VT8500_BANK(0x54, 0x94, 0xD4, 0x14, 32), + VT8500_BANK(0x58, 0x98, 0xD8, 0x18, 32), + VT8500_BANK(0x5C, 0x9C, 0xDC, 0x1C, 32), + VT8500_BANK(0x7C, 0xBC, 0xFC, 0x3C, 32), + }, +}; + +struct vt8500_gpio_chip { + struct gpio_chip chip; + + const struct vt8500_gpio_bank_regoffsets *regs; + void __iomem *base; +}; + + +#define to_vt8500(__chip) container_of(__chip, struct vt8500_gpio_chip, chip) + +static int vt8500_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + u32 val; + struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); + + if (vt8500_chip->regs->en == NO_REG) + return 0; + + val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->en); + val |= BIT(offset); + writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->en); + + return 0; +} + +static void vt8500_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); + u32 val; + + if (vt8500_chip->regs->en == NO_REG) + return; + + val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->en); + val &= ~BIT(offset); + writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->en); +} + +static int vt8500_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); + + u32 val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->dir); + val &= ~BIT(offset); + writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->dir); + + return 0; +} + +static int vt8500_gpio_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); + + u32 val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->dir); + val |= BIT(offset); + writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->dir); + + if (value) { + val = readl_relaxed(vt8500_chip->base + + vt8500_chip->regs->data_out); + val |= BIT(offset); + writel_relaxed(val, vt8500_chip->base + + vt8500_chip->regs->data_out); + } + return 0; +} + +static int vt8500_gpio_get_value(struct gpio_chip *chip, unsigned offset) +{ + struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); + + return (readl_relaxed(vt8500_chip->base + vt8500_chip->regs->data_in) >> + offset) & 1; +} + +static void vt8500_gpio_set_value(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); + + u32 val = readl_relaxed(vt8500_chip->base + + vt8500_chip->regs->data_out); + if (value) + val |= BIT(offset); + else + val &= ~BIT(offset); + + writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->data_out); +} + +static int vt8500_of_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, u32 *flags) +{ + /* bank if specificed in gpiospec->args[0] */ + if (flags) + *flags = gpiospec->args[2]; + + return gpiospec->args[1]; +} + +static int vt8500_add_chips(struct platform_device *pdev, void __iomem *base, + const struct vt8500_gpio_data *data) +{ + struct vt8500_gpio_chip *vtchip; + struct gpio_chip *chip; + int i; + int pin_cnt = 0; + + vtchip = devm_kzalloc(&pdev->dev, + sizeof(struct vt8500_gpio_chip) * data->num_banks, + GFP_KERNEL); + if (!vtchip) { + pr_err("%s: failed to allocate chip memory\n", __func__); + return -ENOMEM; + } + + for (i = 0; i < data->num_banks; i++) { + vtchip[i].base = base; + vtchip[i].regs = &data->banks[i]; + + chip = &vtchip[i].chip; + + chip->of_xlate = vt8500_of_xlate; + chip->of_gpio_n_cells = 3; + chip->of_node = pdev->dev.of_node; + + chip->request = vt8500_gpio_request; + chip->free = vt8500_gpio_free; + chip->direction_input = vt8500_gpio_direction_input; + chip->direction_output = vt8500_gpio_direction_output; + chip->get = vt8500_gpio_get_value; + chip->set = vt8500_gpio_set_value; + chip->can_sleep = 0; + chip->base = pin_cnt; + chip->ngpio = data->banks[i].ngpio; + + pin_cnt += data->banks[i].ngpio; + + gpiochip_add(chip); + } + return 0; +} + +static struct of_device_id vt8500_gpio_dt_ids[] = { + { .compatible = "via,vt8500-gpio", .data = &vt8500_data, }, + { .compatible = "wm,wm8505-gpio", .data = &wm8505_data, }, + { .compatible = "wm,wm8650-gpio", .data = &wm8650_data, }, + { /* Sentinel */ }, +}; + +static int __devinit vt8500_gpio_probe(struct platform_device *pdev) +{ + void __iomem *gpio_base; + struct device_node *np; + const struct of_device_id *of_id = + of_match_device(vt8500_gpio_dt_ids, &pdev->dev); + + if (!of_id) { + dev_err(&pdev->dev, "Failed to find gpio controller\n"); + return -ENODEV; + } + + np = pdev->dev.of_node; + if (!np) { + dev_err(&pdev->dev, "Missing GPIO description in devicetree\n"); + return -EFAULT; + } + + gpio_base = of_iomap(np, 0); + if (!gpio_base) { + dev_err(&pdev->dev, "Unable to map GPIO registers\n"); + of_node_put(np); + return -ENOMEM; + } + + vt8500_add_chips(pdev, gpio_base, of_id->data); + + return 0; +} + +static struct platform_driver vt8500_gpio_driver = { + .probe = vt8500_gpio_probe, + .driver = { + .name = "vt8500-gpio", + .owner = THIS_MODULE, + .of_match_table = vt8500_gpio_dt_ids, + }, +}; + +module_platform_driver(vt8500_gpio_driver); + +MODULE_DESCRIPTION("VT8500 GPIO Driver"); +MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, vt8500_gpio_dt_ids); diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c index e56a2165641c..b6eda35089d5 100644 --- a/drivers/gpio/gpio-wm831x.c +++ b/drivers/gpio/gpio-wm831x.c @@ -250,7 +250,8 @@ static int __devinit wm831x_gpio_probe(struct platform_device *pdev) struct wm831x_gpio *wm831x_gpio; int ret; - wm831x_gpio = kzalloc(sizeof(*wm831x_gpio), GFP_KERNEL); + wm831x_gpio = devm_kzalloc(&pdev->dev, sizeof(*wm831x_gpio), + GFP_KERNEL); if (wm831x_gpio == NULL) return -ENOMEM; @@ -265,30 +266,20 @@ static int __devinit wm831x_gpio_probe(struct platform_device *pdev) ret = gpiochip_add(&wm831x_gpio->gpio_chip); if (ret < 0) { - dev_err(&pdev->dev, "Could not register gpiochip, %d\n", - ret); - goto err; + dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); + return ret; } platform_set_drvdata(pdev, wm831x_gpio); return ret; - -err: - kfree(wm831x_gpio); - return ret; } static int __devexit wm831x_gpio_remove(struct platform_device *pdev) { struct wm831x_gpio *wm831x_gpio = platform_get_drvdata(pdev); - int ret; - - ret = gpiochip_remove(&wm831x_gpio->gpio_chip); - if (ret == 0) - kfree(wm831x_gpio); - return ret; + return gpiochip_remove(&wm831x_gpio->gpio_chip); } static struct platform_driver wm831x_gpio_driver = { diff --git a/drivers/gpio/gpio-wm8350.c b/drivers/gpio/gpio-wm8350.c index a06af5154838..fb4293889392 100644 --- a/drivers/gpio/gpio-wm8350.c +++ b/drivers/gpio/gpio-wm8350.c @@ -116,7 +116,8 @@ static int __devinit wm8350_gpio_probe(struct platform_device *pdev) struct wm8350_gpio_data *wm8350_gpio; int ret; - wm8350_gpio = kzalloc(sizeof(*wm8350_gpio), GFP_KERNEL); + wm8350_gpio = devm_kzalloc(&pdev->dev, sizeof(*wm8350_gpio), + GFP_KERNEL); if (wm8350_gpio == NULL) return -ENOMEM; @@ -131,30 +132,20 @@ static int __devinit wm8350_gpio_probe(struct platform_device *pdev) ret = gpiochip_add(&wm8350_gpio->gpio_chip); if (ret < 0) { - dev_err(&pdev->dev, "Could not register gpiochip, %d\n", - ret); - goto err; + dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); + return ret; } platform_set_drvdata(pdev, wm8350_gpio); return ret; - -err: - kfree(wm8350_gpio); - return ret; } static int __devexit wm8350_gpio_remove(struct platform_device *pdev) { struct wm8350_gpio_data *wm8350_gpio = platform_get_drvdata(pdev); - int ret; - - ret = gpiochip_remove(&wm8350_gpio->gpio_chip); - if (ret == 0) - kfree(wm8350_gpio); - return ret; + return gpiochip_remove(&wm8350_gpio->gpio_chip); } static struct platform_driver wm8350_gpio_driver = { diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index de0213c9d11c..5d6c71edc739 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1773,56 +1773,102 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) } } -static int gpiolib_show(struct seq_file *s, void *unused) +static void *gpiolib_seq_start(struct seq_file *s, loff_t *pos) { - struct gpio_chip *chip = NULL; - unsigned gpio; - int started = 0; + struct gpio_chip *chip = NULL; + unsigned int gpio; + void *ret = NULL; + loff_t index = 0; /* REVISIT this isn't locked against gpio_chip removal ... */ for (gpio = 0; gpio_is_valid(gpio); gpio++) { - struct device *dev; - - if (chip == gpio_desc[gpio].chip) + if (gpio_desc[gpio].chip == chip) continue; + chip = gpio_desc[gpio].chip; if (!chip) continue; - seq_printf(s, "%sGPIOs %d-%d", - started ? "\n" : "", - chip->base, chip->base + chip->ngpio - 1); - dev = chip->dev; - if (dev) - seq_printf(s, ", %s/%s", - dev->bus ? dev->bus->name : "no-bus", - dev_name(dev)); - if (chip->label) - seq_printf(s, ", %s", chip->label); - if (chip->can_sleep) - seq_printf(s, ", can sleep"); - seq_printf(s, ":\n"); - - started = 1; - if (chip->dbg_show) - chip->dbg_show(s, chip); - else - gpiolib_dbg_show(s, chip); + if (index++ >= *pos) { + ret = chip; + break; + } } + + s->private = ""; + + return ret; +} + +static void *gpiolib_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + struct gpio_chip *chip = v; + unsigned int gpio; + void *ret = NULL; + + /* skip GPIOs provided by the current chip */ + for (gpio = chip->base + chip->ngpio; gpio_is_valid(gpio); gpio++) { + chip = gpio_desc[gpio].chip; + if (chip) { + ret = chip; + break; + } + } + + s->private = "\n"; + ++*pos; + + return ret; +} + +static void gpiolib_seq_stop(struct seq_file *s, void *v) +{ +} + +static int gpiolib_seq_show(struct seq_file *s, void *v) +{ + struct gpio_chip *chip = v; + struct device *dev; + + seq_printf(s, "%sGPIOs %d-%d", (char *)s->private, + chip->base, chip->base + chip->ngpio - 1); + dev = chip->dev; + if (dev) + seq_printf(s, ", %s/%s", dev->bus ? dev->bus->name : "no-bus", + dev_name(dev)); + if (chip->label) + seq_printf(s, ", %s", chip->label); + if (chip->can_sleep) + seq_printf(s, ", can sleep"); + seq_printf(s, ":\n"); + + if (chip->dbg_show) + chip->dbg_show(s, chip); + else + gpiolib_dbg_show(s, chip); + return 0; } +static const struct seq_operations gpiolib_seq_ops = { + .start = gpiolib_seq_start, + .next = gpiolib_seq_next, + .stop = gpiolib_seq_stop, + .show = gpiolib_seq_show, +}; + static int gpiolib_open(struct inode *inode, struct file *file) { - return single_open(file, gpiolib_show, NULL); + return seq_open(file, &gpiolib_seq_ops); } static const struct file_operations gpiolib_operations = { + .owner = THIS_MODULE, .open = gpiolib_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; static int __init gpiolib_debugfs_init(void) |