[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250727132143.35a44547@jic23-huawei>
Date: Sun, 27 Jul 2025 13:21:43 +0100
From: Jonathan Cameron <jic23@...nel.org>
To: David Lechner <dlechner@...libre.com>
Cc: Michael Hennerich <Michael.Hennerich@...log.com>, Nuno Sá
<nuno.sa@...log.com>, Andy Shevchenko <andy@...nel.org>, Rob Herring
<robh@...nel.org>, Krzysztof Kozlowski <krzk+dt@...nel.org>, Conor Dooley
<conor+dt@...nel.org>, linux-iio@...r.kernel.org,
devicetree@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: Re: [PATCH 2/4] iio: adc: ad7124: do not require mclk
On Thu, 24 Jul 2025 18:25:23 -0500
David Lechner <dlechner@...libre.com> wrote:
> Make the "mclk" clock optional in the ad7124 driver. The MCLK is an
> internal counter on the ADC, so it is not something that should be
> coming from the devicetree. However, existing users may be using this
> to essentially select the power mode of the ADC from the devicetree.
> In order to not break those users, we have to keep the existing "mclk"
> handling, but now it is optional.
>
> Now, when the "mclk" clock is omitted from the devicetree, the driver
> will default to the full power mode. Support for an external clock
> and dynamic power mode switching can be added later if needed.
>
> Signed-off-by: David Lechner <dlechner@...libre.com>
> ---
> drivers/iio/adc/ad7124.c | 61 ++++++++++++++++++++++++++++++++++--------------
> 1 file changed, 43 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c
> index 9808df2e92424283a86e9c105492c7447d071e44..f587574e8a24040540a470e13fed412ec9c81971 100644
> --- a/drivers/iio/adc/ad7124.c
> +++ b/drivers/iio/adc/ad7124.c
> @@ -174,7 +174,6 @@ struct ad7124_state {
> struct ad_sigma_delta sd;
> struct ad7124_channel *channels;
> struct regulator *vref[4];
> - struct clk *mclk;
> unsigned int adc_control;
> unsigned int num_channels;
> struct mutex cfgs_lock; /* lock for configs access */
> @@ -254,7 +253,9 @@ static void ad7124_set_channel_odr(struct ad7124_state *st, unsigned int channel
> {
> unsigned int fclk, odr_sel_bits;
>
> - fclk = clk_get_rate(st->mclk);
> + fclk = ad7124_master_clk_freq_hz[FIELD_GET(
> + AD7124_ADC_CONTROL_POWER_MODE, st->adc_control)];
> +
I'm not keen on that wrap point.
fclk = ad7124_master_clk_freq_hz[FIELD_GET(AD7124_ADC_CONTROL_POWER_MODE,
st->adc_control)];
maybe?
> /*
> * FS[10:0] = fCLK / (fADC x 32) where:
> * fADC is the output data rate
> @@ -1111,21 +1112,49 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev,
> static int ad7124_setup(struct ad7124_state *st)
> {
> struct device *dev = &st->sd.spi->dev;
> - unsigned int fclk, power_mode;
> + unsigned int power_mode;
> + struct clk *mclk;
> int i, ret;
>
> - fclk = clk_get_rate(st->mclk);
> - if (!fclk)
> - return dev_err_probe(dev, -EINVAL, "Failed to get mclk rate\n");
> + /*
> + * Always use full power mode for max performance. If needed, the driver
> + * could be adapted to use a dynamic power mode based on the requested
> + * output data rate.
> + */
> + power_mode = AD7124_ADC_CONTROL_POWER_MODE_FULL;
>
> - /* The power mode changes the master clock frequency */
> - power_mode = ad7124_find_closest_match(ad7124_master_clk_freq_hz,
> - ARRAY_SIZE(ad7124_master_clk_freq_hz),
> - fclk);
> - if (fclk != ad7124_master_clk_freq_hz[power_mode]) {
> - ret = clk_set_rate(st->mclk, fclk);
> - if (ret)
> - return dev_err_probe(dev, ret, "Failed to set mclk rate\n");
> + /*
> + * HACK: This "mclk" business is needed for backwards compatibility with
I'd drop the HACK bit of this. Whilst I understand the spirit of the comment
that term tends to make people try to 'fix' things ;)
> + * old devicetrees that specified a fake clock named "mclk" to select
> + * the power mode.
> + */
> + mclk = devm_clk_get_optional_enabled(dev, "mclk");
> + if (IS_ERR(mclk))
> + return dev_err_probe(dev, PTR_ERR(mclk), "Failed to get mclk\n");
> +
> + if (mclk) {
> + unsigned long mclk_hz;
> +
> + mclk_hz = clk_get_rate(mclk);
> + if (!mclk_hz)
> + return dev_err_probe(dev, -EINVAL, "Failed to get mclk rate\n");
> +
> + /*
> + * This logic is a bit backwards, which is why it is considered
> + * a hack and is only here for backwards compatibility. The
> + * driver should be able to set the power mode as it sees fit
> + * and the f_clk/mclk rate should be dynamic accordingly. But
> + * here, we are selecting a fixed power mode based on the given
> + * "mclk" rate.
My assumption is that someone had a board with a fixed rate clock on this pin.
So it might not be possible to have the driver do that adjustment.
If anyone ever adds that support, we'll have to be careful about handling fixed
clocks.
This looks fine though.
> + */
> + power_mode = ad7124_find_closest_match(ad7124_master_clk_freq_hz,
> + ARRAY_SIZE(ad7124_master_clk_freq_hz), mclk_hz);
> +
> + if (mclk_hz != ad7124_master_clk_freq_hz[power_mode]) {
> + ret = clk_set_rate(mclk, mclk_hz);
> + if (ret)
> + return dev_err_probe(dev, ret, "Failed to set mclk rate\n");
> + }
> }
>
> /* Set the power mode */
> @@ -1303,10 +1332,6 @@ static int ad7124_probe(struct spi_device *spi)
> return dev_err_probe(dev, ret, "Failed to register disable handler for regulator #%d\n", i);
> }
>
> - st->mclk = devm_clk_get_enabled(&spi->dev, "mclk");
> - if (IS_ERR(st->mclk))
> - return dev_err_probe(dev, PTR_ERR(st->mclk), "Failed to get mclk\n");
> -
> ret = ad7124_soft_reset(st);
> if (ret < 0)
> return ret;
>
Powered by blists - more mailing lists