[U-Boot,1/8] adc: Add driver for Rockchip Saradc
Philipp Tomsich
philipp.tomsich at theobroma-systems.com
Wed Sep 13 13:40:27 PDT 2017
On Wed, 13 Sep 2017, David Wu wrote:
> The ADC can support some channels signal-ended some bits Successive Approximation
> Register (SAR) A/D Converter, like 6-channel and 10-bit. It converts the analog
> input signal into some bits binary digital codes.
>
> Signed-off-by: David Wu <david.wu at rock-chips.com>
Reviewed-by: Philipp Tomsich <philipp.tomsich at theobroma-systems.com>
Please see below for requested changes.
> ---
> drivers/adc/Kconfig | 9 ++
> drivers/adc/Makefile | 1 +
> drivers/adc/rockchip-saradc.c | 188 ++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 198 insertions(+)
> create mode 100644 drivers/adc/rockchip-saradc.c
>
> diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig
> index e5335f7..830fe0f 100644
> --- a/drivers/adc/Kconfig
> +++ b/drivers/adc/Kconfig
> @@ -20,6 +20,15 @@ config ADC_EXYNOS
> - 12-bit resolution
> - 600 KSPS of sample rate
>
> +config SARADC_ROCKCHIP
> + bool "Enable Rockchip SARADC driver"
> + help
> + This enables driver for Rockchip SARADC.
> + It provides:
> + - 2~6 analog input channels
> + - 1O-bit resolution
> + - 1MSPS of sample rate
> +
> config ADC_SANDBOX
> bool "Enable Sandbox ADC test driver"
> help
> diff --git a/drivers/adc/Makefile b/drivers/adc/Makefile
> index cebf26d..4b5aa69 100644
> --- a/drivers/adc/Makefile
> +++ b/drivers/adc/Makefile
> @@ -8,3 +8,4 @@
> obj-$(CONFIG_ADC) += adc-uclass.o
> obj-$(CONFIG_ADC_EXYNOS) += exynos-adc.o
> obj-$(CONFIG_ADC_SANDBOX) += sandbox.o
> +obj-$(CONFIG_SARADC_ROCKCHIP) += rockchip-saradc.o
Do you feel strongly about the "SARADC_ROCKCHIP" or would "ADC_ROCKCHIP"
be correct as well? I don't care either way, but this is the first entry
here that does not start with CONFIG_ADC_, so I am wondering...
> diff --git a/drivers/adc/rockchip-saradc.c b/drivers/adc/rockchip-saradc.c
> new file mode 100644
> index 0000000..5c7c3d9
> --- /dev/null
> +++ b/drivers/adc/rockchip-saradc.c
> @@ -0,0 +1,188 @@
> +/*
> + * (C) Copyright 2017, Fuzhou Rockchip Electronics Co., Ltd
> + *
> + * SPDX-License-Identifier: GPL-2.0+
> + *
> + * Rockchip Saradc driver for U-Boot
Should this be SARADC (all uppercase)?
> + */
> +
> +#include <asm/io.h>
> +#include <clk.h>
> +#include <common.h>
> +#include <dm.h>
> +#include <errno.h>
> +#include <adc.h>
Please see https://www.denx.de/wiki/U-Boot/CodingStyle for the include
order. Please revise.
@Simon: yes, I am quick study ;-)
> +
> +#define SARADC_DATA 0x00
> +
> +#define SARADC_STAS 0x04
Please see https://www.denx.de/wiki/U-Boot/CodingStyle for the guidelines
on using structures for I/O accesses. Please revise.
> +#define SARADC_STAS_BUSY BIT(0)
> +
> +#define SARADC_CTRL 0x08
> +#define SARADC_CTRL_POWER_CTRL BIT(3)
> +#define SARADC_CTRL_CHN_MASK 0x7
> +#define SARADC_CTRL_IRQ_STATUS BIT(6)
> +#define SARADC_CTRL_IRQ_ENABLE BIT(5)
> +
> +#define SARADC_DLY_PU_SOC 0x0c
> +
> +#define SARADC_TIMEOUT (100 * 1000)
> +
> +struct rockchip_saradc_data {
> + int num_bits;
> + int num_channels;
> + unsigned long clk_rate;
> +};
> +
> +struct rockchip_saradc_priv {
> + fdt_addr_t regs;
> + int active_channel;
> + const struct rockchip_saradc_data *data;
> +};
> +
> +int rockchip_saradc_channel_data(struct udevice *dev, int channel,
> + unsigned int *data)
> +{
> + struct rockchip_saradc_priv *priv = dev_get_priv(dev);
> +
> + if (channel != priv->active_channel) {
> + error("Requested channel is not active!");
> + return -EINVAL;
> + }
> +
> + if ((readl(priv->regs + SARADC_CTRL) & SARADC_CTRL_IRQ_STATUS) != SARADC_CTRL_IRQ_STATUS)
> + return -EBUSY;
> +
> + /* Read value */
> + *data = readl(priv->regs + SARADC_DATA);
> + *data &= (1 << priv->data->num_bits) - 1;
This recomputes the data_mask (from below).
Can we just use the data_mask again?
> +
> + /* Power down adc */
> + writel(0, priv->regs + SARADC_CTRL);
> +
> + return 0;
> +}
> +
> +int rockchip_saradc_start_channel(struct udevice *dev, int channel)
> +{
> + struct rockchip_saradc_priv *priv = dev_get_priv(dev);
> +
> + if (channel < 0 || channel >= priv->data->num_channels) {
> + error("Requested channel is invalid!");
> + return -EINVAL;
> + }
> +
> + /* 8 clock periods as delay between power up and start cmd */
> + writel(8, priv->regs + SARADC_DLY_PU_SOC);
> +
> + /* Select the channel to be used and trigger conversion */
> + writel(SARADC_CTRL_POWER_CTRL
> + | (channel & SARADC_CTRL_CHN_MASK) | SARADC_CTRL_IRQ_ENABLE,
This line does not match the style guideline: it is too wide and the
operator should be before the line-break.
Did you run checkpatch or use patman?
> + priv->regs + SARADC_CTRL);
> +
> + priv->active_channel = channel;
> +
> + return 0;
> +}
> +
> +int rockchip_saradc_stop(struct udevice *dev)
> +{
> + struct rockchip_saradc_priv *priv = dev_get_priv(dev);
> +
> + /* Power down adc */
> + writel(0, priv->regs + SARADC_CTRL);
> +
> + priv->active_channel = -1;
> +
> + return 0;
> +}
> +
> +int rockchip_saradc_probe(struct udevice *dev)
> +{
> + struct rockchip_saradc_priv *priv = dev_get_priv(dev);
> + struct clk clk;
> + int ret;
> +
> + ret = clk_get_by_index(dev, 0, &clk);
> + if (ret)
> + return ret;
> +
> + ret = clk_set_rate(&clk, priv->data->clk_rate);
> + if (IS_ERR_VALUE(ret))
> + return ret;
> +
> + priv->active_channel = -1;
> +
> + return 0;
> +}
> +
> +int rockchip_saradc_ofdata_to_platdata(struct udevice *dev)
> +{
> + struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
> + struct rockchip_saradc_priv *priv = dev_get_priv(dev);
> + struct rockchip_saradc_data *data =
> + (struct rockchip_saradc_data *)dev_get_driver_data(dev);
> +
> + priv->regs = devfdt_get_addr(dev);
Shouldn't this be dev_read_addr?
> + if (priv->regs == FDT_ADDR_T_NONE) {
> + error("Dev: %s - can't get address!", dev->name);
> + return -ENODATA;
> + }
> +
> + priv->data = data;
> + uc_pdata->data_mask = (1 << priv->data->num_bits) - 1;;
> + uc_pdata->data_format = ADC_DATA_FORMAT_BIN;
> + uc_pdata->data_timeout_us = SARADC_TIMEOUT / 5;
> + uc_pdata->channel_mask = (1 << priv->data->num_channels) - 1;
> +
> + return 0;
> +}
> +
> +static const struct adc_ops rockchip_saradc_ops = {
> + .start_channel = rockchip_saradc_start_channel,
> + .channel_data = rockchip_saradc_channel_data,
> + .stop = rockchip_saradc_stop,
> +};
> +
> +static const struct rockchip_saradc_data saradc_data = {
> + .num_bits = 10,
> + .num_channels = 3,
> + .clk_rate = 1000000,
> +};
> +
> +static const struct rockchip_saradc_data rk3066_tsadc_data = {
> + .num_bits = 12,
> + .num_channels = 2,
> + .clk_rate = 50000,
> +};
> +
> +static const struct rockchip_saradc_data rk3399_saradc_data = {
> + .num_bits = 10,
> + .num_channels = 6,
> + .clk_rate = 1000000,
> +};
> +
> +static const struct udevice_id rockchip_saradc_ids[] = {
> + {
> + .compatible = "rockchip,saradc",
> + .data = (ulong)&saradc_data,
> + },
> + {
> + .compatible = "rockchip,rk3066-tsadc",
> + .data = (ulong)&rk3066_tsadc_data,
> + }, {
> + .compatible = "rockchip,rk3399-saradc",
> + .data = (ulong)&rk3399_saradc_data,
> + },
> + { }
> +};
> +
> +U_BOOT_DRIVER(rockchip_saradc) = {
> + .name = "rockchip_saradc",
> + .id = UCLASS_ADC,
> + .of_match = rockchip_saradc_ids,
> + .ops = &rockchip_saradc_ops,
> + .probe = rockchip_saradc_probe,
> + .ofdata_to_platdata = rockchip_saradc_ofdata_to_platdata,
> + .priv_auto_alloc_size = sizeof(struct rockchip_saradc_priv),
> +};
>
More information about the Linux-rockchip
mailing list