xref: /openbmc/linux/drivers/iio/inkern.c (revision cc9fb60e)
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 
27*cc9fb60eSLino Sanfilippo static int iio_map_array_unregister_locked(struct iio_dev *indio_dev)
28*cc9fb60eSLino Sanfilippo {
29*cc9fb60eSLino Sanfilippo 	int ret = -ENODEV;
30*cc9fb60eSLino Sanfilippo 	struct iio_map_internal *mapi, *next;
31*cc9fb60eSLino Sanfilippo 
32*cc9fb60eSLino Sanfilippo 	list_for_each_entry_safe(mapi, next, &iio_map_list, l) {
33*cc9fb60eSLino Sanfilippo 		if (indio_dev == mapi->indio_dev) {
34*cc9fb60eSLino Sanfilippo 			list_del(&mapi->l);
35*cc9fb60eSLino Sanfilippo 			kfree(mapi);
36*cc9fb60eSLino Sanfilippo 			ret = 0;
37*cc9fb60eSLino Sanfilippo 		}
38*cc9fb60eSLino Sanfilippo 	}
39*cc9fb60eSLino Sanfilippo 	return ret;
40*cc9fb60eSLino Sanfilippo }
41*cc9fb60eSLino 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:
63a980e046SJonathan Cameron 	mutex_unlock(&iio_map_list_lock);
64a980e046SJonathan Cameron 
65a980e046SJonathan Cameron 	return ret;
66a980e046SJonathan Cameron }
67a980e046SJonathan Cameron EXPORT_SYMBOL_GPL(iio_map_array_register);
68a980e046SJonathan Cameron 
69a980e046SJonathan Cameron 
706cb2afd7SGuenter Roeck /*
716cb2afd7SGuenter Roeck  * Remove all map entries associated with the given iio device
72a980e046SJonathan Cameron  */
736cb2afd7SGuenter Roeck int iio_map_array_unregister(struct iio_dev *indio_dev)
74a980e046SJonathan Cameron {
75*cc9fb60eSLino Sanfilippo 	int ret;
76a980e046SJonathan Cameron 
77a980e046SJonathan Cameron 	mutex_lock(&iio_map_list_lock);
78*cc9fb60eSLino Sanfilippo 	ret = iio_map_array_unregister_locked(indio_dev);
79a980e046SJonathan Cameron 	mutex_unlock(&iio_map_list_lock);
80*cc9fb60eSLino Sanfilippo 
81a980e046SJonathan Cameron 	return ret;
82a980e046SJonathan Cameron }
83a980e046SJonathan Cameron EXPORT_SYMBOL_GPL(iio_map_array_unregister);
84a980e046SJonathan Cameron 
85a980e046SJonathan Cameron static const struct iio_chan_spec
86314be14bSJonathan Cameron *iio_chan_spec_from_name(const struct iio_dev *indio_dev, const char *name)
87a980e046SJonathan Cameron {
88a980e046SJonathan Cameron 	int i;
89a980e046SJonathan Cameron 	const struct iio_chan_spec *chan = NULL;
90a980e046SJonathan Cameron 
91a980e046SJonathan Cameron 	for (i = 0; i < indio_dev->num_channels; i++)
92a980e046SJonathan Cameron 		if (indio_dev->channels[i].datasheet_name &&
93a980e046SJonathan Cameron 		    strcmp(name, indio_dev->channels[i].datasheet_name) == 0) {
94a980e046SJonathan Cameron 			chan = &indio_dev->channels[i];
95a980e046SJonathan Cameron 			break;
96a980e046SJonathan Cameron 		}
97a980e046SJonathan Cameron 	return chan;
98a980e046SJonathan Cameron }
99a980e046SJonathan Cameron 
10017d82b47SGuenter Roeck #ifdef CONFIG_OF
10117d82b47SGuenter Roeck 
102418e3ea1SSuzuki K Poulose static int iio_dev_node_match(struct device *dev, const void *data)
10317d82b47SGuenter Roeck {
10417d82b47SGuenter Roeck 	return dev->of_node == data && dev->type == &iio_device_type;
10517d82b47SGuenter Roeck }
10617d82b47SGuenter Roeck 
107acd82567SIvan T. Ivanov /**
108acd82567SIvan T. Ivanov  * __of_iio_simple_xlate - translate iiospec to the IIO channel index
109acd82567SIvan T. Ivanov  * @indio_dev:	pointer to the iio_dev structure
110acd82567SIvan T. Ivanov  * @iiospec:	IIO specifier as found in the device tree
111acd82567SIvan T. Ivanov  *
112acd82567SIvan T. Ivanov  * This is simple translation function, suitable for the most 1:1 mapped
113acd82567SIvan T. Ivanov  * channels in IIO chips. This function performs only one sanity check:
114acd82567SIvan T. Ivanov  * whether IIO index is less than num_channels (that is specified in the
115acd82567SIvan T. Ivanov  * iio_dev).
116acd82567SIvan T. Ivanov  */
117acd82567SIvan T. Ivanov static int __of_iio_simple_xlate(struct iio_dev *indio_dev,
118acd82567SIvan T. Ivanov 				const struct of_phandle_args *iiospec)
119acd82567SIvan T. Ivanov {
120acd82567SIvan T. Ivanov 	if (!iiospec->args_count)
121acd82567SIvan T. Ivanov 		return 0;
122acd82567SIvan T. Ivanov 
1231f202725SStefan Wahren 	if (iiospec->args[0] >= indio_dev->num_channels) {
1241f202725SStefan Wahren 		dev_err(&indio_dev->dev, "invalid channel index %u\n",
1251f202725SStefan Wahren 			iiospec->args[0]);
126acd82567SIvan T. Ivanov 		return -EINVAL;
1271f202725SStefan Wahren 	}
128acd82567SIvan T. Ivanov 
129acd82567SIvan T. Ivanov 	return iiospec->args[0];
130acd82567SIvan T. Ivanov }
131acd82567SIvan T. Ivanov 
13217d82b47SGuenter Roeck static int __of_iio_channel_get(struct iio_channel *channel,
13317d82b47SGuenter Roeck 				struct device_node *np, int index)
13417d82b47SGuenter Roeck {
13517d82b47SGuenter Roeck 	struct device *idev;
13617d82b47SGuenter Roeck 	struct iio_dev *indio_dev;
13717d82b47SGuenter Roeck 	int err;
13817d82b47SGuenter Roeck 	struct of_phandle_args iiospec;
13917d82b47SGuenter Roeck 
14017d82b47SGuenter Roeck 	err = of_parse_phandle_with_args(np, "io-channels",
14117d82b47SGuenter Roeck 					 "#io-channel-cells",
14217d82b47SGuenter Roeck 					 index, &iiospec);
14317d82b47SGuenter Roeck 	if (err)
14417d82b47SGuenter Roeck 		return err;
14517d82b47SGuenter Roeck 
14617d82b47SGuenter Roeck 	idev = bus_find_device(&iio_bus_type, NULL, iiospec.np,
14717d82b47SGuenter Roeck 			       iio_dev_node_match);
14817d82b47SGuenter Roeck 	of_node_put(iiospec.np);
14917d82b47SGuenter Roeck 	if (idev == NULL)
15017d82b47SGuenter Roeck 		return -EPROBE_DEFER;
15117d82b47SGuenter Roeck 
15217d82b47SGuenter Roeck 	indio_dev = dev_to_iio_dev(idev);
15317d82b47SGuenter Roeck 	channel->indio_dev = indio_dev;
154acd82567SIvan T. Ivanov 	if (indio_dev->info->of_xlate)
155acd82567SIvan T. Ivanov 		index = indio_dev->info->of_xlate(indio_dev, &iiospec);
156acd82567SIvan T. Ivanov 	else
157acd82567SIvan T. Ivanov 		index = __of_iio_simple_xlate(indio_dev, &iiospec);
158acd82567SIvan T. Ivanov 	if (index < 0)
15917d82b47SGuenter Roeck 		goto err_put;
16017d82b47SGuenter Roeck 	channel->channel = &indio_dev->channels[index];
16117d82b47SGuenter Roeck 
16217d82b47SGuenter Roeck 	return 0;
16317d82b47SGuenter Roeck 
16417d82b47SGuenter Roeck err_put:
16517d82b47SGuenter Roeck 	iio_device_put(indio_dev);
166acd82567SIvan T. Ivanov 	return index;
16717d82b47SGuenter Roeck }
16817d82b47SGuenter Roeck 
16917d82b47SGuenter Roeck static struct iio_channel *of_iio_channel_get(struct device_node *np, int index)
17017d82b47SGuenter Roeck {
17117d82b47SGuenter Roeck 	struct iio_channel *channel;
17217d82b47SGuenter Roeck 	int err;
17317d82b47SGuenter Roeck 
17417d82b47SGuenter Roeck 	if (index < 0)
17517d82b47SGuenter Roeck 		return ERR_PTR(-EINVAL);
17617d82b47SGuenter Roeck 
17717d82b47SGuenter Roeck 	channel = kzalloc(sizeof(*channel), GFP_KERNEL);
17817d82b47SGuenter Roeck 	if (channel == NULL)
17917d82b47SGuenter Roeck 		return ERR_PTR(-ENOMEM);
18017d82b47SGuenter Roeck 
18117d82b47SGuenter Roeck 	err = __of_iio_channel_get(channel, np, index);
18217d82b47SGuenter Roeck 	if (err)
18317d82b47SGuenter Roeck 		goto err_free_channel;
18417d82b47SGuenter Roeck 
18517d82b47SGuenter Roeck 	return channel;
18617d82b47SGuenter Roeck 
18717d82b47SGuenter Roeck err_free_channel:
18817d82b47SGuenter Roeck 	kfree(channel);
18917d82b47SGuenter Roeck 	return ERR_PTR(err);
19017d82b47SGuenter Roeck }
19117d82b47SGuenter Roeck 
19217d82b47SGuenter Roeck static struct iio_channel *of_iio_channel_get_by_name(struct device_node *np,
19317d82b47SGuenter Roeck 						      const char *name)
19417d82b47SGuenter Roeck {
19517d82b47SGuenter Roeck 	struct iio_channel *chan = NULL;
19617d82b47SGuenter Roeck 
19717d82b47SGuenter Roeck 	/* Walk up the tree of devices looking for a matching iio channel */
19817d82b47SGuenter Roeck 	while (np) {
19917d82b47SGuenter Roeck 		int index = 0;
20017d82b47SGuenter Roeck 
20117d82b47SGuenter Roeck 		/*
20217d82b47SGuenter Roeck 		 * For named iio channels, first look up the name in the
20317d82b47SGuenter Roeck 		 * "io-channel-names" property.  If it cannot be found, the
20417d82b47SGuenter Roeck 		 * index will be an error code, and of_iio_channel_get()
20517d82b47SGuenter Roeck 		 * will fail.
20617d82b47SGuenter Roeck 		 */
20717d82b47SGuenter Roeck 		if (name)
20817d82b47SGuenter Roeck 			index = of_property_match_string(np, "io-channel-names",
20917d82b47SGuenter Roeck 							 name);
21017d82b47SGuenter Roeck 		chan = of_iio_channel_get(np, index);
211872687f6SJohannes Pointner 		if (!IS_ERR(chan) || PTR_ERR(chan) == -EPROBE_DEFER)
21217d82b47SGuenter Roeck 			break;
21317d82b47SGuenter Roeck 		else if (name && index >= 0) {
2143921db46SRob Herring 			pr_err("ERROR: could not get IIO channel %pOF:%s(%i)\n",
2153921db46SRob Herring 				np, name ? name : "", index);
216a2c12493SAdam Thomson 			return NULL;
21717d82b47SGuenter Roeck 		}
21817d82b47SGuenter Roeck 
21917d82b47SGuenter Roeck 		/*
22017d82b47SGuenter Roeck 		 * No matching IIO channel found on this node.
22117d82b47SGuenter Roeck 		 * If the parent node has a "io-channel-ranges" property,
22217d82b47SGuenter Roeck 		 * then we can try one of its channels.
22317d82b47SGuenter Roeck 		 */
22417d82b47SGuenter Roeck 		np = np->parent;
22517d82b47SGuenter Roeck 		if (np && !of_get_property(np, "io-channel-ranges", NULL))
226a2c12493SAdam Thomson 			return NULL;
22717d82b47SGuenter Roeck 	}
228a2c12493SAdam Thomson 
22917d82b47SGuenter Roeck 	return chan;
23017d82b47SGuenter Roeck }
23117d82b47SGuenter Roeck 
23217d82b47SGuenter Roeck static struct iio_channel *of_iio_channel_get_all(struct device *dev)
23317d82b47SGuenter Roeck {
23417d82b47SGuenter Roeck 	struct iio_channel *chans;
23517d82b47SGuenter Roeck 	int i, mapind, nummaps = 0;
23617d82b47SGuenter Roeck 	int ret;
23717d82b47SGuenter Roeck 
23817d82b47SGuenter Roeck 	do {
23917d82b47SGuenter Roeck 		ret = of_parse_phandle_with_args(dev->of_node,
24017d82b47SGuenter Roeck 						 "io-channels",
24117d82b47SGuenter Roeck 						 "#io-channel-cells",
24217d82b47SGuenter Roeck 						 nummaps, NULL);
24317d82b47SGuenter Roeck 		if (ret < 0)
24417d82b47SGuenter Roeck 			break;
24517d82b47SGuenter Roeck 	} while (++nummaps);
24617d82b47SGuenter Roeck 
24717d82b47SGuenter Roeck 	if (nummaps == 0)	/* no error, return NULL to search map table */
24817d82b47SGuenter Roeck 		return NULL;
24917d82b47SGuenter Roeck 
25017d82b47SGuenter Roeck 	/* NULL terminated array to save passing size */
25117d82b47SGuenter Roeck 	chans = kcalloc(nummaps + 1, sizeof(*chans), GFP_KERNEL);
25217d82b47SGuenter Roeck 	if (chans == NULL)
25317d82b47SGuenter Roeck 		return ERR_PTR(-ENOMEM);
25417d82b47SGuenter Roeck 
25517d82b47SGuenter Roeck 	/* Search for OF matches */
25617d82b47SGuenter Roeck 	for (mapind = 0; mapind < nummaps; mapind++) {
25717d82b47SGuenter Roeck 		ret = __of_iio_channel_get(&chans[mapind], dev->of_node,
25817d82b47SGuenter Roeck 					   mapind);
25917d82b47SGuenter Roeck 		if (ret)
26017d82b47SGuenter Roeck 			goto error_free_chans;
26117d82b47SGuenter Roeck 	}
26217d82b47SGuenter Roeck 	return chans;
26317d82b47SGuenter Roeck 
26417d82b47SGuenter Roeck error_free_chans:
26517d82b47SGuenter Roeck 	for (i = 0; i < mapind; i++)
26617d82b47SGuenter Roeck 		iio_device_put(chans[i].indio_dev);
26717d82b47SGuenter Roeck 	kfree(chans);
26817d82b47SGuenter Roeck 	return ERR_PTR(ret);
26917d82b47SGuenter Roeck }
27017d82b47SGuenter Roeck 
27117d82b47SGuenter Roeck #else /* CONFIG_OF */
27217d82b47SGuenter Roeck 
27317d82b47SGuenter Roeck static inline struct iio_channel *
27417d82b47SGuenter Roeck of_iio_channel_get_by_name(struct device_node *np, const char *name)
27517d82b47SGuenter Roeck {
27617d82b47SGuenter Roeck 	return NULL;
27717d82b47SGuenter Roeck }
27817d82b47SGuenter Roeck 
27917d82b47SGuenter Roeck static inline struct iio_channel *of_iio_channel_get_all(struct device *dev)
28017d82b47SGuenter Roeck {
28117d82b47SGuenter Roeck 	return NULL;
28217d82b47SGuenter Roeck }
28317d82b47SGuenter Roeck 
28417d82b47SGuenter Roeck #endif /* CONFIG_OF */
285a980e046SJonathan Cameron 
2865aa57f0aSGuenter Roeck static struct iio_channel *iio_channel_get_sys(const char *name,
2875aa57f0aSGuenter Roeck 					       const char *channel_name)
288a980e046SJonathan Cameron {
289a980e046SJonathan Cameron 	struct iio_map_internal *c_i = NULL, *c = NULL;
290a980e046SJonathan Cameron 	struct iio_channel *channel;
2913183bac1SKim, Milo 	int err;
292a980e046SJonathan Cameron 
293a980e046SJonathan Cameron 	if (name == NULL && channel_name == NULL)
294a980e046SJonathan Cameron 		return ERR_PTR(-ENODEV);
295a980e046SJonathan Cameron 
296a980e046SJonathan Cameron 	/* first find matching entry the channel map */
297a980e046SJonathan Cameron 	mutex_lock(&iio_map_list_lock);
298a980e046SJonathan Cameron 	list_for_each_entry(c_i, &iio_map_list, l) {
299a980e046SJonathan Cameron 		if ((name && strcmp(name, c_i->map->consumer_dev_name) != 0) ||
300a980e046SJonathan Cameron 		    (channel_name &&
301a980e046SJonathan Cameron 		     strcmp(channel_name, c_i->map->consumer_channel) != 0))
302a980e046SJonathan Cameron 			continue;
303a980e046SJonathan Cameron 		c = c_i;
3041875ffd2SLars-Peter Clausen 		iio_device_get(c->indio_dev);
305a980e046SJonathan Cameron 		break;
306a980e046SJonathan Cameron 	}
307a980e046SJonathan Cameron 	mutex_unlock(&iio_map_list_lock);
308a980e046SJonathan Cameron 	if (c == NULL)
309a980e046SJonathan Cameron 		return ERR_PTR(-ENODEV);
310a980e046SJonathan Cameron 
3112cc412b5SKim, Milo 	channel = kzalloc(sizeof(*channel), GFP_KERNEL);
3123183bac1SKim, Milo 	if (channel == NULL) {
3133183bac1SKim, Milo 		err = -ENOMEM;
314801c4b5cSKim, Milo 		goto error_no_mem;
3153183bac1SKim, Milo 	}
316a980e046SJonathan Cameron 
317a980e046SJonathan Cameron 	channel->indio_dev = c->indio_dev;
318a980e046SJonathan Cameron 
319b2b79ffaSKim, Milo 	if (c->map->adc_channel_label) {
320a980e046SJonathan Cameron 		channel->channel =
321a980e046SJonathan Cameron 			iio_chan_spec_from_name(channel->indio_dev,
322a980e046SJonathan Cameron 						c->map->adc_channel_label);
323a980e046SJonathan Cameron 
3243183bac1SKim, Milo 		if (channel->channel == NULL) {
3253183bac1SKim, Milo 			err = -EINVAL;
326b2b79ffaSKim, Milo 			goto error_no_chan;
327b2b79ffaSKim, Milo 		}
3283183bac1SKim, Milo 	}
329b2b79ffaSKim, Milo 
330a980e046SJonathan Cameron 	return channel;
331b2b79ffaSKim, Milo 
332b2b79ffaSKim, Milo error_no_chan:
333b2b79ffaSKim, Milo 	kfree(channel);
334801c4b5cSKim, Milo error_no_mem:
335801c4b5cSKim, Milo 	iio_device_put(c->indio_dev);
3363183bac1SKim, Milo 	return ERR_PTR(err);
337a980e046SJonathan Cameron }
3385aa57f0aSGuenter Roeck 
3395aa57f0aSGuenter Roeck struct iio_channel *iio_channel_get(struct device *dev,
3405aa57f0aSGuenter Roeck 				    const char *channel_name)
3415aa57f0aSGuenter Roeck {
3425aa57f0aSGuenter Roeck 	const char *name = dev ? dev_name(dev) : NULL;
34317d82b47SGuenter Roeck 	struct iio_channel *channel;
3445aa57f0aSGuenter Roeck 
34517d82b47SGuenter Roeck 	if (dev) {
34617d82b47SGuenter Roeck 		channel = of_iio_channel_get_by_name(dev->of_node,
34717d82b47SGuenter Roeck 						     channel_name);
34817d82b47SGuenter Roeck 		if (channel != NULL)
34917d82b47SGuenter Roeck 			return channel;
35017d82b47SGuenter Roeck 	}
351a2c12493SAdam Thomson 
3525aa57f0aSGuenter Roeck 	return iio_channel_get_sys(name, channel_name);
3535aa57f0aSGuenter Roeck }
354314be14bSJonathan Cameron EXPORT_SYMBOL_GPL(iio_channel_get);
355a980e046SJonathan Cameron 
356314be14bSJonathan Cameron void iio_channel_release(struct iio_channel *channel)
357a980e046SJonathan Cameron {
358d81dac3cSDan Carpenter 	if (!channel)
359d81dac3cSDan Carpenter 		return;
3601875ffd2SLars-Peter Clausen 	iio_device_put(channel->indio_dev);
361a980e046SJonathan Cameron 	kfree(channel);
362a980e046SJonathan Cameron }
363314be14bSJonathan Cameron EXPORT_SYMBOL_GPL(iio_channel_release);
364a980e046SJonathan Cameron 
3658bf872d8SLaxman Dewangan static void devm_iio_channel_free(struct device *dev, void *res)
3668bf872d8SLaxman Dewangan {
3678bf872d8SLaxman Dewangan 	struct iio_channel *channel = *(struct iio_channel **)res;
3688bf872d8SLaxman Dewangan 
3698bf872d8SLaxman Dewangan 	iio_channel_release(channel);
3708bf872d8SLaxman Dewangan }
3718bf872d8SLaxman Dewangan 
3728bf872d8SLaxman Dewangan struct iio_channel *devm_iio_channel_get(struct device *dev,
3738bf872d8SLaxman Dewangan 					 const char *channel_name)
3748bf872d8SLaxman Dewangan {
3758bf872d8SLaxman Dewangan 	struct iio_channel **ptr, *channel;
3768bf872d8SLaxman Dewangan 
3778bf872d8SLaxman Dewangan 	ptr = devres_alloc(devm_iio_channel_free, sizeof(*ptr), GFP_KERNEL);
3788bf872d8SLaxman Dewangan 	if (!ptr)
3798bf872d8SLaxman Dewangan 		return ERR_PTR(-ENOMEM);
3808bf872d8SLaxman Dewangan 
3818bf872d8SLaxman Dewangan 	channel = iio_channel_get(dev, channel_name);
3828bf872d8SLaxman Dewangan 	if (IS_ERR(channel)) {
3838bf872d8SLaxman Dewangan 		devres_free(ptr);
3848bf872d8SLaxman Dewangan 		return channel;
3858bf872d8SLaxman Dewangan 	}
3868bf872d8SLaxman Dewangan 
3878bf872d8SLaxman Dewangan 	*ptr = channel;
3888bf872d8SLaxman Dewangan 	devres_add(dev, ptr);
3898bf872d8SLaxman Dewangan 
3908bf872d8SLaxman Dewangan 	return channel;
3918bf872d8SLaxman Dewangan }
3928bf872d8SLaxman Dewangan EXPORT_SYMBOL_GPL(devm_iio_channel_get);
3938bf872d8SLaxman Dewangan 
394ca7d98dbSGuenter Roeck struct iio_channel *iio_channel_get_all(struct device *dev)
395a980e046SJonathan Cameron {
396ca7d98dbSGuenter Roeck 	const char *name;
397a980e046SJonathan Cameron 	struct iio_channel *chans;
398a980e046SJonathan Cameron 	struct iio_map_internal *c = NULL;
399a980e046SJonathan Cameron 	int nummaps = 0;
400a980e046SJonathan Cameron 	int mapind = 0;
401a980e046SJonathan Cameron 	int i, ret;
402a980e046SJonathan Cameron 
403ca7d98dbSGuenter Roeck 	if (dev == NULL)
404a980e046SJonathan Cameron 		return ERR_PTR(-EINVAL);
40517d82b47SGuenter Roeck 
40617d82b47SGuenter Roeck 	chans = of_iio_channel_get_all(dev);
40717d82b47SGuenter Roeck 	if (chans)
40817d82b47SGuenter Roeck 		return chans;
40917d82b47SGuenter Roeck 
410ca7d98dbSGuenter Roeck 	name = dev_name(dev);
411a980e046SJonathan Cameron 
412a980e046SJonathan Cameron 	mutex_lock(&iio_map_list_lock);
413a980e046SJonathan Cameron 	/* first count the matching maps */
414a980e046SJonathan Cameron 	list_for_each_entry(c, &iio_map_list, l)
415a980e046SJonathan Cameron 		if (name && strcmp(name, c->map->consumer_dev_name) != 0)
416a980e046SJonathan Cameron 			continue;
417a980e046SJonathan Cameron 		else
418a980e046SJonathan Cameron 			nummaps++;
419a980e046SJonathan Cameron 
420a980e046SJonathan Cameron 	if (nummaps == 0) {
421a980e046SJonathan Cameron 		ret = -ENODEV;
422a980e046SJonathan Cameron 		goto error_ret;
423a980e046SJonathan Cameron 	}
424a980e046SJonathan Cameron 
425a980e046SJonathan Cameron 	/* NULL terminated array to save passing size */
4266396bb22SKees Cook 	chans = kcalloc(nummaps + 1, sizeof(*chans), GFP_KERNEL);
427a980e046SJonathan Cameron 	if (chans == NULL) {
428a980e046SJonathan Cameron 		ret = -ENOMEM;
429a980e046SJonathan Cameron 		goto error_ret;
430a980e046SJonathan Cameron 	}
431a980e046SJonathan Cameron 
432a980e046SJonathan Cameron 	/* for each map fill in the chans element */
433a980e046SJonathan Cameron 	list_for_each_entry(c, &iio_map_list, l) {
434a980e046SJonathan Cameron 		if (name && strcmp(name, c->map->consumer_dev_name) != 0)
435a980e046SJonathan Cameron 			continue;
436a980e046SJonathan Cameron 		chans[mapind].indio_dev = c->indio_dev;
4370464415dSJonathan Cameron 		chans[mapind].data = c->map->consumer_data;
438a980e046SJonathan Cameron 		chans[mapind].channel =
439a980e046SJonathan Cameron 			iio_chan_spec_from_name(chans[mapind].indio_dev,
440a980e046SJonathan Cameron 						c->map->adc_channel_label);
441a980e046SJonathan Cameron 		if (chans[mapind].channel == NULL) {
442a980e046SJonathan Cameron 			ret = -EINVAL;
443a980e046SJonathan Cameron 			goto error_free_chans;
444a980e046SJonathan Cameron 		}
4451875ffd2SLars-Peter Clausen 		iio_device_get(chans[mapind].indio_dev);
446a980e046SJonathan Cameron 		mapind++;
447a980e046SJonathan Cameron 	}
448a980e046SJonathan Cameron 	if (mapind == 0) {
449a980e046SJonathan Cameron 		ret = -ENODEV;
450a980e046SJonathan Cameron 		goto error_free_chans;
451a980e046SJonathan Cameron 	}
452e59b9afeSDan Carpenter 	mutex_unlock(&iio_map_list_lock);
453e59b9afeSDan Carpenter 
454a980e046SJonathan Cameron 	return chans;
455a980e046SJonathan Cameron 
456a980e046SJonathan Cameron error_free_chans:
457a980e046SJonathan Cameron 	for (i = 0; i < nummaps; i++)
4581875ffd2SLars-Peter Clausen 		iio_device_put(chans[i].indio_dev);
459a980e046SJonathan Cameron 	kfree(chans);
460a980e046SJonathan Cameron error_ret:
461a980e046SJonathan Cameron 	mutex_unlock(&iio_map_list_lock);
462a980e046SJonathan Cameron 
463a980e046SJonathan Cameron 	return ERR_PTR(ret);
464a980e046SJonathan Cameron }
465314be14bSJonathan Cameron EXPORT_SYMBOL_GPL(iio_channel_get_all);
466a980e046SJonathan Cameron 
467314be14bSJonathan Cameron void iio_channel_release_all(struct iio_channel *channels)
468a980e046SJonathan Cameron {
469a980e046SJonathan Cameron 	struct iio_channel *chan = &channels[0];
470a980e046SJonathan Cameron 
471a980e046SJonathan Cameron 	while (chan->indio_dev) {
4721875ffd2SLars-Peter Clausen 		iio_device_put(chan->indio_dev);
473a980e046SJonathan Cameron 		chan++;
474a980e046SJonathan Cameron 	}
475a980e046SJonathan Cameron 	kfree(channels);
476a980e046SJonathan Cameron }
477314be14bSJonathan Cameron EXPORT_SYMBOL_GPL(iio_channel_release_all);
478a980e046SJonathan Cameron 
479efc2c013SLaxman Dewangan static void devm_iio_channel_free_all(struct device *dev, void *res)
480efc2c013SLaxman Dewangan {
481efc2c013SLaxman Dewangan 	struct iio_channel *channels = *(struct iio_channel **)res;
482efc2c013SLaxman Dewangan 
483efc2c013SLaxman Dewangan 	iio_channel_release_all(channels);
484efc2c013SLaxman Dewangan }
485efc2c013SLaxman Dewangan 
486efc2c013SLaxman Dewangan struct iio_channel *devm_iio_channel_get_all(struct device *dev)
487efc2c013SLaxman Dewangan {
488efc2c013SLaxman Dewangan 	struct iio_channel **ptr, *channels;
489efc2c013SLaxman Dewangan 
490efc2c013SLaxman Dewangan 	ptr = devres_alloc(devm_iio_channel_free_all, sizeof(*ptr), GFP_KERNEL);
491efc2c013SLaxman Dewangan 	if (!ptr)
492efc2c013SLaxman Dewangan 		return ERR_PTR(-ENOMEM);
493efc2c013SLaxman Dewangan 
494efc2c013SLaxman Dewangan 	channels = iio_channel_get_all(dev);
495efc2c013SLaxman Dewangan 	if (IS_ERR(channels)) {
496efc2c013SLaxman Dewangan 		devres_free(ptr);
497efc2c013SLaxman Dewangan 		return channels;
498efc2c013SLaxman Dewangan 	}
499efc2c013SLaxman Dewangan 
500efc2c013SLaxman Dewangan 	*ptr = channels;
501efc2c013SLaxman Dewangan 	devres_add(dev, ptr);
502efc2c013SLaxman Dewangan 
503efc2c013SLaxman Dewangan 	return channels;
504efc2c013SLaxman Dewangan }
505efc2c013SLaxman Dewangan EXPORT_SYMBOL_GPL(devm_iio_channel_get_all);
506efc2c013SLaxman Dewangan 
50748e44ce0SLars-Peter Clausen static int iio_channel_read(struct iio_channel *chan, int *val, int *val2,
50848e44ce0SLars-Peter Clausen 	enum iio_chan_info_enum info)
50948e44ce0SLars-Peter Clausen {
51048e44ce0SLars-Peter Clausen 	int unused;
5119fbfb4b3SSrinivas Pandruvada 	int vals[INDIO_MAX_RAW_ELEMENTS];
5129fbfb4b3SSrinivas Pandruvada 	int ret;
5139fbfb4b3SSrinivas Pandruvada 	int val_len = 2;
51448e44ce0SLars-Peter Clausen 
51548e44ce0SLars-Peter Clausen 	if (val2 == NULL)
51648e44ce0SLars-Peter Clausen 		val2 = &unused;
51748e44ce0SLars-Peter Clausen 
51865de7654SFabien Proriol 	if (!iio_channel_has_info(chan->channel, info))
51965de7654SFabien Proriol 		return -EINVAL;
52065de7654SFabien Proriol 
5219fbfb4b3SSrinivas Pandruvada 	if (chan->indio_dev->info->read_raw_multi) {
5229fbfb4b3SSrinivas Pandruvada 		ret = chan->indio_dev->info->read_raw_multi(chan->indio_dev,
5239fbfb4b3SSrinivas Pandruvada 					chan->channel, INDIO_MAX_RAW_ELEMENTS,
5249fbfb4b3SSrinivas Pandruvada 					vals, &val_len, info);
5259fbfb4b3SSrinivas Pandruvada 		*val = vals[0];
5269fbfb4b3SSrinivas Pandruvada 		*val2 = vals[1];
5279fbfb4b3SSrinivas Pandruvada 	} else
5289fbfb4b3SSrinivas Pandruvada 		ret = chan->indio_dev->info->read_raw(chan->indio_dev,
5299fbfb4b3SSrinivas Pandruvada 					chan->channel, val, val2, info);
5309fbfb4b3SSrinivas Pandruvada 
5319fbfb4b3SSrinivas Pandruvada 	return ret;
53248e44ce0SLars-Peter Clausen }
53348e44ce0SLars-Peter Clausen 
534314be14bSJonathan Cameron int iio_read_channel_raw(struct iio_channel *chan, int *val)
535a980e046SJonathan Cameron {
53648e44ce0SLars-Peter Clausen 	int ret;
537a980e046SJonathan Cameron 
538a980e046SJonathan Cameron 	mutex_lock(&chan->indio_dev->info_exist_lock);
539a980e046SJonathan Cameron 	if (chan->indio_dev->info == NULL) {
540a980e046SJonathan Cameron 		ret = -ENODEV;
541a980e046SJonathan Cameron 		goto err_unlock;
542a980e046SJonathan Cameron 	}
543a980e046SJonathan Cameron 
54448e44ce0SLars-Peter Clausen 	ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW);
545a980e046SJonathan Cameron err_unlock:
546a980e046SJonathan Cameron 	mutex_unlock(&chan->indio_dev->info_exist_lock);
547a980e046SJonathan Cameron 
548a980e046SJonathan Cameron 	return ret;
549a980e046SJonathan Cameron }
550314be14bSJonathan Cameron EXPORT_SYMBOL_GPL(iio_read_channel_raw);
551a980e046SJonathan Cameron 
552476d4af2SSebastian Reichel int iio_read_channel_average_raw(struct iio_channel *chan, int *val)
553476d4af2SSebastian Reichel {
554476d4af2SSebastian Reichel 	int ret;
555476d4af2SSebastian Reichel 
556476d4af2SSebastian Reichel 	mutex_lock(&chan->indio_dev->info_exist_lock);
557476d4af2SSebastian Reichel 	if (chan->indio_dev->info == NULL) {
558476d4af2SSebastian Reichel 		ret = -ENODEV;
559476d4af2SSebastian Reichel 		goto err_unlock;
560476d4af2SSebastian Reichel 	}
561476d4af2SSebastian Reichel 
562476d4af2SSebastian Reichel 	ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_AVERAGE_RAW);
563476d4af2SSebastian Reichel err_unlock:
564476d4af2SSebastian Reichel 	mutex_unlock(&chan->indio_dev->info_exist_lock);
565476d4af2SSebastian Reichel 
566476d4af2SSebastian Reichel 	return ret;
567476d4af2SSebastian Reichel }
568476d4af2SSebastian Reichel EXPORT_SYMBOL_GPL(iio_read_channel_average_raw);
569476d4af2SSebastian Reichel 
57048e44ce0SLars-Peter Clausen static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan,
57148e44ce0SLars-Peter Clausen 	int raw, int *processed, unsigned int scale)
57248e44ce0SLars-Peter Clausen {
57348e44ce0SLars-Peter Clausen 	int scale_type, scale_val, scale_val2, offset;
57448e44ce0SLars-Peter Clausen 	s64 raw64 = raw;
57548e44ce0SLars-Peter Clausen 	int ret;
57648e44ce0SLars-Peter Clausen 
5776c5d4c96SMichael Hennerich 	ret = iio_channel_read(chan, &offset, NULL, IIO_CHAN_INFO_OFFSET);
578f91d1b63SAlexandre Belloni 	if (ret >= 0)
57948e44ce0SLars-Peter Clausen 		raw64 += offset;
58048e44ce0SLars-Peter Clausen 
58148e44ce0SLars-Peter Clausen 	scale_type = iio_channel_read(chan, &scale_val, &scale_val2,
58248e44ce0SLars-Peter Clausen 					IIO_CHAN_INFO_SCALE);
583adc8ec5fSLinus Walleij 	if (scale_type < 0) {
584adc8ec5fSLinus Walleij 		/*
585adc8ec5fSLinus Walleij 		 * Just pass raw values as processed if no scaling is
586adc8ec5fSLinus Walleij 		 * available.
587adc8ec5fSLinus Walleij 		 */
588adc8ec5fSLinus Walleij 		*processed = raw;
589adc8ec5fSLinus Walleij 		return 0;
590adc8ec5fSLinus Walleij 	}
59148e44ce0SLars-Peter Clausen 
59248e44ce0SLars-Peter Clausen 	switch (scale_type) {
59348e44ce0SLars-Peter Clausen 	case IIO_VAL_INT:
59448e44ce0SLars-Peter Clausen 		*processed = raw64 * scale_val;
59548e44ce0SLars-Peter Clausen 		break;
59648e44ce0SLars-Peter Clausen 	case IIO_VAL_INT_PLUS_MICRO:
59748e44ce0SLars-Peter Clausen 		if (scale_val2 < 0)
59848e44ce0SLars-Peter Clausen 			*processed = -raw64 * scale_val;
59948e44ce0SLars-Peter Clausen 		else
60048e44ce0SLars-Peter Clausen 			*processed = raw64 * scale_val;
60148e44ce0SLars-Peter Clausen 		*processed += div_s64(raw64 * (s64)scale_val2 * scale,
60248e44ce0SLars-Peter Clausen 				      1000000LL);
60348e44ce0SLars-Peter Clausen 		break;
60448e44ce0SLars-Peter Clausen 	case IIO_VAL_INT_PLUS_NANO:
60548e44ce0SLars-Peter Clausen 		if (scale_val2 < 0)
60648e44ce0SLars-Peter Clausen 			*processed = -raw64 * scale_val;
60748e44ce0SLars-Peter Clausen 		else
60848e44ce0SLars-Peter Clausen 			*processed = raw64 * scale_val;
60948e44ce0SLars-Peter Clausen 		*processed += div_s64(raw64 * (s64)scale_val2 * scale,
61048e44ce0SLars-Peter Clausen 				      1000000000LL);
61148e44ce0SLars-Peter Clausen 		break;
61248e44ce0SLars-Peter Clausen 	case IIO_VAL_FRACTIONAL:
61348e44ce0SLars-Peter Clausen 		*processed = div_s64(raw64 * (s64)scale_val * scale,
61448e44ce0SLars-Peter Clausen 				     scale_val2);
61548e44ce0SLars-Peter Clausen 		break;
616103d9fb9SLars-Peter Clausen 	case IIO_VAL_FRACTIONAL_LOG2:
617103d9fb9SLars-Peter Clausen 		*processed = (raw64 * (s64)scale_val * scale) >> scale_val2;
618103d9fb9SLars-Peter Clausen 		break;
61948e44ce0SLars-Peter Clausen 	default:
62048e44ce0SLars-Peter Clausen 		return -EINVAL;
62148e44ce0SLars-Peter Clausen 	}
62248e44ce0SLars-Peter Clausen 
62348e44ce0SLars-Peter Clausen 	return 0;
62448e44ce0SLars-Peter Clausen }
62548e44ce0SLars-Peter Clausen 
62648e44ce0SLars-Peter Clausen int iio_convert_raw_to_processed(struct iio_channel *chan, int raw,
62748e44ce0SLars-Peter Clausen 	int *processed, unsigned int scale)
62848e44ce0SLars-Peter Clausen {
62948e44ce0SLars-Peter Clausen 	int ret;
63048e44ce0SLars-Peter Clausen 
63148e44ce0SLars-Peter Clausen 	mutex_lock(&chan->indio_dev->info_exist_lock);
63248e44ce0SLars-Peter Clausen 	if (chan->indio_dev->info == NULL) {
63348e44ce0SLars-Peter Clausen 		ret = -ENODEV;
63448e44ce0SLars-Peter Clausen 		goto err_unlock;
63548e44ce0SLars-Peter Clausen 	}
63648e44ce0SLars-Peter Clausen 
63748e44ce0SLars-Peter Clausen 	ret = iio_convert_raw_to_processed_unlocked(chan, raw, processed,
63848e44ce0SLars-Peter Clausen 							scale);
63948e44ce0SLars-Peter Clausen err_unlock:
64048e44ce0SLars-Peter Clausen 	mutex_unlock(&chan->indio_dev->info_exist_lock);
64148e44ce0SLars-Peter Clausen 
64248e44ce0SLars-Peter Clausen 	return ret;
64348e44ce0SLars-Peter Clausen }
64448e44ce0SLars-Peter Clausen EXPORT_SYMBOL_GPL(iio_convert_raw_to_processed);
64548e44ce0SLars-Peter Clausen 
64634739a21SArnaud Pouliquen int iio_read_channel_attribute(struct iio_channel *chan, int *val, int *val2,
6470023e67dSMatt Ranostay 			       enum iio_chan_info_enum attribute)
6480023e67dSMatt Ranostay {
6490023e67dSMatt Ranostay 	int ret;
6500023e67dSMatt Ranostay 
6510023e67dSMatt Ranostay 	mutex_lock(&chan->indio_dev->info_exist_lock);
6520023e67dSMatt Ranostay 	if (chan->indio_dev->info == NULL) {
6530023e67dSMatt Ranostay 		ret = -ENODEV;
6540023e67dSMatt Ranostay 		goto err_unlock;
6550023e67dSMatt Ranostay 	}
6560023e67dSMatt Ranostay 
6570023e67dSMatt Ranostay 	ret = iio_channel_read(chan, val, val2, attribute);
6580023e67dSMatt Ranostay err_unlock:
6590023e67dSMatt Ranostay 	mutex_unlock(&chan->indio_dev->info_exist_lock);
6600023e67dSMatt Ranostay 
6610023e67dSMatt Ranostay 	return ret;
6620023e67dSMatt Ranostay }
66334739a21SArnaud Pouliquen EXPORT_SYMBOL_GPL(iio_read_channel_attribute);
6640023e67dSMatt Ranostay 
6650023e67dSMatt Ranostay int iio_read_channel_offset(struct iio_channel *chan, int *val, int *val2)
6660023e67dSMatt Ranostay {
6670023e67dSMatt Ranostay 	return iio_read_channel_attribute(chan, val, val2, IIO_CHAN_INFO_OFFSET);
6680023e67dSMatt Ranostay }
6690023e67dSMatt Ranostay EXPORT_SYMBOL_GPL(iio_read_channel_offset);
6700023e67dSMatt Ranostay 
67148e44ce0SLars-Peter Clausen int iio_read_channel_processed(struct iio_channel *chan, int *val)
67248e44ce0SLars-Peter Clausen {
67348e44ce0SLars-Peter Clausen 	int ret;
67448e44ce0SLars-Peter Clausen 
67548e44ce0SLars-Peter Clausen 	mutex_lock(&chan->indio_dev->info_exist_lock);
67648e44ce0SLars-Peter Clausen 	if (chan->indio_dev->info == NULL) {
67748e44ce0SLars-Peter Clausen 		ret = -ENODEV;
67848e44ce0SLars-Peter Clausen 		goto err_unlock;
67948e44ce0SLars-Peter Clausen 	}
68048e44ce0SLars-Peter Clausen 
68148e44ce0SLars-Peter Clausen 	if (iio_channel_has_info(chan->channel, IIO_CHAN_INFO_PROCESSED)) {
68248e44ce0SLars-Peter Clausen 		ret = iio_channel_read(chan, val, NULL,
68348e44ce0SLars-Peter Clausen 				       IIO_CHAN_INFO_PROCESSED);
68448e44ce0SLars-Peter Clausen 	} else {
68548e44ce0SLars-Peter Clausen 		ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW);
68648e44ce0SLars-Peter Clausen 		if (ret < 0)
68748e44ce0SLars-Peter Clausen 			goto err_unlock;
68848e44ce0SLars-Peter Clausen 		ret = iio_convert_raw_to_processed_unlocked(chan, *val, val, 1);
68948e44ce0SLars-Peter Clausen 	}
69048e44ce0SLars-Peter Clausen 
69148e44ce0SLars-Peter Clausen err_unlock:
69248e44ce0SLars-Peter Clausen 	mutex_unlock(&chan->indio_dev->info_exist_lock);
69348e44ce0SLars-Peter Clausen 
69448e44ce0SLars-Peter Clausen 	return ret;
69548e44ce0SLars-Peter Clausen }
69648e44ce0SLars-Peter Clausen EXPORT_SYMBOL_GPL(iio_read_channel_processed);
69748e44ce0SLars-Peter Clausen 
698314be14bSJonathan Cameron int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2)
699a980e046SJonathan Cameron {
7000023e67dSMatt Ranostay 	return iio_read_channel_attribute(chan, val, val2, IIO_CHAN_INFO_SCALE);
701a980e046SJonathan Cameron }
702314be14bSJonathan Cameron EXPORT_SYMBOL_GPL(iio_read_channel_scale);
703a980e046SJonathan Cameron 
70400c5f80cSPeter Rosin static int iio_channel_read_avail(struct iio_channel *chan,
70500c5f80cSPeter Rosin 				  const int **vals, int *type, int *length,
70600c5f80cSPeter Rosin 				  enum iio_chan_info_enum info)
70700c5f80cSPeter Rosin {
70800c5f80cSPeter Rosin 	if (!iio_channel_has_available(chan->channel, info))
70900c5f80cSPeter Rosin 		return -EINVAL;
71000c5f80cSPeter Rosin 
71100c5f80cSPeter Rosin 	return chan->indio_dev->info->read_avail(chan->indio_dev, chan->channel,
71200c5f80cSPeter Rosin 						 vals, type, length, info);
71300c5f80cSPeter Rosin }
71400c5f80cSPeter Rosin 
7159f421096SArtur Rojek int iio_read_avail_channel_attribute(struct iio_channel *chan,
7169f421096SArtur Rojek 				     const int **vals, int *type, int *length,
7179f421096SArtur Rojek 				     enum iio_chan_info_enum attribute)
7189f421096SArtur Rojek {
7199f421096SArtur Rojek 	int ret;
7209f421096SArtur Rojek 
7219f421096SArtur Rojek 	mutex_lock(&chan->indio_dev->info_exist_lock);
7229f421096SArtur Rojek 	if (!chan->indio_dev->info) {
7239f421096SArtur Rojek 		ret = -ENODEV;
7249f421096SArtur Rojek 		goto err_unlock;
7259f421096SArtur Rojek 	}
7269f421096SArtur Rojek 
7279f421096SArtur Rojek 	ret = iio_channel_read_avail(chan, vals, type, length, attribute);
7289f421096SArtur Rojek err_unlock:
7299f421096SArtur Rojek 	mutex_unlock(&chan->indio_dev->info_exist_lock);
7309f421096SArtur Rojek 
7319f421096SArtur Rojek 	return ret;
7329f421096SArtur Rojek }
7339f421096SArtur Rojek EXPORT_SYMBOL_GPL(iio_read_avail_channel_attribute);
7349f421096SArtur Rojek 
73500c5f80cSPeter Rosin int iio_read_avail_channel_raw(struct iio_channel *chan,
73600c5f80cSPeter Rosin 			       const int **vals, int *length)
73700c5f80cSPeter Rosin {
73800c5f80cSPeter Rosin 	int ret;
73900c5f80cSPeter Rosin 	int type;
74000c5f80cSPeter Rosin 
74189388ca4SArtur Rojek 	ret = iio_read_avail_channel_attribute(chan, vals, &type, length,
74289388ca4SArtur Rojek 					 IIO_CHAN_INFO_RAW);
74300c5f80cSPeter Rosin 
744c773f700SPeter Rosin 	if (ret >= 0 && type != IIO_VAL_INT)
74500c5f80cSPeter Rosin 		/* raw values are assumed to be IIO_VAL_INT */
74600c5f80cSPeter Rosin 		ret = -EINVAL;
74700c5f80cSPeter Rosin 
74800c5f80cSPeter Rosin 	return ret;
74900c5f80cSPeter Rosin }
75000c5f80cSPeter Rosin EXPORT_SYMBOL_GPL(iio_read_avail_channel_raw);
75100c5f80cSPeter Rosin 
75200c5f80cSPeter Rosin static int iio_channel_read_max(struct iio_channel *chan,
75300c5f80cSPeter Rosin 				int *val, int *val2, int *type,
75400c5f80cSPeter Rosin 				enum iio_chan_info_enum info)
75500c5f80cSPeter Rosin {
75600c5f80cSPeter Rosin 	int unused;
75700c5f80cSPeter Rosin 	const int *vals;
75800c5f80cSPeter Rosin 	int length;
75900c5f80cSPeter Rosin 	int ret;
76000c5f80cSPeter Rosin 
76100c5f80cSPeter Rosin 	if (!val2)
76200c5f80cSPeter Rosin 		val2 = &unused;
76300c5f80cSPeter Rosin 
76400c5f80cSPeter Rosin 	ret = iio_channel_read_avail(chan, &vals, type, &length, info);
76500c5f80cSPeter Rosin 	switch (ret) {
76600c5f80cSPeter Rosin 	case IIO_AVAIL_RANGE:
76700c5f80cSPeter Rosin 		switch (*type) {
76800c5f80cSPeter Rosin 		case IIO_VAL_INT:
76900c5f80cSPeter Rosin 			*val = vals[2];
77000c5f80cSPeter Rosin 			break;
77100c5f80cSPeter Rosin 		default:
77200c5f80cSPeter Rosin 			*val = vals[4];
77300c5f80cSPeter Rosin 			*val2 = vals[5];
77400c5f80cSPeter Rosin 		}
77500c5f80cSPeter Rosin 		return 0;
77600c5f80cSPeter Rosin 
77700c5f80cSPeter Rosin 	case IIO_AVAIL_LIST:
77800c5f80cSPeter Rosin 		if (length <= 0)
77900c5f80cSPeter Rosin 			return -EINVAL;
78000c5f80cSPeter Rosin 		switch (*type) {
78100c5f80cSPeter Rosin 		case IIO_VAL_INT:
78200c5f80cSPeter Rosin 			*val = vals[--length];
78300c5f80cSPeter Rosin 			while (length) {
78400c5f80cSPeter Rosin 				if (vals[--length] > *val)
78500c5f80cSPeter Rosin 					*val = vals[length];
78600c5f80cSPeter Rosin 			}
78700c5f80cSPeter Rosin 			break;
78800c5f80cSPeter Rosin 		default:
78900c5f80cSPeter Rosin 			/* FIXME: learn about max for other iio values */
79000c5f80cSPeter Rosin 			return -EINVAL;
79100c5f80cSPeter Rosin 		}
79200c5f80cSPeter Rosin 		return 0;
79300c5f80cSPeter Rosin 
79400c5f80cSPeter Rosin 	default:
79500c5f80cSPeter Rosin 		return ret;
79600c5f80cSPeter Rosin 	}
79700c5f80cSPeter Rosin }
79800c5f80cSPeter Rosin 
79900c5f80cSPeter Rosin int iio_read_max_channel_raw(struct iio_channel *chan, int *val)
80000c5f80cSPeter Rosin {
80100c5f80cSPeter Rosin 	int ret;
80200c5f80cSPeter Rosin 	int type;
80300c5f80cSPeter Rosin 
80400c5f80cSPeter Rosin 	mutex_lock(&chan->indio_dev->info_exist_lock);
80500c5f80cSPeter Rosin 	if (!chan->indio_dev->info) {
80600c5f80cSPeter Rosin 		ret = -ENODEV;
80700c5f80cSPeter Rosin 		goto err_unlock;
80800c5f80cSPeter Rosin 	}
80900c5f80cSPeter Rosin 
81000c5f80cSPeter Rosin 	ret = iio_channel_read_max(chan, val, NULL, &type, IIO_CHAN_INFO_RAW);
81100c5f80cSPeter Rosin err_unlock:
81200c5f80cSPeter Rosin 	mutex_unlock(&chan->indio_dev->info_exist_lock);
81300c5f80cSPeter Rosin 
81400c5f80cSPeter Rosin 	return ret;
81500c5f80cSPeter Rosin }
81600c5f80cSPeter Rosin EXPORT_SYMBOL_GPL(iio_read_max_channel_raw);
81700c5f80cSPeter Rosin 
818314be14bSJonathan Cameron int iio_get_channel_type(struct iio_channel *chan, enum iio_chan_type *type)
819a980e046SJonathan Cameron {
820a980e046SJonathan Cameron 	int ret = 0;
821a980e046SJonathan Cameron 	/* Need to verify underlying driver has not gone away */
822a980e046SJonathan Cameron 
823a980e046SJonathan Cameron 	mutex_lock(&chan->indio_dev->info_exist_lock);
824a980e046SJonathan Cameron 	if (chan->indio_dev->info == NULL) {
825a980e046SJonathan Cameron 		ret = -ENODEV;
826a980e046SJonathan Cameron 		goto err_unlock;
827a980e046SJonathan Cameron 	}
828a980e046SJonathan Cameron 
829a980e046SJonathan Cameron 	*type = chan->channel->type;
830a980e046SJonathan Cameron err_unlock:
831a980e046SJonathan Cameron 	mutex_unlock(&chan->indio_dev->info_exist_lock);
832a980e046SJonathan Cameron 
833a980e046SJonathan Cameron 	return ret;
834a980e046SJonathan Cameron }
835314be14bSJonathan Cameron EXPORT_SYMBOL_GPL(iio_get_channel_type);
836f9380e71SDmitry Eremin-Solenikov 
837f9380e71SDmitry Eremin-Solenikov static int iio_channel_write(struct iio_channel *chan, int val, int val2,
838f9380e71SDmitry Eremin-Solenikov 			     enum iio_chan_info_enum info)
839f9380e71SDmitry Eremin-Solenikov {
840f9380e71SDmitry Eremin-Solenikov 	return chan->indio_dev->info->write_raw(chan->indio_dev,
841f9380e71SDmitry Eremin-Solenikov 						chan->channel, val, val2, info);
842f9380e71SDmitry Eremin-Solenikov }
843f9380e71SDmitry Eremin-Solenikov 
84434739a21SArnaud Pouliquen int iio_write_channel_attribute(struct iio_channel *chan, int val, int val2,
84534739a21SArnaud Pouliquen 				enum iio_chan_info_enum attribute)
846f9380e71SDmitry Eremin-Solenikov {
847f9380e71SDmitry Eremin-Solenikov 	int ret;
848f9380e71SDmitry Eremin-Solenikov 
849f9380e71SDmitry Eremin-Solenikov 	mutex_lock(&chan->indio_dev->info_exist_lock);
850f9380e71SDmitry Eremin-Solenikov 	if (chan->indio_dev->info == NULL) {
851f9380e71SDmitry Eremin-Solenikov 		ret = -ENODEV;
852f9380e71SDmitry Eremin-Solenikov 		goto err_unlock;
853f9380e71SDmitry Eremin-Solenikov 	}
854f9380e71SDmitry Eremin-Solenikov 
85534739a21SArnaud Pouliquen 	ret = iio_channel_write(chan, val, val2, attribute);
856f9380e71SDmitry Eremin-Solenikov err_unlock:
857f9380e71SDmitry Eremin-Solenikov 	mutex_unlock(&chan->indio_dev->info_exist_lock);
858f9380e71SDmitry Eremin-Solenikov 
859f9380e71SDmitry Eremin-Solenikov 	return ret;
860f9380e71SDmitry Eremin-Solenikov }
86134739a21SArnaud Pouliquen EXPORT_SYMBOL_GPL(iio_write_channel_attribute);
86234739a21SArnaud Pouliquen 
86334739a21SArnaud Pouliquen int iio_write_channel_raw(struct iio_channel *chan, int val)
86434739a21SArnaud Pouliquen {
86534739a21SArnaud Pouliquen 	return iio_write_channel_attribute(chan, val, 0, IIO_CHAN_INFO_RAW);
86634739a21SArnaud Pouliquen }
867f9380e71SDmitry Eremin-Solenikov EXPORT_SYMBOL_GPL(iio_write_channel_raw);
8688a848e75SPeter Rosin 
8698a848e75SPeter Rosin unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan)
8708a848e75SPeter Rosin {
8718a848e75SPeter Rosin 	const struct iio_chan_spec_ext_info *ext_info;
8728a848e75SPeter Rosin 	unsigned int i = 0;
8738a848e75SPeter Rosin 
8748a848e75SPeter Rosin 	if (!chan->channel->ext_info)
8758a848e75SPeter Rosin 		return i;
8768a848e75SPeter Rosin 
8778a848e75SPeter Rosin 	for (ext_info = chan->channel->ext_info; ext_info->name; ext_info++)
8788a848e75SPeter Rosin 		++i;
8798a848e75SPeter Rosin 
8808a848e75SPeter Rosin 	return i;
8818a848e75SPeter Rosin }
8828a848e75SPeter Rosin EXPORT_SYMBOL_GPL(iio_get_channel_ext_info_count);
8838a848e75SPeter Rosin 
8848a848e75SPeter Rosin static const struct iio_chan_spec_ext_info *iio_lookup_ext_info(
8858a848e75SPeter Rosin 						const struct iio_channel *chan,
8868a848e75SPeter Rosin 						const char *attr)
8878a848e75SPeter Rosin {
8888a848e75SPeter Rosin 	const struct iio_chan_spec_ext_info *ext_info;
8898a848e75SPeter Rosin 
8908a848e75SPeter Rosin 	if (!chan->channel->ext_info)
8918a848e75SPeter Rosin 		return NULL;
8928a848e75SPeter Rosin 
8938a848e75SPeter Rosin 	for (ext_info = chan->channel->ext_info; ext_info->name; ++ext_info) {
8948a848e75SPeter Rosin 		if (!strcmp(attr, ext_info->name))
8958a848e75SPeter Rosin 			return ext_info;
8968a848e75SPeter Rosin 	}
8978a848e75SPeter Rosin 
8988a848e75SPeter Rosin 	return NULL;
8998a848e75SPeter Rosin }
9008a848e75SPeter Rosin 
9018a848e75SPeter Rosin ssize_t iio_read_channel_ext_info(struct iio_channel *chan,
9028a848e75SPeter Rosin 				  const char *attr, char *buf)
9038a848e75SPeter Rosin {
9048a848e75SPeter Rosin 	const struct iio_chan_spec_ext_info *ext_info;
9058a848e75SPeter Rosin 
9068a848e75SPeter Rosin 	ext_info = iio_lookup_ext_info(chan, attr);
9078a848e75SPeter Rosin 	if (!ext_info)
9088a848e75SPeter Rosin 		return -EINVAL;
9098a848e75SPeter Rosin 
9108a848e75SPeter Rosin 	return ext_info->read(chan->indio_dev, ext_info->private,
9118a848e75SPeter Rosin 			      chan->channel, buf);
9128a848e75SPeter Rosin }
9138a848e75SPeter Rosin EXPORT_SYMBOL_GPL(iio_read_channel_ext_info);
9148a848e75SPeter Rosin 
9158a848e75SPeter Rosin ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr,
9168a848e75SPeter Rosin 				   const char *buf, size_t len)
9178a848e75SPeter Rosin {
9188a848e75SPeter Rosin 	const struct iio_chan_spec_ext_info *ext_info;
9198a848e75SPeter Rosin 
9208a848e75SPeter Rosin 	ext_info = iio_lookup_ext_info(chan, attr);
9218a848e75SPeter Rosin 	if (!ext_info)
9228a848e75SPeter Rosin 		return -EINVAL;
9238a848e75SPeter Rosin 
9248a848e75SPeter Rosin 	return ext_info->write(chan->indio_dev, ext_info->private,
9258a848e75SPeter Rosin 			       chan->channel, buf, len);
9268a848e75SPeter Rosin }
9278a848e75SPeter Rosin EXPORT_SYMBOL_GPL(iio_write_channel_ext_info);
928