[RFC v2 08/11] iio: adc: sd modulator: add scale and offset support

From: Olivier Moysan
Date: Thu Jul 27 2023 - 11:06:30 EST


Register the SD modulator as an IIO backend device instead of
a standard IIO device. Expose scale and offset information to
IIO backend consumer.

Signed-off-by: Olivier Moysan <olivier.moysan@xxxxxxxxxxx>
---
drivers/iio/adc/sd_adc_modulator.c | 106 +++++++++++++++++++++++------
1 file changed, 86 insertions(+), 20 deletions(-)

diff --git a/drivers/iio/adc/sd_adc_modulator.c b/drivers/iio/adc/sd_adc_modulator.c
index 327cc2097f6c..e77e7884c403 100644
--- a/drivers/iio/adc/sd_adc_modulator.c
+++ b/drivers/iio/adc/sd_adc_modulator.c
@@ -6,44 +6,110 @@
* Author: Arnaud Pouliquen <arnaud.pouliquen@xxxxxx>.
*/

+#include <linux/iio/backend.h>
#include <linux/iio/iio.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>

-static const struct iio_info iio_sd_mod_iio_info;
+struct iio_sd_mod_priv {
+ struct regulator *vref;
+ int vref_mv;
+};

-static const struct iio_chan_spec iio_sd_mod_ch = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .scan_type = {
- .sign = 'u',
- .realbits = 1,
- .shift = 0,
- },
+static int sd_mod_enable(struct iio_backend *backend)
+{
+ struct iio_sd_mod_priv *priv = backend->priv;
+ int ret;
+
+ ret = regulator_enable(priv->vref);
+ if (ret) {
+ dev_err(&backend->dev, "Failed to enable regulator: %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_get_voltage(priv->vref);
+ priv->vref_mv = ret / 1000;
+
+ return 0;
+};
+
+static int sd_mod_disable(struct iio_backend *backend)
+{
+ struct iio_sd_mod_priv *priv = backend->priv;
+
+ return regulator_disable(priv->vref);
+};
+
+static int sd_mod_read(struct iio_backend *backend, int *val, int *val2, long mask)
+{
+ struct iio_sd_mod_priv *priv = backend->priv;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ *val = priv->vref_mv;
+ *val2 = 0;
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_OFFSET:
+ *val = 0;
+ *val2 = 0;
+ return IIO_VAL_INT;
+ }
+
+ return -EINVAL;
+};
+
+static const struct iio_backend_ops sd_mod_ops = {
+ .enable = sd_mod_enable,
+ .disable = sd_mod_disable,
+ .read_raw = sd_mod_read,
};

static int iio_sd_mod_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct iio_dev *iio;
+ struct regulator *vref;
+ struct iio_backend *backend;
+ struct iio_sd_mod_priv *priv;
+ int ret;

- iio = devm_iio_device_alloc(dev, 0);
- if (!iio)
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
return -ENOMEM;

- iio->name = dev_name(dev);
- iio->info = &iio_sd_mod_iio_info;
- iio->modes = INDIO_BUFFER_HARDWARE;
+ vref = devm_regulator_get_optional(dev, "vref");
+ if (IS_ERR(vref)) {
+ if (PTR_ERR(vref) != -ENODEV)
+ return dev_err_probe(dev, PTR_ERR(vref), "Failed to get vref\n");
+ } else {
+ priv->vref = vref;
+ }

- iio->num_channels = 1;
- iio->channels = &iio_sd_mod_ch;
+ backend = iio_backend_alloc(dev);
+ if (!backend) {
+ dev_err(dev, "Failed to allocate sd modulator backend data\n");
+ return -ENOMEM;
+ }
+
+ backend->priv = priv;
+ backend->ops = &sd_mod_ops;
+
+ ret = iio_backend_register(backend);
+ if (ret) {
+ dev_err(dev, "Failed to register backend: %d\n", ret);
+ goto err_free_backend;
+ }

- platform_set_drvdata(pdev, iio);
+ return 0;

- return devm_iio_device_register(&pdev->dev, iio);
-}
+err_free_backend:
+ iio_backend_free(&backend->dev);
+
+ return ret;
+};

static const struct of_device_id sd_adc_of_match[] = {
{ .compatible = "sd-modulator" },
--
2.25.1