mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH] aiodev: add driver for Rockchip SARADC
@ 2021-06-17 14:36 Michael Riesch
  2021-06-21  4:30 ` Sascha Hauer
  0 siblings, 1 reply; 3+ messages in thread
From: Michael Riesch @ 2021-06-17 14:36 UTC (permalink / raw)
  To: barebox; +Cc: Michael Riesch

This commit adds support for the Successive Approximation Register (SAR)
ADCs that can be found in Rockchip SoCs, such as the RK3568.

Signed-off-by: Michael Riesch <michael.riesch@wolfvision.net>
---
 drivers/aiodev/Kconfig           |   7 ++
 drivers/aiodev/Makefile          |   1 +
 drivers/aiodev/rockchip_saradc.c | 153 +++++++++++++++++++++++++++++++
 3 files changed, 161 insertions(+)
 create mode 100644 drivers/aiodev/rockchip_saradc.c

diff --git a/drivers/aiodev/Kconfig b/drivers/aiodev/Kconfig
index 88d013aad..98223a8f9 100644
--- a/drivers/aiodev/Kconfig
+++ b/drivers/aiodev/Kconfig
@@ -50,4 +50,11 @@ config STM32_ADC
 	  Support for ADC on STM32.  Supports simple one-shot readings
 	  rather than continuous sampling with DMA, etc.  ADC channels should be
 	  configured via device tree, using the kernel bindings.
+
+config ROCKCHIP_SARADC
+	tristate "Rockchip SARADC driver"
+	depends on ARCH_RK3568
+	help
+	  Support for Successive Approximation Register (SAR) ADC in Rockchip
+	  SoCs.
 endif
diff --git a/drivers/aiodev/Makefile b/drivers/aiodev/Makefile
index 52652f67b..1b480f6fa 100644
--- a/drivers/aiodev/Makefile
+++ b/drivers/aiodev/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_MC13XXX_ADC) += mc13xxx_adc.o
 obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o
 obj-$(CONFIG_AM335X_ADC) += am335x_adc.o
 obj-$(CONFIG_STM32_ADC) += stm32-adc.o stm32-adc-core.o
+obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
diff --git a/drivers/aiodev/rockchip_saradc.c b/drivers/aiodev/rockchip_saradc.c
new file mode 100644
index 000000000..abd7ccdd8
--- /dev/null
+++ b/drivers/aiodev/rockchip_saradc.c
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021, WolfVision GmbH
+ * Author: Michael Riesch <michael.riesch@wolfvision.net>
+ *
+ * Originally based on the Linux kernel v5.12 drivers/iio/adc/rockchip-saradc.c.
+ */
+
+#include <common.h>
+#include <aiodev.h>
+
+#define SARADC_DATA	       0x00
+
+#define SARADC_CTRL	       0x08
+#define SARADC_CTRL_IRQ_STATUS (1 << 6)
+#define SARADC_CTRL_IRQ_ENABLE (1 << 5)
+#define SARADC_CTRL_POWER_CTRL (1 << 3)
+#define SARADC_CTRL_CHN_MASK   0x07
+
+#define SARADC_DLY_PU_SOC      0x0c
+
+#define SARADC_TIMEOUT	       100
+
+struct rockchip_saradc_cfg {
+	unsigned int ref_voltage_mv;
+	unsigned int num_bits;
+	unsigned int num_channels;
+};
+
+struct rockchip_saradc_data {
+	const struct rockchip_saradc_cfg *config;
+	struct aiodevice aiodev;
+	void __iomem *base;
+	struct aiochannel *channels;
+};
+
+static inline void rockchip_saradc_reg_wr(struct rockchip_saradc_data *data,
+					  u32 value, u32 reg)
+{
+	writel(value, data->base + reg);
+}
+
+static inline u32 rockchip_saradc_reg_rd(struct rockchip_saradc_data *data,
+					 u32 reg)
+{
+	return readl(data->base + reg);
+}
+
+static int rockchip_saradc_read(struct aiochannel *chan, int *val)
+{
+	struct rockchip_saradc_data *data;
+	int timeout = SARADC_TIMEOUT;
+	u32 value = 0;
+	u32 control = 0;
+	u32 mask;
+
+	if (!chan || !val)
+		return -EINVAL;
+
+	data = container_of(chan->aiodev, struct rockchip_saradc_data, aiodev);
+	if (!data)
+		return -EINVAL;
+
+	rockchip_saradc_reg_wr(data, 8, SARADC_DLY_PU_SOC);
+	rockchip_saradc_reg_wr(data,
+			       (chan->index & SARADC_CTRL_CHN_MASK) |
+				       SARADC_CTRL_IRQ_ENABLE |
+				       SARADC_CTRL_POWER_CTRL,
+			       SARADC_CTRL);
+
+	do {
+		control = rockchip_saradc_reg_rd(data, SARADC_CTRL);
+
+		if (--timeout == 0)
+			return -ETIMEDOUT;
+		mdelay(1);
+	} while (!(control & SARADC_CTRL_IRQ_STATUS));
+
+	mask = (1 << data->config->num_bits) - 1;
+	value = rockchip_saradc_reg_rd(data, SARADC_DATA) & mask;
+	rockchip_saradc_reg_wr(data, 0, SARADC_CTRL);
+
+	printf("Raw value: %d\n", value);
+
+	*val = (value * data->config->ref_voltage_mv) / mask;
+
+	return 0;
+}
+
+static int rockchip_saradc_probe(struct device_d *dev)
+{
+	struct rockchip_saradc_data *data;
+	int i, ret;
+
+	data = xzalloc(sizeof(struct rockchip_saradc_data));
+	data->config = device_get_match_data(dev);
+	if (!data->config) {
+		ret = -EINVAL;
+		goto fail_data;
+	}
+	data->aiodev.hwdev = dev;
+	data->aiodev.read = rockchip_saradc_read;
+	data->base = dev_request_mem_region(dev, 0);
+	if (IS_ERR(data->base)) {
+		ret = PTR_ERR(data->base);
+		goto fail_data;
+	}
+
+	data->aiodev.num_channels = data->config->num_channels;
+	data->channels =
+		xzalloc(sizeof(*data->channels) * data->aiodev.num_channels);
+	data->aiodev.channels = xmalloc(sizeof(*data->aiodev.channels) *
+					data->aiodev.num_channels);
+	for (i = 0; i < data->aiodev.num_channels; i++) {
+		data->aiodev.channels[i] = &data->channels[i];
+		data->channels[i].unit = "mV";
+	}
+
+	rockchip_saradc_reg_wr(data, 0, SARADC_CTRL);
+
+	ret = aiodevice_register(&data->aiodev);
+	if (ret)
+		goto fail_channels;
+
+	dev_info(dev, "registered as %s\n", dev_name(&data->aiodev.dev));
+	return 0;
+
+fail_channels:
+	kfree(data->channels);
+	kfree(data->aiodev.channels);
+
+fail_data:
+	kfree(data);
+	return ret;
+}
+
+static const struct rockchip_saradc_cfg rk3568_saradc_cfg = {
+	.ref_voltage_mv = 1800,
+	.num_bits = 10,
+	.num_channels = 8,
+};
+
+static const struct of_device_id of_rockchip_saradc_match[] = {
+	{ .compatible = "rockchip,rk3568-saradc", .data = &rk3568_saradc_cfg },
+	{ /* end */ }
+};
+
+static struct driver_d rockchip_saradc_driver = {
+	.name = "rockchip_saradc",
+	.probe = rockchip_saradc_probe,
+	.of_compatible = DRV_OF_COMPAT(of_rockchip_saradc_match),
+};
+device_platform_driver(rockchip_saradc_driver);
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] aiodev: add driver for Rockchip SARADC
  2021-06-17 14:36 [PATCH] aiodev: add driver for Rockchip SARADC Michael Riesch
@ 2021-06-21  4:30 ` Sascha Hauer
  2021-06-21 11:27   ` Michael Riesch
  0 siblings, 1 reply; 3+ messages in thread
From: Sascha Hauer @ 2021-06-21  4:30 UTC (permalink / raw)
  To: Michael Riesch; +Cc: barebox

Hi Michael,

On Thu, Jun 17, 2021 at 04:36:54PM +0200, Michael Riesch wrote:
> +static int rockchip_saradc_read(struct aiochannel *chan, int *val)
> +{
> +	struct rockchip_saradc_data *data;
> +	int timeout = SARADC_TIMEOUT;
> +	u32 value = 0;
> +	u32 control = 0;
> +	u32 mask;
> +
> +	if (!chan || !val)
> +		return -EINVAL;
> +
> +	data = container_of(chan->aiodev, struct rockchip_saradc_data, aiodev);
> +	if (!data)
> +		return -EINVAL;
> +
> +	rockchip_saradc_reg_wr(data, 8, SARADC_DLY_PU_SOC);
> +	rockchip_saradc_reg_wr(data,
> +			       (chan->index & SARADC_CTRL_CHN_MASK) |
> +				       SARADC_CTRL_IRQ_ENABLE |
> +				       SARADC_CTRL_POWER_CTRL,
> +			       SARADC_CTRL);
> +
> +	do {
> +		control = rockchip_saradc_reg_rd(data, SARADC_CTRL);
> +
> +		if (--timeout == 0)
> +			return -ETIMEDOUT;
> +		mdelay(1);
> +	} while (!(control & SARADC_CTRL_IRQ_STATUS));

You should do a timeout loop with

	u64 start = get_time_ns();

	do {
		if (is_timeout(start, 100 * MSECOND)
			return -ETIMEDOUT;
	} while(bar);

We don't have any way nor need to put the CPU into idle, so we can poll
as fast as we can.

> +
> +	mask = (1 << data->config->num_bits) - 1;
> +	value = rockchip_saradc_reg_rd(data, SARADC_DATA) & mask;
> +	rockchip_saradc_reg_wr(data, 0, SARADC_CTRL);
> +
> +	printf("Raw value: %d\n", value);

Debugging leftover.

> +fail_channels:
> +	kfree(data->channels);
> +	kfree(data->aiodev.channels);
> +
> +fail_data:
> +	kfree(data);
> +	return ret;
> +}
> +
> +static const struct rockchip_saradc_cfg rk3568_saradc_cfg = {
> +	.ref_voltage_mv = 1800,

>From looking at the downstream dts files this doesn't seem to be SoC
specific:

	&saradc {
        	status = "okay";
		vref-supply = <&vcca_1v8>;
	};

I suggest doing the same here.

> +	.num_bits = 10,
> +	.num_channels = 8,
> +};
> +
> +static const struct of_device_id of_rockchip_saradc_match[] = {
> +	{ .compatible = "rockchip,rk3568-saradc", .data = &rk3568_saradc_cfg },

The device nodes in the downstream Kernel also contain some clocks.
These should be handled in the driver.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] aiodev: add driver for Rockchip SARADC
  2021-06-21  4:30 ` Sascha Hauer
@ 2021-06-21 11:27   ` Michael Riesch
  0 siblings, 0 replies; 3+ messages in thread
From: Michael Riesch @ 2021-06-21 11:27 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox

Hello Sascha,

thanks for the review, I'll prepare a v2.

On 6/21/21 6:30 AM, Sascha Hauer wrote:
> Hi Michael,
> 
> On Thu, Jun 17, 2021 at 04:36:54PM +0200, Michael Riesch wrote:
>> +static int rockchip_saradc_read(struct aiochannel *chan, int *val)
>> +{
>> +	struct rockchip_saradc_data *data;
>> +	int timeout = SARADC_TIMEOUT;
>> +	u32 value = 0;
>> +	u32 control = 0;
>> +	u32 mask;
>> +
>> +	if (!chan || !val)
>> +		return -EINVAL;
>> +
>> +	data = container_of(chan->aiodev, struct rockchip_saradc_data, aiodev);
>> +	if (!data)
>> +		return -EINVAL;
>> +
>> +	rockchip_saradc_reg_wr(data, 8, SARADC_DLY_PU_SOC);
>> +	rockchip_saradc_reg_wr(data,
>> +			       (chan->index & SARADC_CTRL_CHN_MASK) |
>> +				       SARADC_CTRL_IRQ_ENABLE |
>> +				       SARADC_CTRL_POWER_CTRL,
>> +			       SARADC_CTRL);
>> +
>> +	do {
>> +		control = rockchip_saradc_reg_rd(data, SARADC_CTRL);
>> +
>> +		if (--timeout == 0)
>> +			return -ETIMEDOUT;
>> +		mdelay(1);
>> +	} while (!(control & SARADC_CTRL_IRQ_STATUS));
> 
> You should do a timeout loop with
> 
> 	u64 start = get_time_ns();
> 
> 	do {
> 		if (is_timeout(start, 100 * MSECOND)
> 			return -ETIMEDOUT;
> 	} while(bar);
> 
> We don't have any way nor need to put the CPU into idle, so we can poll
> as fast as we can.

OK, will replace that.

>> +
>> +	mask = (1 << data->config->num_bits) - 1;
>> +	value = rockchip_saradc_reg_rd(data, SARADC_DATA) & mask;
>> +	rockchip_saradc_reg_wr(data, 0, SARADC_CTRL);
>> +
>> +	printf("Raw value: %d\n", value);
> 
> Debugging leftover.

D'oh!

>> +fail_channels:
>> +	kfree(data->channels);
>> +	kfree(data->aiodev.channels);
>> +
>> +fail_data:
>> +	kfree(data);
>> +	return ret;
>> +}
>> +
>> +static const struct rockchip_saradc_cfg rk3568_saradc_cfg = {
>> +	.ref_voltage_mv = 1800,
> 
> From looking at the downstream dts files this doesn't seem to be SoC
> specific:
> 
> 	&saradc {
>         	status = "okay";
> 		vref-supply = <&vcca_1v8>;
> 	};
> 
> I suggest doing the same here.
> 
>> +	.num_bits = 10,
>> +	.num_channels = 8,
>> +};
>> +
>> +static const struct of_device_id of_rockchip_saradc_match[] = {
>> +	{ .compatible = "rockchip,rk3568-saradc", .data = &rk3568_saradc_cfg },
> 
> The device nodes in the downstream Kernel also contain some clocks.
> These should be handled in the driver.

I'll see what I can do :-)

Just had a look over the mainstream Kernel device tree. Resets,
interrupts and number of io-channels are also provided there. Now I
think that the interrupts are quite irrelevant for barebox, but should
the resets be addressed as well?

As to the number of iochannels, I think the maximum number should be
provided in the SoC specific struct. Not sure what the value of
specifying the actual number of channels in the device tree is, though.

Regards, Michael

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2021-06-21 11:29 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-17 14:36 [PATCH] aiodev: add driver for Rockchip SARADC Michael Riesch
2021-06-21  4:30 ` Sascha Hauer
2021-06-21 11:27   ` Michael Riesch

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox