aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Zyngier <maz@misterjones.org>2010-03-05 16:44:36 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2010-03-06 14:26:48 -0500
commit89ea8bbe9c3eb2ea0cb57a4ecf283cab7326f0b0 (patch)
treef06f9594be6e64699ae3d8672d4868b81e25cfa7
parent8c35c89aa3d7e0f253c3a10456a8b075288b4565 (diff)
gpio: pca953x.c: add interrupt handling capability
Most of the GPIO expanders controlled by the pca953x driver are able to report changes on the input pins through an *INT pin. This patch implements the irq_chip functionality (edge detection only). The driver has been tested on an Arcom Zeus. [akpm@linux-foundation.org: the compiler does inlining for us nowadays] Signed-off-by: Marc Zyngier <maz@misterjones.org> Cc: Eric Miao <eric.y.miao@gmail.com> Cc: Haojian Zhuang <haojian.zhuang@gmail.com> Cc: David Brownell <david-b@pacbell.net> Cc: Nate Case <ncase@xes-inc.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/gpio/Kconfig7
-rw-r--r--drivers/gpio/pca953x.c249
-rw-r--r--include/linux/i2c/pca953x.h3
3 files changed, 247 insertions, 12 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index f3549b8779d8..c5cc7d9d88e3 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -134,6 +134,13 @@ config GPIO_PCA953X
134 This driver can also be built as a module. If so, the module 134 This driver can also be built as a module. If so, the module
135 will be called pca953x. 135 will be called pca953x.
136 136
137config GPIO_PCA953X_IRQ
138 bool "Interrupt controller support for PCA953x"
139 depends on GPIO_PCA953X=y
140 help
141 Say yes here to enable the pca953x to be used as an interrupt
142 controller. It requires the driver to be built in the kernel.
143
137config GPIO_PCF857X 144config GPIO_PCF857X
138 tristate "PCF857x, PCA{85,96}7x, and MAX732[89] I2C GPIO expanders" 145 tristate "PCF857x, PCA{85,96}7x, and MAX732[89] I2C GPIO expanders"
139 depends on I2C 146 depends on I2C
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
index 6a2fb3fbb3d9..ab5daab14bc2 100644
--- a/drivers/gpio/pca953x.c
+++ b/drivers/gpio/pca953x.c
@@ -14,6 +14,8 @@
14#include <linux/module.h> 14#include <linux/module.h>
15#include <linux/init.h> 15#include <linux/init.h>
16#include <linux/gpio.h> 16#include <linux/gpio.h>
17#include <linux/interrupt.h>
18#include <linux/irq.h>
17#include <linux/i2c.h> 19#include <linux/i2c.h>
18#include <linux/i2c/pca953x.h> 20#include <linux/i2c/pca953x.h>
19#ifdef CONFIG_OF_GPIO 21#ifdef CONFIG_OF_GPIO
@@ -26,23 +28,28 @@
26#define PCA953X_INVERT 2 28#define PCA953X_INVERT 2
27#define PCA953X_DIRECTION 3 29#define PCA953X_DIRECTION 3
28 30
31#define PCA953X_GPIOS 0x00FF
32#define PCA953X_INT 0x0100
33
29static const struct i2c_device_id pca953x_id[] = { 34static const struct i2c_device_id pca953x_id[] = {
30 { "pca9534", 8, }, 35 { "pca9534", 8 | PCA953X_INT, },
31 { "pca9535", 16, }, 36 { "pca9535", 16 | PCA953X_INT, },
32 { "pca9536", 4, }, 37 { "pca9536", 4, },
33 { "pca9537", 4, }, 38 { "pca9537", 4 | PCA953X_INT, },
34 { "pca9538", 8, }, 39 { "pca9538", 8 | PCA953X_INT, },
35 { "pca9539", 16, }, 40 { "pca9539", 16 | PCA953X_INT, },
36 { "pca9554", 8, }, 41 { "pca9554", 8 | PCA953X_INT, },
37 { "pca9555", 16, }, 42 { "pca9555", 16 | PCA953X_INT, },
38 { "pca9556", 8, }, 43 { "pca9556", 8, },
39 { "pca9557", 8, }, 44 { "pca9557", 8, },
40 45
41 { "max7310", 8, }, 46 { "max7310", 8, },
42 { "max7315", 8, }, 47 { "max7312", 16 | PCA953X_INT, },
43 { "pca6107", 8, }, 48 { "max7313", 16 | PCA953X_INT, },
44 { "tca6408", 8, }, 49 { "max7315", 8 | PCA953X_INT, },
45 { "tca6416", 16, }, 50 { "pca6107", 8 | PCA953X_INT, },
51 { "tca6408", 8 | PCA953X_INT, },
52 { "tca6416", 16 | PCA953X_INT, },
46 /* NYET: { "tca6424", 24, }, */ 53 /* NYET: { "tca6424", 24, }, */
47 { } 54 { }
48}; 55};
@@ -53,6 +60,15 @@ struct pca953x_chip {
53 uint16_t reg_output; 60 uint16_t reg_output;
54 uint16_t reg_direction; 61 uint16_t reg_direction;
55 62
63#ifdef CONFIG_GPIO_PCA953X_IRQ
64 struct mutex irq_lock;
65 uint16_t irq_mask;
66 uint16_t irq_stat;
67 uint16_t irq_trig_raise;
68 uint16_t irq_trig_fall;
69 int irq_base;
70#endif
71
56 struct i2c_client *client; 72 struct i2c_client *client;
57 struct pca953x_platform_data *dyn_pdata; 73 struct pca953x_platform_data *dyn_pdata;
58 struct gpio_chip gpio_chip; 74 struct gpio_chip gpio_chip;
@@ -202,6 +218,210 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
202 gc->names = chip->names; 218 gc->names = chip->names;
203} 219}
204 220
221#ifdef CONFIG_GPIO_PCA953X_IRQ
222static int pca953x_gpio_to_irq(struct gpio_chip *gc, unsigned off)
223{
224 struct pca953x_chip *chip;
225
226 chip = container_of(gc, struct pca953x_chip, gpio_chip);
227 return chip->irq_base + off;
228}
229
230static void pca953x_irq_mask(unsigned int irq)
231{
232 struct pca953x_chip *chip = get_irq_chip_data(irq);
233
234 chip->irq_mask &= ~(1 << (irq - chip->irq_base));
235}
236
237static void pca953x_irq_unmask(unsigned int irq)
238{
239 struct pca953x_chip *chip = get_irq_chip_data(irq);
240
241 chip->irq_mask |= 1 << (irq - chip->irq_base);
242}
243
244static void pca953x_irq_bus_lock(unsigned int irq)
245{
246 struct pca953x_chip *chip = get_irq_chip_data(irq);
247
248 mutex_lock(&chip->irq_lock);
249}
250
251static void pca953x_irq_bus_sync_unlock(unsigned int irq)
252{
253 struct pca953x_chip *chip = get_irq_chip_data(irq);
254
255 mutex_unlock(&chip->irq_lock);
256}
257
258static int pca953x_irq_set_type(unsigned int irq, unsigned int type)
259{
260 struct pca953x_chip *chip = get_irq_chip_data(irq);
261 uint16_t level = irq - chip->irq_base;
262 uint16_t mask = 1 << level;
263
264 if (!(type & IRQ_TYPE_EDGE_BOTH)) {
265 dev_err(&chip->client->dev, "irq %d: unsupported type %d\n",
266 irq, type);
267 return -EINVAL;
268 }
269
270 if (type & IRQ_TYPE_EDGE_FALLING)
271 chip->irq_trig_fall |= mask;
272 else
273 chip->irq_trig_fall &= ~mask;
274
275 if (type & IRQ_TYPE_EDGE_RISING)
276 chip->irq_trig_raise |= mask;
277 else
278 chip->irq_trig_raise &= ~mask;
279
280 return pca953x_gpio_direction_input(&chip->gpio_chip, level);
281}
282
283static struct irq_chip pca953x_irq_chip = {
284 .name = "pca953x",
285 .mask = pca953x_irq_mask,
286 .unmask = pca953x_irq_unmask,
287 .bus_lock = pca953x_irq_bus_lock,
288 .bus_sync_unlock = pca953x_irq_bus_sync_unlock,
289 .set_type = pca953x_irq_set_type,
290};
291
292static uint16_t pca953x_irq_pending(struct pca953x_chip *chip)
293{
294 uint16_t cur_stat;
295 uint16_t old_stat;
296 uint16_t pending;
297 uint16_t trigger;
298 int ret;
299
300 ret = pca953x_read_reg(chip, PCA953X_INPUT, &cur_stat);
301 if (ret)
302 return 0;
303
304 /* Remove output pins from the equation */
305 cur_stat &= chip->reg_direction;
306
307 old_stat = chip->irq_stat;
308 trigger = (cur_stat ^ old_stat) & chip->irq_mask;
309
310 if (!trigger)
311 return 0;
312
313 chip->irq_stat = cur_stat;
314
315 pending = (old_stat & chip->irq_trig_fall) |
316 (cur_stat & chip->irq_trig_raise);
317 pending &= trigger;
318
319 return pending;
320}
321