All of lore.kernel.org
 help / color / mirror / Atom feed
From: Paul Cercueil <paul@crapouillou.net>
To: Jonathan Cameron <jic23@kernel.org>
Cc: linux-iio@vger.kernel.org, Paul Cercueil <paul@crapouillou.net>
Subject: [RFC] iio: afe: rescale: Add support for converting scale avail table
Date: Mon, 11 Jul 2022 20:37:14 +0100	[thread overview]
Message-ID: <20220711193714.50314-1-paul@crapouillou.net> (raw)

When the IIO channel has a scale_available attribute, we want the values
contained to be properly converted the same way the scale value is.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/iio/afe/iio-rescale.c   | 75 +++++++++++++++++++++++++++++++++
 include/linux/iio/afe/rescale.h |  2 +
 2 files changed, 77 insertions(+)


 Hi Jonathan,

 I'm trying to add support for converting the scale_available attribute
 in the iio-rescale driver.

 The code below works fine… as long as all the possible scales returned
 by the underlying IIO device driver are translated to the exact same
 type. The problem then is that rescale_process_scale() can return many
 different types, while rescale_read_avail() only supports returning one
 type.

 I don't really know what would be the way forward. Should the
 .read_avail callback support returning multiple types? Should
 rescale_process_scale() have an option to force all the types to be
 converted to a specific one?

 Thoughts welcome.

 Cheers,
 -Paul


diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c
index 6949d2151025..8b00ff3de733 100644
--- a/drivers/iio/afe/iio-rescale.c
+++ b/drivers/iio/afe/iio-rescale.c
@@ -232,6 +232,19 @@ static int rescale_read_avail(struct iio_dev *indio_dev,
 		*type = IIO_VAL_INT;
 		return iio_read_avail_channel_raw(rescale->source,
 						  vals, length);
+	case IIO_CHAN_INFO_SCALE:
+		if (rescale->chan_processed) {
+			return iio_read_avail_channel_attribute(rescale->source,
+								vals, type,
+								length,
+								IIO_CHAN_INFO_SCALE);
+		} else if (rescale->scale_len) {
+			*type = rescale->scale_type;
+			*length = rescale->scale_len;
+			*vals = rescale->scale_data;
+			return IIO_AVAIL_LIST;
+		}
+		fallthrough;
 	default:
 		return -EINVAL;
 	}
@@ -266,11 +279,63 @@ static ssize_t rescale_write_ext_info(struct iio_dev *indio_dev,
 					  buf, len);
 }
 
+static int rescale_init_scale_avail(struct device *dev, struct rescale *rescale)
+{
+	int ret, type, length, *data;
+	const int *scale_raw;
+	unsigned int i;
+
+	ret = iio_read_avail_channel_attribute(rescale->source, &scale_raw,
+					       &type, &length,
+					       IIO_CHAN_INFO_SCALE);
+	if (ret < 0)
+		return ret;
+
+	/* TODO: Support IIO_AVAIL_RANGE */
+	if (ret != IIO_AVAIL_LIST)
+		return -ENOTSUPP;
+
+	length <<= type == IIO_VAL_INT;
+
+	data = devm_kzalloc(dev, sizeof(*data) * length, GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	if (type == IIO_VAL_INT) {
+		/* Convert from integer to fractional form to ease processing */
+		for (i = 0; i < length / 2; i++) {
+			data[i * 2] = scale_raw[i];
+			data[i * 2 + 1] = 1;
+		}
+
+		type = IIO_VAL_FRACTIONAL;
+	} else {
+		/* Copy raw scale info into our own buffer */
+		memcpy(data, scale_raw, sizeof(*scale_raw) * length);
+	}
+
+	for (i = 0; i < length; i += 2) {
+		ret = rescale_process_scale(rescale, type,
+					    &data[i], &data[i + 1]);
+		if (ret < 0)
+			return ret;
+
+		type = ret;
+	}
+
+	rescale->scale_type = type;
+	rescale->scale_len = length;
+	rescale->scale_data = data;
+
+	return 0;
+}
+
 static int rescale_configure_channel(struct device *dev,
 				     struct rescale *rescale)
 {
 	struct iio_chan_spec *chan = &rescale->chan;
 	struct iio_chan_spec const *schan = rescale->source->channel;
+	int ret;
 
 	chan->indexed = 1;
 	chan->output = schan->output;
@@ -303,6 +368,16 @@ static int rescale_configure_channel(struct device *dev,
 	    !rescale->chan_processed)
 		chan->info_mask_separate_available |= BIT(IIO_CHAN_INFO_RAW);
 
+	if (iio_channel_has_available(schan, IIO_CHAN_INFO_SCALE)) {
+		chan->info_mask_separate_available |= BIT(IIO_CHAN_INFO_SCALE);
+
+		if (!rescale->chan_processed) {
+			ret = rescale_init_scale_avail(dev, rescale);
+			if (ret)
+				return ret;
+		}
+	}
+
 	return 0;
 }
 
diff --git a/include/linux/iio/afe/rescale.h b/include/linux/iio/afe/rescale.h
index 6eecb435488f..8618955695df 100644
--- a/include/linux/iio/afe/rescale.h
+++ b/include/linux/iio/afe/rescale.h
@@ -26,6 +26,8 @@ struct rescale {
 	s32 numerator;
 	s32 denominator;
 	s32 offset;
+	int scale_type, scale_len;
+	int *scale_data;
 };
 
 int rescale_process_scale(struct rescale *rescale, int scale_type,
-- 
2.35.1


             reply	other threads:[~2022-07-11 19:37 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-07-11 19:37 Paul Cercueil [this message]
2022-07-12  8:24 ` [RFC] iio: afe: rescale: Add support for converting scale avail table Andy Shevchenko
2022-07-12 10:13   ` Paul Cercueil
2022-07-12 10:15     ` Andy Shevchenko
2022-07-13 16:34 ` Jonathan Cameron
2022-07-14  9:26   ` Paul Cercueil

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220711193714.50314-1-paul@crapouillou.net \
    --to=paul@crapouillou.net \
    --cc=jic23@kernel.org \
    --cc=linux-iio@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.