xref: /openbmc/linux/drivers/iio/inkern.c (revision 33a03aad)
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 		get_device(&c->indio_dev->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 	put_device(&channel->indio_dev->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 			put_device(&chans[mapind].indio_dev->dev);
199 			goto error_free_chans;
200 		}
201 		get_device(&chans[mapind].indio_dev->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 		if (chans[i].indio_dev)
214 			put_device(&chans[i].indio_dev->dev);
215 	kfree(chans);
216 error_ret:
217 	mutex_unlock(&iio_map_list_lock);
218 
219 	return ERR_PTR(ret);
220 }
221 EXPORT_SYMBOL_GPL(iio_st_channel_get_all);
222 
223 void iio_st_channel_release_all(struct iio_channel *channels)
224 {
225 	struct iio_channel *chan = &channels[0];
226 
227 	while (chan->indio_dev) {
228 		put_device(&chan->indio_dev->dev);
229 		chan++;
230 	}
231 	kfree(channels);
232 }
233 EXPORT_SYMBOL_GPL(iio_st_channel_release_all);
234 
235 int iio_st_read_channel_raw(struct iio_channel *chan, int *val)
236 {
237 	int val2, ret;
238 
239 	mutex_lock(&chan->indio_dev->info_exist_lock);
240 	if (chan->indio_dev->info == NULL) {
241 		ret = -ENODEV;
242 		goto err_unlock;
243 	}
244 
245 	ret = chan->indio_dev->info->read_raw(chan->indio_dev, chan->channel,
246 					      val, &val2, 0);
247 err_unlock:
248 	mutex_unlock(&chan->indio_dev->info_exist_lock);
249 
250 	return ret;
251 }
252 EXPORT_SYMBOL_GPL(iio_st_read_channel_raw);
253 
254 int iio_st_read_channel_scale(struct iio_channel *chan, int *val, int *val2)
255 {
256 	int ret;
257 
258 	mutex_lock(&chan->indio_dev->info_exist_lock);
259 	if (chan->indio_dev->info == NULL) {
260 		ret = -ENODEV;
261 		goto err_unlock;
262 	}
263 
264 	ret = chan->indio_dev->info->read_raw(chan->indio_dev,
265 					      chan->channel,
266 					      val, val2,
267 					      IIO_CHAN_INFO_SCALE);
268 err_unlock:
269 	mutex_unlock(&chan->indio_dev->info_exist_lock);
270 
271 	return ret;
272 }
273 EXPORT_SYMBOL_GPL(iio_st_read_channel_scale);
274 
275 int iio_st_get_channel_type(struct iio_channel *chan,
276 			    enum iio_chan_type *type)
277 {
278 	int ret = 0;
279 	/* Need to verify underlying driver has not gone away */
280 
281 	mutex_lock(&chan->indio_dev->info_exist_lock);
282 	if (chan->indio_dev->info == NULL) {
283 		ret = -ENODEV;
284 		goto err_unlock;
285 	}
286 
287 	*type = chan->channel->type;
288 err_unlock:
289 	mutex_unlock(&chan->indio_dev->info_exist_lock);
290 
291 	return ret;
292 }
293 EXPORT_SYMBOL_GPL(iio_st_get_channel_type);
294