xref: /openbmc/linux/drivers/iio/inkern.c (revision 05bcf503)
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, const char *name)
96 {
97 	int i;
98 	const struct iio_chan_spec *chan = NULL;
99 
100 	for (i = 0; i < indio_dev->num_channels; i++)
101 		if (indio_dev->channels[i].datasheet_name &&
102 		    strcmp(name, indio_dev->channels[i].datasheet_name) == 0) {
103 			chan = &indio_dev->channels[i];
104 			break;
105 		}
106 	return chan;
107 }
108 
109 
110 struct iio_channel *iio_channel_get(const char *name, const char *channel_name)
111 {
112 	struct iio_map_internal *c_i = NULL, *c = NULL;
113 	struct iio_channel *channel;
114 	int err;
115 
116 	if (name == NULL && channel_name == NULL)
117 		return ERR_PTR(-ENODEV);
118 
119 	/* first find matching entry the channel map */
120 	mutex_lock(&iio_map_list_lock);
121 	list_for_each_entry(c_i, &iio_map_list, l) {
122 		if ((name && strcmp(name, c_i->map->consumer_dev_name) != 0) ||
123 		    (channel_name &&
124 		     strcmp(channel_name, c_i->map->consumer_channel) != 0))
125 			continue;
126 		c = c_i;
127 		iio_device_get(c->indio_dev);
128 		break;
129 	}
130 	mutex_unlock(&iio_map_list_lock);
131 	if (c == NULL)
132 		return ERR_PTR(-ENODEV);
133 
134 	channel = kzalloc(sizeof(*channel), GFP_KERNEL);
135 	if (channel == NULL) {
136 		err = -ENOMEM;
137 		goto error_no_mem;
138 	}
139 
140 	channel->indio_dev = c->indio_dev;
141 
142 	if (c->map->adc_channel_label) {
143 		channel->channel =
144 			iio_chan_spec_from_name(channel->indio_dev,
145 						c->map->adc_channel_label);
146 
147 		if (channel->channel == NULL) {
148 			err = -EINVAL;
149 			goto error_no_chan;
150 		}
151 	}
152 
153 	return channel;
154 
155 error_no_chan:
156 	kfree(channel);
157 error_no_mem:
158 	iio_device_put(c->indio_dev);
159 	return ERR_PTR(err);
160 }
161 EXPORT_SYMBOL_GPL(iio_channel_get);
162 
163 void iio_channel_release(struct iio_channel *channel)
164 {
165 	iio_device_put(channel->indio_dev);
166 	kfree(channel);
167 }
168 EXPORT_SYMBOL_GPL(iio_channel_release);
169 
170 struct iio_channel *iio_channel_get_all(const char *name)
171 {
172 	struct iio_channel *chans;
173 	struct iio_map_internal *c = NULL;
174 	int nummaps = 0;
175 	int mapind = 0;
176 	int i, ret;
177 
178 	if (name == NULL)
179 		return ERR_PTR(-EINVAL);
180 
181 	mutex_lock(&iio_map_list_lock);
182 	/* first count the matching maps */
183 	list_for_each_entry(c, &iio_map_list, l)
184 		if (name && strcmp(name, c->map->consumer_dev_name) != 0)
185 			continue;
186 		else
187 			nummaps++;
188 
189 	if (nummaps == 0) {
190 		ret = -ENODEV;
191 		goto error_ret;
192 	}
193 
194 	/* NULL terminated array to save passing size */
195 	chans = kzalloc(sizeof(*chans)*(nummaps + 1), GFP_KERNEL);
196 	if (chans == NULL) {
197 		ret = -ENOMEM;
198 		goto error_ret;
199 	}
200 
201 	/* for each map fill in the chans element */
202 	list_for_each_entry(c, &iio_map_list, l) {
203 		if (name && strcmp(name, c->map->consumer_dev_name) != 0)
204 			continue;
205 		chans[mapind].indio_dev = c->indio_dev;
206 		chans[mapind].channel =
207 			iio_chan_spec_from_name(chans[mapind].indio_dev,
208 						c->map->adc_channel_label);
209 		if (chans[mapind].channel == NULL) {
210 			ret = -EINVAL;
211 			goto error_free_chans;
212 		}
213 		iio_device_get(chans[mapind].indio_dev);
214 		mapind++;
215 	}
216 	if (mapind == 0) {
217 		ret = -ENODEV;
218 		goto error_free_chans;
219 	}
220 	mutex_unlock(&iio_map_list_lock);
221 
222 	return chans;
223 
224 error_free_chans:
225 	for (i = 0; i < nummaps; i++)
226 		iio_device_put(chans[i].indio_dev);
227 	kfree(chans);
228 error_ret:
229 	mutex_unlock(&iio_map_list_lock);
230 
231 	return ERR_PTR(ret);
232 }
233 EXPORT_SYMBOL_GPL(iio_channel_get_all);
234 
235 void iio_channel_release_all(struct iio_channel *channels)
236 {
237 	struct iio_channel *chan = &channels[0];
238 
239 	while (chan->indio_dev) {
240 		iio_device_put(chan->indio_dev);
241 		chan++;
242 	}
243 	kfree(channels);
244 }
245 EXPORT_SYMBOL_GPL(iio_channel_release_all);
246 
247 static int iio_channel_read(struct iio_channel *chan, int *val, int *val2,
248 	enum iio_chan_info_enum info)
249 {
250 	int unused;
251 
252 	if (val2 == NULL)
253 		val2 = &unused;
254 
255 	return chan->indio_dev->info->read_raw(chan->indio_dev, chan->channel,
256 						val, val2, info);
257 }
258 
259 int iio_read_channel_raw(struct iio_channel *chan, int *val)
260 {
261 	int ret;
262 
263 	mutex_lock(&chan->indio_dev->info_exist_lock);
264 	if (chan->indio_dev->info == NULL) {
265 		ret = -ENODEV;
266 		goto err_unlock;
267 	}
268 
269 	ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW);
270 err_unlock:
271 	mutex_unlock(&chan->indio_dev->info_exist_lock);
272 
273 	return ret;
274 }
275 EXPORT_SYMBOL_GPL(iio_read_channel_raw);
276 
277 static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan,
278 	int raw, int *processed, unsigned int scale)
279 {
280 	int scale_type, scale_val, scale_val2, offset;
281 	s64 raw64 = raw;
282 	int ret;
283 
284 	ret = iio_channel_read(chan, &offset, NULL, IIO_CHAN_INFO_SCALE);
285 	if (ret == 0)
286 		raw64 += offset;
287 
288 	scale_type = iio_channel_read(chan, &scale_val, &scale_val2,
289 					IIO_CHAN_INFO_SCALE);
290 	if (scale_type < 0)
291 		return scale_type;
292 
293 	switch (scale_type) {
294 	case IIO_VAL_INT:
295 		*processed = raw64 * scale_val;
296 		break;
297 	case IIO_VAL_INT_PLUS_MICRO:
298 		if (scale_val2 < 0)
299 			*processed = -raw64 * scale_val;
300 		else
301 			*processed = raw64 * scale_val;
302 		*processed += div_s64(raw64 * (s64)scale_val2 * scale,
303 				      1000000LL);
304 		break;
305 	case IIO_VAL_INT_PLUS_NANO:
306 		if (scale_val2 < 0)
307 			*processed = -raw64 * scale_val;
308 		else
309 			*processed = raw64 * scale_val;
310 		*processed += div_s64(raw64 * (s64)scale_val2 * scale,
311 				      1000000000LL);
312 		break;
313 	case IIO_VAL_FRACTIONAL:
314 		*processed = div_s64(raw64 * (s64)scale_val * scale,
315 				     scale_val2);
316 		break;
317 	default:
318 		return -EINVAL;
319 	}
320 
321 	return 0;
322 }
323 
324 int iio_convert_raw_to_processed(struct iio_channel *chan, int raw,
325 	int *processed, unsigned int scale)
326 {
327 	int ret;
328 
329 	mutex_lock(&chan->indio_dev->info_exist_lock);
330 	if (chan->indio_dev->info == NULL) {
331 		ret = -ENODEV;
332 		goto err_unlock;
333 	}
334 
335 	ret = iio_convert_raw_to_processed_unlocked(chan, raw, processed,
336 							scale);
337 err_unlock:
338 	mutex_unlock(&chan->indio_dev->info_exist_lock);
339 
340 	return ret;
341 }
342 EXPORT_SYMBOL_GPL(iio_convert_raw_to_processed);
343 
344 int iio_read_channel_processed(struct iio_channel *chan, int *val)
345 {
346 	int ret;
347 
348 	mutex_lock(&chan->indio_dev->info_exist_lock);
349 	if (chan->indio_dev->info == NULL) {
350 		ret = -ENODEV;
351 		goto err_unlock;
352 	}
353 
354 	if (iio_channel_has_info(chan->channel, IIO_CHAN_INFO_PROCESSED)) {
355 		ret = iio_channel_read(chan, val, NULL,
356 				       IIO_CHAN_INFO_PROCESSED);
357 	} else {
358 		ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW);
359 		if (ret < 0)
360 			goto err_unlock;
361 		ret = iio_convert_raw_to_processed_unlocked(chan, *val, val, 1);
362 	}
363 
364 err_unlock:
365 	mutex_unlock(&chan->indio_dev->info_exist_lock);
366 
367 	return ret;
368 }
369 EXPORT_SYMBOL_GPL(iio_read_channel_processed);
370 
371 int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2)
372 {
373 	int ret;
374 
375 	mutex_lock(&chan->indio_dev->info_exist_lock);
376 	if (chan->indio_dev->info == NULL) {
377 		ret = -ENODEV;
378 		goto err_unlock;
379 	}
380 
381 	ret = iio_channel_read(chan, val, val2, IIO_CHAN_INFO_SCALE);
382 err_unlock:
383 	mutex_unlock(&chan->indio_dev->info_exist_lock);
384 
385 	return ret;
386 }
387 EXPORT_SYMBOL_GPL(iio_read_channel_scale);
388 
389 int iio_get_channel_type(struct iio_channel *chan, enum iio_chan_type *type)
390 {
391 	int ret = 0;
392 	/* Need to verify underlying driver has not gone away */
393 
394 	mutex_lock(&chan->indio_dev->info_exist_lock);
395 	if (chan->indio_dev->info == NULL) {
396 		ret = -ENODEV;
397 		goto err_unlock;
398 	}
399 
400 	*type = chan->channel->type;
401 err_unlock:
402 	mutex_unlock(&chan->indio_dev->info_exist_lock);
403 
404 	return ret;
405 }
406 EXPORT_SYMBOL_GPL(iio_get_channel_type);
407