diff options
Diffstat (limited to 'drivers/gpio')
44 files changed, 2495 insertions, 589 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index c4067d0141f..8382dc83292 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. @@ -136,7 +136,7 @@ config GPIO_MPC8XXX config GPIO_MSM_V1 tristate "Qualcomm MSM GPIO v1" - depends on GPIOLIB && ARCH_MSM + depends on GPIOLIB && ARCH_MSM && (ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50) help Say yes here to support the GPIO interface on ARM v6 based Qualcomm MSM chips. Most of the pins on the MSM can be @@ -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 @@ -253,6 +259,12 @@ config GPIO_GE_FPGA comment "I2C GPIO expanders:" +config GPIO_ARIZONA + tristate "Wolfson Microelectronics Arizona class devices" + depends on MFD_ARIZONA + help + Support for GPIOs on Wolfson Arizona class devices. + config GPIO_MAX7300 tristate "Maxim MAX7300 GPIO expander" depends on I2C @@ -288,7 +300,7 @@ config GPIO_MAX732X_IRQ config GPIO_MC9S08DZ60 bool "MX35 3DS BOARD MC9S08DZ60 GPIO functions" - depends on I2C && MACH_MX35_3DS + depends on I2C=y && MACH_MX35_3DS help Select this to enable the MC9S08DZ60 GPIO driver @@ -318,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. @@ -438,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 @@ -466,6 +490,18 @@ config GPIO_BT8XX If unsure, say N. +config GPIO_AMD8111 + tristate "AMD 8111 GPIO driver" + depends on PCI + help + The AMD 8111 south bridge contains 32 GPIO pins which can be used. + + Note, that usually system firmware/ACPI handles GPIO pins on their + own and users might easily break their systems with uncarefull usage + of this driver! + + If unsure, say N + config GPIO_LANGWELL bool "Intel Langwell/Penwell GPIO support" depends on PCI && X86 @@ -579,6 +615,13 @@ config GPIO_AB8500 help Select this to enable the AB8500 IC GPIO driver +config GPIO_TPS6586X + bool "TPS6586X GPIO" + depends on MFD_TPS6586X + help + Select this option to enable GPIO driver for the TPS6586X + chip family. + config GPIO_TPS65910 bool "TPS65910 GPIO" depends on MFD_TPS65910 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 0f55662002c..0ffaa8423e8 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -10,8 +10,11 @@ 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 +obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o @@ -61,11 +64,13 @@ obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o obj-$(CONFIG_ARCH_TEGRA) += gpio-tegra.o obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o obj-$(CONFIG_ARCH_DAVINCI_TNETV107X) += gpio-tnetv107x.o +obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o 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/devres.c b/drivers/gpio/devres.c index 9e9947cb86a..1077754f828 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c @@ -98,6 +98,7 @@ int devm_gpio_request_one(struct device *dev, unsigned gpio, return 0; } +EXPORT_SYMBOL(devm_gpio_request_one); /** * devm_gpio_free - free an interrupt diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index a31ad6f5d91..ed3e55161bd 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 00000000000..3df88336415 --- /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 ae5d7f12ce6..eeedad42913 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-amd8111.c b/drivers/gpio/gpio-amd8111.c new file mode 100644 index 00000000000..710fafcdd1b --- /dev/null +++ b/drivers/gpio/gpio-amd8111.c @@ -0,0 +1,246 @@ +/* + * GPIO driver for AMD 8111 south bridges + * + * Copyright (c) 2012 Dmitry Eremin-Solenikov + * + * Based on the AMD RNG driver: + * Copyright 2005 (c) MontaVista Software, Inc. + * with the majority of the code coming from: + * + * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG) + * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com> + * + * derived from + * + * Hardware driver for the AMD 768 Random Number Generator (RNG) + * (c) Copyright 2001 Red Hat Inc + * + * derived from + * + * Hardware driver for Intel i810 Random Number Generator (RNG) + * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com> + * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/gpio.h> +#include <linux/pci.h> +#include <linux/spinlock.h> + +#define PMBASE_OFFSET 0xb0 +#define PMBASE_SIZE 0x30 + +#define AMD_REG_GPIO(i) (0x10 + (i)) + +#define AMD_GPIO_LTCH_STS 0x40 /* Latch status, w1 */ +#define AMD_GPIO_RTIN 0x20 /* Real Time in, ro */ +#define AMD_GPIO_DEBOUNCE 0x10 /* Debounce, rw */ +#define AMD_GPIO_MODE_MASK 0x0c /* Pin Mode Select, rw */ +#define AMD_GPIO_MODE_IN 0x00 +#define AMD_GPIO_MODE_OUT 0x04 +/* Enable alternative (e.g. clkout, IRQ, etc) function of the pin */ +#define AMD_GPIO_MODE_ALTFN 0x08 /* Or 0x09 */ +#define AMD_GPIO_X_MASK 0x03 /* In/Out specific, rw */ +#define AMD_GPIO_X_IN_ACTIVEHI 0x01 /* Active High */ +#define AMD_GPIO_X_IN_LATCH 0x02 /* Latched version is selected */ +#define AMD_GPIO_X_OUT_LOW 0x00 +#define AMD_GPIO_X_OUT_HI 0x01 +#define AMD_GPIO_X_OUT_CLK0 0x02 +#define AMD_GPIO_X_OUT_CLK1 0x03 + +/* + * Data for PCI driver interface + * + * This data only exists for exporting the supported + * PCI ids via MODULE_DEVICE_TABLE. We do not actually + * register a pci_driver, because someone else might one day + * want to register another driver on the same PCI id. + */ +static DEFINE_PCI_DEVICE_TABLE(pci_tbl) = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS), 0 }, + { 0, }, /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci, pci_tbl); + +struct amd_gpio { + struct gpio_chip chip; + u32 pmbase; + void __iomem *pm; + struct pci_dev *pdev; + spinlock_t lock; /* guards hw registers and orig table */ + u8 orig[32]; +}; + +#define to_agp(chip) container_of(chip, struct amd_gpio, chip) + +static int amd_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + struct amd_gpio *agp = to_agp(chip); + + agp->orig[offset] = ioread8(agp->pm + AMD_REG_GPIO(offset)) & + (AMD_GPIO_DEBOUNCE | AMD_GPIO_MODE_MASK | AMD_GPIO_X_MASK); + + dev_dbg(&agp->pdev->dev, "Requested gpio %d, data %x\n", offset, agp->orig[offset]); + + return 0; +} + +static void amd_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + struct amd_gpio *agp = to_agp(chip); + + dev_dbg(&agp->pdev->dev, "Freed gpio %d, data %x\n", offset, agp->orig[offset]); + + iowrite8(agp->orig[offset], agp->pm + AMD_REG_GPIO(offset)); +} + +static void amd_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct amd_gpio *agp = to_agp(chip); + u8 temp; + unsigned long flags; + + spin_lock_irqsave(&agp->lock, flags); + temp = ioread8(agp->pm + AMD_REG_GPIO(offset)); + temp = (temp & AMD_GPIO_DEBOUNCE) | AMD_GPIO_MODE_OUT | (value ? AMD_GPIO_X_OUT_HI : AMD_GPIO_X_OUT_LOW); + iowrite8(temp, agp->pm + AMD_REG_GPIO(offset)); + spin_unlock_irqrestore(&agp->lock, flags); + + dev_dbg(&agp->pdev->dev, "Setting gpio %d, value %d, reg=%02x\n", offset, !!value, temp); +} + +static int amd_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct amd_gpio *agp = to_agp(chip); + u8 temp; + + temp = ioread8(agp->pm + AMD_REG_GPIO(offset)); + + dev_dbg(&agp->pdev->dev, "Getting gpio %d, reg=%02x\n", offset, temp); + + return (temp & AMD_GPIO_RTIN) ? 1 : 0; +} + +static int amd_gpio_dirout(struct gpio_chip *chip, unsigned offset, int value) +{ + struct amd_gpio *agp = to_agp(chip); + u8 temp; + unsigned long flags; + + spin_lock_irqsave(&agp->lock, flags); + temp = ioread8(agp->pm + AMD_REG_GPIO(offset)); + temp = (temp & AMD_GPIO_DEBOUNCE) | AMD_GPIO_MODE_OUT | (value ? AMD_GPIO_X_OUT_HI : AMD_GPIO_X_OUT_LOW); + iowrite8(temp, agp->pm + AMD_REG_GPIO(offset)); + spin_unlock_irqrestore(&agp->lock, flags); + + dev_dbg(&agp->pdev->dev, "Dirout gpio %d, value %d, reg=%02x\n", offset, !!value, temp); + + return 0; +} + +static int amd_gpio_dirin(struct gpio_chip *chip, unsigned offset) +{ + struct amd_gpio *agp = to_agp(chip); + u8 temp; + unsigned long flags; + + spin_lock_irqsave(&agp->lock, flags); + temp = ioread8(agp->pm + AMD_REG_GPIO(offset)); + temp = (temp & AMD_GPIO_DEBOUNCE) | AMD_GPIO_MODE_IN; + iowrite8(temp, agp->pm + AMD_REG_GPIO(offset)); + spin_unlock_irqrestore(&agp->lock, flags); + + dev_dbg(&agp->pdev->dev, "Dirin gpio %d, reg=%02x\n", offset, temp); + + return 0; +} + +static struct amd_gpio gp = { + .chip = { + .label = "AMD GPIO", + .owner = THIS_MODULE, + .base = -1, + .ngpio = 32, + .request = amd_gpio_request, + .free = amd_gpio_free, + .set = amd_gpio_set, + .get = amd_gpio_get, + .direction_output = amd_gpio_dirout, + .direction_input = amd_gpio_dirin, + }, +}; + +static int __init amd_gpio_init(void) +{ + int err = -ENODEV; + struct pci_dev *pdev = NULL; + const struct pci_device_id *ent; + + + /* We look for our device - AMD South Bridge + * I don't know about a system with two such bridges, + * so we can assume that there is max. one device. + * + * We can't use plain pci_driver mechanism, + * as the device is really a multiple function device, + * main driver that binds to the pci_device is an smbus + * driver and have to find & bind to the device this way. + */ + for_each_pci_dev(pdev) { + ent = pci_match_id(pci_tbl, pdev); + if (ent) + goto found; + } + /* Device not found. */ + goto out; + +found: + err = pci_read_config_dword(pdev, 0x58, &gp.pmbase); + if (err) + goto out; + err = -EIO; + gp.pmbase &= 0x0000FF00; + if (gp.pmbase == 0) + goto out; + if (!request_region(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE, "AMD GPIO")) { + dev_err(&pdev->dev, "AMD GPIO region 0x%x already in use!\n", + gp.pmbase + PMBASE_OFFSET); + err = -EBUSY; + goto out; + } + gp.pm = ioport_map(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE); + gp.pdev = pdev; + gp.chip.dev = &pdev->dev; + + spin_lock_init(&gp.lock); + + printk(KERN_INFO "AMD-8111 GPIO detected\n"); + err = gpiochip_add(&gp.chip); + if (err) { + printk(KERN_ERR "GPIO registering failed (%d)\n", + err); + release_region(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE); + goto out; + } +out: + return err; +} + +static void __exit amd_gpio_exit(void) +{ + int err = gpiochip_remove(&gp.chip); + WARN_ON(err); + ioport_unmap(gp.pm); + release_region(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE); +} + +module_init(amd_gpio_init); +module_exit(amd_gpio_exit); + +MODULE_AUTHOR("The Linux Kernel team"); +MODULE_DESCRIPTION("GPIO driver for AMD chipsets"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c new file mode 100644 index 00000000000..8740d2eb06f --- /dev/null +++ b/drivers/gpio/gpio-arizona.c @@ -0,0 +1,163 @@ +/* + * gpiolib support for Wolfson Arizona class devices + * + * Copyright 2012 Wolfson Microelectronics PLC. + * + * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/seq_file.h> + +#include <linux/mfd/arizona/core.h> +#include <linux/mfd/arizona/pdata.h> +#include <linux/mfd/arizona/registers.h> + +struct arizona_gpio { + struct arizona *arizona; + struct gpio_chip gpio_chip; +}; + +static inline struct arizona_gpio *to_arizona_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct arizona_gpio, gpio_chip); +} + +static int arizona_gpio_direction_in(struct gpio_chip *chip, unsigned offset) +{ + struct arizona_gpio *arizona_gpio = to_arizona_gpio(chip); + struct arizona *arizona = arizona_gpio->arizona; + + return regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset, + ARIZONA_GPN_DIR, ARIZONA_GPN_DIR); +} + +static int arizona_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct arizona_gpio *arizona_gpio = to_arizona_gpio(chip); + struct arizona *arizona = arizona_gpio->arizona; + unsigned int val; + int ret; + + ret = regmap_read(arizona->regmap, ARIZONA_GPIO1_CTRL + offset, &val); + if (ret < 0) + return ret; + + if (val & ARIZONA_GPN_LVL) + return 1; + else + return 0; +} + +static int arizona_gpio_direction_out(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct arizona_gpio *arizona_gpio = to_arizona_gpio(chip); + struct arizona *arizona = arizona_gpio->arizona; + + if (value) + value = ARIZONA_GPN_LVL; + + return regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset, + ARIZONA_GPN_DIR | ARIZONA_GPN_LVL, value); +} + +static void arizona_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct arizona_gpio *arizona_gpio = to_arizona_gpio(chip); + struct arizona *arizona = arizona_gpio->arizona; + + if (value) + value = ARIZONA_GPN_LVL; + + regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset, + ARIZONA_GPN_LVL, value); +} + +static struct gpio_chip template_chip = { + .label = "arizona", + .owner = THIS_MODULE, + .direction_input = arizona_gpio_direction_in, + .get = arizona_gpio_get, + .direction_output = arizona_gpio_direction_out, + .set = arizona_gpio_set, + .can_sleep = 1, +}; + +static int __devinit arizona_gpio_probe(struct platform_device *pdev) +{ + struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); + struct arizona_pdata *pdata = arizona->dev->platform_data; + struct arizona_gpio *arizona_gpio; + int ret; + + arizona_gpio = devm_kzalloc(&pdev->dev, sizeof(*arizona_gpio), + GFP_KERNEL); + if (arizona_gpio == NULL) + return -ENOMEM; + + arizona_gpio->arizona = arizona; + arizona_gpio->gpio_chip = template_chip; + arizona_gpio->gpio_chip.dev = &pdev->dev; + + switch (arizona->type) { + case WM5102: + case WM5110: + arizona_gpio->gpio_chip.ngpio = 5; + break; + default: + dev_err(&pdev->dev, "Unknown chip variant %d\n", + arizona->type); + return -EINVAL; + } + + if (pdata && pdata->gpio_base) + arizona_gpio->gpio_chip.base = pdata->gpio_base; + else + arizona_gpio->gpio_chip.base = -1; + + ret = gpiochip_add(&arizona_gpio->gpio_chip); + if (ret < 0) { + dev_err(&pdev->dev, "Could not register gpiochip, %d\n", + ret); + goto err; + } + + platform_set_drvdata(pdev, arizona_gpio); + + return ret; + +err: + return ret; +} + +static int __devexit arizona_gpio_remove(struct platform_device *pdev) +{ + struct arizona_gpio *arizona_gpio = platform_get_drvdata(pdev); + + return gpiochip_remove(&arizona_gpio->gpio_chip); +} + +static struct platform_driver arizona_gpio_driver = { + .driver.name = "arizona-gpio", + .driver.owner = THIS_MODULE, + .probe = arizona_gpio_probe, + .remove = __devexit_p(arizona_gpio_remove), +}; + +module_platform_driver(arizona_gpio_driver); + +MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); +MODULE_DESCRIPTION("GPIO interface for Arizona devices"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:arizona-gpio"); diff --git a/drivers/gpio/gpio-bt8xx.c b/drivers/gpio/gpio-bt8xx.c index e4cc7eb69bb..aba97abda77 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 56dd047d584..24b8c297404 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 3d000169285..17df6db5dca 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 150d9768811..efb4c2d0d13 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; @@ -247,9 +241,9 @@ static int __devinit em_gio_irq_domain_init(struct em_gio_priv *p) p->irq_base = irq_alloc_descs(pdata->irq_base, 0, pdata->number_of_pins, numa_node_id()); - if (IS_ERR_VALUE(p->irq_base)) { + if (p->irq_base < 0) { dev_err(&pdev->dev, "cannot get irq_desc\n"); - return -ENXIO; + return p->irq_base; } pr_debug("gio: hw base = %d, nr = %d, sw base = %d\n", pdata->gpio_base, pdata->number_of_pins, p->irq_base); @@ -266,7 +260,7 @@ static int __devinit em_gio_irq_domain_init(struct em_gio_priv *p) return 0; } -static void __devexit em_gio_irq_domain_cleanup(struct em_gio_priv *p) +static void em_gio_irq_domain_cleanup(struct em_gio_priv *p) { struct gpio_em_config *pdata = p->pdev->dev.platform_data; diff --git a/drivers/gpio/gpio-langwell.c b/drivers/gpio/gpio-langwell.c index a1c8754f52c..202a99207b7 100644 --- a/drivers/gpio/gpio-langwell.c +++ b/drivers/gpio/gpio-langwell.c @@ -339,7 +339,7 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev, resource_size_t start, len; struct lnw_gpio *lnw; u32 gpio_base; - int retval = 0; + int retval; int ngpio = id->driver_data; retval = pci_enable_device(pdev); @@ -357,6 +357,7 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev, base = ioremap_nocache(start, len); if (!base) { dev_err(&pdev->dev, "error mapping bar1\n"); + retval = -EFAULT; goto err3; } gpio_base = *((u32 *)base + 1); @@ -381,8 +382,10 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev, lnw->domain = irq_domain_add_linear(pdev->dev.of_node, ngpio, &lnw_gpio_irq_ops, lnw); - if (!lnw->domain) + if (!lnw->domain) { + retval = -ENOMEM; goto err3; + } lnw->reg_base = base; lnw->chip.label = dev_name(&pdev->dev); diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index c2199beca98..3644e0dcb3d 100644 --- a/drivers/gpio/gpio-lpc32xx.c +++ b/drivers/gpio/gpio-lpc32xx.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-lpc32xx/gpiolib.c + * GPIO driver for LPC32xx SoC * * Author: Kevin Wells <kevin.wells@nxp.com> * @@ -28,6 +28,7 @@ #include <mach/hardware.h> #include <mach/platform.h> #include <mach/gpio-lpc32xx.h> +#include <mach/irqs.h> #define LPC32XX_GPIO_P3_INP_STATE _GPREG(0x000) #define LPC32XX_GPIO_P3_OUTP_SET _GPREG(0x004) @@ -112,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] = { @@ -307,6 +309,7 @@ static int lpc32xx_gpio_dir_output_p012(struct gpio_chip *chip, unsigned pin, { struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip); + __set_gpio_level_p012(group, pin, value); __set_gpio_dir_p012(group, pin, 0); return 0; @@ -317,6 +320,7 @@ static int lpc32xx_gpio_dir_output_p3(struct gpio_chip *chip, unsigned pin, { struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip); + __set_gpio_level_p3(group, pin, value); __set_gpio_dir_p3(group, pin, 0); return 0; @@ -325,6 +329,9 @@ static int lpc32xx_gpio_dir_output_p3(struct gpio_chip *chip, unsigned pin, static int lpc32xx_gpio_dir_out_always(struct gpio_chip *chip, unsigned pin, int value) { + struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip); + + __set_gpo_level_p3(group, pin, value); return 0; } @@ -367,6 +374,66 @@ static int lpc32xx_gpio_request(struct gpio_chip *chip, unsigned pin) return -EINVAL; } +static int lpc32xx_gpio_to_irq_p01(struct gpio_chip *chip, unsigned offset) +{ + return IRQ_LPC32XX_P0_P1_IRQ; +} + +static const char lpc32xx_gpio_to_irq_gpio_p3_table[] = { + IRQ_LPC32XX_GPIO_00, + IRQ_LPC32XX_GPIO_01, + IRQ_LPC32XX_GPIO_02, + IRQ_LPC32XX_GPIO_03, + IRQ_LPC32XX_GPIO_04, + IRQ_LPC32XX_GPIO_05, +}; + +static int lpc32xx_gpio_to_irq_gpio_p3(struct gpio_chip *chip, unsigned offset) +{ + if (offset < ARRAY_SIZE(lpc32xx_gpio_to_irq_gpio_p3_table)) + return lpc32xx_gpio_to_irq_gpio_p3_table[offset]; + return -ENXIO; +} + +static const char lpc32xx_gpio_to_irq_gpi_p3_table[] = { + IRQ_LPC32XX_GPI_00, + IRQ_LPC32XX_GPI_01, + IRQ_LPC32XX_GPI_02, + IRQ_LPC32XX_GPI_03, + IRQ_LPC32XX_GPI_04, + IRQ_LPC32XX_GPI_05, + IRQ_LPC32XX_GPI_06, + IRQ_LPC32XX_GPI_07, + IRQ_LPC32XX_GPI_08, + IRQ_LPC32XX_GPI_09, + -ENXIO, /* 10 */ + -ENXIO, /* 11 */ + -ENXIO, /* 12 */ + -ENXIO, /* 13 */ + -ENXIO, /* 14 */ + -ENXIO, /* 15 */ + -ENXIO, /* 16 */ + -ENXIO, /* 17 */ + -ENXIO, /* 18 */ + IRQ_LPC32XX_GPI_19, + -ENXIO, /* 20 */ + -ENXIO, /* 21 */ + -ENXIO, /* 22 */ + -ENXIO, /* 23 */ + -ENXIO, /* 24 */ + -ENXIO, /* 25 */ + -ENXIO, /* 26 */ + -ENXIO, /* 27 */ + IRQ_LPC32XX_GPI_28, +}; + +static int lpc32xx_gpio_to_irq_gpi_p3(struct gpio_chip *chip, unsigned offset) +{ + if (offset < ARRAY_SIZE(lpc32xx_gpio_to_irq_gpi_p3_table)) + return lpc32xx_gpio_to_irq_gpi_p3_table[offset]; + return -ENXIO; +} + static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { { .chip = { @@ -376,6 +443,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { .direction_output = lpc32xx_gpio_dir_output_p012, .set = lpc32xx_gpio_set_value_p012, .request = lpc32xx_gpio_request, + .to_irq = lpc32xx_gpio_to_irq_p01, .base = LPC32XX_GPIO_P0_GRP, .ngpio = LPC32XX_GPIO_P0_MAX, .names = gpio_p0_names, @@ -391,6 +459,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { .direction_output = lpc32xx_gpio_dir_output_p012, .set = lpc32xx_gpio_set_value_p012, .request = lpc32xx_gpio_request, + .to_irq = lpc32xx_gpio_to_irq_p01, .base = LPC32XX_GPIO_P1_GRP, .ngpio = LPC32XX_GPIO_P1_MAX, .names = gpio_p1_names, @@ -421,6 +490,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { .direction_output = lpc32xx_gpio_dir_output_p3, .set = lpc32xx_gpio_set_value_p3, .request = lpc32xx_gpio_request, + .to_irq = lpc32xx_gpio_to_irq_gpio_p3, .base = LPC32XX_GPIO_P3_GRP, .ngpio = LPC32XX_GPIO_P3_MAX, .names = gpio_p3_names, @@ -434,6 +504,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { .direction_input = lpc32xx_gpio_dir_in_always, .get = lpc32xx_gpi_get_value, .request = lpc32xx_gpio_request, + .to_irq = lpc32xx_gpio_to_irq_gpi_p3, .base = LPC32XX_GPI_P3_GRP, .ngpio = LPC32XX_GPI_P3_MAX, .names = gpi_p3_names, @@ -457,13 +528,6 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { }, }; -/* Empty now, can be removed later when mach-lpc32xx is finally switched over - * to DT support - */ -void __init lpc32xx_gpio_init(void) -{ -} - static int lpc32xx_of_xlate(struct gpio_chip *gc, const struct of_phandle_args *gpiospec, u32 *flags) { diff --git a/drivers/gpio/gpio-mc9s08dz60.c b/drivers/gpio/gpio-mc9s08dz60.c index 2738cc44d63..0ab700046a2 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 db01f151d41..6a29ee1847b 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 5a1817eedd1..9ae29cc0d17 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-msic.c b/drivers/gpio/gpio-msic.c index 71a838f4450..b3898628586 100644 --- a/drivers/gpio/gpio-msic.c +++ b/drivers/gpio/gpio-msic.c @@ -99,7 +99,7 @@ static int msic_gpio_to_oreg(unsigned offset) if (offset < 20) return INTEL_MSIC_GPIO0HV0CTLO - offset + 16; - return INTEL_MSIC_GPIO1HV0CTLO + offset + 20; + return INTEL_MSIC_GPIO1HV0CTLO - offset + 20; } static int msic_gpio_direction_input(struct gpio_chip *chip, unsigned offset) diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c index 5cb1227d69c..38305beb437 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-mxc.c b/drivers/gpio/gpio-mxc.c index c337143b18f..80f44bb64a8 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -23,6 +23,7 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/irq.h> +#include <linux/irqdomain.h> #include <linux/gpio.h> #include <linux/platform_device.h> #include <linux/slab.h> @@ -33,12 +34,11 @@ #include <asm-generic/bug.h> #include <asm/mach/irq.h> -#define irq_to_gpio(irq) ((irq) - MXC_GPIO_IRQ_START) - enum mxc_gpio_hwtype { IMX1_GPIO, /* runs on i.mx1 */ IMX21_GPIO, /* runs on i.mx21 and i.mx27 */ - IMX31_GPIO, /* runs on all other i.mx */ + IMX31_GPIO, /* runs on i.mx31 */ + IMX35_GPIO, /* runs on all other i.mx */ }; /* device type dependent stuff */ @@ -50,6 +50,7 @@ struct mxc_gpio_hwdata { unsigned icr2_reg; unsigned imr_reg; unsigned isr_reg; + int edge_sel_reg; unsigned low_level; unsigned high_level; unsigned rise_edge; @@ -61,7 +62,7 @@ struct mxc_gpio_port { void __iomem *base; int irq; int irq_high; - int virtual_irq_start; + struct irq_domain *domain; struct bgpio_chip bgc; u32 both_edges; }; @@ -74,6 +75,7 @@ static struct mxc_gpio_hwdata imx1_imx21_gpio_hwdata = { .icr2_reg = 0x2c, .imr_reg = 0x30, .isr_reg = 0x34, + .edge_sel_reg = -EINVAL, .low_level = 0x03, .high_level = 0x02, .rise_edge = 0x00, @@ -88,6 +90,22 @@ static struct mxc_gpio_hwdata imx31_gpio_hwdata = { .icr2_reg = 0x10, .imr_reg = 0x14, .isr_reg = 0x18, + .edge_sel_reg = -EINVAL, + .low_level = 0x00, + .high_level = 0x01, + .rise_edge = 0x02, + .fall_edge = 0x03, +}; + +static struct mxc_gpio_hwdata imx35_gpio_hwdata = { + .dr_reg = 0x00, + .gdir_reg = 0x04, + .psr_reg = 0x08, + .icr1_reg = 0x0c, + .icr2_reg = 0x10, + .imr_reg = 0x14, + .isr_reg = 0x18, + .edge_sel_reg = 0x1c, .low_level = 0x00, .high_level = 0x01, .rise_edge = 0x02, @@ -104,12 +122,13 @@ static struct mxc_gpio_hwdata *mxc_gpio_hwdata; #define GPIO_ICR2 (mxc_gpio_hwdata->icr2_reg) #define GPIO_IMR (mxc_gpio_hwdata->imr_reg) #define GPIO_ISR (mxc_gpio_hwdata->isr_reg) +#define GPIO_EDGE_SEL (mxc_gpio_hwdata->edge_sel_reg) #define GPIO_INT_LOW_LEV (mxc_gpio_hwdata->low_level) #define GPIO_INT_HIGH_LEV (mxc_gpio_hwdata->high_level) #define GPIO_INT_RISE_EDGE (mxc_gpio_hwdata->rise_edge) #define GPIO_INT_FALL_EDGE (mxc_gpio_hwdata->fall_edge) -#define GPIO_INT_NONE 0x4 +#define GPIO_INT_BOTH_EDGES 0x4 static struct platform_device_id mxc_gpio_devtype[] = { { @@ -122,6 +141,9 @@ static struct platform_device_id mxc_gpio_devtype[] = { .name = "imx31-gpio", .driver_data = IMX31_GPIO, }, { + .name = "imx35-gpio", + .driver_data = IMX35_GPIO, + }, { /* sentinel */ } }; @@ -130,6 +152,7 @@ static const struct of_device_id mxc_gpio_dt_ids[] = { { .compatible = "fsl,imx1-gpio", .data = &mxc_gpio_devtype[IMX1_GPIO], }, { .compatible = "fsl,imx21-gpio", .data = &mxc_gpio_devtype[IMX21_GPIO], }, { .compatible = "fsl,imx31-gpio", .data = &mxc_gpio_devtype[IMX31_GPIO], }, + { .compatible = "fsl,imx35-gpio", .data = &mxc_gpio_devtype[IMX35_GPIO], }, { /* sentinel */ } }; @@ -144,14 +167,15 @@ static LIST_HEAD(mxc_gpio_ports); static int gpio_set_irq_type(struct irq_data *d, u32 type) { - u32 gpio = irq_to_gpio(d->irq); struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct mxc_gpio_port *port = gc->private; u32 bit, val; + u32 gpio_idx = d->hwirq; + u32 gpio = port->bgc.gc.base + gpio_idx; int edge; void __iomem *reg = port->base; - port->both_edges &= ~(1 << (gpio & 31)); + port->both_edges &= ~(1 << gpio_idx); switch (type) { case IRQ_TYPE_EDGE_RISING: edge = GPIO_INT_RISE_EDGE; @@ -160,15 +184,19 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) edge = GPIO_INT_FALL_EDGE; break; case IRQ_TYPE_EDGE_BOTH: - val = gpio_get_value(gpio); - if (val) { - edge = GPIO_INT_LOW_LEV; - pr_debug("mxc: set GPIO %d to low trigger\n", gpio); + if (GPIO_EDGE_SEL >= 0) { + edge = GPIO_INT_BOTH_EDGES; } else { - edge = GPIO_INT_HIGH_LEV; - pr_debug("mxc: set GPIO %d to high trigger\n", gpio); + val = gpio_get_value(gpio); + if (val) { + edge = GPIO_INT_LOW_LEV; + pr_debug("mxc: set GPIO %d to low trigger\n", gpio); + } else { + edge = GPIO_INT_HIGH_LEV; + pr_debug("mxc: set GPIO %d to high trigger\n", gpio); + } + port->both_edges |= 1 << gpio_idx; } - port->both_edges |= 1 << (gpio & 31); break; case IRQ_TYPE_LEVEL_LOW: edge = GPIO_INT_LOW_LEV; @@ -180,11 +208,24 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) return -EINVAL; } - reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */ - bit = gpio & 0xf; - val = readl(reg) & ~(0x3 << (bit << 1)); - writel(val | (edge << (bit << 1)), reg); - writel(1 << (gpio & 0x1f), port->base + GPIO_ISR); + if (GPIO_EDGE_SEL >= 0) { + val = readl(port->base + GPIO_EDGE_SEL); + if (edge == GPIO_INT_BOTH_EDGES) + writel(val | (1 << gpio_idx), + port->base + GPIO_EDGE_SEL); + else + writel(val & ~(1 << gpio_idx), + port->base + GPIO_EDGE_SEL); + } + + if (edge != GPIO_INT_BOTH_EDGES) { + reg += GPIO_ICR1 + ((gpio_idx & 0x10) >> 2); /* lower or upper register */ + bit = gpio_idx & 0xf; + val = readl(reg) & ~(0x3 << (bit << 1)); + writel(val | (edge << (bit << 1)), reg); + } + + writel(1 << gpio_idx, port->base + GPIO_ISR); return 0; } @@ -217,15 +258,13 @@ static void mxc_flip_edge(struct mxc_gpio_port *port, u32 gpio) /* handle 32 interrupts in one status register */ static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat) { - u32 gpio_irq_no_base = port->virtual_irq_start; - while (irq_stat != 0) { int irqoffset = fls(irq_stat) - 1; if (port->both_edges & (1 << irqoffset)) mxc_flip_edge(port, irqoffset); - generic_handle_irq(gpio_irq_no_base + irqoffset); + generic_handle_irq(irq_find_mapping(port->domain, irqoffset)); irq_stat &= ~(1 << irqoffset); } @@ -276,10 +315,9 @@ static void mx2_gpio_irq_handler(u32 irq, struct irq_desc *desc) */ static int gpio_set_wake_irq(struct irq_data *d, u32 enable) { - u32 gpio = irq_to_gpio(d->irq); - u32 gpio_idx = gpio & 0x1F; struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct mxc_gpio_port *port = gc->private; + u32 gpio_idx = d->hwirq; if (enable) { if (port->irq_high && (gpio_idx >= 16)) @@ -296,12 +334,12 @@ static int gpio_set_wake_irq(struct irq_data *d, u32 enable) return 0; } -static void __init mxc_gpio_init_gc(struct mxc_gpio_port *port) +static void __init mxc_gpio_init_gc(struct mxc_gpio_port *port, int irq_base) { struct irq_chip_generic *gc; struct irq_chip_type *ct; - gc = irq_alloc_generic_chip("gpio-mxc", 1, port->virtual_irq_start, + gc = irq_alloc_generic_chip("gpio-mxc", 1, irq_base, port->base, handle_level_irq); gc->private = port; @@ -338,7 +376,9 @@ static void __devinit mxc_gpio_get_hw(struct platform_device *pdev) return; } - if (hwtype == IMX31_GPIO) + if (hwtype == IMX35_GPIO) + mxc_gpio_hwdata = &imx35_gpio_hwdata; + else if (hwtype == IMX31_GPIO) mxc_gpio_hwdata = &imx31_gpio_hwdata; else mxc_gpio_hwdata = &imx1_imx21_gpio_hwdata; @@ -352,7 +392,7 @@ static int mxc_gpio_to_irq(struct gpio_chip *gc, unsigned offset) struct mxc_gpio_port *port = container_of(bgc, struct mxc_gpio_port, bgc); - return port->virtual_irq_start + offset; + return irq_find_mapping(port->domain, offset); } static int __devinit mxc_gpio_probe(struct platform_device *pdev) @@ -360,6 +400,7 @@ static int __devinit mxc_gpio_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct mxc_gpio_port *port; struct resource *iores; + int irq_base; int err; mxc_gpio_get_hw(pdev); @@ -398,10 +439,12 @@ static int __devinit mxc_gpio_probe(struct platform_device *pdev) writel(~0, port->base + GPIO_ISR); if (mxc_gpio_hwtype == IMX21_GPIO) { - /* setup one handler for all GPIO interrupts */ - if (pdev->id == 0) - irq_set_chained_handler(port->irq, - mx2_gpio_irq_handler); + /* + * Setup one handler for all GPIO interrupts. Actually setting + * the handler is needed only once, but doing it for every port + * is more robust and easier. + */ + irq_set_chained_handler(port->irq, mx2_gpio_irq_handler); } else { /* setup one handler for each entry */ irq_set_chained_handler(port->irq, mx3_gpio_irq_handler); @@ -422,28 +465,37 @@ static int __devinit mxc_gpio_probe(struct platform_device *pdev) goto out_iounmap; port->bgc.gc.to_irq = mxc_gpio_to_irq; - port->bgc.gc.base = pdev->id * 32; - port->bgc.dir = port->bgc.read_reg(port->bgc.reg_dir); - port->bgc.data = port->bgc.read_reg(port->bgc.reg_set); + port->bgc.gc.base = (pdev->id < 0) ? of_alias_get_id(np, "gpio") * 32 : + pdev->id * 32; err = gpiochip_add(&port->bgc.gc); if (err) goto out_bgpio_remove; - /* - * In dt case, we use gpio number range dynamically - * allocated by gpio core. - */ - port->virtual_irq_start = MXC_GPIO_IRQ_START + (np ? port->bgc.gc.base : - pdev->id * 32); + irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id()); + if (irq_base < 0) { + err = irq_base; + goto out_gpiochip_remove; + } + + 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-mxc can be a generic irq chip */ - mxc_gpio_init_gc(port); + mxc_gpio_init_gc(port, irq_base); list_add_tail(&port->node, &mxc_gpio_ports); return 0; +out_irqdesc_free: + irq_free_descs(irq_base, 32); +out_gpiochip_remove: + WARN_ON(gpiochip_remove(&port->bgc.gc) < 0); out_bgpio_remove: bgpio_remove(&port->bgc); out_iounmap: diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index 39e49566996..796fb13e481 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 c4ed1722734..94cbc842fbc 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 @@ -174,12 +172,22 @@ static inline void _gpio_dbck_enable(struct gpio_bank *bank) if (bank->dbck_enable_mask && !bank->dbck_enabled) { clk_enable(bank->dbck); bank->dbck_enabled = true; + + __raw_writel(bank->dbck_enable_mask, + bank->base + bank->regs->debounce_en); } } static inline void _gpio_dbck_disable(struct gpio_bank *bank) { if (bank->dbck_enable_mask && bank->dbck_enabled) { + /* + * Disable debounce before cutting it's clock. If debounce is + * enabled but the clock is not, GPIO module seems to be unable + * to detect events and generate interrupts at least on OMAP3. + */ + __raw_writel(0, bank->base + bank->regs->debounce_en); + clk_disable(bank->dbck); bank->dbck_enabled = false; } @@ -375,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) @@ -889,12 +900,6 @@ static int gpio_debounce(struct gpio_chip *chip, unsigned offset, bank = container_of(chip, struct gpio_bank, chip); - if (!bank->dbck) { - bank->dbck = clk_get(bank->dev, "dbclk"); - if (IS_ERR(bank->dbck)) - dev_err(bank->dev, "Could not get gpio dbck\n"); - } - spin_lock_irqsave(&bank->lock, flags); _set_gpio_debounce(bank, offset, debounce); spin_unlock_irqrestore(&bank->lock, flags); @@ -966,6 +971,10 @@ static void omap_gpio_mod_init(struct gpio_bank *bank) /* Initialize interface clk ungated, module enabled */ if (bank->regs->ctrl) __raw_writel(0, base + bank->regs->ctrl); + + bank->dbck = clk_get(bank->dev, "dbclk"); + if (IS_ERR(bank->dbck)) + dev_err(bank->dev, "Could not get gpio dbck\n"); } static __devinit void @@ -1050,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; @@ -1081,7 +1090,6 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) bank->is_mpuio = pdata->is_mpuio; bank->non_wakeup_gpios = pdata->non_wakeup_gpios; bank->loses_context = pdata->loses_context; - bank->get_context_loss_count = pdata->get_context_loss_count; bank->regs = pdata->regs; #ifdef CONFIG_OF_GPIO bank->chip.of_node = of_node_get(node); @@ -1135,6 +1143,9 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) omap_gpio_chip_init(bank); omap_gpio_show_rev(bank); + if (bank->loses_context) + bank->get_context_loss_count = pdata->get_context_loss_count; + pm_runtime_put(bank->dev); list_add_tail(&bank->node, &omap_gpio_list); @@ -1430,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-pca953x.c b/drivers/gpio/gpio-pca953x.c index 1c313c710be..9c693ae1795 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -78,10 +78,10 @@ struct pca953x_chip { #ifdef CONFIG_GPIO_PCA953X_IRQ struct mutex irq_lock; - uint16_t irq_mask; - uint16_t irq_stat; - uint16_t irq_trig_raise; - uint16_t irq_trig_fall; + u32 irq_mask; + u32 irq_stat; + u32 irq_trig_raise; + u32 irq_trig_fall; int irq_base; #endif @@ -98,12 +98,11 @@ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val) if (chip->gpio_chip.ngpio <= 8) ret = i2c_smbus_write_byte_data(chip->client, reg, val); else if (chip->gpio_chip.ngpio == 24) { - ret = i2c_smbus_write_word_data(chip->client, + cpu_to_le32s(&val); + ret = i2c_smbus_write_i2c_block_data(chip->client, (reg << 2) | REG_ADDR_AI, - val & 0xffff); - ret = i2c_smbus_write_byte_data(chip->client, - (reg << 2) + 2, - (val & 0xff0000) >> 16); + 3, + (u8 *) &val); } else { switch (chip->chip_type) { @@ -135,22 +134,27 @@ static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val) { int ret; - if (chip->gpio_chip.ngpio <= 8) + if (chip->gpio_chip.ngpio <= 8) { ret = i2c_smbus_read_byte_data(chip->client, reg); - else if (chip->gpio_chip.ngpio == 24) { - ret = i2c_smbus_read_word_data(chip->client, reg << 2); - ret |= (i2c_smbus_read_byte_data(chip->client, - (reg << 2) + 2)<<16); + *val = ret; } - else + else if (chip->gpio_chip.ngpio == 24) { + *val = 0; + ret = i2c_smbus_read_i2c_block_data(chip->client, + (reg << 2) | REG_ADDR_AI, + 3, + (u8 *) val); + le32_to_cpus(val); + } else { ret = i2c_smbus_read_word_data(chip->client, reg << 1); + *val = ret; + } if (ret < 0) { dev_err(&chip->client->dev, "failed reading register\n"); return ret; } - *val = (u32)ret; return 0; } @@ -349,8 +353,8 @@ static void pca953x_irq_bus_lock(struct irq_data *d) static void pca953x_irq_bus_sync_unlock(struct irq_data *d) { struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); - uint16_t new_irqs; - uint16_t level; + u32 new_irqs; + u32 level; /* Look for any newly setup interrupt */ new_irqs = chip->irq_trig_fall | chip->irq_trig_raise; @@ -368,8 +372,8 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) static int pca953x_irq_set_type(struct irq_data *d, unsigned int type) { struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); - uint16_t level = d->irq - chip->irq_base; - uint16_t mask = 1 << level; + u32 level = d->irq - chip->irq_base; + u32 mask = 1 << level; if (!(type & IRQ_TYPE_EDGE_BOTH)) { dev_err(&chip->client->dev, "irq %d: unsupported type %d\n", @@ -399,12 +403,12 @@ static struct irq_chip pca953x_irq_chip = { .irq_set_type = pca953x_irq_set_type, }; -static uint16_t pca953x_irq_pending(struct pca953x_chip *chip) +static u32 pca953x_irq_pending(struct pca953x_chip *chip) { u32 cur_stat; - uint16_t old_stat; - uint16_t pending; - uint16_t trigger; + u32 old_stat; + u32 pending; + u32 trigger; int ret, offset = 0; switch (chip->chip_type) { @@ -440,8 +444,8 @@ static uint16_t pca953x_irq_pending(struct pca953x_chip *chip) static irqreturn_t pca953x_irq_handler(int irq, void *devid) { struct pca953x_chip *chip = devid; - uint16_t pending; - uint16_t level; + u32 pending; + u32 level; pending = pca953x_irq_pending(chip); @@ -564,7 +568,7 @@ static void pca953x_irq_teardown(struct pca953x_chip *chip) * WARNING: This is DEPRECATED and will be removed eventually! */ static void -pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, int *invert) +pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert) { struct device_node *node; const __be32 *val; @@ -592,13 +596,13 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, int *invert) } #else static void -pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, int *invert) +pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert) { *gpio_base = -1; } #endif -static int __devinit device_pca953x_init(struct pca953x_chip *chip, int invert) +static int __devinit device_pca953x_init(struct pca953x_chip *chip, u32 invert) { int ret; @@ -617,7 +621,7 @@ out: return ret; } -static int __devinit device_pca957x_init(struct pca953x_chip *chip, int invert) +static int __devinit device_pca957x_init(struct pca953x_chip *chip, u32 invert) { int ret; u32 val = 0; @@ -653,8 +657,9 @@ static int __devinit pca953x_probe(struct i2c_client *client, { struct pca953x_platform_data *pdata; struct pca953x_chip *chip; - int irq_base=0, invert=0; + int irq_base = 0; int ret; + u32 invert = 0; chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL); if (chip == NULL) diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 2d1de9e7e9b..16af35cd2b1 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,62 +65,34 @@ 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); }; /*-------------------------------------------------------------------------*/ /* Talk to 8-bit I/O expander */ -static int pcf857x_input8(struct gpio_chip *chip, unsigned offset) +static int i2c_write_le8(struct i2c_client *client, unsigned data) { - struct pcf857x *gpio = container_of(chip, struct pcf857x, chip); - int status; - - mutex_lock(&gpio->lock); - gpio->out |= (1 << offset); - status = i2c_smbus_write_byte(gpio->client, gpio->out); - mutex_unlock(&gpio->lock); - - return status; -} - -static int pcf857x_get8(struct gpio_chip *chip, unsigned offset) -{ - struct pcf857x *gpio = container_of(chip, struct pcf857x, chip); - s32 value; - - value = i2c_smbus_read_byte(gpio->client); - return (value < 0) ? 0 : (value & (1 << offset)); -} - -static int pcf857x_output8(struct gpio_chip *chip, unsigned offset, int value) -{ - struct pcf857x *gpio = container_of(chip, struct pcf857x, chip); - unsigned bit = 1 << offset; - int status; - - mutex_lock(&gpio->lock); - if (value) - gpio->out |= bit; - else - gpio->out &= ~bit; - status = i2c_smbus_write_byte(gpio->client, gpio->out); - mutex_unlock(&gpio->lock); - - return status; + return i2c_smbus_write_byte(client, data); } -static void pcf857x_set8(struct gpio_chip *chip, unsigned offset, int value) +static int i2c_read_le8(struct i2c_client *client) { - pcf857x_output8(chip, offset, value); + return (int)i2c_smbus_read_byte(client); } -/*-------------------------------------------------------------------------*/ - /* Talk to 16-bit I/O expander */ -static int i2c_write_le16(struct i2c_client *client, u16 word) +static int i2c_write_le16(struct i2c_client *client, unsigned word) { u8 buf[2] = { word & 0xff, word >> 8, }; int status; @@ -135,29 +112,31 @@ static int i2c_read_le16(struct i2c_client *client) return (buf[1] << 8) | buf[0]; } -static int pcf857x_input16(struct gpio_chip *chip, unsigned offset) +/*-------------------------------------------------------------------------*/ + +static int pcf857x_input(struct gpio_chip *chip, unsigned offset) { struct pcf857x *gpio = container_of(chip, struct pcf857x, chip); int status; mutex_lock(&gpio->lock); gpio->out |= (1 << offset); - status = i2c_write_le16(gpio->client, gpio->out); + status = gpio->write(gpio->client, gpio->out); mutex_unlock(&gpio->lock); return status; } -static int pcf857x_get16(struct gpio_chip *chip, unsigned offset) +static int pcf857x_get(struct gpio_chip *chip, unsigned offset) { struct pcf857x *gpio = container_of(chip, struct pcf857x, chip); int value; - value = i2c_read_le16(gpio->client); + value = gpio->read(gpio->client); return (value < 0) ? 0 : (value & (1 << offset)); } -static int pcf857x_output16(struct gpio_chip *chip, unsigned offset, int value) +static int pcf857x_output(struct gpio_chip *chip, unsigned offset, int value) { struct pcf857x *gpio = container_of(chip, struct pcf857x, chip); unsigned bit = 1 << offset; @@ -168,15 +147,109 @@ static int pcf857x_output16(struct gpio_chip *chip, unsigned offset, int value) gpio->out |= bit; else gpio->out &= ~bit; - status = i2c_write_le16(gpio->client, gpio->out); + status = gpio->write(gpio->client, gpio->out); mutex_unlock(&gpio->lock); return status; } -static void pcf857x_set16(struct gpio_chip *chip, unsigned offset, int value) +static void pcf857x_set(struct gpio_chip *chip, unsigned offset, int value) { - pcf857x_output16(chip, offset, value); + pcf857x_output(chip, offset, 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; } /*-------------------------------------------------------------------------*/ @@ -199,11 +272,26 @@ static int pcf857x_probe(struct i2c_client *client, return -ENOMEM; mutex_init(&gpio->lock); - - gpio->chip.base = pdata ? pdata->gpio_base : -1; - gpio->chip.can_sleep = 1; - gpio->chip.dev = &client->dev; - gpio->chip.owner = THIS_MODULE; + spin_lock_init(&gpio->slock); + + gpio->chip.base = pdata ? pdata->gpio_base : -1; + gpio->chip.can_sleep = 1; + gpio->chip.dev = &client->dev; + gpio->chip.owner = THIS_MODULE; + gpio->chip.get = pcf857x_get; + gpio->chip.set = pcf857x_set; + gpio->chip.direction_input = pcf857x_input; + 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 @@ -216,12 +304,9 @@ static int pcf857x_probe(struct i2c_client *client, * * NOTE: we don't distinguish here between *4 and *4a parts. */ - gpio->chip.ngpio = id->driver_data; if (gpio->chip.ngpio == 8) { - gpio->chip.direction_input = pcf857x_input8; - gpio->chip.get = pcf857x_get8; - gpio->chip.direction_output = pcf857x_output8; - gpio->chip.set = pcf857x_set8; + gpio->write = i2c_write_le8; + gpio->read = i2c_read_le8; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) @@ -238,10 +323,8 @@ static int pcf857x_probe(struct i2c_client *client, * NOTE: we don't distinguish here between '75 and '75c parts. */ } else if (gpio->chip.ngpio == 16) { - gpio->chip.direction_input = pcf857x_input16; - gpio->chip.get = pcf857x_get16; - gpio->chip.direction_output = pcf857x_output16; - gpio->chip.set = pcf857x_set16; + gpio->write = i2c_write_le16; + gpio->read = i2c_read_le16; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) status = -EIO; @@ -279,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) @@ -309,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; } @@ -330,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 139ad3e2001..4ad0c4f9171 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 58a6a63a6ec..98d52cb3fd1 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,9 +61,11 @@ #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; +static struct device_node *pxa_gpio_of_node; #endif struct pxa_gpio_chip { @@ -166,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) @@ -277,6 +232,24 @@ static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value) (value ? GPSR_OFFSET : GPCR_OFFSET)); } +#ifdef CONFIG_OF_GPIO +static int pxa_gpio_of_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, + u32 *flags) +{ + if (gpiospec->args[0] > pxa_last_gpio) + return -EINVAL; + + if (gc != &pxa_gpio_chips[gpiospec->args[0] / 32].chip) + return -EINVAL; + + if (flags) + *flags = gpiospec->args[1]; + + return gpiospec->args[0] % 32; +} +#endif + static int __devinit pxa_init_gpio_chip(int gpio_end, int (*set_wake)(unsigned int, unsigned int)) { @@ -304,6 +277,11 @@ static int __devinit pxa_init_gpio_chip(int gpio_end, c->get = pxa_gpio_get; c->set = pxa_gpio_set; c->to_irq = pxa_gpio_to_irq; +#ifdef CONFIG_OF_GPIO + c->of_node = pxa_gpio_of_node; + c->of_xlate = pxa_gpio_of_xlate; + c->of_gpio_n_cells = 2; +#endif /* number of GPIOs on last bank may be less than 32 */ c->ngpio = (gpio + 31 > gpio_end) ? (gpio_end - gpio + 1) : 32; @@ -379,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; @@ -389,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) @@ -488,6 +469,7 @@ static int pxa_gpio_nums(void) return count; } +#ifdef CONFIG_OF static struct of_device_id pxa_gpio_dt_ids[] = { { .compatible = "mrvl,pxa-gpio" }, { .compatible = "mrvl,mmp-gpio", .data = (void *)MMP_GPIO }, @@ -505,12 +487,12 @@ static int pxa_irq_domain_map(struct irq_domain *d, unsigned int irq, const struct irq_domain_ops pxa_irq_domain_ops = { .map = pxa_irq_domain_map, + .xlate = irq_domain_xlate_twocell, }; -#ifdef CONFIG_OF 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); @@ -545,6 +527,7 @@ static int __devinit pxa_gpio_probe_dt(struct platform_device *pdev) } domain = irq_domain_add_legacy(np, nr_gpios, irq_base, 0, &pxa_irq_domain_ops, NULL); + pxa_gpio_of_node = np; return 0; err: iounmap(gpio_reg_base); @@ -564,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; @@ -594,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; @@ -653,7 +639,7 @@ static struct platform_driver pxa_gpio_driver = { .probe = pxa_gpio_probe, .driver = { .name = "pxa-gpio", - .of_match_table = pxa_gpio_dt_ids, + .of_match_table = of_match_ptr(pxa_gpio_dt_ids), }, }; diff --git a/drivers/gpio/gpio-rdc321x.c b/drivers/gpio/gpio-rdc321x.c index e97016af644..b62d443e9a5 100644 --- a/drivers/gpio/gpio-rdc321x.c +++ b/drivers/gpio/gpio-rdc321x.c @@ -170,6 +170,7 @@ static int __devinit rdc321x_gpio_probe(struct platform_device *pdev) rdc321x_gpio_dev->reg2_data_base = r->start + 0x4; rdc321x_gpio_dev->chip.label = "rdc321x-gpio"; + rdc321x_gpio_dev->chip.owner = THIS_MODULE; rdc321x_gpio_dev->chip.direction_input = rdc_gpio_direction_input; rdc321x_gpio_dev->chip.direction_output = rdc_gpio_config; rdc321x_gpio_dev->chip.get = rdc_gpio_get_value; diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index b6453d0e44a..a006f0db15a 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); } } @@ -2454,12 +2517,6 @@ static struct samsung_gpio_chip exynos5_gpios_1[] = { }, }, { .chip = { - .base = EXYNOS5_GPC4(0), - .ngpio = EXYNOS5_GPIO_C4_NR, - .label = "GPC4", - }, - }, { - .chip = { .base = EXYNOS5_GPD0(0), .ngpio = EXYNOS5_GPIO_D0_NR, .label = "GPD0", @@ -2513,6 +2570,12 @@ static struct samsung_gpio_chip exynos5_gpios_1[] = { .label = "GPY6", }, }, { + .chip = { + .base = EXYNOS5_GPC4(0), + .ngpio = EXYNOS5_GPIO_C4_NR, + .label = "GPC4", + }, + }, { .config = &samsung_gpio_cfgs[9], .irq_base = IRQ_EINT(0), .chip = { @@ -2681,11 +2744,14 @@ static int exynos_gpio_xlate(struct gpio_chip *gc, 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])) + if (s3c_gpio_setpull(pin, gpiospec->args[2] & 0xffff)) pr_warn("gpio_xlate: failed to set pin pull up/down\n"); if (s5p_gpio_set_drvstr(pin, gpiospec->args[3])) pr_warn("gpio_xlate: failed to set pin drive strength\n"); + if (flags) + *flags = gpiospec->args[2] >> 16; + return gpiospec->args[0]; } @@ -2731,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) { @@ -2833,7 +2920,7 @@ static __init void exynos5_gpiolib_init(void) } /* need to set base address for gpc4 */ - exynos5_gpios_1[11].base = gpio_base1 + 0x2E0; + exynos5_gpios_1[20].base = gpio_base1 + 0x2E0; /* need to set base address for gpx */ chip = &exynos5_gpios_1[21]; @@ -3128,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-sch.c b/drivers/gpio/gpio-sch.c index 424dce8e3f3..8707d4572a0 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -241,7 +241,8 @@ static int __devinit sch_gpio_probe(struct platform_device *pdev) break; default: - return -ENODEV; + err = -ENODEV; + goto err_sch_gpio_core; } sch_gpio_core.dev = &pdev->dev; diff --git a/drivers/gpio/gpio-sodaville.c b/drivers/gpio/gpio-sodaville.c index 9d9891f7a60..e25f73130b4 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-sta2x11.c b/drivers/gpio/gpio-sta2x11.c index 38416be8ba1..6064fb376e1 100644 --- a/drivers/gpio/gpio-sta2x11.c +++ b/drivers/gpio/gpio-sta2x11.c @@ -383,8 +383,9 @@ static int __devinit gsta_probe(struct platform_device *dev) } spin_lock_init(&chip->lock); gsta_gpio_setup(chip); - for (i = 0; i < GSTA_NR_GPIO; i++) - gsta_set_config(chip, i, gpio_pdata->pinconfig[i]); + if (gpio_pdata) + for (i = 0; i < GSTA_NR_GPIO; i++) + gsta_set_config(chip, i, gpio_pdata->pinconfig[i]); /* 384 was used in previous code: be compatible for other drivers */ err = irq_alloc_descs(-1, 384, GSTA_NR_GPIO, NUMA_NO_NODE); diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c index a4f73534394..eb3e215d239 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 2a82e8999a4..1e48317e70f 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 dc5184d5789..d982593d756 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-tps6586x.c b/drivers/gpio/gpio-tps6586x.c new file mode 100644 index 00000000000..2526b3bb0fa --- /dev/null +++ b/drivers/gpio/gpio-tps6586x.c @@ -0,0 +1,158 @@ +/* + * TI TPS6586x GPIO driver + * + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * Author: Laxman dewangan <ldewangan@nvidia.com> + * + * Based on tps6586x.c + * Copyright (c) 2010 CompuLab Ltd. + * Mike Rapoport <mike@compulab.co.il> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/errno.h> +#include <linux/gpio.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mfd/tps6586x.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> + +/* GPIO control registers */ +#define TPS6586X_GPIOSET1 0x5d +#define TPS6586X_GPIOSET2 0x5e + +struct tps6586x_gpio { + struct gpio_chip gpio_chip; + struct device *parent; +}; + +static inline struct tps6586x_gpio *to_tps6586x_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct tps6586x_gpio, gpio_chip); +} + +static int tps6586x_gpio_get(struct gpio_chip *gc, unsigned offset) +{ + struct tps6586x_gpio *tps6586x_gpio = to_tps6586x_gpio(gc); + uint8_t val; + int ret; + + ret = tps6586x_read(tps6586x_gpio->parent, TPS6586X_GPIOSET2, &val); + if (ret) + return ret; + + return !!(val & (1 << offset)); +} + +static void tps6586x_gpio_set(struct gpio_chip *gc, unsigned offset, + int value) +{ + struct tps6586x_gpio *tps6586x_gpio = to_tps6586x_gpio(gc); + + tps6586x_update(tps6586x_gpio->parent, TPS6586X_GPIOSET2, + value << offset, 1 << offset); +} + +static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset, + int value) +{ + struct tps6586x_gpio *tps6586x_gpio = to_tps6586x_gpio(gc); + uint8_t val, mask; + + tps6586x_gpio_set(gc, offset, value); + + val = 0x1 << (offset * 2); + mask = 0x3 << (offset * 2); + + return tps6586x_update(tps6586x_gpio->parent, TPS6586X_GPIOSET1, + val, mask); +} + +static int __devinit tps6586x_gpio_probe(struct platform_device *pdev) +{ + struct tps6586x_platform_data *pdata; + struct tps6586x_gpio *tps6586x_gpio; + int ret; + + pdata = dev_get_platdata(pdev->dev.parent); + tps6586x_gpio = devm_kzalloc(&pdev->dev, + sizeof(*tps6586x_gpio), GFP_KERNEL); + if (!tps6586x_gpio) { + dev_err(&pdev->dev, "Could not allocate tps6586x_gpio\n"); + return -ENOMEM; + } + + tps6586x_gpio->parent = pdev->dev.parent; + + tps6586x_gpio->gpio_chip.owner = THIS_MODULE; + tps6586x_gpio->gpio_chip.label = pdev->name; + tps6586x_gpio->gpio_chip.dev = &pdev->dev; + tps6586x_gpio->gpio_chip.ngpio = 4; + tps6586x_gpio->gpio_chip.can_sleep = 1; + + /* FIXME: add handling of GPIOs as dedicated inputs */ + tps6586x_gpio->gpio_chip.direction_output = tps6586x_gpio_output; + tps6586x_gpio->gpio_chip.set = tps6586x_gpio_set; + tps6586x_gpio->gpio_chip.get = tps6586x_gpio_get; + +#ifdef CONFIG_OF_GPIO + tps6586x_gpio->gpio_chip.of_node = pdev->dev.parent->of_node; +#endif + if (pdata && pdata->gpio_base) + tps6586x_gpio->gpio_chip.base = pdata->gpio_base; + else + tps6586x_gpio->gpio_chip.base = -1; + + ret = gpiochip_add(&tps6586x_gpio->gpio_chip); + if (ret < 0) { + dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, tps6586x_gpio); + + return ret; +} + +static int __devexit tps6586x_gpio_remove(struct platform_device *pdev) +{ + struct tps6586x_gpio *tps6586x_gpio = platform_get_drvdata(pdev); + + return gpiochip_remove(&tps6586x_gpio->gpio_chip); +} + +static struct platform_driver tps6586x_gpio_driver = { + .driver.name = "tps6586x-gpio", + .driver.owner = THIS_MODULE, + .probe = tps6586x_gpio_probe, + .remove = __devexit_p(tps6586x_gpio_remove), +}; + +static int __init tps6586x_gpio_init(void) +{ + return platform_driver_register(&tps6586x_gpio_driver); +} +subsys_initcall(tps6586x_gpio_init); + +static void __exit tps6586x_gpio_exit(void) +{ + platform_driver_unregister(&tps6586x_gpio_driver); +} +module_exit(tps6586x_gpio_exit); + +MODULE_ALIAS("platform:tps6586x-gpio"); +MODULE_DESCRIPTION("GPIO interface for TPS6586X PMIC"); +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c index c1ad2884f2e..11f29c82253 100644 --- a/drivers/gpio/gpio-tps65910.c +++ b/drivers/gpio/gpio-tps65910.c @@ -149,6 +149,9 @@ static int __devinit tps65910_gpio_probe(struct platform_device *pdev) tps65910_gpio->gpio_chip.set = tps65910_gpio_set; tps65910_gpio->gpio_chip.get = tps65910_gpio_get; tps65910_gpio->gpio_chip.dev = &pdev->dev; +#ifdef CONFIG_OF_GPIO + tps65910_gpio->gpio_chip.of_node = tps65910->dev->of_node; +#endif if (pdata && pdata->gpio_base) tps65910_gpio->gpio_chip.base = pdata->gpio_base; else diff --git a/drivers/gpio/gpio-tps65912.c b/drivers/gpio/gpio-tps65912.c index 79e66c00235..99106d1e2e5 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 94256fe7bf3..c5f8ca233e1 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 00000000000..bcd8e4aa7c7 --- /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 e56a2165641..b6eda35089d 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 a06af515483..fb429388939 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/gpio-wm8994.c b/drivers/gpio/gpio-wm8994.c index 92ea5350dfe..1c764e779d8 100644 --- a/drivers/gpio/gpio-wm8994.c +++ b/drivers/gpio/gpio-wm8994.c @@ -19,6 +19,7 @@ #include <linux/mfd/core.h> #include <linux/platform_device.h> #include <linux/seq_file.h> +#include <linux/regmap.h> #include <linux/mfd/wm8994/core.h> #include <linux/mfd/wm8994/pdata.h> @@ -89,8 +90,11 @@ static int wm8994_gpio_direction_out(struct gpio_chip *chip, struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip); struct wm8994 *wm8994 = wm8994_gpio->wm8994; + if (value) + value = WM8994_GPN_LVL; + return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset, - WM8994_GPN_DIR, 0); + WM8994_GPN_DIR | WM8994_GPN_LVL, value); } static void wm8994_gpio_set(struct gpio_chip *chip, unsigned offset, int value) @@ -109,10 +113,7 @@ static int wm8994_gpio_to_irq(struct gpio_chip *chip, unsigned offset) struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip); struct wm8994 *wm8994 = wm8994_gpio->wm8994; - if (!wm8994->irq_base) - return -EINVAL; - - return wm8994->irq_base + offset; + return regmap_irq_get_virq(wm8994->irq_data, offset); } @@ -251,7 +252,8 @@ static int __devinit wm8994_gpio_probe(struct platform_device *pdev) struct wm8994_gpio *wm8994_gpio; int ret; - wm8994_gpio = kzalloc(sizeof(*wm8994_gpio), GFP_KERNEL); + wm8994_gpio = devm_kzalloc(&pdev->dev, sizeof(*wm8994_gpio), + GFP_KERNEL); if (wm8994_gpio == NULL) return -ENOMEM; @@ -276,20 +278,14 @@ static int __devinit wm8994_gpio_probe(struct platform_device *pdev) return ret; err: - kfree(wm8994_gpio); return ret; } static int __devexit wm8994_gpio_remove(struct platform_device *pdev) { struct wm8994_gpio *wm8994_gpio = platform_get_drvdata(pdev); - int ret; - - ret = gpiochip_remove(&wm8994_gpio->gpio_chip); - if (ret == 0) - kfree(wm8994_gpio); - return ret; + return gpiochip_remove(&wm8994_gpio->gpio_chip); } static struct platform_driver wm8994_gpio_driver = { diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index d18068a9f3e..f1a45997aea 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -21,7 +21,7 @@ #include <linux/of_gpio.h> #include <linux/slab.h> -/* Private data structure for of_gpiochip_is_match */ +/* Private data structure for of_gpiochip_find_and_xlate */ struct gg_data { enum of_gpio_flags *flags; struct of_phandle_args gpiospec; @@ -62,7 +62,10 @@ static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data) int of_get_named_gpio_flags(struct device_node *np, const char *propname, int index, enum of_gpio_flags *flags) { - struct gg_data gg_data = { .flags = flags, .out_gpio = -ENODEV }; + /* Return -EPROBE_DEFER to support probe() functions to be called + * later when the GPIO actually becomes available + */ + struct gg_data gg_data = { .flags = flags, .out_gpio = -EPROBE_DEFER }; int ret; /* .of_xlate might decide to not fill in the flags, so clear it. */ @@ -73,13 +76,13 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname, &gg_data.gpiospec); if (ret) { pr_debug("%s: can't parse gpios property\n", __func__); - return -EINVAL; + return ret; } gpiochip_find(&gg_data, of_gpiochip_find_and_xlate); of_node_put(gg_data.gpiospec.np); - pr_debug("%s exited with status %d\n", __func__, ret); + pr_debug("%s exited with status %d\n", __func__, gg_data.out_gpio); return gg_data.out_gpio; } EXPORT_SYMBOL(of_get_named_gpio_flags); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 120b2a0e316..5d6c71edc73 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1186,7 +1186,7 @@ int gpio_request(unsigned gpio, const char *label) { struct gpio_desc *desc; struct gpio_chip *chip; - int status = -EINVAL; + int status = -EPROBE_DEFER; unsigned long flags; spin_lock_irqsave(&gpio_lock, flags); @@ -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) |