blob: cf268bc2ee1f63ace29709ff10b27ef953f3be87 [file] [log] [blame]
Jonathan Cameron847ec802009-08-18 18:06:19 +01001/* The industrial I/O core
2 *
3 * Copyright (c) 2008 Jonathan Cameron
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
8 *
9 * Based on elements of hwmon and input subsystems.
10 */
11
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/idr.h>
15#include <linux/kdev_t.h>
16#include <linux/err.h>
17#include <linux/device.h>
18#include <linux/fs.h>
Jonathan Cameron847ec802009-08-18 18:06:19 +010019#include <linux/poll.h>
Jonathan Cameronffc18af2009-10-12 19:18:09 +010020#include <linux/sched.h>
Jeff Mahoney4439c932009-10-12 17:10:34 -040021#include <linux/wait.h>
Jonathan Cameron847ec802009-08-18 18:06:19 +010022#include <linux/cdev.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090023#include <linux/slab.h>
Jonathan Cameron847ec802009-08-18 18:06:19 +010024#include "iio.h"
25#include "trigger_consumer.h"
Jonathan Camerondf9c1c42011-08-12 17:56:03 +010026#include "iio_core.h"
Jonathan Cameron847ec802009-08-18 18:06:19 +010027
28#define IIO_ID_PREFIX "device"
29#define IIO_ID_FORMAT IIO_ID_PREFIX "%d"
30
31/* IDR to assign each registered device a unique id*/
Jonathan Cameronb156cf72010-09-04 17:54:43 +010032static DEFINE_IDA(iio_ida);
Jonathan Cameron847ec802009-08-18 18:06:19 +010033/* IDR to allocate character device minor numbers */
Jonathan Cameronb156cf72010-09-04 17:54:43 +010034static DEFINE_IDA(iio_chrdev_ida);
Jonathan Cameron847ec802009-08-18 18:06:19 +010035/* Lock used to protect both of the above */
Jonathan Cameronb156cf72010-09-04 17:54:43 +010036static DEFINE_SPINLOCK(iio_ida_lock);
Jonathan Cameron847ec802009-08-18 18:06:19 +010037
38dev_t iio_devt;
Jonathan Cameron847ec802009-08-18 18:06:19 +010039
40#define IIO_DEV_MAX 256
Jonathan Cameron5aaaeba2010-05-04 14:43:00 +010041struct bus_type iio_bus_type = {
Jonathan Cameron847ec802009-08-18 18:06:19 +010042 .name = "iio",
Jonathan Cameron847ec802009-08-18 18:06:19 +010043};
Jonathan Cameron5aaaeba2010-05-04 14:43:00 +010044EXPORT_SYMBOL(iio_bus_type);
Jonathan Cameron847ec802009-08-18 18:06:19 +010045
Jonathan Cameron1d892712011-05-18 14:40:51 +010046static const char * const iio_chan_type_name_spec_shared[] = {
Jonathan Cameron1d892712011-05-18 14:40:51 +010047 [IIO_IN] = "in",
Michael Hennerichae191782011-06-10 15:40:48 +020048 [IIO_OUT] = "out",
Michael Hennerichfaf290e2011-05-18 14:42:02 +010049 [IIO_CURRENT] = "current",
50 [IIO_POWER] = "power",
Bryan Freed9bff02f2011-07-07 12:01:54 -070051 [IIO_ACCEL] = "accel",
Jonathan Cameron1d892712011-05-18 14:40:51 +010052 [IIO_IN_DIFF] = "in-in",
53 [IIO_GYRO] = "gyro",
Jonathan Cameron1d892712011-05-18 14:40:51 +010054 [IIO_MAGN] = "magn",
Bryan Freed9bff02f2011-07-07 12:01:54 -070055 [IIO_LIGHT] = "illuminance",
56 [IIO_INTENSITY] = "intensity",
Bryan Freedf09f2c82011-07-07 12:01:55 -070057 [IIO_PROXIMITY] = "proximity",
Bryan Freed9bff02f2011-07-07 12:01:54 -070058 [IIO_TEMP] = "temp",
Jonathan Cameron1d892712011-05-18 14:40:51 +010059 [IIO_INCLI] = "incli",
60 [IIO_ROT] = "rot",
Jonathan Cameron1d892712011-05-18 14:40:51 +010061 [IIO_ANGL] = "angl",
Bryan Freed9bff02f2011-07-07 12:01:54 -070062 [IIO_TIMESTAMP] = "timestamp",
Jonathan Cameron1d892712011-05-18 14:40:51 +010063};
64
65static const char * const iio_chan_type_name_spec_complex[] = {
66 [IIO_IN_DIFF] = "in%d-in%d",
67};
68
69static const char * const iio_modifier_names_light[] = {
70 [IIO_MOD_LIGHT_BOTH] = "both",
71 [IIO_MOD_LIGHT_IR] = "ir",
72};
73
74static const char * const iio_modifier_names_axial[] = {
75 [IIO_MOD_X] = "x",
76 [IIO_MOD_Y] = "y",
77 [IIO_MOD_Z] = "z",
78};
79
80/* relies on pairs of these shared then separate */
81static const char * const iio_chan_info_postfix[] = {
82 [IIO_CHAN_INFO_SCALE_SHARED/2] = "scale",
83 [IIO_CHAN_INFO_OFFSET_SHARED/2] = "offset",
84 [IIO_CHAN_INFO_CALIBSCALE_SHARED/2] = "calibscale",
85 [IIO_CHAN_INFO_CALIBBIAS_SHARED/2] = "calibbias",
Jonathan Cameroneb7fea52011-05-18 14:41:57 +010086 [IIO_CHAN_INFO_PEAK_SHARED/2] = "peak_raw",
87 [IIO_CHAN_INFO_PEAK_SCALE_SHARED/2] = "peak_scale",
Jonathan Cameron7d438172011-08-12 17:47:53 +010088 [IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SHARED/2]
89 = "quadrature_correction_raw",
Jonathan Cameron1d892712011-05-18 14:40:51 +010090};
91
Jonathan Cameron9aa1a162011-08-12 17:08:50 +010092/* Return a negative errno on failure */
Jonathan Camerondf9c1c42011-08-12 17:56:03 +010093static int iio_get_new_ida_val(struct ida *this_ida)
Jonathan Cameron9aa1a162011-08-12 17:08:50 +010094{
95 int ret;
96 int val;
97
98ida_again:
99 if (unlikely(ida_pre_get(this_ida, GFP_KERNEL) == 0))
100 return -ENOMEM;
101
102 spin_lock(&iio_ida_lock);
103 ret = ida_get_new(this_ida, &val);
104 spin_unlock(&iio_ida_lock);
105 if (unlikely(ret == -EAGAIN))
106 goto ida_again;
107 else if (unlikely(ret))
108 return ret;
109
110 return val;
111}
Jonathan Cameron9aa1a162011-08-12 17:08:50 +0100112
Jonathan Camerondf9c1c42011-08-12 17:56:03 +0100113static void iio_free_ida_val(struct ida *this_ida, int id)
Jonathan Cameron9aa1a162011-08-12 17:08:50 +0100114{
115 spin_lock(&iio_ida_lock);
116 ida_remove(this_ida, id);
117 spin_unlock(&iio_ida_lock);
118}
Jonathan Cameron9aa1a162011-08-12 17:08:50 +0100119
Jonathan Cameronaaf370d2011-05-18 14:41:16 +0100120int iio_push_event(struct iio_dev *dev_info,
121 int ev_line,
122 int ev_code,
123 s64 timestamp)
Jonathan Cameron847ec802009-08-18 18:06:19 +0100124{
Jonathan Cameronaaf370d2011-05-18 14:41:16 +0100125 struct iio_event_interface *ev_int
126 = &dev_info->event_interfaces[ev_line];
Jonathan Cameron847ec802009-08-18 18:06:19 +0100127 struct iio_detected_event_list *ev;
128 int ret = 0;
129
130 /* Does anyone care? */
131 mutex_lock(&ev_int->event_list_lock);
132 if (test_bit(IIO_BUSY_BIT_POS, &ev_int->handler.flags)) {
Jonathan Cameron75c80752010-01-09 16:57:34 +0000133 if (ev_int->current_events == ev_int->max_events) {
134 mutex_unlock(&ev_int->event_list_lock);
Jonathan Cameron847ec802009-08-18 18:06:19 +0100135 return 0;
Jonathan Cameron75c80752010-01-09 16:57:34 +0000136 }
Jonathan Cameron847ec802009-08-18 18:06:19 +0100137 ev = kmalloc(sizeof(*ev), GFP_KERNEL);
138 if (ev == NULL) {
139 ret = -ENOMEM;
Jonathan Cameron75c80752010-01-09 16:57:34 +0000140 mutex_unlock(&ev_int->event_list_lock);
Jonathan Cameron847ec802009-08-18 18:06:19 +0100141 goto error_ret;
142 }
143 ev->ev.id = ev_code;
144 ev->ev.timestamp = timestamp;
Jonathan Cameron847ec802009-08-18 18:06:19 +0100145
Jonathan Cameron3b8ebfb2011-05-18 14:42:21 +0100146 list_add_tail(&ev->list, &ev_int->det_events);
Jonathan Cameron847ec802009-08-18 18:06:19 +0100147 ev_int->current_events++;
148 mutex_unlock(&ev_int->event_list_lock);
149 wake_up_interruptible(&ev_int->wait);
150 } else
151 mutex_unlock(&ev_int->event_list_lock);
152
153error_ret:
154 return ret;
155}
Jonathan Cameron847ec802009-08-18 18:06:19 +0100156EXPORT_SYMBOL(iio_push_event);
157
Jonathan Cameron847ec802009-08-18 18:06:19 +0100158
159/* This turns up an awful lot */
160ssize_t iio_read_const_attr(struct device *dev,
161 struct device_attribute *attr,
162 char *buf)
163{
164 return sprintf(buf, "%s\n", to_iio_const_attr(attr)->string);
165}
166EXPORT_SYMBOL(iio_read_const_attr);
167
Jonathan Cameron847ec802009-08-18 18:06:19 +0100168
Mark Brown77712e52010-02-18 17:19:17 +0000169static ssize_t iio_event_chrdev_read(struct file *filep,
170 char __user *buf,
171 size_t count,
172 loff_t *f_ps)
Jonathan Cameron847ec802009-08-18 18:06:19 +0100173{
174 struct iio_event_interface *ev_int = filep->private_data;
175 struct iio_detected_event_list *el;
176 int ret;
177 size_t len;
178
179 mutex_lock(&ev_int->event_list_lock);
Jonathan Cameron3b8ebfb2011-05-18 14:42:21 +0100180 if (list_empty(&ev_int->det_events)) {
Jonathan Cameron847ec802009-08-18 18:06:19 +0100181 if (filep->f_flags & O_NONBLOCK) {
182 ret = -EAGAIN;
183 goto error_mutex_unlock;
184 }
185 mutex_unlock(&ev_int->event_list_lock);
186 /* Blocking on device; waiting for something to be there */
187 ret = wait_event_interruptible(ev_int->wait,
188 !list_empty(&ev_int
Jonathan Cameron3b8ebfb2011-05-18 14:42:21 +0100189 ->det_events));
Jonathan Cameron847ec802009-08-18 18:06:19 +0100190 if (ret)
191 goto error_ret;
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300192 /* Single access device so no one else can get the data */
Jonathan Cameron847ec802009-08-18 18:06:19 +0100193 mutex_lock(&ev_int->event_list_lock);
194 }
195
Jonathan Cameron3b8ebfb2011-05-18 14:42:21 +0100196 el = list_first_entry(&ev_int->det_events,
Jonathan Cameron847ec802009-08-18 18:06:19 +0100197 struct iio_detected_event_list,
198 list);
199 len = sizeof el->ev;
200 if (copy_to_user(buf, &(el->ev), len)) {
201 ret = -EFAULT;
202 goto error_mutex_unlock;
203 }
204 list_del(&el->list);
205 ev_int->current_events--;
206 mutex_unlock(&ev_int->event_list_lock);
Jonathan Cameron847ec802009-08-18 18:06:19 +0100207 kfree(el);
208
209 return len;
210
211error_mutex_unlock:
212 mutex_unlock(&ev_int->event_list_lock);
213error_ret:
214
215 return ret;
216}
217
Mark Brown77712e52010-02-18 17:19:17 +0000218static int iio_event_chrdev_release(struct inode *inode, struct file *filep)
Jonathan Cameron847ec802009-08-18 18:06:19 +0100219{
220 struct iio_handler *hand = iio_cdev_to_handler(inode->i_cdev);
221 struct iio_event_interface *ev_int = hand->private;
222 struct iio_detected_event_list *el, *t;
223
224 mutex_lock(&ev_int->event_list_lock);
225 clear_bit(IIO_BUSY_BIT_POS, &ev_int->handler.flags);
226 /*
227 * In order to maintain a clean state for reopening,
228 * clear out any awaiting events. The mask will prevent
229 * any new __iio_push_event calls running.
230 */
Jonathan Cameron3b8ebfb2011-05-18 14:42:21 +0100231 list_for_each_entry_safe(el, t, &ev_int->det_events, list) {
Jonathan Cameron847ec802009-08-18 18:06:19 +0100232 list_del(&el->list);
233 kfree(el);
234 }
235 mutex_unlock(&ev_int->event_list_lock);
236
237 return 0;
238}
239
Mark Brown77712e52010-02-18 17:19:17 +0000240static int iio_event_chrdev_open(struct inode *inode, struct file *filep)
Jonathan Cameron847ec802009-08-18 18:06:19 +0100241{
242 struct iio_handler *hand = iio_cdev_to_handler(inode->i_cdev);
243 struct iio_event_interface *ev_int = hand->private;
244
245 mutex_lock(&ev_int->event_list_lock);
246 if (test_and_set_bit(IIO_BUSY_BIT_POS, &hand->flags)) {
247 fops_put(filep->f_op);
248 mutex_unlock(&ev_int->event_list_lock);
249 return -EBUSY;
250 }
251 filep->private_data = hand->private;
252 mutex_unlock(&ev_int->event_list_lock);
253
254 return 0;
255}
256
257static const struct file_operations iio_event_chrdev_fileops = {
258 .read = iio_event_chrdev_read,
259 .release = iio_event_chrdev_release,
260 .open = iio_event_chrdev_open,
261 .owner = THIS_MODULE,
Arnd Bergmann6038f372010-08-15 18:52:59 +0200262 .llseek = noop_llseek,
Jonathan Cameron847ec802009-08-18 18:06:19 +0100263};
264
265static void iio_event_dev_release(struct device *dev)
266{
267 struct iio_event_interface *ev_int
268 = container_of(dev, struct iio_event_interface, dev);
269 cdev_del(&ev_int->handler.chrdev);
270 iio_device_free_chrdev_minor(MINOR(dev->devt));
271};
272
273static struct device_type iio_event_type = {
274 .release = iio_event_dev_release,
275};
276
277int iio_device_get_chrdev_minor(void)
278{
Jonathan Cameron9aa1a162011-08-12 17:08:50 +0100279 int ret;
Jonathan Cameron847ec802009-08-18 18:06:19 +0100280
Jonathan Cameron9aa1a162011-08-12 17:08:50 +0100281 ret = iio_get_new_ida_val(&iio_chrdev_ida);
282 if (ret < IIO_DEV_MAX) /* both errors and valid */
Jonathan Cameron847ec802009-08-18 18:06:19 +0100283 return ret;
Jonathan Cameron9aa1a162011-08-12 17:08:50 +0100284 else
Jonathan Cameron847ec802009-08-18 18:06:19 +0100285 return -ENOMEM;
Jonathan Cameron847ec802009-08-18 18:06:19 +0100286}
287
288void iio_device_free_chrdev_minor(int val)
289{
Jonathan Cameron9aa1a162011-08-12 17:08:50 +0100290 iio_free_ida_val(&iio_chrdev_ida, val);
Jonathan Cameron847ec802009-08-18 18:06:19 +0100291}
292
Jonathan Cameronb9d40a92011-05-18 14:40:56 +0100293static int iio_setup_ev_int(struct iio_event_interface *ev_int,
Jonathan Cameronc74b0de2011-05-18 14:42:33 +0100294 const char *dev_name,
295 int index,
296 struct module *owner,
297 struct device *dev)
Jonathan Cameron847ec802009-08-18 18:06:19 +0100298{
299 int ret, minor;
300
Jonathan Cameron5aaaeba2010-05-04 14:43:00 +0100301 ev_int->dev.bus = &iio_bus_type;
Jonathan Cameron847ec802009-08-18 18:06:19 +0100302 ev_int->dev.parent = dev;
303 ev_int->dev.type = &iio_event_type;
304 device_initialize(&ev_int->dev);
305
306 minor = iio_device_get_chrdev_minor();
307 if (minor < 0) {
308 ret = minor;
309 goto error_device_put;
310 }
311 ev_int->dev.devt = MKDEV(MAJOR(iio_devt), minor);
Jonathan Cameronc74b0de2011-05-18 14:42:33 +0100312 dev_set_name(&ev_int->dev, "%s:event%d", dev_name, index);
Jonathan Cameron847ec802009-08-18 18:06:19 +0100313
314 ret = device_add(&ev_int->dev);
315 if (ret)
316 goto error_free_minor;
317
318 cdev_init(&ev_int->handler.chrdev, &iio_event_chrdev_fileops);
319 ev_int->handler.chrdev.owner = owner;
320
321 mutex_init(&ev_int->event_list_lock);
322 /* discussion point - make this variable? */
323 ev_int->max_events = 10;
324 ev_int->current_events = 0;
Jonathan Cameron3b8ebfb2011-05-18 14:42:21 +0100325 INIT_LIST_HEAD(&ev_int->det_events);
Jonathan Cameron847ec802009-08-18 18:06:19 +0100326 init_waitqueue_head(&ev_int->wait);
327 ev_int->handler.private = ev_int;
328 ev_int->handler.flags = 0;
329
330 ret = cdev_add(&ev_int->handler.chrdev, ev_int->dev.devt, 1);
331 if (ret)
332 goto error_unreg_device;
333
334 return 0;
335
336error_unreg_device:
337 device_unregister(&ev_int->dev);
338error_free_minor:
339 iio_device_free_chrdev_minor(minor);
340error_device_put:
341 put_device(&ev_int->dev);
342
343 return ret;
344}
345
Jonathan Cameronb9d40a92011-05-18 14:40:56 +0100346static void iio_free_ev_int(struct iio_event_interface *ev_int)
Jonathan Cameron847ec802009-08-18 18:06:19 +0100347{
348 device_unregister(&ev_int->dev);
349 put_device(&ev_int->dev);
350}
351
Jonathan Cameron847ec802009-08-18 18:06:19 +0100352static int __init iio_init(void)
353{
354 int ret;
355
Jonathan Cameron5aaaeba2010-05-04 14:43:00 +0100356 /* Register sysfs bus */
357 ret = bus_register(&iio_bus_type);
Jonathan Cameron847ec802009-08-18 18:06:19 +0100358 if (ret < 0) {
359 printk(KERN_ERR
Jonathan Cameron5aaaeba2010-05-04 14:43:00 +0100360 "%s could not register bus type\n",
Jonathan Cameron847ec802009-08-18 18:06:19 +0100361 __FILE__);
362 goto error_nothing;
363 }
364
Jonathan Cameron9aa1a162011-08-12 17:08:50 +0100365 ret = alloc_chrdev_region(&iio_devt, 0, IIO_DEV_MAX, "iio");
366 if (ret < 0) {
367 printk(KERN_ERR "%s: failed to allocate char dev region\n",
368 __FILE__);
Jonathan Cameron5aaaeba2010-05-04 14:43:00 +0100369 goto error_unregister_bus_type;
Jonathan Cameron9aa1a162011-08-12 17:08:50 +0100370 }
Jonathan Cameron847ec802009-08-18 18:06:19 +0100371
372 return 0;
373
Jonathan Cameron5aaaeba2010-05-04 14:43:00 +0100374error_unregister_bus_type:
375 bus_unregister(&iio_bus_type);
Jonathan Cameron847ec802009-08-18 18:06:19 +0100376error_nothing:
377 return ret;
378}
379
380static void __exit iio_exit(void)
381{
Jonathan Cameron9aa1a162011-08-12 17:08:50 +0100382 if (iio_devt)
383 unregister_chrdev_region(iio_devt, IIO_DEV_MAX);
Jonathan Cameron5aaaeba2010-05-04 14:43:00 +0100384 bus_unregister(&iio_bus_type);
Jonathan Cameron847ec802009-08-18 18:06:19 +0100385}
386
Jonathan Cameron1d892712011-05-18 14:40:51 +0100387static ssize_t iio_read_channel_info(struct device *dev,
388 struct device_attribute *attr,
389 char *buf)
Jonathan Cameron847ec802009-08-18 18:06:19 +0100390{
Jonathan Cameron1d892712011-05-18 14:40:51 +0100391 struct iio_dev *indio_dev = dev_get_drvdata(dev);
392 struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
393 int val, val2;
Jonathan Cameron6fe81352011-05-18 14:42:37 +0100394 int ret = indio_dev->info->read_raw(indio_dev, this_attr->c,
395 &val, &val2, this_attr->address);
Jonathan Cameron847ec802009-08-18 18:06:19 +0100396
Jonathan Cameron1d892712011-05-18 14:40:51 +0100397 if (ret < 0)
398 return ret;
399
400 if (ret == IIO_VAL_INT)
401 return sprintf(buf, "%d\n", val);
402 else if (ret == IIO_VAL_INT_PLUS_MICRO) {
403 if (val2 < 0)
404 return sprintf(buf, "-%d.%06u\n", val, -val2);
405 else
406 return sprintf(buf, "%d.%06u\n", val, val2);
Michael Hennerich71646e22011-06-27 13:07:07 +0100407 } else if (ret == IIO_VAL_INT_PLUS_NANO) {
408 if (val2 < 0)
409 return sprintf(buf, "-%d.%09u\n", val, -val2);
410 else
411 return sprintf(buf, "%d.%09u\n", val, val2);
Jonathan Cameron1d892712011-05-18 14:40:51 +0100412 } else
413 return 0;
414}
415
416static ssize_t iio_write_channel_info(struct device *dev,
417 struct device_attribute *attr,
418 const char *buf,
419 size_t len)
420{
421 struct iio_dev *indio_dev = dev_get_drvdata(dev);
422 struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
Michael Hennerich5c04af02011-06-27 13:07:10 +0100423 int ret, integer = 0, fract = 0, fract_mult = 100000;
Jonathan Cameron1d892712011-05-18 14:40:51 +0100424 bool integer_part = true, negative = false;
425
426 /* Assumes decimal - precision based on number of digits */
Jonathan Cameron6fe81352011-05-18 14:42:37 +0100427 if (!indio_dev->info->write_raw)
Jonathan Cameron1d892712011-05-18 14:40:51 +0100428 return -EINVAL;
Michael Hennerich5c04af02011-06-27 13:07:10 +0100429
430 if (indio_dev->info->write_raw_get_fmt)
431 switch (indio_dev->info->write_raw_get_fmt(indio_dev,
432 this_attr->c, this_attr->address)) {
433 case IIO_VAL_INT_PLUS_MICRO:
434 fract_mult = 100000;
435 break;
436 case IIO_VAL_INT_PLUS_NANO:
437 fract_mult = 100000000;
438 break;
439 default:
440 return -EINVAL;
441 }
442
Jonathan Cameron1d892712011-05-18 14:40:51 +0100443 if (buf[0] == '-') {
444 negative = true;
445 buf++;
446 }
Michael Hennerich5c04af02011-06-27 13:07:10 +0100447
Jonathan Cameron1d892712011-05-18 14:40:51 +0100448 while (*buf) {
449 if ('0' <= *buf && *buf <= '9') {
450 if (integer_part)
451 integer = integer*10 + *buf - '0';
452 else {
Michael Hennerich5c04af02011-06-27 13:07:10 +0100453 fract += fract_mult*(*buf - '0');
454 if (fract_mult == 1)
Jonathan Cameron1d892712011-05-18 14:40:51 +0100455 break;
Michael Hennerich5c04af02011-06-27 13:07:10 +0100456 fract_mult /= 10;
Jonathan Cameron1d892712011-05-18 14:40:51 +0100457 }
458 } else if (*buf == '\n') {
459 if (*(buf + 1) == '\0')
460 break;
461 else
462 return -EINVAL;
463 } else if (*buf == '.') {
464 integer_part = false;
465 } else {
466 return -EINVAL;
467 }
468 buf++;
469 }
470 if (negative) {
471 if (integer)
472 integer = -integer;
473 else
Michael Hennerich5c04af02011-06-27 13:07:10 +0100474 fract = -fract;
Jonathan Cameron847ec802009-08-18 18:06:19 +0100475 }
476
Jonathan Cameron6fe81352011-05-18 14:42:37 +0100477 ret = indio_dev->info->write_raw(indio_dev, this_attr->c,
Michael Hennerich5c04af02011-06-27 13:07:10 +0100478 integer, fract, this_attr->address);
Jonathan Cameron1d892712011-05-18 14:40:51 +0100479 if (ret)
480 return ret;
481
482 return len;
483}
484
485static int __iio_build_postfix(struct iio_chan_spec const *chan,
486 bool generic,
487 const char *postfix,
488 char **result)
489{
490 char *all_post;
491 /* 3 options - generic, extend_name, modified - if generic, extend_name
492 * and modified cannot apply.*/
493
494 if (generic || (!chan->modified && !chan->extend_name)) {
495 all_post = kasprintf(GFP_KERNEL, "%s", postfix);
496 } else if (chan->modified) {
497 const char *intermediate;
498 switch (chan->type) {
499 case IIO_INTENSITY:
500 intermediate
501 = iio_modifier_names_light[chan->channel2];
502 break;
503 case IIO_ACCEL:
504 case IIO_GYRO:
505 case IIO_MAGN:
506 case IIO_INCLI:
507 case IIO_ROT:
508 case IIO_ANGL:
509 intermediate
510 = iio_modifier_names_axial[chan->channel2];
511 break;
512 default:
513 return -EINVAL;
514 }
515 if (chan->extend_name)
516 all_post = kasprintf(GFP_KERNEL, "%s_%s_%s",
517 intermediate,
518 chan->extend_name,
519 postfix);
520 else
521 all_post = kasprintf(GFP_KERNEL, "%s_%s",
522 intermediate,
523 postfix);
524 } else
525 all_post = kasprintf(GFP_KERNEL, "%s_%s", chan->extend_name,
526 postfix);
527 if (all_post == NULL)
528 return -ENOMEM;
529 *result = all_post;
530 return 0;
531}
532
Jonathan Camerondf9c1c42011-08-12 17:56:03 +0100533static
Jonathan Cameron1d892712011-05-18 14:40:51 +0100534int __iio_device_attr_init(struct device_attribute *dev_attr,
535 const char *postfix,
536 struct iio_chan_spec const *chan,
537 ssize_t (*readfunc)(struct device *dev,
538 struct device_attribute *attr,
539 char *buf),
540 ssize_t (*writefunc)(struct device *dev,
541 struct device_attribute *attr,
542 const char *buf,
543 size_t len),
544 bool generic)
545{
546 int ret;
547 char *name_format, *full_postfix;
548 sysfs_attr_init(&dev_attr->attr);
549 ret = __iio_build_postfix(chan, generic, postfix, &full_postfix);
550 if (ret)
551 goto error_ret;
552
553 /* Special case for types that uses both channel numbers in naming */
554 if (chan->type == IIO_IN_DIFF && !generic)
555 name_format
556 = kasprintf(GFP_KERNEL, "%s_%s",
557 iio_chan_type_name_spec_complex[chan->type],
558 full_postfix);
559 else if (generic || !chan->indexed)
560 name_format
561 = kasprintf(GFP_KERNEL, "%s_%s",
562 iio_chan_type_name_spec_shared[chan->type],
563 full_postfix);
564 else
565 name_format
566 = kasprintf(GFP_KERNEL, "%s%d_%s",
567 iio_chan_type_name_spec_shared[chan->type],
568 chan->channel,
569 full_postfix);
570
571 if (name_format == NULL) {
572 ret = -ENOMEM;
573 goto error_free_full_postfix;
574 }
575 dev_attr->attr.name = kasprintf(GFP_KERNEL,
576 name_format,
577 chan->channel,
578 chan->channel2);
579 if (dev_attr->attr.name == NULL) {
580 ret = -ENOMEM;
581 goto error_free_name_format;
582 }
583
584 if (readfunc) {
585 dev_attr->attr.mode |= S_IRUGO;
586 dev_attr->show = readfunc;
587 }
588
589 if (writefunc) {
590 dev_attr->attr.mode |= S_IWUSR;
591 dev_attr->store = writefunc;
592 }
593 kfree(name_format);
594 kfree(full_postfix);
595
596 return 0;
597
598error_free_name_format:
599 kfree(name_format);
600error_free_full_postfix:
601 kfree(full_postfix);
Jonathan Cameron847ec802009-08-18 18:06:19 +0100602error_ret:
603 return ret;
604}
605
Jonathan Camerondf9c1c42011-08-12 17:56:03 +0100606static void __iio_device_attr_deinit(struct device_attribute *dev_attr)
Jonathan Cameron1d892712011-05-18 14:40:51 +0100607{
608 kfree(dev_attr->attr.name);
609}
610
611int __iio_add_chan_devattr(const char *postfix,
612 const char *group,
613 struct iio_chan_spec const *chan,
614 ssize_t (*readfunc)(struct device *dev,
615 struct device_attribute *attr,
616 char *buf),
617 ssize_t (*writefunc)(struct device *dev,
618 struct device_attribute *attr,
619 const char *buf,
620 size_t len),
621 int mask,
622 bool generic,
623 struct device *dev,
624 struct list_head *attr_list)
625{
626 int ret;
627 struct iio_dev_attr *iio_attr, *t;
628
629 iio_attr = kzalloc(sizeof *iio_attr, GFP_KERNEL);
630 if (iio_attr == NULL) {
631 ret = -ENOMEM;
632 goto error_ret;
633 }
634 ret = __iio_device_attr_init(&iio_attr->dev_attr,
635 postfix, chan,
636 readfunc, writefunc, generic);
637 if (ret)
638 goto error_iio_dev_attr_free;
639 iio_attr->c = chan;
640 iio_attr->address = mask;
641 list_for_each_entry(t, attr_list, l)
642 if (strcmp(t->dev_attr.attr.name,
643 iio_attr->dev_attr.attr.name) == 0) {
644 if (!generic)
645 dev_err(dev, "tried to double register : %s\n",
646 t->dev_attr.attr.name);
647 ret = -EBUSY;
648 goto error_device_attr_deinit;
649 }
650
651 ret = sysfs_add_file_to_group(&dev->kobj,
652 &iio_attr->dev_attr.attr, group);
653 if (ret < 0)
654 goto error_device_attr_deinit;
655
656 list_add(&iio_attr->l, attr_list);
657
658 return 0;
659
660error_device_attr_deinit:
661 __iio_device_attr_deinit(&iio_attr->dev_attr);
662error_iio_dev_attr_free:
663 kfree(iio_attr);
664error_ret:
665 return ret;
666}
667
668static int iio_device_add_channel_sysfs(struct iio_dev *dev_info,
669 struct iio_chan_spec const *chan)
670{
671 int ret, i;
672
673
674 if (chan->channel < 0)
675 return 0;
676 if (chan->processed_val)
677 ret = __iio_add_chan_devattr("input", NULL, chan,
678 &iio_read_channel_info,
679 NULL,
680 0,
681 0,
682 &dev_info->dev,
683 &dev_info->channel_attr_list);
684 else
685 ret = __iio_add_chan_devattr("raw", NULL, chan,
686 &iio_read_channel_info,
Michael Hennerichae191782011-06-10 15:40:48 +0200687 (chan->type == IIO_OUT ?
688 &iio_write_channel_info : NULL),
Jonathan Cameron1d892712011-05-18 14:40:51 +0100689 0,
690 0,
691 &dev_info->dev,
692 &dev_info->channel_attr_list);
693 if (ret)
694 goto error_ret;
695
696 for_each_set_bit(i, &chan->info_mask, sizeof(long)*8) {
697 ret = __iio_add_chan_devattr(iio_chan_info_postfix[i/2],
698 NULL, chan,
699 &iio_read_channel_info,
700 &iio_write_channel_info,
701 (1 << i),
702 !(i%2),
703 &dev_info->dev,
704 &dev_info->channel_attr_list);
705 if (ret == -EBUSY && (i%2 == 0)) {
706 ret = 0;
707 continue;
708 }
709 if (ret < 0)
710 goto error_ret;
711 }
712error_ret:
713 return ret;
714}
715
716static void iio_device_remove_and_free_read_attr(struct iio_dev *dev_info,
717 struct iio_dev_attr *p)
718{
719 sysfs_remove_file_from_group(&dev_info->dev.kobj,
720 &p->dev_attr.attr, NULL);
721 kfree(p->dev_attr.attr.name);
722 kfree(p);
723}
724
Jonathan Cameron1b732882011-05-18 14:41:43 +0100725static ssize_t iio_show_dev_name(struct device *dev,
726 struct device_attribute *attr,
727 char *buf)
728{
729 struct iio_dev *indio_dev = dev_get_drvdata(dev);
730 return sprintf(buf, "%s\n", indio_dev->name);
731}
732
733static DEVICE_ATTR(name, S_IRUGO, iio_show_dev_name, NULL);
734
Jonathan Cameronf7256872011-08-12 16:55:35 +0100735static struct attribute *iio_base_dummy_attrs[] = {
736 NULL
737};
738static struct attribute_group iio_base_dummy_group = {
739 .attrs = iio_base_dummy_attrs,
740};
741
Jonathan Cameron1d892712011-05-18 14:40:51 +0100742static int iio_device_register_sysfs(struct iio_dev *dev_info)
743{
744 int i, ret = 0;
745 struct iio_dev_attr *p, *n;
746
Jonathan Cameronf7256872011-08-12 16:55:35 +0100747 if (dev_info->info->attrs)
Jonathan Cameron6fe81352011-05-18 14:42:37 +0100748 ret = sysfs_create_group(&dev_info->dev.kobj,
749 dev_info->info->attrs);
Jonathan Cameronf7256872011-08-12 16:55:35 +0100750 else
751 ret = sysfs_create_group(&dev_info->dev.kobj,
752 &iio_base_dummy_group);
753
754 if (ret) {
755 dev_err(dev_info->dev.parent,
756 "Failed to register sysfs hooks\n");
757 goto error_ret;
Jonathan Cameron1d892712011-05-18 14:40:51 +0100758 }
759
760 /*
761 * New channel registration method - relies on the fact a group does
762 * not need to be initialized if it is name is NULL.
763 */
764 INIT_LIST_HEAD(&dev_info->channel_attr_list);
765 if (dev_info->channels)
766 for (i = 0; i < dev_info->num_channels; i++) {
767 ret = iio_device_add_channel_sysfs(dev_info,
768 &dev_info
769 ->channels[i]);
770 if (ret < 0)
771 goto error_clear_attrs;
772 }
Jonathan Cameronf7256872011-08-12 16:55:35 +0100773 if (dev_info->name) {
Jonathan Cameron1b732882011-05-18 14:41:43 +0100774 ret = sysfs_add_file_to_group(&dev_info->dev.kobj,
775 &dev_attr_name.attr,
776 NULL);
777 if (ret)
778 goto error_clear_attrs;
779 }
Jonathan Cameron1d892712011-05-18 14:40:51 +0100780 return 0;
Jonathan Cameron1b732882011-05-18 14:41:43 +0100781
Jonathan Cameron1d892712011-05-18 14:40:51 +0100782error_clear_attrs:
783 list_for_each_entry_safe(p, n,
784 &dev_info->channel_attr_list, l) {
785 list_del(&p->l);
786 iio_device_remove_and_free_read_attr(dev_info, p);
787 }
Jonathan Cameron6fe81352011-05-18 14:42:37 +0100788 if (dev_info->info->attrs)
789 sysfs_remove_group(&dev_info->dev.kobj, dev_info->info->attrs);
Jonathan Cameronf7256872011-08-12 16:55:35 +0100790 else
791 sysfs_remove_group(&dev_info->dev.kobj, &iio_base_dummy_group);
Jonathan Cameron1d892712011-05-18 14:40:51 +0100792error_ret:
793 return ret;
794
795}
796
Jonathan Cameron847ec802009-08-18 18:06:19 +0100797static void iio_device_unregister_sysfs(struct iio_dev *dev_info)
798{
Jonathan Cameron1d892712011-05-18 14:40:51 +0100799
800 struct iio_dev_attr *p, *n;
Jonathan Cameron1b732882011-05-18 14:41:43 +0100801 if (dev_info->name)
802 sysfs_remove_file_from_group(&dev_info->dev.kobj,
803 &dev_attr_name.attr,
804 NULL);
Jonathan Cameron1d892712011-05-18 14:40:51 +0100805 list_for_each_entry_safe(p, n, &dev_info->channel_attr_list, l) {
806 list_del(&p->l);
807 iio_device_remove_and_free_read_attr(dev_info, p);
808 }
809
Jonathan Cameron6fe81352011-05-18 14:42:37 +0100810 if (dev_info->info->attrs)
811 sysfs_remove_group(&dev_info->dev.kobj, dev_info->info->attrs);
Jonathan Cameronf7256872011-08-12 16:55:35 +0100812 else
813 sysfs_remove_group(&dev_info->dev.kobj, &iio_base_dummy_group);
Jonathan Cameron847ec802009-08-18 18:06:19 +0100814}
815
Jonathan Cameron1d892712011-05-18 14:40:51 +0100816static const char * const iio_ev_type_text[] = {
817 [IIO_EV_TYPE_THRESH] = "thresh",
818 [IIO_EV_TYPE_MAG] = "mag",
819 [IIO_EV_TYPE_ROC] = "roc"
820};
821
822static const char * const iio_ev_dir_text[] = {
823 [IIO_EV_DIR_EITHER] = "either",
824 [IIO_EV_DIR_RISING] = "rising",
825 [IIO_EV_DIR_FALLING] = "falling"
826};
827
828static ssize_t iio_ev_state_store(struct device *dev,
829 struct device_attribute *attr,
830 const char *buf,
831 size_t len)
832{
833 struct iio_dev *indio_dev = dev_get_drvdata(dev);
Jonathan Cameronaaf370d2011-05-18 14:41:16 +0100834 struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
Jonathan Cameron1d892712011-05-18 14:40:51 +0100835 int ret;
Jonathan Cameronc74b0de2011-05-18 14:42:33 +0100836 bool val;
837
838 ret = strtobool(buf, &val);
839 if (ret < 0)
840 return ret;
Jonathan Cameron1d892712011-05-18 14:40:51 +0100841
Jonathan Cameron6fe81352011-05-18 14:42:37 +0100842 ret = indio_dev->info->write_event_config(indio_dev,
843 this_attr->address,
844 val);
Jonathan Cameron1d892712011-05-18 14:40:51 +0100845 return (ret < 0) ? ret : len;
846}
847
848static ssize_t iio_ev_state_show(struct device *dev,
849 struct device_attribute *attr,
850 char *buf)
851{
852 struct iio_dev *indio_dev = dev_get_drvdata(dev);
Jonathan Cameronaaf370d2011-05-18 14:41:16 +0100853 struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
Jonathan Cameron6fe81352011-05-18 14:42:37 +0100854 int val = indio_dev->info->read_event_config(indio_dev,
855 this_attr->address);
Jonathan Cameron1d892712011-05-18 14:40:51 +0100856
857 if (val < 0)
858 return val;
859 else
860 return sprintf(buf, "%d\n", val);
861}
862
863static ssize_t iio_ev_value_show(struct device *dev,
864 struct device_attribute *attr,
865 char *buf)
866{
867 struct iio_dev *indio_dev = dev_get_drvdata(dev);
868 struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
869 int val, ret;
870
Jonathan Cameron6fe81352011-05-18 14:42:37 +0100871 ret = indio_dev->info->read_event_value(indio_dev,
872 this_attr->address, &val);
Jonathan Cameron1d892712011-05-18 14:40:51 +0100873 if (ret < 0)
874 return ret;
875
876 return sprintf(buf, "%d\n", val);
877}
878
879static ssize_t iio_ev_value_store(struct device *dev,
880 struct device_attribute *attr,
881 const char *buf,
882 size_t len)
883{
884 struct iio_dev *indio_dev = dev_get_drvdata(dev);
885 struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
886 unsigned long val;
887 int ret;
888
889 ret = strict_strtoul(buf, 10, &val);
890 if (ret)
891 return ret;
892
Jonathan Cameron6fe81352011-05-18 14:42:37 +0100893 ret = indio_dev->info->write_event_value(indio_dev, this_attr->address,
894 val);
Jonathan Cameron1d892712011-05-18 14:40:51 +0100895 if (ret < 0)
896 return ret;
897
898 return len;
899}
900
Jonathan Cameron1d892712011-05-18 14:40:51 +0100901static int iio_device_add_event_sysfs(struct iio_dev *dev_info,
902 struct iio_chan_spec const *chan)
903{
904
Jonathan Camerondf9c1c42011-08-12 17:56:03 +0100905 int ret = 0, i, mask = 0;
Jonathan Cameron1d892712011-05-18 14:40:51 +0100906 char *postfix;
907 if (!chan->event_mask)
908 return 0;
909
910 for_each_set_bit(i, &chan->event_mask, sizeof(chan->event_mask)*8) {
911 postfix = kasprintf(GFP_KERNEL, "%s_%s_en",
912 iio_ev_type_text[i/IIO_EV_TYPE_MAX],
913 iio_ev_dir_text[i%IIO_EV_TYPE_MAX]);
914 if (postfix == NULL) {
915 ret = -ENOMEM;
916 goto error_ret;
917 }
918 switch (chan->type) {
919 /* Switch this to a table at some point */
920 case IIO_IN:
921 mask = IIO_UNMOD_EVENT_CODE(chan->type, chan->channel,
922 i/IIO_EV_TYPE_MAX,
923 i%IIO_EV_TYPE_MAX);
924 break;
925 case IIO_ACCEL:
926 mask = IIO_MOD_EVENT_CODE(chan->type, 0, chan->channel,
927 i/IIO_EV_TYPE_MAX,
928 i%IIO_EV_TYPE_MAX);
929 break;
930 case IIO_IN_DIFF:
931 mask = IIO_MOD_EVENT_CODE(chan->type, chan->channel,
932 chan->channel2,
933 i/IIO_EV_TYPE_MAX,
934 i%IIO_EV_TYPE_MAX);
935 break;
936 default:
937 printk(KERN_INFO "currently unhandled type of event\n");
Jonathan Cameron9076faa2011-08-12 16:55:36 +0100938 continue;
Jonathan Cameron1d892712011-05-18 14:40:51 +0100939 }
Jonathan Cameronaaf370d2011-05-18 14:41:16 +0100940 ret = __iio_add_chan_devattr(postfix,
941 NULL,
942 chan,
943 &iio_ev_state_show,
944 iio_ev_state_store,
945 mask,
946 /*HACK. - limits us to one
947 event interface - fix by
948 extending the bitmask - but
949 how far*/
950 0,
Jonathan Cameron6fe81352011-05-18 14:42:37 +0100951 &dev_info->event_interfaces[0].dev,
Jonathan Cameronaaf370d2011-05-18 14:41:16 +0100952 &dev_info->event_interfaces[0].
953 dev_attr_list);
Jonathan Cameron1d892712011-05-18 14:40:51 +0100954 kfree(postfix);
955 if (ret)
956 goto error_ret;
957
958 postfix = kasprintf(GFP_KERNEL, "%s_%s_value",
959 iio_ev_type_text[i/IIO_EV_TYPE_MAX],
960 iio_ev_dir_text[i%IIO_EV_TYPE_MAX]);
961 if (postfix == NULL) {
962 ret = -ENOMEM;
963 goto error_ret;
964 }
965 ret = __iio_add_chan_devattr(postfix, NULL, chan,
966 iio_ev_value_show,
967 iio_ev_value_store,
968 mask,
969 0,
970 &dev_info->event_interfaces[0]
971 .dev,
972 &dev_info->event_interfaces[0]
973 .dev_attr_list);
974 kfree(postfix);
975 if (ret)
976 goto error_ret;
977
978 }
979
980error_ret:
981 return ret;
982}
983
Jonathan Cameron232b9cb2011-08-12 17:08:49 +0100984static inline void __iio_remove_event_config_attrs(struct iio_dev *dev_info,
985 int i)
Jonathan Cameron1d892712011-05-18 14:40:51 +0100986{
987 struct iio_dev_attr *p, *n;
Jonathan Cameron1d892712011-05-18 14:40:51 +0100988 list_for_each_entry_safe(p, n,
Jonathan Cameron232b9cb2011-08-12 17:08:49 +0100989 &dev_info->event_interfaces[i].
Jonathan Cameron1d892712011-05-18 14:40:51 +0100990 dev_attr_list, l) {
991 sysfs_remove_file_from_group(&dev_info
Jonathan Cameron232b9cb2011-08-12 17:08:49 +0100992 ->event_interfaces[i].dev.kobj,
Jonathan Cameron1d892712011-05-18 14:40:51 +0100993 &p->dev_attr.attr,
Jonathan Cameron232b9cb2011-08-12 17:08:49 +0100994 NULL);
Jonathan Cameron1d892712011-05-18 14:40:51 +0100995 kfree(p->dev_attr.attr.name);
996 kfree(p);
997 }
Jonathan Cameron1d892712011-05-18 14:40:51 +0100998}
999
Jonathan Cameron847ec802009-08-18 18:06:19 +01001000static inline int __iio_add_event_config_attrs(struct iio_dev *dev_info, int i)
1001{
Jonathan Cameron1d892712011-05-18 14:40:51 +01001002 int j;
Jonathan Cameron847ec802009-08-18 18:06:19 +01001003 int ret;
Jonathan Cameron232b9cb2011-08-12 17:08:49 +01001004 INIT_LIST_HEAD(&dev_info->event_interfaces[i].dev_attr_list);
Jonathan Cameron1d892712011-05-18 14:40:51 +01001005 /* Dynically created from the channels array */
1006 if (dev_info->channels) {
1007 for (j = 0; j < dev_info->num_channels; j++) {
1008 ret = iio_device_add_event_sysfs(dev_info,
1009 &dev_info
1010 ->channels[j]);
1011 if (ret)
1012 goto error_clear_attrs;
1013 }
1014 }
Jonathan Cameron847ec802009-08-18 18:06:19 +01001015 return 0;
1016
Jonathan Cameron1d892712011-05-18 14:40:51 +01001017error_clear_attrs:
Jonathan Cameron232b9cb2011-08-12 17:08:49 +01001018 __iio_remove_event_config_attrs(dev_info, i);
Jonathan Cameron847ec802009-08-18 18:06:19 +01001019
1020 return ret;
1021}
1022
Jonathan Cameron847ec802009-08-18 18:06:19 +01001023static int iio_device_register_eventset(struct iio_dev *dev_info)
1024{
1025 int ret = 0, i, j;
1026
Jonathan Cameron6fe81352011-05-18 14:42:37 +01001027 if (dev_info->info->num_interrupt_lines == 0)
Jonathan Cameron847ec802009-08-18 18:06:19 +01001028 return 0;
1029
1030 dev_info->event_interfaces =
1031 kzalloc(sizeof(struct iio_event_interface)
Jonathan Cameron6fe81352011-05-18 14:42:37 +01001032 *dev_info->info->num_interrupt_lines,
Jonathan Cameron847ec802009-08-18 18:06:19 +01001033 GFP_KERNEL);
1034 if (dev_info->event_interfaces == NULL) {
1035 ret = -ENOMEM;
1036 goto error_ret;
1037 }
1038
Jonathan Cameron6fe81352011-05-18 14:42:37 +01001039 for (i = 0; i < dev_info->info->num_interrupt_lines; i++) {
Jonathan Cameron847ec802009-08-18 18:06:19 +01001040 ret = iio_setup_ev_int(&dev_info->event_interfaces[i],
Jonathan Cameronc74b0de2011-05-18 14:42:33 +01001041 dev_name(&dev_info->dev),
1042 i,
Jonathan Cameron6fe81352011-05-18 14:42:37 +01001043 dev_info->info->driver_module,
Jonathan Cameron847ec802009-08-18 18:06:19 +01001044 &dev_info->dev);
1045 if (ret) {
1046 dev_err(&dev_info->dev,
1047 "Could not get chrdev interface\n");
Jonathan Cameroncc2439f2011-08-12 16:55:30 +01001048 goto error_free_setup_event_lines;
Jonathan Cameron847ec802009-08-18 18:06:19 +01001049 }
Jonathan Cameron847ec802009-08-18 18:06:19 +01001050
Jonathan Cameron5cba2202010-05-04 14:43:01 +01001051 dev_set_drvdata(&dev_info->event_interfaces[i].dev,
1052 (void *)dev_info);
Jonathan Cameron1d892712011-05-18 14:40:51 +01001053
Jonathan Cameron6fe81352011-05-18 14:42:37 +01001054 if (dev_info->info->event_attrs != NULL)
Jonathan Cameron1d892712011-05-18 14:40:51 +01001055 ret = sysfs_create_group(&dev_info
1056 ->event_interfaces[i]
1057 .dev.kobj,
Jonathan Cameron6fe81352011-05-18 14:42:37 +01001058 &dev_info->info
1059 ->event_attrs[i]);
Jonathan Cameron5cba2202010-05-04 14:43:01 +01001060
Jonathan Cameron847ec802009-08-18 18:06:19 +01001061 if (ret) {
1062 dev_err(&dev_info->dev,
1063 "Failed to register sysfs for event attrs");
Jonathan Cameroncc2439f2011-08-12 16:55:30 +01001064 iio_free_ev_int(&dev_info->event_interfaces[i]);
1065 goto error_free_setup_event_lines;
Jonathan Cameron847ec802009-08-18 18:06:19 +01001066 }
Jonathan Cameron847ec802009-08-18 18:06:19 +01001067 ret = __iio_add_event_config_attrs(dev_info, i);
Jonathan Cameroncc2439f2011-08-12 16:55:30 +01001068 if (ret) {
1069 if (dev_info->info->event_attrs != NULL)
1070 sysfs_remove_group(&dev_info
1071 ->event_interfaces[i]
1072 .dev.kobj,
1073 &dev_info->info
1074 ->event_attrs[i]);
1075 iio_free_ev_int(&dev_info->event_interfaces[i]);
1076 goto error_free_setup_event_lines;
1077 }
Jonathan Cameron847ec802009-08-18 18:06:19 +01001078 }
1079
1080 return 0;
1081
Jonathan Cameroncc2439f2011-08-12 16:55:30 +01001082error_free_setup_event_lines:
1083 for (j = 0; j < i; j++) {
1084 __iio_remove_event_config_attrs(dev_info, j);
Jonathan Cameron6fe81352011-05-18 14:42:37 +01001085 if (dev_info->info->event_attrs != NULL)
Jonathan Cameron1d892712011-05-18 14:40:51 +01001086 sysfs_remove_group(&dev_info
Jonathan Cameroncc2439f2011-08-12 16:55:30 +01001087 ->event_interfaces[j].dev.kobj,
1088 &dev_info->info->event_attrs[j]);
Jonathan Cameron847ec802009-08-18 18:06:19 +01001089 iio_free_ev_int(&dev_info->event_interfaces[j]);
Jonathan Cameroncc2439f2011-08-12 16:55:30 +01001090 }
Jonathan Cameron847ec802009-08-18 18:06:19 +01001091 kfree(dev_info->event_interfaces);
1092error_ret:
1093
1094 return ret;
1095}
1096
1097static void iio_device_unregister_eventset(struct iio_dev *dev_info)
1098{
1099 int i;
1100
Jonathan Cameron6fe81352011-05-18 14:42:37 +01001101 if (dev_info->info->num_interrupt_lines == 0)
Jonathan Cameron847ec802009-08-18 18:06:19 +01001102 return;
Jonathan Cameron6fe81352011-05-18 14:42:37 +01001103 for (i = 0; i < dev_info->info->num_interrupt_lines; i++) {
Jonathan Cameron1d892712011-05-18 14:40:51 +01001104 __iio_remove_event_config_attrs(dev_info, i);
Jonathan Cameron6fe81352011-05-18 14:42:37 +01001105 if (dev_info->info->event_attrs != NULL)
Jonathan Cameron1d892712011-05-18 14:40:51 +01001106 sysfs_remove_group(&dev_info
1107 ->event_interfaces[i].dev.kobj,
Jonathan Cameron6fe81352011-05-18 14:42:37 +01001108 &dev_info->info->event_attrs[i]);
Jonathan Cameron847ec802009-08-18 18:06:19 +01001109 iio_free_ev_int(&dev_info->event_interfaces[i]);
Jonathan Cameroncc2439f2011-08-12 16:55:30 +01001110 }
Jonathan Cameron847ec802009-08-18 18:06:19 +01001111 kfree(dev_info->event_interfaces);
1112}
1113
1114static void iio_dev_release(struct device *device)
1115{
Jonathan Camerondf9c1c42011-08-12 17:56:03 +01001116 struct iio_dev *dev_info = container_of(device, struct iio_dev, dev);
Jonathan Cameron847ec802009-08-18 18:06:19 +01001117 iio_put();
Jonathan Camerondf9c1c42011-08-12 17:56:03 +01001118 kfree(dev_info);
Jonathan Cameron847ec802009-08-18 18:06:19 +01001119}
1120
1121static struct device_type iio_dev_type = {
1122 .name = "iio_device",
1123 .release = iio_dev_release,
1124};
1125
Jonathan Cameron6f7c8ee2011-04-15 18:55:56 +01001126struct iio_dev *iio_allocate_device(int sizeof_priv)
Jonathan Cameron847ec802009-08-18 18:06:19 +01001127{
Jonathan Cameron6f7c8ee2011-04-15 18:55:56 +01001128 struct iio_dev *dev;
1129 size_t alloc_size;
1130
1131 alloc_size = sizeof(struct iio_dev);
1132 if (sizeof_priv) {
1133 alloc_size = ALIGN(alloc_size, IIO_ALIGN);
1134 alloc_size += sizeof_priv;
1135 }
1136 /* ensure 32-byte alignment of whole construct ? */
1137 alloc_size += IIO_ALIGN - 1;
1138
1139 dev = kzalloc(alloc_size, GFP_KERNEL);
Jonathan Cameron847ec802009-08-18 18:06:19 +01001140
1141 if (dev) {
1142 dev->dev.type = &iio_dev_type;
Jonathan Cameron5aaaeba2010-05-04 14:43:00 +01001143 dev->dev.bus = &iio_bus_type;
Jonathan Cameron847ec802009-08-18 18:06:19 +01001144 device_initialize(&dev->dev);
1145 dev_set_drvdata(&dev->dev, (void *)dev);
1146 mutex_init(&dev->mlock);
1147 iio_get();
1148 }
1149
1150 return dev;
1151}
1152EXPORT_SYMBOL(iio_allocate_device);
1153
1154void iio_free_device(struct iio_dev *dev)
1155{
1156 if (dev)
1157 iio_put_device(dev);
1158}
1159EXPORT_SYMBOL(iio_free_device);
1160
1161int iio_device_register(struct iio_dev *dev_info)
1162{
1163 int ret;
1164
Jonathan Cameronc74b0de2011-05-18 14:42:33 +01001165 dev_info->id = iio_get_new_ida_val(&iio_ida);
1166 if (dev_info->id < 0) {
1167 ret = dev_info->id;
Jonathan Cameron847ec802009-08-18 18:06:19 +01001168 dev_err(&dev_info->dev, "Failed to get id\n");
1169 goto error_ret;
1170 }
1171 dev_set_name(&dev_info->dev, "device%d", dev_info->id);
1172
1173 ret = device_add(&dev_info->dev);
1174 if (ret)
Jonathan Cameronb156cf72010-09-04 17:54:43 +01001175 goto error_free_ida;
Jonathan Cameron847ec802009-08-18 18:06:19 +01001176 ret = iio_device_register_sysfs(dev_info);
1177 if (ret) {
1178 dev_err(dev_info->dev.parent,
1179 "Failed to register sysfs interfaces\n");
1180 goto error_del_device;
1181 }
1182 ret = iio_device_register_eventset(dev_info);
1183 if (ret) {
1184 dev_err(dev_info->dev.parent,
Roel Van Nyenc849d252010-04-29 19:27:31 +02001185 "Failed to register event set\n");
Jonathan Cameron847ec802009-08-18 18:06:19 +01001186 goto error_free_sysfs;
1187 }
1188 if (dev_info->modes & INDIO_RING_TRIGGERED)
1189 iio_device_register_trigger_consumer(dev_info);
1190
1191 return 0;
1192
1193error_free_sysfs:
1194 iio_device_unregister_sysfs(dev_info);
1195error_del_device:
1196 device_del(&dev_info->dev);
Jonathan Cameronb156cf72010-09-04 17:54:43 +01001197error_free_ida:
Jonathan Cameronc74b0de2011-05-18 14:42:33 +01001198 iio_free_ida_val(&iio_ida, dev_info->id);
Jonathan Cameron847ec802009-08-18 18:06:19 +01001199error_ret:
1200 return ret;
1201}
1202EXPORT_SYMBOL(iio_device_register);
1203
1204void iio_device_unregister(struct iio_dev *dev_info)
1205{
1206 if (dev_info->modes & INDIO_RING_TRIGGERED)
1207 iio_device_unregister_trigger_consumer(dev_info);
1208 iio_device_unregister_eventset(dev_info);
1209 iio_device_unregister_sysfs(dev_info);
Jonathan Cameronc74b0de2011-05-18 14:42:33 +01001210 iio_free_ida_val(&iio_ida, dev_info->id);
Jonathan Cameron847ec802009-08-18 18:06:19 +01001211 device_unregister(&dev_info->dev);
1212}
1213EXPORT_SYMBOL(iio_device_unregister);
1214
1215void iio_put(void)
1216{
1217 module_put(THIS_MODULE);
1218}
1219
1220void iio_get(void)
1221{
1222 __module_get(THIS_MODULE);
1223}
1224
1225subsys_initcall(iio_init);
1226module_exit(iio_exit);
1227
1228MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
1229MODULE_DESCRIPTION("Industrial I/O core");
1230MODULE_LICENSE("GPL");