Conversation
Add device tree bindings for the Analog Devices AD5706R 16-bit 4-channel current output DAC. The AD5706R features: - 4 independent current output channels - 16-bit resolution - SPI interface (up to 50MHz write, 25MHz read) - Multiple LDAC trigger modes (hardware/software) - Toggle and dither function generators - Programmable output ranges (50mA to 300mA) Signed-off-by: Alexis Czezar Torreno <alexisczezar.torreno@analog.com>
d8113bb to
620846b
Compare
stefpopa
left a comment
There was a problem hiding this comment.
A few small issues and some things that need to be clarified. Overall looks good!
drivers/iio/dac/ad5706r.c
Outdated
| ret = clk_set_rate(st->reference_clk, rate * 2); | ||
|
|
||
| /* Re-enable the clock after setting the rate */ | ||
| clk_prepare_enable(st->reference_clk); |
There was a problem hiding this comment.
Should we check the return value of the clk_prepare_enable()? Otherwise, in case it fails, the clock remains disabled, but we move forward.
There was a problem hiding this comment.
Yes i've checked a few other codes, will need to edit this to have error check.
drivers/iio/dac/ad5706r.c
Outdated
| break; | ||
| case RANGE_SEL_300: | ||
| default: | ||
| *val = 300 * MEGA / AD5706R_DAC_MAX_CODE; |
There was a problem hiding this comment.
For the other ranges, HZ_PER_MHZ is used, but for RANGE_SEL_300, MEGA is used, should we use the same constant everywhere? Otherwise, add a comment here explaining why a different constant is used.
There was a problem hiding this comment.
will make this consistent (I'm also wondering why I did this)
drivers/iio/dac/ad5706r.c
Outdated
| mutex_init(&st->lock); | ||
| st->spi = spi; | ||
|
|
||
| _ad5706r_setup(st); |
There was a problem hiding this comment.
should we acquire a lock during the ad5706r_setup? It seems that inside the function we are accessing the HW.
There was a problem hiding this comment.
will add a lock in the function
drivers/iio/dac/ad5706r.c
Outdated
| break; | ||
| case RANGE_SEL_300: | ||
| default: | ||
| *val = 300 * MEGA / AD5706R_DAC_MAX_CODE; |
There was a problem hiding this comment.
Why are we using a different range for RANGE_SEL_300? Either use MAGA everywhere or please add a comment here explaining why a different constant is needed.
There was a problem hiding this comment.
already acknowledged similar comment above, will change for consistency
drivers/iio/dac/ad5706r.c
Outdated
| ret = clk_set_rate(st->reference_clk, rate * 2); | ||
|
|
||
| /* Re-enable the clock after setting the rate */ | ||
| clk_prepare_enable(st->reference_clk); |
There was a problem hiding this comment.
Should we check the return value of the clk_prepare_enable()? Otherwise, if enabling the clock fails, we continue while the clock remains disabled.
There was a problem hiding this comment.
ditto, similar comment above
drivers/iio/dac/ad5706r.c
Outdated
| if (val < 1) | ||
| val = 1; | ||
| if (val > 10000000) | ||
| val = 10000000; |
There was a problem hiding this comment.
We could define the minimum and maximum frequencies as constants at the top of the file with other defines and use clamp() to enforce the valid range for the PWM generator.
There was a problem hiding this comment.
will figure out how to use this but yes noted on this.
drivers/iio/dac/ad5706r.c
Outdated
| ldacb_pwm_state.enabled = true; | ||
| ret = pwm_apply_might_sleep(st->ldacb_pwm, &ldacb_pwm_state); | ||
| if (ret) | ||
| return ret; |
There was a problem hiding this comment.
should we use dev_err_probe() here? Check everywhere in _ad5706r_setup(). Sometimes ret is returned directly, sometimes dev_err_probe() is returned. For consistency sake, we can return dev_err_probe() everywhere.
There was a problem hiding this comment.
am not sure if its a style but
when the function is something like xxxx = devm_yyyy_get, this is where dev_err_probe is used
others just return ret
or is it any function in the probe must receieve the dev_err treatment
edit: i added the dev_err to everything inside the function for consistency
| st->debug_spi_speed_hz_read = current_rate; | ||
|
|
||
| /* Wait for clock to stabilize */ | ||
| usleep_range(3000, 3100); |
There was a problem hiding this comment.
This is concerning to me. It adds a 3ms delay with every SPI transaction. Is this a real HW requirement? Isn't it enough to add a short delay after initial setup? I assume 100-200us should be plenty.
Or is it necessary to have a _ad5706r_set_clk_rate() call with each read/write?
There was a problem hiding this comment.
Yes, this is related to the not so common feature the requestor wants.
They want to have runtime configurable spi_speeds, and spi_read and spi_write should be separate speeds. The use case something like spi_write at 50MHz and read is 25Mhz.
After testing on higher frequencies, the data fetch fails if spi read/write are fast, not the same speed, and alternating. when read/write alternates the spi fails on high frequency setting.
This 3ms was manually tested as the minimum to stabilize the clock when alternating read/write.
There was a problem hiding this comment.
If reads are infrequent, the 3ms delay on speed changes is acceptable, but if we have to perform frequent alternating read/writes, it's a heavy penalty.
There was a problem hiding this comment.
Were you able to identify the root cause of the clock stabilization? Is it something related to the SPI Engine?
There was a problem hiding this comment.
Anyway, I guess it's not so bad, if we do multiple consecutive writes and an occasional read.
There was a problem hiding this comment.
my best guess here is it's caused by changing the actual clock rate of the spi_engine
i mean normally the way it goes is like
clk_gen -> spi_engine (regmap -> interconnect -> execution module) -> spi transaction
changing spi_speeds can be done in the execution module but this is only an integer divider (a 50Mhz input makes 25MHz, 16.66, 12.5, 10, etc)
requestor wanted more fine changes so I controlled the speed on the clk_gen itself
There was a problem hiding this comment.
Aha! So, it must be related to the PLL lock time. Do you know what specific frequencies they actually need?
There was a problem hiding this comment.
To quote the requestor's message to us:
"Reason is different customers have different clock requirements. We have seen numbers like 48MHz, 16.384MHz, 33MHz in optical modules where this part goes."
There was a problem hiding this comment.
Ok, then the delay makes sense, as dynamic clock reconfiguration is necessary for these requirements. Sorry for asking so many questions, but I am a bit worried about making this acceptable upstream. In the best case scenario, we will need to provide an explanation.
98610ab to
6704915
Compare
|
v2:
|
6704915 to
736645d
Compare
stefpopa
left a comment
There was a problem hiding this comment.
The PR looks good overall, there is only one outstanding topic regarding the 3ms delay.
It seems that this delay is required for PLL reconfiguration which is needed for special speeds such as 48/16/33MHz.
However, PLL reconfiguration is not required for standard speeds such as 50/25MHz. Therefore, customers using these speeds should not experience any performance penalty.
One suggestion is to use a hybrid approach by trying to achieve a target frequency via the SPI Engine integer division (inside the _ad5706r_set_clk_rate() function). This eliminates the 3ms delay.
If this is not possible, then we must go on the "slow path" which needs precise frequency not achievable via integer division. This is the current implementation with the 3ms delay.
We also need to document this properly.
Additional suggestion is to add a device tree property to let customers choose the path. It can be something like this:
properties:
adi,spi-speed-mode:
description: |
SPI clock speed configuration mode.
"auto" (default): Automatically use integer division for standard
frequencies (faster), fall back to PLL reconfiguration for exact
frequencies not achievable via division.
"precise": Always use PLL reconfiguration for exact requested
frequency (adds 3ms delay on speed changes).
"fast-only": Restrict to frequencies achievable via integer division
from 100MHz base clock. Reject attempts to set other frequencies.
enum: [auto, precise, fast-only]
default: auto
398a3a6 to
36982ac
Compare
|
v3:
The SPI Engine mode was added to avoid the 3ms penalty of purely using the clkgen for SPI speed changes. Regarding the Additional suggestion to add a device tree property, I currently opted not and did the automatic version. |
stefpopa
left a comment
There was a problem hiding this comment.
One small refactoring to improve readability, rest looks good.
36982ac to
3262009
Compare
Add driver for the Analog Devices AD5706R 16-bit 4-channel current output DAC with SPI interface. The device features: - 4 independent current output channels (OUT0-OUT3) - 16-bit resolution - Programmable output ranges: 50mA, 150mA, 200mA, 300mA - Hardware and software LDAC trigger modes - Toggle and dither function generators - Output shutdown modes (tri-state or ground) - Asynchronous/synchronous LDAC operation - Dynamic SPI clock frequency adjustment The driver provides IIO standard interfaces for: - DAC output control via raw values - Output range selection (scale) - LDAC trigger configuration - Output state control (normal/shutdown) - Function generator modes (toggle/dither) Signed-off-by: Alexis Czezar Torreno <alexisczezar.torreno@analog.com>
Adding maintainer entry for AD5706R. Signed-off-by: Alexis Czezar Torreno <alexisczezar.torreno@analog.com>
Editing kconfig.adi to imply AD5706R Signed-off-by: Alexis Czezar Torreno <alexisczezar.torreno@analog.com>
3262009 to
8f5a813
Compare
|
Will Proceed to upstream, thanks! |
PR Description
PR Type
PR Checklist