Re: [PATCH v1] meson saradc: fix clock divider mask length

From: George Stark
Date: Thu Jun 01 2023 - 16:56:43 EST


On 5/29/23 23:41, Martin Blumenstingl wrote:
Hi George,

On Mon, May 22, 2023 at 5:47 PM Старк Георгий Николаевич
<GNStark@xxxxxxxxxxxxxx> wrote:
Hello Martin

Actually you were right that my patch affects only meson8 family not the all new ones, my bad.
It's clear from the driver code meson_saradc.c and dts files.
I've made an experiment on a113l soc - changingclock_rate inmeson_sar_adc_param and measuring adc channel many times
and with low clockfrequency (priv->adc_clk) time of measurementis high
and vice versa. ADC_CLK_DIV field in SAR_ADC_REG3 is always zero.
Thanks for sharing your findings!

I need to get s805 (meson8) board for example and made experiment on it.
If you don't find any Meson8 (S802)/Meson8b (S805) or Meson8m2 (S812)
board then please provide the code that you used for your experiment
as a patch so I can give it a try on my Odroid-C1 (Meson8b).


Best regards,
Martin

Hello Martin

Here the test I promised:
Question: what's the real size of clock divder field in SAR_ADC_REG3 register in saradc in meson8 socs?
The current kernel code says 5 bits
The datasheet says 6 bit

The parent clock of adc clock is 24Mhz
I can check it here by:

# cat /sys/kernel/debug/clk/clk_summary
 xtal                                 4        4        1    24000000          0     0  50000         Y
    c1108680.adc#adc_div              1        1        0      1142858         0     0  50000         Y
       c1108680.adc#adc_en            1        1        0      1142858         0     0  50000         Y

for divider width 5bit min adc clock is 24Mhz / 32 =  750KHZ
for divider width 6bit min adc clock is 24Mhz / 64 =  375KHz

I suppose that the lower adc clock rate the higher measurement time
so I need to get measurement time at both clk freqs and the times differ so
6bit divider is really applied

I performed test at Odroid-C1, kernel 6.2-rc8
Two kernel patches must be applied:

the topic starter patch and the helper patch at the end of the letter
In the helper patch I turn on CLOCK_ALLOW_WRITE_DEBUGFS to change clock rate from she shell
and use ktime_get_raw_ts64 to measure measurement time

So the the test itself:
cat /sys/devices/platform/soc/c1100000.cbus/c1108680.adc/iio:device0/in_voltage3_raw
[ 1781.226309] ==== freq: 1142858 time 42408000

# echo 750000 > /sys/kernel/debug/clk/c1108680.adc#adc_en/clk_rate
# cat /sys/devices/platform/soc/c1100000.cbus/c1108680.adc/iio:device0/in_voltage3_raw
[ 1790.728656] ==== freq: 750000 time 49173000

# echo 375000 > /sys/kernel/debug/clk/c1108680.adc#adc_en/clk_rate
# cat /sys/devices/platform/soc/c1100000.cbus/c1108680.adc/iio:device0/in_voltage3_raw
[ 1816.955477] ==== freq: 375000 time 68245000

# cat /sys/kernel/debug/clk/clk_summary
 xtal                                 4        4        1    24000000          0     0  50000         Y
    c1108680.adc#adc_div              1        1        0      375000          0     0  50000         Y
       c1108680.adc#adc_en            1        1        0      375000          0     0  50000         Y

Helper patch:

diff --git a/drivers/clk/baikal-t1/ccu-pll.c b/drivers/clk/baikal-t1/ccu-pll.c
index 13ef28001439..226e0d46a994 100644
--- a/drivers/clk/baikal-t1/ccu-pll.c
+++ b/drivers/clk/baikal-t1/ccu-pll.c
@@ -363,7 +363,7 @@ static const struct ccu_pll_dbgfs_fld ccu_pll_flds[] = {
  * therefore we don't provide any kernel config based compile time option for
  * this feature to enable.
  */
-#undef CCU_PLL_ALLOW_WRITE_DEBUGFS
+#define CCU_PLL_ALLOW_WRITE_DEBUGFS
 #ifdef CCU_PLL_ALLOW_WRITE_DEBUGFS

 static int ccu_pll_dbgfs_bit_set(void *priv, u64 val)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index e62552a75f08..d552acdaa7bc 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -3263,7 +3263,7 @@ static int clk_dump_show(struct seq_file *s, void *data)
 }
 DEFINE_SHOW_ATTRIBUTE(clk_dump);

-#undef CLOCK_ALLOW_WRITE_DEBUGFS
+#define CLOCK_ALLOW_WRITE_DEBUGFS
 #ifdef CLOCK_ALLOW_WRITE_DEBUGFS
 /*
  * This can be dangerous, therefore don't provide any real compile time
diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c
index 6959a0064551..65132d3ca46a 100644
--- a/drivers/iio/adc/meson_saradc.c
+++ b/drivers/iio/adc/meson_saradc.c
@@ -24,6 +24,8 @@
 #include <linux/regulator/consumer.h>
 #include <linux/mfd/syscon.h>

+#include <linux/timekeeping.h>
+
 #define MESON_SAR_ADC_REG0                                     0x00
        #define MESON_SAR_ADC_REG0_PANEL_DETECT BIT(31)
        #define MESON_SAR_ADC_REG0_BUSY_MASK GENMASK(30, 28)
@@ -599,6 +601,8 @@ static int meson_sar_adc_get_sample(struct iio_dev *indio_dev,
        struct device *dev = indio_dev->dev.parent;
        int ret;

+       int i;
+
        if (chan->type == IIO_TEMP && !priv->temperature_sensor_calibrated)
                return -ENOTSUPP;

@@ -606,16 +610,28 @@ static int meson_sar_adc_get_sample(struct iio_dev *indio_dev,
        if (ret)
                return ret;

-       /* clear the FIFO to make sure we're not reading old values */
-       meson_sar_adc_clear_fifo(indio_dev);

-       meson_sar_adc_set_averaging(indio_dev, chan, avg_mode, avg_samples);
+       struct timespec64 ts0, ts1;
+       ktime_get_raw_ts64(&ts0);

-       meson_sar_adc_enable_channel(indio_dev, chan);
+       for (i = 0; i < 1000; i++) {

-       meson_sar_adc_start_sample_engine(indio_dev);
-       ret = meson_sar_adc_read_raw_sample(indio_dev, chan, val);
-       meson_sar_adc_stop_sample_engine(indio_dev);
+               /* clear the FIFO to make sure we're not reading old values */
+               meson_sar_adc_clear_fifo(indio_dev);
+
+               meson_sar_adc_set_averaging(indio_dev, chan, avg_mode, avg_samples);
+
+               meson_sar_adc_enable_channel(indio_dev, chan);
+
+               meson_sar_adc_start_sample_engine(indio_dev);
+               ret = meson_sar_adc_read_raw_sample(indio_dev, chan, val);
+               meson_sar_adc_stop_sample_engine(indio_dev);
+       }
+
+       ktime_get_raw_ts64(&ts1);
+       u64 t0 = NSEC_PER_SEC * ts0.tv_sec + ts0.tv_nsec;
+       u64 t1 = NSEC_PER_SEC * ts1.tv_sec + ts1.tv_nsec;
+       printk("==== freq: %lu time %lld\n", clk_get_rate(priv->adc_clk), t1 - t0);

        meson_sar_adc_unlock(indio_dev);

Best regards
George