iio: dac: ad3552r-hs: add support for internal ramp
authorAngelo Dureghello <adureghello@baylibre.com>
Wed, 9 Apr 2025 18:36:32 +0000 (20:36 +0200)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Tue, 22 Apr 2025 18:10:04 +0000 (19:10 +0100)
The ad3552r can be feeded from the HDL controller by an internally
generated 16bit ramp, useful for debug pourposes. Add debugfs a file
to enable or disable it.

Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
Link: https://patch.msgid.link/20250409-wip-bl-ad3552r-fixes-v5-5-fb429c3a6515@baylibre.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
drivers/iio/dac/ad3552r-hs.c

index 37397e188f225a8099745ec03f7c604da76960b1..41b96b48ba98b6009723c6a7c0c39071083852f8 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/bitfield.h>
+#include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/gpio/consumer.h>
 #include <linux/iio/backend.h>
@@ -54,6 +55,18 @@ struct ad3552r_hs_state {
        struct ad3552r_hs_platform_data *data;
        /* INTERFACE_CONFIG_D register cache, in DDR we cannot read values. */
        u32 config_d;
+       /* Protects backend I/O operations from concurrent accesses. */
+       struct mutex lock;
+};
+
+enum ad3552r_sources {
+       AD3552R_SRC_NORMAL,
+       AD3552R_SRC_RAMP_16BIT,
+};
+
+static const char * const dbgfs_attr_source[] = {
+       [AD3552R_SRC_NORMAL] = "normal",
+       [AD3552R_SRC_RAMP_16BIT] = "ramp-16bit",
 };
 
 static int ad3552r_hs_reg_read(struct ad3552r_hs_state *st, u32 reg, u32 *val,
@@ -65,6 +78,20 @@ static int ad3552r_hs_reg_read(struct ad3552r_hs_state *st, u32 reg, u32 *val,
        return st->data->bus_reg_read(st->back, reg, val, xfer_size);
 }
 
+static int ad3552r_hs_set_data_source(struct ad3552r_hs_state *st,
+                                     enum iio_backend_data_source type)
+{
+       int i, ret;
+
+       for (i = 0; i < st->model_data->num_hw_channels; ++i) {
+               ret = iio_backend_data_source_set(st->back, i, type);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 static int ad3552r_hs_update_reg_bits(struct ad3552r_hs_state *st, u32 reg,
                                      u32 mask, u32 val, size_t xfer_size)
 {
@@ -483,6 +510,103 @@ static int ad3552r_hs_reg_access(struct iio_dev *indio_dev, unsigned int reg,
        return st->data->bus_reg_write(st->back, reg, writeval, 1);
 }
 
+static ssize_t ad3552r_hs_show_data_source(struct file *f, char __user *userbuf,
+                                          size_t count, loff_t *ppos)
+{
+       struct ad3552r_hs_state *st = file_inode(f)->i_private;
+       enum iio_backend_data_source type;
+       int idx, ret;
+
+       guard(mutex)(&st->lock);
+
+       ret = iio_backend_data_source_get(st->back, 0, &type);
+       if (ret)
+               return ret;
+
+       switch (type) {
+       case IIO_BACKEND_INTERNAL_RAMP_16BIT:
+               idx = AD3552R_SRC_RAMP_16BIT;
+               break;
+       case IIO_BACKEND_EXTERNAL:
+               idx = AD3552R_SRC_NORMAL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return simple_read_from_buffer(userbuf, count, ppos,
+                                      dbgfs_attr_source[idx],
+                                      strlen(dbgfs_attr_source[idx]));
+}
+
+static ssize_t ad3552r_hs_write_data_source(struct file *f,
+                                           const char __user *userbuf,
+                                           size_t count, loff_t *ppos)
+{
+       struct ad3552r_hs_state *st = file_inode(f)->i_private;
+       char buf[64];
+       int ret, source;
+
+       guard(mutex)(&st->lock);
+
+       ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, userbuf,
+                                    count);
+       if (ret < 0)
+               return ret;
+
+       buf[count] = '\0';
+
+       ret = match_string(dbgfs_attr_source, ARRAY_SIZE(dbgfs_attr_source),
+                          buf);
+       if (ret < 0)
+               return ret;
+
+       switch (ret) {
+       case AD3552R_SRC_RAMP_16BIT:
+               source = IIO_BACKEND_INTERNAL_RAMP_16BIT;
+               break;
+       case AD3552R_SRC_NORMAL:
+               source = IIO_BACKEND_EXTERNAL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = ad3552r_hs_set_data_source(st, source);
+       if (ret)
+               return ret;
+
+       return count;
+}
+
+static ssize_t ad3552r_hs_show_data_source_avail(struct file *f,
+                                                char __user *userbuf,
+                                                size_t count, loff_t *ppos)
+{
+       ssize_t len = 0;
+       char buf[128];
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(dbgfs_attr_source); i++) {
+               len += scnprintf(buf + len, PAGE_SIZE - len, "%s ",
+                                dbgfs_attr_source[i]);
+       }
+       buf[len - 1] = '\n';
+
+       return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+}
+
+static const struct file_operations ad3552r_hs_data_source_fops = {
+       .owner = THIS_MODULE,
+       .write = ad3552r_hs_write_data_source,
+       .read = ad3552r_hs_show_data_source,
+};
+
+static const struct file_operations ad3552r_hs_data_source_avail_fops = {
+       .owner = THIS_MODULE,
+       .read = ad3552r_hs_show_data_source_avail,
+};
+
 static int ad3552r_hs_setup(struct ad3552r_hs_state *st)
 {
        u16 id;
@@ -550,11 +674,7 @@ static int ad3552r_hs_setup(struct ad3552r_hs_state *st)
        if (ret)
                return ret;
 
-       ret = iio_backend_data_source_set(st->back, 0, IIO_BACKEND_EXTERNAL);
-       if (ret)
-               return ret;
-
-       ret = iio_backend_data_source_set(st->back, 1, IIO_BACKEND_EXTERNAL);
+       ret = ad3552r_hs_set_data_source(st, IIO_BACKEND_EXTERNAL);
        if (ret)
                return ret;
 
@@ -661,6 +781,26 @@ static const struct iio_info ad3552r_hs_info = {
        .debugfs_reg_access = &ad3552r_hs_reg_access,
 };
 
+static void ad3552r_hs_debugfs_init(struct iio_dev *indio_dev)
+{
+       struct ad3552r_hs_state *st = iio_priv(indio_dev);
+       struct dentry *d = iio_get_debugfs_dentry(indio_dev);
+
+       if (!IS_ENABLED(CONFIG_DEBUG_FS))
+               return;
+
+       d = iio_get_debugfs_dentry(indio_dev);
+       if (!d) {
+               dev_warn(st->dev, "can't set debugfs in driver dir\n");
+               return;
+       }
+
+       debugfs_create_file("data_source", 0600, d, st,
+                           &ad3552r_hs_data_source_fops);
+       debugfs_create_file("data_source_available", 0600, d, st,
+                           &ad3552r_hs_data_source_avail_fops);
+}
+
 static int ad3552r_hs_probe(struct platform_device *pdev)
 {
        struct ad3552r_hs_state *st;
@@ -705,7 +845,17 @@ static int ad3552r_hs_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       return devm_iio_device_register(&pdev->dev, indio_dev);
+       ret = devm_iio_device_register(&pdev->dev, indio_dev);
+       if (ret)
+               return ret;
+
+       ret = devm_mutex_init(&pdev->dev, &st->lock);
+       if (ret)
+               return ret;
+
+       ad3552r_hs_debugfs_init(indio_dev);
+
+       return ret;
 }
 
 static const struct of_device_id ad3552r_hs_of_id[] = {