.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* The industrial I/O core in kernel channel mapping |
---|
2 | 3 | * |
---|
3 | 4 | * Copyright (c) 2011 Jonathan Cameron |
---|
4 | | - * |
---|
5 | | - * This program is free software; you can redistribute it and/or modify it |
---|
6 | | - * under the terms of the GNU General Public License version 2 as published by |
---|
7 | | - * the Free Software Foundation. |
---|
8 | 5 | */ |
---|
9 | 6 | #include <linux/err.h> |
---|
10 | 7 | #include <linux/export.h> |
---|
.. | .. |
---|
93 | 90 | |
---|
94 | 91 | #ifdef CONFIG_OF |
---|
95 | 92 | |
---|
96 | | -static int iio_dev_node_match(struct device *dev, void *data) |
---|
| 93 | +static int iio_dev_node_match(struct device *dev, const void *data) |
---|
97 | 94 | { |
---|
98 | 95 | return dev->of_node == data && dev->type == &iio_device_type; |
---|
99 | 96 | } |
---|
.. | .. |
---|
139 | 136 | |
---|
140 | 137 | idev = bus_find_device(&iio_bus_type, NULL, iiospec.np, |
---|
141 | 138 | iio_dev_node_match); |
---|
142 | | - of_node_put(iiospec.np); |
---|
143 | | - if (idev == NULL) |
---|
| 139 | + if (idev == NULL) { |
---|
| 140 | + of_node_put(iiospec.np); |
---|
144 | 141 | return -EPROBE_DEFER; |
---|
| 142 | + } |
---|
145 | 143 | |
---|
146 | 144 | indio_dev = dev_to_iio_dev(idev); |
---|
147 | 145 | channel->indio_dev = indio_dev; |
---|
.. | .. |
---|
149 | 147 | index = indio_dev->info->of_xlate(indio_dev, &iiospec); |
---|
150 | 148 | else |
---|
151 | 149 | index = __of_iio_simple_xlate(indio_dev, &iiospec); |
---|
| 150 | + of_node_put(iiospec.np); |
---|
152 | 151 | if (index < 0) |
---|
153 | 152 | goto err_put; |
---|
154 | 153 | channel->channel = &indio_dev->channels[index]; |
---|
.. | .. |
---|
363 | 362 | iio_channel_release(channel); |
---|
364 | 363 | } |
---|
365 | 364 | |
---|
366 | | -static int devm_iio_channel_match(struct device *dev, void *res, void *data) |
---|
367 | | -{ |
---|
368 | | - struct iio_channel **r = res; |
---|
369 | | - |
---|
370 | | - if (!r || !*r) { |
---|
371 | | - WARN_ON(!r || !*r); |
---|
372 | | - return 0; |
---|
373 | | - } |
---|
374 | | - |
---|
375 | | - return *r == data; |
---|
376 | | -} |
---|
377 | | - |
---|
378 | 365 | struct iio_channel *devm_iio_channel_get(struct device *dev, |
---|
379 | 366 | const char *channel_name) |
---|
380 | 367 | { |
---|
.. | .. |
---|
396 | 383 | return channel; |
---|
397 | 384 | } |
---|
398 | 385 | EXPORT_SYMBOL_GPL(devm_iio_channel_get); |
---|
399 | | - |
---|
400 | | -void devm_iio_channel_release(struct device *dev, struct iio_channel *channel) |
---|
401 | | -{ |
---|
402 | | - WARN_ON(devres_release(dev, devm_iio_channel_free, |
---|
403 | | - devm_iio_channel_match, channel)); |
---|
404 | | -} |
---|
405 | | -EXPORT_SYMBOL_GPL(devm_iio_channel_release); |
---|
406 | 386 | |
---|
407 | 387 | struct iio_channel *iio_channel_get_all(struct device *dev) |
---|
408 | 388 | { |
---|
.. | .. |
---|
517 | 497 | } |
---|
518 | 498 | EXPORT_SYMBOL_GPL(devm_iio_channel_get_all); |
---|
519 | 499 | |
---|
520 | | -void devm_iio_channel_release_all(struct device *dev, |
---|
521 | | - struct iio_channel *channels) |
---|
522 | | -{ |
---|
523 | | - WARN_ON(devres_release(dev, devm_iio_channel_free_all, |
---|
524 | | - devm_iio_channel_match, channels)); |
---|
525 | | -} |
---|
526 | | -EXPORT_SYMBOL_GPL(devm_iio_channel_release_all); |
---|
527 | | - |
---|
528 | 500 | static int iio_channel_read(struct iio_channel *chan, int *val, int *val2, |
---|
529 | 501 | enum iio_chan_info_enum info) |
---|
530 | 502 | { |
---|
.. | .. |
---|
591 | 563 | static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan, |
---|
592 | 564 | int raw, int *processed, unsigned int scale) |
---|
593 | 565 | { |
---|
594 | | - int scale_type, scale_val, scale_val2, offset; |
---|
| 566 | + int scale_type, scale_val, scale_val2; |
---|
| 567 | + int offset_type, offset_val, offset_val2; |
---|
595 | 568 | s64 raw64 = raw; |
---|
596 | | - int ret; |
---|
597 | 569 | |
---|
598 | | - ret = iio_channel_read(chan, &offset, NULL, IIO_CHAN_INFO_OFFSET); |
---|
599 | | - if (ret >= 0) |
---|
600 | | - raw64 += offset; |
---|
| 570 | + offset_type = iio_channel_read(chan, &offset_val, &offset_val2, |
---|
| 571 | + IIO_CHAN_INFO_OFFSET); |
---|
| 572 | + if (offset_type >= 0) { |
---|
| 573 | + switch (offset_type) { |
---|
| 574 | + case IIO_VAL_INT: |
---|
| 575 | + break; |
---|
| 576 | + case IIO_VAL_INT_PLUS_MICRO: |
---|
| 577 | + case IIO_VAL_INT_PLUS_NANO: |
---|
| 578 | + /* |
---|
| 579 | + * Both IIO_VAL_INT_PLUS_MICRO and IIO_VAL_INT_PLUS_NANO |
---|
| 580 | + * implicitely truncate the offset to it's integer form. |
---|
| 581 | + */ |
---|
| 582 | + break; |
---|
| 583 | + case IIO_VAL_FRACTIONAL: |
---|
| 584 | + offset_val /= offset_val2; |
---|
| 585 | + break; |
---|
| 586 | + case IIO_VAL_FRACTIONAL_LOG2: |
---|
| 587 | + offset_val >>= offset_val2; |
---|
| 588 | + break; |
---|
| 589 | + default: |
---|
| 590 | + return -EINVAL; |
---|
| 591 | + } |
---|
| 592 | + |
---|
| 593 | + raw64 += offset_val; |
---|
| 594 | + } |
---|
601 | 595 | |
---|
602 | 596 | scale_type = iio_channel_read(chan, &scale_val, &scale_val2, |
---|
603 | 597 | IIO_CHAN_INFO_SCALE); |
---|
604 | 598 | if (scale_type < 0) { |
---|
605 | 599 | /* |
---|
606 | | - * Just pass raw values as processed if no scaling is |
---|
607 | | - * available. |
---|
| 600 | + * If no channel scaling is available apply consumer scale to |
---|
| 601 | + * raw value and return. |
---|
608 | 602 | */ |
---|
609 | | - *processed = raw; |
---|
| 603 | + *processed = raw * scale; |
---|
610 | 604 | return 0; |
---|
611 | 605 | } |
---|
612 | 606 | |
---|
613 | 607 | switch (scale_type) { |
---|
614 | 608 | case IIO_VAL_INT: |
---|
615 | | - *processed = raw64 * scale_val; |
---|
| 609 | + *processed = raw64 * scale_val * scale; |
---|
616 | 610 | break; |
---|
617 | 611 | case IIO_VAL_INT_PLUS_MICRO: |
---|
618 | 612 | if (scale_val2 < 0) |
---|
.. | .. |
---|
733 | 727 | vals, type, length, info); |
---|
734 | 728 | } |
---|
735 | 729 | |
---|
736 | | -int iio_read_avail_channel_raw(struct iio_channel *chan, |
---|
737 | | - const int **vals, int *length) |
---|
| 730 | +int iio_read_avail_channel_attribute(struct iio_channel *chan, |
---|
| 731 | + const int **vals, int *type, int *length, |
---|
| 732 | + enum iio_chan_info_enum attribute) |
---|
738 | 733 | { |
---|
739 | 734 | int ret; |
---|
740 | | - int type; |
---|
741 | 735 | |
---|
742 | 736 | mutex_lock(&chan->indio_dev->info_exist_lock); |
---|
743 | 737 | if (!chan->indio_dev->info) { |
---|
.. | .. |
---|
745 | 739 | goto err_unlock; |
---|
746 | 740 | } |
---|
747 | 741 | |
---|
748 | | - ret = iio_channel_read_avail(chan, |
---|
749 | | - vals, &type, length, IIO_CHAN_INFO_RAW); |
---|
| 742 | + ret = iio_channel_read_avail(chan, vals, type, length, attribute); |
---|
750 | 743 | err_unlock: |
---|
751 | 744 | mutex_unlock(&chan->indio_dev->info_exist_lock); |
---|
752 | 745 | |
---|
| 746 | + return ret; |
---|
| 747 | +} |
---|
| 748 | +EXPORT_SYMBOL_GPL(iio_read_avail_channel_attribute); |
---|
| 749 | + |
---|
| 750 | +int iio_read_avail_channel_raw(struct iio_channel *chan, |
---|
| 751 | + const int **vals, int *length) |
---|
| 752 | +{ |
---|
| 753 | + int ret; |
---|
| 754 | + int type; |
---|
| 755 | + |
---|
| 756 | + ret = iio_read_avail_channel_attribute(chan, vals, &type, length, |
---|
| 757 | + IIO_CHAN_INFO_RAW); |
---|
| 758 | + |
---|
753 | 759 | if (ret >= 0 && type != IIO_VAL_INT) |
---|
754 | 760 | /* raw values are assumed to be IIO_VAL_INT */ |
---|
755 | 761 | ret = -EINVAL; |
---|