industrialio-core.c revision 9aa1a167f0b8d6a58fe012992fd801bd78bf91f1
1847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron/* The industrial I/O core
2847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron *
3847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron * Copyright (c) 2008 Jonathan Cameron
4847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron *
5847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron * This program is free software; you can redistribute it and/or modify it
6847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron * under the terms of the GNU General Public License version 2 as published by
7847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron * the Free Software Foundation.
8847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron *
9847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron * Based on elements of hwmon and input subsystems.
10847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron */
11847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
12847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron#include <linux/kernel.h>
13847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron#include <linux/module.h>
14847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron#include <linux/idr.h>
15847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron#include <linux/kdev_t.h>
16847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron#include <linux/err.h>
17847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron#include <linux/device.h>
18847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron#include <linux/fs.h>
19847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron#include <linux/poll.h>
20ffc18afa11f32d59839b5f3c605c64c63d38c218Jonathan Cameron#include <linux/sched.h>
214439c9353589f4def506b94f8f6344433333a4b9Jeff Mahoney#include <linux/wait.h>
22847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron#include <linux/cdev.h>
235a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
24847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron#include "iio.h"
25847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron#include "trigger_consumer.h"
26847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
27847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron#define IIO_ID_PREFIX "device"
28847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron#define IIO_ID_FORMAT IIO_ID_PREFIX "%d"
29847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
30847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron/* IDR to assign each registered device a unique id*/
31b156cf70e1f4befc4856baaf9681dede9a143888Jonathan Cameronstatic DEFINE_IDA(iio_ida);
32847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron/* IDR to allocate character device minor numbers */
33b156cf70e1f4befc4856baaf9681dede9a143888Jonathan Cameronstatic DEFINE_IDA(iio_chrdev_ida);
34847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron/* Lock used to protect both of the above */
35b156cf70e1f4befc4856baaf9681dede9a143888Jonathan Cameronstatic DEFINE_SPINLOCK(iio_ida_lock);
36847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
37847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Camerondev_t iio_devt;
38847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan CameronEXPORT_SYMBOL(iio_devt);
39847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
40847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron#define IIO_DEV_MAX 256
415aaaeba82e00958ecb2c890b4953a249bbde9426Jonathan Cameronstruct bus_type iio_bus_type = {
42847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	.name = "iio",
43847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron};
445aaaeba82e00958ecb2c890b4953a249bbde9426Jonathan CameronEXPORT_SYMBOL(iio_bus_type);
45847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
461d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronstatic const char * const iio_chan_type_name_spec_shared[] = {
471d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	[IIO_IN] = "in",
48ae19178eacfab141afdd886e002bb80c99dba63aMichael Hennerich	[IIO_OUT] = "out",
49faf290e867fd51e227165d0bef113b022520a58fMichael Hennerich	[IIO_CURRENT] = "current",
50faf290e867fd51e227165d0bef113b022520a58fMichael Hennerich	[IIO_POWER] = "power",
519bff02f8f71c4366efd6f5d79150f9786884bd1cBryan Freed	[IIO_ACCEL] = "accel",
521d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	[IIO_IN_DIFF] = "in-in",
531d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	[IIO_GYRO] = "gyro",
541d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	[IIO_MAGN] = "magn",
559bff02f8f71c4366efd6f5d79150f9786884bd1cBryan Freed	[IIO_LIGHT] = "illuminance",
569bff02f8f71c4366efd6f5d79150f9786884bd1cBryan Freed	[IIO_INTENSITY] = "intensity",
57f09f2c8142d275b0d9321d2ea93c8bd0d8dc32ecBryan Freed	[IIO_PROXIMITY] = "proximity",
589bff02f8f71c4366efd6f5d79150f9786884bd1cBryan Freed	[IIO_TEMP] = "temp",
591d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	[IIO_INCLI] = "incli",
601d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	[IIO_ROT] = "rot",
611d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	[IIO_ANGL] = "angl",
629bff02f8f71c4366efd6f5d79150f9786884bd1cBryan Freed	[IIO_TIMESTAMP] = "timestamp",
631d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron};
641d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
651d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronstatic const char * const iio_chan_type_name_spec_complex[] = {
661d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	[IIO_IN_DIFF] = "in%d-in%d",
671d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron};
681d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
691d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronstatic const char * const iio_modifier_names_light[] = {
701d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	[IIO_MOD_LIGHT_BOTH] = "both",
711d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	[IIO_MOD_LIGHT_IR] = "ir",
721d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron};
731d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
741d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronstatic const char * const iio_modifier_names_axial[] = {
751d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	[IIO_MOD_X] = "x",
761d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	[IIO_MOD_Y] = "y",
771d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	[IIO_MOD_Z] = "z",
781d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron};
791d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
801d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron/* relies on pairs of these shared then separate */
811d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronstatic const char * const iio_chan_info_postfix[] = {
821d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	[IIO_CHAN_INFO_SCALE_SHARED/2] = "scale",
831d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	[IIO_CHAN_INFO_OFFSET_SHARED/2] = "offset",
841d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	[IIO_CHAN_INFO_CALIBSCALE_SHARED/2] = "calibscale",
851d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	[IIO_CHAN_INFO_CALIBBIAS_SHARED/2] = "calibbias",
86eb7fea53e53ed47e82b4cc9911dd8fdc7f953de5Jonathan Cameron	[IIO_CHAN_INFO_PEAK_SHARED/2] = "peak_raw",
87eb7fea53e53ed47e82b4cc9911dd8fdc7f953de5Jonathan Cameron	[IIO_CHAN_INFO_PEAK_SCALE_SHARED/2] = "peak_scale",
881d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron};
891d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
909aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron/* Return a negative errno on failure */
919aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameronint iio_get_new_ida_val(struct ida *this_ida)
929aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron{
939aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron	int ret;
949aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron	int val;
959aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron
969aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameronida_again:
979aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron	if (unlikely(ida_pre_get(this_ida, GFP_KERNEL) == 0))
989aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron		return -ENOMEM;
999aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron
1009aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron	spin_lock(&iio_ida_lock);
1019aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron	ret = ida_get_new(this_ida, &val);
1029aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron	spin_unlock(&iio_ida_lock);
1039aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron	if (unlikely(ret == -EAGAIN))
1049aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron		goto ida_again;
1059aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron	else if (unlikely(ret))
1069aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron		return ret;
1079aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron
1089aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron	return val;
1099aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron}
1109aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan CameronEXPORT_SYMBOL(iio_get_new_ida_val);
1119aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron
1129aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameronvoid iio_free_ida_val(struct ida *this_ida, int id)
1139aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron{
1149aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron	spin_lock(&iio_ida_lock);
1159aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron	ida_remove(this_ida, id);
1169aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron	spin_unlock(&iio_ida_lock);
1179aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron}
1189aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan CameronEXPORT_SYMBOL(iio_free_ida_val);
1199aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron
120aaf370db7dad574e166f64cd9ad4129f12198145Jonathan Cameronint iio_push_event(struct iio_dev *dev_info,
121aaf370db7dad574e166f64cd9ad4129f12198145Jonathan Cameron		   int ev_line,
122aaf370db7dad574e166f64cd9ad4129f12198145Jonathan Cameron		   int ev_code,
123aaf370db7dad574e166f64cd9ad4129f12198145Jonathan Cameron		   s64 timestamp)
124847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron{
125aaf370db7dad574e166f64cd9ad4129f12198145Jonathan Cameron	struct iio_event_interface *ev_int
126aaf370db7dad574e166f64cd9ad4129f12198145Jonathan Cameron		= &dev_info->event_interfaces[ev_line];
127847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	struct iio_detected_event_list *ev;
128847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	int ret = 0;
129847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
130847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	/* Does anyone care? */
131847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	mutex_lock(&ev_int->event_list_lock);
132847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	if (test_bit(IIO_BUSY_BIT_POS, &ev_int->handler.flags)) {
13375c8075394906b4bda4b056328bd9b401277d9b8Jonathan Cameron		if (ev_int->current_events == ev_int->max_events) {
13475c8075394906b4bda4b056328bd9b401277d9b8Jonathan Cameron			mutex_unlock(&ev_int->event_list_lock);
135847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron			return 0;
13675c8075394906b4bda4b056328bd9b401277d9b8Jonathan Cameron		}
137847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		ev = kmalloc(sizeof(*ev), GFP_KERNEL);
138847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		if (ev == NULL) {
139847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron			ret = -ENOMEM;
14075c8075394906b4bda4b056328bd9b401277d9b8Jonathan Cameron			mutex_unlock(&ev_int->event_list_lock);
141847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron			goto error_ret;
142847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		}
143847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		ev->ev.id = ev_code;
144847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		ev->ev.timestamp = timestamp;
145847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
1463b8ebfb47f0cacc82c88b6f886ad84d78d6fdd61Jonathan Cameron		list_add_tail(&ev->list, &ev_int->det_events);
147847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		ev_int->current_events++;
148847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		mutex_unlock(&ev_int->event_list_lock);
149847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		wake_up_interruptible(&ev_int->wait);
150847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	} else
151847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		mutex_unlock(&ev_int->event_list_lock);
152847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
153847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronerror_ret:
154847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	return ret;
155847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron}
156847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan CameronEXPORT_SYMBOL(iio_push_event);
157847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
158847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
159847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron/* This turns up an awful lot */
160847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronssize_t iio_read_const_attr(struct device *dev,
161847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron			    struct device_attribute *attr,
162847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron			    char *buf)
163847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron{
164847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	return sprintf(buf, "%s\n", to_iio_const_attr(attr)->string);
165847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron}
166847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan CameronEXPORT_SYMBOL(iio_read_const_attr);
167847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
168847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
16977712e5fbe2e47476823f4853d756cc5ad1dfabcMark Brownstatic ssize_t iio_event_chrdev_read(struct file *filep,
17077712e5fbe2e47476823f4853d756cc5ad1dfabcMark Brown				     char __user *buf,
17177712e5fbe2e47476823f4853d756cc5ad1dfabcMark Brown				     size_t count,
17277712e5fbe2e47476823f4853d756cc5ad1dfabcMark Brown				     loff_t *f_ps)
173847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron{
174847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	struct iio_event_interface *ev_int = filep->private_data;
175847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	struct iio_detected_event_list *el;
176847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	int ret;
177847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	size_t len;
178847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
179847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	mutex_lock(&ev_int->event_list_lock);
1803b8ebfb47f0cacc82c88b6f886ad84d78d6fdd61Jonathan Cameron	if (list_empty(&ev_int->det_events)) {
181847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		if (filep->f_flags & O_NONBLOCK) {
182847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron			ret = -EAGAIN;
183847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron			goto error_mutex_unlock;
184847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		}
185847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		mutex_unlock(&ev_int->event_list_lock);
186847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		/* Blocking on device; waiting for something to be there */
187847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		ret = wait_event_interruptible(ev_int->wait,
188847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron					       !list_empty(&ev_int
1893b8ebfb47f0cacc82c88b6f886ad84d78d6fdd61Jonathan Cameron							   ->det_events));
190847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		if (ret)
191847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron			goto error_ret;
19225985edcedea6396277003854657b5f3cb31a628Lucas De Marchi		/* Single access device so no one else can get the data */
193847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		mutex_lock(&ev_int->event_list_lock);
194847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	}
195847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
1963b8ebfb47f0cacc82c88b6f886ad84d78d6fdd61Jonathan Cameron	el = list_first_entry(&ev_int->det_events,
197847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron			      struct iio_detected_event_list,
198847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron			      list);
199847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	len = sizeof el->ev;
200847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	if (copy_to_user(buf, &(el->ev), len)) {
201847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		ret = -EFAULT;
202847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		goto error_mutex_unlock;
203847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	}
204847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	list_del(&el->list);
205847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	ev_int->current_events--;
206847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	mutex_unlock(&ev_int->event_list_lock);
207847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	kfree(el);
208847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
209847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	return len;
210847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
211847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronerror_mutex_unlock:
212847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	mutex_unlock(&ev_int->event_list_lock);
213847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronerror_ret:
214847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
215847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	return ret;
216847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron}
217847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
21877712e5fbe2e47476823f4853d756cc5ad1dfabcMark Brownstatic int iio_event_chrdev_release(struct inode *inode, struct file *filep)
219847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron{
220847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	struct iio_handler *hand = iio_cdev_to_handler(inode->i_cdev);
221847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	struct iio_event_interface *ev_int = hand->private;
222847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	struct iio_detected_event_list *el, *t;
223847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
224847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	mutex_lock(&ev_int->event_list_lock);
225847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	clear_bit(IIO_BUSY_BIT_POS, &ev_int->handler.flags);
226847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	/*
227847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	 * In order to maintain a clean state for reopening,
228847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	 * clear out any awaiting events. The mask will prevent
229847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	 * any new __iio_push_event calls running.
230847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	 */
2313b8ebfb47f0cacc82c88b6f886ad84d78d6fdd61Jonathan Cameron	list_for_each_entry_safe(el, t, &ev_int->det_events, list) {
232847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		list_del(&el->list);
233847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		kfree(el);
234847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	}
235847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	mutex_unlock(&ev_int->event_list_lock);
236847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
237847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	return 0;
238847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron}
239847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
24077712e5fbe2e47476823f4853d756cc5ad1dfabcMark Brownstatic int iio_event_chrdev_open(struct inode *inode, struct file *filep)
241847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron{
242847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	struct iio_handler *hand = iio_cdev_to_handler(inode->i_cdev);
243847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	struct iio_event_interface *ev_int = hand->private;
244847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
245847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	mutex_lock(&ev_int->event_list_lock);
246847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	if (test_and_set_bit(IIO_BUSY_BIT_POS, &hand->flags)) {
247847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		fops_put(filep->f_op);
248847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		mutex_unlock(&ev_int->event_list_lock);
249847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		return -EBUSY;
250847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	}
251847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	filep->private_data = hand->private;
252847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	mutex_unlock(&ev_int->event_list_lock);
253847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
254847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	return 0;
255847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron}
256847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
257847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronstatic const struct file_operations iio_event_chrdev_fileops = {
258847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	.read =  iio_event_chrdev_read,
259847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	.release = iio_event_chrdev_release,
260847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	.open = iio_event_chrdev_open,
261847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	.owner = THIS_MODULE,
2626038f373a3dc1f1c26496e60b6c40b164716f07eArnd Bergmann	.llseek = noop_llseek,
263847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron};
264847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
265847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronstatic void iio_event_dev_release(struct device *dev)
266847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron{
267847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	struct iio_event_interface *ev_int
268847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		= container_of(dev, struct iio_event_interface, dev);
269847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	cdev_del(&ev_int->handler.chrdev);
270847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	iio_device_free_chrdev_minor(MINOR(dev->devt));
271847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron};
272847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
273847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronstatic struct device_type iio_event_type = {
274847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	.release = iio_event_dev_release,
275847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron};
276847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
277847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronint iio_device_get_chrdev_minor(void)
278847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron{
2799aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron	int ret;
280847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
2819aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron	ret = iio_get_new_ida_val(&iio_chrdev_ida);
2829aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron	if (ret < IIO_DEV_MAX) /* both errors and valid */
283847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		return ret;
2849aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron	else
285847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		return -ENOMEM;
286847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron}
287847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
288847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronvoid iio_device_free_chrdev_minor(int val)
289847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron{
2909aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron	iio_free_ida_val(&iio_chrdev_ida, val);
291847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron}
292847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
293b9d40a9d5583a530372b4e1888e4f643ed05aca6Jonathan Cameronstatic int iio_setup_ev_int(struct iio_event_interface *ev_int,
294c74b0de1666f8b8f6c65e1e944deff71fed0769aJonathan Cameron			    const char *dev_name,
295c74b0de1666f8b8f6c65e1e944deff71fed0769aJonathan Cameron			    int index,
296c74b0de1666f8b8f6c65e1e944deff71fed0769aJonathan Cameron			    struct module *owner,
297c74b0de1666f8b8f6c65e1e944deff71fed0769aJonathan Cameron			    struct device *dev)
298847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron{
299847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	int ret, minor;
300847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
3015aaaeba82e00958ecb2c890b4953a249bbde9426Jonathan Cameron	ev_int->dev.bus = &iio_bus_type;
302847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	ev_int->dev.parent = dev;
303847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	ev_int->dev.type = &iio_event_type;
304847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	device_initialize(&ev_int->dev);
305847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
306847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	minor = iio_device_get_chrdev_minor();
307847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	if (minor < 0) {
308847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		ret = minor;
309847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		goto error_device_put;
310847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	}
311847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	ev_int->dev.devt = MKDEV(MAJOR(iio_devt), minor);
312c74b0de1666f8b8f6c65e1e944deff71fed0769aJonathan Cameron	dev_set_name(&ev_int->dev, "%s:event%d", dev_name, index);
313847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
314847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	ret = device_add(&ev_int->dev);
315847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	if (ret)
316847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		goto error_free_minor;
317847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
318847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	cdev_init(&ev_int->handler.chrdev, &iio_event_chrdev_fileops);
319847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	ev_int->handler.chrdev.owner = owner;
320847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
321847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	mutex_init(&ev_int->event_list_lock);
322847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	/* discussion point - make this variable? */
323847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	ev_int->max_events = 10;
324847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	ev_int->current_events = 0;
3253b8ebfb47f0cacc82c88b6f886ad84d78d6fdd61Jonathan Cameron	INIT_LIST_HEAD(&ev_int->det_events);
326847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	init_waitqueue_head(&ev_int->wait);
327847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	ev_int->handler.private = ev_int;
328847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	ev_int->handler.flags = 0;
329847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
330847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	ret = cdev_add(&ev_int->handler.chrdev, ev_int->dev.devt, 1);
331847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	if (ret)
332847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		goto error_unreg_device;
333847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
334847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	return 0;
335847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
336847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronerror_unreg_device:
337847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	device_unregister(&ev_int->dev);
338847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronerror_free_minor:
339847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	iio_device_free_chrdev_minor(minor);
340847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronerror_device_put:
341847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	put_device(&ev_int->dev);
342847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
343847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	return ret;
344847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron}
345847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
346b9d40a9d5583a530372b4e1888e4f643ed05aca6Jonathan Cameronstatic void iio_free_ev_int(struct iio_event_interface *ev_int)
347847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron{
348847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	device_unregister(&ev_int->dev);
349847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	put_device(&ev_int->dev);
350847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron}
351847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
352847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronstatic int __init iio_init(void)
353847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron{
354847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	int ret;
355847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
3565aaaeba82e00958ecb2c890b4953a249bbde9426Jonathan Cameron	/* Register sysfs bus */
3575aaaeba82e00958ecb2c890b4953a249bbde9426Jonathan Cameron	ret  = bus_register(&iio_bus_type);
358847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	if (ret < 0) {
359847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		printk(KERN_ERR
3605aaaeba82e00958ecb2c890b4953a249bbde9426Jonathan Cameron		       "%s could not register bus type\n",
361847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron			__FILE__);
362847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		goto error_nothing;
363847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	}
364847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
3659aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron	ret = alloc_chrdev_region(&iio_devt, 0, IIO_DEV_MAX, "iio");
3669aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron	if (ret < 0) {
3679aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron		printk(KERN_ERR "%s: failed to allocate char dev region\n",
3689aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron		       __FILE__);
3695aaaeba82e00958ecb2c890b4953a249bbde9426Jonathan Cameron		goto error_unregister_bus_type;
3709aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron	}
371847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
372847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	return 0;
373847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
3745aaaeba82e00958ecb2c890b4953a249bbde9426Jonathan Cameronerror_unregister_bus_type:
3755aaaeba82e00958ecb2c890b4953a249bbde9426Jonathan Cameron	bus_unregister(&iio_bus_type);
376847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronerror_nothing:
377847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	return ret;
378847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron}
379847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
380847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronstatic void __exit iio_exit(void)
381847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron{
3829aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron	if (iio_devt)
3839aa1a167f0b8d6a58fe012992fd801bd78bf91f1Jonathan Cameron		unregister_chrdev_region(iio_devt, IIO_DEV_MAX);
3845aaaeba82e00958ecb2c890b4953a249bbde9426Jonathan Cameron	bus_unregister(&iio_bus_type);
385847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron}
386847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
3871d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronstatic ssize_t iio_read_channel_info(struct device *dev,
3881d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				     struct device_attribute *attr,
3891d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				     char *buf)
390847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron{
3911d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	struct iio_dev *indio_dev = dev_get_drvdata(dev);
3921d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
3931d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	int val, val2;
3946fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron	int ret = indio_dev->info->read_raw(indio_dev, this_attr->c,
3956fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron					    &val, &val2, this_attr->address);
3961d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
3971d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (ret < 0)
3981d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		return ret;
399847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
4001d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (ret == IIO_VAL_INT)
4011d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		return sprintf(buf, "%d\n", val);
4021d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	else if (ret == IIO_VAL_INT_PLUS_MICRO) {
4031d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		if (val2 < 0)
4041d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			return sprintf(buf, "-%d.%06u\n", val, -val2);
4051d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		else
4061d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			return sprintf(buf, "%d.%06u\n", val, val2);
40771646e2c7ae4edb92dfa89eccb354d81be1cbbbdMichael Hennerich	} else if (ret == IIO_VAL_INT_PLUS_NANO) {
40871646e2c7ae4edb92dfa89eccb354d81be1cbbbdMichael Hennerich		if (val2 < 0)
40971646e2c7ae4edb92dfa89eccb354d81be1cbbbdMichael Hennerich			return sprintf(buf, "-%d.%09u\n", val, -val2);
41071646e2c7ae4edb92dfa89eccb354d81be1cbbbdMichael Hennerich		else
41171646e2c7ae4edb92dfa89eccb354d81be1cbbbdMichael Hennerich			return sprintf(buf, "%d.%09u\n", val, val2);
4121d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	} else
4131d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		return 0;
4141d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron}
4151d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
4161d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronstatic ssize_t iio_write_channel_info(struct device *dev,
4171d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				      struct device_attribute *attr,
4181d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				      const char *buf,
4191d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				      size_t len)
4201d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron{
4211d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	struct iio_dev *indio_dev = dev_get_drvdata(dev);
4221d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
4235c04af04835269c194662be63fe168893fad667fMichael Hennerich	int ret, integer = 0, fract = 0, fract_mult = 100000;
4241d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	bool integer_part = true, negative = false;
4251d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
4261d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	/* Assumes decimal - precision based on number of digits */
4276fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron	if (!indio_dev->info->write_raw)
4281d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		return -EINVAL;
4295c04af04835269c194662be63fe168893fad667fMichael Hennerich
4305c04af04835269c194662be63fe168893fad667fMichael Hennerich	if (indio_dev->info->write_raw_get_fmt)
4315c04af04835269c194662be63fe168893fad667fMichael Hennerich		switch (indio_dev->info->write_raw_get_fmt(indio_dev,
4325c04af04835269c194662be63fe168893fad667fMichael Hennerich			this_attr->c, this_attr->address)) {
4335c04af04835269c194662be63fe168893fad667fMichael Hennerich		case IIO_VAL_INT_PLUS_MICRO:
4345c04af04835269c194662be63fe168893fad667fMichael Hennerich			fract_mult = 100000;
4355c04af04835269c194662be63fe168893fad667fMichael Hennerich			break;
4365c04af04835269c194662be63fe168893fad667fMichael Hennerich		case IIO_VAL_INT_PLUS_NANO:
4375c04af04835269c194662be63fe168893fad667fMichael Hennerich			fract_mult = 100000000;
4385c04af04835269c194662be63fe168893fad667fMichael Hennerich			break;
4395c04af04835269c194662be63fe168893fad667fMichael Hennerich		default:
4405c04af04835269c194662be63fe168893fad667fMichael Hennerich			return -EINVAL;
4415c04af04835269c194662be63fe168893fad667fMichael Hennerich		}
4425c04af04835269c194662be63fe168893fad667fMichael Hennerich
4431d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (buf[0] == '-') {
4441d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		negative = true;
4451d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		buf++;
4461d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	}
4475c04af04835269c194662be63fe168893fad667fMichael Hennerich
4481d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	while (*buf) {
4491d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		if ('0' <= *buf && *buf <= '9') {
4501d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			if (integer_part)
4511d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				integer = integer*10 + *buf - '0';
4521d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			else {
4535c04af04835269c194662be63fe168893fad667fMichael Hennerich				fract += fract_mult*(*buf - '0');
4545c04af04835269c194662be63fe168893fad667fMichael Hennerich				if (fract_mult == 1)
4551d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					break;
4565c04af04835269c194662be63fe168893fad667fMichael Hennerich				fract_mult /= 10;
4571d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			}
4581d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		} else if (*buf == '\n') {
4591d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			if (*(buf + 1) == '\0')
4601d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				break;
4611d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			else
4621d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				return -EINVAL;
4631d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		} else if (*buf == '.') {
4641d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			integer_part = false;
4651d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		} else {
4661d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			return -EINVAL;
4671d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		}
4681d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		buf++;
4691d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	}
4701d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (negative) {
4711d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		if (integer)
4721d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			integer = -integer;
4731d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		else
4745c04af04835269c194662be63fe168893fad667fMichael Hennerich			fract = -fract;
4751d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	}
4761d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
4776fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron	ret = indio_dev->info->write_raw(indio_dev, this_attr->c,
4785c04af04835269c194662be63fe168893fad667fMichael Hennerich					 integer, fract, this_attr->address);
4791d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (ret)
4801d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		return ret;
4811d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
4821d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	return len;
4831d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron}
4841d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
4851d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronstatic int __iio_build_postfix(struct iio_chan_spec const *chan,
4861d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			       bool generic,
4871d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			       const char *postfix,
4881d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			       char **result)
4891d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron{
4901d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	char *all_post;
4911d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	/* 3 options - generic, extend_name, modified - if generic, extend_name
4921d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	* and modified cannot apply.*/
4931d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
4941d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (generic || (!chan->modified && !chan->extend_name)) {
4951d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		all_post = kasprintf(GFP_KERNEL, "%s", postfix);
4961d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	} else if (chan->modified) {
4971d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		const char *intermediate;
4981d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		switch (chan->type) {
4991d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		case IIO_INTENSITY:
5001d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			intermediate
5011d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				= iio_modifier_names_light[chan->channel2];
5021d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			break;
5031d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		case IIO_ACCEL:
5041d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		case IIO_GYRO:
5051d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		case IIO_MAGN:
5061d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		case IIO_INCLI:
5071d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		case IIO_ROT:
5081d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		case IIO_ANGL:
5091d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			intermediate
5101d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				= iio_modifier_names_axial[chan->channel2];
5111d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			break;
5121d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		default:
5131d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			return -EINVAL;
5141d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		}
5151d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		if (chan->extend_name)
5161d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			all_post = kasprintf(GFP_KERNEL, "%s_%s_%s",
5171d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     intermediate,
5181d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     chan->extend_name,
5191d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     postfix);
5201d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		else
5211d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			all_post = kasprintf(GFP_KERNEL, "%s_%s",
5221d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     intermediate,
5231d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     postfix);
5241d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	} else
5251d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		all_post = kasprintf(GFP_KERNEL, "%s_%s", chan->extend_name,
5261d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				     postfix);
5271d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (all_post == NULL)
5281d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		return -ENOMEM;
5291d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	*result = all_post;
5301d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	return 0;
5311d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron}
5321d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
5331d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronint __iio_device_attr_init(struct device_attribute *dev_attr,
5341d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			   const char *postfix,
5351d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			   struct iio_chan_spec const *chan,
5361d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			   ssize_t (*readfunc)(struct device *dev,
5371d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					       struct device_attribute *attr,
5381d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					       char *buf),
5391d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			   ssize_t (*writefunc)(struct device *dev,
5401d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron						struct device_attribute *attr,
5411d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron						const char *buf,
5421d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron						size_t len),
5431d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			   bool generic)
5441d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron{
5451d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	int ret;
5461d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	char *name_format, *full_postfix;
5471d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	sysfs_attr_init(&dev_attr->attr);
5481d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	ret = __iio_build_postfix(chan, generic, postfix, &full_postfix);
5491d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (ret)
550847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		goto error_ret;
5511d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
5521d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	/* Special case for types that uses both channel numbers in naming */
5531d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (chan->type == IIO_IN_DIFF && !generic)
5541d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		name_format
5551d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			= kasprintf(GFP_KERNEL, "%s_%s",
5561d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				    iio_chan_type_name_spec_complex[chan->type],
5571d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				    full_postfix);
5581d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	else if (generic || !chan->indexed)
5591d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		name_format
5601d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			= kasprintf(GFP_KERNEL, "%s_%s",
5611d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				    iio_chan_type_name_spec_shared[chan->type],
5621d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				    full_postfix);
5631d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	else
5641d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		name_format
5651d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			= kasprintf(GFP_KERNEL, "%s%d_%s",
5661d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				    iio_chan_type_name_spec_shared[chan->type],
5671d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				    chan->channel,
5681d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				    full_postfix);
5691d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
5701d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (name_format == NULL) {
5711d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		ret = -ENOMEM;
5721d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		goto error_free_full_postfix;
5731d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	}
5741d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	dev_attr->attr.name = kasprintf(GFP_KERNEL,
5751d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					name_format,
5761d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					chan->channel,
5771d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					chan->channel2);
5781d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (dev_attr->attr.name == NULL) {
5791d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		ret = -ENOMEM;
5801d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		goto error_free_name_format;
5811d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	}
5821d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
5831d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (readfunc) {
5841d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		dev_attr->attr.mode |= S_IRUGO;
5851d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		dev_attr->show = readfunc;
5861d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	}
5871d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
5881d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (writefunc) {
5891d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		dev_attr->attr.mode |= S_IWUSR;
5901d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		dev_attr->store = writefunc;
5911d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	}
5921d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	kfree(name_format);
5931d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	kfree(full_postfix);
5941d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
5951d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	return 0;
5961d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
5971d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronerror_free_name_format:
5981d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	kfree(name_format);
5991d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronerror_free_full_postfix:
6001d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	kfree(full_postfix);
6011d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronerror_ret:
6021d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	return ret;
6031d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron}
6041d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
6051d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronvoid __iio_device_attr_deinit(struct device_attribute *dev_attr)
6061d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron{
6071d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	kfree(dev_attr->attr.name);
6081d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron}
6091d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
6101d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronint __iio_add_chan_devattr(const char *postfix,
6111d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			   const char *group,
6121d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			   struct iio_chan_spec const *chan,
6131d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			   ssize_t (*readfunc)(struct device *dev,
6141d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					       struct device_attribute *attr,
6151d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					       char *buf),
6161d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			   ssize_t (*writefunc)(struct device *dev,
6171d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron						struct device_attribute *attr,
6181d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron						const char *buf,
6191d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron						size_t len),
6201d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			   int mask,
6211d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			   bool generic,
6221d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			   struct device *dev,
6231d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			   struct list_head *attr_list)
6241d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron{
6251d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	int ret;
6261d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	struct iio_dev_attr *iio_attr, *t;
6271d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
6281d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	iio_attr = kzalloc(sizeof *iio_attr, GFP_KERNEL);
6291d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (iio_attr == NULL) {
6301d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		ret = -ENOMEM;
6311d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		goto error_ret;
6321d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	}
6331d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	ret = __iio_device_attr_init(&iio_attr->dev_attr,
6341d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				     postfix, chan,
6351d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				     readfunc, writefunc, generic);
6361d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (ret)
6371d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		goto error_iio_dev_attr_free;
6381d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	iio_attr->c = chan;
6391d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	iio_attr->address = mask;
6401d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	list_for_each_entry(t, attr_list, l)
6411d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		if (strcmp(t->dev_attr.attr.name,
6421d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			   iio_attr->dev_attr.attr.name) == 0) {
6431d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			if (!generic)
6441d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				dev_err(dev, "tried to double register : %s\n",
6451d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					t->dev_attr.attr.name);
6461d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			ret = -EBUSY;
6471d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			goto error_device_attr_deinit;
6481d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		}
6491d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
6501d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	ret = sysfs_add_file_to_group(&dev->kobj,
6511d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				      &iio_attr->dev_attr.attr, group);
6521d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (ret < 0)
6531d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		goto error_device_attr_deinit;
6541d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
6551d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	list_add(&iio_attr->l, attr_list);
6561d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
6571d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	return 0;
6581d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
6591d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronerror_device_attr_deinit:
6601d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	__iio_device_attr_deinit(&iio_attr->dev_attr);
6611d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronerror_iio_dev_attr_free:
6621d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	kfree(iio_attr);
6631d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronerror_ret:
6641d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	return ret;
6651d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron}
6661d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
6671d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronstatic int iio_device_add_channel_sysfs(struct iio_dev *dev_info,
6681d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					struct iio_chan_spec const *chan)
6691d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron{
6701d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	int ret, i;
6711d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
6721d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
6731d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (chan->channel < 0)
6741d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		return 0;
6751d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (chan->processed_val)
6761d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		ret = __iio_add_chan_devattr("input", NULL, chan,
6771d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     &iio_read_channel_info,
6781d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     NULL,
6791d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     0,
6801d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     0,
6811d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     &dev_info->dev,
6821d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     &dev_info->channel_attr_list);
6831d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	else
6841d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		ret = __iio_add_chan_devattr("raw", NULL, chan,
6851d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     &iio_read_channel_info,
686ae19178eacfab141afdd886e002bb80c99dba63aMichael Hennerich					     (chan->type == IIO_OUT ?
687ae19178eacfab141afdd886e002bb80c99dba63aMichael Hennerich					     &iio_write_channel_info : NULL),
6881d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     0,
6891d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     0,
6901d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     &dev_info->dev,
6911d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     &dev_info->channel_attr_list);
6921d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (ret)
6931d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		goto error_ret;
6941d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
6951d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	for_each_set_bit(i, &chan->info_mask, sizeof(long)*8) {
6961d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		ret = __iio_add_chan_devattr(iio_chan_info_postfix[i/2],
6971d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     NULL, chan,
6981d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     &iio_read_channel_info,
6991d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     &iio_write_channel_info,
7001d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     (1 << i),
7011d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     !(i%2),
7021d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     &dev_info->dev,
7031d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     &dev_info->channel_attr_list);
7041d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		if (ret == -EBUSY && (i%2 == 0)) {
7051d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			ret = 0;
7061d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			continue;
7071d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		}
7081d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		if (ret < 0)
7091d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			goto error_ret;
7101d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	}
7111d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronerror_ret:
7121d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	return ret;
7131d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron}
7141d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
7151d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronstatic void iio_device_remove_and_free_read_attr(struct iio_dev *dev_info,
7161d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron						 struct iio_dev_attr *p)
7171d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron{
7181d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	sysfs_remove_file_from_group(&dev_info->dev.kobj,
7191d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				     &p->dev_attr.attr, NULL);
7201d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	kfree(p->dev_attr.attr.name);
7211d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	kfree(p);
7221d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron}
7231d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
7241b732888d83f71a31a4bd26290ca8a00df1bf928Jonathan Cameronstatic ssize_t iio_show_dev_name(struct device *dev,
7251b732888d83f71a31a4bd26290ca8a00df1bf928Jonathan Cameron				 struct device_attribute *attr,
7261b732888d83f71a31a4bd26290ca8a00df1bf928Jonathan Cameron				 char *buf)
7271b732888d83f71a31a4bd26290ca8a00df1bf928Jonathan Cameron{
7281b732888d83f71a31a4bd26290ca8a00df1bf928Jonathan Cameron	struct iio_dev *indio_dev = dev_get_drvdata(dev);
7291b732888d83f71a31a4bd26290ca8a00df1bf928Jonathan Cameron	return sprintf(buf, "%s\n", indio_dev->name);
7301b732888d83f71a31a4bd26290ca8a00df1bf928Jonathan Cameron}
7311b732888d83f71a31a4bd26290ca8a00df1bf928Jonathan Cameron
7321b732888d83f71a31a4bd26290ca8a00df1bf928Jonathan Cameronstatic DEVICE_ATTR(name, S_IRUGO, iio_show_dev_name, NULL);
7331b732888d83f71a31a4bd26290ca8a00df1bf928Jonathan Cameron
734f7256877c777d08f3af445840d94e37b11038fe2Jonathan Cameronstatic struct attribute *iio_base_dummy_attrs[] = {
735f7256877c777d08f3af445840d94e37b11038fe2Jonathan Cameron	NULL
736f7256877c777d08f3af445840d94e37b11038fe2Jonathan Cameron};
737f7256877c777d08f3af445840d94e37b11038fe2Jonathan Cameronstatic struct attribute_group iio_base_dummy_group = {
738f7256877c777d08f3af445840d94e37b11038fe2Jonathan Cameron	.attrs = iio_base_dummy_attrs,
739f7256877c777d08f3af445840d94e37b11038fe2Jonathan Cameron};
740f7256877c777d08f3af445840d94e37b11038fe2Jonathan Cameron
7411d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronstatic int iio_device_register_sysfs(struct iio_dev *dev_info)
7421d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron{
7431d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	int i, ret = 0;
7441d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	struct iio_dev_attr *p, *n;
7451d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
746f7256877c777d08f3af445840d94e37b11038fe2Jonathan Cameron	if (dev_info->info->attrs)
7476fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron		ret = sysfs_create_group(&dev_info->dev.kobj,
7486fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron					 dev_info->info->attrs);
749f7256877c777d08f3af445840d94e37b11038fe2Jonathan Cameron	else
750f7256877c777d08f3af445840d94e37b11038fe2Jonathan Cameron		ret = sysfs_create_group(&dev_info->dev.kobj,
751f7256877c777d08f3af445840d94e37b11038fe2Jonathan Cameron					 &iio_base_dummy_group);
752f7256877c777d08f3af445840d94e37b11038fe2Jonathan Cameron
753f7256877c777d08f3af445840d94e37b11038fe2Jonathan Cameron	if (ret) {
754f7256877c777d08f3af445840d94e37b11038fe2Jonathan Cameron		dev_err(dev_info->dev.parent,
755f7256877c777d08f3af445840d94e37b11038fe2Jonathan Cameron			"Failed to register sysfs hooks\n");
756f7256877c777d08f3af445840d94e37b11038fe2Jonathan Cameron		goto error_ret;
757847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	}
758847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
7591d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	/*
7601d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	 * New channel registration method - relies on the fact a group does
7611d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	 *  not need to be initialized if it is name is NULL.
7621d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	 */
7631d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	INIT_LIST_HEAD(&dev_info->channel_attr_list);
7641d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (dev_info->channels)
7651d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		for (i = 0; i < dev_info->num_channels; i++) {
7661d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			ret = iio_device_add_channel_sysfs(dev_info,
7671d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron							   &dev_info
7681d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron							   ->channels[i]);
7691d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			if (ret < 0)
7701d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				goto error_clear_attrs;
7711d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		}
772f7256877c777d08f3af445840d94e37b11038fe2Jonathan Cameron	if (dev_info->name) {
7731b732888d83f71a31a4bd26290ca8a00df1bf928Jonathan Cameron		ret = sysfs_add_file_to_group(&dev_info->dev.kobj,
7741b732888d83f71a31a4bd26290ca8a00df1bf928Jonathan Cameron					      &dev_attr_name.attr,
7751b732888d83f71a31a4bd26290ca8a00df1bf928Jonathan Cameron					      NULL);
7761b732888d83f71a31a4bd26290ca8a00df1bf928Jonathan Cameron		if (ret)
7771b732888d83f71a31a4bd26290ca8a00df1bf928Jonathan Cameron			goto error_clear_attrs;
7781b732888d83f71a31a4bd26290ca8a00df1bf928Jonathan Cameron	}
7791d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	return 0;
7801b732888d83f71a31a4bd26290ca8a00df1bf928Jonathan Cameron
7811d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronerror_clear_attrs:
7821d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	list_for_each_entry_safe(p, n,
7831d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				 &dev_info->channel_attr_list, l) {
7841d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		list_del(&p->l);
7851d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		iio_device_remove_and_free_read_attr(dev_info, p);
7861d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	}
7876fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron	if (dev_info->info->attrs)
7886fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron		sysfs_remove_group(&dev_info->dev.kobj, dev_info->info->attrs);
789f7256877c777d08f3af445840d94e37b11038fe2Jonathan Cameron	else
790f7256877c777d08f3af445840d94e37b11038fe2Jonathan Cameron		sysfs_remove_group(&dev_info->dev.kobj, &iio_base_dummy_group);
791847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronerror_ret:
792847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	return ret;
7931d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
794847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron}
795847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
796847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronstatic void iio_device_unregister_sysfs(struct iio_dev *dev_info)
797847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron{
7981d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
7991d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	struct iio_dev_attr *p, *n;
8001b732888d83f71a31a4bd26290ca8a00df1bf928Jonathan Cameron	if (dev_info->name)
8011b732888d83f71a31a4bd26290ca8a00df1bf928Jonathan Cameron		sysfs_remove_file_from_group(&dev_info->dev.kobj,
8021b732888d83f71a31a4bd26290ca8a00df1bf928Jonathan Cameron					     &dev_attr_name.attr,
8031b732888d83f71a31a4bd26290ca8a00df1bf928Jonathan Cameron					     NULL);
8041d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	list_for_each_entry_safe(p, n, &dev_info->channel_attr_list, l) {
8051d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		list_del(&p->l);
8061d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		iio_device_remove_and_free_read_attr(dev_info, p);
8071d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	}
8081d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
8096fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron	if (dev_info->info->attrs)
8106fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron		sysfs_remove_group(&dev_info->dev.kobj, dev_info->info->attrs);
811f7256877c777d08f3af445840d94e37b11038fe2Jonathan Cameron	else
812f7256877c777d08f3af445840d94e37b11038fe2Jonathan Cameron		sysfs_remove_group(&dev_info->dev.kobj, &iio_base_dummy_group);
813847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron}
814847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
8151d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronstatic const char * const iio_ev_type_text[] = {
8161d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	[IIO_EV_TYPE_THRESH] = "thresh",
8171d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	[IIO_EV_TYPE_MAG] = "mag",
8181d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	[IIO_EV_TYPE_ROC] = "roc"
8191d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron};
8201d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
8211d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronstatic const char * const iio_ev_dir_text[] = {
8221d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	[IIO_EV_DIR_EITHER] = "either",
8231d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	[IIO_EV_DIR_RISING] = "rising",
8241d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	[IIO_EV_DIR_FALLING] = "falling"
8251d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron};
8261d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
8271d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronstatic ssize_t iio_ev_state_store(struct device *dev,
8281d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				  struct device_attribute *attr,
8291d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				  const char *buf,
8301d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				  size_t len)
8311d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron{
8321d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	struct iio_dev *indio_dev = dev_get_drvdata(dev);
833aaf370db7dad574e166f64cd9ad4129f12198145Jonathan Cameron	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
8341d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	int ret;
835c74b0de1666f8b8f6c65e1e944deff71fed0769aJonathan Cameron	bool val;
836c74b0de1666f8b8f6c65e1e944deff71fed0769aJonathan Cameron
837c74b0de1666f8b8f6c65e1e944deff71fed0769aJonathan Cameron	ret = strtobool(buf, &val);
838c74b0de1666f8b8f6c65e1e944deff71fed0769aJonathan Cameron	if (ret < 0)
839c74b0de1666f8b8f6c65e1e944deff71fed0769aJonathan Cameron		return ret;
8401d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
8416fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron	ret = indio_dev->info->write_event_config(indio_dev,
8426fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron						  this_attr->address,
8436fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron						  val);
8441d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	return (ret < 0) ? ret : len;
8451d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron}
8461d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
8471d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronstatic ssize_t iio_ev_state_show(struct device *dev,
8481d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				 struct device_attribute *attr,
8491d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				 char *buf)
8501d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron{
8511d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	struct iio_dev *indio_dev = dev_get_drvdata(dev);
852aaf370db7dad574e166f64cd9ad4129f12198145Jonathan Cameron	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
8536fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron	int val = indio_dev->info->read_event_config(indio_dev,
8546fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron						     this_attr->address);
8551d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
8561d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (val < 0)
8571d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		return val;
8581d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	else
8591d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		return sprintf(buf, "%d\n", val);
8601d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron}
8611d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
8621d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronstatic ssize_t iio_ev_value_show(struct device *dev,
8631d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				 struct device_attribute *attr,
8641d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				 char *buf)
8651d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron{
8661d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	struct iio_dev *indio_dev = dev_get_drvdata(dev);
8671d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
8681d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	int val, ret;
8691d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
8706fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron	ret = indio_dev->info->read_event_value(indio_dev,
8716fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron						this_attr->address, &val);
8721d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (ret < 0)
8731d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		return ret;
8741d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
8751d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	return sprintf(buf, "%d\n", val);
8761d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron}
8771d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
8781d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronstatic ssize_t iio_ev_value_store(struct device *dev,
8791d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				  struct device_attribute *attr,
8801d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				  const char *buf,
8811d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				  size_t len)
8821d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron{
8831d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	struct iio_dev *indio_dev = dev_get_drvdata(dev);
8841d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
8851d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	unsigned long val;
8861d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	int ret;
8871d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
8881d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	ret = strict_strtoul(buf, 10, &val);
8891d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (ret)
8901d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		return ret;
8911d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
8926fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron	ret = indio_dev->info->write_event_value(indio_dev, this_attr->address,
8936fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron						 val);
8941d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (ret < 0)
8951d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		return ret;
8961d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
8971d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	return len;
8981d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron}
8991d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
9001d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronstatic int iio_device_add_event_sysfs(struct iio_dev *dev_info,
9011d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				      struct iio_chan_spec const *chan)
9021d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron{
9031d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
9041d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	int ret = 0, i, mask;
9051d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	char *postfix;
9061d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (!chan->event_mask)
9071d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		return 0;
9081d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
9091d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	for_each_set_bit(i, &chan->event_mask, sizeof(chan->event_mask)*8) {
9101d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		postfix = kasprintf(GFP_KERNEL, "%s_%s_en",
9111d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				    iio_ev_type_text[i/IIO_EV_TYPE_MAX],
9121d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				    iio_ev_dir_text[i%IIO_EV_TYPE_MAX]);
9131d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		if (postfix == NULL) {
9141d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			ret = -ENOMEM;
9151d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			goto error_ret;
9161d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		}
9171d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		switch (chan->type) {
9181d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			/* Switch this to a table at some point */
9191d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		case IIO_IN:
9201d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			mask = IIO_UNMOD_EVENT_CODE(chan->type, chan->channel,
9211d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron						    i/IIO_EV_TYPE_MAX,
9221d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron						    i%IIO_EV_TYPE_MAX);
9231d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			break;
9241d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		case IIO_ACCEL:
9251d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			mask = IIO_MOD_EVENT_CODE(chan->type, 0, chan->channel,
9261d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron						  i/IIO_EV_TYPE_MAX,
9271d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron						  i%IIO_EV_TYPE_MAX);
9281d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			break;
9291d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		case IIO_IN_DIFF:
9301d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			mask = IIO_MOD_EVENT_CODE(chan->type, chan->channel,
9311d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron						  chan->channel2,
9321d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron						  i/IIO_EV_TYPE_MAX,
9331d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron						  i%IIO_EV_TYPE_MAX);
9341d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			break;
9351d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		default:
9361d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			printk(KERN_INFO "currently unhandled type of event\n");
9379076faa9af99e6eb69fb8939b97ab701d14b3145Jonathan Cameron			continue;
9381d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		}
939aaf370db7dad574e166f64cd9ad4129f12198145Jonathan Cameron		ret = __iio_add_chan_devattr(postfix,
940aaf370db7dad574e166f64cd9ad4129f12198145Jonathan Cameron					     NULL,
941aaf370db7dad574e166f64cd9ad4129f12198145Jonathan Cameron					     chan,
942aaf370db7dad574e166f64cd9ad4129f12198145Jonathan Cameron					     &iio_ev_state_show,
943aaf370db7dad574e166f64cd9ad4129f12198145Jonathan Cameron					     iio_ev_state_store,
944aaf370db7dad574e166f64cd9ad4129f12198145Jonathan Cameron					     mask,
945aaf370db7dad574e166f64cd9ad4129f12198145Jonathan Cameron					     /*HACK. - limits us to one
946aaf370db7dad574e166f64cd9ad4129f12198145Jonathan Cameron					       event interface - fix by
947aaf370db7dad574e166f64cd9ad4129f12198145Jonathan Cameron					       extending the bitmask - but
948aaf370db7dad574e166f64cd9ad4129f12198145Jonathan Cameron					       how far*/
949aaf370db7dad574e166f64cd9ad4129f12198145Jonathan Cameron					     0,
9506fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron					     &dev_info->event_interfaces[0].dev,
951aaf370db7dad574e166f64cd9ad4129f12198145Jonathan Cameron					     &dev_info->event_interfaces[0].
952aaf370db7dad574e166f64cd9ad4129f12198145Jonathan Cameron					     dev_attr_list);
9531d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		kfree(postfix);
9541d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		if (ret)
9551d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			goto error_ret;
9561d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
9571d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		postfix = kasprintf(GFP_KERNEL, "%s_%s_value",
9581d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				    iio_ev_type_text[i/IIO_EV_TYPE_MAX],
9591d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				    iio_ev_dir_text[i%IIO_EV_TYPE_MAX]);
9601d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		if (postfix == NULL) {
9611d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			ret = -ENOMEM;
9621d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			goto error_ret;
9631d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		}
9641d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		ret = __iio_add_chan_devattr(postfix, NULL, chan,
9651d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     iio_ev_value_show,
9661d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     iio_ev_value_store,
9671d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     mask,
9681d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     0,
9691d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     &dev_info->event_interfaces[0]
9701d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     .dev,
9711d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     &dev_info->event_interfaces[0]
9721d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     .dev_attr_list);
9731d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		kfree(postfix);
9741d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		if (ret)
9751d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			goto error_ret;
9761d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
9771d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	}
9781d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
9791d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronerror_ret:
9801d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	return ret;
9811d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron}
9821d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
983232b9cba130025d47531c5c539d6affc64950213Jonathan Cameronstatic inline void __iio_remove_event_config_attrs(struct iio_dev *dev_info,
984232b9cba130025d47531c5c539d6affc64950213Jonathan Cameron						  int i)
9851d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron{
9861d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	struct iio_dev_attr *p, *n;
9871d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	list_for_each_entry_safe(p, n,
988232b9cba130025d47531c5c539d6affc64950213Jonathan Cameron				 &dev_info->event_interfaces[i].
9891d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				 dev_attr_list, l) {
9901d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		sysfs_remove_file_from_group(&dev_info
991232b9cba130025d47531c5c539d6affc64950213Jonathan Cameron					     ->event_interfaces[i].dev.kobj,
9921d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					     &p->dev_attr.attr,
993232b9cba130025d47531c5c539d6affc64950213Jonathan Cameron					     NULL);
9941d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		kfree(p->dev_attr.attr.name);
9951d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		kfree(p);
9961d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	}
9971d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron}
9981d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
999847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronstatic inline int __iio_add_event_config_attrs(struct iio_dev *dev_info, int i)
1000847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron{
10011d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	int j;
1002847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	int ret;
1003232b9cba130025d47531c5c539d6affc64950213Jonathan Cameron	INIT_LIST_HEAD(&dev_info->event_interfaces[i].dev_attr_list);
10041d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	/* Dynically created from the channels array */
10051d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	if (dev_info->channels) {
10061d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		for (j = 0; j < dev_info->num_channels; j++) {
10071d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			ret = iio_device_add_event_sysfs(dev_info,
10081d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron							 &dev_info
10091d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron							 ->channels[j]);
10101d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			if (ret)
10111d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron				goto error_clear_attrs;
10121d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		}
10131d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron	}
1014847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	return 0;
1015847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
10161d892719e70e477156f62e060e0805d991d450e5Jonathan Cameronerror_clear_attrs:
1017232b9cba130025d47531c5c539d6affc64950213Jonathan Cameron	__iio_remove_event_config_attrs(dev_info, i);
1018847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
1019847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	return ret;
1020847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron}
1021847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
1022847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronstatic int iio_device_register_eventset(struct iio_dev *dev_info)
1023847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron{
1024847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	int ret = 0, i, j;
1025847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
10266fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron	if (dev_info->info->num_interrupt_lines == 0)
1027847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		return 0;
1028847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
1029847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	dev_info->event_interfaces =
1030847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		kzalloc(sizeof(struct iio_event_interface)
10316fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron			*dev_info->info->num_interrupt_lines,
1032847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron			GFP_KERNEL);
1033847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	if (dev_info->event_interfaces == NULL) {
1034847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		ret = -ENOMEM;
1035847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		goto error_ret;
1036847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	}
1037847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
10386fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron	for (i = 0; i < dev_info->info->num_interrupt_lines; i++) {
1039847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		ret = iio_setup_ev_int(&dev_info->event_interfaces[i],
1040c74b0de1666f8b8f6c65e1e944deff71fed0769aJonathan Cameron				       dev_name(&dev_info->dev),
1041c74b0de1666f8b8f6c65e1e944deff71fed0769aJonathan Cameron				       i,
10426fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron				       dev_info->info->driver_module,
1043847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron				       &dev_info->dev);
1044847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		if (ret) {
1045847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron			dev_err(&dev_info->dev,
1046847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron				"Could not get chrdev interface\n");
1047cc2439fdecb85f27866cab0ae1cbf21a9b61c423Jonathan Cameron			goto error_free_setup_event_lines;
1048847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		}
1049847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
10505cba220b0a3211befd5514cbd822a97578ef5ed4Jonathan Cameron		dev_set_drvdata(&dev_info->event_interfaces[i].dev,
10515cba220b0a3211befd5514cbd822a97578ef5ed4Jonathan Cameron				(void *)dev_info);
10521d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron
10536fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron		if (dev_info->info->event_attrs != NULL)
10541d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			ret = sysfs_create_group(&dev_info
10551d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron						 ->event_interfaces[i]
10561d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron						 .dev.kobj,
10576fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron						 &dev_info->info
10586fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron						 ->event_attrs[i]);
10595cba220b0a3211befd5514cbd822a97578ef5ed4Jonathan Cameron
1060847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		if (ret) {
1061847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron			dev_err(&dev_info->dev,
1062847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron				"Failed to register sysfs for event attrs");
1063cc2439fdecb85f27866cab0ae1cbf21a9b61c423Jonathan Cameron			iio_free_ev_int(&dev_info->event_interfaces[i]);
1064cc2439fdecb85f27866cab0ae1cbf21a9b61c423Jonathan Cameron			goto error_free_setup_event_lines;
1065847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		}
1066847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		ret = __iio_add_event_config_attrs(dev_info, i);
1067cc2439fdecb85f27866cab0ae1cbf21a9b61c423Jonathan Cameron		if (ret) {
1068cc2439fdecb85f27866cab0ae1cbf21a9b61c423Jonathan Cameron			if (dev_info->info->event_attrs != NULL)
1069cc2439fdecb85f27866cab0ae1cbf21a9b61c423Jonathan Cameron				sysfs_remove_group(&dev_info
1070cc2439fdecb85f27866cab0ae1cbf21a9b61c423Jonathan Cameron						   ->event_interfaces[i]
1071cc2439fdecb85f27866cab0ae1cbf21a9b61c423Jonathan Cameron						   .dev.kobj,
1072cc2439fdecb85f27866cab0ae1cbf21a9b61c423Jonathan Cameron						   &dev_info->info
1073cc2439fdecb85f27866cab0ae1cbf21a9b61c423Jonathan Cameron						   ->event_attrs[i]);
1074cc2439fdecb85f27866cab0ae1cbf21a9b61c423Jonathan Cameron			iio_free_ev_int(&dev_info->event_interfaces[i]);
1075cc2439fdecb85f27866cab0ae1cbf21a9b61c423Jonathan Cameron			goto error_free_setup_event_lines;
1076cc2439fdecb85f27866cab0ae1cbf21a9b61c423Jonathan Cameron		}
1077847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	}
1078847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
1079847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	return 0;
1080847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
1081cc2439fdecb85f27866cab0ae1cbf21a9b61c423Jonathan Cameronerror_free_setup_event_lines:
1082cc2439fdecb85f27866cab0ae1cbf21a9b61c423Jonathan Cameron	for (j = 0; j < i; j++) {
1083cc2439fdecb85f27866cab0ae1cbf21a9b61c423Jonathan Cameron		__iio_remove_event_config_attrs(dev_info, j);
10846fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron		if (dev_info->info->event_attrs != NULL)
10851d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			sysfs_remove_group(&dev_info
1086cc2439fdecb85f27866cab0ae1cbf21a9b61c423Jonathan Cameron					   ->event_interfaces[j].dev.kobj,
1087cc2439fdecb85f27866cab0ae1cbf21a9b61c423Jonathan Cameron					   &dev_info->info->event_attrs[j]);
1088847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		iio_free_ev_int(&dev_info->event_interfaces[j]);
1089cc2439fdecb85f27866cab0ae1cbf21a9b61c423Jonathan Cameron	}
1090847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	kfree(dev_info->event_interfaces);
1091847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronerror_ret:
1092847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
1093847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	return ret;
1094847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron}
1095847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
1096847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronstatic void iio_device_unregister_eventset(struct iio_dev *dev_info)
1097847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron{
1098847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	int i;
1099847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
11006fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron	if (dev_info->info->num_interrupt_lines == 0)
1101847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		return;
11026fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron	for (i = 0; i < dev_info->info->num_interrupt_lines; i++) {
11031d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron		__iio_remove_event_config_attrs(dev_info, i);
11046fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron		if (dev_info->info->event_attrs != NULL)
11051d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron			sysfs_remove_group(&dev_info
11061d892719e70e477156f62e060e0805d991d450e5Jonathan Cameron					   ->event_interfaces[i].dev.kobj,
11076fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron					   &dev_info->info->event_attrs[i]);
1108847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		iio_free_ev_int(&dev_info->event_interfaces[i]);
1109cc2439fdecb85f27866cab0ae1cbf21a9b61c423Jonathan Cameron	}
1110847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	kfree(dev_info->event_interfaces);
1111847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron}
1112847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
1113847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronstatic void iio_dev_release(struct device *device)
1114847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron{
1115847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	iio_put();
1116c74b0de1666f8b8f6c65e1e944deff71fed0769aJonathan Cameron	kfree(to_iio_dev(device));
1117847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron}
1118847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
1119847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronstatic struct device_type iio_dev_type = {
1120847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	.name = "iio_device",
1121847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	.release = iio_dev_release,
1122847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron};
1123847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
11246f7c8ee585e9db54cb29af1bdb93f29837824933Jonathan Cameronstruct iio_dev *iio_allocate_device(int sizeof_priv)
1125847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron{
11266f7c8ee585e9db54cb29af1bdb93f29837824933Jonathan Cameron	struct iio_dev *dev;
11276f7c8ee585e9db54cb29af1bdb93f29837824933Jonathan Cameron	size_t alloc_size;
11286f7c8ee585e9db54cb29af1bdb93f29837824933Jonathan Cameron
11296f7c8ee585e9db54cb29af1bdb93f29837824933Jonathan Cameron	alloc_size = sizeof(struct iio_dev);
11306f7c8ee585e9db54cb29af1bdb93f29837824933Jonathan Cameron	if (sizeof_priv) {
11316f7c8ee585e9db54cb29af1bdb93f29837824933Jonathan Cameron		alloc_size = ALIGN(alloc_size, IIO_ALIGN);
11326f7c8ee585e9db54cb29af1bdb93f29837824933Jonathan Cameron		alloc_size += sizeof_priv;
11336f7c8ee585e9db54cb29af1bdb93f29837824933Jonathan Cameron	}
11346f7c8ee585e9db54cb29af1bdb93f29837824933Jonathan Cameron	/* ensure 32-byte alignment of whole construct ? */
11356f7c8ee585e9db54cb29af1bdb93f29837824933Jonathan Cameron	alloc_size += IIO_ALIGN - 1;
11366f7c8ee585e9db54cb29af1bdb93f29837824933Jonathan Cameron
11376f7c8ee585e9db54cb29af1bdb93f29837824933Jonathan Cameron	dev = kzalloc(alloc_size, GFP_KERNEL);
1138847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
1139847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	if (dev) {
1140847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		dev->dev.type = &iio_dev_type;
11415aaaeba82e00958ecb2c890b4953a249bbde9426Jonathan Cameron		dev->dev.bus = &iio_bus_type;
1142847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		device_initialize(&dev->dev);
1143847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		dev_set_drvdata(&dev->dev, (void *)dev);
1144847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		mutex_init(&dev->mlock);
1145847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		iio_get();
1146847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	}
1147847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
1148847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	return dev;
1149847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron}
1150847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan CameronEXPORT_SYMBOL(iio_allocate_device);
1151847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
1152847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronvoid iio_free_device(struct iio_dev *dev)
1153847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron{
1154847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	if (dev)
1155847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		iio_put_device(dev);
1156847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron}
1157847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan CameronEXPORT_SYMBOL(iio_free_device);
1158847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
1159847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronint iio_device_register(struct iio_dev *dev_info)
1160847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron{
1161847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	int ret;
1162847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
1163c74b0de1666f8b8f6c65e1e944deff71fed0769aJonathan Cameron	dev_info->id = iio_get_new_ida_val(&iio_ida);
1164c74b0de1666f8b8f6c65e1e944deff71fed0769aJonathan Cameron	if (dev_info->id < 0) {
1165c74b0de1666f8b8f6c65e1e944deff71fed0769aJonathan Cameron		ret = dev_info->id;
1166847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		dev_err(&dev_info->dev, "Failed to get id\n");
1167847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		goto error_ret;
1168847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	}
1169847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	dev_set_name(&dev_info->dev, "device%d", dev_info->id);
1170847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
1171847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	ret = device_add(&dev_info->dev);
1172847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	if (ret)
1173b156cf70e1f4befc4856baaf9681dede9a143888Jonathan Cameron		goto error_free_ida;
1174847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	ret = iio_device_register_sysfs(dev_info);
1175847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	if (ret) {
1176847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		dev_err(dev_info->dev.parent,
1177847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron			"Failed to register sysfs interfaces\n");
1178847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		goto error_del_device;
1179847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	}
1180847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	ret = iio_device_register_eventset(dev_info);
1181847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	if (ret) {
1182847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		dev_err(dev_info->dev.parent,
1183c849d2538ebeef1ac26fad7a10c18b1e0fc35161Roel Van Nyen			"Failed to register event set\n");
1184847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		goto error_free_sysfs;
1185847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	}
1186847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	if (dev_info->modes & INDIO_RING_TRIGGERED)
1187847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		iio_device_register_trigger_consumer(dev_info);
1188847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
1189847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	return 0;
1190847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
1191847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronerror_free_sysfs:
1192847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	iio_device_unregister_sysfs(dev_info);
1193847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronerror_del_device:
1194847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	device_del(&dev_info->dev);
1195b156cf70e1f4befc4856baaf9681dede9a143888Jonathan Cameronerror_free_ida:
1196c74b0de1666f8b8f6c65e1e944deff71fed0769aJonathan Cameron	iio_free_ida_val(&iio_ida, dev_info->id);
1197847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronerror_ret:
1198847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	return ret;
1199847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron}
1200847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan CameronEXPORT_SYMBOL(iio_device_register);
1201847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
1202847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronvoid iio_device_unregister(struct iio_dev *dev_info)
1203847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron{
1204847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	if (dev_info->modes & INDIO_RING_TRIGGERED)
1205847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron		iio_device_unregister_trigger_consumer(dev_info);
1206847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	iio_device_unregister_eventset(dev_info);
1207847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	iio_device_unregister_sysfs(dev_info);
1208c74b0de1666f8b8f6c65e1e944deff71fed0769aJonathan Cameron	iio_free_ida_val(&iio_ida, dev_info->id);
1209847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	device_unregister(&dev_info->dev);
1210847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron}
1211847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan CameronEXPORT_SYMBOL(iio_device_unregister);
1212847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
1213847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronvoid iio_put(void)
1214847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron{
1215847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	module_put(THIS_MODULE);
1216847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron}
1217847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
1218847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronvoid iio_get(void)
1219847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron{
1220847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron	__module_get(THIS_MODULE);
1221847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron}
1222847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
1223847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronsubsys_initcall(iio_init);
1224847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameronmodule_exit(iio_exit);
1225847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan Cameron
1226847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan CameronMODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
1227847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan CameronMODULE_DESCRIPTION("Industrial I/O core");
1228847ec80bbaa76aae41062d6802cea9c1b2289f14Jonathan CameronMODULE_LICENSE("GPL");
1229