103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent/*
203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent * Copyright (C) ST-Ericsson SA 2010
303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent *
403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent * License Terms: GNU General Public License, version 2
503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent */
703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent#include <linux/module.h>
903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent#include <linux/init.h>
1003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent#include <linux/platform_device.h>
1103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent#include <linux/slab.h>
1203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent#include <linux/gpio.h>
1303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent#include <linux/irq.h>
1403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent#include <linux/interrupt.h>
1503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent#include <linux/mfd/stmpe.h>
1603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
1703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent/*
1803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent * These registers are modified under the irq bus lock and cached to avoid
1903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent * unnecessary writes in bus_sync_unlock.
2003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent */
2103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincentenum { REG_RE, REG_FE, REG_IE };
2203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
2303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent#define CACHE_NR_REGS	3
2403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent#define CACHE_NR_BANKS	(STMPE_NR_GPIOS / 8)
2503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
2603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincentstruct stmpe_gpio {
2703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	struct gpio_chip chip;
2803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	struct stmpe *stmpe;
2903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	struct device *dev;
3003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	struct mutex irq_lock;
3103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
3203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	int irq_base;
33b8e9cf0b28173fc25dae9f3ac44de6fc4e9fc385Wolfram Sang	unsigned norequest_mask;
3403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
3503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	/* Caches of interrupt control registers for bus_lock */
3603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS];
3703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS];
3803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent};
3903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
4003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincentstatic inline struct stmpe_gpio *to_stmpe_gpio(struct gpio_chip *chip)
4103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent{
4203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	return container_of(chip, struct stmpe_gpio, chip);
4303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent}
4403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
4503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincentstatic int stmpe_gpio_get(struct gpio_chip *chip, unsigned offset)
4603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent{
4703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
4803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	struct stmpe *stmpe = stmpe_gpio->stmpe;
4903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	u8 reg = stmpe->regs[STMPE_IDX_GPMR_LSB] - (offset / 8);
5003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	u8 mask = 1 << (offset % 8);
5103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	int ret;
5203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
5303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	ret = stmpe_reg_read(stmpe, reg);
5403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	if (ret < 0)
5503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		return ret;
5603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
5703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	return ret & mask;
5803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent}
5903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
6003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincentstatic void stmpe_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
6103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent{
6203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
6303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	struct stmpe *stmpe = stmpe_gpio->stmpe;
6403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	int which = val ? STMPE_IDX_GPSR_LSB : STMPE_IDX_GPCR_LSB;
6503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	u8 reg = stmpe->regs[which] - (offset / 8);
6603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	u8 mask = 1 << (offset % 8);
6703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
68cccdceb938b37a415c42a0635b8a19893a3a19bbViresh Kumar	/*
69cccdceb938b37a415c42a0635b8a19893a3a19bbViresh Kumar	 * Some variants have single register for gpio set/clear functionality.
70cccdceb938b37a415c42a0635b8a19893a3a19bbViresh Kumar	 * For them we need to write 0 to clear and 1 to set.
71cccdceb938b37a415c42a0635b8a19893a3a19bbViresh Kumar	 */
72cccdceb938b37a415c42a0635b8a19893a3a19bbViresh Kumar	if (stmpe->regs[STMPE_IDX_GPSR_LSB] == stmpe->regs[STMPE_IDX_GPCR_LSB])
73cccdceb938b37a415c42a0635b8a19893a3a19bbViresh Kumar		stmpe_set_bits(stmpe, reg, mask, val ? mask : 0);
74cccdceb938b37a415c42a0635b8a19893a3a19bbViresh Kumar	else
75cccdceb938b37a415c42a0635b8a19893a3a19bbViresh Kumar		stmpe_reg_write(stmpe, reg, mask);
7603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent}
7703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
7803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincentstatic int stmpe_gpio_direction_output(struct gpio_chip *chip,
7903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent					 unsigned offset, int val)
8003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent{
8103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
8203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	struct stmpe *stmpe = stmpe_gpio->stmpe;
8303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
8403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	u8 mask = 1 << (offset % 8);
8503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
8603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	stmpe_gpio_set(chip, offset, val);
8703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
8803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	return stmpe_set_bits(stmpe, reg, mask, mask);
8903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent}
9003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
9103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincentstatic int stmpe_gpio_direction_input(struct gpio_chip *chip,
9203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent					unsigned offset)
9303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent{
9403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
9503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	struct stmpe *stmpe = stmpe_gpio->stmpe;
9603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
9703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	u8 mask = 1 << (offset % 8);
9803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
9903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	return stmpe_set_bits(stmpe, reg, mask, 0);
10003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent}
10103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
10203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincentstatic int stmpe_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
10303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent{
10403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
10503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
10603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	return stmpe_gpio->irq_base + offset;
10703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent}
10803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
10903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincentstatic int stmpe_gpio_request(struct gpio_chip *chip, unsigned offset)
11003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent{
11103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
11203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	struct stmpe *stmpe = stmpe_gpio->stmpe;
11303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
114b8e9cf0b28173fc25dae9f3ac44de6fc4e9fc385Wolfram Sang	if (stmpe_gpio->norequest_mask & (1 << offset))
115b8e9cf0b28173fc25dae9f3ac44de6fc4e9fc385Wolfram Sang		return -EINVAL;
116b8e9cf0b28173fc25dae9f3ac44de6fc4e9fc385Wolfram Sang
11703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	return stmpe_set_altfunc(stmpe, 1 << offset, STMPE_BLOCK_GPIO);
11803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent}
11903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
12003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincentstatic struct gpio_chip template_chip = {
12103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	.label			= "stmpe",
12203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	.owner			= THIS_MODULE,
12303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	.direction_input	= stmpe_gpio_direction_input,
12403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	.get			= stmpe_gpio_get,
12503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	.direction_output	= stmpe_gpio_direction_output,
12603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	.set			= stmpe_gpio_set,
12703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	.to_irq			= stmpe_gpio_to_irq,
12803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	.request		= stmpe_gpio_request,
12903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	.can_sleep		= 1,
13003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent};
13103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
1322a866f39146a5613d5c2db9031c13c218a4c7402Lennert Buytenhekstatic int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type)
13303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent{
1342a866f39146a5613d5c2db9031c13c218a4c7402Lennert Buytenhek	struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
1352a866f39146a5613d5c2db9031c13c218a4c7402Lennert Buytenhek	int offset = d->irq - stmpe_gpio->irq_base;
13603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	int regoffset = offset / 8;
13703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	int mask = 1 << (offset % 8);
13803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
13903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH)
14003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		return -EINVAL;
14103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
142cccdceb938b37a415c42a0635b8a19893a3a19bbViresh Kumar	/* STMPE801 doesn't have RE and FE registers */
143cccdceb938b37a415c42a0635b8a19893a3a19bbViresh Kumar	if (stmpe_gpio->stmpe->partnum == STMPE801)
144cccdceb938b37a415c42a0635b8a19893a3a19bbViresh Kumar		return 0;
145cccdceb938b37a415c42a0635b8a19893a3a19bbViresh Kumar
14603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	if (type == IRQ_TYPE_EDGE_RISING)
14703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		stmpe_gpio->regs[REG_RE][regoffset] |= mask;
14803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	else
14903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		stmpe_gpio->regs[REG_RE][regoffset] &= ~mask;
15003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
15103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	if (type == IRQ_TYPE_EDGE_FALLING)
15203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		stmpe_gpio->regs[REG_FE][regoffset] |= mask;
15303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	else
15403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		stmpe_gpio->regs[REG_FE][regoffset] &= ~mask;
15503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
15603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	return 0;
15703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent}
15803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
1592a866f39146a5613d5c2db9031c13c218a4c7402Lennert Buytenhekstatic void stmpe_gpio_irq_lock(struct irq_data *d)
16003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent{
1612a866f39146a5613d5c2db9031c13c218a4c7402Lennert Buytenhek	struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
16203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
16303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	mutex_lock(&stmpe_gpio->irq_lock);
16403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent}
16503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
1662a866f39146a5613d5c2db9031c13c218a4c7402Lennert Buytenhekstatic void stmpe_gpio_irq_sync_unlock(struct irq_data *d)
16703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent{
1682a866f39146a5613d5c2db9031c13c218a4c7402Lennert Buytenhek	struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
16903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	struct stmpe *stmpe = stmpe_gpio->stmpe;
17003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
17103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	static const u8 regmap[] = {
17203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		[REG_RE]	= STMPE_IDX_GPRER_LSB,
17303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		[REG_FE]	= STMPE_IDX_GPFER_LSB,
17403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		[REG_IE]	= STMPE_IDX_IEGPIOR_LSB,
17503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	};
17603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	int i, j;
17703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
17803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	for (i = 0; i < CACHE_NR_REGS; i++) {
179cccdceb938b37a415c42a0635b8a19893a3a19bbViresh Kumar		/* STMPE801 doesn't have RE and FE registers */
180cccdceb938b37a415c42a0635b8a19893a3a19bbViresh Kumar		if ((stmpe->partnum == STMPE801) &&
181cccdceb938b37a415c42a0635b8a19893a3a19bbViresh Kumar				(i != REG_IE))
182cccdceb938b37a415c42a0635b8a19893a3a19bbViresh Kumar			continue;
183cccdceb938b37a415c42a0635b8a19893a3a19bbViresh Kumar
18403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		for (j = 0; j < num_banks; j++) {
18503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent			u8 old = stmpe_gpio->oldregs[i][j];
18603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent			u8 new = stmpe_gpio->regs[i][j];
18703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
18803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent			if (new == old)
18903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent				continue;
19003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
19103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent			stmpe_gpio->oldregs[i][j] = new;
19203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent			stmpe_reg_write(stmpe, stmpe->regs[regmap[i]] - j, new);
19303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		}
19403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	}
19503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
19603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	mutex_unlock(&stmpe_gpio->irq_lock);
19703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent}
19803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
1992a866f39146a5613d5c2db9031c13c218a4c7402Lennert Buytenhekstatic void stmpe_gpio_irq_mask(struct irq_data *d)
20003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent{
2012a866f39146a5613d5c2db9031c13c218a4c7402Lennert Buytenhek	struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
2022a866f39146a5613d5c2db9031c13c218a4c7402Lennert Buytenhek	int offset = d->irq - stmpe_gpio->irq_base;
20303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	int regoffset = offset / 8;
20403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	int mask = 1 << (offset % 8);
20503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
20603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	stmpe_gpio->regs[REG_IE][regoffset] &= ~mask;
20703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent}
20803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
2092a866f39146a5613d5c2db9031c13c218a4c7402Lennert Buytenhekstatic void stmpe_gpio_irq_unmask(struct irq_data *d)
21003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent{
2112a866f39146a5613d5c2db9031c13c218a4c7402Lennert Buytenhek	struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
2122a866f39146a5613d5c2db9031c13c218a4c7402Lennert Buytenhek	int offset = d->irq - stmpe_gpio->irq_base;
21303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	int regoffset = offset / 8;
21403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	int mask = 1 << (offset % 8);
21503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
21603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	stmpe_gpio->regs[REG_IE][regoffset] |= mask;
21703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent}
21803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
21903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincentstatic struct irq_chip stmpe_gpio_irq_chip = {
22003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	.name			= "stmpe-gpio",
2212a866f39146a5613d5c2db9031c13c218a4c7402Lennert Buytenhek	.irq_bus_lock		= stmpe_gpio_irq_lock,
2222a866f39146a5613d5c2db9031c13c218a4c7402Lennert Buytenhek	.irq_bus_sync_unlock	= stmpe_gpio_irq_sync_unlock,
2232a866f39146a5613d5c2db9031c13c218a4c7402Lennert Buytenhek	.irq_mask		= stmpe_gpio_irq_mask,
2242a866f39146a5613d5c2db9031c13c218a4c7402Lennert Buytenhek	.irq_unmask		= stmpe_gpio_irq_unmask,
2252a866f39146a5613d5c2db9031c13c218a4c7402Lennert Buytenhek	.irq_set_type		= stmpe_gpio_irq_set_type,
22603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent};
22703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
22803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincentstatic irqreturn_t stmpe_gpio_irq(int irq, void *dev)
22903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent{
23003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	struct stmpe_gpio *stmpe_gpio = dev;
23103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	struct stmpe *stmpe = stmpe_gpio->stmpe;
23203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	u8 statmsbreg = stmpe->regs[STMPE_IDX_ISGPIOR_MSB];
23303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
23403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	u8 status[num_banks];
23503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	int ret;
23603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	int i;
23703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
23803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	ret = stmpe_block_read(stmpe, statmsbreg, num_banks, status);
23903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	if (ret < 0)
24003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		return IRQ_NONE;
24103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
24203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	for (i = 0; i < num_banks; i++) {
24303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		int bank = num_banks - i - 1;
24403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		unsigned int enabled = stmpe_gpio->regs[REG_IE][bank];
24503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		unsigned int stat = status[i];
24603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
24703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		stat &= enabled;
24803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		if (!stat)
24903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent			continue;
25003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
25103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		while (stat) {
25203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent			int bit = __ffs(stat);
25303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent			int line = bank * 8 + bit;
25403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
25503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent			handle_nested_irq(stmpe_gpio->irq_base + line);
25603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent			stat &= ~(1 << bit);
25703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		}
25803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
25903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		stmpe_reg_write(stmpe, statmsbreg + i, status[i]);
260cccdceb938b37a415c42a0635b8a19893a3a19bbViresh Kumar
261cccdceb938b37a415c42a0635b8a19893a3a19bbViresh Kumar		/* Edge detect register is not present on 801 */
262cccdceb938b37a415c42a0635b8a19893a3a19bbViresh Kumar		if (stmpe->partnum != STMPE801)
263cccdceb938b37a415c42a0635b8a19893a3a19bbViresh Kumar			stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_GPEDR_MSB]
264cccdceb938b37a415c42a0635b8a19893a3a19bbViresh Kumar					+ i, status[i]);
26503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	}
26603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
26703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	return IRQ_HANDLED;
26803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent}
26903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
27003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincentstatic int __devinit stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio)
27103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent{
27203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	int base = stmpe_gpio->irq_base;
27303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	int irq;
27403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
27503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	for (irq = base; irq < base + stmpe_gpio->chip.ngpio; irq++) {
276b51804bcf0774a8bc6af1e8bb6ae818f4b71173aThomas Gleixner		irq_set_chip_data(irq, stmpe_gpio);
277b51804bcf0774a8bc6af1e8bb6ae818f4b71173aThomas Gleixner		irq_set_chip_and_handler(irq, &stmpe_gpio_irq_chip,
27803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent					 handle_simple_irq);
279b51804bcf0774a8bc6af1e8bb6ae818f4b71173aThomas Gleixner		irq_set_nested_thread(irq, 1);
28003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent#ifdef CONFIG_ARM
28103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		set_irq_flags(irq, IRQF_VALID);
28203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent#else
283b51804bcf0774a8bc6af1e8bb6ae818f4b71173aThomas Gleixner		irq_set_noprobe(irq);
28403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent#endif
28503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	}
28603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
28703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	return 0;
28803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent}
28903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
29003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincentstatic void stmpe_gpio_irq_remove(struct stmpe_gpio *stmpe_gpio)
29103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent{
29203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	int base = stmpe_gpio->irq_base;
29303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	int irq;
29403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
29503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	for (irq = base; irq < base + stmpe_gpio->chip.ngpio; irq++) {
29603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent#ifdef CONFIG_ARM
29703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		set_irq_flags(irq, 0);
29803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent#endif
299b51804bcf0774a8bc6af1e8bb6ae818f4b71173aThomas Gleixner		irq_set_chip_and_handler(irq, NULL, NULL);
300b51804bcf0774a8bc6af1e8bb6ae818f4b71173aThomas Gleixner		irq_set_chip_data(irq, NULL);
30103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	}
30203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent}
30303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
30403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincentstatic int __devinit stmpe_gpio_probe(struct platform_device *pdev)
30503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent{
30603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
30703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	struct stmpe_gpio_platform_data *pdata;
30803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	struct stmpe_gpio *stmpe_gpio;
30903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	int ret;
31003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	int irq;
31103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
31203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	pdata = stmpe->pdata->gpio;
31303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
31403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	irq = platform_get_irq(pdev, 0);
31503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	if (irq < 0)
31603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		return irq;
31703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
31803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	stmpe_gpio = kzalloc(sizeof(struct stmpe_gpio), GFP_KERNEL);
31903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	if (!stmpe_gpio)
32003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		return -ENOMEM;
32103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
32203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	mutex_init(&stmpe_gpio->irq_lock);
32303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
32403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	stmpe_gpio->dev = &pdev->dev;
32503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	stmpe_gpio->stmpe = stmpe;
326b8e9cf0b28173fc25dae9f3ac44de6fc4e9fc385Wolfram Sang	stmpe_gpio->norequest_mask = pdata ? pdata->norequest_mask : 0;
32703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
32803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	stmpe_gpio->chip = template_chip;
32903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	stmpe_gpio->chip.ngpio = stmpe->num_gpios;
33003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	stmpe_gpio->chip.dev = &pdev->dev;
33103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1;
33203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
33303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0);
33403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
33503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	ret = stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
33603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	if (ret)
33702bf07492341d94e29890082201dd69dbf406570Vasiliy Kulikov		goto out_free;
33803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
33903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	ret = stmpe_gpio_irq_init(stmpe_gpio);
34003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	if (ret)
34102bf07492341d94e29890082201dd69dbf406570Vasiliy Kulikov		goto out_disable;
34203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
34303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq, IRQF_ONESHOT,
34403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent				   "stmpe-gpio", stmpe_gpio);
34503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	if (ret) {
34603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
34703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		goto out_removeirq;
34803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	}
34903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
35003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	ret = gpiochip_add(&stmpe_gpio->chip);
35103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	if (ret) {
35203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
35303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		goto out_freeirq;
35403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	}
35503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
35603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	if (pdata && pdata->setup)
35703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		pdata->setup(stmpe, stmpe_gpio->chip.base);
35803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
35903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	platform_set_drvdata(pdev, stmpe_gpio);
36003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
36103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	return 0;
36203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
36303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincentout_freeirq:
36403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	free_irq(irq, stmpe_gpio);
36503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincentout_removeirq:
36603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	stmpe_gpio_irq_remove(stmpe_gpio);
36702bf07492341d94e29890082201dd69dbf406570Vasiliy Kulikovout_disable:
36802bf07492341d94e29890082201dd69dbf406570Vasiliy Kulikov	stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
36903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincentout_free:
37003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	kfree(stmpe_gpio);
37103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	return ret;
37203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent}
37303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
37403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincentstatic int __devexit stmpe_gpio_remove(struct platform_device *pdev)
37503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent{
37603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	struct stmpe_gpio *stmpe_gpio = platform_get_drvdata(pdev);
37703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	struct stmpe *stmpe = stmpe_gpio->stmpe;
37803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	struct stmpe_gpio_platform_data *pdata = stmpe->pdata->gpio;
37903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	int irq = platform_get_irq(pdev, 0);
38003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	int ret;
38103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
38203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	if (pdata && pdata->remove)
38303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		pdata->remove(stmpe, stmpe_gpio->chip.base);
38403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
38503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	ret = gpiochip_remove(&stmpe_gpio->chip);
38603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	if (ret < 0) {
38703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		dev_err(stmpe_gpio->dev,
38803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent			"unable to remove gpiochip: %d\n", ret);
38903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent		return ret;
39003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	}
39103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
39203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
39303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
39403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	free_irq(irq, stmpe_gpio);
39503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	stmpe_gpio_irq_remove(stmpe_gpio);
39603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	platform_set_drvdata(pdev, NULL);
39703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	kfree(stmpe_gpio);
39803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
39903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	return 0;
40003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent}
40103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
40203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincentstatic struct platform_driver stmpe_gpio_driver = {
40303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	.driver.name	= "stmpe-gpio",
40403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	.driver.owner	= THIS_MODULE,
40503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	.probe		= stmpe_gpio_probe,
40603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	.remove		= __devexit_p(stmpe_gpio_remove),
40703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent};
40803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
40903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincentstatic int __init stmpe_gpio_init(void)
41003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent{
41103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	return platform_driver_register(&stmpe_gpio_driver);
41203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent}
41303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincentsubsys_initcall(stmpe_gpio_init);
41403f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
41503f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincentstatic void __exit stmpe_gpio_exit(void)
41603f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent{
41703f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent	platform_driver_unregister(&stmpe_gpio_driver);
41803f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent}
41903f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincentmodule_exit(stmpe_gpio_exit);
42003f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin Vincent
42103f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin VincentMODULE_LICENSE("GPL v2");
42203f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin VincentMODULE_DESCRIPTION("STMPExxxx GPIO driver");
42303f822f5e5f5924f4ad372d3e698855c6a9275e0Rabin VincentMODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>");
424