18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* The industrial I/O core in kernel channel mapping 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2011 Jonathan Cameron 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci#include <linux/err.h> 78c2ecf20Sopenharmony_ci#include <linux/export.h> 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci#include <linux/mutex.h> 108c2ecf20Sopenharmony_ci#include <linux/of.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 138c2ecf20Sopenharmony_ci#include "iio_core.h" 148c2ecf20Sopenharmony_ci#include <linux/iio/machine.h> 158c2ecf20Sopenharmony_ci#include <linux/iio/driver.h> 168c2ecf20Sopenharmony_ci#include <linux/iio/consumer.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistruct iio_map_internal { 198c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 208c2ecf20Sopenharmony_ci struct iio_map *map; 218c2ecf20Sopenharmony_ci struct list_head l; 228c2ecf20Sopenharmony_ci}; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic LIST_HEAD(iio_map_list); 258c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(iio_map_list_lock); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ciint iio_map_array_register(struct iio_dev *indio_dev, struct iio_map *maps) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci int i = 0, ret = 0; 308c2ecf20Sopenharmony_ci struct iio_map_internal *mapi; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci if (maps == NULL) 338c2ecf20Sopenharmony_ci return 0; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci mutex_lock(&iio_map_list_lock); 368c2ecf20Sopenharmony_ci while (maps[i].consumer_dev_name != NULL) { 378c2ecf20Sopenharmony_ci mapi = kzalloc(sizeof(*mapi), GFP_KERNEL); 388c2ecf20Sopenharmony_ci if (mapi == NULL) { 398c2ecf20Sopenharmony_ci ret = -ENOMEM; 408c2ecf20Sopenharmony_ci goto error_ret; 418c2ecf20Sopenharmony_ci } 428c2ecf20Sopenharmony_ci mapi->map = &maps[i]; 438c2ecf20Sopenharmony_ci mapi->indio_dev = indio_dev; 448c2ecf20Sopenharmony_ci list_add_tail(&mapi->l, &iio_map_list); 458c2ecf20Sopenharmony_ci i++; 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_cierror_ret: 488c2ecf20Sopenharmony_ci mutex_unlock(&iio_map_list_lock); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci return ret; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_map_array_register); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/* 568c2ecf20Sopenharmony_ci * Remove all map entries associated with the given iio device 578c2ecf20Sopenharmony_ci */ 588c2ecf20Sopenharmony_ciint iio_map_array_unregister(struct iio_dev *indio_dev) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci int ret = -ENODEV; 618c2ecf20Sopenharmony_ci struct iio_map_internal *mapi, *next; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci mutex_lock(&iio_map_list_lock); 648c2ecf20Sopenharmony_ci list_for_each_entry_safe(mapi, next, &iio_map_list, l) { 658c2ecf20Sopenharmony_ci if (indio_dev == mapi->indio_dev) { 668c2ecf20Sopenharmony_ci list_del(&mapi->l); 678c2ecf20Sopenharmony_ci kfree(mapi); 688c2ecf20Sopenharmony_ci ret = 0; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci mutex_unlock(&iio_map_list_lock); 728c2ecf20Sopenharmony_ci return ret; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_map_array_unregister); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic const struct iio_chan_spec 778c2ecf20Sopenharmony_ci*iio_chan_spec_from_name(const struct iio_dev *indio_dev, const char *name) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci int i; 808c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan = NULL; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci for (i = 0; i < indio_dev->num_channels; i++) 838c2ecf20Sopenharmony_ci if (indio_dev->channels[i].datasheet_name && 848c2ecf20Sopenharmony_ci strcmp(name, indio_dev->channels[i].datasheet_name) == 0) { 858c2ecf20Sopenharmony_ci chan = &indio_dev->channels[i]; 868c2ecf20Sopenharmony_ci break; 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci return chan; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic int iio_dev_node_match(struct device *dev, const void *data) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci return dev->of_node == data && dev->type == &iio_device_type; 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/** 998c2ecf20Sopenharmony_ci * __of_iio_simple_xlate - translate iiospec to the IIO channel index 1008c2ecf20Sopenharmony_ci * @indio_dev: pointer to the iio_dev structure 1018c2ecf20Sopenharmony_ci * @iiospec: IIO specifier as found in the device tree 1028c2ecf20Sopenharmony_ci * 1038c2ecf20Sopenharmony_ci * This is simple translation function, suitable for the most 1:1 mapped 1048c2ecf20Sopenharmony_ci * channels in IIO chips. This function performs only one sanity check: 1058c2ecf20Sopenharmony_ci * whether IIO index is less than num_channels (that is specified in the 1068c2ecf20Sopenharmony_ci * iio_dev). 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_cistatic int __of_iio_simple_xlate(struct iio_dev *indio_dev, 1098c2ecf20Sopenharmony_ci const struct of_phandle_args *iiospec) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci if (!iiospec->args_count) 1128c2ecf20Sopenharmony_ci return 0; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (iiospec->args[0] >= indio_dev->num_channels) { 1158c2ecf20Sopenharmony_ci dev_err(&indio_dev->dev, "invalid channel index %u\n", 1168c2ecf20Sopenharmony_ci iiospec->args[0]); 1178c2ecf20Sopenharmony_ci return -EINVAL; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci return iiospec->args[0]; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic int __of_iio_channel_get(struct iio_channel *channel, 1248c2ecf20Sopenharmony_ci struct device_node *np, int index) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci struct device *idev; 1278c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 1288c2ecf20Sopenharmony_ci int err; 1298c2ecf20Sopenharmony_ci struct of_phandle_args iiospec; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci err = of_parse_phandle_with_args(np, "io-channels", 1328c2ecf20Sopenharmony_ci "#io-channel-cells", 1338c2ecf20Sopenharmony_ci index, &iiospec); 1348c2ecf20Sopenharmony_ci if (err) 1358c2ecf20Sopenharmony_ci return err; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci idev = bus_find_device(&iio_bus_type, NULL, iiospec.np, 1388c2ecf20Sopenharmony_ci iio_dev_node_match); 1398c2ecf20Sopenharmony_ci if (idev == NULL) { 1408c2ecf20Sopenharmony_ci of_node_put(iiospec.np); 1418c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci indio_dev = dev_to_iio_dev(idev); 1458c2ecf20Sopenharmony_ci channel->indio_dev = indio_dev; 1468c2ecf20Sopenharmony_ci if (indio_dev->info->of_xlate) 1478c2ecf20Sopenharmony_ci index = indio_dev->info->of_xlate(indio_dev, &iiospec); 1488c2ecf20Sopenharmony_ci else 1498c2ecf20Sopenharmony_ci index = __of_iio_simple_xlate(indio_dev, &iiospec); 1508c2ecf20Sopenharmony_ci of_node_put(iiospec.np); 1518c2ecf20Sopenharmony_ci if (index < 0) 1528c2ecf20Sopenharmony_ci goto err_put; 1538c2ecf20Sopenharmony_ci channel->channel = &indio_dev->channels[index]; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci return 0; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cierr_put: 1588c2ecf20Sopenharmony_ci iio_device_put(indio_dev); 1598c2ecf20Sopenharmony_ci return index; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic struct iio_channel *of_iio_channel_get(struct device_node *np, int index) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci struct iio_channel *channel; 1658c2ecf20Sopenharmony_ci int err; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if (index < 0) 1688c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci channel = kzalloc(sizeof(*channel), GFP_KERNEL); 1718c2ecf20Sopenharmony_ci if (channel == NULL) 1728c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci err = __of_iio_channel_get(channel, np, index); 1758c2ecf20Sopenharmony_ci if (err) 1768c2ecf20Sopenharmony_ci goto err_free_channel; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci return channel; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cierr_free_channel: 1818c2ecf20Sopenharmony_ci kfree(channel); 1828c2ecf20Sopenharmony_ci return ERR_PTR(err); 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic struct iio_channel *of_iio_channel_get_by_name(struct device_node *np, 1868c2ecf20Sopenharmony_ci const char *name) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci struct iio_channel *chan = NULL; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci /* Walk up the tree of devices looking for a matching iio channel */ 1918c2ecf20Sopenharmony_ci while (np) { 1928c2ecf20Sopenharmony_ci int index = 0; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci /* 1958c2ecf20Sopenharmony_ci * For named iio channels, first look up the name in the 1968c2ecf20Sopenharmony_ci * "io-channel-names" property. If it cannot be found, the 1978c2ecf20Sopenharmony_ci * index will be an error code, and of_iio_channel_get() 1988c2ecf20Sopenharmony_ci * will fail. 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_ci if (name) 2018c2ecf20Sopenharmony_ci index = of_property_match_string(np, "io-channel-names", 2028c2ecf20Sopenharmony_ci name); 2038c2ecf20Sopenharmony_ci chan = of_iio_channel_get(np, index); 2048c2ecf20Sopenharmony_ci if (!IS_ERR(chan) || PTR_ERR(chan) == -EPROBE_DEFER) 2058c2ecf20Sopenharmony_ci break; 2068c2ecf20Sopenharmony_ci else if (name && index >= 0) { 2078c2ecf20Sopenharmony_ci pr_err("ERROR: could not get IIO channel %pOF:%s(%i)\n", 2088c2ecf20Sopenharmony_ci np, name ? name : "", index); 2098c2ecf20Sopenharmony_ci return NULL; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci /* 2138c2ecf20Sopenharmony_ci * No matching IIO channel found on this node. 2148c2ecf20Sopenharmony_ci * If the parent node has a "io-channel-ranges" property, 2158c2ecf20Sopenharmony_ci * then we can try one of its channels. 2168c2ecf20Sopenharmony_ci */ 2178c2ecf20Sopenharmony_ci np = np->parent; 2188c2ecf20Sopenharmony_ci if (np && !of_get_property(np, "io-channel-ranges", NULL)) 2198c2ecf20Sopenharmony_ci return NULL; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci return chan; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic struct iio_channel *of_iio_channel_get_all(struct device *dev) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci struct iio_channel *chans; 2288c2ecf20Sopenharmony_ci int i, mapind, nummaps = 0; 2298c2ecf20Sopenharmony_ci int ret; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci do { 2328c2ecf20Sopenharmony_ci ret = of_parse_phandle_with_args(dev->of_node, 2338c2ecf20Sopenharmony_ci "io-channels", 2348c2ecf20Sopenharmony_ci "#io-channel-cells", 2358c2ecf20Sopenharmony_ci nummaps, NULL); 2368c2ecf20Sopenharmony_ci if (ret < 0) 2378c2ecf20Sopenharmony_ci break; 2388c2ecf20Sopenharmony_ci } while (++nummaps); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (nummaps == 0) /* no error, return NULL to search map table */ 2418c2ecf20Sopenharmony_ci return NULL; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* NULL terminated array to save passing size */ 2448c2ecf20Sopenharmony_ci chans = kcalloc(nummaps + 1, sizeof(*chans), GFP_KERNEL); 2458c2ecf20Sopenharmony_ci if (chans == NULL) 2468c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* Search for OF matches */ 2498c2ecf20Sopenharmony_ci for (mapind = 0; mapind < nummaps; mapind++) { 2508c2ecf20Sopenharmony_ci ret = __of_iio_channel_get(&chans[mapind], dev->of_node, 2518c2ecf20Sopenharmony_ci mapind); 2528c2ecf20Sopenharmony_ci if (ret) 2538c2ecf20Sopenharmony_ci goto error_free_chans; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci return chans; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cierror_free_chans: 2588c2ecf20Sopenharmony_ci for (i = 0; i < mapind; i++) 2598c2ecf20Sopenharmony_ci iio_device_put(chans[i].indio_dev); 2608c2ecf20Sopenharmony_ci kfree(chans); 2618c2ecf20Sopenharmony_ci return ERR_PTR(ret); 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci#else /* CONFIG_OF */ 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic inline struct iio_channel * 2678c2ecf20Sopenharmony_ciof_iio_channel_get_by_name(struct device_node *np, const char *name) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci return NULL; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic inline struct iio_channel *of_iio_channel_get_all(struct device *dev) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci return NULL; 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci#endif /* CONFIG_OF */ 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic struct iio_channel *iio_channel_get_sys(const char *name, 2808c2ecf20Sopenharmony_ci const char *channel_name) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci struct iio_map_internal *c_i = NULL, *c = NULL; 2838c2ecf20Sopenharmony_ci struct iio_channel *channel; 2848c2ecf20Sopenharmony_ci int err; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if (name == NULL && channel_name == NULL) 2878c2ecf20Sopenharmony_ci return ERR_PTR(-ENODEV); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* first find matching entry the channel map */ 2908c2ecf20Sopenharmony_ci mutex_lock(&iio_map_list_lock); 2918c2ecf20Sopenharmony_ci list_for_each_entry(c_i, &iio_map_list, l) { 2928c2ecf20Sopenharmony_ci if ((name && strcmp(name, c_i->map->consumer_dev_name) != 0) || 2938c2ecf20Sopenharmony_ci (channel_name && 2948c2ecf20Sopenharmony_ci strcmp(channel_name, c_i->map->consumer_channel) != 0)) 2958c2ecf20Sopenharmony_ci continue; 2968c2ecf20Sopenharmony_ci c = c_i; 2978c2ecf20Sopenharmony_ci iio_device_get(c->indio_dev); 2988c2ecf20Sopenharmony_ci break; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci mutex_unlock(&iio_map_list_lock); 3018c2ecf20Sopenharmony_ci if (c == NULL) 3028c2ecf20Sopenharmony_ci return ERR_PTR(-ENODEV); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci channel = kzalloc(sizeof(*channel), GFP_KERNEL); 3058c2ecf20Sopenharmony_ci if (channel == NULL) { 3068c2ecf20Sopenharmony_ci err = -ENOMEM; 3078c2ecf20Sopenharmony_ci goto error_no_mem; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci channel->indio_dev = c->indio_dev; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (c->map->adc_channel_label) { 3138c2ecf20Sopenharmony_ci channel->channel = 3148c2ecf20Sopenharmony_ci iio_chan_spec_from_name(channel->indio_dev, 3158c2ecf20Sopenharmony_ci c->map->adc_channel_label); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (channel->channel == NULL) { 3188c2ecf20Sopenharmony_ci err = -EINVAL; 3198c2ecf20Sopenharmony_ci goto error_no_chan; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci return channel; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cierror_no_chan: 3268c2ecf20Sopenharmony_ci kfree(channel); 3278c2ecf20Sopenharmony_cierror_no_mem: 3288c2ecf20Sopenharmony_ci iio_device_put(c->indio_dev); 3298c2ecf20Sopenharmony_ci return ERR_PTR(err); 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistruct iio_channel *iio_channel_get(struct device *dev, 3338c2ecf20Sopenharmony_ci const char *channel_name) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci const char *name = dev ? dev_name(dev) : NULL; 3368c2ecf20Sopenharmony_ci struct iio_channel *channel; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci if (dev) { 3398c2ecf20Sopenharmony_ci channel = of_iio_channel_get_by_name(dev->of_node, 3408c2ecf20Sopenharmony_ci channel_name); 3418c2ecf20Sopenharmony_ci if (channel != NULL) 3428c2ecf20Sopenharmony_ci return channel; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci return iio_channel_get_sys(name, channel_name); 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_channel_get); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_civoid iio_channel_release(struct iio_channel *channel) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci if (!channel) 3528c2ecf20Sopenharmony_ci return; 3538c2ecf20Sopenharmony_ci iio_device_put(channel->indio_dev); 3548c2ecf20Sopenharmony_ci kfree(channel); 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_channel_release); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic void devm_iio_channel_free(struct device *dev, void *res) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci struct iio_channel *channel = *(struct iio_channel **)res; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci iio_channel_release(channel); 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistruct iio_channel *devm_iio_channel_get(struct device *dev, 3668c2ecf20Sopenharmony_ci const char *channel_name) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci struct iio_channel **ptr, *channel; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci ptr = devres_alloc(devm_iio_channel_free, sizeof(*ptr), GFP_KERNEL); 3718c2ecf20Sopenharmony_ci if (!ptr) 3728c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci channel = iio_channel_get(dev, channel_name); 3758c2ecf20Sopenharmony_ci if (IS_ERR(channel)) { 3768c2ecf20Sopenharmony_ci devres_free(ptr); 3778c2ecf20Sopenharmony_ci return channel; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci *ptr = channel; 3818c2ecf20Sopenharmony_ci devres_add(dev, ptr); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci return channel; 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_iio_channel_get); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistruct iio_channel *iio_channel_get_all(struct device *dev) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci const char *name; 3908c2ecf20Sopenharmony_ci struct iio_channel *chans; 3918c2ecf20Sopenharmony_ci struct iio_map_internal *c = NULL; 3928c2ecf20Sopenharmony_ci int nummaps = 0; 3938c2ecf20Sopenharmony_ci int mapind = 0; 3948c2ecf20Sopenharmony_ci int i, ret; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci if (dev == NULL) 3978c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci chans = of_iio_channel_get_all(dev); 4008c2ecf20Sopenharmony_ci if (chans) 4018c2ecf20Sopenharmony_ci return chans; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci name = dev_name(dev); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci mutex_lock(&iio_map_list_lock); 4068c2ecf20Sopenharmony_ci /* first count the matching maps */ 4078c2ecf20Sopenharmony_ci list_for_each_entry(c, &iio_map_list, l) 4088c2ecf20Sopenharmony_ci if (name && strcmp(name, c->map->consumer_dev_name) != 0) 4098c2ecf20Sopenharmony_ci continue; 4108c2ecf20Sopenharmony_ci else 4118c2ecf20Sopenharmony_ci nummaps++; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (nummaps == 0) { 4148c2ecf20Sopenharmony_ci ret = -ENODEV; 4158c2ecf20Sopenharmony_ci goto error_ret; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci /* NULL terminated array to save passing size */ 4198c2ecf20Sopenharmony_ci chans = kcalloc(nummaps + 1, sizeof(*chans), GFP_KERNEL); 4208c2ecf20Sopenharmony_ci if (chans == NULL) { 4218c2ecf20Sopenharmony_ci ret = -ENOMEM; 4228c2ecf20Sopenharmony_ci goto error_ret; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci /* for each map fill in the chans element */ 4268c2ecf20Sopenharmony_ci list_for_each_entry(c, &iio_map_list, l) { 4278c2ecf20Sopenharmony_ci if (name && strcmp(name, c->map->consumer_dev_name) != 0) 4288c2ecf20Sopenharmony_ci continue; 4298c2ecf20Sopenharmony_ci chans[mapind].indio_dev = c->indio_dev; 4308c2ecf20Sopenharmony_ci chans[mapind].data = c->map->consumer_data; 4318c2ecf20Sopenharmony_ci chans[mapind].channel = 4328c2ecf20Sopenharmony_ci iio_chan_spec_from_name(chans[mapind].indio_dev, 4338c2ecf20Sopenharmony_ci c->map->adc_channel_label); 4348c2ecf20Sopenharmony_ci if (chans[mapind].channel == NULL) { 4358c2ecf20Sopenharmony_ci ret = -EINVAL; 4368c2ecf20Sopenharmony_ci goto error_free_chans; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci iio_device_get(chans[mapind].indio_dev); 4398c2ecf20Sopenharmony_ci mapind++; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci if (mapind == 0) { 4428c2ecf20Sopenharmony_ci ret = -ENODEV; 4438c2ecf20Sopenharmony_ci goto error_free_chans; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci mutex_unlock(&iio_map_list_lock); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci return chans; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cierror_free_chans: 4508c2ecf20Sopenharmony_ci for (i = 0; i < nummaps; i++) 4518c2ecf20Sopenharmony_ci iio_device_put(chans[i].indio_dev); 4528c2ecf20Sopenharmony_ci kfree(chans); 4538c2ecf20Sopenharmony_cierror_ret: 4548c2ecf20Sopenharmony_ci mutex_unlock(&iio_map_list_lock); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci return ERR_PTR(ret); 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_channel_get_all); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_civoid iio_channel_release_all(struct iio_channel *channels) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci struct iio_channel *chan = &channels[0]; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci while (chan->indio_dev) { 4658c2ecf20Sopenharmony_ci iio_device_put(chan->indio_dev); 4668c2ecf20Sopenharmony_ci chan++; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci kfree(channels); 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_channel_release_all); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic void devm_iio_channel_free_all(struct device *dev, void *res) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci struct iio_channel *channels = *(struct iio_channel **)res; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci iio_channel_release_all(channels); 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistruct iio_channel *devm_iio_channel_get_all(struct device *dev) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci struct iio_channel **ptr, *channels; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci ptr = devres_alloc(devm_iio_channel_free_all, sizeof(*ptr), GFP_KERNEL); 4848c2ecf20Sopenharmony_ci if (!ptr) 4858c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci channels = iio_channel_get_all(dev); 4888c2ecf20Sopenharmony_ci if (IS_ERR(channels)) { 4898c2ecf20Sopenharmony_ci devres_free(ptr); 4908c2ecf20Sopenharmony_ci return channels; 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci *ptr = channels; 4948c2ecf20Sopenharmony_ci devres_add(dev, ptr); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci return channels; 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_iio_channel_get_all); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_cistatic int iio_channel_read(struct iio_channel *chan, int *val, int *val2, 5018c2ecf20Sopenharmony_ci enum iio_chan_info_enum info) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci int unused; 5048c2ecf20Sopenharmony_ci int vals[INDIO_MAX_RAW_ELEMENTS]; 5058c2ecf20Sopenharmony_ci int ret; 5068c2ecf20Sopenharmony_ci int val_len = 2; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci if (val2 == NULL) 5098c2ecf20Sopenharmony_ci val2 = &unused; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci if (!iio_channel_has_info(chan->channel, info)) 5128c2ecf20Sopenharmony_ci return -EINVAL; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci if (chan->indio_dev->info->read_raw_multi) { 5158c2ecf20Sopenharmony_ci ret = chan->indio_dev->info->read_raw_multi(chan->indio_dev, 5168c2ecf20Sopenharmony_ci chan->channel, INDIO_MAX_RAW_ELEMENTS, 5178c2ecf20Sopenharmony_ci vals, &val_len, info); 5188c2ecf20Sopenharmony_ci *val = vals[0]; 5198c2ecf20Sopenharmony_ci *val2 = vals[1]; 5208c2ecf20Sopenharmony_ci } else 5218c2ecf20Sopenharmony_ci ret = chan->indio_dev->info->read_raw(chan->indio_dev, 5228c2ecf20Sopenharmony_ci chan->channel, val, val2, info); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci return ret; 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ciint iio_read_channel_raw(struct iio_channel *chan, int *val) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci int ret; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci mutex_lock(&chan->indio_dev->info_exist_lock); 5328c2ecf20Sopenharmony_ci if (chan->indio_dev->info == NULL) { 5338c2ecf20Sopenharmony_ci ret = -ENODEV; 5348c2ecf20Sopenharmony_ci goto err_unlock; 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW); 5388c2ecf20Sopenharmony_cierr_unlock: 5398c2ecf20Sopenharmony_ci mutex_unlock(&chan->indio_dev->info_exist_lock); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci return ret; 5428c2ecf20Sopenharmony_ci} 5438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_read_channel_raw); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ciint iio_read_channel_average_raw(struct iio_channel *chan, int *val) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci int ret; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci mutex_lock(&chan->indio_dev->info_exist_lock); 5508c2ecf20Sopenharmony_ci if (chan->indio_dev->info == NULL) { 5518c2ecf20Sopenharmony_ci ret = -ENODEV; 5528c2ecf20Sopenharmony_ci goto err_unlock; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_AVERAGE_RAW); 5568c2ecf20Sopenharmony_cierr_unlock: 5578c2ecf20Sopenharmony_ci mutex_unlock(&chan->indio_dev->info_exist_lock); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci return ret; 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_read_channel_average_raw); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_cistatic int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan, 5648c2ecf20Sopenharmony_ci int raw, int *processed, unsigned int scale) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci int scale_type, scale_val, scale_val2; 5678c2ecf20Sopenharmony_ci int offset_type, offset_val, offset_val2; 5688c2ecf20Sopenharmony_ci s64 raw64 = raw; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci offset_type = iio_channel_read(chan, &offset_val, &offset_val2, 5718c2ecf20Sopenharmony_ci IIO_CHAN_INFO_OFFSET); 5728c2ecf20Sopenharmony_ci if (offset_type >= 0) { 5738c2ecf20Sopenharmony_ci switch (offset_type) { 5748c2ecf20Sopenharmony_ci case IIO_VAL_INT: 5758c2ecf20Sopenharmony_ci break; 5768c2ecf20Sopenharmony_ci case IIO_VAL_INT_PLUS_MICRO: 5778c2ecf20Sopenharmony_ci case IIO_VAL_INT_PLUS_NANO: 5788c2ecf20Sopenharmony_ci /* 5798c2ecf20Sopenharmony_ci * Both IIO_VAL_INT_PLUS_MICRO and IIO_VAL_INT_PLUS_NANO 5808c2ecf20Sopenharmony_ci * implicitely truncate the offset to it's integer form. 5818c2ecf20Sopenharmony_ci */ 5828c2ecf20Sopenharmony_ci break; 5838c2ecf20Sopenharmony_ci case IIO_VAL_FRACTIONAL: 5848c2ecf20Sopenharmony_ci offset_val /= offset_val2; 5858c2ecf20Sopenharmony_ci break; 5868c2ecf20Sopenharmony_ci case IIO_VAL_FRACTIONAL_LOG2: 5878c2ecf20Sopenharmony_ci offset_val >>= offset_val2; 5888c2ecf20Sopenharmony_ci break; 5898c2ecf20Sopenharmony_ci default: 5908c2ecf20Sopenharmony_ci return -EINVAL; 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci raw64 += offset_val; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci scale_type = iio_channel_read(chan, &scale_val, &scale_val2, 5978c2ecf20Sopenharmony_ci IIO_CHAN_INFO_SCALE); 5988c2ecf20Sopenharmony_ci if (scale_type < 0) { 5998c2ecf20Sopenharmony_ci /* 6008c2ecf20Sopenharmony_ci * If no channel scaling is available apply consumer scale to 6018c2ecf20Sopenharmony_ci * raw value and return. 6028c2ecf20Sopenharmony_ci */ 6038c2ecf20Sopenharmony_ci *processed = raw * scale; 6048c2ecf20Sopenharmony_ci return 0; 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci switch (scale_type) { 6088c2ecf20Sopenharmony_ci case IIO_VAL_INT: 6098c2ecf20Sopenharmony_ci *processed = raw64 * scale_val * scale; 6108c2ecf20Sopenharmony_ci break; 6118c2ecf20Sopenharmony_ci case IIO_VAL_INT_PLUS_MICRO: 6128c2ecf20Sopenharmony_ci if (scale_val2 < 0) 6138c2ecf20Sopenharmony_ci *processed = -raw64 * scale_val; 6148c2ecf20Sopenharmony_ci else 6158c2ecf20Sopenharmony_ci *processed = raw64 * scale_val; 6168c2ecf20Sopenharmony_ci *processed += div_s64(raw64 * (s64)scale_val2 * scale, 6178c2ecf20Sopenharmony_ci 1000000LL); 6188c2ecf20Sopenharmony_ci break; 6198c2ecf20Sopenharmony_ci case IIO_VAL_INT_PLUS_NANO: 6208c2ecf20Sopenharmony_ci if (scale_val2 < 0) 6218c2ecf20Sopenharmony_ci *processed = -raw64 * scale_val; 6228c2ecf20Sopenharmony_ci else 6238c2ecf20Sopenharmony_ci *processed = raw64 * scale_val; 6248c2ecf20Sopenharmony_ci *processed += div_s64(raw64 * (s64)scale_val2 * scale, 6258c2ecf20Sopenharmony_ci 1000000000LL); 6268c2ecf20Sopenharmony_ci break; 6278c2ecf20Sopenharmony_ci case IIO_VAL_FRACTIONAL: 6288c2ecf20Sopenharmony_ci *processed = div_s64(raw64 * (s64)scale_val * scale, 6298c2ecf20Sopenharmony_ci scale_val2); 6308c2ecf20Sopenharmony_ci break; 6318c2ecf20Sopenharmony_ci case IIO_VAL_FRACTIONAL_LOG2: 6328c2ecf20Sopenharmony_ci *processed = (raw64 * (s64)scale_val * scale) >> scale_val2; 6338c2ecf20Sopenharmony_ci break; 6348c2ecf20Sopenharmony_ci default: 6358c2ecf20Sopenharmony_ci return -EINVAL; 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci return 0; 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ciint iio_convert_raw_to_processed(struct iio_channel *chan, int raw, 6428c2ecf20Sopenharmony_ci int *processed, unsigned int scale) 6438c2ecf20Sopenharmony_ci{ 6448c2ecf20Sopenharmony_ci int ret; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci mutex_lock(&chan->indio_dev->info_exist_lock); 6478c2ecf20Sopenharmony_ci if (chan->indio_dev->info == NULL) { 6488c2ecf20Sopenharmony_ci ret = -ENODEV; 6498c2ecf20Sopenharmony_ci goto err_unlock; 6508c2ecf20Sopenharmony_ci } 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci ret = iio_convert_raw_to_processed_unlocked(chan, raw, processed, 6538c2ecf20Sopenharmony_ci scale); 6548c2ecf20Sopenharmony_cierr_unlock: 6558c2ecf20Sopenharmony_ci mutex_unlock(&chan->indio_dev->info_exist_lock); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci return ret; 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_convert_raw_to_processed); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ciint iio_read_channel_attribute(struct iio_channel *chan, int *val, int *val2, 6628c2ecf20Sopenharmony_ci enum iio_chan_info_enum attribute) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci int ret; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci mutex_lock(&chan->indio_dev->info_exist_lock); 6678c2ecf20Sopenharmony_ci if (chan->indio_dev->info == NULL) { 6688c2ecf20Sopenharmony_ci ret = -ENODEV; 6698c2ecf20Sopenharmony_ci goto err_unlock; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci ret = iio_channel_read(chan, val, val2, attribute); 6738c2ecf20Sopenharmony_cierr_unlock: 6748c2ecf20Sopenharmony_ci mutex_unlock(&chan->indio_dev->info_exist_lock); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci return ret; 6778c2ecf20Sopenharmony_ci} 6788c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_read_channel_attribute); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ciint iio_read_channel_offset(struct iio_channel *chan, int *val, int *val2) 6818c2ecf20Sopenharmony_ci{ 6828c2ecf20Sopenharmony_ci return iio_read_channel_attribute(chan, val, val2, IIO_CHAN_INFO_OFFSET); 6838c2ecf20Sopenharmony_ci} 6848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_read_channel_offset); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ciint iio_read_channel_processed(struct iio_channel *chan, int *val) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci int ret; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci mutex_lock(&chan->indio_dev->info_exist_lock); 6918c2ecf20Sopenharmony_ci if (chan->indio_dev->info == NULL) { 6928c2ecf20Sopenharmony_ci ret = -ENODEV; 6938c2ecf20Sopenharmony_ci goto err_unlock; 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci if (iio_channel_has_info(chan->channel, IIO_CHAN_INFO_PROCESSED)) { 6978c2ecf20Sopenharmony_ci ret = iio_channel_read(chan, val, NULL, 6988c2ecf20Sopenharmony_ci IIO_CHAN_INFO_PROCESSED); 6998c2ecf20Sopenharmony_ci } else { 7008c2ecf20Sopenharmony_ci ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW); 7018c2ecf20Sopenharmony_ci if (ret < 0) 7028c2ecf20Sopenharmony_ci goto err_unlock; 7038c2ecf20Sopenharmony_ci ret = iio_convert_raw_to_processed_unlocked(chan, *val, val, 1); 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_cierr_unlock: 7078c2ecf20Sopenharmony_ci mutex_unlock(&chan->indio_dev->info_exist_lock); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci return ret; 7108c2ecf20Sopenharmony_ci} 7118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_read_channel_processed); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ciint iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci return iio_read_channel_attribute(chan, val, val2, IIO_CHAN_INFO_SCALE); 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_read_channel_scale); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_cistatic int iio_channel_read_avail(struct iio_channel *chan, 7208c2ecf20Sopenharmony_ci const int **vals, int *type, int *length, 7218c2ecf20Sopenharmony_ci enum iio_chan_info_enum info) 7228c2ecf20Sopenharmony_ci{ 7238c2ecf20Sopenharmony_ci if (!iio_channel_has_available(chan->channel, info)) 7248c2ecf20Sopenharmony_ci return -EINVAL; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci return chan->indio_dev->info->read_avail(chan->indio_dev, chan->channel, 7278c2ecf20Sopenharmony_ci vals, type, length, info); 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ciint iio_read_avail_channel_attribute(struct iio_channel *chan, 7318c2ecf20Sopenharmony_ci const int **vals, int *type, int *length, 7328c2ecf20Sopenharmony_ci enum iio_chan_info_enum attribute) 7338c2ecf20Sopenharmony_ci{ 7348c2ecf20Sopenharmony_ci int ret; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci mutex_lock(&chan->indio_dev->info_exist_lock); 7378c2ecf20Sopenharmony_ci if (!chan->indio_dev->info) { 7388c2ecf20Sopenharmony_ci ret = -ENODEV; 7398c2ecf20Sopenharmony_ci goto err_unlock; 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci ret = iio_channel_read_avail(chan, vals, type, length, attribute); 7438c2ecf20Sopenharmony_cierr_unlock: 7448c2ecf20Sopenharmony_ci mutex_unlock(&chan->indio_dev->info_exist_lock); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci return ret; 7478c2ecf20Sopenharmony_ci} 7488c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_read_avail_channel_attribute); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ciint iio_read_avail_channel_raw(struct iio_channel *chan, 7518c2ecf20Sopenharmony_ci const int **vals, int *length) 7528c2ecf20Sopenharmony_ci{ 7538c2ecf20Sopenharmony_ci int ret; 7548c2ecf20Sopenharmony_ci int type; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci ret = iio_read_avail_channel_attribute(chan, vals, &type, length, 7578c2ecf20Sopenharmony_ci IIO_CHAN_INFO_RAW); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci if (ret >= 0 && type != IIO_VAL_INT) 7608c2ecf20Sopenharmony_ci /* raw values are assumed to be IIO_VAL_INT */ 7618c2ecf20Sopenharmony_ci ret = -EINVAL; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci return ret; 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_read_avail_channel_raw); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_cistatic int iio_channel_read_max(struct iio_channel *chan, 7688c2ecf20Sopenharmony_ci int *val, int *val2, int *type, 7698c2ecf20Sopenharmony_ci enum iio_chan_info_enum info) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci int unused; 7728c2ecf20Sopenharmony_ci const int *vals; 7738c2ecf20Sopenharmony_ci int length; 7748c2ecf20Sopenharmony_ci int ret; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci if (!val2) 7778c2ecf20Sopenharmony_ci val2 = &unused; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci ret = iio_channel_read_avail(chan, &vals, type, &length, info); 7808c2ecf20Sopenharmony_ci switch (ret) { 7818c2ecf20Sopenharmony_ci case IIO_AVAIL_RANGE: 7828c2ecf20Sopenharmony_ci switch (*type) { 7838c2ecf20Sopenharmony_ci case IIO_VAL_INT: 7848c2ecf20Sopenharmony_ci *val = vals[2]; 7858c2ecf20Sopenharmony_ci break; 7868c2ecf20Sopenharmony_ci default: 7878c2ecf20Sopenharmony_ci *val = vals[4]; 7888c2ecf20Sopenharmony_ci *val2 = vals[5]; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci return 0; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci case IIO_AVAIL_LIST: 7938c2ecf20Sopenharmony_ci if (length <= 0) 7948c2ecf20Sopenharmony_ci return -EINVAL; 7958c2ecf20Sopenharmony_ci switch (*type) { 7968c2ecf20Sopenharmony_ci case IIO_VAL_INT: 7978c2ecf20Sopenharmony_ci *val = vals[--length]; 7988c2ecf20Sopenharmony_ci while (length) { 7998c2ecf20Sopenharmony_ci if (vals[--length] > *val) 8008c2ecf20Sopenharmony_ci *val = vals[length]; 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci break; 8038c2ecf20Sopenharmony_ci default: 8048c2ecf20Sopenharmony_ci /* FIXME: learn about max for other iio values */ 8058c2ecf20Sopenharmony_ci return -EINVAL; 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci return 0; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci default: 8108c2ecf20Sopenharmony_ci return ret; 8118c2ecf20Sopenharmony_ci } 8128c2ecf20Sopenharmony_ci} 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ciint iio_read_max_channel_raw(struct iio_channel *chan, int *val) 8158c2ecf20Sopenharmony_ci{ 8168c2ecf20Sopenharmony_ci int ret; 8178c2ecf20Sopenharmony_ci int type; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci mutex_lock(&chan->indio_dev->info_exist_lock); 8208c2ecf20Sopenharmony_ci if (!chan->indio_dev->info) { 8218c2ecf20Sopenharmony_ci ret = -ENODEV; 8228c2ecf20Sopenharmony_ci goto err_unlock; 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci ret = iio_channel_read_max(chan, val, NULL, &type, IIO_CHAN_INFO_RAW); 8268c2ecf20Sopenharmony_cierr_unlock: 8278c2ecf20Sopenharmony_ci mutex_unlock(&chan->indio_dev->info_exist_lock); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci return ret; 8308c2ecf20Sopenharmony_ci} 8318c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_read_max_channel_raw); 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ciint iio_get_channel_type(struct iio_channel *chan, enum iio_chan_type *type) 8348c2ecf20Sopenharmony_ci{ 8358c2ecf20Sopenharmony_ci int ret = 0; 8368c2ecf20Sopenharmony_ci /* Need to verify underlying driver has not gone away */ 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci mutex_lock(&chan->indio_dev->info_exist_lock); 8398c2ecf20Sopenharmony_ci if (chan->indio_dev->info == NULL) { 8408c2ecf20Sopenharmony_ci ret = -ENODEV; 8418c2ecf20Sopenharmony_ci goto err_unlock; 8428c2ecf20Sopenharmony_ci } 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci *type = chan->channel->type; 8458c2ecf20Sopenharmony_cierr_unlock: 8468c2ecf20Sopenharmony_ci mutex_unlock(&chan->indio_dev->info_exist_lock); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci return ret; 8498c2ecf20Sopenharmony_ci} 8508c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_get_channel_type); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_cistatic int iio_channel_write(struct iio_channel *chan, int val, int val2, 8538c2ecf20Sopenharmony_ci enum iio_chan_info_enum info) 8548c2ecf20Sopenharmony_ci{ 8558c2ecf20Sopenharmony_ci return chan->indio_dev->info->write_raw(chan->indio_dev, 8568c2ecf20Sopenharmony_ci chan->channel, val, val2, info); 8578c2ecf20Sopenharmony_ci} 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ciint iio_write_channel_attribute(struct iio_channel *chan, int val, int val2, 8608c2ecf20Sopenharmony_ci enum iio_chan_info_enum attribute) 8618c2ecf20Sopenharmony_ci{ 8628c2ecf20Sopenharmony_ci int ret; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci mutex_lock(&chan->indio_dev->info_exist_lock); 8658c2ecf20Sopenharmony_ci if (chan->indio_dev->info == NULL) { 8668c2ecf20Sopenharmony_ci ret = -ENODEV; 8678c2ecf20Sopenharmony_ci goto err_unlock; 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci ret = iio_channel_write(chan, val, val2, attribute); 8718c2ecf20Sopenharmony_cierr_unlock: 8728c2ecf20Sopenharmony_ci mutex_unlock(&chan->indio_dev->info_exist_lock); 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci return ret; 8758c2ecf20Sopenharmony_ci} 8768c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_write_channel_attribute); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ciint iio_write_channel_raw(struct iio_channel *chan, int val) 8798c2ecf20Sopenharmony_ci{ 8808c2ecf20Sopenharmony_ci return iio_write_channel_attribute(chan, val, 0, IIO_CHAN_INFO_RAW); 8818c2ecf20Sopenharmony_ci} 8828c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_write_channel_raw); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ciunsigned int iio_get_channel_ext_info_count(struct iio_channel *chan) 8858c2ecf20Sopenharmony_ci{ 8868c2ecf20Sopenharmony_ci const struct iio_chan_spec_ext_info *ext_info; 8878c2ecf20Sopenharmony_ci unsigned int i = 0; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci if (!chan->channel->ext_info) 8908c2ecf20Sopenharmony_ci return i; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci for (ext_info = chan->channel->ext_info; ext_info->name; ext_info++) 8938c2ecf20Sopenharmony_ci ++i; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci return i; 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_get_channel_ext_info_count); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_cistatic const struct iio_chan_spec_ext_info *iio_lookup_ext_info( 9008c2ecf20Sopenharmony_ci const struct iio_channel *chan, 9018c2ecf20Sopenharmony_ci const char *attr) 9028c2ecf20Sopenharmony_ci{ 9038c2ecf20Sopenharmony_ci const struct iio_chan_spec_ext_info *ext_info; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci if (!chan->channel->ext_info) 9068c2ecf20Sopenharmony_ci return NULL; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci for (ext_info = chan->channel->ext_info; ext_info->name; ++ext_info) { 9098c2ecf20Sopenharmony_ci if (!strcmp(attr, ext_info->name)) 9108c2ecf20Sopenharmony_ci return ext_info; 9118c2ecf20Sopenharmony_ci } 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci return NULL; 9148c2ecf20Sopenharmony_ci} 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_cissize_t iio_read_channel_ext_info(struct iio_channel *chan, 9178c2ecf20Sopenharmony_ci const char *attr, char *buf) 9188c2ecf20Sopenharmony_ci{ 9198c2ecf20Sopenharmony_ci const struct iio_chan_spec_ext_info *ext_info; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci ext_info = iio_lookup_ext_info(chan, attr); 9228c2ecf20Sopenharmony_ci if (!ext_info) 9238c2ecf20Sopenharmony_ci return -EINVAL; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci return ext_info->read(chan->indio_dev, ext_info->private, 9268c2ecf20Sopenharmony_ci chan->channel, buf); 9278c2ecf20Sopenharmony_ci} 9288c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_read_channel_ext_info); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_cissize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr, 9318c2ecf20Sopenharmony_ci const char *buf, size_t len) 9328c2ecf20Sopenharmony_ci{ 9338c2ecf20Sopenharmony_ci const struct iio_chan_spec_ext_info *ext_info; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci ext_info = iio_lookup_ext_info(chan, attr); 9368c2ecf20Sopenharmony_ci if (!ext_info) 9378c2ecf20Sopenharmony_ci return -EINVAL; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci return ext_info->write(chan->indio_dev, ext_info->private, 9408c2ecf20Sopenharmony_ci chan->channel, buf, len); 9418c2ecf20Sopenharmony_ci} 9428c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_write_channel_ext_info); 943