From: "Nuno Sá" <noname.nuno@gmail.com>
To: Jonathan Cameron <jic23@kernel.org>,
Nuno Sa via B4 Relay <devnull+nuno.sa.analog.com@kernel.org>
Cc: nuno.sa@analog.com, linux-iio@vger.kernel.org,
devicetree@vger.kernel.org,
Dragos Bogdan <dragos.bogdan@analog.com>,
Lars-Peter Clausen <lars@metafoo.de>,
Michael Hennerich <Michael.Hennerich@analog.com>,
Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>,
Conor Dooley <conor+dt@kernel.org>,
Olivier Moysan <olivier.moysan@foss.st.com>
Subject: Re: [PATCH 09/10] iio: dac: add support for AXI DAC IP core
Date: Thu, 28 Mar 2024 17:43:43 +0100 [thread overview]
Message-ID: <d86dbdd7c1f234ebedc08c3433735f43abff7f7e.camel@gmail.com> (raw)
In-Reply-To: <20240328153542.7ddb897c@jic23-huawei>
On Thu, 2024-03-28 at 15:35 +0000, Jonathan Cameron wrote:
> On Thu, 28 Mar 2024 14:22:33 +0100
> Nuno Sa via B4 Relay <devnull+nuno.sa.analog.com@kernel.org> wrote:
>
> > From: Nuno Sa <nuno.sa@analog.com>
> >
> > Support the Analog Devices Generic AXI DAC IP core. The IP core is used
> > for interfacing with digital-to-analog (DAC) converters that require either
> > a high-speed serial interface (JESD204B/C) or a source synchronous parallel
> > interface (LVDS/CMOS). Typically (for such devices) SPI will be used for
> > configuration only, while this IP core handles the streaming of data into
> > memory via DMA.
> >
> > Signed-off-by: Nuno Sa <nuno.sa@analog.com>
>
>
> A few minor things inline, but mostly seems fine to me.
>
> Jonathan
>
>
> ...
>
> > diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c
> > new file mode 100644
> > index 000000000000..0022ecb4e4bb
> > --- /dev/null
> > +++ b/drivers/iio/dac/adi-axi-dac.c
>
>
> > +
> > +enum {
> > + AXI_DAC_FREQ_TONE_1,
> > + AXI_DAC_FREQ_TONE_2,
> > + AXI_DAC_SCALE_TONE_1,
> > + AXI_DAC_SCALE_TONE_2,
> > + AXI_DAC_PHASE_TONE_1,
> > + AXI_DAC_PHASE_TONE_2,
> > +};
> > +
> > +static int __axi_dac_frequency_get(struct axi_dac_state *st, unsigned int chan,
> > + unsigned int tone, unsigned int *freq)
> > +{
> > + u32 reg, raw;
> > + int ret;
> > +
> > + if (!st->dac_clk) {
> > + dev_err(st->dev, "Sampling rate is 0...\n");
> > + return -EINVAL;
> > + }
> > +
> > + if (tone == AXI_DAC_FREQ_TONE_1)
>
> Given this is matching 2 out of enum with other values, it would be more
> locally readable as a switch statement with an error returning default.
> Then we wouldn't need to look at the caller.
>
> Or at the caller convert from the enum to 0,1 for all these functions.
>
Ok, will see what of the alternatives looks better.
>
>
> > + reg = AXI_DAC_REG_CHAN_CNTRL_2(chan);
> > + else
> > + reg = AXI_DAC_REG_CHAN_CNTRL_4(chan);
> > +
> > + ret = regmap_read(st->regmap, reg, &raw);
> > + if (ret)
> > + return ret;
> > +
> > + raw = FIELD_GET(AXI_DAC_FREQUENCY, raw);
> > + *freq = DIV_ROUND_CLOSEST_ULL(raw * st->dac_clk, BIT(16));
> > +
> > + return 0;
> > +}
>
> ...
>
> > +static int axi_dac_scale_set(struct axi_dac_state *st,
> > + const struct iio_chan_spec *chan,
> > + const char *buf, size_t len, unsigned int tone)
> > +{
> > + int integer, frac, scale;
> > + u32 raw = 0, reg;
> > + int ret;
> > +
> > + ret = iio_str_to_fixpoint(buf, 100000, &integer, &frac);
> > + if (ret)
> > + return ret;
> > +
> > + scale = integer * MEGA + frac;
> > + if (scale <= -2 * (int)MEGA || scale >= 2 * (int)MEGA)
> > + return -EINVAL;
> > +
> > + /* format is 1.1.14 (sign, integer and fractional bits) */
> > + if (scale < 0) {
> > + raw = FIELD_PREP(AXI_DAC_SCALE_SIGN, 1);
> > + scale *= -1;
> > + }
> > +
> > + raw |= div_u64((u64)scale * AXI_DAC_SCALE_INT, MEGA);
> > +
> > + if (tone == AXI_DAC_SCALE_TONE_1)
> > + reg = AXI_DAC_REG_CHAN_CNTRL_1(chan->channel);
> > + else
> > + reg = AXI_DAC_REG_CHAN_CNTRL_3(chan->channel);
> > +
> > + guard(mutex)(&st->lock);
> > + ret = regmap_write(st->regmap, reg, raw);
> > + if (ret)
> > + return ret;
> > +
> > + /* synchronize channels */
> > + ret = regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_1, AXI_DAC_SYNC);
> > + if (ret)
> > + return ret;
> > +
> > + return len;
> > +}
> > +
> > +static int axi_dac_phase_set(struct axi_dac_state *st,
> > + const struct iio_chan_spec *chan,
> > + const char *buf, size_t len, unsigned int tone)
> > +{
> > + int integer, frac, phase;
> > + u32 raw, reg;
> > + int ret;
> > +
> > + ret = iio_str_to_fixpoint(buf, 100000, &integer, &frac);
>
> > + if (ret)
> > + return ret;
> > +
> > + phase = integer * MEGA + frac;
> > + if (phase < 0 || phase > AXI_DAC_2_PI_MEGA)
> > + return -EINVAL;
> > +
> > + raw = DIV_ROUND_CLOSEST_ULL((u64)phase * U16_MAX, AXI_DAC_2_PI_MEGA);
> > +
> > + if (tone == AXI_DAC_PHASE_TONE_1)
> Preference for a switch so it's clear there are only 2 choices.
> > + reg = AXI_DAC_REG_CHAN_CNTRL_2(chan->channel);
> > + else
> > + reg = AXI_DAC_REG_CHAN_CNTRL_4(chan->channel);
> > +
> > + guard(mutex)(&st->lock);
> > + ret = regmap_update_bits(st->regmap, reg, AXI_DAC_PHASE,
> > + FIELD_PREP(AXI_DAC_PHASE, raw));
> > + if (ret)
> > + return ret;
> > +
> > + /* synchronize channels */
> > + ret = regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_1, AXI_DAC_SYNC);
> > + if (ret)
> > + return ret;
> > +
> > + return len;
> > +}
> > +
> > +static int axi_dac_ext_info_set(struct iio_backend *back, uintptr_t private,
> > + const struct iio_chan_spec *chan,
> > + const char *buf, size_t len)
> > +{
> > + struct axi_dac_state *st = iio_backend_get_priv(back);
> > +
> > + switch (private) {
> > + case AXI_DAC_FREQ_TONE_1:
> > + case AXI_DAC_FREQ_TONE_2:
>
> Same as the get path - convert to which tone here so that the enum becomes
> a tone index for the functions called and the mapping to that single enum
> is kept clear of the lower level code.
>
> > + return axi_dac_frequency_set(st, chan, buf, len, private);
> > + case AXI_DAC_SCALE_TONE_1:
> > + case AXI_DAC_SCALE_TONE_2:
> > + return axi_dac_scale_set(st, chan, buf, len, private);
> > + case AXI_DAC_PHASE_TONE_1:
> > + case AXI_DAC_PHASE_TONE_2:
> > + return axi_dac_phase_set(st, chan, buf, len, private);
> > + default:
> > + return -EOPNOTSUPP;
> > + }
> > +}
> > +
> > +static int axi_dac_ext_info_get(struct iio_backend *back, uintptr_t private,
> > + const struct iio_chan_spec *chan, char *buf)
> > +{
> > + struct axi_dac_state *st = iio_backend_get_priv(back);
> > +
> > + switch (private) {
> > + case AXI_DAC_FREQ_TONE_1:
> > + case AXI_DAC_FREQ_TONE_2:
> > + return axi_dac_frequency_get(st, chan, buf, private);
> I'd break out private as an unsigned int here and then - AXI_DAC_FREQ_TONE_1
> so that it is just which tone for all the calls made from here.
> Similar for the following ones.
>
ack..
> > + case AXI_DAC_SCALE_TONE_1:
> > + case AXI_DAC_SCALE_TONE_2:
> > + return axi_dac_scale_get(st, chan, buf, private);
> > + case AXI_DAC_PHASE_TONE_1:
> > + case AXI_DAC_PHASE_TONE_2:
> > + return axi_dac_phase_get(st, chan, buf, private);
> > + default:
> > + return -EOPNOTSUPP;
> > + }
> > +}
> > +
> > +static const struct iio_chan_spec_ext_info axi_dac_ext_info[] = {
> > + IIO_BACKEND_EX_INFO("frequency0", IIO_SEPARATE, AXI_DAC_FREQ_TONE_1),
> > + IIO_BACKEND_EX_INFO("frequency1", IIO_SEPARATE, AXI_DAC_FREQ_TONE_2),
> > + IIO_BACKEND_EX_INFO("scale0", IIO_SEPARATE, AXI_DAC_SCALE_TONE_1),
> > + IIO_BACKEND_EX_INFO("scale1", IIO_SEPARATE, AXI_DAC_SCALE_TONE_2),
> > + IIO_BACKEND_EX_INFO("phase0", IIO_SEPARATE, AXI_DAC_PHASE_TONE_1),
> > + IIO_BACKEND_EX_INFO("phase1", IIO_SEPARATE, AXI_DAC_PHASE_TONE_2),
> > + {}
> > +};
> > +
> > +static int axi_dac_extend_chan(struct iio_backend *back,
> > + struct iio_chan_spec *chan)
> > +{
> > + struct axi_dac_state *st = iio_backend_get_priv(back);
> > +
> > + if (chan->type != IIO_ALTVOLTAGE)
> > + return -EINVAL;
> > + if (st->reg_config & AXI_DDS_DISABLE)
> > + /* nothing to extend */
> > + return 0;
> > +
> > + chan->ext_info = axi_dac_ext_info;
> > +
> > + return 0;
> > +}
>
> > +static int axi_dac_set_sample_rate(struct iio_backend *back, unsigned int chan,
> > + u64 sample_rate)
> > +{
> > + struct axi_dac_state *st = iio_backend_get_priv(back);
> > + unsigned int freq;
> > + int ret, tone;
> > +
> > + if (!sample_rate)
> > + return -EINVAL;
> > + if (st->reg_config & AXI_DDS_DISABLE)
> > + /* nothing to care if DDS is disabled */
> Rephrase this. Is the point that the sample rate has no meaning without DDS or
> that it has meaning but nothing to do here?
Has no meaning as it's not used with DDS enabled...
- Nuno Sá
>
next prev parent reply other threads:[~2024-03-28 16:43 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-03-28 13:22 [PATCH 00/10] iio: dac: support IIO backends on the output direction Nuno Sa via B4 Relay
2024-03-28 13:22 ` [PATCH 01/10] iio: buffer: add helper for setting direction Nuno Sa via B4 Relay
2024-03-28 14:36 ` Jonathan Cameron
2024-03-28 15:18 ` Nuno Sá
2024-03-28 15:54 ` Jonathan Cameron
2024-03-28 13:22 ` [PATCH 02/10] iio: buffer-dma: Rename iio_dma_buffer_data_available() Nuno Sa via B4 Relay
2024-03-28 13:22 ` [PATCH 03/10] iio: buffer-dma: Enable buffer write support Nuno Sa via B4 Relay
2024-03-28 13:22 ` [PATCH 04/10] iio: buffer-dmaengine: Support specifying buffer direction Nuno Sa via B4 Relay
2024-03-28 13:22 ` [PATCH 05/10] iio: buffer-dmaengine: Enable write support Nuno Sa via B4 Relay
2024-03-28 13:22 ` [PATCH 06/10] dt-bindings: iio: dac: add bindings doc for AXI DAC driver Nuno Sa via B4 Relay
2024-03-29 18:46 ` David Lechner
2024-04-02 7:51 ` Nuno Sá
2024-04-01 13:59 ` Rob Herring
2024-04-04 10:03 ` Nuno Sá
2024-03-28 13:22 ` [PATCH 07/10] dt-bindings: iio: dac: add bindings doc for AD9739A Nuno Sa via B4 Relay
2024-03-29 19:06 ` David Lechner
2024-03-30 18:27 ` Krzysztof Kozlowski
2024-04-02 7:49 ` Nuno Sá
2024-04-02 7:50 ` Nuno Sá
2024-04-01 14:02 ` Rob Herring
2024-03-28 13:22 ` [PATCH 08/10] iio: backend: add new functionality Nuno Sa via B4 Relay
2024-03-28 15:16 ` Jonathan Cameron
2024-03-28 15:42 ` Nuno Sá
2024-03-28 15:59 ` Jonathan Cameron
2024-03-28 16:54 ` Nuno Sá
2024-03-28 13:22 ` [PATCH 09/10] iio: dac: add support for AXI DAC IP core Nuno Sa via B4 Relay
2024-03-28 15:35 ` Jonathan Cameron
2024-03-28 16:43 ` Nuno Sá [this message]
2024-03-28 13:22 ` [PATCH 10/10] iio: dac: support the ad9739a RF DAC Nuno Sa via B4 Relay
2024-03-28 15:51 ` Jonathan Cameron
2024-03-28 16:37 ` Nuno Sá
2024-03-28 16:52 ` Jonathan Cameron
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=d86dbdd7c1f234ebedc08c3433735f43abff7f7e.camel@gmail.com \
--to=noname.nuno@gmail.com \
--cc=Michael.Hennerich@analog.com \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=devnull+nuno.sa.analog.com@kernel.org \
--cc=dragos.bogdan@analog.com \
--cc=jic23@kernel.org \
--cc=krzysztof.kozlowski+dt@linaro.org \
--cc=lars@metafoo.de \
--cc=linux-iio@vger.kernel.org \
--cc=nuno.sa@analog.com \
--cc=olivier.moysan@foss.st.com \
--cc=robh@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox