1a980e046SJonathan Cameron /* The industrial I/O core in kernel channel mapping 2a980e046SJonathan Cameron * 3a980e046SJonathan Cameron * Copyright (c) 2011 Jonathan Cameron 4a980e046SJonathan Cameron * 5a980e046SJonathan Cameron * This program is free software; you can redistribute it and/or modify it 6a980e046SJonathan Cameron * under the terms of the GNU General Public License version 2 as published by 7a980e046SJonathan Cameron * the Free Software Foundation. 8a980e046SJonathan Cameron */ 9a980e046SJonathan Cameron #include <linux/err.h> 10a980e046SJonathan Cameron #include <linux/export.h> 11a980e046SJonathan Cameron #include <linux/slab.h> 12a980e046SJonathan Cameron #include <linux/mutex.h> 1317d82b47SGuenter Roeck #include <linux/of.h> 14a980e046SJonathan Cameron 15a980e046SJonathan Cameron #include <linux/iio/iio.h> 16a980e046SJonathan Cameron #include "iio_core.h" 17a980e046SJonathan Cameron #include <linux/iio/machine.h> 18a980e046SJonathan Cameron #include <linux/iio/driver.h> 19a980e046SJonathan Cameron #include <linux/iio/consumer.h> 20a980e046SJonathan Cameron 21a980e046SJonathan Cameron struct iio_map_internal { 22a980e046SJonathan Cameron struct iio_dev *indio_dev; 23a980e046SJonathan Cameron struct iio_map *map; 24a980e046SJonathan Cameron struct list_head l; 25a980e046SJonathan Cameron }; 26a980e046SJonathan Cameron 27a980e046SJonathan Cameron static LIST_HEAD(iio_map_list); 28a980e046SJonathan Cameron static DEFINE_MUTEX(iio_map_list_lock); 29a980e046SJonathan Cameron 30a980e046SJonathan Cameron int iio_map_array_register(struct iio_dev *indio_dev, struct iio_map *maps) 31a980e046SJonathan Cameron { 32a980e046SJonathan Cameron int i = 0, ret = 0; 33a980e046SJonathan Cameron struct iio_map_internal *mapi; 34a980e046SJonathan Cameron 35a980e046SJonathan Cameron if (maps == NULL) 36a980e046SJonathan Cameron return 0; 37a980e046SJonathan Cameron 38a980e046SJonathan Cameron mutex_lock(&iio_map_list_lock); 39a980e046SJonathan Cameron while (maps[i].consumer_dev_name != NULL) { 40a980e046SJonathan Cameron mapi = kzalloc(sizeof(*mapi), GFP_KERNEL); 41a980e046SJonathan Cameron if (mapi == NULL) { 42a980e046SJonathan Cameron ret = -ENOMEM; 43a980e046SJonathan Cameron goto error_ret; 44a980e046SJonathan Cameron } 45a980e046SJonathan Cameron mapi->map = &maps[i]; 46a980e046SJonathan Cameron mapi->indio_dev = indio_dev; 47a980e046SJonathan Cameron list_add(&mapi->l, &iio_map_list); 48a980e046SJonathan Cameron i++; 49a980e046SJonathan Cameron } 50a980e046SJonathan Cameron error_ret: 51a980e046SJonathan Cameron mutex_unlock(&iio_map_list_lock); 52a980e046SJonathan Cameron 53a980e046SJonathan Cameron return ret; 54a980e046SJonathan Cameron } 55a980e046SJonathan Cameron EXPORT_SYMBOL_GPL(iio_map_array_register); 56a980e046SJonathan Cameron 57a980e046SJonathan Cameron 586cb2afd7SGuenter Roeck /* 596cb2afd7SGuenter Roeck * Remove all map entries associated with the given iio device 60a980e046SJonathan Cameron */ 616cb2afd7SGuenter Roeck int iio_map_array_unregister(struct iio_dev *indio_dev) 62a980e046SJonathan Cameron { 636cb2afd7SGuenter Roeck int ret = -ENODEV; 64a980e046SJonathan Cameron struct iio_map_internal *mapi; 656cb2afd7SGuenter Roeck struct list_head *pos, *tmp; 66a980e046SJonathan Cameron 67a980e046SJonathan Cameron mutex_lock(&iio_map_list_lock); 686cb2afd7SGuenter Roeck list_for_each_safe(pos, tmp, &iio_map_list) { 696cb2afd7SGuenter Roeck mapi = list_entry(pos, struct iio_map_internal, l); 706cb2afd7SGuenter Roeck if (indio_dev == mapi->indio_dev) { 71a980e046SJonathan Cameron list_del(&mapi->l); 72a980e046SJonathan Cameron kfree(mapi); 736cb2afd7SGuenter Roeck ret = 0; 74a980e046SJonathan Cameron } 75a980e046SJonathan Cameron } 76a980e046SJonathan Cameron mutex_unlock(&iio_map_list_lock); 77a980e046SJonathan Cameron return ret; 78a980e046SJonathan Cameron } 79a980e046SJonathan Cameron EXPORT_SYMBOL_GPL(iio_map_array_unregister); 80a980e046SJonathan Cameron 81a980e046SJonathan Cameron static const struct iio_chan_spec 82314be14bSJonathan Cameron *iio_chan_spec_from_name(const struct iio_dev *indio_dev, const char *name) 83a980e046SJonathan Cameron { 84a980e046SJonathan Cameron int i; 85a980e046SJonathan Cameron const struct iio_chan_spec *chan = NULL; 86a980e046SJonathan Cameron 87a980e046SJonathan Cameron for (i = 0; i < indio_dev->num_channels; i++) 88a980e046SJonathan Cameron if (indio_dev->channels[i].datasheet_name && 89a980e046SJonathan Cameron strcmp(name, indio_dev->channels[i].datasheet_name) == 0) { 90a980e046SJonathan Cameron chan = &indio_dev->channels[i]; 91a980e046SJonathan Cameron break; 92a980e046SJonathan Cameron } 93a980e046SJonathan Cameron return chan; 94a980e046SJonathan Cameron } 95a980e046SJonathan Cameron 9617d82b47SGuenter Roeck #ifdef CONFIG_OF 9717d82b47SGuenter Roeck 9817d82b47SGuenter Roeck static int iio_dev_node_match(struct device *dev, void *data) 9917d82b47SGuenter Roeck { 10017d82b47SGuenter Roeck return dev->of_node == data && dev->type == &iio_device_type; 10117d82b47SGuenter Roeck } 10217d82b47SGuenter Roeck 10317d82b47SGuenter Roeck static int __of_iio_channel_get(struct iio_channel *channel, 10417d82b47SGuenter Roeck struct device_node *np, int index) 10517d82b47SGuenter Roeck { 10617d82b47SGuenter Roeck struct device *idev; 10717d82b47SGuenter Roeck struct iio_dev *indio_dev; 10817d82b47SGuenter Roeck int err; 10917d82b47SGuenter Roeck struct of_phandle_args iiospec; 11017d82b47SGuenter Roeck 11117d82b47SGuenter Roeck err = of_parse_phandle_with_args(np, "io-channels", 11217d82b47SGuenter Roeck "#io-channel-cells", 11317d82b47SGuenter Roeck index, &iiospec); 11417d82b47SGuenter Roeck if (err) 11517d82b47SGuenter Roeck return err; 11617d82b47SGuenter Roeck 11717d82b47SGuenter Roeck idev = bus_find_device(&iio_bus_type, NULL, iiospec.np, 11817d82b47SGuenter Roeck iio_dev_node_match); 11917d82b47SGuenter Roeck of_node_put(iiospec.np); 12017d82b47SGuenter Roeck if (idev == NULL) 12117d82b47SGuenter Roeck return -EPROBE_DEFER; 12217d82b47SGuenter Roeck 12317d82b47SGuenter Roeck indio_dev = dev_to_iio_dev(idev); 12417d82b47SGuenter Roeck channel->indio_dev = indio_dev; 12517d82b47SGuenter Roeck index = iiospec.args_count ? iiospec.args[0] : 0; 12617d82b47SGuenter Roeck if (index >= indio_dev->num_channels) { 127e916b80dSJoe Perches err = -EINVAL; 12817d82b47SGuenter Roeck goto err_put; 12917d82b47SGuenter Roeck } 13017d82b47SGuenter Roeck channel->channel = &indio_dev->channels[index]; 13117d82b47SGuenter Roeck 13217d82b47SGuenter Roeck return 0; 13317d82b47SGuenter Roeck 13417d82b47SGuenter Roeck err_put: 13517d82b47SGuenter Roeck iio_device_put(indio_dev); 13617d82b47SGuenter Roeck return err; 13717d82b47SGuenter Roeck } 13817d82b47SGuenter Roeck 13917d82b47SGuenter Roeck static struct iio_channel *of_iio_channel_get(struct device_node *np, int index) 14017d82b47SGuenter Roeck { 14117d82b47SGuenter Roeck struct iio_channel *channel; 14217d82b47SGuenter Roeck int err; 14317d82b47SGuenter Roeck 14417d82b47SGuenter Roeck if (index < 0) 14517d82b47SGuenter Roeck return ERR_PTR(-EINVAL); 14617d82b47SGuenter Roeck 14717d82b47SGuenter Roeck channel = kzalloc(sizeof(*channel), GFP_KERNEL); 14817d82b47SGuenter Roeck if (channel == NULL) 14917d82b47SGuenter Roeck return ERR_PTR(-ENOMEM); 15017d82b47SGuenter Roeck 15117d82b47SGuenter Roeck err = __of_iio_channel_get(channel, np, index); 15217d82b47SGuenter Roeck if (err) 15317d82b47SGuenter Roeck goto err_free_channel; 15417d82b47SGuenter Roeck 15517d82b47SGuenter Roeck return channel; 15617d82b47SGuenter Roeck 15717d82b47SGuenter Roeck err_free_channel: 15817d82b47SGuenter Roeck kfree(channel); 15917d82b47SGuenter Roeck return ERR_PTR(err); 16017d82b47SGuenter Roeck } 16117d82b47SGuenter Roeck 16217d82b47SGuenter Roeck static struct iio_channel *of_iio_channel_get_by_name(struct device_node *np, 16317d82b47SGuenter Roeck const char *name) 16417d82b47SGuenter Roeck { 16517d82b47SGuenter Roeck struct iio_channel *chan = NULL; 16617d82b47SGuenter Roeck 16717d82b47SGuenter Roeck /* Walk up the tree of devices looking for a matching iio channel */ 16817d82b47SGuenter Roeck while (np) { 16917d82b47SGuenter Roeck int index = 0; 17017d82b47SGuenter Roeck 17117d82b47SGuenter Roeck /* 17217d82b47SGuenter Roeck * For named iio channels, first look up the name in the 17317d82b47SGuenter Roeck * "io-channel-names" property. If it cannot be found, the 17417d82b47SGuenter Roeck * index will be an error code, and of_iio_channel_get() 17517d82b47SGuenter Roeck * will fail. 17617d82b47SGuenter Roeck */ 17717d82b47SGuenter Roeck if (name) 17817d82b47SGuenter Roeck index = of_property_match_string(np, "io-channel-names", 17917d82b47SGuenter Roeck name); 18017d82b47SGuenter Roeck chan = of_iio_channel_get(np, index); 18117d82b47SGuenter Roeck if (!IS_ERR(chan)) 18217d82b47SGuenter Roeck break; 18317d82b47SGuenter Roeck else if (name && index >= 0) { 18417d82b47SGuenter Roeck pr_err("ERROR: could not get IIO channel %s:%s(%i)\n", 18517d82b47SGuenter Roeck np->full_name, name ? name : "", index); 18617d82b47SGuenter Roeck return chan; 18717d82b47SGuenter Roeck } 18817d82b47SGuenter Roeck 18917d82b47SGuenter Roeck /* 19017d82b47SGuenter Roeck * No matching IIO channel found on this node. 19117d82b47SGuenter Roeck * If the parent node has a "io-channel-ranges" property, 19217d82b47SGuenter Roeck * then we can try one of its channels. 19317d82b47SGuenter Roeck */ 19417d82b47SGuenter Roeck np = np->parent; 19517d82b47SGuenter Roeck if (np && !of_get_property(np, "io-channel-ranges", NULL)) 19617d82b47SGuenter Roeck break; 19717d82b47SGuenter Roeck } 19817d82b47SGuenter Roeck return chan; 19917d82b47SGuenter Roeck } 20017d82b47SGuenter Roeck 20117d82b47SGuenter Roeck static struct iio_channel *of_iio_channel_get_all(struct device *dev) 20217d82b47SGuenter Roeck { 20317d82b47SGuenter Roeck struct iio_channel *chans; 20417d82b47SGuenter Roeck int i, mapind, nummaps = 0; 20517d82b47SGuenter Roeck int ret; 20617d82b47SGuenter Roeck 20717d82b47SGuenter Roeck do { 20817d82b47SGuenter Roeck ret = of_parse_phandle_with_args(dev->of_node, 20917d82b47SGuenter Roeck "io-channels", 21017d82b47SGuenter Roeck "#io-channel-cells", 21117d82b47SGuenter Roeck nummaps, NULL); 21217d82b47SGuenter Roeck if (ret < 0) 21317d82b47SGuenter Roeck break; 21417d82b47SGuenter Roeck } while (++nummaps); 21517d82b47SGuenter Roeck 21617d82b47SGuenter Roeck if (nummaps == 0) /* no error, return NULL to search map table */ 21717d82b47SGuenter Roeck return NULL; 21817d82b47SGuenter Roeck 21917d82b47SGuenter Roeck /* NULL terminated array to save passing size */ 22017d82b47SGuenter Roeck chans = kcalloc(nummaps + 1, sizeof(*chans), GFP_KERNEL); 22117d82b47SGuenter Roeck if (chans == NULL) 22217d82b47SGuenter Roeck return ERR_PTR(-ENOMEM); 22317d82b47SGuenter Roeck 22417d82b47SGuenter Roeck /* Search for OF matches */ 22517d82b47SGuenter Roeck for (mapind = 0; mapind < nummaps; mapind++) { 22617d82b47SGuenter Roeck ret = __of_iio_channel_get(&chans[mapind], dev->of_node, 22717d82b47SGuenter Roeck mapind); 22817d82b47SGuenter Roeck if (ret) 22917d82b47SGuenter Roeck goto error_free_chans; 23017d82b47SGuenter Roeck } 23117d82b47SGuenter Roeck return chans; 23217d82b47SGuenter Roeck 23317d82b47SGuenter Roeck error_free_chans: 23417d82b47SGuenter Roeck for (i = 0; i < mapind; i++) 23517d82b47SGuenter Roeck iio_device_put(chans[i].indio_dev); 23617d82b47SGuenter Roeck kfree(chans); 23717d82b47SGuenter Roeck return ERR_PTR(ret); 23817d82b47SGuenter Roeck } 23917d82b47SGuenter Roeck 24017d82b47SGuenter Roeck #else /* CONFIG_OF */ 24117d82b47SGuenter Roeck 24217d82b47SGuenter Roeck static inline struct iio_channel * 24317d82b47SGuenter Roeck of_iio_channel_get_by_name(struct device_node *np, const char *name) 24417d82b47SGuenter Roeck { 24517d82b47SGuenter Roeck return NULL; 24617d82b47SGuenter Roeck } 24717d82b47SGuenter Roeck 24817d82b47SGuenter Roeck static inline struct iio_channel *of_iio_channel_get_all(struct device *dev) 24917d82b47SGuenter Roeck { 25017d82b47SGuenter Roeck return NULL; 25117d82b47SGuenter Roeck } 25217d82b47SGuenter Roeck 25317d82b47SGuenter Roeck #endif /* CONFIG_OF */ 254a980e046SJonathan Cameron 2555aa57f0aSGuenter Roeck static struct iio_channel *iio_channel_get_sys(const char *name, 2565aa57f0aSGuenter Roeck const char *channel_name) 257a980e046SJonathan Cameron { 258a980e046SJonathan Cameron struct iio_map_internal *c_i = NULL, *c = NULL; 259a980e046SJonathan Cameron struct iio_channel *channel; 2603183bac1SKim, Milo int err; 261a980e046SJonathan Cameron 262a980e046SJonathan Cameron if (name == NULL && channel_name == NULL) 263a980e046SJonathan Cameron return ERR_PTR(-ENODEV); 264a980e046SJonathan Cameron 265a980e046SJonathan Cameron /* first find matching entry the channel map */ 266a980e046SJonathan Cameron mutex_lock(&iio_map_list_lock); 267a980e046SJonathan Cameron list_for_each_entry(c_i, &iio_map_list, l) { 268a980e046SJonathan Cameron if ((name && strcmp(name, c_i->map->consumer_dev_name) != 0) || 269a980e046SJonathan Cameron (channel_name && 270a980e046SJonathan Cameron strcmp(channel_name, c_i->map->consumer_channel) != 0)) 271a980e046SJonathan Cameron continue; 272a980e046SJonathan Cameron c = c_i; 2731875ffd2SLars-Peter Clausen iio_device_get(c->indio_dev); 274a980e046SJonathan Cameron break; 275a980e046SJonathan Cameron } 276a980e046SJonathan Cameron mutex_unlock(&iio_map_list_lock); 277a980e046SJonathan Cameron if (c == NULL) 278a980e046SJonathan Cameron return ERR_PTR(-ENODEV); 279a980e046SJonathan Cameron 2802cc412b5SKim, Milo channel = kzalloc(sizeof(*channel), GFP_KERNEL); 2813183bac1SKim, Milo if (channel == NULL) { 2823183bac1SKim, Milo err = -ENOMEM; 283801c4b5cSKim, Milo goto error_no_mem; 2843183bac1SKim, Milo } 285a980e046SJonathan Cameron 286a980e046SJonathan Cameron channel->indio_dev = c->indio_dev; 287a980e046SJonathan Cameron 288b2b79ffaSKim, Milo if (c->map->adc_channel_label) { 289a980e046SJonathan Cameron channel->channel = 290a980e046SJonathan Cameron iio_chan_spec_from_name(channel->indio_dev, 291a980e046SJonathan Cameron c->map->adc_channel_label); 292a980e046SJonathan Cameron 2933183bac1SKim, Milo if (channel->channel == NULL) { 2943183bac1SKim, Milo err = -EINVAL; 295b2b79ffaSKim, Milo goto error_no_chan; 296b2b79ffaSKim, Milo } 2973183bac1SKim, Milo } 298b2b79ffaSKim, Milo 299a980e046SJonathan Cameron return channel; 300b2b79ffaSKim, Milo 301b2b79ffaSKim, Milo error_no_chan: 302b2b79ffaSKim, Milo kfree(channel); 303801c4b5cSKim, Milo error_no_mem: 304801c4b5cSKim, Milo iio_device_put(c->indio_dev); 3053183bac1SKim, Milo return ERR_PTR(err); 306a980e046SJonathan Cameron } 3075aa57f0aSGuenter Roeck 3085aa57f0aSGuenter Roeck struct iio_channel *iio_channel_get(struct device *dev, 3095aa57f0aSGuenter Roeck const char *channel_name) 3105aa57f0aSGuenter Roeck { 3115aa57f0aSGuenter Roeck const char *name = dev ? dev_name(dev) : NULL; 31217d82b47SGuenter Roeck struct iio_channel *channel; 3135aa57f0aSGuenter Roeck 31417d82b47SGuenter Roeck if (dev) { 31517d82b47SGuenter Roeck channel = of_iio_channel_get_by_name(dev->of_node, 31617d82b47SGuenter Roeck channel_name); 31717d82b47SGuenter Roeck if (channel != NULL) 31817d82b47SGuenter Roeck return channel; 31917d82b47SGuenter Roeck } 3205aa57f0aSGuenter Roeck return iio_channel_get_sys(name, channel_name); 3215aa57f0aSGuenter Roeck } 322314be14bSJonathan Cameron EXPORT_SYMBOL_GPL(iio_channel_get); 323a980e046SJonathan Cameron 324314be14bSJonathan Cameron void iio_channel_release(struct iio_channel *channel) 325a980e046SJonathan Cameron { 3261875ffd2SLars-Peter Clausen iio_device_put(channel->indio_dev); 327a980e046SJonathan Cameron kfree(channel); 328a980e046SJonathan Cameron } 329314be14bSJonathan Cameron EXPORT_SYMBOL_GPL(iio_channel_release); 330a980e046SJonathan Cameron 331ca7d98dbSGuenter Roeck struct iio_channel *iio_channel_get_all(struct device *dev) 332a980e046SJonathan Cameron { 333ca7d98dbSGuenter Roeck const char *name; 334a980e046SJonathan Cameron struct iio_channel *chans; 335a980e046SJonathan Cameron struct iio_map_internal *c = NULL; 336a980e046SJonathan Cameron int nummaps = 0; 337a980e046SJonathan Cameron int mapind = 0; 338a980e046SJonathan Cameron int i, ret; 339a980e046SJonathan Cameron 340ca7d98dbSGuenter Roeck if (dev == NULL) 341a980e046SJonathan Cameron return ERR_PTR(-EINVAL); 34217d82b47SGuenter Roeck 34317d82b47SGuenter Roeck chans = of_iio_channel_get_all(dev); 34417d82b47SGuenter Roeck if (chans) 34517d82b47SGuenter Roeck return chans; 34617d82b47SGuenter Roeck 347ca7d98dbSGuenter Roeck name = dev_name(dev); 348a980e046SJonathan Cameron 349a980e046SJonathan Cameron mutex_lock(&iio_map_list_lock); 350a980e046SJonathan Cameron /* first count the matching maps */ 351a980e046SJonathan Cameron list_for_each_entry(c, &iio_map_list, l) 352a980e046SJonathan Cameron if (name && strcmp(name, c->map->consumer_dev_name) != 0) 353a980e046SJonathan Cameron continue; 354a980e046SJonathan Cameron else 355a980e046SJonathan Cameron nummaps++; 356a980e046SJonathan Cameron 357a980e046SJonathan Cameron if (nummaps == 0) { 358a980e046SJonathan Cameron ret = -ENODEV; 359a980e046SJonathan Cameron goto error_ret; 360a980e046SJonathan Cameron } 361a980e046SJonathan Cameron 362a980e046SJonathan Cameron /* NULL terminated array to save passing size */ 363a980e046SJonathan Cameron chans = kzalloc(sizeof(*chans)*(nummaps + 1), GFP_KERNEL); 364a980e046SJonathan Cameron if (chans == NULL) { 365a980e046SJonathan Cameron ret = -ENOMEM; 366a980e046SJonathan Cameron goto error_ret; 367a980e046SJonathan Cameron } 368a980e046SJonathan Cameron 369a980e046SJonathan Cameron /* for each map fill in the chans element */ 370a980e046SJonathan Cameron list_for_each_entry(c, &iio_map_list, l) { 371a980e046SJonathan Cameron if (name && strcmp(name, c->map->consumer_dev_name) != 0) 372a980e046SJonathan Cameron continue; 373a980e046SJonathan Cameron chans[mapind].indio_dev = c->indio_dev; 3740464415dSJonathan Cameron chans[mapind].data = c->map->consumer_data; 375a980e046SJonathan Cameron chans[mapind].channel = 376a980e046SJonathan Cameron iio_chan_spec_from_name(chans[mapind].indio_dev, 377a980e046SJonathan Cameron c->map->adc_channel_label); 378a980e046SJonathan Cameron if (chans[mapind].channel == NULL) { 379a980e046SJonathan Cameron ret = -EINVAL; 380a980e046SJonathan Cameron goto error_free_chans; 381a980e046SJonathan Cameron } 3821875ffd2SLars-Peter Clausen iio_device_get(chans[mapind].indio_dev); 383a980e046SJonathan Cameron mapind++; 384a980e046SJonathan Cameron } 385a980e046SJonathan Cameron if (mapind == 0) { 386a980e046SJonathan Cameron ret = -ENODEV; 387a980e046SJonathan Cameron goto error_free_chans; 388a980e046SJonathan Cameron } 389e59b9afeSDan Carpenter mutex_unlock(&iio_map_list_lock); 390e59b9afeSDan Carpenter 391a980e046SJonathan Cameron return chans; 392a980e046SJonathan Cameron 393a980e046SJonathan Cameron error_free_chans: 394a980e046SJonathan Cameron for (i = 0; i < nummaps; i++) 3951875ffd2SLars-Peter Clausen iio_device_put(chans[i].indio_dev); 396a980e046SJonathan Cameron kfree(chans); 397a980e046SJonathan Cameron error_ret: 398a980e046SJonathan Cameron mutex_unlock(&iio_map_list_lock); 399a980e046SJonathan Cameron 400a980e046SJonathan Cameron return ERR_PTR(ret); 401a980e046SJonathan Cameron } 402314be14bSJonathan Cameron EXPORT_SYMBOL_GPL(iio_channel_get_all); 403a980e046SJonathan Cameron 404314be14bSJonathan Cameron void iio_channel_release_all(struct iio_channel *channels) 405a980e046SJonathan Cameron { 406a980e046SJonathan Cameron struct iio_channel *chan = &channels[0]; 407a980e046SJonathan Cameron 408a980e046SJonathan Cameron while (chan->indio_dev) { 4091875ffd2SLars-Peter Clausen iio_device_put(chan->indio_dev); 410a980e046SJonathan Cameron chan++; 411a980e046SJonathan Cameron } 412a980e046SJonathan Cameron kfree(channels); 413a980e046SJonathan Cameron } 414314be14bSJonathan Cameron EXPORT_SYMBOL_GPL(iio_channel_release_all); 415a980e046SJonathan Cameron 41648e44ce0SLars-Peter Clausen static int iio_channel_read(struct iio_channel *chan, int *val, int *val2, 41748e44ce0SLars-Peter Clausen enum iio_chan_info_enum info) 41848e44ce0SLars-Peter Clausen { 41948e44ce0SLars-Peter Clausen int unused; 42048e44ce0SLars-Peter Clausen 42148e44ce0SLars-Peter Clausen if (val2 == NULL) 42248e44ce0SLars-Peter Clausen val2 = &unused; 42348e44ce0SLars-Peter Clausen 42448e44ce0SLars-Peter Clausen return chan->indio_dev->info->read_raw(chan->indio_dev, chan->channel, 42548e44ce0SLars-Peter Clausen val, val2, info); 42648e44ce0SLars-Peter Clausen } 42748e44ce0SLars-Peter Clausen 428314be14bSJonathan Cameron int iio_read_channel_raw(struct iio_channel *chan, int *val) 429a980e046SJonathan Cameron { 43048e44ce0SLars-Peter Clausen int ret; 431a980e046SJonathan Cameron 432a980e046SJonathan Cameron mutex_lock(&chan->indio_dev->info_exist_lock); 433a980e046SJonathan Cameron if (chan->indio_dev->info == NULL) { 434a980e046SJonathan Cameron ret = -ENODEV; 435a980e046SJonathan Cameron goto err_unlock; 436a980e046SJonathan Cameron } 437a980e046SJonathan Cameron 43848e44ce0SLars-Peter Clausen ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW); 439a980e046SJonathan Cameron err_unlock: 440a980e046SJonathan Cameron mutex_unlock(&chan->indio_dev->info_exist_lock); 441a980e046SJonathan Cameron 442a980e046SJonathan Cameron return ret; 443a980e046SJonathan Cameron } 444314be14bSJonathan Cameron EXPORT_SYMBOL_GPL(iio_read_channel_raw); 445a980e046SJonathan Cameron 44648e44ce0SLars-Peter Clausen static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan, 44748e44ce0SLars-Peter Clausen int raw, int *processed, unsigned int scale) 44848e44ce0SLars-Peter Clausen { 44948e44ce0SLars-Peter Clausen int scale_type, scale_val, scale_val2, offset; 45048e44ce0SLars-Peter Clausen s64 raw64 = raw; 45148e44ce0SLars-Peter Clausen int ret; 45248e44ce0SLars-Peter Clausen 45348e44ce0SLars-Peter Clausen ret = iio_channel_read(chan, &offset, NULL, IIO_CHAN_INFO_SCALE); 45448e44ce0SLars-Peter Clausen if (ret == 0) 45548e44ce0SLars-Peter Clausen raw64 += offset; 45648e44ce0SLars-Peter Clausen 45748e44ce0SLars-Peter Clausen scale_type = iio_channel_read(chan, &scale_val, &scale_val2, 45848e44ce0SLars-Peter Clausen IIO_CHAN_INFO_SCALE); 45948e44ce0SLars-Peter Clausen if (scale_type < 0) 46048e44ce0SLars-Peter Clausen return scale_type; 46148e44ce0SLars-Peter Clausen 46248e44ce0SLars-Peter Clausen switch (scale_type) { 46348e44ce0SLars-Peter Clausen case IIO_VAL_INT: 46448e44ce0SLars-Peter Clausen *processed = raw64 * scale_val; 46548e44ce0SLars-Peter Clausen break; 46648e44ce0SLars-Peter Clausen case IIO_VAL_INT_PLUS_MICRO: 46748e44ce0SLars-Peter Clausen if (scale_val2 < 0) 46848e44ce0SLars-Peter Clausen *processed = -raw64 * scale_val; 46948e44ce0SLars-Peter Clausen else 47048e44ce0SLars-Peter Clausen *processed = raw64 * scale_val; 47148e44ce0SLars-Peter Clausen *processed += div_s64(raw64 * (s64)scale_val2 * scale, 47248e44ce0SLars-Peter Clausen 1000000LL); 47348e44ce0SLars-Peter Clausen break; 47448e44ce0SLars-Peter Clausen case IIO_VAL_INT_PLUS_NANO: 47548e44ce0SLars-Peter Clausen if (scale_val2 < 0) 47648e44ce0SLars-Peter Clausen *processed = -raw64 * scale_val; 47748e44ce0SLars-Peter Clausen else 47848e44ce0SLars-Peter Clausen *processed = raw64 * scale_val; 47948e44ce0SLars-Peter Clausen *processed += div_s64(raw64 * (s64)scale_val2 * scale, 48048e44ce0SLars-Peter Clausen 1000000000LL); 48148e44ce0SLars-Peter Clausen break; 48248e44ce0SLars-Peter Clausen case IIO_VAL_FRACTIONAL: 48348e44ce0SLars-Peter Clausen *processed = div_s64(raw64 * (s64)scale_val * scale, 48448e44ce0SLars-Peter Clausen scale_val2); 48548e44ce0SLars-Peter Clausen break; 486103d9fb9SLars-Peter Clausen case IIO_VAL_FRACTIONAL_LOG2: 487103d9fb9SLars-Peter Clausen *processed = (raw64 * (s64)scale_val * scale) >> scale_val2; 488103d9fb9SLars-Peter Clausen break; 48948e44ce0SLars-Peter Clausen default: 49048e44ce0SLars-Peter Clausen return -EINVAL; 49148e44ce0SLars-Peter Clausen } 49248e44ce0SLars-Peter Clausen 49348e44ce0SLars-Peter Clausen return 0; 49448e44ce0SLars-Peter Clausen } 49548e44ce0SLars-Peter Clausen 49648e44ce0SLars-Peter Clausen int iio_convert_raw_to_processed(struct iio_channel *chan, int raw, 49748e44ce0SLars-Peter Clausen int *processed, unsigned int scale) 49848e44ce0SLars-Peter Clausen { 49948e44ce0SLars-Peter Clausen int ret; 50048e44ce0SLars-Peter Clausen 50148e44ce0SLars-Peter Clausen mutex_lock(&chan->indio_dev->info_exist_lock); 50248e44ce0SLars-Peter Clausen if (chan->indio_dev->info == NULL) { 50348e44ce0SLars-Peter Clausen ret = -ENODEV; 50448e44ce0SLars-Peter Clausen goto err_unlock; 50548e44ce0SLars-Peter Clausen } 50648e44ce0SLars-Peter Clausen 50748e44ce0SLars-Peter Clausen ret = iio_convert_raw_to_processed_unlocked(chan, raw, processed, 50848e44ce0SLars-Peter Clausen scale); 50948e44ce0SLars-Peter Clausen err_unlock: 51048e44ce0SLars-Peter Clausen mutex_unlock(&chan->indio_dev->info_exist_lock); 51148e44ce0SLars-Peter Clausen 51248e44ce0SLars-Peter Clausen return ret; 51348e44ce0SLars-Peter Clausen } 51448e44ce0SLars-Peter Clausen EXPORT_SYMBOL_GPL(iio_convert_raw_to_processed); 51548e44ce0SLars-Peter Clausen 51648e44ce0SLars-Peter Clausen int iio_read_channel_processed(struct iio_channel *chan, int *val) 51748e44ce0SLars-Peter Clausen { 51848e44ce0SLars-Peter Clausen int ret; 51948e44ce0SLars-Peter Clausen 52048e44ce0SLars-Peter Clausen mutex_lock(&chan->indio_dev->info_exist_lock); 52148e44ce0SLars-Peter Clausen if (chan->indio_dev->info == NULL) { 52248e44ce0SLars-Peter Clausen ret = -ENODEV; 52348e44ce0SLars-Peter Clausen goto err_unlock; 52448e44ce0SLars-Peter Clausen } 52548e44ce0SLars-Peter Clausen 52648e44ce0SLars-Peter Clausen if (iio_channel_has_info(chan->channel, IIO_CHAN_INFO_PROCESSED)) { 52748e44ce0SLars-Peter Clausen ret = iio_channel_read(chan, val, NULL, 52848e44ce0SLars-Peter Clausen IIO_CHAN_INFO_PROCESSED); 52948e44ce0SLars-Peter Clausen } else { 53048e44ce0SLars-Peter Clausen ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW); 53148e44ce0SLars-Peter Clausen if (ret < 0) 53248e44ce0SLars-Peter Clausen goto err_unlock; 53348e44ce0SLars-Peter Clausen ret = iio_convert_raw_to_processed_unlocked(chan, *val, val, 1); 53448e44ce0SLars-Peter Clausen } 53548e44ce0SLars-Peter Clausen 53648e44ce0SLars-Peter Clausen err_unlock: 53748e44ce0SLars-Peter Clausen mutex_unlock(&chan->indio_dev->info_exist_lock); 53848e44ce0SLars-Peter Clausen 53948e44ce0SLars-Peter Clausen return ret; 54048e44ce0SLars-Peter Clausen } 54148e44ce0SLars-Peter Clausen EXPORT_SYMBOL_GPL(iio_read_channel_processed); 54248e44ce0SLars-Peter Clausen 543314be14bSJonathan Cameron int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2) 544a980e046SJonathan Cameron { 545a980e046SJonathan Cameron int ret; 546a980e046SJonathan Cameron 547a980e046SJonathan Cameron mutex_lock(&chan->indio_dev->info_exist_lock); 548a980e046SJonathan Cameron if (chan->indio_dev->info == NULL) { 549a980e046SJonathan Cameron ret = -ENODEV; 550a980e046SJonathan Cameron goto err_unlock; 551a980e046SJonathan Cameron } 552a980e046SJonathan Cameron 55348e44ce0SLars-Peter Clausen ret = iio_channel_read(chan, val, val2, IIO_CHAN_INFO_SCALE); 554a980e046SJonathan Cameron err_unlock: 555a980e046SJonathan Cameron mutex_unlock(&chan->indio_dev->info_exist_lock); 556a980e046SJonathan Cameron 557a980e046SJonathan Cameron return ret; 558a980e046SJonathan Cameron } 559314be14bSJonathan Cameron EXPORT_SYMBOL_GPL(iio_read_channel_scale); 560a980e046SJonathan Cameron 561314be14bSJonathan Cameron int iio_get_channel_type(struct iio_channel *chan, enum iio_chan_type *type) 562a980e046SJonathan Cameron { 563a980e046SJonathan Cameron int ret = 0; 564a980e046SJonathan Cameron /* Need to verify underlying driver has not gone away */ 565a980e046SJonathan Cameron 566a980e046SJonathan Cameron mutex_lock(&chan->indio_dev->info_exist_lock); 567a980e046SJonathan Cameron if (chan->indio_dev->info == NULL) { 568a980e046SJonathan Cameron ret = -ENODEV; 569a980e046SJonathan Cameron goto err_unlock; 570a980e046SJonathan Cameron } 571a980e046SJonathan Cameron 572a980e046SJonathan Cameron *type = chan->channel->type; 573a980e046SJonathan Cameron err_unlock: 574a980e046SJonathan Cameron mutex_unlock(&chan->indio_dev->info_exist_lock); 575a980e046SJonathan Cameron 576a980e046SJonathan Cameron return ret; 577a980e046SJonathan Cameron } 578314be14bSJonathan Cameron EXPORT_SYMBOL_GPL(iio_get_channel_type); 579