Commit b1c5d68e authored by Angelo Dureghello's avatar Angelo Dureghello Committed by Jonathan Cameron
Browse files

iio: dac: ad3552r-hs: add support for internal ramp



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: default avatarAngelo Dureghello <adureghello@baylibre.com>
Link: https://patch.msgid.link/20250409-wip-bl-ad3552r-fixes-v5-5-fb429c3a6515@baylibre.com


Signed-off-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
parent ca74d0eb
Loading
Loading
Loading
Loading
+156 −6
Original line number Diff line number Diff line
@@ -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[] = {