aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/iio
diff options
context:
space:
mode:
authorJonathan Cameron <jic23@cam.ac.uk>2012-02-15 14:48:01 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-02-24 15:10:02 -0500
commite27d75d71c0dbbab83768c6e327d13f445d0214f (patch)
tree3076216ea6fba337f8a88351c35f40427fa86301 /drivers/staging/iio
parentac917a81117ce0286847666b55dd265f6cda8383 (diff)
staging:iio:core add in kernel interface mapping and getting IIO channels.
Lifted from proposal for in kernel interface built on the out of staging branch. Two elements here: * Map as defined in "inkern.h" * Matching code to actually get the iio_dev and channel that we want from the global list of IIO devices. V4: Everything now built if iio is built (rather than being optional) Removal race condition prevented by using info pointer as a check of removal under a lock. V3: Drop the option of registering / getting channels using dev pointer. Stick to name only as suggested by Mark Brown (this has caused user confusion in the regulator framework.) V2: As per Greg KH suggestion, move over to registration by passing the tables into the provider drivers (how regulator does it). This does not prevent us using the original more flexible approach if at a later date there is a usecase that demands it. Signed-off-by: Jonathan Cameron <jic23@kernel.org> Acked-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/iio')
-rw-r--r--drivers/staging/iio/Makefile2
-rw-r--r--drivers/staging/iio/consumer.h96
-rw-r--r--drivers/staging/iio/driver.h34
-rw-r--r--drivers/staging/iio/inkern.c292
-rw-r--r--drivers/staging/iio/machine.h24
5 files changed, 447 insertions, 1 deletions
diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile
index 657710b266b..ff059d448c2 100644
--- a/drivers/staging/iio/Makefile
+++ b/drivers/staging/iio/Makefile
@@ -3,7 +3,7 @@
3# 3#
4 4
5obj-$(CONFIG_IIO) += industrialio.o 5obj-$(CONFIG_IIO) += industrialio.o
6industrialio-y := industrialio-core.o industrialio-event.o 6industrialio-y := industrialio-core.o industrialio-event.o inkern.o
7industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o 7industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
8industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o 8industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
9 9
diff --git a/drivers/staging/iio/consumer.h b/drivers/staging/iio/consumer.h
new file mode 100644
index 00000000000..36a060cd3a2
--- /dev/null
+++ b/drivers/staging/iio/consumer.h
@@ -0,0 +1,96 @@
1/*
2 * Industrial I/O in kernel consumer interface
3 *
4 * Copyright (c) 2011 Jonathan Cameron
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
9 */
10#ifndef _IIO_INKERN_CONSUMER_H_
11#define _IIO_INKERN_CONSUMER_H
12#include "types.h"
13
14struct iio_dev;
15struct iio_chan_spec;
16
17/**
18 * struct iio_channel - everything needed for a consumer to use a channel
19 * @indio_dev: Device on which the channel exists.
20 * @channel: Full description of the channel.
21 */
22struct iio_channel {
23 struct iio_dev *indio_dev;
24 const struct iio_chan_spec *channel;
25};
26
27/**
28 * iio_channel_get() - get description of all that is needed to access channel.
29 * @name: Unique name of the device as provided in the iio_map
30 * with which the desired provider to consumer mapping
31 * was registered.
32 * @consumer_channel: Unique name to identify the channel on the consumer
33 * side. This typically describes the channels use within
34 * the consumer. E.g. 'battery_voltage'
35 */
36struct iio_channel *iio_st_channel_get(const char *name,
37 const char *consumer_channel);
38
39/**
40 * iio_st_channel_release() - release channels obtained via iio_st_channel_get
41 * @chan: The channel to be released.
42 */
43void iio_st_channel_release(struct iio_channel *chan);
44
45/**
46 * iio_st_channel_get_all() - get all channels associated with a client
47 * @name: name of consumer device.
48 *
49 * Returns an array of iio_channel structures terminated with one with
50 * null iio_dev pointer.
51 * This function is used by fairly generic consumers to get all the
52 * channels registered as having this consumer.
53 */
54struct iio_channel *iio_st_channel_get_all(const char *name);
55
56/**
57 * iio_st_channel_release_all() - reverse iio_st_get_all
58 * @chan: Array of channels to be released.
59 */
60void iio_st_channel_release_all(struct iio_channel *chan);
61
62/**
63 * iio_st_read_channel_raw() - read from a given channel
64 * @channel: The channel being queried.
65 * @val: Value read back.
66 *
67 * Note raw reads from iio channels are in adc counts and hence
68 * scale will need to be applied if standard units required.
69 */
70int iio_st_read_channel_raw(struct iio_channel *chan,
71 int *val);
72
73/**
74 * iio_st_get_channel_type() - get the type of a channel
75 * @channel: The channel being queried.
76 * @type: The type of the channel.
77 *
78 * returns the enum iio_chan_type of the channel
79 */
80int iio_st_get_channel_type(struct iio_channel *channel,
81 enum iio_chan_type *type);
82
83/**
84 * iio_st_read_channel_scale() - read the scale value for a channel
85 * @channel: The channel being queried.
86 * @val: First part of value read back.
87 * @val2: Second part of value read back.
88 *
89 * Note returns a description of what is in val and val2, such
90 * as IIO_VAL_INT_PLUS_MICRO telling us we have a value of val
91 * + val2/1e6
92 */
93int iio_st_read_channel_scale(struct iio_channel *chan, int *val,
94 int *val2);
95
96#endif
diff --git a/drivers/staging/iio/driver.h b/drivers/staging/iio/driver.h
new file mode 100644
index 00000000000..a4f8b2e05af
--- /dev/null
+++ b/drivers/staging/iio/driver.h
@@ -0,0 +1,34 @@
1/*
2 * Industrial I/O in kernel access map interface.
3 *
4 * Copyright (c) 2011 Jonathan Cameron
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
9 */
10
11#ifndef _IIO_INKERN_H_
12#define _IIO_INKERN_H_
13
14struct iio_map;
15
16/**
17 * iio_map_array_register() - tell the core about inkernel consumers
18 * @indio_dev: provider device
19 * @map: array of mappings specifying association of channel with client
20 */
21int iio_map_array_register(struct iio_dev *indio_dev,
22 struct iio_map *map);
23
24/**
25 * iio_map_array_unregister() - tell the core to remove consumer mappings
26 * @indio_dev: provider device
27 * @map: array of mappings to remove. Note these must have same memory
28 * addresses as those originally added not just equal parameter
29 * values.
30 */
31int iio_map_array_unregister(struct iio_dev *indio_dev,
32 struct iio_map *map);
33
34#endif
diff --git a/drivers/staging/iio/inkern.c b/drivers/staging/iio/inkern.c
new file mode 100644
index 00000000000..de2c8ea6496
--- /dev/null
+++ b/drivers/staging/iio/inkern.c
@@ -0,0 +1,292 @@
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 "iio.h"
15#include "iio_core.h"
16#include "machine.h"
17#include "driver.h"
18#include "consumer.h"
19
20struct iio_map_internal {
21 struct iio_dev *indio_dev;
22 struct iio_map *map;
23 struct list_head l;
24};
25
26static LIST_HEAD(iio_map_list);
27static DEFINE_MUTEX(iio_map_list_lock);
28
29int 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 }
49error_ret:
50 mutex_unlock(&iio_map_list_lock);
51
52 return ret;
53}
54EXPORT_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 */
61int 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 }
86error_ret:
87 mutex_unlock(&iio_map_list_lock);
88
89 return ret;
90}
91EXPORT_SYMBOL_GPL(iio_map_array_unregister);
92
93static const struct iio_chan_spec
94*iio_chan_spec_from_name(const struct iio_dev *indio_dev,
95 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
110struct iio_channel *iio_st_channel_get(const char *name,
111 const char *channel_name)
112{
113 struct iio_map_internal *c_i = NULL, *c = NULL;
114 struct iio_channel *channel;
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 get_device(&c->indio_dev->dev);
128 break;
129 }
130 mutex_unlock(&iio_map_list_lock);
131 if (c == NULL)
132 return ERR_PTR(-ENODEV);
133
134 channel = kmalloc(sizeof(*channel), GFP_KERNEL);
135 if (channel == NULL)
136 return ERR_PTR(-ENOMEM);
137
138 channel->indio_dev = c->indio_dev;
139
140 if (c->map->adc_channel_label)
141 channel->channel =
142 iio_chan_spec_from_name(channel->indio_dev,
143 c->map->adc_channel_label);
144
145 return channel;
146}
147EXPORT_SYMBOL_GPL(iio_st_channel_get);
148
149void iio_st_channel_release(struct iio_channel *channel)
150{
151 put_device(&channel->indio_dev->dev);
152 kfree(channel);
153}
154EXPORT_SYMBOL_GPL(iio_st_channel_release);
155
156struct iio_channel *iio_st_channel_get_all(const char *name)
157{
158 struct iio_channel *chans;
159 struct iio_map_internal *c = NULL;
160 int nummaps = 0;
161 int mapind = 0;
162 int i, ret;
163
164 if (name == NULL)
165 return ERR_PTR(-EINVAL);
166
167 mutex_lock(&iio_map_list_lock);
168 /* first count the matching maps */
169 list_for_each_entry(c, &iio_map_list, l)
170 if (name && strcmp(name, c->map->consumer_dev_name) != 0)
171 continue;
172 else
173 nummaps++;
174
175 if (nummaps == 0) {
176 ret = -ENODEV;
177 goto error_ret;
178 }
179
180 /* NULL terminated array to save passing size */
181 chans = kzalloc(sizeof(*chans)*(nummaps + 1), GFP_KERNEL);
182 if (chans == NULL) {
183 ret = -ENOMEM;
184 goto error_ret;
185 }
186
187 /* for each map fill in the chans element */
188 list_for_each_entry(c, &iio_map_list, l) {
189 if (name && strcmp(name, c->map->consumer_dev_name) != 0)
190 continue;
191 chans[mapind].indio_dev = c->indio_dev;
192 chans[mapind].channel =
193 iio_chan_spec_from_name(chans[mapind].indio_dev,
194 c->map->adc_channel_label);
195 if (chans[mapind].channel == NULL) {
196 ret = -EINVAL;
197 put_device(&chans[mapind].indio_dev->dev);
198 goto error_free_chans;
199 }
200 get_device(&chans[mapind].indio_dev->dev);
201 mapind++;
202 }
203 mutex_unlock(&iio_map_list_lock);
204 if (mapind == 0) {
205 ret = -ENODEV;
206 goto error_free_chans;
207 }
208 return chans;
209
210error_free_chans:
211 for (i = 0; i < nummaps; i++)
212 if (chans[i].indio_dev)
213 put_device(&chans[i].indio_dev->dev);
214 kfree(chans);
215error_ret:
216 mutex_unlock(&iio_map_list_lock);
217
218 return ERR_PTR(ret);
219}
220EXPORT_SYMBOL_GPL(iio_st_channel_get_all);
221
222void iio_st_channel_release_all(struct iio_channel *channels)
223{
224 struct iio_channel *chan = &channels[0];
225
226 while (chan->indio_dev) {
227 put_device(&chan->indio_dev->dev);
228 chan++;
229 }
230 kfree(channels);
231}
232EXPORT_SYMBOL_GPL(iio_st_channel_release_all);
233
234int 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);
246err_unlock:
247 mutex_unlock(&chan->indio_dev->info_exist_lock);
248
249 return ret;
250}
251EXPORT_SYMBOL_GPL(iio_st_read_channel_raw);
252
253int 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);
267err_unlock:
268 mutex_unlock(&chan->indio_dev->info_exist_lock);
269
270 return ret;
271}
272EXPORT_SYMBOL_GPL(iio_st_read_channel_scale);
273
274int 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;
287err_unlock:
288 mutex_unlock(&chan->indio_dev->info_exist_lock);
289
290 return ret;
291}
292EXPORT_SYMBOL_GPL(iio_st_get_channel_type);
diff --git a/drivers/staging/iio/machine.h b/drivers/staging/iio/machine.h
new file mode 100644
index 00000000000..0b1f19bfdc4
--- /dev/null
+++ b/drivers/staging/iio/machine.h
@@ -0,0 +1,24 @@
1/*
2 * Industrial I/O in kernel access map definitions for board files.
3 *
4 * Copyright (c) 2011 Jonathan Cameron
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
9 */
10
11/**
12 * struct iio_map - description of link between consumer and device channels
13 * @adc_channel_label: Label used to identify the channel on the provider.
14 * This is matched against the datasheet_name element
15 * of struct iio_chan_spec.
16 * @consumer_dev_name: Name to uniquely identify the consumer device.
17 * @consumer_channel: Unique name used to idenitify the channel on the
18 * consumer side.
19 */
20struct iio_map {
21 const char *adc_channel_label;
22 const char *consumer_dev_name;
23 const char *consumer_channel;
24};