diff options
Diffstat (limited to 'drivers/iio/inkern.c')
-rw-r--r-- | drivers/iio/inkern.c | 500 |
1 files changed, 290 insertions, 210 deletions
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 5a8351c9a426..872fd5c24147 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -5,11 +5,12 @@ */ #include <linux/err.h> #include <linux/export.h> +#include <linux/property.h> #include <linux/slab.h> #include <linux/mutex.h> -#include <linux/of.h> #include <linux/iio/iio.h> +#include <linux/iio/iio-opaque.h> #include "iio_core.h" #include <linux/iio/machine.h> #include <linux/iio/driver.h> @@ -24,18 +25,33 @@ struct iio_map_internal { static LIST_HEAD(iio_map_list); static DEFINE_MUTEX(iio_map_list_lock); +static int iio_map_array_unregister_locked(struct iio_dev *indio_dev) +{ + int ret = -ENODEV; + struct iio_map_internal *mapi, *next; + + list_for_each_entry_safe(mapi, next, &iio_map_list, l) { + if (indio_dev == mapi->indio_dev) { + list_del(&mapi->l); + kfree(mapi); + ret = 0; + } + } + return ret; +} + int iio_map_array_register(struct iio_dev *indio_dev, struct iio_map *maps) { int i = 0, ret = 0; struct iio_map_internal *mapi; - if (maps == NULL) + if (!maps) return 0; mutex_lock(&iio_map_list_lock); - while (maps[i].consumer_dev_name != NULL) { + while (maps[i].consumer_dev_name) { mapi = kzalloc(sizeof(*mapi), GFP_KERNEL); - if (mapi == NULL) { + if (!mapi) { ret = -ENOMEM; goto error_ret; } @@ -45,34 +61,46 @@ int iio_map_array_register(struct iio_dev *indio_dev, struct iio_map *maps) i++; } error_ret: + if (ret) + iio_map_array_unregister_locked(indio_dev); mutex_unlock(&iio_map_list_lock); return ret; } EXPORT_SYMBOL_GPL(iio_map_array_register); - /* * Remove all map entries associated with the given iio device */ int iio_map_array_unregister(struct iio_dev *indio_dev) { - int ret = -ENODEV; - struct iio_map_internal *mapi, *next; + int ret; mutex_lock(&iio_map_list_lock); - list_for_each_entry_safe(mapi, next, &iio_map_list, l) { - if (indio_dev == mapi->indio_dev) { - list_del(&mapi->l); - kfree(mapi); - ret = 0; - } - } + ret = iio_map_array_unregister_locked(indio_dev); mutex_unlock(&iio_map_list_lock); + return ret; } EXPORT_SYMBOL_GPL(iio_map_array_unregister); +static void iio_map_array_unregister_cb(void *indio_dev) +{ + iio_map_array_unregister(indio_dev); +} + +int devm_iio_map_array_register(struct device *dev, struct iio_dev *indio_dev, struct iio_map *maps) +{ + int ret; + + ret = iio_map_array_register(indio_dev, maps); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, iio_map_array_unregister_cb, indio_dev); +} +EXPORT_SYMBOL_GPL(devm_iio_map_array_register); + static const struct iio_chan_spec *iio_chan_spec_from_name(const struct iio_dev *indio_dev, const char *name) { @@ -88,15 +116,8 @@ static const struct iio_chan_spec return chan; } -#ifdef CONFIG_OF - -static int iio_dev_node_match(struct device *dev, const void *data) -{ - return dev->of_node == data && dev->type == &iio_device_type; -} - /** - * __of_iio_simple_xlate - translate iiospec to the IIO channel index + * __fwnode_iio_simple_xlate - translate iiospec to the IIO channel index * @indio_dev: pointer to the iio_dev structure * @iiospec: IIO specifier as found in the device tree * @@ -105,14 +126,14 @@ static int iio_dev_node_match(struct device *dev, const void *data) * whether IIO index is less than num_channels (that is specified in the * iio_dev). */ -static int __of_iio_simple_xlate(struct iio_dev *indio_dev, - const struct of_phandle_args *iiospec) +static int __fwnode_iio_simple_xlate(struct iio_dev *indio_dev, + const struct fwnode_reference_args *iiospec) { - if (!iiospec->args_count) + if (!iiospec->nargs) return 0; if (iiospec->args[0] >= indio_dev->num_channels) { - dev_err(&indio_dev->dev, "invalid channel index %u\n", + dev_err(&indio_dev->dev, "invalid channel index %llu\n", iiospec->args[0]); return -EINVAL; } @@ -120,32 +141,33 @@ static int __of_iio_simple_xlate(struct iio_dev *indio_dev, return iiospec->args[0]; } -static int __of_iio_channel_get(struct iio_channel *channel, - struct device_node *np, int index) +static int __fwnode_iio_channel_get(struct iio_channel *channel, + struct fwnode_handle *fwnode, int index) { + struct fwnode_reference_args iiospec; struct device *idev; struct iio_dev *indio_dev; int err; - struct of_phandle_args iiospec; - err = of_parse_phandle_with_args(np, "io-channels", - "#io-channel-cells", - index, &iiospec); + err = fwnode_property_get_reference_args(fwnode, "io-channels", + "#io-channel-cells", 0, + index, &iiospec); if (err) return err; - idev = bus_find_device(&iio_bus_type, NULL, iiospec.np, - iio_dev_node_match); - of_node_put(iiospec.np); - if (idev == NULL) + idev = bus_find_device_by_fwnode(&iio_bus_type, iiospec.fwnode); + if (!idev) { + fwnode_handle_put(iiospec.fwnode); return -EPROBE_DEFER; + } indio_dev = dev_to_iio_dev(idev); channel->indio_dev = indio_dev; - if (indio_dev->info->of_xlate) - index = indio_dev->info->of_xlate(indio_dev, &iiospec); + if (indio_dev->info->fwnode_xlate) + index = indio_dev->info->fwnode_xlate(indio_dev, &iiospec); else - index = __of_iio_simple_xlate(indio_dev, &iiospec); + index = __fwnode_iio_simple_xlate(indio_dev, &iiospec); + fwnode_handle_put(iiospec.fwnode); if (index < 0) goto err_put; channel->channel = &indio_dev->channels[index]; @@ -157,7 +179,8 @@ err_put: return index; } -static struct iio_channel *of_iio_channel_get(struct device_node *np, int index) +static struct iio_channel *fwnode_iio_channel_get(struct fwnode_handle *fwnode, + int index) { struct iio_channel *channel; int err; @@ -166,10 +189,10 @@ static struct iio_channel *of_iio_channel_get(struct device_node *np, int index) return ERR_PTR(-EINVAL); channel = kzalloc(sizeof(*channel), GFP_KERNEL); - if (channel == NULL) + if (!channel) return ERR_PTR(-ENOMEM); - err = __of_iio_channel_get(channel, np, index); + err = __fwnode_iio_channel_get(channel, fwnode, index); if (err) goto err_free_channel; @@ -180,73 +203,116 @@ err_free_channel: return ERR_PTR(err); } -static struct iio_channel *of_iio_channel_get_by_name(struct device_node *np, - const char *name) +static struct iio_channel * +__fwnode_iio_channel_get_by_name(struct fwnode_handle *fwnode, const char *name) { - struct iio_channel *chan = NULL; - - /* Walk up the tree of devices looking for a matching iio channel */ - while (np) { - int index = 0; - + struct iio_channel *chan; + int index = 0; + + /* + * For named iio channels, first look up the name in the + * "io-channel-names" property. If it cannot be found, the + * index will be an error code, and fwnode_iio_channel_get() + * will fail. + */ + if (name) + index = fwnode_property_match_string(fwnode, "io-channel-names", + name); + + chan = fwnode_iio_channel_get(fwnode, index); + if (!IS_ERR(chan) || PTR_ERR(chan) == -EPROBE_DEFER) + return chan; + if (name) { + if (index >= 0) { + pr_err("ERROR: could not get IIO channel %pfw:%s(%i)\n", + fwnode, name, index); + /* + * In this case, we found 'name' in 'io-channel-names' + * but somehow we still fail so that we should not proceed + * with any other lookup. Hence, explicitly return -EINVAL + * (maybe not the better error code) so that the caller + * won't do a system lookup. + */ + return ERR_PTR(-EINVAL); + } /* - * For named iio channels, first look up the name in the - * "io-channel-names" property. If it cannot be found, the - * index will be an error code, and of_iio_channel_get() - * will fail. + * If index < 0, then fwnode_property_get_reference_args() fails + * with -EINVAL or -ENOENT (ACPI case) which is expected. We + * should not proceed if we get any other error. */ - if (name) - index = of_property_match_string(np, "io-channel-names", - name); - chan = of_iio_channel_get(np, index); - if (!IS_ERR(chan) || PTR_ERR(chan) == -EPROBE_DEFER) - break; - else if (name && index >= 0) { - pr_err("ERROR: could not get IIO channel %pOF:%s(%i)\n", - np, name ? name : "", index); - return NULL; - } - + if (PTR_ERR(chan) != -EINVAL && PTR_ERR(chan) != -ENOENT) + return chan; + } else if (PTR_ERR(chan) != -ENOENT) { /* - * No matching IIO channel found on this node. - * If the parent node has a "io-channel-ranges" property, - * then we can try one of its channels. + * if !name, then we should only proceed the lookup if + * fwnode_property_get_reference_args() returns -ENOENT. */ - np = np->parent; - if (np && !of_get_property(np, "io-channel-ranges", NULL)) - return NULL; + return chan; } - return chan; + /* so we continue the lookup */ + return ERR_PTR(-ENODEV); +} + +struct iio_channel *fwnode_iio_channel_get_by_name(struct fwnode_handle *fwnode, + const char *name) +{ + struct fwnode_handle *parent; + struct iio_channel *chan; + + /* Walk up the tree of devices looking for a matching iio channel */ + chan = __fwnode_iio_channel_get_by_name(fwnode, name); + if (!IS_ERR(chan) || PTR_ERR(chan) != -ENODEV) + return chan; + + /* + * No matching IIO channel found on this node. + * If the parent node has a "io-channel-ranges" property, + * then we can try one of its channels. + */ + fwnode_for_each_parent_node(fwnode, parent) { + if (!fwnode_property_present(parent, "io-channel-ranges")) { + fwnode_handle_put(parent); + return ERR_PTR(-ENODEV); + } + + chan = __fwnode_iio_channel_get_by_name(fwnode, name); + if (!IS_ERR(chan) || PTR_ERR(chan) != -ENODEV) { + fwnode_handle_put(parent); + return chan; + } + } + + return ERR_PTR(-ENODEV); } +EXPORT_SYMBOL_GPL(fwnode_iio_channel_get_by_name); -static struct iio_channel *of_iio_channel_get_all(struct device *dev) +static struct iio_channel *fwnode_iio_channel_get_all(struct device *dev) { + struct fwnode_handle *fwnode = dev_fwnode(dev); struct iio_channel *chans; int i, mapind, nummaps = 0; int ret; do { - ret = of_parse_phandle_with_args(dev->of_node, - "io-channels", - "#io-channel-cells", - nummaps, NULL); + ret = fwnode_property_get_reference_args(fwnode, "io-channels", + "#io-channel-cells", 0, + nummaps, NULL); if (ret < 0) break; } while (++nummaps); - if (nummaps == 0) /* no error, return NULL to search map table */ - return NULL; + if (nummaps == 0) + return ERR_PTR(-ENODEV); /* NULL terminated array to save passing size */ chans = kcalloc(nummaps + 1, sizeof(*chans), GFP_KERNEL); - if (chans == NULL) + if (!chans) return ERR_PTR(-ENOMEM); - /* Search for OF matches */ + /* Search for FW matches */ for (mapind = 0; mapind < nummaps; mapind++) { - ret = __of_iio_channel_get(&chans[mapind], dev->of_node, - mapind); + ret = __fwnode_iio_channel_get(&chans[mapind], fwnode, mapind); if (ret) goto error_free_chans; } @@ -259,21 +325,6 @@ error_free_chans: return ERR_PTR(ret); } -#else /* CONFIG_OF */ - -static inline struct iio_channel * -of_iio_channel_get_by_name(struct device_node *np, const char *name) -{ - return NULL; -} - -static inline struct iio_channel *of_iio_channel_get_all(struct device *dev) -{ - return NULL; -} - -#endif /* CONFIG_OF */ - static struct iio_channel *iio_channel_get_sys(const char *name, const char *channel_name) { @@ -281,7 +332,7 @@ static struct iio_channel *iio_channel_get_sys(const char *name, struct iio_channel *channel; int err; - if (name == NULL && channel_name == NULL) + if (!(name || channel_name)) return ERR_PTR(-ENODEV); /* first find matching entry the channel map */ @@ -296,11 +347,11 @@ static struct iio_channel *iio_channel_get_sys(const char *name, break; } mutex_unlock(&iio_map_list_lock); - if (c == NULL) + if (!c) return ERR_PTR(-ENODEV); channel = kzalloc(sizeof(*channel), GFP_KERNEL); - if (channel == NULL) { + if (!channel) { err = -ENOMEM; goto error_no_mem; } @@ -312,7 +363,7 @@ static struct iio_channel *iio_channel_get_sys(const char *name, iio_chan_spec_from_name(channel->indio_dev, c->map->adc_channel_label); - if (channel->channel == NULL) { + if (!channel->channel) { err = -EINVAL; goto error_no_chan; } @@ -334,9 +385,9 @@ struct iio_channel *iio_channel_get(struct device *dev, struct iio_channel *channel; if (dev) { - channel = of_iio_channel_get_by_name(dev->of_node, - channel_name); - if (channel != NULL) + channel = fwnode_iio_channel_get_by_name(dev_fwnode(dev), + channel_name); + if (!IS_ERR(channel) || PTR_ERR(channel) != -ENODEV) return channel; } @@ -353,53 +404,47 @@ void iio_channel_release(struct iio_channel *channel) } EXPORT_SYMBOL_GPL(iio_channel_release); -static void devm_iio_channel_free(struct device *dev, void *res) +static void devm_iio_channel_free(void *iio_channel) { - struct iio_channel *channel = *(struct iio_channel **)res; - - iio_channel_release(channel); -} - -static int devm_iio_channel_match(struct device *dev, void *res, void *data) -{ - struct iio_channel **r = res; - - if (!r || !*r) { - WARN_ON(!r || !*r); - return 0; - } - - return *r == data; + iio_channel_release(iio_channel); } struct iio_channel *devm_iio_channel_get(struct device *dev, const char *channel_name) { - struct iio_channel **ptr, *channel; - - ptr = devres_alloc(devm_iio_channel_free, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return ERR_PTR(-ENOMEM); + struct iio_channel *channel; + int ret; channel = iio_channel_get(dev, channel_name); - if (IS_ERR(channel)) { - devres_free(ptr); + if (IS_ERR(channel)) return channel; - } - *ptr = channel; - devres_add(dev, ptr); + ret = devm_add_action_or_reset(dev, devm_iio_channel_free, channel); + if (ret) + return ERR_PTR(ret); return channel; } EXPORT_SYMBOL_GPL(devm_iio_channel_get); -void devm_iio_channel_release(struct device *dev, struct iio_channel *channel) +struct iio_channel *devm_fwnode_iio_channel_get_by_name(struct device *dev, + struct fwnode_handle *fwnode, + const char *channel_name) { - WARN_ON(devres_release(dev, devm_iio_channel_free, - devm_iio_channel_match, channel)); + struct iio_channel *channel; + int ret; + + channel = fwnode_iio_channel_get_by_name(fwnode, channel_name); + if (IS_ERR(channel)) + return channel; + + ret = devm_add_action_or_reset(dev, devm_iio_channel_free, channel); + if (ret) + return ERR_PTR(ret); + + return channel; } -EXPORT_SYMBOL_GPL(devm_iio_channel_release); +EXPORT_SYMBOL_GPL(devm_fwnode_iio_channel_get_by_name); struct iio_channel *iio_channel_get_all(struct device *dev) { @@ -410,11 +455,15 @@ struct iio_channel *iio_channel_get_all(struct device *dev) int mapind = 0; int i, ret; - if (dev == NULL) + if (!dev) return ERR_PTR(-EINVAL); - chans = of_iio_channel_get_all(dev); - if (chans) + chans = fwnode_iio_channel_get_all(dev); + /* + * We only want to carry on if the error is -ENODEV. Anything else + * should be reported up the stack. + */ + if (!IS_ERR(chans) || PTR_ERR(chans) != -ENODEV) return chans; name = dev_name(dev); @@ -434,7 +483,7 @@ struct iio_channel *iio_channel_get_all(struct device *dev) /* NULL terminated array to save passing size */ chans = kcalloc(nummaps + 1, sizeof(*chans), GFP_KERNEL); - if (chans == NULL) { + if (!chans) { ret = -ENOMEM; goto error_ret; } @@ -448,7 +497,7 @@ struct iio_channel *iio_channel_get_all(struct device *dev) chans[mapind].channel = iio_chan_spec_from_name(chans[mapind].indio_dev, c->map->adc_channel_label); - if (chans[mapind].channel == NULL) { + if (!chans[mapind].channel) { ret = -EINVAL; goto error_free_chans; } @@ -486,51 +535,38 @@ void iio_channel_release_all(struct iio_channel *channels) } EXPORT_SYMBOL_GPL(iio_channel_release_all); -static void devm_iio_channel_free_all(struct device *dev, void *res) +static void devm_iio_channel_free_all(void *iio_channels) { - struct iio_channel *channels = *(struct iio_channel **)res; - - iio_channel_release_all(channels); + iio_channel_release_all(iio_channels); } struct iio_channel *devm_iio_channel_get_all(struct device *dev) { - struct iio_channel **ptr, *channels; - - ptr = devres_alloc(devm_iio_channel_free_all, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return ERR_PTR(-ENOMEM); + struct iio_channel *channels; + int ret; channels = iio_channel_get_all(dev); - if (IS_ERR(channels)) { - devres_free(ptr); + if (IS_ERR(channels)) return channels; - } - *ptr = channels; - devres_add(dev, ptr); + ret = devm_add_action_or_reset(dev, devm_iio_channel_free_all, + channels); + if (ret) + return ERR_PTR(ret); return channels; } EXPORT_SYMBOL_GPL(devm_iio_channel_get_all); -void devm_iio_channel_release_all(struct device *dev, - struct iio_channel *channels) -{ - WARN_ON(devres_release(dev, devm_iio_channel_free_all, - devm_iio_channel_match, channels)); -} -EXPORT_SYMBOL_GPL(devm_iio_channel_release_all); - static int iio_channel_read(struct iio_channel *chan, int *val, int *val2, - enum iio_chan_info_enum info) + enum iio_chan_info_enum info) { int unused; int vals[INDIO_MAX_RAW_ELEMENTS]; int ret; int val_len = 2; - if (val2 == NULL) + if (!val2) val2 = &unused; if (!iio_channel_has_info(chan->channel, info)) @@ -542,26 +578,28 @@ static int iio_channel_read(struct iio_channel *chan, int *val, int *val2, vals, &val_len, info); *val = vals[0]; *val2 = vals[1]; - } else + } else { ret = chan->indio_dev->info->read_raw(chan->indio_dev, chan->channel, val, val2, info); + } return ret; } int iio_read_channel_raw(struct iio_channel *chan, int *val) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); int ret; - mutex_lock(&chan->indio_dev->info_exist_lock); - if (chan->indio_dev->info == NULL) { + mutex_lock(&iio_dev_opaque->info_exist_lock); + if (!chan->indio_dev->info) { ret = -ENODEV; goto err_unlock; } ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW); err_unlock: - mutex_unlock(&chan->indio_dev->info_exist_lock); + mutex_unlock(&iio_dev_opaque->info_exist_lock); return ret; } @@ -569,47 +607,71 @@ EXPORT_SYMBOL_GPL(iio_read_channel_raw); int iio_read_channel_average_raw(struct iio_channel *chan, int *val) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); int ret; - mutex_lock(&chan->indio_dev->info_exist_lock); - if (chan->indio_dev->info == NULL) { + mutex_lock(&iio_dev_opaque->info_exist_lock); + if (!chan->indio_dev->info) { ret = -ENODEV; goto err_unlock; } ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_AVERAGE_RAW); err_unlock: - mutex_unlock(&chan->indio_dev->info_exist_lock); + mutex_unlock(&iio_dev_opaque->info_exist_lock); return ret; } EXPORT_SYMBOL_GPL(iio_read_channel_average_raw); static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan, - int raw, int *processed, unsigned int scale) + int raw, int *processed, + unsigned int scale) { - int scale_type, scale_val, scale_val2, offset; + int scale_type, scale_val, scale_val2; + int offset_type, offset_val, offset_val2; s64 raw64 = raw; - int ret; - ret = iio_channel_read(chan, &offset, NULL, IIO_CHAN_INFO_OFFSET); - if (ret >= 0) - raw64 += offset; + offset_type = iio_channel_read(chan, &offset_val, &offset_val2, + IIO_CHAN_INFO_OFFSET); + if (offset_type >= 0) { + switch (offset_type) { + case IIO_VAL_INT: + break; + case IIO_VAL_INT_PLUS_MICRO: + case IIO_VAL_INT_PLUS_NANO: + /* + * Both IIO_VAL_INT_PLUS_MICRO and IIO_VAL_INT_PLUS_NANO + * implicitely truncate the offset to it's integer form. + */ + break; + case IIO_VAL_FRACTIONAL: + offset_val /= offset_val2; + break; + case IIO_VAL_FRACTIONAL_LOG2: + offset_val >>= offset_val2; + break; + default: + return -EINVAL; + } + + raw64 += offset_val; + } scale_type = iio_channel_read(chan, &scale_val, &scale_val2, - IIO_CHAN_INFO_SCALE); + IIO_CHAN_INFO_SCALE); if (scale_type < 0) { /* - * Just pass raw values as processed if no scaling is - * available. + * If no channel scaling is available apply consumer scale to + * raw value and return. */ - *processed = raw; + *processed = raw * scale; return 0; } switch (scale_type) { case IIO_VAL_INT: - *processed = raw64 * scale_val; + *processed = raw64 * scale_val * scale; break; case IIO_VAL_INT_PLUS_MICRO: if (scale_val2 < 0) @@ -642,20 +704,21 @@ static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan, } int iio_convert_raw_to_processed(struct iio_channel *chan, int raw, - int *processed, unsigned int scale) + int *processed, unsigned int scale) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); int ret; - mutex_lock(&chan->indio_dev->info_exist_lock); - if (chan->indio_dev->info == NULL) { + mutex_lock(&iio_dev_opaque->info_exist_lock); + if (!chan->indio_dev->info) { ret = -ENODEV; goto err_unlock; } ret = iio_convert_raw_to_processed_unlocked(chan, raw, processed, - scale); + scale); err_unlock: - mutex_unlock(&chan->indio_dev->info_exist_lock); + mutex_unlock(&iio_dev_opaque->info_exist_lock); return ret; } @@ -664,17 +727,18 @@ EXPORT_SYMBOL_GPL(iio_convert_raw_to_processed); int iio_read_channel_attribute(struct iio_channel *chan, int *val, int *val2, enum iio_chan_info_enum attribute) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); int ret; - mutex_lock(&chan->indio_dev->info_exist_lock); - if (chan->indio_dev->info == NULL) { + mutex_lock(&iio_dev_opaque->info_exist_lock); + if (!chan->indio_dev->info) { ret = -ENODEV; goto err_unlock; } ret = iio_channel_read(chan, val, val2, attribute); err_unlock: - mutex_unlock(&chan->indio_dev->info_exist_lock); + mutex_unlock(&iio_dev_opaque->info_exist_lock); return ret; } @@ -686,12 +750,14 @@ int iio_read_channel_offset(struct iio_channel *chan, int *val, int *val2) } EXPORT_SYMBOL_GPL(iio_read_channel_offset); -int iio_read_channel_processed(struct iio_channel *chan, int *val) +int iio_read_channel_processed_scale(struct iio_channel *chan, int *val, + unsigned int scale) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); int ret; - mutex_lock(&chan->indio_dev->info_exist_lock); - if (chan->indio_dev->info == NULL) { + mutex_lock(&iio_dev_opaque->info_exist_lock); + if (!chan->indio_dev->info) { ret = -ENODEV; goto err_unlock; } @@ -699,18 +765,29 @@ int iio_read_channel_processed(struct iio_channel *chan, int *val) if (iio_channel_has_info(chan->channel, IIO_CHAN_INFO_PROCESSED)) { ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_PROCESSED); + if (ret < 0) + goto err_unlock; + *val *= scale; } else { ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW); if (ret < 0) goto err_unlock; - ret = iio_convert_raw_to_processed_unlocked(chan, *val, val, 1); + ret = iio_convert_raw_to_processed_unlocked(chan, *val, val, + scale); } err_unlock: - mutex_unlock(&chan->indio_dev->info_exist_lock); + mutex_unlock(&iio_dev_opaque->info_exist_lock); return ret; } +EXPORT_SYMBOL_GPL(iio_read_channel_processed_scale); + +int iio_read_channel_processed(struct iio_channel *chan, int *val) +{ + /* This is just a special case with scale factor 1 */ + return iio_read_channel_processed_scale(chan, val, 1); +} EXPORT_SYMBOL_GPL(iio_read_channel_processed); int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2) @@ -734,9 +811,10 @@ int iio_read_avail_channel_attribute(struct iio_channel *chan, const int **vals, int *type, int *length, enum iio_chan_info_enum attribute) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); int ret; - mutex_lock(&chan->indio_dev->info_exist_lock); + mutex_lock(&iio_dev_opaque->info_exist_lock); if (!chan->indio_dev->info) { ret = -ENODEV; goto err_unlock; @@ -744,7 +822,7 @@ int iio_read_avail_channel_attribute(struct iio_channel *chan, ret = iio_channel_read_avail(chan, vals, type, length, attribute); err_unlock: - mutex_unlock(&chan->indio_dev->info_exist_lock); + mutex_unlock(&iio_dev_opaque->info_exist_lock); return ret; } @@ -757,7 +835,7 @@ int iio_read_avail_channel_raw(struct iio_channel *chan, int type; ret = iio_read_avail_channel_attribute(chan, vals, &type, length, - IIO_CHAN_INFO_RAW); + IIO_CHAN_INFO_RAW); if (ret >= 0 && type != IIO_VAL_INT) /* raw values are assumed to be IIO_VAL_INT */ @@ -816,10 +894,11 @@ static int iio_channel_read_max(struct iio_channel *chan, int iio_read_max_channel_raw(struct iio_channel *chan, int *val) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); int ret; int type; - mutex_lock(&chan->indio_dev->info_exist_lock); + mutex_lock(&iio_dev_opaque->info_exist_lock); if (!chan->indio_dev->info) { ret = -ENODEV; goto err_unlock; @@ -827,7 +906,7 @@ int iio_read_max_channel_raw(struct iio_channel *chan, int *val) ret = iio_channel_read_max(chan, val, NULL, &type, IIO_CHAN_INFO_RAW); err_unlock: - mutex_unlock(&chan->indio_dev->info_exist_lock); + mutex_unlock(&iio_dev_opaque->info_exist_lock); return ret; } @@ -835,18 +914,19 @@ EXPORT_SYMBOL_GPL(iio_read_max_channel_raw); int iio_get_channel_type(struct iio_channel *chan, enum iio_chan_type *type) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); int ret = 0; /* Need to verify underlying driver has not gone away */ - mutex_lock(&chan->indio_dev->info_exist_lock); - if (chan->indio_dev->info == NULL) { + mutex_lock(&iio_dev_opaque->info_exist_lock); + if (!chan->indio_dev->info) { ret = -ENODEV; goto err_unlock; } *type = chan->channel->type; err_unlock: - mutex_unlock(&chan->indio_dev->info_exist_lock); + mutex_unlock(&iio_dev_opaque->info_exist_lock); return ret; } @@ -862,17 +942,18 @@ static int iio_channel_write(struct iio_channel *chan, int val, int val2, int iio_write_channel_attribute(struct iio_channel *chan, int val, int val2, enum iio_chan_info_enum attribute) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); int ret; - mutex_lock(&chan->indio_dev->info_exist_lock); - if (chan->indio_dev->info == NULL) { + mutex_lock(&iio_dev_opaque->info_exist_lock); + if (!chan->indio_dev->info) { ret = -ENODEV; goto err_unlock; } ret = iio_channel_write(chan, val, val2, attribute); err_unlock: - mutex_unlock(&chan->indio_dev->info_exist_lock); + mutex_unlock(&iio_dev_opaque->info_exist_lock); return ret; } @@ -899,9 +980,8 @@ unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan) } EXPORT_SYMBOL_GPL(iio_get_channel_ext_info_count); -static const struct iio_chan_spec_ext_info *iio_lookup_ext_info( - const struct iio_channel *chan, - const char *attr) +static const struct iio_chan_spec_ext_info * +iio_lookup_ext_info(const struct iio_channel *chan, const char *attr) { const struct iio_chan_spec_ext_info *ext_info; |