aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpiolib.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio/gpiolib.c')
-rw-r--r--drivers/gpio/gpiolib.c208
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};
57static struct gpio_desc gpio_desc[ARCH_NR_GPIOS]; 66static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
58 67
68#ifdef CONFIG_GPIO_SYSFS
69struct poll_desc {
70 struct work_struct work;
71 struct sysfs_dirent *value_sd;
72};
73
74static struct idr pdesc_idr;
75#endif
76
59static inline void desc_set_label(struct gpio_desc *d, const char *label) 77static 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
197static ssize_t gpio_direction_show(struct device *dev, 215static ssize_t gpio_direction_show(struct device *dev,
@@ -288,6 +306,175 @@ static ssize_t gpio_value_store(struct device *dev,
288static /*const*/ DEVICE_ATTR(value, 0644, 306static /*const*/ DEVICE_ATTR(value, 0644,
289 gpio_value_show, gpio_value_store); 307 gpio_value_show, gpio_value_store);
290 308
309static 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
317static 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
325static 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
400free_sd:
401 sysfs_put(pdesc->value_sd);
402free_id:
403 idr_remove(&pdesc_idr, id);
404 desc->flags &= GPIO_FLAGS_MASK;
405free_mem:
406 kfree(pdesc);
407err_out:
408 return ret;
409}
410
411static 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
421static 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
448static 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
460found:
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
476static DEVICE_ATTR(edge, 0644, gpio_edge_show, gpio_edge_store);
477
291static const struct attribute *gpio_attrs[] = { 478static 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;