Merge 3.5-rc4 into staging-next
[firefly-linux-kernel-4.4.55.git] / drivers / iio / inkern.c
1 /* The industrial I/O core in kernel channel mapping
2  *
3  * Copyright (c) 2011 Jonathan Cameron
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 as published by
7  * the Free Software Foundation.
8  */
9 #include <linux/err.h>
10 #include <linux/export.h>
11 #include <linux/slab.h>
12 #include <linux/mutex.h>
13
14 #include <linux/iio/iio.h>
15 #include "iio_core.h"
16 #include <linux/iio/machine.h>
17 #include <linux/iio/driver.h>
18 #include <linux/iio/consumer.h>
19
20 struct iio_map_internal {
21         struct iio_dev *indio_dev;
22         struct iio_map *map;
23         struct list_head l;
24 };
25
26 static LIST_HEAD(iio_map_list);
27 static DEFINE_MUTEX(iio_map_list_lock);
28
29 int iio_map_array_register(struct iio_dev *indio_dev, struct iio_map *maps)
30 {
31         int i = 0, ret = 0;
32         struct iio_map_internal *mapi;
33
34         if (maps == NULL)
35                 return 0;
36
37         mutex_lock(&iio_map_list_lock);
38         while (maps[i].consumer_dev_name != NULL) {
39                 mapi = kzalloc(sizeof(*mapi), GFP_KERNEL);
40                 if (mapi == NULL) {
41                         ret = -ENOMEM;
42                         goto error_ret;
43                 }
44                 mapi->map = &maps[i];
45                 mapi->indio_dev = indio_dev;
46                 list_add(&mapi->l, &iio_map_list);
47                 i++;
48         }
49 error_ret:
50         mutex_unlock(&iio_map_list_lock);
51
52         return ret;
53 }
54 EXPORT_SYMBOL_GPL(iio_map_array_register);
55
56
57 /* Assumes the exact same array (e.g. memory locations)
58  * used at unregistration as used at registration rather than
59  * more complex checking of contents.
60  */
61 int iio_map_array_unregister(struct iio_dev *indio_dev,
62                              struct iio_map *maps)
63 {
64         int i = 0, ret = 0;
65         bool found_it;
66         struct iio_map_internal *mapi;
67
68         if (maps == NULL)
69                 return 0;
70
71         mutex_lock(&iio_map_list_lock);
72         while (maps[i].consumer_dev_name != NULL) {
73                 found_it = false;
74                 list_for_each_entry(mapi, &iio_map_list, l)
75                         if (&maps[i] == mapi->map) {
76                                 list_del(&mapi->l);
77                                 kfree(mapi);
78                                 found_it = true;
79                                 break;
80                         }
81                 if (found_it == false) {
82                         ret = -ENODEV;
83                         goto error_ret;
84                 }
85                 i++;
86         }
87 error_ret:
88         mutex_unlock(&iio_map_list_lock);
89
90         return ret;
91 }
92 EXPORT_SYMBOL_GPL(iio_map_array_unregister);
93
94 static const struct iio_chan_spec
95 *iio_chan_spec_from_name(const struct iio_dev *indio_dev,
96                          const char *name)
97 {
98         int i;
99         const struct iio_chan_spec *chan = NULL;
100
101         for (i = 0; i < indio_dev->num_channels; i++)
102                 if (indio_dev->channels[i].datasheet_name &&
103                     strcmp(name, indio_dev->channels[i].datasheet_name) == 0) {
104                         chan = &indio_dev->channels[i];
105                         break;
106                 }
107         return chan;
108 }
109
110
111 struct iio_channel *iio_st_channel_get(const char *name,
112                                        const char *channel_name)
113 {
114         struct iio_map_internal *c_i = NULL, *c = NULL;
115         struct iio_channel *channel;
116
117         if (name == NULL && channel_name == NULL)
118                 return ERR_PTR(-ENODEV);
119
120         /* first find matching entry the channel map */
121         mutex_lock(&iio_map_list_lock);
122         list_for_each_entry(c_i, &iio_map_list, l) {
123                 if ((name && strcmp(name, c_i->map->consumer_dev_name) != 0) ||
124                     (channel_name &&
125                      strcmp(channel_name, c_i->map->consumer_channel) != 0))
126                         continue;
127                 c = c_i;
128                 iio_device_get(c->indio_dev);
129                 break;
130         }
131         mutex_unlock(&iio_map_list_lock);
132         if (c == NULL)
133                 return ERR_PTR(-ENODEV);
134
135         channel = kmalloc(sizeof(*channel), GFP_KERNEL);
136         if (channel == NULL)
137                 return ERR_PTR(-ENOMEM);
138
139         channel->indio_dev = c->indio_dev;
140
141         if (c->map->adc_channel_label)
142                 channel->channel =
143                         iio_chan_spec_from_name(channel->indio_dev,
144                                                 c->map->adc_channel_label);
145
146         return channel;
147 }
148 EXPORT_SYMBOL_GPL(iio_st_channel_get);
149
150 void iio_st_channel_release(struct iio_channel *channel)
151 {
152         iio_device_put(channel->indio_dev);
153         kfree(channel);
154 }
155 EXPORT_SYMBOL_GPL(iio_st_channel_release);
156
157 struct iio_channel *iio_st_channel_get_all(const char *name)
158 {
159         struct iio_channel *chans;
160         struct iio_map_internal *c = NULL;
161         int nummaps = 0;
162         int mapind = 0;
163         int i, ret;
164
165         if (name == NULL)
166                 return ERR_PTR(-EINVAL);
167
168         mutex_lock(&iio_map_list_lock);
169         /* first count the matching maps */
170         list_for_each_entry(c, &iio_map_list, l)
171                 if (name && strcmp(name, c->map->consumer_dev_name) != 0)
172                         continue;
173                 else
174                         nummaps++;
175
176         if (nummaps == 0) {
177                 ret = -ENODEV;
178                 goto error_ret;
179         }
180
181         /* NULL terminated array to save passing size */
182         chans = kzalloc(sizeof(*chans)*(nummaps + 1), GFP_KERNEL);
183         if (chans == NULL) {
184                 ret = -ENOMEM;
185                 goto error_ret;
186         }
187
188         /* for each map fill in the chans element */
189         list_for_each_entry(c, &iio_map_list, l) {
190                 if (name && strcmp(name, c->map->consumer_dev_name) != 0)
191                         continue;
192                 chans[mapind].indio_dev = c->indio_dev;
193                 chans[mapind].channel =
194                         iio_chan_spec_from_name(chans[mapind].indio_dev,
195                                                 c->map->adc_channel_label);
196                 if (chans[mapind].channel == NULL) {
197                         ret = -EINVAL;
198                         iio_device_put(chans[mapind].indio_dev);
199                         goto error_free_chans;
200                 }
201                 iio_device_get(chans[mapind].indio_dev);
202                 mapind++;
203         }
204         mutex_unlock(&iio_map_list_lock);
205         if (mapind == 0) {
206                 ret = -ENODEV;
207                 goto error_free_chans;
208         }
209         return chans;
210
211 error_free_chans:
212         for (i = 0; i < nummaps; i++)
213                 iio_device_put(chans[i].indio_dev);
214         kfree(chans);
215 error_ret:
216         mutex_unlock(&iio_map_list_lock);
217
218         return ERR_PTR(ret);
219 }
220 EXPORT_SYMBOL_GPL(iio_st_channel_get_all);
221
222 void iio_st_channel_release_all(struct iio_channel *channels)
223 {
224         struct iio_channel *chan = &channels[0];
225
226         while (chan->indio_dev) {
227                 iio_device_put(chan->indio_dev);
228                 chan++;
229         }
230         kfree(channels);
231 }
232 EXPORT_SYMBOL_GPL(iio_st_channel_release_all);
233
234 int iio_st_read_channel_raw(struct iio_channel *chan, int *val)
235 {
236         int val2, ret;
237
238         mutex_lock(&chan->indio_dev->info_exist_lock);
239         if (chan->indio_dev->info == NULL) {
240                 ret = -ENODEV;
241                 goto err_unlock;
242         }
243
244         ret = chan->indio_dev->info->read_raw(chan->indio_dev, chan->channel,
245                                               val, &val2, 0);
246 err_unlock:
247         mutex_unlock(&chan->indio_dev->info_exist_lock);
248
249         return ret;
250 }
251 EXPORT_SYMBOL_GPL(iio_st_read_channel_raw);
252
253 int iio_st_read_channel_scale(struct iio_channel *chan, int *val, int *val2)
254 {
255         int ret;
256
257         mutex_lock(&chan->indio_dev->info_exist_lock);
258         if (chan->indio_dev->info == NULL) {
259                 ret = -ENODEV;
260                 goto err_unlock;
261         }
262
263         ret = chan->indio_dev->info->read_raw(chan->indio_dev,
264                                               chan->channel,
265                                               val, val2,
266                                               IIO_CHAN_INFO_SCALE);
267 err_unlock:
268         mutex_unlock(&chan->indio_dev->info_exist_lock);
269
270         return ret;
271 }
272 EXPORT_SYMBOL_GPL(iio_st_read_channel_scale);
273
274 int iio_st_get_channel_type(struct iio_channel *chan,
275                             enum iio_chan_type *type)
276 {
277         int ret = 0;
278         /* Need to verify underlying driver has not gone away */
279
280         mutex_lock(&chan->indio_dev->info_exist_lock);
281         if (chan->indio_dev->info == NULL) {
282                 ret = -ENODEV;
283                 goto err_unlock;
284         }
285
286         *type = chan->channel->type;
287 err_unlock:
288         mutex_unlock(&chan->indio_dev->info_exist_lock);
289
290         return ret;
291 }
292 EXPORT_SYMBOL_GPL(iio_st_get_channel_type);