^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * IIO rescale driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2018 Axentia Technologies AB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Author: Peter Rosin <peda@axentia.se>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/gcd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/iio/consumer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/iio/iio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/property.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) struct rescale;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct rescale_cfg {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) enum iio_chan_type type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) int (*props)(struct device *dev, struct rescale *rescale);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct rescale {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) const struct rescale_cfg *cfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct iio_channel *source;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct iio_chan_spec chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) struct iio_chan_spec_ext_info *ext_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) s32 numerator;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) s32 denominator;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static int rescale_read_raw(struct iio_dev *indio_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct iio_chan_spec const *chan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) int *val, int *val2, long mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) struct rescale *rescale = iio_priv(indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) s64 tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) switch (mask) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) case IIO_CHAN_INFO_RAW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) return iio_read_channel_raw(rescale->source, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) case IIO_CHAN_INFO_SCALE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) ret = iio_read_channel_scale(rescale->source, val, val2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) switch (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) case IIO_VAL_FRACTIONAL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) *val *= rescale->numerator;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) *val2 *= rescale->denominator;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) case IIO_VAL_INT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) *val *= rescale->numerator;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (rescale->denominator == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) *val2 = rescale->denominator;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) return IIO_VAL_FRACTIONAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) case IIO_VAL_FRACTIONAL_LOG2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) tmp = (s64)*val * 1000000000LL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) tmp = div_s64(tmp, rescale->denominator);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) tmp *= rescale->numerator;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) tmp = div_s64(tmp, 1000000000LL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) *val = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) static int rescale_read_avail(struct iio_dev *indio_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) struct iio_chan_spec const *chan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) const int **vals, int *type, int *length,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) long mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct rescale *rescale = iio_priv(indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) switch (mask) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) case IIO_CHAN_INFO_RAW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) *type = IIO_VAL_INT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) return iio_read_avail_channel_raw(rescale->source,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) vals, length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) static const struct iio_info rescale_info = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) .read_raw = rescale_read_raw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) .read_avail = rescale_read_avail,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) static ssize_t rescale_read_ext_info(struct iio_dev *indio_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) uintptr_t private,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) struct iio_chan_spec const *chan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) struct rescale *rescale = iio_priv(indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return iio_read_channel_ext_info(rescale->source,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) rescale->ext_info[private].name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) static ssize_t rescale_write_ext_info(struct iio_dev *indio_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) uintptr_t private,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) struct iio_chan_spec const *chan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) struct rescale *rescale = iio_priv(indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) return iio_write_channel_ext_info(rescale->source,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) rescale->ext_info[private].name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) static int rescale_configure_channel(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) struct rescale *rescale)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) struct iio_chan_spec *chan = &rescale->chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) struct iio_chan_spec const *schan = rescale->source->channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) chan->indexed = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) chan->output = schan->output;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) chan->ext_info = rescale->ext_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) chan->type = rescale->cfg->type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) if (!iio_channel_has_info(schan, IIO_CHAN_INFO_RAW) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) !iio_channel_has_info(schan, IIO_CHAN_INFO_SCALE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) dev_err(dev, "source channel does not support raw/scale\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) BIT(IIO_CHAN_INFO_SCALE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) if (iio_channel_has_available(schan, IIO_CHAN_INFO_RAW))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) chan->info_mask_separate_available |= BIT(IIO_CHAN_INFO_RAW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) static int rescale_current_sense_amplifier_props(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) struct rescale *rescale)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) u32 sense;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) u32 gain_mult = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) u32 gain_div = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) u32 factor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) ret = device_property_read_u32(dev, "sense-resistor-micro-ohms",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) &sense);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) dev_err(dev, "failed to read the sense resistance: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) device_property_read_u32(dev, "sense-gain-mult", &gain_mult);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) device_property_read_u32(dev, "sense-gain-div", &gain_div);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) * Calculate the scaling factor, 1 / (gain * sense), or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) * gain_div / (gain_mult * sense), while trying to keep the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) * numerator/denominator from overflowing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) factor = gcd(sense, 1000000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) rescale->numerator = 1000000 / factor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) rescale->denominator = sense / factor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) factor = gcd(rescale->numerator, gain_mult);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) rescale->numerator /= factor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) rescale->denominator *= gain_mult / factor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) factor = gcd(rescale->denominator, gain_div);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) rescale->numerator *= gain_div / factor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) rescale->denominator /= factor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) static int rescale_current_sense_shunt_props(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) struct rescale *rescale)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) u32 shunt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) u32 factor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) ret = device_property_read_u32(dev, "shunt-resistor-micro-ohms",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) &shunt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) dev_err(dev, "failed to read the shunt resistance: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) factor = gcd(shunt, 1000000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) rescale->numerator = 1000000 / factor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) rescale->denominator = shunt / factor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) static int rescale_voltage_divider_props(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) struct rescale *rescale)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) u32 factor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) ret = device_property_read_u32(dev, "output-ohms",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) &rescale->denominator);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) dev_err(dev, "failed to read output-ohms: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) ret = device_property_read_u32(dev, "full-ohms",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) &rescale->numerator);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) dev_err(dev, "failed to read full-ohms: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) factor = gcd(rescale->numerator, rescale->denominator);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) rescale->numerator /= factor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) rescale->denominator /= factor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) enum rescale_variant {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) CURRENT_SENSE_AMPLIFIER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) CURRENT_SENSE_SHUNT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) VOLTAGE_DIVIDER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) static const struct rescale_cfg rescale_cfg[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) [CURRENT_SENSE_AMPLIFIER] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) .type = IIO_CURRENT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) .props = rescale_current_sense_amplifier_props,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) [CURRENT_SENSE_SHUNT] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) .type = IIO_CURRENT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) .props = rescale_current_sense_shunt_props,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) [VOLTAGE_DIVIDER] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) .type = IIO_VOLTAGE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) .props = rescale_voltage_divider_props,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) static const struct of_device_id rescale_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) { .compatible = "current-sense-amplifier",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) .data = &rescale_cfg[CURRENT_SENSE_AMPLIFIER], },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) { .compatible = "current-sense-shunt",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) .data = &rescale_cfg[CURRENT_SENSE_SHUNT], },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) { .compatible = "voltage-divider",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) .data = &rescale_cfg[VOLTAGE_DIVIDER], },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) { /* sentinel */ }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) MODULE_DEVICE_TABLE(of, rescale_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) static int rescale_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) struct iio_dev *indio_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) struct iio_channel *source;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) struct rescale *rescale;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) int sizeof_ext_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) int sizeof_priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) source = devm_iio_channel_get(dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) if (IS_ERR(source))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) return dev_err_probe(dev, PTR_ERR(source),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) "failed to get source channel\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) sizeof_ext_info = iio_get_channel_ext_info_count(source);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) if (sizeof_ext_info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) sizeof_ext_info += 1; /* one extra entry for the sentinel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) sizeof_ext_info *= sizeof(*rescale->ext_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) sizeof_priv = sizeof(*rescale) + sizeof_ext_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) indio_dev = devm_iio_device_alloc(dev, sizeof_priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) if (!indio_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) rescale = iio_priv(indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) rescale->cfg = of_device_get_match_data(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) rescale->numerator = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) rescale->denominator = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) ret = rescale->cfg->props(dev, rescale);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) if (!rescale->numerator || !rescale->denominator) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) dev_err(dev, "invalid scaling factor.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) platform_set_drvdata(pdev, indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) rescale->source = source;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) indio_dev->name = dev_name(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) indio_dev->info = &rescale_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) indio_dev->modes = INDIO_DIRECT_MODE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) indio_dev->channels = &rescale->chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) indio_dev->num_channels = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) if (sizeof_ext_info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) rescale->ext_info = devm_kmemdup(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) source->channel->ext_info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) sizeof_ext_info, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) if (!rescale->ext_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) for (i = 0; rescale->ext_info[i].name; ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) struct iio_chan_spec_ext_info *ext_info =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) &rescale->ext_info[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) if (source->channel->ext_info[i].read)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) ext_info->read = rescale_read_ext_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) if (source->channel->ext_info[i].write)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) ext_info->write = rescale_write_ext_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) ext_info->private = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) ret = rescale_configure_channel(dev, rescale);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) return devm_iio_device_register(dev, indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) static struct platform_driver rescale_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) .probe = rescale_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) .name = "iio-rescale",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) .of_match_table = rescale_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) module_platform_driver(rescale_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) MODULE_DESCRIPTION("IIO rescale driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) MODULE_LICENSE("GPL v2");