Message ID | 20240304-rk3588-saradc-v3-11-7424e2ed5d3b@theobroma-systems.com |
---|---|
State | Accepted |
Delegated to: | Kever Yang |
Headers | show |
Series | rockchip: add support for SARADCv2 and RK806 PMIC and regulators | expand |
On 2024/3/4 19:30, Quentin Schulz wrote: > From: Quentin Schulz <quentin.schulz@theobroma-systems.com> > > This adds support for the SARADCv2 found on RK3588. > > There is no stop callback as it is currently configured in single > conversion mode, where the ADC is powered down after a single conversion > has been made. > > Due to what seems to be a silicon bug, a controller reset needs to be > issued before starting a channel conversion otherwise Rockchip says that > channel 1 will error whatever that means. This is aligned with upstream > and downstream Linux kernel as well as downstream U-Boot. > > Cc: Quentin Schulz <foss+uboot@0leil.net> > Signed-off-by: Quentin Schulz <quentin.schulz@theobroma-systems.com> Reviewed-by: Kever Yang <kever.yang@rock-chips.com> Thanks, - Kever > --- > drivers/adc/rockchip-saradc.c | 102 +++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 101 insertions(+), 1 deletion(-) > > diff --git a/drivers/adc/rockchip-saradc.c b/drivers/adc/rockchip-saradc.c > index b5df58fe3eb..10ded1b088f 100644 > --- a/drivers/adc/rockchip-saradc.c > +++ b/drivers/adc/rockchip-saradc.c > @@ -10,12 +10,17 @@ > #include <clk.h> > #include <dm.h> > #include <errno.h> > -#include <asm/io.h> > +#include <reset.h> > +#include <asm/arch-rockchip/hardware.h> > +#include <linux/bitfield.h> > #include <linux/bitops.h> > +#include <linux/delay.h> > #include <linux/err.h> > #include <linux/printk.h> > #include <power/regulator.h> > > +#define usleep_range(a, b) udelay((b)) > + > #define SARADC_CTRL_CHN_MASK GENMASK(2, 0) > #define SARADC_CTRL_POWER_CTRL BIT(3) > #define SARADC_CTRL_IRQ_ENABLE BIT(5) > @@ -30,8 +35,37 @@ struct rockchip_saradc_regs_v1 { > unsigned int dly_pu_soc; > }; > > +struct rockchip_saradc_regs_v2 { > + unsigned int conv_con; > +#define SARADC2_SINGLE_MODE BIT(5) > +#define SARADC2_START BIT(4) > +#define SARADC2_CONV_CHANNELS GENMASK(3, 0) > + unsigned int t_pd_soc; > + unsigned int t_as_soc; > + unsigned int t_das_soc; > + unsigned int t_sel_soc; > + unsigned int high_comp[16]; > + unsigned int low_comp[16]; > + unsigned int debounce; > + unsigned int ht_int_en; > + unsigned int lt_int_en; > + unsigned int reserved[24]; > + unsigned int mt_int_en; > + unsigned int end_int_en; > +#define SARADC2_EN_END_INT BIT(0) > + unsigned int st_con; > + unsigned int status; > + unsigned int end_int_st; > + unsigned int ht_int_st; > + unsigned int lt_int_st; > + unsigned int mt_int_st; > + unsigned int data[16]; > + unsigned int auto_ch_en; > +}; > + > union rockchip_saradc_regs { > struct rockchip_saradc_regs_v1 *v1; > + struct rockchip_saradc_regs_v2 *v2; > }; > struct rockchip_saradc_data { > int num_bits; > @@ -46,6 +80,7 @@ struct rockchip_saradc_priv { > union rockchip_saradc_regs regs; > int active_channel; > const struct rockchip_saradc_data *data; > + struct reset_ctl *reset; > }; > > int rockchip_saradc_channel_data_v1(struct udevice *dev, int channel, > @@ -66,6 +101,22 @@ int rockchip_saradc_channel_data_v1(struct udevice *dev, int channel, > return 0; > } > > +int rockchip_saradc_channel_data_v2(struct udevice *dev, int channel, > + unsigned int *data) > +{ > + struct rockchip_saradc_priv *priv = dev_get_priv(dev); > + > + if (!(readl(&priv->regs.v2->end_int_st) & SARADC2_EN_END_INT)) > + return -EBUSY; > + > + /* Read value */ > + *data = readl(&priv->regs.v2->data[channel]); > + > + /* Acknowledge the interrupt */ > + writel(SARADC2_EN_END_INT, &priv->regs.v2->end_int_st); > + > + return 0; > +} > int rockchip_saradc_channel_data(struct udevice *dev, int channel, > unsigned int *data) > { > @@ -104,6 +155,40 @@ int rockchip_saradc_start_channel_v1(struct udevice *dev, int channel) > return 0; > } > > +static void rockchip_saradc_reset_controller(struct reset_ctl *reset) > +{ > + reset_assert(reset); > + usleep_range(10, 20); > + reset_deassert(reset); > +} > + > +int rockchip_saradc_start_channel_v2(struct udevice *dev, int channel) > +{ > + struct rockchip_saradc_priv *priv = dev_get_priv(dev); > + > + /* > + * Downstream says > + * """If read other chn at anytime, then chn1 will error, assert > + * controller as a workaround.""" > + */ > + if (priv->reset) > + rockchip_saradc_reset_controller(priv->reset); > + > + writel(0xc, &priv->regs.v2->t_das_soc); > + writel(0x20, &priv->regs.v2->t_pd_soc); > + > + /* Acknowledge any previous interrupt */ > + writel(SARADC2_EN_END_INT, &priv->regs.v2->end_int_st); > + > + rk_clrsetreg(&priv->regs.v2->conv_con, > + SARADC2_CONV_CHANNELS | SARADC2_START | SARADC2_SINGLE_MODE, > + FIELD_PREP(SARADC2_CONV_CHANNELS, channel) | > + FIELD_PREP(SARADC2_START, 1) | > + FIELD_PREP(SARADC2_SINGLE_MODE, 1)); > + > + return 0; > +} > + > int rockchip_saradc_start_channel(struct udevice *dev, int channel) > { > struct rockchip_saradc_priv *priv = dev_get_priv(dev); > @@ -162,6 +247,8 @@ int rockchip_saradc_probe(struct udevice *dev) > int vref_uv; > int ret; > > + priv->reset = devm_reset_control_get_optional(dev, "saradc-apb"); > + > ret = clk_get_by_index(dev, 0, &clk); > if (ret) > return ret; > @@ -178,6 +265,9 @@ int rockchip_saradc_probe(struct udevice *dev) > return ret; > } > > + if (priv->reset) > + rockchip_saradc_reset_controller(priv->reset); > + > vref_uv = regulator_get_value(vref); > if (vref_uv < 0) { > printf("can't get vref-supply value: %d\n", vref_uv); > @@ -247,6 +337,14 @@ static const struct rockchip_saradc_data rk3399_saradc_data = { > .stop = rockchip_saradc_stop_v1, > }; > > +static const struct rockchip_saradc_data rk3588_saradc_data = { > + .num_bits = 12, > + .num_channels = 8, > + .clk_rate = 1000000, > + .channel_data = rockchip_saradc_channel_data_v2, > + .start_channel = rockchip_saradc_start_channel_v2, > +}; > + > static const struct udevice_id rockchip_saradc_ids[] = { > { .compatible = "rockchip,saradc", > .data = (ulong)&saradc_data }, > @@ -254,6 +352,8 @@ static const struct udevice_id rockchip_saradc_ids[] = { > .data = (ulong)&rk3066_tsadc_data }, > { .compatible = "rockchip,rk3399-saradc", > .data = (ulong)&rk3399_saradc_data }, > + { .compatible = "rockchip,rk3588-saradc", > + .data = (ulong)&rk3588_saradc_data }, > { } > }; > >
diff --git a/drivers/adc/rockchip-saradc.c b/drivers/adc/rockchip-saradc.c index b5df58fe3eb..10ded1b088f 100644 --- a/drivers/adc/rockchip-saradc.c +++ b/drivers/adc/rockchip-saradc.c @@ -10,12 +10,17 @@ #include <clk.h> #include <dm.h> #include <errno.h> -#include <asm/io.h> +#include <reset.h> +#include <asm/arch-rockchip/hardware.h> +#include <linux/bitfield.h> #include <linux/bitops.h> +#include <linux/delay.h> #include <linux/err.h> #include <linux/printk.h> #include <power/regulator.h> +#define usleep_range(a, b) udelay((b)) + #define SARADC_CTRL_CHN_MASK GENMASK(2, 0) #define SARADC_CTRL_POWER_CTRL BIT(3) #define SARADC_CTRL_IRQ_ENABLE BIT(5) @@ -30,8 +35,37 @@ struct rockchip_saradc_regs_v1 { unsigned int dly_pu_soc; }; +struct rockchip_saradc_regs_v2 { + unsigned int conv_con; +#define SARADC2_SINGLE_MODE BIT(5) +#define SARADC2_START BIT(4) +#define SARADC2_CONV_CHANNELS GENMASK(3, 0) + unsigned int t_pd_soc; + unsigned int t_as_soc; + unsigned int t_das_soc; + unsigned int t_sel_soc; + unsigned int high_comp[16]; + unsigned int low_comp[16]; + unsigned int debounce; + unsigned int ht_int_en; + unsigned int lt_int_en; + unsigned int reserved[24]; + unsigned int mt_int_en; + unsigned int end_int_en; +#define SARADC2_EN_END_INT BIT(0) + unsigned int st_con; + unsigned int status; + unsigned int end_int_st; + unsigned int ht_int_st; + unsigned int lt_int_st; + unsigned int mt_int_st; + unsigned int data[16]; + unsigned int auto_ch_en; +}; + union rockchip_saradc_regs { struct rockchip_saradc_regs_v1 *v1; + struct rockchip_saradc_regs_v2 *v2; }; struct rockchip_saradc_data { int num_bits; @@ -46,6 +80,7 @@ struct rockchip_saradc_priv { union rockchip_saradc_regs regs; int active_channel; const struct rockchip_saradc_data *data; + struct reset_ctl *reset; }; int rockchip_saradc_channel_data_v1(struct udevice *dev, int channel, @@ -66,6 +101,22 @@ int rockchip_saradc_channel_data_v1(struct udevice *dev, int channel, return 0; } +int rockchip_saradc_channel_data_v2(struct udevice *dev, int channel, + unsigned int *data) +{ + struct rockchip_saradc_priv *priv = dev_get_priv(dev); + + if (!(readl(&priv->regs.v2->end_int_st) & SARADC2_EN_END_INT)) + return -EBUSY; + + /* Read value */ + *data = readl(&priv->regs.v2->data[channel]); + + /* Acknowledge the interrupt */ + writel(SARADC2_EN_END_INT, &priv->regs.v2->end_int_st); + + return 0; +} int rockchip_saradc_channel_data(struct udevice *dev, int channel, unsigned int *data) { @@ -104,6 +155,40 @@ int rockchip_saradc_start_channel_v1(struct udevice *dev, int channel) return 0; } +static void rockchip_saradc_reset_controller(struct reset_ctl *reset) +{ + reset_assert(reset); + usleep_range(10, 20); + reset_deassert(reset); +} + +int rockchip_saradc_start_channel_v2(struct udevice *dev, int channel) +{ + struct rockchip_saradc_priv *priv = dev_get_priv(dev); + + /* + * Downstream says + * """If read other chn at anytime, then chn1 will error, assert + * controller as a workaround.""" + */ + if (priv->reset) + rockchip_saradc_reset_controller(priv->reset); + + writel(0xc, &priv->regs.v2->t_das_soc); + writel(0x20, &priv->regs.v2->t_pd_soc); + + /* Acknowledge any previous interrupt */ + writel(SARADC2_EN_END_INT, &priv->regs.v2->end_int_st); + + rk_clrsetreg(&priv->regs.v2->conv_con, + SARADC2_CONV_CHANNELS | SARADC2_START | SARADC2_SINGLE_MODE, + FIELD_PREP(SARADC2_CONV_CHANNELS, channel) | + FIELD_PREP(SARADC2_START, 1) | + FIELD_PREP(SARADC2_SINGLE_MODE, 1)); + + return 0; +} + int rockchip_saradc_start_channel(struct udevice *dev, int channel) { struct rockchip_saradc_priv *priv = dev_get_priv(dev); @@ -162,6 +247,8 @@ int rockchip_saradc_probe(struct udevice *dev) int vref_uv; int ret; + priv->reset = devm_reset_control_get_optional(dev, "saradc-apb"); + ret = clk_get_by_index(dev, 0, &clk); if (ret) return ret; @@ -178,6 +265,9 @@ int rockchip_saradc_probe(struct udevice *dev) return ret; } + if (priv->reset) + rockchip_saradc_reset_controller(priv->reset); + vref_uv = regulator_get_value(vref); if (vref_uv < 0) { printf("can't get vref-supply value: %d\n", vref_uv); @@ -247,6 +337,14 @@ static const struct rockchip_saradc_data rk3399_saradc_data = { .stop = rockchip_saradc_stop_v1, }; +static const struct rockchip_saradc_data rk3588_saradc_data = { + .num_bits = 12, + .num_channels = 8, + .clk_rate = 1000000, + .channel_data = rockchip_saradc_channel_data_v2, + .start_channel = rockchip_saradc_start_channel_v2, +}; + static const struct udevice_id rockchip_saradc_ids[] = { { .compatible = "rockchip,saradc", .data = (ulong)&saradc_data }, @@ -254,6 +352,8 @@ static const struct udevice_id rockchip_saradc_ids[] = { .data = (ulong)&rk3066_tsadc_data }, { .compatible = "rockchip,rk3399-saradc", .data = (ulong)&rk3399_saradc_data }, + { .compatible = "rockchip,rk3588-saradc", + .data = (ulong)&rk3588_saradc_data }, { } };