diff options
30 files changed, 1103 insertions, 247 deletions
diff --git a/Documentation/devicetree/bindings/gpio/gpio-74x164.txt b/Documentation/devicetree/bindings/gpio/gpio-74x164.txt new file mode 100644 index 00000000000..cc2608021f2 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-74x164.txt @@ -0,0 +1,22 @@ +* Generic 8-bits shift register GPIO driver + +Required properties: +- compatible : Should be "fairchild,74hc595" +- reg : chip select number +- gpio-controller : Marks the device node as a gpio controller. +- #gpio-cells : Should be two.  The first cell is the pin number and +  the second cell is used to specify the gpio polarity: +      0 = active high +      1 = active low +- registers-number: Number of daisy-chained shift registers + +Example: + +gpio5: gpio5@0 { +	compatible = "fairchild,74hc595"; +	reg = <0>; +	gpio-controller; +	#gpio-cells = <2>; +	registers-number = <4>; +	spi-max-frequency = <100000>; +}; diff --git a/Documentation/devicetree/bindings/gpio/gpio-adnp.txt b/Documentation/devicetree/bindings/gpio/gpio-adnp.txt new file mode 100644 index 00000000000..af66b272483 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-adnp.txt @@ -0,0 +1,34 @@ +Avionic Design N-bit GPIO expander bindings + +Required properties: +- compatible: should be "ad,gpio-adnp" +- reg: The I2C slave address for this device. +- interrupt-parent: phandle of the parent interrupt controller. +- interrupts: Interrupt specifier for the controllers interrupt. +- #gpio-cells: Should be 2. The first cell is the GPIO number and the +  second cell is used to specify optional parameters: +  - bit 0: polarity (0: normal, 1: inverted) +- gpio-controller: Marks the device as a GPIO controller +- nr-gpios: The number of pins supported by the controller. + +The GPIO expander can optionally be used as an interrupt controller, in +which case it uses the default two cell specifier as described in +Documentation/devicetree/bindings/interrupt-controller/interrupts.txt. + +Example: + +	gpioext: gpio-controller@41 { +		compatible = "ad,gpio-adnp"; +		reg = <0x41>; + +		interrupt-parent = <&gpio>; +		interrupts = <160 1>; + +		gpio-controller; +		#gpio-cells = <2>; + +		interrupt-controller; +		#interrupt-cells = <2>; + +		nr-gpios = <64>; +	}; diff --git a/Documentation/devicetree/bindings/gpio/led.txt b/Documentation/devicetree/bindings/gpio/led.txt index 9bb308abd22..edc83c1c0d5 100644 --- a/Documentation/devicetree/bindings/gpio/led.txt +++ b/Documentation/devicetree/bindings/gpio/led.txt @@ -8,7 +8,7 @@ node's name represents the name of the corresponding LED.  LED sub-node properties:  - gpios :  Should specify the LED's GPIO, see "gpios property" in -  Documentation/devicetree/gpio.txt.  Active low LEDs should be +  Documentation/devicetree/bindings/gpio/gpio.txt.  Active low LEDs should be    indicated using flags in the GPIO specifier.  - label :  (optional) The label for this LED.  If omitted, the label is    taken from the node name (excluding the unit address). diff --git a/arch/arm/configs/kzm9g_defconfig b/arch/arm/configs/kzm9g_defconfig index 5d0c6670896..c88b57886e7 100644 --- a/arch/arm/configs/kzm9g_defconfig +++ b/arch/arm/configs/kzm9g_defconfig @@ -23,7 +23,6 @@ CONFIG_MODULE_UNLOAD=y  # CONFIG_IOSCHED_DEADLINE is not set  # CONFIG_IOSCHED_CFQ is not set  CONFIG_ARCH_SHMOBILE=y -CONFIG_KEYBOARD_GPIO_POLLED=y  CONFIG_ARCH_SH73A0=y  CONFIG_MACH_KZM9G=y  CONFIG_MEMORY_START=0x41000000 @@ -71,6 +70,7 @@ CONFIG_INPUT_SPARSEKMAP=y  # CONFIG_INPUT_MOUSEDEV is not set  CONFIG_INPUT_EVDEV=y  # CONFIG_KEYBOARD_ATKBD is not set +CONFIG_KEYBOARD_GPIO=y  # CONFIG_INPUT_MOUSE is not set  CONFIG_INPUT_TOUCHSCREEN=y  CONFIG_TOUCHSCREEN_ST1232=y diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c index 773a2b95a4e..0a43f3189c2 100644 --- a/arch/arm/mach-shmobile/board-kzm9g.c +++ b/arch/arm/mach-shmobile/board-kzm9g.c @@ -482,12 +482,10 @@ static struct gpio_keys_button gpio_buttons[] = {  static struct gpio_keys_platform_data gpio_key_info = {  	.buttons	= gpio_buttons,  	.nbuttons	= ARRAY_SIZE(gpio_buttons), -	.poll_interval	= 250, /* poling at this point */  };  static struct platform_device gpio_keys_device = { -	/* gpio-pcf857x.c driver doesn't support gpio_to_irq() */ -	.name	= "gpio-keys-polled", +	.name	= "gpio-keys",  	.dev	= {  		.platform_data  = &gpio_key_info,  	}, @@ -550,6 +548,7 @@ static struct platform_device fsi_ak4648_device = {  /* I2C */  static struct pcf857x_platform_data pcf8575_pdata = {  	.gpio_base	= GPIO_PCF8575_BASE, +	.irq		= intcs_evt2irq(0x3260), /* IRQ19 */  };  static struct i2c_board_info i2c0_devices[] = { diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index a00b828b164..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. @@ -330,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. @@ -450,6 +451,17 @@ config GPIO_ADP5588_IRQ  	  Say yes here to enable the adp5588 to be used as an interrupt  	  controller. It requires the driver to be built in the kernel. +config GPIO_ADNP +	tristate "Avionic Design N-bit GPIO expander" +	depends on I2C && OF +	help +	  This option enables support for N GPIOs found on Avionic Design +	  I2C GPIO expanders. The register space will be extended by powers +	  of two, so the controller will need to accomodate for that. For +	  example: if a controller provides 48 pins, 6 registers will be +	  enough to represent all pins, but the driver will assume a +	  register layout for 64 pins (8 registers). +  comment "PCI GPIO expanders:"  config GPIO_CS5535 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index a288142ad99..0ffaa8423e8 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_GPIO_GENERIC)	+= gpio-generic.o  obj-$(CONFIG_GPIO_74X164)	+= gpio-74x164.o  obj-$(CONFIG_GPIO_AB8500)	+= gpio-ab8500.o +obj-$(CONFIG_GPIO_ADNP)		+= gpio-adnp.o  obj-$(CONFIG_GPIO_ADP5520)	+= gpio-adp5520.o  obj-$(CONFIG_GPIO_ADP5588)	+= gpio-adp5588.o  obj-$(CONFIG_GPIO_AMD8111)	+= gpio-amd8111.o 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-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 ec48ed51262..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; diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index ed94b4ea72e..3644e0dcb3d 100644 --- a/drivers/gpio/gpio-lpc32xx.c +++ b/drivers/gpio/gpio-lpc32xx.c @@ -113,7 +113,8 @@ static const char *gpi_p3_names[LPC32XX_GPI_P3_MAX] = {  	 NULL,    NULL,    NULL,   "gpi15",  	"gpi16", "gpi17", "gpi18", "gpi19",  	"gpi20", "gpi21", "gpi22", "gpi23", -	"gpi24", "gpi25", "gpi26", "gpi27" +	"gpi24", "gpi25", "gpi26", "gpi27", +	"gpi28"  };  static const char *gpo_p3_names[LPC32XX_GPO_P3_MAX] = { diff --git a/drivers/gpio/gpio-mc9s08dz60.c b/drivers/gpio/gpio-mc9s08dz60.c index 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-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-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 076e236d0da..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,7 +65,12 @@ struct pcf857x {  	struct gpio_chip	chip;  	struct i2c_client	*client;  	struct mutex		lock;		/* protect 'out' */ +	struct work_struct	work;		/* irq demux work */ +	struct irq_domain	*irq_domain;	/* for irq demux  */ +	spinlock_t		slock;		/* protect irq demux */  	unsigned		out;		/* software latch */ +	unsigned		status;		/* current status */ +	int			irq;		/* real irq number */  	int (*write)(struct i2c_client *client, unsigned data);  	int (*read)(struct i2c_client *client); @@ -150,6 +160,100 @@ static void pcf857x_set(struct gpio_chip *chip, unsigned offset, int value)  /*-------------------------------------------------------------------------*/ +static int pcf857x_to_irq(struct gpio_chip *chip, unsigned offset) +{ +	struct pcf857x *gpio = container_of(chip, struct pcf857x, chip); + +	return irq_create_mapping(gpio->irq_domain, offset); +} + +static void pcf857x_irq_demux_work(struct work_struct *work) +{ +	struct pcf857x *gpio = container_of(work, +					       struct pcf857x, +					       work); +	unsigned long change, i, status, flags; + +	status = gpio->read(gpio->client); + +	spin_lock_irqsave(&gpio->slock, flags); + +	change = gpio->status ^ status; +	for_each_set_bit(i, &change, gpio->chip.ngpio) +		generic_handle_irq(irq_find_mapping(gpio->irq_domain, i)); +	gpio->status = status; + +	spin_unlock_irqrestore(&gpio->slock, flags); +} + +static irqreturn_t pcf857x_irq_demux(int irq, void *data) +{ +	struct pcf857x	*gpio = data; + +	/* +	 * pcf857x can't read/write data here, +	 * since i2c data access might go to sleep. +	 */ +	schedule_work(&gpio->work); + +	return IRQ_HANDLED; +} + +static int pcf857x_irq_domain_map(struct irq_domain *domain, unsigned int virq, +				 irq_hw_number_t hw) +{ +	irq_set_chip_and_handler(virq, +				 &dummy_irq_chip, +				 handle_level_irq); +	return 0; +} + +static struct irq_domain_ops pcf857x_irq_domain_ops = { +	.map	= pcf857x_irq_domain_map, +}; + +static void pcf857x_irq_domain_cleanup(struct pcf857x *gpio) +{ +	if (gpio->irq_domain) +		irq_domain_remove(gpio->irq_domain); + +	if (gpio->irq) +		free_irq(gpio->irq, gpio); +} + +static int pcf857x_irq_domain_init(struct pcf857x *gpio, +				   struct pcf857x_platform_data *pdata, +				   struct device *dev) +{ +	int status; + +	gpio->irq_domain = irq_domain_add_linear(dev->of_node, +						 gpio->chip.ngpio, +						 &pcf857x_irq_domain_ops, +						 NULL); +	if (!gpio->irq_domain) +		goto fail; + +	/* enable real irq */ +	status = request_irq(pdata->irq, pcf857x_irq_demux, 0, +			     dev_name(dev), gpio); +	if (status) +		goto fail; + +	/* enable gpio_to_irq() */ +	INIT_WORK(&gpio->work, pcf857x_irq_demux_work); +	gpio->chip.to_irq	= pcf857x_to_irq; +	gpio->irq		= pdata->irq; + +	return 0; + +fail: +	pcf857x_irq_domain_cleanup(gpio); +	return -EINVAL; +} + +/*-------------------------------------------------------------------------*/ +  static int pcf857x_probe(struct i2c_client *client,  			 const struct i2c_device_id *id)  { @@ -168,6 +272,7 @@ static int pcf857x_probe(struct i2c_client *client,  		return -ENOMEM;  	mutex_init(&gpio->lock); +	spin_lock_init(&gpio->slock);  	gpio->chip.base			= pdata ? pdata->gpio_base : -1;  	gpio->chip.can_sleep		= 1; @@ -179,6 +284,15 @@ static int pcf857x_probe(struct i2c_client *client,  	gpio->chip.direction_output	= pcf857x_output;  	gpio->chip.ngpio		= id->driver_data; +	/* enable gpio_to_irq() if platform has settings */ +	if (pdata && pdata->irq) { +		status = pcf857x_irq_domain_init(gpio, pdata, &client->dev); +		if (status < 0) { +			dev_err(&client->dev, "irq_domain init failed\n"); +			goto fail; +		} +	} +  	/* NOTE:  the OnSemi jlc1562b is also largely compatible with  	 * these parts, notably for output.  It has a low-resolution  	 * DAC instead of pin change IRQs; and its inputs can be the @@ -248,6 +362,7 @@ static int pcf857x_probe(struct i2c_client *client,  	 * all-ones reset state.  Otherwise it flags pins to be driven low.  	 */  	gpio->out = pdata ? ~pdata->n_latch : ~0; +	gpio->status = gpio->out;  	status = gpiochip_add(&gpio->chip);  	if (status < 0) @@ -278,6 +393,10 @@ static int pcf857x_probe(struct i2c_client *client,  fail:  	dev_dbg(&client->dev, "probe error %d for '%s'\n",  			status, client->name); + +	if (pdata && pdata->irq) +		pcf857x_irq_domain_cleanup(gpio); +  	kfree(gpio);  	return status;  } @@ -299,6 +418,9 @@ static int pcf857x_remove(struct i2c_client *client)  		}  	} +	if (pdata && pdata->irq) +		pcf857x_irq_domain_cleanup(gpio); +  	status = gpiochip_remove(&gpio->chip);  	if (status == 0)  		kfree(gpio); diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 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 9528779ca46..98d52cb3fd1 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -370,12 +370,10 @@ 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); @@ -589,19 +587,12 @@ static int __devinit pxa_gpio_probe(struct platform_device *pdev)  		iounmap(gpio_reg_base);  		return PTR_ERR(clk);  	} -	ret = clk_prepare(clk); +	ret = clk_prepare_enable(clk);  	if (ret) {  		clk_put(clk);  		iounmap(gpio_reg_base);  		return ret;  	} -	ret = clk_enable(clk); -	if (ret) { -		clk_unprepare(clk); -		clk_put(clk); -		iounmap(gpio_reg_base); -		return ret; -	}  	/* Initialize GPIO chips */  	info = dev_get_platdata(&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-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-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-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/gpiolib.c b/drivers/gpio/gpiolib.c index de0213c9d11..5d6c71edc73 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1773,56 +1773,102 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)  	}  } -static int gpiolib_show(struct seq_file *s, void *unused) +static void *gpiolib_seq_start(struct seq_file *s, loff_t *pos)  { -	struct gpio_chip	*chip = NULL; -	unsigned		gpio; -	int			started = 0; +	struct gpio_chip *chip = NULL; +	unsigned int gpio; +	void *ret = NULL; +	loff_t index = 0;  	/* REVISIT this isn't locked against gpio_chip removal ... */  	for (gpio = 0; gpio_is_valid(gpio); gpio++) { -		struct device *dev; - -		if (chip == gpio_desc[gpio].chip) +		if (gpio_desc[gpio].chip == chip)  			continue; +  		chip = gpio_desc[gpio].chip;  		if (!chip)  			continue; -		seq_printf(s, "%sGPIOs %d-%d", -				started ? "\n" : "", -				chip->base, chip->base + chip->ngpio - 1); -		dev = chip->dev; -		if (dev) -			seq_printf(s, ", %s/%s", -				dev->bus ? dev->bus->name : "no-bus", -				dev_name(dev)); -		if (chip->label) -			seq_printf(s, ", %s", chip->label); -		if (chip->can_sleep) -			seq_printf(s, ", can sleep"); -		seq_printf(s, ":\n"); +		if (index++ >= *pos) { +			ret = chip; +			break; +		} +	} + +	s->private = ""; -		started = 1; -		if (chip->dbg_show) -			chip->dbg_show(s, chip); -		else -			gpiolib_dbg_show(s, chip); +	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) diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 365ea09ed3b..a9432fc6b8b 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -60,6 +60,8 @@ struct device_node;   * @get: returns value for signal "offset"; for output signals this   *	returns either the value actually sensed, or zero   * @direction_output: configures signal "offset" as output, or returns error + * @set_debounce: optional hook for setting debounce time for specified gpio in + *      interrupt triggered gpio chips   * @set: assigns output value for signal "offset"   * @to_irq: optional hook supporting non-static gpio_to_irq() mappings;   *	implementation may not sleep diff --git a/include/linux/i2c/pcf857x.h b/include/linux/i2c/pcf857x.h index 0767a2a6b2f..781e6bd06c3 100644 --- a/include/linux/i2c/pcf857x.h +++ b/include/linux/i2c/pcf857x.h @@ -10,6 +10,7 @@   * @setup: optional callback issued once the GPIOs are valid   * @teardown: optional callback issued before the GPIOs are invalidated   * @context: optional parameter passed to setup() and teardown() + * @irq: optional interrupt number   *   * In addition to the I2C_BOARD_INFO() state appropriate to each chip,   * the i2c_board_info used with the pcf875x driver must provide its @@ -39,6 +40,8 @@ struct pcf857x_platform_data {  					int gpio, unsigned ngpio,  					void *context);  	void		*context; + +	int		irq;  };  #endif /* __LINUX_PCF857X_H */  |