linux-iio.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] iio:trigger: Added iio-hrtimer-trigger
  2013-09-23 10:51 Added hrtimer trigger support Denis CIOCCA
@ 2013-09-23 10:51 ` Denis CIOCCA
  0 siblings, 0 replies; 5+ messages in thread
From: Denis CIOCCA @ 2013-09-23 10:51 UTC (permalink / raw)
  To: jic23, lars; +Cc: linux-iio, Denis Ciocca

This patch adds high resolution timer trigger support for iio framework.

Signed-off-by: Denis Ciocca <denis.ciocca@st.com>
---
 drivers/iio/trigger/Kconfig            |   11 ++
 drivers/iio/trigger/Makefile           |    1 +
 drivers/iio/trigger/iio-trig-hrtimer.c |  282 ++++++++++++++++++++++++++++++++
 3 files changed, 294 insertions(+)
 create mode 100644 drivers/iio/trigger/iio-trig-hrtimer.c

diff --git a/drivers/iio/trigger/Kconfig b/drivers/iio/trigger/Kconfig
index 7999612..ba1d308 100644
--- a/drivers/iio/trigger/Kconfig
+++ b/drivers/iio/trigger/Kconfig
@@ -25,4 +25,15 @@ config IIO_SYSFS_TRIGGER
 	  To compile this driver as a module, choose M here: the
 	  module will be called iio-trig-sysfs.
 
+config IIO_HRTIMER_TRIGGER
+	tristate "HRTIMER trigger"
+	#depends on HRTIMER
+	select IRQ_WORK
+	help
+	  Provides support for using HRTIMER entries as IIO triggers.
+	  If unsure, say N (but it's safe to say "Y").
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called iio-trig-hrtimer.
+
 endmenu
diff --git a/drivers/iio/trigger/Makefile b/drivers/iio/trigger/Makefile
index 0694dae..4e1876d 100644
--- a/drivers/iio/trigger/Makefile
+++ b/drivers/iio/trigger/Makefile
@@ -5,3 +5,4 @@
 # When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_IIO_INTERRUPT_TRIGGER) += iio-trig-interrupt.o
 obj-$(CONFIG_IIO_SYSFS_TRIGGER) += iio-trig-sysfs.o
+obj-$(CONFIG_IIO_HRTIMER_TRIGGER) += iio-trig-hrtimer.o
diff --git a/drivers/iio/trigger/iio-trig-hrtimer.c b/drivers/iio/trigger/iio-trig-hrtimer.c
new file mode 100644
index 0000000..3ee71de
--- /dev/null
+++ b/drivers/iio/trigger/iio-trig-hrtimer.c
@@ -0,0 +1,282 @@
+/*
+ * Industrial I/O - hrtimer trigger support
+ *
+ * Copyright 2013 STMicroelectronics Inc.
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/hrtimer.h>
+#include <linux/ktime.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+
+struct iio_hrtimer_trigger_data {
+	struct iio_trigger *trig;
+	struct hrtimer timer;
+	struct list_head l;
+	ktime_t period;
+	u16  freq;
+	int id;
+};
+
+static LIST_HEAD(iio_hrtimer_trigger_list);
+static DEFINE_MUTEX(iio_hrtimer_trigger_list_mut);
+
+static int iio_hrtimer_trigger_probe(int id);
+static int iio_hrtimer_trigger_remove(int id);
+
+static ssize_t iio_sysfs_hrtimer_trig_add(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t len)
+{
+	int ret;
+	unsigned long input;
+
+	ret = kstrtoul(buf, 10, &input);
+	if (ret)
+		return ret;
+
+	ret = iio_hrtimer_trigger_probe(input);
+	if (ret)
+		return ret;
+
+	return len;
+}
+static DEVICE_ATTR(add_trigger, S_IWUSR, NULL, &iio_sysfs_hrtimer_trig_add);
+
+static ssize_t iio_sysfs_hrtimer_trig_remove(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t len)
+{
+	int ret;
+	unsigned long input;
+
+	ret = kstrtoul(buf, 10, &input);
+	if (ret)
+		return ret;
+
+	ret = iio_hrtimer_trigger_remove(input);
+	if (ret)
+		return ret;
+
+	return len;
+}
+static DEVICE_ATTR(remove_trigger, S_IWUSR,
+					NULL, &iio_sysfs_hrtimer_trig_remove);
+
+static struct attribute *iio_hrtimer_trig_attrs[] = {
+	&dev_attr_add_trigger.attr,
+	&dev_attr_remove_trigger.attr,
+	NULL,
+};
+
+static const struct attribute_group iio_hrtimer_trig_group = {
+	.attrs = iio_hrtimer_trig_attrs,
+};
+
+static const struct attribute_group *iio_hrtimer_trig_groups[] = {
+	&iio_hrtimer_trig_group,
+	NULL,
+};
+
+static struct device iio_hrtimer_trig_dev = {
+	.bus = &iio_bus_type,
+	.groups = iio_hrtimer_trig_groups,
+};
+
+static int iio_hrtimer_trig_set_state(struct iio_trigger *trig, bool state)
+{
+	struct iio_hrtimer_trigger_data *trig_data =
+						iio_trigger_get_drvdata(trig);
+
+	if (trig_data->freq == 0)
+		return -EINVAL;
+
+	if (state)
+		hrtimer_start(&trig_data->timer,
+					trig_data->period, HRTIMER_MODE_REL);
+	else
+		hrtimer_cancel(&trig_data->timer);
+
+	return 0;
+}
+
+static ssize_t iio_hrtimer_trigger_set_freq_value(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t len)
+{
+	int ret;
+	u16 frequency;
+	struct iio_trigger *trig = to_iio_trigger(dev);
+	struct iio_hrtimer_trigger_data *trig_data =
+						iio_trigger_get_drvdata(trig);
+
+	ret = kstrtou16(buf, 10, &frequency);
+	if (ret < 0)
+		return ret;
+
+	if (frequency > NSEC_PER_SEC)
+		return -EINVAL;
+
+	trig_data->freq = frequency;
+
+	if (frequency)
+		trig_data->period =
+				ktime_set(0, NSEC_PER_SEC / trig_data->freq);
+
+	return len;
+}
+
+static ssize_t iio_hrtimer_trigger_get_freq_value(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct iio_trigger *trig = to_iio_trigger(dev);
+	struct iio_hrtimer_trigger_data *trig_data =
+						iio_trigger_get_drvdata(trig);
+
+	return sprintf(buf, "%hu\n", trig_data->freq);
+}
+
+static DEVICE_ATTR(frequency, S_IWUSR | S_IRUGO,
+					iio_hrtimer_trigger_get_freq_value,
+					iio_hrtimer_trigger_set_freq_value);
+
+static struct attribute *iio_hrtimer_trigger_attrs[] = {
+	&dev_attr_frequency.attr,
+	NULL,
+};
+
+static const struct attribute_group iio_hrtimer_trigger_attr_group = {
+	.attrs = iio_hrtimer_trigger_attrs,
+};
+
+static const struct attribute_group *iio_hrtimer_trigger_attr_groups[] = {
+	&iio_hrtimer_trigger_attr_group,
+	NULL,
+};
+
+static const struct iio_trigger_ops iio_hrtimer_trigger_ops = {
+	.owner = THIS_MODULE,
+	.set_trigger_state = &iio_hrtimer_trig_set_state,
+};
+
+enum hrtimer_restart iio_hrtimer_trigger_func(struct hrtimer *timer)
+{
+	struct iio_hrtimer_trigger_data *trig_data;
+
+	trig_data = container_of(timer, struct iio_hrtimer_trigger_data, timer);
+
+	hrtimer_forward_now(timer, trig_data->period);
+	iio_trigger_poll(trig_data->trig, 0);
+
+	return HRTIMER_RESTART;
+}
+
+static int iio_hrtimer_trigger_probe(int id)
+{
+	int err;
+	bool foundit = false;
+	struct iio_hrtimer_trigger_data *trig_data;
+
+	mutex_lock(&iio_hrtimer_trigger_list_mut);
+	list_for_each_entry(trig_data, &iio_hrtimer_trigger_list, l) {
+		if (id == trig_data->id) {
+			foundit = true;
+			break;
+		}
+	}
+	if (foundit) {
+		err = -EINVAL;
+		goto iio_hrtimer_mutex_unlock;
+	}
+
+	trig_data = kmalloc(sizeof(*trig_data), GFP_KERNEL);
+	if (trig_data == NULL) {
+		err = -ENOMEM;
+		goto iio_hrtimer_mutex_unlock;
+	}
+
+	trig_data->id = id;
+	trig_data->trig = iio_trigger_alloc("hrtimer_trig%d", id);
+	if (!trig_data->trig) {
+		err = -ENOMEM;
+		goto iio_hrtimer_free_trig_data;
+	}
+
+	trig_data->trig->dev.groups = iio_hrtimer_trigger_attr_groups;
+	trig_data->trig->ops = &iio_hrtimer_trigger_ops;
+	trig_data->trig->dev.parent = &iio_hrtimer_trig_dev;
+	iio_trigger_set_drvdata(trig_data->trig, trig_data);
+
+	trig_data->freq = 0;
+	hrtimer_init(&trig_data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	trig_data->timer.function = &iio_hrtimer_trigger_func;
+
+	err = iio_trigger_register(trig_data->trig);
+	if (err)
+		goto iio_hrtimer_free_trig_data;
+
+	list_add(&trig_data->l, &iio_hrtimer_trigger_list);
+	__module_get(THIS_MODULE);
+	mutex_unlock(&iio_hrtimer_trigger_list_mut);
+
+	return 0;
+
+iio_hrtimer_free_trig_data:
+	kfree(trig_data);
+iio_hrtimer_mutex_unlock:
+	mutex_unlock(&iio_hrtimer_trigger_list_mut);
+	return err;
+}
+
+static int iio_hrtimer_trigger_remove(int id)
+{
+	bool foundit = false;
+	struct iio_hrtimer_trigger_data *trig_data;
+
+	mutex_lock(&iio_hrtimer_trigger_list_mut);
+	list_for_each_entry(trig_data, &iio_hrtimer_trigger_list, l) {
+		if (id == trig_data->id) {
+			foundit = true;
+			break;
+		}
+	}
+	if (!foundit) {
+		mutex_unlock(&iio_hrtimer_trigger_list_mut);
+		return -EINVAL;
+	}
+
+	iio_trigger_unregister(trig_data->trig);
+	iio_trigger_free(trig_data->trig);
+
+	list_del(&trig_data->l);
+	kfree(trig_data);
+	module_put(THIS_MODULE);
+	mutex_unlock(&iio_hrtimer_trigger_list_mut);
+
+	return 0;
+}
+
+static int __init iio_hrtimer_trig_init(void)
+{
+	device_initialize(&iio_hrtimer_trig_dev);
+	dev_set_name(&iio_hrtimer_trig_dev, "iio_hrtimer_trigger");
+	return device_add(&iio_hrtimer_trig_dev);
+}
+module_init(iio_hrtimer_trig_init);
+
+static void __exit iio_hrtimer_trig_exit(void)
+{
+	device_unregister(&iio_hrtimer_trig_dev);
+}
+module_exit(iio_hrtimer_trig_exit);
+
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
+MODULE_DESCRIPTION("Hrtimer trigger for the iio subsystem");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Added hrtimer trigger v2
@ 2013-09-24  9:26 Denis CIOCCA
  2013-09-24  9:26 ` [PATCH] iio:trigger: Added iio-hrtimer-trigger Denis CIOCCA
  0 siblings, 1 reply; 5+ messages in thread
From: Denis CIOCCA @ 2013-09-24  9:26 UTC (permalink / raw)
  To: jic23, lars, linux-iio

Hi,

This patch is the revision 2 of hrtimer iio trigger.
- Used int as trigger id instead of long;
- Fix Kconfig;
- checked maximium value of frequency (u16);

Thanks,
Denis


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH] iio:trigger: Added iio-hrtimer-trigger
  2013-09-24  9:26 Added hrtimer trigger v2 Denis CIOCCA
@ 2013-09-24  9:26 ` Denis CIOCCA
  2013-09-28 10:13   ` Lars-Peter Clausen
  0 siblings, 1 reply; 5+ messages in thread
From: Denis CIOCCA @ 2013-09-24  9:26 UTC (permalink / raw)
  To: jic23, lars, linux-iio; +Cc: Denis Ciocca

This patch adds high resolution timer trigger support for iio framework.

Signed-off-by: Denis Ciocca <denis.ciocca@st.com>
---
 drivers/iio/trigger/Kconfig            |    9 +
 drivers/iio/trigger/Makefile           |    1 +
 drivers/iio/trigger/iio-trig-hrtimer.c |  284 ++++++++++++++++++++++++++++++++
 3 files changed, 294 insertions(+)
 create mode 100644 drivers/iio/trigger/iio-trig-hrtimer.c

diff --git a/drivers/iio/trigger/Kconfig b/drivers/iio/trigger/Kconfig
index 7999612..131e171 100644
--- a/drivers/iio/trigger/Kconfig
+++ b/drivers/iio/trigger/Kconfig
@@ -25,4 +25,13 @@ config IIO_SYSFS_TRIGGER
 	  To compile this driver as a module, choose M here: the
 	  module will be called iio-trig-sysfs.
 
+config IIO_HRTIMER_TRIGGER
+	tristate "HRTIMER trigger"
+	help
+	  Provides support for using HRTIMER entries as IIO triggers.
+	  If unsure, say N (but it's safe to say "Y").
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called iio-trig-hrtimer.
+
 endmenu
diff --git a/drivers/iio/trigger/Makefile b/drivers/iio/trigger/Makefile
index 0694dae..4e1876d 100644
--- a/drivers/iio/trigger/Makefile
+++ b/drivers/iio/trigger/Makefile
@@ -5,3 +5,4 @@
 # When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_IIO_INTERRUPT_TRIGGER) += iio-trig-interrupt.o
 obj-$(CONFIG_IIO_SYSFS_TRIGGER) += iio-trig-sysfs.o
+obj-$(CONFIG_IIO_HRTIMER_TRIGGER) += iio-trig-hrtimer.o
diff --git a/drivers/iio/trigger/iio-trig-hrtimer.c b/drivers/iio/trigger/iio-trig-hrtimer.c
new file mode 100644
index 0000000..a743672
--- /dev/null
+++ b/drivers/iio/trigger/iio-trig-hrtimer.c
@@ -0,0 +1,284 @@
+/*
+ * Industrial I/O - hrtimer trigger support
+ *
+ * Copyright 2013 STMicroelectronics Inc.
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/hrtimer.h>
+#include <linux/ktime.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+
+#define MAX_UNSIGNED_INT16			(65535U)
+
+struct iio_hrtimer_trigger_data {
+	struct iio_trigger *trig;
+	struct hrtimer timer;
+	struct list_head l;
+	ktime_t period;
+	u16  freq;
+	int id;
+};
+
+static LIST_HEAD(iio_hrtimer_trigger_list);
+static DEFINE_MUTEX(iio_hrtimer_trigger_list_mut);
+
+static int iio_hrtimer_trigger_probe(int id);
+static int iio_hrtimer_trigger_remove(int id);
+
+static ssize_t iio_sysfs_hrtimer_trig_add(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t len)
+{
+	int ret;
+	unsigned int input;
+
+	ret = kstrtouint(buf, 10, &input);
+	if (ret)
+		return ret;
+
+	ret = iio_hrtimer_trigger_probe(input);
+	if (ret)
+		return ret;
+
+	return len;
+}
+static DEVICE_ATTR(add_trigger, S_IWUSR, NULL, &iio_sysfs_hrtimer_trig_add);
+
+static ssize_t iio_sysfs_hrtimer_trig_remove(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t len)
+{
+	int ret;
+	unsigned int input;
+
+	ret = kstrtouint(buf, 10, &input);
+	if (ret)
+		return ret;
+
+	ret = iio_hrtimer_trigger_remove(input);
+	if (ret)
+		return ret;
+
+	return len;
+}
+static DEVICE_ATTR(remove_trigger, S_IWUSR,
+					NULL, &iio_sysfs_hrtimer_trig_remove);
+
+static struct attribute *iio_hrtimer_trig_attrs[] = {
+	&dev_attr_add_trigger.attr,
+	&dev_attr_remove_trigger.attr,
+	NULL,
+};
+
+static const struct attribute_group iio_hrtimer_trig_group = {
+	.attrs = iio_hrtimer_trig_attrs,
+};
+
+static const struct attribute_group *iio_hrtimer_trig_groups[] = {
+	&iio_hrtimer_trig_group,
+	NULL,
+};
+
+static struct device iio_hrtimer_trig_dev = {
+	.bus = &iio_bus_type,
+	.groups = iio_hrtimer_trig_groups,
+};
+
+static int iio_hrtimer_trig_set_state(struct iio_trigger *trig, bool state)
+{
+	struct iio_hrtimer_trigger_data *trig_data =
+						iio_trigger_get_drvdata(trig);
+
+	if (trig_data->freq == 0)
+		return -EINVAL;
+
+	if (state)
+		hrtimer_start(&trig_data->timer,
+					trig_data->period, HRTIMER_MODE_REL);
+	else
+		hrtimer_cancel(&trig_data->timer);
+
+	return 0;
+}
+
+static ssize_t iio_hrtimer_trigger_set_freq_value(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t len)
+{
+	int ret;
+	u16 frequency;
+	struct iio_trigger *trig = to_iio_trigger(dev);
+	struct iio_hrtimer_trigger_data *trig_data =
+						iio_trigger_get_drvdata(trig);
+
+	ret = kstrtou16(buf, 10, &frequency);
+	if (ret < 0)
+		return ret;
+
+	if (frequency > MAX_UNSIGNED_INT16)
+		return -EINVAL;
+
+	trig_data->freq = frequency;
+
+	if (frequency)
+		trig_data->period =
+				ktime_set(0, NSEC_PER_SEC / trig_data->freq);
+
+	return len;
+}
+
+static ssize_t iio_hrtimer_trigger_get_freq_value(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct iio_trigger *trig = to_iio_trigger(dev);
+	struct iio_hrtimer_trigger_data *trig_data =
+						iio_trigger_get_drvdata(trig);
+
+	return sprintf(buf, "%hu\n", trig_data->freq);
+}
+
+static DEVICE_ATTR(frequency, S_IWUSR | S_IRUGO,
+					iio_hrtimer_trigger_get_freq_value,
+					iio_hrtimer_trigger_set_freq_value);
+
+static struct attribute *iio_hrtimer_trigger_attrs[] = {
+	&dev_attr_frequency.attr,
+	NULL,
+};
+
+static const struct attribute_group iio_hrtimer_trigger_attr_group = {
+	.attrs = iio_hrtimer_trigger_attrs,
+};
+
+static const struct attribute_group *iio_hrtimer_trigger_attr_groups[] = {
+	&iio_hrtimer_trigger_attr_group,
+	NULL,
+};
+
+static const struct iio_trigger_ops iio_hrtimer_trigger_ops = {
+	.owner = THIS_MODULE,
+	.set_trigger_state = &iio_hrtimer_trig_set_state,
+};
+
+enum hrtimer_restart iio_hrtimer_trigger_func(struct hrtimer *timer)
+{
+	struct iio_hrtimer_trigger_data *trig_data;
+
+	trig_data = container_of(timer, struct iio_hrtimer_trigger_data, timer);
+
+	hrtimer_forward_now(timer, trig_data->period);
+	iio_trigger_poll(trig_data->trig, 0);
+
+	return HRTIMER_RESTART;
+}
+
+static int iio_hrtimer_trigger_probe(int id)
+{
+	int err;
+	bool foundit = false;
+	struct iio_hrtimer_trigger_data *trig_data;
+
+	mutex_lock(&iio_hrtimer_trigger_list_mut);
+	list_for_each_entry(trig_data, &iio_hrtimer_trigger_list, l) {
+		if (id == trig_data->id) {
+			foundit = true;
+			break;
+		}
+	}
+	if (foundit) {
+		err = -EINVAL;
+		goto iio_hrtimer_mutex_unlock;
+	}
+
+	trig_data = kmalloc(sizeof(*trig_data), GFP_KERNEL);
+	if (trig_data == NULL) {
+		err = -ENOMEM;
+		goto iio_hrtimer_mutex_unlock;
+	}
+
+	trig_data->id = id;
+	trig_data->trig = iio_trigger_alloc("hrtimer_trig%d", id);
+	if (!trig_data->trig) {
+		err = -ENOMEM;
+		goto iio_hrtimer_free_trig_data;
+	}
+
+	trig_data->trig->dev.groups = iio_hrtimer_trigger_attr_groups;
+	trig_data->trig->ops = &iio_hrtimer_trigger_ops;
+	trig_data->trig->dev.parent = &iio_hrtimer_trig_dev;
+	iio_trigger_set_drvdata(trig_data->trig, trig_data);
+
+	trig_data->freq = 0;
+	hrtimer_init(&trig_data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	trig_data->timer.function = &iio_hrtimer_trigger_func;
+
+	err = iio_trigger_register(trig_data->trig);
+	if (err)
+		goto iio_hrtimer_free_trig_data;
+
+	list_add(&trig_data->l, &iio_hrtimer_trigger_list);
+	__module_get(THIS_MODULE);
+	mutex_unlock(&iio_hrtimer_trigger_list_mut);
+
+	return 0;
+
+iio_hrtimer_free_trig_data:
+	kfree(trig_data);
+iio_hrtimer_mutex_unlock:
+	mutex_unlock(&iio_hrtimer_trigger_list_mut);
+	return err;
+}
+
+static int iio_hrtimer_trigger_remove(int id)
+{
+	bool foundit = false;
+	struct iio_hrtimer_trigger_data *trig_data;
+
+	mutex_lock(&iio_hrtimer_trigger_list_mut);
+	list_for_each_entry(trig_data, &iio_hrtimer_trigger_list, l) {
+		if (id == trig_data->id) {
+			foundit = true;
+			break;
+		}
+	}
+	if (!foundit) {
+		mutex_unlock(&iio_hrtimer_trigger_list_mut);
+		return -EINVAL;
+	}
+
+	iio_trigger_unregister(trig_data->trig);
+	iio_trigger_free(trig_data->trig);
+
+	list_del(&trig_data->l);
+	kfree(trig_data);
+	module_put(THIS_MODULE);
+	mutex_unlock(&iio_hrtimer_trigger_list_mut);
+
+	return 0;
+}
+
+static int __init iio_hrtimer_trig_init(void)
+{
+	device_initialize(&iio_hrtimer_trig_dev);
+	dev_set_name(&iio_hrtimer_trig_dev, "iio_hrtimer_trigger");
+	return device_add(&iio_hrtimer_trig_dev);
+}
+module_init(iio_hrtimer_trig_init);
+
+static void __exit iio_hrtimer_trig_exit(void)
+{
+	device_unregister(&iio_hrtimer_trig_dev);
+}
+module_exit(iio_hrtimer_trig_exit);
+
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
+MODULE_DESCRIPTION("Hrtimer trigger for the iio subsystem");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH] iio:trigger: Added iio-hrtimer-trigger
  2013-09-24  9:26 ` [PATCH] iio:trigger: Added iio-hrtimer-trigger Denis CIOCCA
@ 2013-09-28 10:13   ` Lars-Peter Clausen
  0 siblings, 0 replies; 5+ messages in thread
From: Lars-Peter Clausen @ 2013-09-28 10:13 UTC (permalink / raw)
  To: Denis CIOCCA; +Cc: jic23, linux-iio

On 09/24/2013 11:26 AM, Denis CIOCCA wrote:
> This patch adds high resolution timer trigger support for iio framework.
> 

I think the driver is mostly fine (a couple of minor comments inline). But
maybe we should give some more though how we want to deal with the creation
and deletion of software triggers like this one. Half of the code in this
drivers is boiler plate code copied from the sysfs trigger and is dealing
with creating and deleting the triggers.

[...]
> diff --git a/drivers/iio/trigger/Makefile b/drivers/iio/trigger/Makefile
> index 0694dae..4e1876d 100644
> --- a/drivers/iio/trigger/Makefile
> +++ b/drivers/iio/trigger/Makefile
> @@ -5,3 +5,4 @@
>  # When adding new entries keep the list in alphabetical order
>  obj-$(CONFIG_IIO_INTERRUPT_TRIGGER) += iio-trig-interrupt.o
>  obj-$(CONFIG_IIO_SYSFS_TRIGGER) += iio-trig-sysfs.o
> +obj-$(CONFIG_IIO_HRTIMER_TRIGGER) += iio-trig-hrtimer.o

Alphabetical order, please.

[...]
> +static ssize_t iio_hrtimer_trigger_set_freq_value(struct device *dev,
> +		struct device_attribute *attr, const char *buf, size_t len)
> +{
> +	int ret;
> +	u16 frequency;
> +	struct iio_trigger *trig = to_iio_trigger(dev);
> +	struct iio_hrtimer_trigger_data *trig_data =
> +						iio_trigger_get_drvdata(trig);
> +
> +	ret = kstrtou16(buf, 10, &frequency);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (frequency > MAX_UNSIGNED_INT16)

Will never be true with frequency being a u16.

> +		return -EINVAL;
> +
> +	trig_data->freq = frequency;
> +
> +	if (frequency)
> +		trig_data->period =
> +				ktime_set(0, NSEC_PER_SEC / trig_data->freq);
> +
> +	return len;
> +}
[...]
> +
> +enum hrtimer_restart iio_hrtimer_trigger_func(struct hrtimer *timer)
> +{
> +	struct iio_hrtimer_trigger_data *trig_data;
> +
> +	trig_data = container_of(timer, struct iio_hrtimer_trigger_data, timer);
> +
> +	hrtimer_forward_now(timer, trig_data->period);
> +	iio_trigger_poll(trig_data->trig, 0);

iio_trigger_poll(trig_data->trig, iio_get_time_ns());

> +
> +	return HRTIMER_RESTART;
> +}
[...]


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH] iio:trigger: Added iio-hrtimer-trigger
  2013-09-29 19:36 IIO hrtimer trigger Denis CIOCCA
@ 2013-09-29 19:36 ` Denis CIOCCA
  0 siblings, 0 replies; 5+ messages in thread
From: Denis CIOCCA @ 2013-09-29 19:36 UTC (permalink / raw)
  To: lars, jic23; +Cc: linux-iio, Denis Ciocca

This patch adds high resolution timer trigger support for iio framework.

Signed-off-by: Denis Ciocca <denis.ciocca@st.com>
---
 drivers/iio/trigger/Kconfig            |    9 +
 drivers/iio/trigger/Makefile           |    1 +
 drivers/iio/trigger/iio-trig-hrtimer.c |  292 ++++++++++++++++++++++++++++++++
 3 files changed, 302 insertions(+)
 create mode 100644 drivers/iio/trigger/iio-trig-hrtimer.c

diff --git a/drivers/iio/trigger/Kconfig b/drivers/iio/trigger/Kconfig
index 7999612..f0da684 100644
--- a/drivers/iio/trigger/Kconfig
+++ b/drivers/iio/trigger/Kconfig
@@ -5,6 +5,15 @@
 
 menu "Triggers - standalone"
 
+config IIO_HRTIMER_TRIGGER
+	tristate "HRTIMER trigger"
+	help
+	  Provides support for using HRTIMER entries as IIO triggers.
+	  If unsure, say N (but it's safe to say "Y").
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called iio-trig-hrtimer.
+
 config IIO_INTERRUPT_TRIGGER
 	tristate "Generic interrupt trigger"
 	help
diff --git a/drivers/iio/trigger/Makefile b/drivers/iio/trigger/Makefile
index 0694dae..424032c 100644
--- a/drivers/iio/trigger/Makefile
+++ b/drivers/iio/trigger/Makefile
@@ -3,5 +3,6 @@
 #
 
 # When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_IIO_HRTIMER_TRIGGER) += iio-trig-hrtimer.o
 obj-$(CONFIG_IIO_INTERRUPT_TRIGGER) += iio-trig-interrupt.o
 obj-$(CONFIG_IIO_SYSFS_TRIGGER) += iio-trig-sysfs.o
diff --git a/drivers/iio/trigger/iio-trig-hrtimer.c b/drivers/iio/trigger/iio-trig-hrtimer.c
new file mode 100644
index 0000000..245c51d
--- /dev/null
+++ b/drivers/iio/trigger/iio-trig-hrtimer.c
@@ -0,0 +1,292 @@
+/*
+ * Industrial I/O - hrtimer trigger support
+ *
+ * Copyright 2013 STMicroelectronics Inc.
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/hrtimer.h>
+#include <linux/ktime.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+
+struct iio_hrtimer_trigger_data {
+	struct iio_trigger *trig;
+	struct hrtimer timer;
+	struct list_head l;
+	ktime_t period;
+	u16  freq;
+	int id;
+};
+
+static LIST_HEAD(iio_hrtimer_trigger_list);
+static DEFINE_MUTEX(iio_hrtimer_trigger_list_mut);
+
+static int iio_hrtimer_trigger_probe(int id);
+static int iio_hrtimer_trigger_remove(int id);
+
+static ssize_t iio_sysfs_hrtimer_trig_add(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t len)
+{
+	int ret;
+	unsigned int input;
+
+	ret = kstrtouint(buf, 10, &input);
+	if (ret)
+		return ret;
+
+	ret = iio_hrtimer_trigger_probe(input);
+	if (ret)
+		return ret;
+
+	return len;
+}
+static DEVICE_ATTR(add_trigger, S_IWUSR, NULL, &iio_sysfs_hrtimer_trig_add);
+
+static ssize_t iio_sysfs_hrtimer_trig_remove(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t len)
+{
+	int ret;
+	unsigned int input;
+
+	ret = kstrtouint(buf, 10, &input);
+	if (ret)
+		return ret;
+
+	ret = iio_hrtimer_trigger_remove(input);
+	if (ret)
+		return ret;
+
+	return len;
+}
+static DEVICE_ATTR(remove_trigger, S_IWUSR,
+					NULL, &iio_sysfs_hrtimer_trig_remove);
+
+static struct attribute *iio_hrtimer_trig_attrs[] = {
+	&dev_attr_add_trigger.attr,
+	&dev_attr_remove_trigger.attr,
+	NULL,
+};
+
+static const struct attribute_group iio_hrtimer_trig_group = {
+	.attrs = iio_hrtimer_trig_attrs,
+};
+
+static const struct attribute_group *iio_hrtimer_trig_groups[] = {
+	&iio_hrtimer_trig_group,
+	NULL,
+};
+
+static struct device iio_hrtimer_trig_dev = {
+	.bus = &iio_bus_type,
+	.groups = iio_hrtimer_trig_groups,
+};
+
+static int iio_hrtimer_trig_set_state(struct iio_trigger *trig, bool state)
+{
+	struct iio_hrtimer_trigger_data *trig_data =
+						iio_trigger_get_drvdata(trig);
+
+	if (trig_data->freq == 0)
+		return -EINVAL;
+
+	if (state)
+		hrtimer_start(&trig_data->timer,
+					trig_data->period, HRTIMER_MODE_REL);
+	else
+		hrtimer_cancel(&trig_data->timer);
+
+	return 0;
+}
+
+static ssize_t iio_hrtimer_trigger_set_freq_value(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t len)
+{
+	int ret;
+	u16 frequency;
+	struct iio_trigger *trig = to_iio_trigger(dev);
+	struct iio_hrtimer_trigger_data *trig_data =
+						iio_trigger_get_drvdata(trig);
+
+	ret = kstrtou16(buf, 10, &frequency);
+	if (ret < 0)
+		return ret;
+
+	trig_data->freq = frequency;
+
+	if (frequency)
+		trig_data->period =
+				ktime_set(0, NSEC_PER_SEC / trig_data->freq);
+
+	return len;
+}
+
+static ssize_t iio_hrtimer_trigger_get_freq_value(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct iio_trigger *trig = to_iio_trigger(dev);
+	struct iio_hrtimer_trigger_data *trig_data =
+						iio_trigger_get_drvdata(trig);
+
+	return sprintf(buf, "%hu\n", trig_data->freq);
+}
+
+static DEVICE_ATTR(frequency, S_IWUSR | S_IRUGO,
+					iio_hrtimer_trigger_get_freq_value,
+					iio_hrtimer_trigger_set_freq_value);
+
+static ssize_t iio_hrtimer_trigger_get_id(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct iio_trigger *trig = to_iio_trigger(dev);
+	struct iio_hrtimer_trigger_data *trig_data =
+						iio_trigger_get_drvdata(trig);
+
+	return sprintf(buf, "%d\n", trig_data->id);
+}
+
+static DEVICE_ATTR(id, S_IRUGO, iio_hrtimer_trigger_get_id, NULL);
+
+static struct attribute *iio_hrtimer_trigger_attrs[] = {
+	&dev_attr_frequency.attr,
+	&dev_attr_id.attr,
+	NULL,
+};
+
+static const struct attribute_group iio_hrtimer_trigger_attr_group = {
+	.attrs = iio_hrtimer_trigger_attrs,
+};
+
+static const struct attribute_group *iio_hrtimer_trigger_attr_groups[] = {
+	&iio_hrtimer_trigger_attr_group,
+	NULL,
+};
+
+static const struct iio_trigger_ops iio_hrtimer_trigger_ops = {
+	.owner = THIS_MODULE,
+	.set_trigger_state = &iio_hrtimer_trig_set_state,
+};
+
+enum hrtimer_restart iio_hrtimer_trigger_func(struct hrtimer *timer)
+{
+	struct iio_hrtimer_trigger_data *trig_data;
+
+	trig_data = container_of(timer, struct iio_hrtimer_trigger_data, timer);
+
+	hrtimer_forward_now(timer, trig_data->period);
+	iio_trigger_poll(trig_data->trig, iio_get_time_ns());
+
+	return HRTIMER_RESTART;
+}
+
+static int iio_hrtimer_trigger_probe(int id)
+{
+	int err;
+	bool foundit = false;
+	struct iio_hrtimer_trigger_data *trig_data;
+
+	mutex_lock(&iio_hrtimer_trigger_list_mut);
+	list_for_each_entry(trig_data, &iio_hrtimer_trigger_list, l) {
+		if (id == trig_data->id) {
+			foundit = true;
+			break;
+		}
+	}
+	if (foundit) {
+		err = -EINVAL;
+		goto iio_hrtimer_mutex_unlock;
+	}
+
+	trig_data = kmalloc(sizeof(*trig_data), GFP_KERNEL);
+	if (trig_data == NULL) {
+		err = -ENOMEM;
+		goto iio_hrtimer_mutex_unlock;
+	}
+
+	trig_data->id = id;
+	trig_data->trig = iio_trigger_alloc("hrtimer_trig%d", id);
+	if (!trig_data->trig) {
+		err = -ENOMEM;
+		goto iio_hrtimer_free_trig_data;
+	}
+
+	trig_data->trig->dev.groups = iio_hrtimer_trigger_attr_groups;
+	trig_data->trig->ops = &iio_hrtimer_trigger_ops;
+	trig_data->trig->dev.parent = &iio_hrtimer_trig_dev;
+	iio_trigger_set_drvdata(trig_data->trig, trig_data);
+
+	trig_data->freq = 0;
+	hrtimer_init(&trig_data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	trig_data->timer.function = &iio_hrtimer_trigger_func;
+
+	err = iio_trigger_register(trig_data->trig);
+	if (err)
+		goto iio_hrtimer_free_trig_data;
+
+	list_add(&trig_data->l, &iio_hrtimer_trigger_list);
+	__module_get(THIS_MODULE);
+	mutex_unlock(&iio_hrtimer_trigger_list_mut);
+
+	return 0;
+
+iio_hrtimer_free_trig_data:
+	kfree(trig_data);
+iio_hrtimer_mutex_unlock:
+	mutex_unlock(&iio_hrtimer_trigger_list_mut);
+	return err;
+}
+
+static int iio_hrtimer_trigger_remove(int id)
+{
+	bool foundit = false;
+	struct iio_hrtimer_trigger_data *trig_data;
+
+	mutex_lock(&iio_hrtimer_trigger_list_mut);
+	list_for_each_entry(trig_data, &iio_hrtimer_trigger_list, l) {
+		if (id == trig_data->id) {
+			foundit = true;
+			break;
+		}
+	}
+	if (!foundit) {
+		mutex_unlock(&iio_hrtimer_trigger_list_mut);
+		return -EINVAL;
+	}
+
+	iio_trigger_unregister(trig_data->trig);
+	iio_trigger_free(trig_data->trig);
+
+	list_del(&trig_data->l);
+	kfree(trig_data);
+	module_put(THIS_MODULE);
+	mutex_unlock(&iio_hrtimer_trigger_list_mut);
+
+	return 0;
+}
+
+static int __init iio_hrtimer_trig_init(void)
+{
+	device_initialize(&iio_hrtimer_trig_dev);
+	dev_set_name(&iio_hrtimer_trig_dev, "iio_hrtimer_trigger");
+	return device_add(&iio_hrtimer_trig_dev);
+}
+module_init(iio_hrtimer_trig_init);
+
+static void __exit iio_hrtimer_trig_exit(void)
+{
+	device_unregister(&iio_hrtimer_trig_dev);
+}
+module_exit(iio_hrtimer_trig_exit);
+
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
+MODULE_DESCRIPTION("Hrtimer trigger for the iio subsystem");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2013-09-29 19:36 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-09-24  9:26 Added hrtimer trigger v2 Denis CIOCCA
2013-09-24  9:26 ` [PATCH] iio:trigger: Added iio-hrtimer-trigger Denis CIOCCA
2013-09-28 10:13   ` Lars-Peter Clausen
  -- strict thread matches above, loose matches on Subject: below --
2013-09-29 19:36 IIO hrtimer trigger Denis CIOCCA
2013-09-29 19:36 ` [PATCH] iio:trigger: Added iio-hrtimer-trigger Denis CIOCCA
2013-09-23 10:51 Added hrtimer trigger support Denis CIOCCA
2013-09-23 10:51 ` [PATCH] iio:trigger: Added iio-hrtimer-trigger Denis CIOCCA

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).