diff options
author | Daniel Glöckner <dg@emlix.com> | 2009-09-22 19:46:38 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-23 10:39:48 -0400 |
commit | ff77c352ae17768c61cfc36357f0a3904552f11c (patch) | |
tree | 195c102f75445654e87453cbce284b2f658d13a8 /drivers/gpio/gpiolib.c | |
parent | d120c17faeb391f5b4b99af8b1e190619934ecdd (diff) |
gpiolib: allow poll() on value
Many gpio chips allow to generate interrupts when the value of a pin
changes. This patch gives usermode application the opportunity to make
use of this feature by calling poll(2) on the /sys/class/gpio/gpioN/value
sysfs file. The edge to trigger can be set in the edge file in the same
directory. Possible values are "none", "rising", "falling", and "both".
Using level triggers is not possible with current sysfs since nothing
changes the GPIO value (and the IRQ keeps triggering). Edge triggering
will "just work". Note that if there was an event between read() and
poll(), the poll() returns immediately.
Also note that this version only supports true GPIO interrupts. Some
later patch might be able to synthesize this behavior by timer-driven
polling; some systems seem to need that.
[dbrownell@users.sourceforge.net: align ids to 16 bit ids; whitespace]
Signed-off-by: Daniel Glöckner <dg@emlix.com>
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/gpio/gpiolib.c')
-rw-r--r-- | drivers/gpio/gpiolib.c | 208 |
1 files changed, 203 insertions, 5 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index aef6b3d8e2cf..bb11a429394a 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #include <linux/kernel.h> | 1 | #include <linux/kernel.h> |
2 | #include <linux/module.h> | 2 | #include <linux/module.h> |
3 | #include <linux/interrupt.h> | ||
3 | #include <linux/irq.h> | 4 | #include <linux/irq.h> |
4 | #include <linux/spinlock.h> | 5 | #include <linux/spinlock.h> |
5 | #include <linux/device.h> | 6 | #include <linux/device.h> |
@@ -7,6 +8,7 @@ | |||
7 | #include <linux/debugfs.h> | 8 | #include <linux/debugfs.h> |
8 | #include <linux/seq_file.h> | 9 | #include <linux/seq_file.h> |
9 | #include <linux/gpio.h> | 10 | #include <linux/gpio.h> |
11 | #include <linux/idr.h> | ||
10 | 12 | ||
11 | 13 | ||
12 | /* Optional implementation infrastructure for GPIO interfaces. | 14 | /* Optional implementation infrastructure for GPIO interfaces. |
@@ -49,6 +51,13 @@ struct gpio_desc { | |||
49 | #define FLAG_RESERVED 2 | 51 | #define FLAG_RESERVED 2 |
50 | #define FLAG_EXPORT 3 /* protected by sysfs_lock */ | 52 | #define FLAG_EXPORT 3 /* protected by sysfs_lock */ |
51 | #define FLAG_SYSFS 4 /* exported via /sys/class/gpio/control */ | 53 | #define FLAG_SYSFS 4 /* exported via /sys/class/gpio/control */ |
54 | #define FLAG_TRIG_FALL 5 /* trigger on falling edge */ | ||
55 | #define FLAG_TRIG_RISE 6 /* trigger on rising edge */ | ||
56 | |||
57 | #define PDESC_ID_SHIFT 16 /* add new flags before this one */ | ||
58 | |||
59 | #define GPIO_FLAGS_MASK ((1 << PDESC_ID_SHIFT) - 1) | ||
60 | #define GPIO_TRIGGER_MASK (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE)) | ||
52 | 61 | ||
53 | #ifdef CONFIG_DEBUG_FS | 62 | #ifdef CONFIG_DEBUG_FS |
54 | const char *label; | 63 | const char *label; |
@@ -56,6 +65,15 @@ struct gpio_desc { | |||
56 | }; | 65 | }; |
57 | static struct gpio_desc gpio_desc[ARCH_NR_GPIOS]; | 66 | static struct gpio_desc gpio_desc[ARCH_NR_GPIOS]; |
58 | 67 | ||
68 | #ifdef CONFIG_GPIO_SYSFS | ||
69 | struct poll_desc { | ||
70 | struct work_struct work; | ||
71 | struct sysfs_dirent *value_sd; | ||
72 | }; | ||
73 | |||
74 | static struct idr pdesc_idr; | ||
75 | #endif | ||
76 | |||
59 | static inline void desc_set_label(struct gpio_desc *d, const char *label) | 77 | static inline void desc_set_label(struct gpio_desc *d, const char *label) |
60 | { | 78 | { |
61 | #ifdef CONFIG_DEBUG_FS | 79 | #ifdef CONFIG_DEBUG_FS |
@@ -188,10 +206,10 @@ static DEFINE_MUTEX(sysfs_lock); | |||
188 | * /value | 206 | * /value |
189 | * * always readable, subject to hardware behavior | 207 | * * always readable, subject to hardware behavior |
190 | * * may be writable, as zero/nonzero | 208 | * * may be writable, as zero/nonzero |
191 | * | 209 | * /edge |
192 | * REVISIT there will likely be an attribute for configuring async | 210 | * * configures behavior of poll(2) on /value |
193 | * notifications, e.g. to specify polling interval or IRQ trigger type | 211 | * * available only if pin can generate IRQs on input |
194 | * that would for example trigger a poll() on the "value". | 212 | * * is read/write as "none", "falling", "rising", or "both" |
195 | */ | 213 | */ |
196 | 214 | ||
197 | static ssize_t gpio_direction_show(struct device *dev, | 215 | static ssize_t gpio_direction_show(struct device *dev, |
@@ -288,6 +306,175 @@ static ssize_t gpio_value_store(struct device *dev, | |||
288 | static /*const*/ DEVICE_ATTR(value, 0644, | 306 | static /*const*/ DEVICE_ATTR(value, 0644, |
289 | gpio_value_show, gpio_value_store); | 307 | gpio_value_show, gpio_value_store); |
290 | 308 | ||
309 | static irqreturn_t gpio_sysfs_irq(int irq, void *priv) | ||
310 | { | ||
311 | struct work_struct *work = priv; | ||
312 | |||
313 | schedule_work(work); | ||
314 | return IRQ_HANDLED; | ||
315 | } | ||
316 | |||
317 | static void gpio_notify_sysfs(struct work_struct *work) | ||
318 | { | ||
319 | struct poll_desc *pdesc; | ||
320 | |||
321 | pdesc = container_of(work, struct poll_desc, work); | ||
322 | sysfs_notify_dirent(pdesc->value_sd); | ||
323 | } | ||
324 | |||
325 | static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, | ||
326 | unsigned long gpio_flags) | ||
327 | { | ||
328 | struct poll_desc *pdesc; | ||
329 | unsigned long irq_flags; | ||
330 | int ret, irq, id; | ||
331 | |||
332 | if ((desc->flags & GPIO_TRIGGER_MASK) == gpio_flags) | ||
333 | return 0; | ||
334 | |||
335 | irq = gpio_to_irq(desc - gpio_desc); | ||
336 | if (irq < 0) | ||
337 | return -EIO; | ||
338 | |||
339 | id = desc->flags >> PDESC_ID_SHIFT; | ||
340 | pdesc = idr_find(&pdesc_idr, id); | ||
341 | if (pdesc) { | ||
342 | free_irq(irq, &pdesc->work); | ||
343 | cancel_work_sync(&pdesc->work); | ||
344 | } | ||
345 | |||
346 | desc->flags &= ~GPIO_TRIGGER_MASK; | ||
347 | |||
348 | if (!gpio_flags) { | ||
349 | ret = 0; | ||
350 | goto free_sd; | ||
351 | } | ||
352 | |||
353 | irq_flags = IRQF_SHARED; | ||
354 | if (test_bit(FLAG_TRIG_FALL, &gpio_flags)) | ||
355 | irq_flags |= IRQF_TRIGGER_FALLING; | ||
356 | if (test_bit(FLAG_TRIG_RISE, &gpio_flags)) | ||
357 | irq_flags |= IRQF_TRIGGER_RISING; | ||
358 | |||
359 | if (!pdesc) { | ||
360 | pdesc = kmalloc(sizeof(*pdesc), GFP_KERNEL); | ||
361 | if (!pdesc) { | ||
362 | ret = -ENOMEM; | ||
363 | goto err_out; | ||
364 | } | ||
365 | |||
366 | do { | ||
367 | ret = -ENOMEM; | ||
368 | if (idr_pre_get(&pdesc_idr, GFP_KERNEL)) | ||
369 | ret = idr_get_new_above(&pdesc_idr, | ||
370 | pdesc, 1, &id); | ||
371 | } while (ret == -EAGAIN); | ||
372 | |||
373 | if (ret) | ||
374 | goto free_mem; | ||
375 | |||
376 | desc->flags &= GPIO_FLAGS_MASK; | ||
377 | desc->flags |= (unsigned long)id << PDESC_ID_SHIFT; | ||
378 | |||
379 | if (desc->flags >> PDESC_ID_SHIFT != id) { | ||
380 | ret = -ERANGE; | ||
381 | goto free_id; | ||
382 | } | ||
383 | |||
384 | pdesc->value_sd = sysfs_get_dirent(dev->kobj.sd, "value"); | ||
385 | if (!pdesc->value_sd) { | ||
386 | ret = -ENODEV; | ||
387 | goto free_id; | ||
388 | } | ||
389 | INIT_WORK(&pdesc->work, gpio_notify_sysfs); | ||
390 | } | ||
391 | |||
392 | ret = request_irq(irq, gpio_sysfs_irq, irq_flags, | ||
393 | "gpiolib", &pdesc->work); | ||
394 | if (ret) | ||
395 | goto free_sd; | ||
396 | |||
397 | desc->flags |= gpio_flags; | ||
398 | return 0; | ||
399 | |||
400 | free_sd: | ||
401 | sysfs_put(pdesc->value_sd); | ||
402 | free_id: | ||
403 | idr_remove(&pdesc_idr, id); | ||
404 | desc->flags &= GPIO_FLAGS_MASK; | ||
405 | free_mem: | ||
406 | kfree(pdesc); | ||
407 | err_out: | ||
408 | return ret; | ||
409 | } | ||
410 | |||
411 | static const struct { | ||
412 | const char *name; | ||
413 | unsigned long flags; | ||
414 | } trigger_types[] = { | ||
415 | { "none", 0 }, | ||
416 | { "falling", BIT(FLAG_TRIG_FALL) }, | ||
417 | { "rising", BIT(FLAG_TRIG_RISE) }, | ||
418 | { "both", BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE) }, | ||
419 | }; | ||
420 | |||
421 | static ssize_t gpio_edge_show(struct device *dev, | ||
422 | struct device_attribute *attr, char *buf) | ||
423 | { | ||
424 | const struct gpio_desc *desc = dev_get_drvdata(dev); | ||
425 | ssize_t status; | ||
426 | |||
427 | mutex_lock(&sysfs_lock); | ||
428 | |||
429 | if (!test_bit(FLAG_EXPORT, &desc->flags)) | ||
430 | status = -EIO; | ||
431 | else { | ||
432 | int i; | ||
433 | |||
434 | status = 0; | ||
435 | for (i = 0; i < ARRAY_SIZE(trigger_types); i++) | ||
436 | if ((desc->flags & GPIO_TRIGGER_MASK) | ||
437 | == trigger_types[i].flags) { | ||
438 | status = sprintf(buf, "%s\n", | ||
439 | trigger_types[i].name); | ||
440 | break; | ||
441 | } | ||
442 | } | ||
443 | |||
444 | mutex_unlock(&sysfs_lock); | ||
445 | return status; | ||
446 | } | ||
447 | |||
448 | static ssize_t gpio_edge_store(struct device *dev, | ||
449 | struct device_attribute *attr, const char *buf, size_t size) | ||
450 | { | ||
451 | struct gpio_desc *desc = dev_get_drvdata(dev); | ||
452 | ssize_t status; | ||
453 | int i; | ||
454 | |||
455 | for (i = 0; i < ARRAY_SIZE(trigger_types); i++) | ||
456 | if (sysfs_streq(trigger_types[i].name, buf)) | ||
457 | goto found; | ||
458 | return -EINVAL; | ||
459 | |||
460 | found: | ||
461 | mutex_lock(&sysfs_lock); | ||
462 | |||
463 | if (!test_bit(FLAG_EXPORT, &desc->flags)) | ||
464 | status = -EIO; | ||
465 | else { | ||
466 | status = gpio_setup_irq(desc, dev, trigger_types[i].flags); | ||
467 | if (!status) | ||
468 | status = size; | ||
469 | } | ||
470 | |||
471 | mutex_unlock(&sysfs_lock); | ||
472 | |||
473 | return status; | ||
474 | } | ||
475 | |||
476 | static DEVICE_ATTR(edge, 0644, gpio_edge_show, gpio_edge_store); | ||
477 | |||
291 | static const struct attribute *gpio_attrs[] = { | 478 | static const struct attribute *gpio_attrs[] = { |
292 | &dev_attr_direction.attr, | 479 | &dev_attr_direction.attr, |
293 | &dev_attr_value.attr, | 480 | &dev_attr_value.attr, |
@@ -473,7 +660,7 @@ int gpio_export(unsigned gpio, bool direction_may_change) | |||
473 | struct device *dev; | 660 | struct device *dev; |
474 | 661 | ||
475 | dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0), | 662 | dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0), |
476 | desc, ioname ? ioname : "gpio%d", gpio); | 663 | desc, ioname ? ioname : "gpio%d", gpio); |
477 | if (dev) { | 664 | if (dev) { |
478 | if (direction_may_change) | 665 | if (direction_may_change) |
479 | status = sysfs_create_group(&dev->kobj, | 666 | status = sysfs_create_group(&dev->kobj, |
@@ -481,6 +668,14 @@ int gpio_export(unsigned gpio, bool direction_may_change) | |||
481 | else | 668 | else |
482 | status = device_create_file(dev, | 669 | status = device_create_file(dev, |
483 | &dev_attr_value); | 670 | &dev_attr_value); |
671 | |||
672 | if (!status && gpio_to_irq(gpio) >= 0 | ||
673 | && (direction_may_change | ||
674 | || !test_bit(FLAG_IS_OUT, | ||
675 | &desc->flags))) | ||
676 | status = device_create_file(dev, | ||
677 | &dev_attr_edge); | ||
678 | |||
484 | if (status != 0) | 679 | if (status != 0) |
485 | device_unregister(dev); | 680 | device_unregister(dev); |
486 | } else | 681 | } else |
@@ -572,6 +767,7 @@ void gpio_unexport(unsigned gpio) | |||
572 | 767 | ||
573 | dev = class_find_device(&gpio_class, NULL, desc, match_export); | 768 | dev = class_find_device(&gpio_class, NULL, desc, match_export); |
574 | if (dev) { | 769 | if (dev) { |
770 | gpio_setup_irq(desc, dev, 0); | ||
575 | clear_bit(FLAG_EXPORT, &desc->flags); | 771 | clear_bit(FLAG_EXPORT, &desc->flags); |
576 | put_device(dev); | 772 | put_device(dev); |
577 | device_unregister(dev); | 773 | device_unregister(dev); |
@@ -656,6 +852,8 @@ static int __init gpiolib_sysfs_init(void) | |||
656 | unsigned long flags; | 852 | unsigned long flags; |
657 | unsigned gpio; | 853 | unsigned gpio; |
658 | 854 | ||
855 | idr_init(&pdesc_idr); | ||
856 | |||
659 | status = class_register(&gpio_class); | 857 | status = class_register(&gpio_class); |
660 | if (status < 0) | 858 | if (status < 0) |
661 | return status; | 859 | return status; |