[PATCH 1/2] [GPIOLib] GPIO Interrupt counter support v2

Federico Fuga fuga at studiofuga.com
Wed May 28 03:17:48 PDT 2014


This patch add a per-pin interrupt counter to GPIOs.
This way, GPIOs Interrupt will increment an internal counter that
can be accessed through sysfs. Counter can be read and written
from user space.

Signed-off-by: Federico Fuga <fuga at studiofuga.com>
---
 drivers/gpio/Kconfig       |  9 +++++
 drivers/gpio/gpiolib.c     | 92 ++++++++++++++++++++++++++++++++++++++++++++++
 include/asm-generic/gpio.h | 25 +++++++++++++
 3 files changed, 126 insertions(+)

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index b2450ba..cbdc62e 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -81,6 +81,15 @@ config GPIO_SYSFS
 	  Kernel drivers may also request that a particular GPIO be
 	  exported to userspace; this can be useful when debugging.
 
+config GPIO_COUNTER
+	bool "GPIO Interrupt counter"
+	help
+	  Say Y here to add a per-pin interrupt counter to GPIOs.
+
+	  This way, GPIOs Interrupt will increment an internal counter that
+	  can be accessed through sysfs. Counter can be read and written
+	  from user space.
+
 config GPIO_GENERIC
 	tristate
 
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index ff0fd65..5829f7a 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -69,6 +69,10 @@ struct gpio_desc {
 #ifdef CONFIG_DEBUG_FS
 	const char		*label;
 #endif
+
+#ifdef CONFIG_GPIO_COUNTER
+	unsigned long    counter;    /* IRQ Events counter */
+#endif
 };
 static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
 
@@ -583,9 +587,57 @@ static ssize_t gpio_active_low_store(struct device *dev,
 static const DEVICE_ATTR(active_low, 0644,
 		gpio_active_low_show, gpio_active_low_store);
 
+#ifdef CONFIG_GPIO_COUNTER
+static ssize_t counter_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct gpio_desc	*desc = dev_get_drvdata(dev);
+	ssize_t			status;
+
+	mutex_lock(&sysfs_lock);
+
+	if (!test_bit(FLAG_EXPORT, &desc->flags)) {
+		status = -EIO;
+	} else {
+		long		value;
+
+		status = kstrtol(buf, 10, &value);
+		if (status == 0)
+			desc->counter = value;
+	}
+
+	mutex_unlock(&sysfs_lock);
+
+	return status ? : size;
+
+}
+
+static ssize_t counter_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	const struct gpio_desc	*desc = dev_get_drvdata(dev);
+	ssize_t			status;
+
+	mutex_lock(&sysfs_lock);
+
+	if (!test_bit(FLAG_EXPORT, &desc->flags))
+		status = -EIO;
+	else
+		status = sprintf(buf, "%ld\n", desc->counter);
+
+	mutex_unlock(&sysfs_lock);
+
+	return status;
+}
+static const DEVICE_ATTR_RW(counter);
+#endif
+
 static const struct attribute *gpio_attrs[] = {
 	&dev_attr_value.attr,
 	&dev_attr_active_low.attr,
+#ifdef CONFIG_GPIO_COUNTER
+	&dev_attr_counter.attr,
+#endif
 	NULL,
 };
 
@@ -1114,6 +1166,46 @@ static inline void gpiod_unexport(struct gpio_desc *desc)
 
 #endif /* CONFIG_GPIO_SYSFS */
 
+#ifdef CONFIG_GPIO_COUNTER
+int gpio_counter_inc(unsigned gpio)
+{
+	struct gpio_desc	*desc = gpio_to_desc(gpio);
+
+	mutex_lock(&sysfs_lock);
+	desc->counter++;
+	mutex_unlock(&sysfs_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(gpio_counter_inc);
+
+long gpio_counter_get(unsigned gpio)
+{
+	long ret;
+	struct gpio_desc	*desc = gpio_to_desc(gpio);
+
+	mutex_lock(&sysfs_lock);
+	ret = desc->counter;
+	mutex_unlock(&sysfs_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(gpio_counter_get);
+
+int gpio_counter_set(unsigned gpio, long value)
+{
+	struct gpio_desc	*desc = gpio_to_desc(gpio);
+
+	mutex_lock(&sysfs_lock);
+	desc->counter = value;
+	mutex_unlock(&sysfs_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(gpio_counter_set);
+#endif
+
+
 /*
  * Add a new chip to the global chips list, keeping the list of chips sorted
  * by base order.
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index bde6469..e3e3001 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -210,6 +210,31 @@ extern void gpio_unexport(unsigned gpio);
 
 #endif	/* CONFIG_GPIO_SYSFS */
 
+#ifdef CONFIG_GPIO_COUNTER
+
+extern int gpio_counter_inc(unsigned gpio);
+extern long gpio_counter_get(unsigned gpio);
+extern int gpio_counter_set(unsigned gpio, long value);
+
+#else
+
+static inline int gpio_counter_inc(unsigned gpio)
+{
+	return 0;
+}
+
+static inline long gpio_counter_get(unsigned gpio)
+{
+	return 0;
+}
+
+static inline int gpio_counter_set(unsigned gpio, long value)
+{
+	return 0;
+}
+
+#endif
+
 #ifdef CONFIG_PINCTRL
 
 /**
-- 
1.9.1




More information about the linux-rpi-kernel mailing list