aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2013-10-07 10:11:00 -0400
committerJonathan Cameron <jic23@kernel.org>2013-10-12 07:32:19 -0400
commitb4e3ac0a204ff1775c69924510f49922a56910a7 (patch)
treed71492a1357e418a3cc22fc59d185b3329a5790e
parent3661f3f5e961f73d40d93495c0de6711dabe6f8d (diff)
iio: Extend the event config interface
The event configuration interface of the IIO framework has not been getting the same attention as other parts. As a result it has not seen the same improvements as e.g. the channel interface has seen with the introduction of the channel spec struct. Currently all the event config callbacks take a u64 (the so called event code) to pass all the different information about for which event the callback is invoked. The callback function then has to extract the information it is interested in using some macros with rather long names. Most information encoded in the event code comes straight from the iio_chan_spec struct the event was registered for. Since we always have a handle to the channel spec when we call the event callbacks the first step is to add the channel spec as a parameter to the event callbacks. The two remaining things encoded in the event code are the type and direction of the event. Instead of passing them in one parameter, add one parameter for each of them and remove the eventcode from the event callbacks. The patch also adds a new iio_event_info parameter to the {read,write}_event_value callbacks. This makes it possible, similar to the iio_chan_info_enum for channels, to specify additional properties other than just the value for an event. Furthermore the new interface will allow to register shared events. This is e.g. useful if a device allows configuring a threshold event, but the threshold setting is the same for all channels. To implement this the patch adds a new iio_event_spec struct which is similar to the iio_chan_spec struct. It as two field to specify the type and the direction of the event. Furthermore it has a mask field for each one of the different iio_shared_by types. These mask fields holds which kind of attributes should be registered for the event. Creation of the attributes follows the same rules as the for the channel attributes. E.g. for the separate_mask there will be a attribute for each channel with this event, for the shared_by_type there will only be one attribute per channel type. The iio_chan_spec struct gets two new fields, 'event_spec' and 'num_event_specs', which is used to specify which the events for this channel. These two fields are going to replace the channel's event_mask field. For now both the old and the new event config interface coexist, but over the few patches all drivers will be converted from the old to the new interface. Once that is done all code for supporting the old interface will be removed. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
-rw-r--r--drivers/iio/industrialio-event.c193
-rw-r--r--include/linux/iio/events.h14
-rw-r--r--include/linux/iio/iio.h58
-rw-r--r--include/linux/iio/types.h19
4 files changed, 248 insertions, 36 deletions
diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c
index 4a3fd5acda94..b7a5d7cbed42 100644
--- a/drivers/iio/industrialio-event.c
+++ b/drivers/iio/industrialio-event.c
@@ -201,6 +201,26 @@ static const char * const iio_ev_dir_text[] = {
201 [IIO_EV_DIR_FALLING] = "falling" 201 [IIO_EV_DIR_FALLING] = "falling"
202}; 202};
203 203
204static const char * const iio_ev_info_text[] = {
205 [IIO_EV_INFO_ENABLE] = "en",
206 [IIO_EV_INFO_VALUE] = "value",
207};
208
209static enum iio_event_direction iio_ev_attr_dir(struct iio_dev_attr *attr)
210{
211 return attr->c->event_spec[attr->address & 0xffff].dir;
212}
213
214static enum iio_event_type iio_ev_attr_type(struct iio_dev_attr *attr)
215{
216 return attr->c->event_spec[attr->address & 0xffff].type;
217}
218
219static enum iio_event_info iio_ev_attr_info(struct iio_dev_attr *attr)
220{
221 return (attr->address >> 16) & 0xffff;
222}
223
204static ssize_t iio_ev_state_store(struct device *dev, 224static ssize_t iio_ev_state_store(struct device *dev,
205 struct device_attribute *attr, 225 struct device_attribute *attr,
206 const char *buf, 226 const char *buf,
@@ -215,9 +235,14 @@ static ssize_t iio_ev_state_store(struct device *dev,
215 if (ret < 0) 235 if (ret < 0)
216 return ret; 236 return ret;
217 237
218 ret = indio_dev->info->write_event_config(indio_dev, 238 if (indio_dev->info->write_event_config)
219 this_attr->address, 239 ret = indio_dev->info->write_event_config(indio_dev,
220 val); 240 this_attr->address, val);
241 else
242 ret = indio_dev->info->write_event_config_new(indio_dev,
243 this_attr->c, iio_ev_attr_type(this_attr),
244 iio_ev_attr_dir(this_attr), val);
245
221 return (ret < 0) ? ret : len; 246 return (ret < 0) ? ret : len;
222} 247}
223 248
@@ -227,9 +252,15 @@ static ssize_t iio_ev_state_show(struct device *dev,
227{ 252{
228 struct iio_dev *indio_dev = dev_to_iio_dev(dev); 253 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
229 struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); 254 struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
230 int val = indio_dev->info->read_event_config(indio_dev, 255 int val;
231 this_attr->address);
232 256
257 if (indio_dev->info->read_event_config)
258 val = indio_dev->info->read_event_config(indio_dev,
259 this_attr->address);
260 else
261 val = indio_dev->info->read_event_config_new(indio_dev,
262 this_attr->c, iio_ev_attr_type(this_attr),
263 iio_ev_attr_dir(this_attr));
233 if (val < 0) 264 if (val < 0)
234 return val; 265 return val;
235 else 266 else
@@ -242,14 +273,24 @@ static ssize_t iio_ev_value_show(struct device *dev,
242{ 273{
243 struct iio_dev *indio_dev = dev_to_iio_dev(dev); 274 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
244 struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); 275 struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
245 int val, ret; 276 int val, val2;
246 277 int ret;
247 ret = indio_dev->info->read_event_value(indio_dev,
248 this_attr->address, &val);
249 if (ret < 0)
250 return ret;
251 278
252 return sprintf(buf, "%d\n", val); 279 if (indio_dev->info->read_event_value) {
280 ret = indio_dev->info->read_event_value(indio_dev,
281 this_attr->address, &val);
282 if (ret < 0)
283 return ret;
284 return sprintf(buf, "%d\n", val);
285 } else {
286 ret = indio_dev->info->read_event_value_new(indio_dev,
287 this_attr->c, iio_ev_attr_type(this_attr),
288 iio_ev_attr_dir(this_attr), iio_ev_attr_info(this_attr),
289 &val, &val2);
290 if (ret < 0)
291 return ret;
292 return iio_format_value(buf, ret, val, val2);
293 }
253} 294}
254 295
255static ssize_t iio_ev_value_store(struct device *dev, 296static ssize_t iio_ev_value_store(struct device *dev,
@@ -259,25 +300,120 @@ static ssize_t iio_ev_value_store(struct device *dev,
259{ 300{
260 struct iio_dev *indio_dev = dev_to_iio_dev(dev); 301 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
261 struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); 302 struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
262 int val; 303 int val, val2;
263 int ret; 304 int ret;
264 305
265 if (!indio_dev->info->write_event_value) 306 if (!indio_dev->info->write_event_value &&
307 !indio_dev->info->write_event_value_new)
266 return -EINVAL; 308 return -EINVAL;
267 309
268 ret = kstrtoint(buf, 10, &val); 310 if (indio_dev->info->write_event_value) {
269 if (ret) 311 ret = kstrtoint(buf, 10, &val);
270 return ret; 312 if (ret)
271 313 return ret;
272 ret = indio_dev->info->write_event_value(indio_dev, this_attr->address, 314 ret = indio_dev->info->write_event_value(indio_dev,
273 val); 315 this_attr->address, val);
316 } else {
317 ret = iio_str_to_fixpoint(buf, 100000, &val, &val2);
318 if (ret)
319 return ret;
320 ret = indio_dev->info->write_event_value_new(indio_dev,
321 this_attr->c, iio_ev_attr_type(this_attr),
322 iio_ev_attr_dir(this_attr), iio_ev_attr_info(this_attr),
323 val, val2);
324 }
274 if (ret < 0) 325 if (ret < 0)
275 return ret; 326 return ret;
276 327
277 return len; 328 return len;
278} 329}
279 330
280static int iio_device_add_event_sysfs(struct iio_dev *indio_dev, 331static int iio_device_add_event(struct iio_dev *indio_dev,
332 const struct iio_chan_spec *chan, unsigned int spec_index,
333 enum iio_event_type type, enum iio_event_direction dir,
334 enum iio_shared_by shared_by, const unsigned long *mask)
335{
336 ssize_t (*show)(struct device *, struct device_attribute *, char *);
337 ssize_t (*store)(struct device *, struct device_attribute *,
338 const char *, size_t);
339 unsigned int attrcount = 0;
340 unsigned int i;
341 char *postfix;
342 int ret;
343
344 for_each_set_bit(i, mask, sizeof(*mask)) {
345 postfix = kasprintf(GFP_KERNEL, "%s_%s_%s",
346 iio_ev_type_text[type], iio_ev_dir_text[dir],
347 iio_ev_info_text[i]);
348 if (postfix == NULL)
349 return -ENOMEM;
350
351 if (i == IIO_EV_INFO_ENABLE) {
352 show = iio_ev_state_show;
353 store = iio_ev_state_store;
354 } else {
355 show = iio_ev_value_show;
356 store = iio_ev_value_store;
357 }
358
359 ret = __iio_add_chan_devattr(postfix, chan, show, store,
360 (i << 16) | spec_index, shared_by, &indio_dev->dev,
361 &indio_dev->event_interface->dev_attr_list);
362 kfree(postfix);
363
364 if (ret)
365 return ret;
366
367 attrcount++;
368 }
369
370 return attrcount;
371}
372
373static int iio_device_add_event_sysfs_new(struct iio_dev *indio_dev,
374 struct iio_chan_spec const *chan)
375{
376 int ret = 0, i, attrcount = 0;
377 enum iio_event_direction dir;
378 enum iio_event_type type;
379
380 for (i = 0; i < chan->num_event_specs; i++) {
381 type = chan->event_spec[i].type;
382 dir = chan->event_spec[i].dir;
383
384 ret = iio_device_add_event(indio_dev, chan, i, type, dir,
385 IIO_SEPARATE, &chan->event_spec[i].mask_separate);
386 if (ret < 0)
387 goto error_ret;
388 attrcount += ret;
389
390 ret = iio_device_add_event(indio_dev, chan, i, type, dir,
391 IIO_SHARED_BY_TYPE,
392 &chan->event_spec[i].mask_shared_by_type);
393 if (ret < 0)
394 goto error_ret;
395 attrcount += ret;
396
397 ret = iio_device_add_event(indio_dev, chan, i, type, dir,
398 IIO_SHARED_BY_DIR,
399 &chan->event_spec[i].mask_shared_by_dir);
400 if (ret < 0)
401 goto error_ret;
402 attrcount += ret;
403
404 ret = iio_device_add_event(indio_dev, chan, i, type, dir,
405 IIO_SHARED_BY_ALL,
406 &chan->event_spec[i].mask_shared_by_all);
407 if (ret < 0)
408 goto error_ret;
409 attrcount += ret;
410 }
411 ret = attrcount;
412error_ret:
413 return ret;
414}
415
416static int iio_device_add_event_sysfs_old(struct iio_dev *indio_dev,
281 struct iio_chan_spec const *chan) 417 struct iio_chan_spec const *chan)
282{ 418{
283 int ret = 0, i, attrcount = 0; 419 int ret = 0, i, attrcount = 0;
@@ -350,6 +486,16 @@ error_ret:
350 return ret; 486 return ret;
351} 487}
352 488
489
490static int iio_device_add_event_sysfs(struct iio_dev *indio_dev,
491 struct iio_chan_spec const *chan)
492{
493 if (chan->event_mask)
494 return iio_device_add_event_sysfs_old(indio_dev, chan);
495 else
496 return iio_device_add_event_sysfs_new(indio_dev, chan);
497}
498
353static inline int __iio_add_event_config_attrs(struct iio_dev *indio_dev) 499static inline int __iio_add_event_config_attrs(struct iio_dev *indio_dev)
354{ 500{
355 int j, ret, attrcount = 0; 501 int j, ret, attrcount = 0;
@@ -369,9 +515,12 @@ static bool iio_check_for_dynamic_events(struct iio_dev *indio_dev)
369{ 515{
370 int j; 516 int j;
371 517
372 for (j = 0; j < indio_dev->num_channels; j++) 518 for (j = 0; j < indio_dev->num_channels; j++) {
373 if (indio_dev->channels[j].event_mask != 0) 519 if (indio_dev->channels[j].event_mask != 0)
374 return true; 520 return true;
521 if (indio_dev->channels[j].num_event_specs != 0)
522 return true;
523 }
375 return false; 524 return false;
376} 525}
377 526
diff --git a/include/linux/iio/events.h b/include/linux/iio/events.h
index 13ce220c7003..5dab2c41031f 100644
--- a/include/linux/iio/events.h
+++ b/include/linux/iio/events.h
@@ -26,20 +26,6 @@ struct iio_event_data {
26 26
27#define IIO_GET_EVENT_FD_IOCTL _IOR('i', 0x90, int) 27#define IIO_GET_EVENT_FD_IOCTL _IOR('i', 0x90, int)
28 28
29enum iio_event_type {
30 IIO_EV_TYPE_THRESH,
31 IIO_EV_TYPE_MAG,
32 IIO_EV_TYPE_ROC,
33 IIO_EV_TYPE_THRESH_ADAPTIVE,
34 IIO_EV_TYPE_MAG_ADAPTIVE,
35};
36
37enum iio_event_direction {
38 IIO_EV_DIR_EITHER,
39 IIO_EV_DIR_RISING,
40 IIO_EV_DIR_FALLING,
41};
42
43/** 29/**
44 * IIO_EVENT_CODE() - create event identifier 30 * IIO_EVENT_CODE() - create event identifier
45 * @chan_type: Type of the channel. Should be one of enum iio_chan_type. 31 * @chan_type: Type of the channel. Should be one of enum iio_chan_type.
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index ac1cb8f1858c..256a90a1bea6 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -139,6 +139,29 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev,
139} 139}
140 140
141/** 141/**
142 * struct iio_event_spec - specification for a channel event
143 * @type: Type of the event
144 * @dir: Direction of the event
145 * @mask_separate: Bit mask of enum iio_event_info values. Attributes
146 * set in this mask will be registered per channel.
147 * @mask_shared_by_type: Bit mask of enum iio_event_info values. Attributes
148 * set in this mask will be shared by channel type.
149 * @mask_shared_by_dir: Bit mask of enum iio_event_info values. Attributes
150 * set in this mask will be shared by channel type and
151 * direction.
152 * @mask_shared_by_all: Bit mask of enum iio_event_info values. Attributes
153 * set in this mask will be shared by all channels.
154 */
155struct iio_event_spec {
156 enum iio_event_type type;
157 enum iio_event_direction dir;
158 unsigned long mask_separate;
159 unsigned long mask_shared_by_type;
160 unsigned long mask_shared_by_dir;
161 unsigned long mask_shared_by_all;
162};
163
164/**
142 * struct iio_chan_spec - specification of a single channel 165 * struct iio_chan_spec - specification of a single channel
143 * @type: What type of measurement is the channel making. 166 * @type: What type of measurement is the channel making.
144 * @channel: What number do we wish to assign the channel. 167 * @channel: What number do we wish to assign the channel.
@@ -163,6 +186,9 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev,
163 * @info_mask_shared_by_all: What information is to be exported that is shared 186 * @info_mask_shared_by_all: What information is to be exported that is shared
164 * by all channels. 187 * by all channels.
165 * @event_mask: What events can this channel produce. 188 * @event_mask: What events can this channel produce.
189 * @event_spec: Array of events which should be registered for this
190 * channel.
191 * @num_event_specs: Size of the event_spec array.
166 * @ext_info: Array of extended info attributes for this channel. 192 * @ext_info: Array of extended info attributes for this channel.
167 * The array is NULL terminated, the last element should 193 * The array is NULL terminated, the last element should
168 * have its name field set to NULL. 194 * have its name field set to NULL.
@@ -201,6 +227,8 @@ struct iio_chan_spec {
201 long info_mask_shared_by_dir; 227 long info_mask_shared_by_dir;
202 long info_mask_shared_by_all; 228 long info_mask_shared_by_all;
203 long event_mask; 229 long event_mask;
230 const struct iio_event_spec *event_spec;
231 unsigned int num_event_specs;
204 const struct iio_chan_spec_ext_info *ext_info; 232 const struct iio_chan_spec_ext_info *ext_info;
205 const char *extend_name; 233 const char *extend_name;
206 const char *datasheet_name; 234 const char *datasheet_name;
@@ -283,6 +311,12 @@ struct iio_dev;
283 * is event dependant. event_code specifies which event. 311 * is event dependant. event_code specifies which event.
284 * @write_event_value: write the value associated with the event. 312 * @write_event_value: write the value associated with the event.
285 * Meaning is event dependent. 313 * Meaning is event dependent.
314 * @read_event_config_new: find out if the event is enabled. New style interface.
315 * @write_event_config_new: set if the event is enabled. New style interface.
316 * @read_event_value_new: read a configuration value associated with the event.
317 * New style interface.
318 * @write_event_value_new: write a configuration value for the event. New style
319 * interface.
286 * @validate_trigger: function to validate the trigger when the 320 * @validate_trigger: function to validate the trigger when the
287 * current trigger gets changed. 321 * current trigger gets changed.
288 * @update_scan_mode: function to configure device and scan buffer when 322 * @update_scan_mode: function to configure device and scan buffer when
@@ -323,6 +357,30 @@ struct iio_info {
323 int (*write_event_value)(struct iio_dev *indio_dev, 357 int (*write_event_value)(struct iio_dev *indio_dev,
324 u64 event_code, 358 u64 event_code,
325 int val); 359 int val);
360
361 int (*read_event_config_new)(struct iio_dev *indio_dev,
362 const struct iio_chan_spec *chan,
363 enum iio_event_type type,
364 enum iio_event_direction dir);
365
366 int (*write_event_config_new)(struct iio_dev *indio_dev,
367 const struct iio_chan_spec *chan,
368 enum iio_event_type type,
369 enum iio_event_direction dir,
370 int state);
371
372 int (*read_event_value_new)(struct iio_dev *indio_dev,
373 const struct iio_chan_spec *chan,
374 enum iio_event_type type,
375 enum iio_event_direction dir,
376 enum iio_event_info info, int *val, int *val2);
377
378 int (*write_event_value_new)(struct iio_dev *indio_dev,
379 const struct iio_chan_spec *chan,
380 enum iio_event_type type,
381 enum iio_event_direction dir,
382 enum iio_event_info info, int val, int val2);
383
326 int (*validate_trigger)(struct iio_dev *indio_dev, 384 int (*validate_trigger)(struct iio_dev *indio_dev,
327 struct iio_trigger *trig); 385 struct iio_trigger *trig);
328 int (*update_scan_mode)(struct iio_dev *indio_dev, 386 int (*update_scan_mode)(struct iio_dev *indio_dev,
diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h
index 88bf0f0d27b4..18339ef4ff5d 100644
--- a/include/linux/iio/types.h
+++ b/include/linux/iio/types.h
@@ -54,6 +54,25 @@ enum iio_modifier {
54 IIO_MOD_LIGHT_BLUE, 54 IIO_MOD_LIGHT_BLUE,
55}; 55};
56 56
57enum iio_event_type {
58 IIO_EV_TYPE_THRESH,
59 IIO_EV_TYPE_MAG,
60 IIO_EV_TYPE_ROC,
61 IIO_EV_TYPE_THRESH_ADAPTIVE,
62 IIO_EV_TYPE_MAG_ADAPTIVE,
63};
64
65enum iio_event_info {
66 IIO_EV_INFO_ENABLE,
67 IIO_EV_INFO_VALUE,
68};
69
70enum iio_event_direction {
71 IIO_EV_DIR_EITHER,
72 IIO_EV_DIR_RISING,
73 IIO_EV_DIR_FALLING,
74};
75
57#define IIO_VAL_INT 1 76#define IIO_VAL_INT 1
58#define IIO_VAL_INT_PLUS_MICRO 2 77#define IIO_VAL_INT_PLUS_MICRO 2
59#define IIO_VAL_INT_PLUS_NANO 3 78#define IIO_VAL_INT_PLUS_NANO 3