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