1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * The industrial I/O periodic hrtimer trigger driver |
4 | * |
5 | * Copyright (C) Intuitive Aerial AB |
6 | * Written by Marten Svanfeldt, marten@intuitiveaerial.com |
7 | * Copyright (C) 2012, Analog Devices Inc. |
8 | * Author: Lars-Peter Clausen <lars@metafoo.de> |
9 | * Copyright (C) 2015, Intel Corporation |
10 | */ |
11 | #include <linux/kernel.h> |
12 | #include <linux/slab.h> |
13 | #include <linux/hrtimer.h> |
14 | |
15 | #include <linux/iio/iio.h> |
16 | #include <linux/iio/trigger.h> |
17 | #include <linux/iio/sw_trigger.h> |
18 | |
19 | /* Defined locally, not in time64.h yet. */ |
20 | #define PSEC_PER_SEC 1000000000000LL |
21 | |
22 | /* default sampling frequency - 100Hz */ |
23 | #define HRTIMER_DEFAULT_SAMPLING_FREQUENCY 100 |
24 | |
25 | struct iio_hrtimer_info { |
26 | struct iio_sw_trigger swt; |
27 | struct hrtimer timer; |
28 | int sampling_frequency[2]; |
29 | ktime_t period; |
30 | }; |
31 | |
32 | static const struct config_item_type iio_hrtimer_type = { |
33 | .ct_owner = THIS_MODULE, |
34 | }; |
35 | |
36 | static |
37 | ssize_t iio_hrtimer_show_sampling_frequency(struct device *dev, |
38 | struct device_attribute *attr, |
39 | char *buf) |
40 | { |
41 | struct iio_trigger *trig = to_iio_trigger(d: dev); |
42 | struct iio_hrtimer_info *info = iio_trigger_get_drvdata(trig); |
43 | |
44 | return iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, |
45 | ARRAY_SIZE(info->sampling_frequency), |
46 | vals: info->sampling_frequency); |
47 | } |
48 | |
49 | static |
50 | ssize_t iio_hrtimer_store_sampling_frequency(struct device *dev, |
51 | struct device_attribute *attr, |
52 | const char *buf, size_t len) |
53 | { |
54 | struct iio_trigger *trig = to_iio_trigger(d: dev); |
55 | struct iio_hrtimer_info *info = iio_trigger_get_drvdata(trig); |
56 | unsigned long long val; |
57 | u64 period; |
58 | int integer, fract, ret; |
59 | |
60 | ret = iio_str_to_fixpoint(str: buf, fract_mult: 100, integer: &integer, fract: &fract); |
61 | if (ret) |
62 | return ret; |
63 | if (integer < 0 || fract < 0) |
64 | return -ERANGE; |
65 | |
66 | val = fract + 1000ULL * integer; /* mHz */ |
67 | |
68 | if (!val || val > UINT_MAX) |
69 | return -EINVAL; |
70 | |
71 | info->sampling_frequency[0] = integer; /* Hz */ |
72 | info->sampling_frequency[1] = fract * 1000; /* uHz */ |
73 | period = PSEC_PER_SEC; |
74 | do_div(period, val); |
75 | info->period = period; /* nS */ |
76 | |
77 | return len; |
78 | } |
79 | |
80 | static DEVICE_ATTR(sampling_frequency, S_IRUGO | S_IWUSR, |
81 | iio_hrtimer_show_sampling_frequency, |
82 | iio_hrtimer_store_sampling_frequency); |
83 | |
84 | static struct attribute *iio_hrtimer_attrs[] = { |
85 | &dev_attr_sampling_frequency.attr, |
86 | NULL |
87 | }; |
88 | |
89 | static const struct attribute_group iio_hrtimer_attr_group = { |
90 | .attrs = iio_hrtimer_attrs, |
91 | }; |
92 | |
93 | static const struct attribute_group *iio_hrtimer_attr_groups[] = { |
94 | &iio_hrtimer_attr_group, |
95 | NULL |
96 | }; |
97 | |
98 | static enum hrtimer_restart iio_hrtimer_trig_handler(struct hrtimer *timer) |
99 | { |
100 | struct iio_hrtimer_info *info; |
101 | |
102 | info = container_of(timer, struct iio_hrtimer_info, timer); |
103 | |
104 | hrtimer_forward_now(timer, interval: info->period); |
105 | iio_trigger_poll(trig: info->swt.trigger); |
106 | |
107 | return HRTIMER_RESTART; |
108 | } |
109 | |
110 | static int iio_trig_hrtimer_set_state(struct iio_trigger *trig, bool state) |
111 | { |
112 | struct iio_hrtimer_info *trig_info; |
113 | |
114 | trig_info = iio_trigger_get_drvdata(trig); |
115 | |
116 | if (state) |
117 | hrtimer_start(timer: &trig_info->timer, tim: trig_info->period, |
118 | mode: HRTIMER_MODE_REL_HARD); |
119 | else |
120 | hrtimer_cancel(timer: &trig_info->timer); |
121 | |
122 | return 0; |
123 | } |
124 | |
125 | static const struct iio_trigger_ops iio_hrtimer_trigger_ops = { |
126 | .set_trigger_state = iio_trig_hrtimer_set_state, |
127 | }; |
128 | |
129 | static struct iio_sw_trigger *iio_trig_hrtimer_probe(const char *name) |
130 | { |
131 | struct iio_hrtimer_info *trig_info; |
132 | int ret; |
133 | |
134 | trig_info = kzalloc(size: sizeof(*trig_info), GFP_KERNEL); |
135 | if (!trig_info) |
136 | return ERR_PTR(error: -ENOMEM); |
137 | |
138 | trig_info->swt.trigger = iio_trigger_alloc(NULL, "%s" , name); |
139 | if (!trig_info->swt.trigger) { |
140 | ret = -ENOMEM; |
141 | goto err_free_trig_info; |
142 | } |
143 | |
144 | iio_trigger_set_drvdata(trig: trig_info->swt.trigger, data: trig_info); |
145 | trig_info->swt.trigger->ops = &iio_hrtimer_trigger_ops; |
146 | trig_info->swt.trigger->dev.groups = iio_hrtimer_attr_groups; |
147 | |
148 | hrtimer_init(timer: &trig_info->timer, CLOCK_MONOTONIC, mode: HRTIMER_MODE_REL_HARD); |
149 | trig_info->timer.function = iio_hrtimer_trig_handler; |
150 | |
151 | trig_info->sampling_frequency[0] = HRTIMER_DEFAULT_SAMPLING_FREQUENCY; |
152 | trig_info->period = NSEC_PER_SEC / trig_info->sampling_frequency[0]; |
153 | |
154 | ret = iio_trigger_register(trig_info: trig_info->swt.trigger); |
155 | if (ret) |
156 | goto err_free_trigger; |
157 | |
158 | iio_swt_group_init_type_name(t: &trig_info->swt, name, type: &iio_hrtimer_type); |
159 | return &trig_info->swt; |
160 | err_free_trigger: |
161 | iio_trigger_free(trig: trig_info->swt.trigger); |
162 | err_free_trig_info: |
163 | kfree(objp: trig_info); |
164 | |
165 | return ERR_PTR(error: ret); |
166 | } |
167 | |
168 | static int iio_trig_hrtimer_remove(struct iio_sw_trigger *swt) |
169 | { |
170 | struct iio_hrtimer_info *trig_info; |
171 | |
172 | trig_info = iio_trigger_get_drvdata(trig: swt->trigger); |
173 | |
174 | iio_trigger_unregister(trig_info: swt->trigger); |
175 | |
176 | /* cancel the timer after unreg to make sure no one rearms it */ |
177 | hrtimer_cancel(timer: &trig_info->timer); |
178 | iio_trigger_free(trig: swt->trigger); |
179 | kfree(objp: trig_info); |
180 | |
181 | return 0; |
182 | } |
183 | |
184 | static const struct iio_sw_trigger_ops iio_trig_hrtimer_ops = { |
185 | .probe = iio_trig_hrtimer_probe, |
186 | .remove = iio_trig_hrtimer_remove, |
187 | }; |
188 | |
189 | static struct iio_sw_trigger_type iio_trig_hrtimer = { |
190 | .name = "hrtimer" , |
191 | .owner = THIS_MODULE, |
192 | .ops = &iio_trig_hrtimer_ops, |
193 | }; |
194 | |
195 | module_iio_sw_trigger_driver(iio_trig_hrtimer); |
196 | |
197 | MODULE_AUTHOR("Marten Svanfeldt <marten@intuitiveaerial.com>" ); |
198 | MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>" ); |
199 | MODULE_DESCRIPTION("Periodic hrtimer trigger for the IIO subsystem" ); |
200 | MODULE_LICENSE("GPL v2" ); |
201 | |