diff options
author | Daniel Baluta <daniel.baluta@intel.com> | 2015-11-09 02:14:01 -0500 |
---|---|---|
committer | Jonathan Cameron <jic23@kernel.org> | 2015-12-03 13:19:27 -0500 |
commit | ac5006a2a558a2441a840c7be1e0e717839d5e07 (patch) | |
tree | 5c285709eb45eb37cbdfa4e7f7661d790b646555 | |
parent | b662f809d41009749a9ee6f9a4db3d9af579e171 (diff) |
iio: trigger: Introduce IIO hrtimer based trigger
This patch registers a new IIO software trigger interrupt source
based on high resolution timers.
Notice that if configfs is enabled we create sampling_frequency
attribute allowing users to change hrtimer period (1/sampling_frequency).
The IIO hrtimer trigger has a long history, this patch is based on
an older version from Marten and Lars-Peter.
Signed-off-by: Marten Svanfeldt <marten@intuitiveaerial.com>
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Daniel Baluta <daniel.baluta@intel.com>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
-rw-r--r-- | drivers/iio/trigger/Kconfig | 10 | ||||
-rw-r--r-- | drivers/iio/trigger/Makefile | 2 | ||||
-rw-r--r-- | drivers/iio/trigger/iio-trig-hrtimer.c | 193 |
3 files changed, 205 insertions, 0 deletions
diff --git a/drivers/iio/trigger/Kconfig b/drivers/iio/trigger/Kconfig index 79996123a71b..519e6772f6f5 100644 --- a/drivers/iio/trigger/Kconfig +++ b/drivers/iio/trigger/Kconfig | |||
@@ -5,6 +5,16 @@ | |||
5 | 5 | ||
6 | menu "Triggers - standalone" | 6 | menu "Triggers - standalone" |
7 | 7 | ||
8 | config IIO_HRTIMER_TRIGGER | ||
9 | tristate "High resolution timer trigger" | ||
10 | depends on IIO_SW_TRIGGER | ||
11 | help | ||
12 | Provides a frequency based IIO trigger using high resolution | ||
13 | timers as interrupt source. | ||
14 | |||
15 | To compile this driver as a module, choose M here: the | ||
16 | module will be called iio-trig-hrtimer. | ||
17 | |||
8 | config IIO_INTERRUPT_TRIGGER | 18 | config IIO_INTERRUPT_TRIGGER |
9 | tristate "Generic interrupt trigger" | 19 | tristate "Generic interrupt trigger" |
10 | help | 20 | help |
diff --git a/drivers/iio/trigger/Makefile b/drivers/iio/trigger/Makefile index 0694daecaf22..fe06eb564367 100644 --- a/drivers/iio/trigger/Makefile +++ b/drivers/iio/trigger/Makefile | |||
@@ -3,5 +3,7 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | # When adding new entries keep the list in alphabetical order | 5 | # When adding new entries keep the list in alphabetical order |
6 | |||
7 | obj-$(CONFIG_IIO_HRTIMER_TRIGGER) += iio-trig-hrtimer.o | ||
6 | obj-$(CONFIG_IIO_INTERRUPT_TRIGGER) += iio-trig-interrupt.o | 8 | obj-$(CONFIG_IIO_INTERRUPT_TRIGGER) += iio-trig-interrupt.o |
7 | obj-$(CONFIG_IIO_SYSFS_TRIGGER) += iio-trig-sysfs.o | 9 | 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 000000000000..5e6d451febeb --- /dev/null +++ b/drivers/iio/trigger/iio-trig-hrtimer.c | |||
@@ -0,0 +1,193 @@ | |||
1 | /** | ||
2 | * The industrial I/O periodic hrtimer trigger driver | ||
3 | * | ||
4 | * Copyright (C) Intuitive Aerial AB | ||
5 | * Written by Marten Svanfeldt, marten@intuitiveaerial.com | ||
6 | * Copyright (C) 2012, Analog Device Inc. | ||
7 | * Author: Lars-Peter Clausen <lars@metafoo.de> | ||
8 | * Copyright (C) 2015, Intel Corporation | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License version 2 as published by | ||
12 | * the Free Software Foundation. | ||
13 | * | ||
14 | */ | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/hrtimer.h> | ||
18 | |||
19 | #include <linux/iio/iio.h> | ||
20 | #include <linux/iio/trigger.h> | ||
21 | #include <linux/iio/sw_trigger.h> | ||
22 | |||
23 | /* default sampling frequency - 100Hz */ | ||
24 | #define HRTIMER_DEFAULT_SAMPLING_FREQUENCY 100 | ||
25 | |||
26 | struct iio_hrtimer_info { | ||
27 | struct iio_sw_trigger swt; | ||
28 | struct hrtimer timer; | ||
29 | unsigned long sampling_frequency; | ||
30 | ktime_t period; | ||
31 | }; | ||
32 | |||
33 | static struct config_item_type iio_hrtimer_type = { | ||
34 | .ct_owner = THIS_MODULE, | ||
35 | }; | ||
36 | |||
37 | static | ||
38 | ssize_t iio_hrtimer_show_sampling_frequency(struct device *dev, | ||
39 | struct device_attribute *attr, | ||
40 | char *buf) | ||
41 | { | ||
42 | struct iio_trigger *trig = to_iio_trigger(dev); | ||
43 | struct iio_hrtimer_info *info = iio_trigger_get_drvdata(trig); | ||
44 | |||
45 | return snprintf(buf, PAGE_SIZE, "%lu\n", info->sampling_frequency); | ||
46 | } | ||
47 | |||
48 | static | ||
49 | ssize_t iio_hrtimer_store_sampling_frequency(struct device *dev, | ||
50 | struct device_attribute *attr, | ||
51 | const char *buf, size_t len) | ||
52 | { | ||
53 | struct iio_trigger *trig = to_iio_trigger(dev); | ||
54 | struct iio_hrtimer_info *info = iio_trigger_get_drvdata(trig); | ||
55 | unsigned long val; | ||
56 | int ret; | ||
57 | |||
58 | ret = kstrtoul(buf, 10, &val); | ||
59 | if (ret) | ||
60 | return ret; | ||
61 | |||
62 | if (!val || val > NSEC_PER_SEC) | ||
63 | return -EINVAL; | ||
64 | |||
65 | info->sampling_frequency = val; | ||
66 | info->period = ktime_set(0, NSEC_PER_SEC / val); | ||
67 | |||
68 | return len; | ||
69 | } | ||
70 | |||
71 | static DEVICE_ATTR(sampling_frequency, S_IRUGO | S_IWUSR, | ||
72 | iio_hrtimer_show_sampling_frequency, | ||
73 | iio_hrtimer_store_sampling_frequency); | ||
74 | |||
75 | static struct attribute *iio_hrtimer_attrs[] = { | ||
76 | &dev_attr_sampling_frequency.attr, | ||
77 | NULL | ||
78 | }; | ||
79 | |||
80 | static const struct attribute_group iio_hrtimer_attr_group = { | ||
81 | .attrs = iio_hrtimer_attrs, | ||
82 | }; | ||
83 | |||
84 | static const struct attribute_group *iio_hrtimer_attr_groups[] = { | ||
85 | &iio_hrtimer_attr_group, | ||
86 | NULL | ||
87 | }; | ||
88 | |||
89 | static enum hrtimer_restart iio_hrtimer_trig_handler(struct hrtimer *timer) | ||
90 | { | ||
91 | struct iio_hrtimer_info *info; | ||
92 | |||
93 | info = container_of(timer, struct iio_hrtimer_info, timer); | ||
94 | |||
95 | hrtimer_forward_now(timer, info->period); | ||
96 | iio_trigger_poll(info->swt.trigger); | ||
97 | |||
98 | return HRTIMER_RESTART; | ||
99 | } | ||
100 | |||
101 | static int iio_trig_hrtimer_set_state(struct iio_trigger *trig, bool state) | ||
102 | { | ||
103 | struct iio_hrtimer_info *trig_info; | ||
104 | |||
105 | trig_info = iio_trigger_get_drvdata(trig); | ||
106 | |||
107 | if (state) | ||
108 | hrtimer_start(&trig_info->timer, trig_info->period, | ||
109 | HRTIMER_MODE_REL); | ||
110 | else | ||
111 | hrtimer_cancel(&trig_info->timer); | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static const struct iio_trigger_ops iio_hrtimer_trigger_ops = { | ||
117 | .owner = THIS_MODULE, | ||
118 | .set_trigger_state = iio_trig_hrtimer_set_state, | ||
119 | }; | ||
120 | |||
121 | static struct iio_sw_trigger *iio_trig_hrtimer_probe(const char *name) | ||
122 | { | ||
123 | struct iio_hrtimer_info *trig_info; | ||
124 | int ret; | ||
125 | |||
126 | trig_info = kzalloc(sizeof(*trig_info), GFP_KERNEL); | ||
127 | if (!trig_info) | ||
128 | return ERR_PTR(-ENOMEM); | ||
129 | |||
130 | trig_info->swt.trigger = iio_trigger_alloc("%s", name); | ||
131 | if (!trig_info->swt.trigger) { | ||
132 | ret = -ENOMEM; | ||
133 | goto err_free_trig_info; | ||
134 | } | ||
135 | |||
136 | iio_trigger_set_drvdata(trig_info->swt.trigger, trig_info); | ||
137 | trig_info->swt.trigger->ops = &iio_hrtimer_trigger_ops; | ||
138 | trig_info->swt.trigger->dev.groups = iio_hrtimer_attr_groups; | ||
139 | |||
140 | hrtimer_init(&trig_info->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
141 | trig_info->timer.function = iio_hrtimer_trig_handler; | ||
142 | |||
143 | trig_info->sampling_frequency = HRTIMER_DEFAULT_SAMPLING_FREQUENCY; | ||
144 | trig_info->period = ktime_set(0, NSEC_PER_SEC / | ||
145 | trig_info->sampling_frequency); | ||
146 | |||
147 | ret = iio_trigger_register(trig_info->swt.trigger); | ||
148 | if (ret) | ||
149 | goto err_free_trigger; | ||
150 | |||
151 | iio_swt_group_init_type_name(&trig_info->swt, name, &iio_hrtimer_type); | ||
152 | return &trig_info->swt; | ||
153 | err_free_trigger: | ||
154 | iio_trigger_free(trig_info->swt.trigger); | ||
155 | err_free_trig_info: | ||
156 | kfree(trig_info); | ||
157 | |||
158 | return ERR_PTR(ret); | ||
159 | } | ||
160 | |||
161 | static int iio_trig_hrtimer_remove(struct iio_sw_trigger *swt) | ||
162 | { | ||
163 | struct iio_hrtimer_info *trig_info; | ||
164 | |||
165 | trig_info = iio_trigger_get_drvdata(swt->trigger); | ||
166 | |||
167 | iio_trigger_unregister(swt->trigger); | ||
168 | |||
169 | /* cancel the timer after unreg to make sure no one rearms it */ | ||
170 | hrtimer_cancel(&trig_info->timer); | ||
171 | iio_trigger_free(swt->trigger); | ||
172 | kfree(trig_info); | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static const struct iio_sw_trigger_ops iio_trig_hrtimer_ops = { | ||
178 | .probe = iio_trig_hrtimer_probe, | ||
179 | .remove = iio_trig_hrtimer_remove, | ||
180 | }; | ||
181 | |||
182 | static struct iio_sw_trigger_type iio_trig_hrtimer = { | ||
183 | .name = "hrtimer", | ||
184 | .owner = THIS_MODULE, | ||
185 | .ops = &iio_trig_hrtimer_ops, | ||
186 | }; | ||
187 | |||
188 | module_iio_sw_trigger_driver(iio_trig_hrtimer); | ||
189 | |||
190 | MODULE_AUTHOR("Marten Svanfeldt <marten@intuitiveaerial.com>"); | ||
191 | MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>"); | ||
192 | MODULE_DESCRIPTION("Periodic hrtimer trigger for the IIO subsystem"); | ||
193 | MODULE_LICENSE("GPL v2"); | ||