xref: /openbmc/linux/drivers/iio/inkern.c (revision 7349e8a3)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2a980e046SJonathan Cameron /* The industrial I/O core in kernel channel mapping
3a980e046SJonathan Cameron  *
4a980e046SJonathan Cameron  * Copyright (c) 2011 Jonathan Cameron
5a980e046SJonathan Cameron  */
6a980e046SJonathan Cameron #include <linux/err.h>
7a980e046SJonathan Cameron #include <linux/export.h>
8a980e046SJonathan Cameron #include <linux/slab.h>
9a980e046SJonathan Cameron #include <linux/mutex.h>
1017d82b47SGuenter Roeck #include <linux/of.h>
11a980e046SJonathan Cameron 
12a980e046SJonathan Cameron #include <linux/iio/iio.h>
13a980e046SJonathan Cameron #include "iio_core.h"
14a980e046SJonathan Cameron #include <linux/iio/machine.h>
15a980e046SJonathan Cameron #include <linux/iio/driver.h>
16a980e046SJonathan Cameron #include <linux/iio/consumer.h>
17a980e046SJonathan Cameron 
18a980e046SJonathan Cameron struct iio_map_internal {
19a980e046SJonathan Cameron 	struct iio_dev *indio_dev;
20a980e046SJonathan Cameron 	struct iio_map *map;
21a980e046SJonathan Cameron 	struct list_head l;
22a980e046SJonathan Cameron };
23a980e046SJonathan Cameron 
24a980e046SJonathan Cameron static LIST_HEAD(iio_map_list);
25a980e046SJonathan Cameron static DEFINE_MUTEX(iio_map_list_lock);
26a980e046SJonathan Cameron 
27cc9fb60eSLino Sanfilippo static int iio_map_array_unregister_locked(struct iio_dev *indio_dev)
28cc9fb60eSLino Sanfilippo {
29cc9fb60eSLino Sanfilippo 	int ret = -ENODEV;
30cc9fb60eSLino Sanfilippo 	struct iio_map_internal *mapi, *next;
31cc9fb60eSLino Sanfilippo 
32cc9fb60eSLino Sanfilippo 	list_for_each_entry_safe(mapi, next, &iio_map_list, l) {
33cc9fb60eSLino Sanfilippo 		if (indio_dev == mapi->indio_dev) {
34cc9fb60eSLino Sanfilippo 			list_del(&mapi->l);
35cc9fb60eSLino Sanfilippo 			kfree(mapi);
36cc9fb60eSLino Sanfilippo 			ret = 0;
37cc9fb60eSLino Sanfilippo 		}
38cc9fb60eSLino Sanfilippo 	}
39cc9fb60eSLino Sanfilippo 	return ret;
40cc9fb60eSLino Sanfilippo }
41cc9fb60eSLino Sanfilippo 
42a980e046SJonathan Cameron int iio_map_array_register(struct iio_dev *indio_dev, struct iio_map *maps)
43a980e046SJonathan Cameron {
44a980e046SJonathan Cameron 	int i = 0, ret = 0;
45a980e046SJonathan Cameron 	struct iio_map_internal *mapi;
46a980e046SJonathan Cameron 
47a980e046SJonathan Cameron 	if (maps == NULL)
48a980e046SJonathan Cameron 		return 0;
49a980e046SJonathan Cameron 
50a980e046SJonathan Cameron 	mutex_lock(&iio_map_list_lock);
51a980e046SJonathan Cameron 	while (maps[i].consumer_dev_name != NULL) {
52a980e046SJonathan Cameron 		mapi = kzalloc(sizeof(*mapi), GFP_KERNEL);
53a980e046SJonathan Cameron 		if (mapi == NULL) {
54a980e046SJonathan Cameron 			ret = -ENOMEM;
55a980e046SJonathan Cameron 			goto error_ret;
56a980e046SJonathan Cameron 		}
57a980e046SJonathan Cameron 		mapi->map = &maps[i];
58a980e046SJonathan Cameron 		mapi->indio_dev = indio_dev;
59bc4b2a51SGaurav Gupta 		list_add_tail(&mapi->l, &iio_map_list);
60a980e046SJonathan Cameron 		i++;
61a980e046SJonathan Cameron 	}
62a980e046SJonathan Cameron error_ret:
6334fce6caSLino Sanfilippo 	if (ret)
6434fce6caSLino Sanfilippo 		iio_map_array_unregister_locked(indio_dev);
65a980e046SJonathan Cameron 	mutex_unlock(&iio_map_list_lock);
66a980e046SJonathan Cameron 
67a980e046SJonathan Cameron 	return ret;
68a980e046SJonathan Cameron }
69a980e046SJonathan Cameron EXPORT_SYMBOL_GPL(iio_map_array_register);
70a980e046SJonathan Cameron 
71a980e046SJonathan Cameron 
726cb2afd7SGuenter Roeck /*
736cb2afd7SGuenter Roeck  * Remove all map entries associated with the given iio device
74a980e046SJonathan Cameron  */
756cb2afd7SGuenter Roeck int iio_map_array_unregister(struct iio_dev *indio_dev)
76a980e046SJonathan Cameron {
77cc9fb60eSLino Sanfilippo 	int ret;
78a980e046SJonathan Cameron 
79a980e046SJonathan Cameron 	mutex_lock(&iio_map_list_lock);
80cc9fb60eSLino Sanfilippo 	ret = iio_map_array_unregister_locked(indio_dev);
81a980e046SJonathan Cameron 	mutex_unlock(&iio_map_list_lock);
82cc9fb60eSLino Sanfilippo 
83a980e046SJonathan Cameron 	return ret;
84a980e046SJonathan Cameron }
85a980e046SJonathan Cameron EXPORT_SYMBOL_GPL(iio_map_array_unregister);
86a980e046SJonathan Cameron 
87a980e046SJonathan Cameron static const struct iio_chan_spec
88314be14bSJonathan Cameron *iio_chan_spec_from_name(const struct iio_dev *indio_dev, const char *name)
89a980e046SJonathan Cameron {
90a980e046SJonathan Cameron 	int i;
91a980e046SJonathan Cameron 	const struct iio_chan_spec *chan = NULL;
92a980e046SJonathan Cameron 
93a980e046SJonathan Cameron 	for (i = 0; i < indio_dev->num_channels; i++)
94a980e046SJonathan Cameron 		if (indio_dev->channels[i].datasheet_name &&
95a980e046SJonathan Cameron 		    strcmp(name, indio_dev->channels[i].datasheet_name) == 0) {
96a980e046SJonathan Cameron 			chan = &indio_dev->channels[i];
97a980e046SJonathan Cameron 			break;
98a980e046SJonathan Cameron 		}
99a980e046SJonathan Cameron 	return chan;
100a980e046SJonathan Cameron }
101a980e046SJonathan Cameron 
10217d82b47SGuenter Roeck #ifdef CONFIG_OF
10317d82b47SGuenter Roeck 
104418e3ea1SSuzuki K Poulose static int iio_dev_node_match(struct device *dev, const void *data)
10517d82b47SGuenter Roeck {
10617d82b47SGuenter Roeck 	return dev->of_node == data && dev->type == &iio_device_type;
10717d82b47SGuenter Roeck }
10817d82b47SGuenter Roeck 
109acd82567SIvan T. Ivanov /**
110acd82567SIvan T. Ivanov  * __of_iio_simple_xlate - translate iiospec to the IIO channel index
111acd82567SIvan T. Ivanov  * @indio_dev:	pointer to the iio_dev structure
112acd82567SIvan T. Ivanov  * @iiospec:	IIO specifier as found in the device tree
113acd82567SIvan T. Ivanov  *
114acd82567SIvan T. Ivanov  * This is simple translation function, suitable for the most 1:1 mapped
115acd82567SIvan T. Ivanov  * channels in IIO chips. This function performs only one sanity check:
116acd82567SIvan T. Ivanov  * whether IIO index is less than num_channels (that is specified in the
117acd82567SIvan T. Ivanov  * iio_dev).
118acd82567SIvan T. Ivanov  */
119acd82567SIvan T. Ivanov static int __of_iio_simple_xlate(struct iio_dev *indio_dev,
120acd82567SIvan T. Ivanov 				const struct of_phandle_args *iiospec)
121acd82567SIvan T. Ivanov {
122acd82567SIvan T. Ivanov 	if (!iiospec->args_count)
123acd82567SIvan T. Ivanov 		return 0;
124acd82567SIvan T. Ivanov 
1251f202725SStefan Wahren 	if (iiospec->args[0] >= indio_dev->num_channels) {
1261f202725SStefan Wahren 		dev_err(&indio_dev->dev, "invalid channel index %u\n",
1271f202725SStefan Wahren 			iiospec->args[0]);
128acd82567SIvan T. Ivanov 		return -EINVAL;
1291f202725SStefan Wahren 	}
130acd82567SIvan T. Ivanov 
131acd82567SIvan T. Ivanov 	return iiospec->args[0];
132acd82567SIvan T. Ivanov }
133acd82567SIvan T. Ivanov 
13417d82b47SGuenter Roeck static int __of_iio_channel_get(struct iio_channel *channel,
13517d82b47SGuenter Roeck 				struct device_node *np, int index)
13617d82b47SGuenter Roeck {
13717d82b47SGuenter Roeck 	struct device *idev;
13817d82b47SGuenter Roeck 	struct iio_dev *indio_dev;
13917d82b47SGuenter Roeck 	int err;
14017d82b47SGuenter Roeck 	struct of_phandle_args iiospec;
14117d82b47SGuenter Roeck 
14217d82b47SGuenter Roeck 	err = of_parse_phandle_with_args(np, "io-channels",
14317d82b47SGuenter Roeck 					 "#io-channel-cells",
14417d82b47SGuenter Roeck 					 index, &iiospec);
14517d82b47SGuenter Roeck 	if (err)
14617d82b47SGuenter Roeck 		return err;
14717d82b47SGuenter Roeck 
14817d82b47SGuenter Roeck 	idev = bus_find_device(&iio_bus_type, NULL, iiospec.np,
14917d82b47SGuenter Roeck 			       iio_dev_node_match);
15017d82b47SGuenter Roeck 	of_node_put(iiospec.np);
15117d82b47SGuenter Roeck 	if (idev == NULL)
15217d82b47SGuenter Roeck 		return -EPROBE_DEFER;
15317d82b47SGuenter Roeck 
15417d82b47SGuenter Roeck 	indio_dev = dev_to_iio_dev(idev);
15517d82b47SGuenter Roeck 	channel->indio_dev = indio_dev;
156acd82567SIvan T. Ivanov 	if (indio_dev->info->of_xlate)
157acd82567SIvan T. Ivanov 		index = indio_dev->info->of_xlate(indio_dev, &iiospec);
158acd82567SIvan T. Ivanov 	else
159acd82567SIvan T. Ivanov 		index = __of_iio_simple_xlate(indio_dev, &iiospec);
160acd82567SIvan T. Ivanov 	if (index < 0)
16117d82b47SGuenter Roeck 		goto err_put;
16217d82b47SGuenter Roeck 	channel->channel = &indio_dev->channels[index];
16317d82b47SGuenter Roeck 
16417d82b47SGuenter Roeck 	return 0;
16517d82b47SGuenter Roeck 
16617d82b47SGuenter Roeck err_put:
16717d82b47SGuenter Roeck 	iio_device_put(indio_dev);
168acd82567SIvan T. Ivanov 	return index;
16917d82b47SGuenter Roeck }
17017d82b47SGuenter Roeck 
17117d82b47SGuenter Roeck static struct iio_channel *of_iio_channel_get(struct device_node *np, int index)
17217d82b47SGuenter Roeck {
17317d82b47SGuenter Roeck 	struct iio_channel *channel;
17417d82b47SGuenter Roeck 	int err;
17517d82b47SGuenter Roeck 
17617d82b47SGuenter Roeck 	if (index < 0)
17717d82b47SGuenter Roeck 		return ERR_PTR(-EINVAL);
17817d82b47SGuenter Roeck 
17917d82b47SGuenter Roeck 	channel = kzalloc(sizeof(*channel), GFP_KERNEL);
18017d82b47SGuenter Roeck 	if (channel == NULL)
18117d82b47SGuenter Roeck 		return ERR_PTR(-ENOMEM);
18217d82b47SGuenter Roeck 
18317d82b47SGuenter Roeck 	err = __of_iio_channel_get(channel, np, index);
18417d82b47SGuenter Roeck 	if (err)
18517d82b47SGuenter Roeck 		goto err_free_channel;
18617d82b47SGuenter Roeck 
18717d82b47SGuenter Roeck 	return channel;
18817d82b47SGuenter Roeck 
18917d82b47SGuenter Roeck err_free_channel:
19017d82b47SGuenter Roeck 	kfree(channel);
19117d82b47SGuenter Roeck 	return ERR_PTR(err);
19217d82b47SGuenter Roeck }
19317d82b47SGuenter Roeck 
1946e39b145SDmitry Baryshkov struct iio_channel *of_iio_channel_get_by_name(struct device_node *np,
19517d82b47SGuenter Roeck 					       const char *name)
19617d82b47SGuenter Roeck {
19717d82b47SGuenter Roeck 	struct iio_channel *chan = NULL;
19817d82b47SGuenter Roeck 
19917d82b47SGuenter Roeck 	/* Walk up the tree of devices looking for a matching iio channel */
20017d82b47SGuenter Roeck 	while (np) {
20117d82b47SGuenter Roeck 		int index = 0;
20217d82b47SGuenter Roeck 
20317d82b47SGuenter Roeck 		/*
20417d82b47SGuenter Roeck 		 * For named iio channels, first look up the name in the
20517d82b47SGuenter Roeck 		 * "io-channel-names" property.  If it cannot be found, the
20617d82b47SGuenter Roeck 		 * index will be an error code, and of_iio_channel_get()
20717d82b47SGuenter Roeck 		 * will fail.
20817d82b47SGuenter Roeck 		 */
20917d82b47SGuenter Roeck 		if (name)
21017d82b47SGuenter Roeck 			index = of_property_match_string(np, "io-channel-names",
21117d82b47SGuenter Roeck 							 name);
21217d82b47SGuenter Roeck 		chan = of_iio_channel_get(np, index);
213872687f6SJohannes Pointner 		if (!IS_ERR(chan) || PTR_ERR(chan) == -EPROBE_DEFER)
21417d82b47SGuenter Roeck 			break;
21517d82b47SGuenter Roeck 		else if (name && index >= 0) {
2163921db46SRob Herring 			pr_err("ERROR: could not get IIO channel %pOF:%s(%i)\n",
2173921db46SRob Herring 				np, name ? name : "", index);
218a2c12493SAdam Thomson 			return NULL;
21917d82b47SGuenter Roeck 		}
22017d82b47SGuenter Roeck 
22117d82b47SGuenter Roeck 		/*
22217d82b47SGuenter Roeck 		 * No matching IIO channel found on this node.
22317d82b47SGuenter Roeck 		 * If the parent node has a "io-channel-ranges" property,
22417d82b47SGuenter Roeck 		 * then we can try one of its channels.
22517d82b47SGuenter Roeck 		 */
22617d82b47SGuenter Roeck 		np = np->parent;
22717d82b47SGuenter Roeck 		if (np && !of_get_property(np, "io-channel-ranges", NULL))
228a2c12493SAdam Thomson 			return NULL;
22917d82b47SGuenter Roeck 	}
230a2c12493SAdam Thomson 
23117d82b47SGuenter Roeck 	return chan;
23217d82b47SGuenter Roeck }
2336e39b145SDmitry Baryshkov EXPORT_SYMBOL_GPL(of_iio_channel_get_by_name);
23417d82b47SGuenter Roeck 
23517d82b47SGuenter Roeck static struct iio_channel *of_iio_channel_get_all(struct device *dev)
23617d82b47SGuenter Roeck {
23717d82b47SGuenter Roeck 	struct iio_channel *chans;
23817d82b47SGuenter Roeck 	int i, mapind, nummaps = 0;
23917d82b47SGuenter Roeck 	int ret;
24017d82b47SGuenter Roeck 
24117d82b47SGuenter Roeck 	do {
24217d82b47SGuenter Roeck 		ret = of_parse_phandle_with_args(dev->of_node,
24317d82b47SGuenter Roeck 						 "io-channels",
24417d82b47SGuenter Roeck 						 "#io-channel-cells",
24517d82b47SGuenter Roeck 						 nummaps, NULL);
24617d82b47SGuenter Roeck 		if (ret < 0)
24717d82b47SGuenter Roeck 			break;
24817d82b47SGuenter Roeck 	} while (++nummaps);
24917d82b47SGuenter Roeck 
25017d82b47SGuenter Roeck 	if (nummaps == 0)	/* no error, return NULL to search map table */
25117d82b47SGuenter Roeck 		return NULL;
25217d82b47SGuenter Roeck 
25317d82b47SGuenter Roeck 	/* NULL terminated array to save passing size */
25417d82b47SGuenter Roeck 	chans = kcalloc(nummaps + 1, sizeof(*chans), GFP_KERNEL);
25517d82b47SGuenter Roeck 	if (chans == NULL)
25617d82b47SGuenter Roeck 		return ERR_PTR(-ENOMEM);
25717d82b47SGuenter Roeck 
25817d82b47SGuenter Roeck 	/* Search for OF matches */
25917d82b47SGuenter Roeck 	for (mapind = 0; mapind < nummaps; mapind++) {
26017d82b47SGuenter Roeck 		ret = __of_iio_channel_get(&chans[mapind], dev->of_node,
26117d82b47SGuenter Roeck 					   mapind);
26217d82b47SGuenter Roeck 		if (ret)
26317d82b47SGuenter Roeck 			goto error_free_chans;
26417d82b47SGuenter Roeck 	}
26517d82b47SGuenter Roeck 	return chans;
26617d82b47SGuenter Roeck 
26717d82b47SGuenter Roeck error_free_chans:
26817d82b47SGuenter Roeck 	for (i = 0; i < mapind; i++)
26917d82b47SGuenter Roeck 		iio_device_put(chans[i].indio_dev);
27017d82b47SGuenter Roeck 	kfree(chans);
27117d82b47SGuenter Roeck 	return ERR_PTR(ret);
27217d82b47SGuenter Roeck }
27317d82b47SGuenter Roeck 
27417d82b47SGuenter Roeck #else /* CONFIG_OF */
27517d82b47SGuenter Roeck 
27617d82b47SGuenter Roeck static inline struct iio_channel *of_iio_channel_get_all(struct device *dev)
27717d82b47SGuenter Roeck {
27817d82b47SGuenter Roeck 	return NULL;
27917d82b47SGuenter Roeck }
28017d82b47SGuenter Roeck 
28117d82b47SGuenter Roeck #endif /* CONFIG_OF */
282a980e046SJonathan Cameron 
2835aa57f0aSGuenter Roeck static struct iio_channel *iio_channel_get_sys(const char *name,
2845aa57f0aSGuenter Roeck 					       const char *channel_name)
285a980e046SJonathan Cameron {
286a980e046SJonathan Cameron 	struct iio_map_internal *c_i = NULL, *c = NULL;
287a980e046SJonathan Cameron 	struct iio_channel *channel;
2883183bac1SKim, Milo 	int err;
289a980e046SJonathan Cameron 
290a980e046SJonathan Cameron 	if (name == NULL && channel_name == NULL)
291a980e046SJonathan Cameron 		return ERR_PTR(-ENODEV);
292a980e046SJonathan Cameron 
293a980e046SJonathan Cameron 	/* first find matching entry the channel map */
294a980e046SJonathan Cameron 	mutex_lock(&iio_map_list_lock);
295a980e046SJonathan Cameron 	list_for_each_entry(c_i, &iio_map_list, l) {
296a980e046SJonathan Cameron 		if ((name && strcmp(name, c_i->map->consumer_dev_name) != 0) ||
297a980e046SJonathan Cameron 		    (channel_name &&
298a980e046SJonathan Cameron 		     strcmp(channel_name, c_i->map->consumer_channel) != 0))
299a980e046SJonathan Cameron 			continue;
300a980e046SJonathan Cameron 		c = c_i;
3011875ffd2SLars-Peter Clausen 		iio_device_get(c->indio_dev);
302a980e046SJonathan Cameron 		break;
303a980e046SJonathan Cameron 	}
304a980e046SJonathan Cameron 	mutex_unlock(&iio_map_list_lock);
305a980e046SJonathan Cameron 	if (c == NULL)
306a980e046SJonathan Cameron 		return ERR_PTR(-ENODEV);
307a980e046SJonathan Cameron 
3082cc412b5SKim, Milo 	channel = kzalloc(sizeof(*channel), GFP_KERNEL);
3093183bac1SKim, Milo 	if (channel == NULL) {
3103183bac1SKim, Milo 		err = -ENOMEM;
311801c4b5cSKim, Milo 		goto error_no_mem;
3123183bac1SKim, Milo 	}
313a980e046SJonathan Cameron 
314a980e046SJonathan Cameron 	channel->indio_dev = c->indio_dev;
315a980e046SJonathan Cameron 
316b2b79ffaSKim, Milo 	if (c->map->adc_channel_label) {
317a980e046SJonathan Cameron 		channel->channel =
318a980e046SJonathan Cameron 			iio_chan_spec_from_name(channel->indio_dev,
319a980e046SJonathan Cameron 						c->map->adc_channel_label);
320a980e046SJonathan Cameron 
3213183bac1SKim, Milo 		if (channel->channel == NULL) {
3223183bac1SKim, Milo 			err = -EINVAL;
323b2b79ffaSKim, Milo 			goto error_no_chan;
324b2b79ffaSKim, Milo 		}
3253183bac1SKim, Milo 	}
326b2b79ffaSKim, Milo 
327a980e046SJonathan Cameron 	return channel;
328b2b79ffaSKim, Milo 
329b2b79ffaSKim, Milo error_no_chan:
330b2b79ffaSKim, Milo 	kfree(channel);
331801c4b5cSKim, Milo error_no_mem:
332801c4b5cSKim, Milo 	iio_device_put(c->indio_dev);
3333183bac1SKim, Milo 	return ERR_PTR(err);
334a980e046SJonathan Cameron }
3355aa57f0aSGuenter Roeck 
3365aa57f0aSGuenter Roeck struct iio_channel *iio_channel_get(struct device *dev,
3375aa57f0aSGuenter Roeck 				    const char *channel_name)
3385aa57f0aSGuenter Roeck {
3395aa57f0aSGuenter Roeck 	const char *name = dev ? dev_name(dev) : NULL;
34017d82b47SGuenter Roeck 	struct iio_channel *channel;
3415aa57f0aSGuenter Roeck 
34217d82b47SGuenter Roeck 	if (dev) {
34317d82b47SGuenter Roeck 		channel = of_iio_channel_get_by_name(dev->of_node,
34417d82b47SGuenter Roeck 						     channel_name);
34517d82b47SGuenter Roeck 		if (channel != NULL)
34617d82b47SGuenter Roeck 			return channel;
34717d82b47SGuenter Roeck 	}
348a2c12493SAdam Thomson 
3495aa57f0aSGuenter Roeck 	return iio_channel_get_sys(name, channel_name);
3505aa57f0aSGuenter Roeck }
351314be14bSJonathan Cameron EXPORT_SYMBOL_GPL(iio_channel_get);
352a980e046SJonathan Cameron 
353314be14bSJonathan Cameron void iio_channel_release(struct iio_channel *channel)
354a980e046SJonathan Cameron {
355d81dac3cSDan Carpenter 	if (!channel)
356d81dac3cSDan Carpenter 		return;
3571875ffd2SLars-Peter Clausen 	iio_device_put(channel->indio_dev);
358a980e046SJonathan Cameron 	kfree(channel);
359a980e046SJonathan Cameron }
360314be14bSJonathan Cameron EXPORT_SYMBOL_GPL(iio_channel_release);
361a980e046SJonathan Cameron 
362*7349e8a3SYicong Yang static void devm_iio_channel_free(void *iio_channel)
3638bf872d8SLaxman Dewangan {
364*7349e8a3SYicong Yang 	iio_channel_release(iio_channel);
3658bf872d8SLaxman Dewangan }
3668bf872d8SLaxman Dewangan 
3678bf872d8SLaxman Dewangan struct iio_channel *devm_iio_channel_get(struct device *dev,
3688bf872d8SLaxman Dewangan 					 const char *channel_name)
3698bf872d8SLaxman Dewangan {
370*7349e8a3SYicong Yang 	struct iio_channel *channel;
371*7349e8a3SYicong Yang 	int ret;
3728bf872d8SLaxman Dewangan 
3738bf872d8SLaxman Dewangan 	channel = iio_channel_get(dev, channel_name);
374*7349e8a3SYicong Yang 	if (IS_ERR(channel))
3758bf872d8SLaxman Dewangan 		return channel;
3768bf872d8SLaxman Dewangan 
377*7349e8a3SYicong Yang 	ret = devm_add_action_or_reset(dev, devm_iio_channel_free, channel);
378*7349e8a3SYicong Yang 	if (ret)
379*7349e8a3SYicong Yang 		return ERR_PTR(ret);
3808bf872d8SLaxman Dewangan 
3818bf872d8SLaxman Dewangan 	return channel;
3828bf872d8SLaxman Dewangan }
3838bf872d8SLaxman Dewangan EXPORT_SYMBOL_GPL(devm_iio_channel_get);
3848bf872d8SLaxman Dewangan 
3856e39b145SDmitry Baryshkov struct iio_channel *devm_of_iio_channel_get_by_name(struct device *dev,
3866e39b145SDmitry Baryshkov 						    struct device_node *np,
3876e39b145SDmitry Baryshkov 						    const char *channel_name)
3886e39b145SDmitry Baryshkov {
389*7349e8a3SYicong Yang 	struct iio_channel *channel;
390*7349e8a3SYicong Yang 	int ret;
3916e39b145SDmitry Baryshkov 
3926e39b145SDmitry Baryshkov 	channel = of_iio_channel_get_by_name(np, channel_name);
393*7349e8a3SYicong Yang 	if (IS_ERR(channel))
3946e39b145SDmitry Baryshkov 		return channel;
3956e39b145SDmitry Baryshkov 
396*7349e8a3SYicong Yang 	ret = devm_add_action_or_reset(dev, devm_iio_channel_free, channel);
397*7349e8a3SYicong Yang 	if (ret)
398*7349e8a3SYicong Yang 		return ERR_PTR(ret);
3996e39b145SDmitry Baryshkov 
4006e39b145SDmitry Baryshkov 	return channel;
4016e39b145SDmitry Baryshkov }
4026e39b145SDmitry Baryshkov EXPORT_SYMBOL_GPL(devm_of_iio_channel_get_by_name);
4036e39b145SDmitry Baryshkov 
404ca7d98dbSGuenter Roeck struct iio_channel *iio_channel_get_all(struct device *dev)
405a980e046SJonathan Cameron {
406ca7d98dbSGuenter Roeck 	const char *name;
407a980e046SJonathan Cameron 	struct iio_channel *chans;
408a980e046SJonathan Cameron 	struct iio_map_internal *c = NULL;
409a980e046SJonathan Cameron 	int nummaps = 0;
410a980e046SJonathan Cameron 	int mapind = 0;
411a980e046SJonathan Cameron 	int i, ret;
412a980e046SJonathan Cameron 
413ca7d98dbSGuenter Roeck 	if (dev == NULL)
414a980e046SJonathan Cameron 		return ERR_PTR(-EINVAL);
41517d82b47SGuenter Roeck 
41617d82b47SGuenter Roeck 	chans = of_iio_channel_get_all(dev);
41717d82b47SGuenter Roeck 	if (chans)
41817d82b47SGuenter Roeck 		return chans;
41917d82b47SGuenter Roeck 
420ca7d98dbSGuenter Roeck 	name = dev_name(dev);
421a980e046SJonathan Cameron 
422a980e046SJonathan Cameron 	mutex_lock(&iio_map_list_lock);
423a980e046SJonathan Cameron 	/* first count the matching maps */
424a980e046SJonathan Cameron 	list_for_each_entry(c, &iio_map_list, l)
425a980e046SJonathan Cameron 		if (name && strcmp(name, c->map->consumer_dev_name) != 0)
426a980e046SJonathan Cameron 			continue;
427a980e046SJonathan Cameron 		else
428a980e046SJonathan Cameron 			nummaps++;
429a980e046SJonathan Cameron 
430a980e046SJonathan Cameron 	if (nummaps == 0) {
431a980e046SJonathan Cameron 		ret = -ENODEV;
432a980e046SJonathan Cameron 		goto error_ret;
433a980e046SJonathan Cameron 	}
434a980e046SJonathan Cameron 
435a980e046SJonathan Cameron 	/* NULL terminated array to save passing size */
4366396bb22SKees Cook 	chans = kcalloc(nummaps + 1, sizeof(*chans), GFP_KERNEL);
437a980e046SJonathan Cameron 	if (chans == NULL) {
438a980e046SJonathan Cameron 		ret = -ENOMEM;
439a980e046SJonathan Cameron 		goto error_ret;
440a980e046SJonathan Cameron 	}
441a980e046SJonathan Cameron 
442a980e046SJonathan Cameron 	/* for each map fill in the chans element */
443a980e046SJonathan Cameron 	list_for_each_entry(c, &iio_map_list, l) {
444a980e046SJonathan Cameron 		if (name && strcmp(name, c->map->consumer_dev_name) != 0)
445a980e046SJonathan Cameron 			continue;
446a980e046SJonathan Cameron 		chans[mapind].indio_dev = c->indio_dev;
4470464415dSJonathan Cameron 		chans[mapind].data = c->map->consumer_data;
448a980e046SJonathan Cameron 		chans[mapind].channel =
449a980e046SJonathan Cameron 			iio_chan_spec_from_name(chans[mapind].indio_dev,
450a980e046SJonathan Cameron 						c->map->adc_channel_label);
451a980e046SJonathan Cameron 		if (chans[mapind].channel == NULL) {
452a980e046SJonathan Cameron 			ret = -EINVAL;
453a980e046SJonathan Cameron 			goto error_free_chans;
454a980e046SJonathan Cameron 		}
4551875ffd2SLars-Peter Clausen 		iio_device_get(chans[mapind].indio_dev);
456a980e046SJonathan Cameron 		mapind++;
457a980e046SJonathan Cameron 	}
458a980e046SJonathan Cameron 	if (mapind == 0) {
459a980e046SJonathan Cameron 		ret = -ENODEV;
460a980e046SJonathan Cameron 		goto error_free_chans;
461a980e046SJonathan Cameron 	}
462e59b9afeSDan Carpenter 	mutex_unlock(&iio_map_list_lock);
463e59b9afeSDan Carpenter 
464a980e046SJonathan Cameron 	return chans;
465a980e046SJonathan Cameron 
466a980e046SJonathan Cameron error_free_chans:
467a980e046SJonathan Cameron 	for (i = 0; i < nummaps; i++)
4681875ffd2SLars-Peter Clausen 		iio_device_put(chans[i].indio_dev);
469a980e046SJonathan Cameron 	kfree(chans);
470a980e046SJonathan Cameron error_ret:
471a980e046SJonathan Cameron 	mutex_unlock(&iio_map_list_lock);
472a980e046SJonathan Cameron 
473a980e046SJonathan Cameron 	return ERR_PTR(ret);
474a980e046SJonathan Cameron }
475314be14bSJonathan Cameron EXPORT_SYMBOL_GPL(iio_channel_get_all);
476a980e046SJonathan Cameron 
477314be14bSJonathan Cameron void iio_channel_release_all(struct iio_channel *channels)
478a980e046SJonathan Cameron {
479a980e046SJonathan Cameron 	struct iio_channel *chan = &channels[0];
480a980e046SJonathan Cameron 
481a980e046SJonathan Cameron 	while (chan->indio_dev) {
4821875ffd2SLars-Peter Clausen 		iio_device_put(chan->indio_dev);
483a980e046SJonathan Cameron 		chan++;
484a980e046SJonathan Cameron 	}
485a980e046SJonathan Cameron 	kfree(channels);
486a980e046SJonathan Cameron }
487314be14bSJonathan Cameron EXPORT_SYMBOL_GPL(iio_channel_release_all);
488a980e046SJonathan Cameron 
489*7349e8a3SYicong Yang static void devm_iio_channel_free_all(void *iio_channels)
490efc2c013SLaxman Dewangan {
491*7349e8a3SYicong Yang 	iio_channel_release_all(iio_channels);
492efc2c013SLaxman Dewangan }
493efc2c013SLaxman Dewangan 
494efc2c013SLaxman Dewangan struct iio_channel *devm_iio_channel_get_all(struct device *dev)
495efc2c013SLaxman Dewangan {
496*7349e8a3SYicong Yang 	struct iio_channel *channels;
497*7349e8a3SYicong Yang 	int ret;
498efc2c013SLaxman Dewangan 
499efc2c013SLaxman Dewangan 	channels = iio_channel_get_all(dev);
500*7349e8a3SYicong Yang 	if (IS_ERR(channels))
501efc2c013SLaxman Dewangan 		return channels;
502efc2c013SLaxman Dewangan 
503*7349e8a3SYicong Yang 	ret = devm_add_action_or_reset(dev, devm_iio_channel_free_all,
504*7349e8a3SYicong Yang 				       channels);
505*7349e8a3SYicong Yang 	if (ret)
506*7349e8a3SYicong Yang 		return ERR_PTR(ret);
507efc2c013SLaxman Dewangan 
508efc2c013SLaxman Dewangan 	return channels;
509efc2c013SLaxman Dewangan }
510efc2c013SLaxman Dewangan EXPORT_SYMBOL_GPL(devm_iio_channel_get_all);
511efc2c013SLaxman Dewangan 
51248e44ce0SLars-Peter Clausen static int iio_channel_read(struct iio_channel *chan, int *val, int *val2,
51348e44ce0SLars-Peter Clausen 	enum iio_chan_info_enum info)
51448e44ce0SLars-Peter Clausen {
51548e44ce0SLars-Peter Clausen 	int unused;
5169fbfb4b3SSrinivas Pandruvada 	int vals[INDIO_MAX_RAW_ELEMENTS];
5179fbfb4b3SSrinivas Pandruvada 	int ret;
5189fbfb4b3SSrinivas Pandruvada 	int val_len = 2;
51948e44ce0SLars-Peter Clausen 
52048e44ce0SLars-Peter Clausen 	if (val2 == NULL)
52148e44ce0SLars-Peter Clausen 		val2 = &unused;
52248e44ce0SLars-Peter Clausen 
52365de7654SFabien Proriol 	if (!iio_channel_has_info(chan->channel, info))
52465de7654SFabien Proriol 		return -EINVAL;
52565de7654SFabien Proriol 
5269fbfb4b3SSrinivas Pandruvada 	if (chan->indio_dev->info->read_raw_multi) {
5279fbfb4b3SSrinivas Pandruvada 		ret = chan->indio_dev->info->read_raw_multi(chan->indio_dev,
5289fbfb4b3SSrinivas Pandruvada 					chan->channel, INDIO_MAX_RAW_ELEMENTS,
5299fbfb4b3SSrinivas Pandruvada 					vals, &val_len, info);
5309fbfb4b3SSrinivas Pandruvada 		*val = vals[0];
5319fbfb4b3SSrinivas Pandruvada 		*val2 = vals[1];
5329fbfb4b3SSrinivas Pandruvada 	} else
5339fbfb4b3SSrinivas Pandruvada 		ret = chan->indio_dev->info->read_raw(chan->indio_dev,
5349fbfb4b3SSrinivas Pandruvada 					chan->channel, val, val2, info);
5359fbfb4b3SSrinivas Pandruvada 
5369fbfb4b3SSrinivas Pandruvada 	return ret;
53748e44ce0SLars-Peter Clausen }
53848e44ce0SLars-Peter Clausen 
539314be14bSJonathan Cameron int iio_read_channel_raw(struct iio_channel *chan, int *val)
540a980e046SJonathan Cameron {
54148e44ce0SLars-Peter Clausen 	int ret;
542a980e046SJonathan Cameron 
543a980e046SJonathan Cameron 	mutex_lock(&chan->indio_dev->info_exist_lock);
544a980e046SJonathan Cameron 	if (chan->indio_dev->info == NULL) {
545a980e046SJonathan Cameron 		ret = -ENODEV;
546a980e046SJonathan Cameron 		goto err_unlock;
547a980e046SJonathan Cameron 	}
548a980e046SJonathan Cameron 
54948e44ce0SLars-Peter Clausen 	ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW);
550a980e046SJonathan Cameron err_unlock:
551a980e046SJonathan Cameron 	mutex_unlock(&chan->indio_dev->info_exist_lock);
552a980e046SJonathan Cameron 
553a980e046SJonathan Cameron 	return ret;
554a980e046SJonathan Cameron }
555314be14bSJonathan Cameron EXPORT_SYMBOL_GPL(iio_read_channel_raw);
556a980e046SJonathan Cameron 
557476d4af2SSebastian Reichel int iio_read_channel_average_raw(struct iio_channel *chan, int *val)
558476d4af2SSebastian Reichel {
559476d4af2SSebastian Reichel 	int ret;
560476d4af2SSebastian Reichel 
561476d4af2SSebastian Reichel 	mutex_lock(&chan->indio_dev->info_exist_lock);
562476d4af2SSebastian Reichel 	if (chan->indio_dev->info == NULL) {
563476d4af2SSebastian Reichel 		ret = -ENODEV;
564476d4af2SSebastian Reichel 		goto err_unlock;
565476d4af2SSebastian Reichel 	}
566476d4af2SSebastian Reichel 
567476d4af2SSebastian Reichel 	ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_AVERAGE_RAW);
568476d4af2SSebastian Reichel err_unlock:
569476d4af2SSebastian Reichel 	mutex_unlock(&chan->indio_dev->info_exist_lock);
570476d4af2SSebastian Reichel 
571476d4af2SSebastian Reichel 	return ret;
572476d4af2SSebastian Reichel }
573476d4af2SSebastian Reichel EXPORT_SYMBOL_GPL(iio_read_channel_average_raw);
574476d4af2SSebastian Reichel 
57548e44ce0SLars-Peter Clausen static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan,
57648e44ce0SLars-Peter Clausen 	int raw, int *processed, unsigned int scale)
57748e44ce0SLars-Peter Clausen {
57848e44ce0SLars-Peter Clausen 	int scale_type, scale_val, scale_val2, offset;
57948e44ce0SLars-Peter Clausen 	s64 raw64 = raw;
58048e44ce0SLars-Peter Clausen 	int ret;
58148e44ce0SLars-Peter Clausen 
5826c5d4c96SMichael Hennerich 	ret = iio_channel_read(chan, &offset, NULL, IIO_CHAN_INFO_OFFSET);
583f91d1b63SAlexandre Belloni 	if (ret >= 0)
58448e44ce0SLars-Peter Clausen 		raw64 += offset;
58548e44ce0SLars-Peter Clausen 
58648e44ce0SLars-Peter Clausen 	scale_type = iio_channel_read(chan, &scale_val, &scale_val2,
58748e44ce0SLars-Peter Clausen 					IIO_CHAN_INFO_SCALE);
588adc8ec5fSLinus Walleij 	if (scale_type < 0) {
589adc8ec5fSLinus Walleij 		/*
590adc8ec5fSLinus Walleij 		 * Just pass raw values as processed if no scaling is
591adc8ec5fSLinus Walleij 		 * available.
592adc8ec5fSLinus Walleij 		 */
593adc8ec5fSLinus Walleij 		*processed = raw;
594adc8ec5fSLinus Walleij 		return 0;
595adc8ec5fSLinus Walleij 	}
59648e44ce0SLars-Peter Clausen 
59748e44ce0SLars-Peter Clausen 	switch (scale_type) {
59848e44ce0SLars-Peter Clausen 	case IIO_VAL_INT:
59948e44ce0SLars-Peter Clausen 		*processed = raw64 * scale_val;
60048e44ce0SLars-Peter Clausen 		break;
60148e44ce0SLars-Peter Clausen 	case IIO_VAL_INT_PLUS_MICRO:
60248e44ce0SLars-Peter Clausen 		if (scale_val2 < 0)
60348e44ce0SLars-Peter Clausen 			*processed = -raw64 * scale_val;
60448e44ce0SLars-Peter Clausen 		else
60548e44ce0SLars-Peter Clausen 			*processed = raw64 * scale_val;
60648e44ce0SLars-Peter Clausen 		*processed += div_s64(raw64 * (s64)scale_val2 * scale,
60748e44ce0SLars-Peter Clausen 				      1000000LL);
60848e44ce0SLars-Peter Clausen 		break;
60948e44ce0SLars-Peter Clausen 	case IIO_VAL_INT_PLUS_NANO:
61048e44ce0SLars-Peter Clausen 		if (scale_val2 < 0)
61148e44ce0SLars-Peter Clausen 			*processed = -raw64 * scale_val;
61248e44ce0SLars-Peter Clausen 		else
61348e44ce0SLars-Peter Clausen 			*processed = raw64 * scale_val;
61448e44ce0SLars-Peter Clausen 		*processed += div_s64(raw64 * (s64)scale_val2 * scale,
61548e44ce0SLars-Peter Clausen 				      1000000000LL);
61648e44ce0SLars-Peter Clausen 		break;
61748e44ce0SLars-Peter Clausen 	case IIO_VAL_FRACTIONAL:
61848e44ce0SLars-Peter Clausen 		*processed = div_s64(raw64 * (s64)scale_val * scale,
61948e44ce0SLars-Peter Clausen 				     scale_val2);
62048e44ce0SLars-Peter Clausen 		break;
621103d9fb9SLars-Peter Clausen 	case IIO_VAL_FRACTIONAL_LOG2:
622103d9fb9SLars-Peter Clausen 		*processed = (raw64 * (s64)scale_val * scale) >> scale_val2;
623103d9fb9SLars-Peter Clausen 		break;
62448e44ce0SLars-Peter Clausen 	default:
62548e44ce0SLars-Peter Clausen 		return -EINVAL;
62648e44ce0SLars-Peter Clausen 	}
62748e44ce0SLars-Peter Clausen 
62848e44ce0SLars-Peter Clausen 	return 0;
62948e44ce0SLars-Peter Clausen }
63048e44ce0SLars-Peter Clausen 
63148e44ce0SLars-Peter Clausen int iio_convert_raw_to_processed(struct iio_channel *chan, int raw,
63248e44ce0SLars-Peter Clausen 	int *processed, unsigned int scale)
63348e44ce0SLars-Peter Clausen {
63448e44ce0SLars-Peter Clausen 	int ret;
63548e44ce0SLars-Peter Clausen 
63648e44ce0SLars-Peter Clausen 	mutex_lock(&chan->indio_dev->info_exist_lock);
63748e44ce0SLars-Peter Clausen 	if (chan->indio_dev->info == NULL) {
63848e44ce0SLars-Peter Clausen 		ret = -ENODEV;
63948e44ce0SLars-Peter Clausen 		goto err_unlock;
64048e44ce0SLars-Peter Clausen 	}
64148e44ce0SLars-Peter Clausen 
64248e44ce0SLars-Peter Clausen 	ret = iio_convert_raw_to_processed_unlocked(chan, raw, processed,
64348e44ce0SLars-Peter Clausen 							scale);
64448e44ce0SLars-Peter Clausen err_unlock:
64548e44ce0SLars-Peter Clausen 	mutex_unlock(&chan->indio_dev->info_exist_lock);
64648e44ce0SLars-Peter Clausen 
64748e44ce0SLars-Peter Clausen 	return ret;
64848e44ce0SLars-Peter Clausen }
64948e44ce0SLars-Peter Clausen EXPORT_SYMBOL_GPL(iio_convert_raw_to_processed);
65048e44ce0SLars-Peter Clausen 
65134739a21SArnaud Pouliquen int iio_read_channel_attribute(struct iio_channel *chan, int *val, int *val2,
6520023e67dSMatt Ranostay 			       enum iio_chan_info_enum attribute)
6530023e67dSMatt Ranostay {
6540023e67dSMatt Ranostay 	int ret;
6550023e67dSMatt Ranostay 
6560023e67dSMatt Ranostay 	mutex_lock(&chan->indio_dev->info_exist_lock);
6570023e67dSMatt Ranostay 	if (chan->indio_dev->info == NULL) {
6580023e67dSMatt Ranostay 		ret = -ENODEV;
6590023e67dSMatt Ranostay 		goto err_unlock;
6600023e67dSMatt Ranostay 	}
6610023e67dSMatt Ranostay 
6620023e67dSMatt Ranostay 	ret = iio_channel_read(chan, val, val2, attribute);
6630023e67dSMatt Ranostay err_unlock:
6640023e67dSMatt Ranostay 	mutex_unlock(&chan->indio_dev->info_exist_lock);
6650023e67dSMatt Ranostay 
6660023e67dSMatt Ranostay 	return ret;
6670023e67dSMatt Ranostay }
66834739a21SArnaud Pouliquen EXPORT_SYMBOL_GPL(iio_read_channel_attribute);
6690023e67dSMatt Ranostay 
6700023e67dSMatt Ranostay int iio_read_channel_offset(struct iio_channel *chan, int *val, int *val2)
6710023e67dSMatt Ranostay {
6720023e67dSMatt Ranostay 	return iio_read_channel_attribute(chan, val, val2, IIO_CHAN_INFO_OFFSET);
6730023e67dSMatt Ranostay }
6740023e67dSMatt Ranostay EXPORT_SYMBOL_GPL(iio_read_channel_offset);
6750023e67dSMatt Ranostay 
676635ef601SLinus Walleij int iio_read_channel_processed_scale(struct iio_channel *chan, int *val,
677635ef601SLinus Walleij 				     unsigned int scale)
67848e44ce0SLars-Peter Clausen {
67948e44ce0SLars-Peter Clausen 	int ret;
68048e44ce0SLars-Peter Clausen 
68148e44ce0SLars-Peter Clausen 	mutex_lock(&chan->indio_dev->info_exist_lock);
68248e44ce0SLars-Peter Clausen 	if (chan->indio_dev->info == NULL) {
68348e44ce0SLars-Peter Clausen 		ret = -ENODEV;
68448e44ce0SLars-Peter Clausen 		goto err_unlock;
68548e44ce0SLars-Peter Clausen 	}
68648e44ce0SLars-Peter Clausen 
68748e44ce0SLars-Peter Clausen 	if (iio_channel_has_info(chan->channel, IIO_CHAN_INFO_PROCESSED)) {
68848e44ce0SLars-Peter Clausen 		ret = iio_channel_read(chan, val, NULL,
68948e44ce0SLars-Peter Clausen 				       IIO_CHAN_INFO_PROCESSED);
690b3b64e2cSLinus Walleij 		if (ret < 0)
691635ef601SLinus Walleij 			goto err_unlock;
692635ef601SLinus Walleij 		*val *= scale;
69348e44ce0SLars-Peter Clausen 	} else {
69448e44ce0SLars-Peter Clausen 		ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW);
69548e44ce0SLars-Peter Clausen 		if (ret < 0)
69648e44ce0SLars-Peter Clausen 			goto err_unlock;
697635ef601SLinus Walleij 		ret = iio_convert_raw_to_processed_unlocked(chan, *val, val,
698635ef601SLinus Walleij 							    scale);
69948e44ce0SLars-Peter Clausen 	}
70048e44ce0SLars-Peter Clausen 
70148e44ce0SLars-Peter Clausen err_unlock:
70248e44ce0SLars-Peter Clausen 	mutex_unlock(&chan->indio_dev->info_exist_lock);
70348e44ce0SLars-Peter Clausen 
70448e44ce0SLars-Peter Clausen 	return ret;
70548e44ce0SLars-Peter Clausen }
706635ef601SLinus Walleij EXPORT_SYMBOL_GPL(iio_read_channel_processed_scale);
707635ef601SLinus Walleij 
708635ef601SLinus Walleij int iio_read_channel_processed(struct iio_channel *chan, int *val)
709635ef601SLinus Walleij {
710635ef601SLinus Walleij 	/* This is just a special case with scale factor 1 */
711635ef601SLinus Walleij 	return iio_read_channel_processed_scale(chan, val, 1);
712635ef601SLinus Walleij }
71348e44ce0SLars-Peter Clausen EXPORT_SYMBOL_GPL(iio_read_channel_processed);
71448e44ce0SLars-Peter Clausen 
715314be14bSJonathan Cameron int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2)
716a980e046SJonathan Cameron {
7170023e67dSMatt Ranostay 	return iio_read_channel_attribute(chan, val, val2, IIO_CHAN_INFO_SCALE);
718a980e046SJonathan Cameron }
719314be14bSJonathan Cameron EXPORT_SYMBOL_GPL(iio_read_channel_scale);
720a980e046SJonathan Cameron 
72100c5f80cSPeter Rosin static int iio_channel_read_avail(struct iio_channel *chan,
72200c5f80cSPeter Rosin 				  const int **vals, int *type, int *length,
72300c5f80cSPeter Rosin 				  enum iio_chan_info_enum info)
72400c5f80cSPeter Rosin {
72500c5f80cSPeter Rosin 	if (!iio_channel_has_available(chan->channel, info))
72600c5f80cSPeter Rosin 		return -EINVAL;
72700c5f80cSPeter Rosin 
72800c5f80cSPeter Rosin 	return chan->indio_dev->info->read_avail(chan->indio_dev, chan->channel,
72900c5f80cSPeter Rosin 						 vals, type, length, info);
73000c5f80cSPeter Rosin }
73100c5f80cSPeter Rosin 
7329f421096SArtur Rojek int iio_read_avail_channel_attribute(struct iio_channel *chan,
7339f421096SArtur Rojek 				     const int **vals, int *type, int *length,
7349f421096SArtur Rojek 				     enum iio_chan_info_enum attribute)
7359f421096SArtur Rojek {
7369f421096SArtur Rojek 	int ret;
7379f421096SArtur Rojek 
7389f421096SArtur Rojek 	mutex_lock(&chan->indio_dev->info_exist_lock);
7399f421096SArtur Rojek 	if (!chan->indio_dev->info) {
7409f421096SArtur Rojek 		ret = -ENODEV;
7419f421096SArtur Rojek 		goto err_unlock;
7429f421096SArtur Rojek 	}
7439f421096SArtur Rojek 
7449f421096SArtur Rojek 	ret = iio_channel_read_avail(chan, vals, type, length, attribute);
7459f421096SArtur Rojek err_unlock:
7469f421096SArtur Rojek 	mutex_unlock(&chan->indio_dev->info_exist_lock);
7479f421096SArtur Rojek 
7489f421096SArtur Rojek 	return ret;
7499f421096SArtur Rojek }
7509f421096SArtur Rojek EXPORT_SYMBOL_GPL(iio_read_avail_channel_attribute);
7519f421096SArtur Rojek 
75200c5f80cSPeter Rosin int iio_read_avail_channel_raw(struct iio_channel *chan,
75300c5f80cSPeter Rosin 			       const int **vals, int *length)
75400c5f80cSPeter Rosin {
75500c5f80cSPeter Rosin 	int ret;
75600c5f80cSPeter Rosin 	int type;
75700c5f80cSPeter Rosin 
75889388ca4SArtur Rojek 	ret = iio_read_avail_channel_attribute(chan, vals, &type, length,
75989388ca4SArtur Rojek 					 IIO_CHAN_INFO_RAW);
76000c5f80cSPeter Rosin 
761c773f700SPeter Rosin 	if (ret >= 0 && type != IIO_VAL_INT)
76200c5f80cSPeter Rosin 		/* raw values are assumed to be IIO_VAL_INT */
76300c5f80cSPeter Rosin 		ret = -EINVAL;
76400c5f80cSPeter Rosin 
76500c5f80cSPeter Rosin 	return ret;
76600c5f80cSPeter Rosin }
76700c5f80cSPeter Rosin EXPORT_SYMBOL_GPL(iio_read_avail_channel_raw);
76800c5f80cSPeter Rosin 
76900c5f80cSPeter Rosin static int iio_channel_read_max(struct iio_channel *chan,
77000c5f80cSPeter Rosin 				int *val, int *val2, int *type,
77100c5f80cSPeter Rosin 				enum iio_chan_info_enum info)
77200c5f80cSPeter Rosin {
77300c5f80cSPeter Rosin 	int unused;
77400c5f80cSPeter Rosin 	const int *vals;
77500c5f80cSPeter Rosin 	int length;
77600c5f80cSPeter Rosin 	int ret;
77700c5f80cSPeter Rosin 
77800c5f80cSPeter Rosin 	if (!val2)
77900c5f80cSPeter Rosin 		val2 = &unused;
78000c5f80cSPeter Rosin 
78100c5f80cSPeter Rosin 	ret = iio_channel_read_avail(chan, &vals, type, &length, info);
78200c5f80cSPeter Rosin 	switch (ret) {
78300c5f80cSPeter Rosin 	case IIO_AVAIL_RANGE:
78400c5f80cSPeter Rosin 		switch (*type) {
78500c5f80cSPeter Rosin 		case IIO_VAL_INT:
78600c5f80cSPeter Rosin 			*val = vals[2];
78700c5f80cSPeter Rosin 			break;
78800c5f80cSPeter Rosin 		default:
78900c5f80cSPeter Rosin 			*val = vals[4];
79000c5f80cSPeter Rosin 			*val2 = vals[5];
79100c5f80cSPeter Rosin 		}
79200c5f80cSPeter Rosin 		return 0;
79300c5f80cSPeter Rosin 
79400c5f80cSPeter Rosin 	case IIO_AVAIL_LIST:
79500c5f80cSPeter Rosin 		if (length <= 0)
79600c5f80cSPeter Rosin 			return -EINVAL;
79700c5f80cSPeter Rosin 		switch (*type) {
79800c5f80cSPeter Rosin 		case IIO_VAL_INT:
79900c5f80cSPeter Rosin 			*val = vals[--length];
80000c5f80cSPeter Rosin 			while (length) {
80100c5f80cSPeter Rosin 				if (vals[--length] > *val)
80200c5f80cSPeter Rosin 					*val = vals[length];
80300c5f80cSPeter Rosin 			}
80400c5f80cSPeter Rosin 			break;
80500c5f80cSPeter Rosin 		default:
80600c5f80cSPeter Rosin 			/* FIXME: learn about max for other iio values */
80700c5f80cSPeter Rosin 			return -EINVAL;
80800c5f80cSPeter Rosin 		}
80900c5f80cSPeter Rosin 		return 0;
81000c5f80cSPeter Rosin 
81100c5f80cSPeter Rosin 	default:
81200c5f80cSPeter Rosin 		return ret;
81300c5f80cSPeter Rosin 	}
81400c5f80cSPeter Rosin }
81500c5f80cSPeter Rosin 
81600c5f80cSPeter Rosin int iio_read_max_channel_raw(struct iio_channel *chan, int *val)
81700c5f80cSPeter Rosin {
81800c5f80cSPeter Rosin 	int ret;
81900c5f80cSPeter Rosin 	int type;
82000c5f80cSPeter Rosin 
82100c5f80cSPeter Rosin 	mutex_lock(&chan->indio_dev->info_exist_lock);
82200c5f80cSPeter Rosin 	if (!chan->indio_dev->info) {
82300c5f80cSPeter Rosin 		ret = -ENODEV;
82400c5f80cSPeter Rosin 		goto err_unlock;
82500c5f80cSPeter Rosin 	}
82600c5f80cSPeter Rosin 
82700c5f80cSPeter Rosin 	ret = iio_channel_read_max(chan, val, NULL, &type, IIO_CHAN_INFO_RAW);
82800c5f80cSPeter Rosin err_unlock:
82900c5f80cSPeter Rosin 	mutex_unlock(&chan->indio_dev->info_exist_lock);
83000c5f80cSPeter Rosin 
83100c5f80cSPeter Rosin 	return ret;
83200c5f80cSPeter Rosin }
83300c5f80cSPeter Rosin EXPORT_SYMBOL_GPL(iio_read_max_channel_raw);
83400c5f80cSPeter Rosin 
835314be14bSJonathan Cameron int iio_get_channel_type(struct iio_channel *chan, enum iio_chan_type *type)
836a980e046SJonathan Cameron {
837a980e046SJonathan Cameron 	int ret = 0;
838a980e046SJonathan Cameron 	/* Need to verify underlying driver has not gone away */
839a980e046SJonathan Cameron 
840a980e046SJonathan Cameron 	mutex_lock(&chan->indio_dev->info_exist_lock);
841a980e046SJonathan Cameron 	if (chan->indio_dev->info == NULL) {
842a980e046SJonathan Cameron 		ret = -ENODEV;
843a980e046SJonathan Cameron 		goto err_unlock;
844a980e046SJonathan Cameron 	}
845a980e046SJonathan Cameron 
846a980e046SJonathan Cameron 	*type = chan->channel->type;
847a980e046SJonathan Cameron err_unlock:
848a980e046SJonathan Cameron 	mutex_unlock(&chan->indio_dev->info_exist_lock);
849a980e046SJonathan Cameron 
850a980e046SJonathan Cameron 	return ret;
851a980e046SJonathan Cameron }
852314be14bSJonathan Cameron EXPORT_SYMBOL_GPL(iio_get_channel_type);
853f9380e71SDmitry Eremin-Solenikov 
854f9380e71SDmitry Eremin-Solenikov static int iio_channel_write(struct iio_channel *chan, int val, int val2,
855f9380e71SDmitry Eremin-Solenikov 			     enum iio_chan_info_enum info)
856f9380e71SDmitry Eremin-Solenikov {
857f9380e71SDmitry Eremin-Solenikov 	return chan->indio_dev->info->write_raw(chan->indio_dev,
858f9380e71SDmitry Eremin-Solenikov 						chan->channel, val, val2, info);
859f9380e71SDmitry Eremin-Solenikov }
860f9380e71SDmitry Eremin-Solenikov 
86134739a21SArnaud Pouliquen int iio_write_channel_attribute(struct iio_channel *chan, int val, int val2,
86234739a21SArnaud Pouliquen 				enum iio_chan_info_enum attribute)
863f9380e71SDmitry Eremin-Solenikov {
864f9380e71SDmitry Eremin-Solenikov 	int ret;
865f9380e71SDmitry Eremin-Solenikov 
866f9380e71SDmitry Eremin-Solenikov 	mutex_lock(&chan->indio_dev->info_exist_lock);
867f9380e71SDmitry Eremin-Solenikov 	if (chan->indio_dev->info == NULL) {
868f9380e71SDmitry Eremin-Solenikov 		ret = -ENODEV;
869f9380e71SDmitry Eremin-Solenikov 		goto err_unlock;
870f9380e71SDmitry Eremin-Solenikov 	}
871f9380e71SDmitry Eremin-Solenikov 
87234739a21SArnaud Pouliquen 	ret = iio_channel_write(chan, val, val2, attribute);
873f9380e71SDmitry Eremin-Solenikov err_unlock:
874f9380e71SDmitry Eremin-Solenikov 	mutex_unlock(&chan->indio_dev->info_exist_lock);
875f9380e71SDmitry Eremin-Solenikov 
876f9380e71SDmitry Eremin-Solenikov 	return ret;
877f9380e71SDmitry Eremin-Solenikov }
87834739a21SArnaud Pouliquen EXPORT_SYMBOL_GPL(iio_write_channel_attribute);
87934739a21SArnaud Pouliquen 
88034739a21SArnaud Pouliquen int iio_write_channel_raw(struct iio_channel *chan, int val)
88134739a21SArnaud Pouliquen {
88234739a21SArnaud Pouliquen 	return iio_write_channel_attribute(chan, val, 0, IIO_CHAN_INFO_RAW);
88334739a21SArnaud Pouliquen }
884f9380e71SDmitry Eremin-Solenikov EXPORT_SYMBOL_GPL(iio_write_channel_raw);
8858a848e75SPeter Rosin 
8868a848e75SPeter Rosin unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan)
8878a848e75SPeter Rosin {
8888a848e75SPeter Rosin 	const struct iio_chan_spec_ext_info *ext_info;
8898a848e75SPeter Rosin 	unsigned int i = 0;
8908a848e75SPeter Rosin 
8918a848e75SPeter Rosin 	if (!chan->channel->ext_info)
8928a848e75SPeter Rosin 		return i;
8938a848e75SPeter Rosin 
8948a848e75SPeter Rosin 	for (ext_info = chan->channel->ext_info; ext_info->name; ext_info++)
8958a848e75SPeter Rosin 		++i;
8968a848e75SPeter Rosin 
8978a848e75SPeter Rosin 	return i;
8988a848e75SPeter Rosin }
8998a848e75SPeter Rosin EXPORT_SYMBOL_GPL(iio_get_channel_ext_info_count);
9008a848e75SPeter Rosin 
9018a848e75SPeter Rosin static const struct iio_chan_spec_ext_info *iio_lookup_ext_info(
9028a848e75SPeter Rosin 						const struct iio_channel *chan,
9038a848e75SPeter Rosin 						const char *attr)
9048a848e75SPeter Rosin {
9058a848e75SPeter Rosin 	const struct iio_chan_spec_ext_info *ext_info;
9068a848e75SPeter Rosin 
9078a848e75SPeter Rosin 	if (!chan->channel->ext_info)
9088a848e75SPeter Rosin 		return NULL;
9098a848e75SPeter Rosin 
9108a848e75SPeter Rosin 	for (ext_info = chan->channel->ext_info; ext_info->name; ++ext_info) {
9118a848e75SPeter Rosin 		if (!strcmp(attr, ext_info->name))
9128a848e75SPeter Rosin 			return ext_info;
9138a848e75SPeter Rosin 	}
9148a848e75SPeter Rosin 
9158a848e75SPeter Rosin 	return NULL;
9168a848e75SPeter Rosin }
9178a848e75SPeter Rosin 
9188a848e75SPeter Rosin ssize_t iio_read_channel_ext_info(struct iio_channel *chan,
9198a848e75SPeter Rosin 				  const char *attr, char *buf)
9208a848e75SPeter Rosin {
9218a848e75SPeter Rosin 	const struct iio_chan_spec_ext_info *ext_info;
9228a848e75SPeter Rosin 
9238a848e75SPeter Rosin 	ext_info = iio_lookup_ext_info(chan, attr);
9248a848e75SPeter Rosin 	if (!ext_info)
9258a848e75SPeter Rosin 		return -EINVAL;
9268a848e75SPeter Rosin 
9278a848e75SPeter Rosin 	return ext_info->read(chan->indio_dev, ext_info->private,
9288a848e75SPeter Rosin 			      chan->channel, buf);
9298a848e75SPeter Rosin }
9308a848e75SPeter Rosin EXPORT_SYMBOL_GPL(iio_read_channel_ext_info);
9318a848e75SPeter Rosin 
9328a848e75SPeter Rosin ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr,
9338a848e75SPeter Rosin 				   const char *buf, size_t len)
9348a848e75SPeter Rosin {
9358a848e75SPeter Rosin 	const struct iio_chan_spec_ext_info *ext_info;
9368a848e75SPeter Rosin 
9378a848e75SPeter Rosin 	ext_info = iio_lookup_ext_info(chan, attr);
9388a848e75SPeter Rosin 	if (!ext_info)
9398a848e75SPeter Rosin 		return -EINVAL;
9408a848e75SPeter Rosin 
9418a848e75SPeter Rosin 	return ext_info->write(chan->indio_dev, ext_info->private,
9428a848e75SPeter Rosin 			       chan->channel, buf, len);
9438a848e75SPeter Rosin }
9448a848e75SPeter Rosin EXPORT_SYMBOL_GPL(iio_write_channel_ext_info);
945