-
Notifications
You must be signed in to change notification settings - Fork 882
iio: dac: Add AD5413 support #2786
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
iio: dac: Add AD5413 support #2786
Conversation
The AD5413 is a single-channel, 14-bit DAC with programmable current or voltage output. It communicates via SPI at clock rates up to 50 MHz. The output can be configured as either voltage or current and is available on a single terminal. Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ad5413.pdf Signed-off-by: Bruce Tsao <bruce.tsao@analog.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the warnings that caused the ci to exit with an error but were not logged
drivers/iio/dac/ad5413.c
Outdated
{ | ||
unsigned int tmp, tmparray[2], size; | ||
const struct ad5413_range *range; | ||
int *index, ret; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
drivers/iio/dac/ad5413.c: In function 'ad5413_parse_dt':
::warning file=drivers/iio/dac/ad5413.c,line=590,col=14::gcc_fanalayzer: unused variable 'index' [-Wunused-variable]
590 | int *index, ret;
| ^~~~~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’ve removed the unused index variable from the ad5413_parse_dt() signature so that only int ret remains. This eliminates the -Wunused-variable warning. Please let me know if you spot any other unused declarations.
drivers/iio/dac/ad5413.c
Outdated
else | ||
indio_dev->channels = ad5413_current_ch; | ||
|
||
ret = ad5413_init(st); | ||
if (ret < 0) { | ||
dev_err(&spi->dev, "AD5413 init failed\n"); | ||
return ret; | ||
} | ||
|
||
return devm_iio_device_register(&st->spi->dev, indio_dev); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
drivers/iio/dac/ad5413.c: In function 'ad5413_probe':
::warning file=drivers/iio/dac/ad5413.c,line=724,col=5::gcc_fanalayzer: this 'else' clause does not guard... [-Wmisleading-indentation]
724 | else
| ^~~~
drivers/iio/dac/ad5413.c:727:9: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'else'
727 | ret = ad5413_init(st);
| ^~~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for spotting that. I’ve refactored the if/else block to use braces so the indentation matches the actual control flow. This removes the misleading indentation and eliminates the warning. Let me know if you’d like any further adjustments.
enum: | ||
- [-10500000, 10500000] | ||
- [-12600000, 12600000] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
enum
doesn't work like that. See other bindings that already have this same property for what works.
enum: | |
- [-10500000, 10500000] | |
- [-12600000, 12600000] | |
adi,range-microvolt: | |
description: Voltage output range specified as <minimum, maximum> | |
oneOf: | |
- items: | |
- const: -10500000 | |
- const: 10500000 | |
- items: | |
- const: -12600000 | |
- const: 12600000 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’ve updated the adi,range-microvolt binding to use oneOf instead of enum.
|
||
adi,range-microamp: | ||
description: Current output range <min, max> in microamps | ||
enum: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
Will also want to call out in the commit message why there is only one option here (and why adi,range-microvolt
doesn't have a default:
- the same reason - but it isn't obvious until later, so best to mention it before)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’ve updated adi,range-microamp to use oneOf with the single supported span (0–24 000 μA).
description: | | ||
Output digital slew control time in microseconds |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
description: | | |
Output digital slew control time in microseconds | |
description: Output digital slew control time in microseconds |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’ve changed the adi,slew-time-us property to use an inline description instead of a multi-line block.
allOf: | ||
- $ref: /schemas/spi/spi-peripheral-props.yaml# | ||
- if: | ||
required: [adi, range-microamp] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
required: [adi, range-microamp] | |
required: [ 'adi,range-microamp' ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’ve updated the required array to quote the property name as ['adi,range-microamp'].
properties: | ||
adi,range-microvolt: false | ||
- if: | ||
required: [adi, range-microvolt] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
required: [adi, range-microvolt] | |
required: [ 'adi,range-microvolt' ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
drivers/iio/dac/ad5413.c
Outdated
/* 3) read slew-time(optional) */ | ||
ret = device_property_read_u32(&st->spi->dev, | ||
"adi,slew-time-us", &tmp); | ||
if (ret) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Checking all of the device_property_
returns in this function could be more strict. There are different errors for "property is missing" (-EINAL) and other error caused, e.g. by typos in the .dts file (e.g. a not enough items in the array).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the catch. I’ve updated the adi,slew-time-us handling so that:
-ENODATA and -EINVAL are treated as “property not provided” and default to 0
Any other negative return is treated as a real parsing error (logged via dev_err) and aborts probe
Please let me know if this covers all cases or if further tweaks are needed.
drivers/iio/dac/ad5413.c
Outdated
|
||
#define AD5413_DAC_CHAN(_chan_type) { \ | ||
.type = (_chan_type), \ | ||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_RAW) | \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIO_CHAN_INFO_RAW
is for sure separate
, not shared_by_type
. Since there aren't versions of this chip with more than one channel, it isn't clear if SCALE and OFFSET should also be separate
, so could go either way on those.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for pointing that out. I’ve removed IIO_CHAN_INFO_RAW from info_mask_shared_by_type and added it to info_mask_separate to ensure RAW is treated as a separate attribute. SCALE and OFFSET remain in info_mask_shared_by_type since this device only has one channel. Please let me know if you’d prefer SCALE and OFFSET to be marked separate as well.
int *index, ret; | ||
|
||
/* 1) voltage */ | ||
ret = device_property_read_u32_array(&st->spi->dev, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will allow the +/- 12.6 range to be given in the devicetree but set up the chip for +/-10.5V, but OVRNG_EN
isn't implemented yet. So we should not allow that or now or implement OVRNG_EN
.
It also wouldn't hurt to check the current values as well (even if there is only one option, someone might try to put something else in the .dts file)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for catching that. I’ve made the following updates:
Voltage range: The DT binding and driver now only allow ±10.5 V. Any attempt to use ±12.6 V is rejected with -EINVAL until we implement the OVRNG_EN bit.
Current range: Added explicit validation so that adi,range-microamp must be exactly 0–24 000 µA; anything else also returns -EINVAL.
With these checks in place, we prevent the chip from being configured for unsupported ranges. OVRNG_EN support can be added in a follow-up patch once fully tested.
drivers/iio/dac/ad5413.c
Outdated
|
||
struct ad5413_range { | ||
int reg; | ||
int min; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Upstream prefers units on macros and variables, e.g. min_uv
here.
Same applies throughout the driver. (It would especially help to make the raw_read
function easier to understand)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the suggestion. I’ve renamed all range struct members and related macros to include explicit unit suffixes (e.g. min_uv/max_uv for microvolt ranges), which should improve readability and prevent confusion. Please let me know if any other identifiers need unit annotations.
This patch addresses various improvements based on reviewer suggestions: - Removed unused index variable in parse_dt() - Fixed misleading indentation in probe() conditional blocks - Reworked DT bindings: switched to enum/oneOf and restricted voltage/current ranges - Added driver-side range validation for voltage and current modes - Replaced manual bit macros with FIELD_PREP() for DAC_CONFIG - Removed unnecessary include: <linux/kernel.h> - Sorted entries in Kconfig and Makefile - Quoted DT required property names and simplified mutual-exclusion logic - Tidied up whitespace, blank lines, and long lines Signed-off-by: Bruce Tsao <bruce.tsao@analog.com>
- items: | ||
- const: -10500000 | ||
- const: 10500000 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- items: | |
- const: -10500000 | |
- const: 10500000 | |
- items: | |
- const: -10500000 | |
- const: 10500000 | |
- items: | |
- const: -12600000 | |
- const: 12600000 |
This needs to include all possibilities.
oneOf: | ||
- items: | ||
- const: 0 | ||
- const: 24000 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oneOf: | |
- items: | |
- const: 0 | |
- const: 24000 | |
items: | |
- const: 0 | |
- const: 24000 |
oneOf
doesn't make sense when there is only one possibility.
/* AD5413 DAC_CONFIG Register (Addr = 0x06) Bitfield Macros */ | ||
/* Slew Rate Step (Bits[15:13]) */ | ||
#define AD5413_REG_DAC_CONFIG_SR_STEP_MSK GENMASK(15, 13) | ||
#define AD5413_REG_DAC_CONFIG_SR_STEP_MODE(x) FIELD_PREP(AD5413_REG_DAC_CONFIG_SR_STEP_MSK, (x)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The IIO maintainer prefers to just use FIELD_PREP()
directly instead of making macros to hide it.
|
||
|
||
/* AD5413 Key Register (Address: 0x08) */ | ||
#define AD5413_REG_KEY_REG_ADDR_SHIFT 16 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#define AD5413_REG_KEY_REG_ADDR_SHIFT 16 |
unused
|
||
|
||
|
||
/* AD5413 DAC_CONFIG Register (Addr = 0x06) Bitfield Macros */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of comments like this, the IIO maintainer prefers to have masks like this right below the corresponding register address (with a few extra spaces indent).
I.e. above we would have...
...
#define AD5413_REG_USER_OFFSET 0x05
#define AD5413_REG_DAC_CONFIG 0x06
#define AD5413_REG_DAC_CONFIG_SR_STEP_MSK GENMASK(15, 13)
#define AD5413_REG_DAC_CONFIG_SR_CLOCK_MSK GENMASK(12, 9)
#define AD5413_REG_DAC_CONFIG_SR_EN_MSK BIT(8)
#define AD5413_REG_DAC_CONFIG_RSET_EXT_EN_MSK BIT(7)
#define AD5413_REG_DAC_CONFIG_OUT_EN_MSK BIT(6)
#define AD5413_REG_DAC_CONFIG_INT_EN_MSK BIT(5)
#define AD5413_REG_DAC_CONFIG_OVRNG_EN_MSK BIT(4)
#define AD5413_REG_DAC_CONFIG_RANGE_MSK GENMASK(3, 0)
#define AD5413_REG_SW_LDAC 0x07
#define AD5413_REG_KEY 0x08
#define AD5413_REG_KEY_REG_ADDR_MASK GENMASK(20, 16)
#define AD5413_REG_KEY_CODE_MASK GENMASK(15, 0)
...
if (ret < 0) | ||
return ret; | ||
|
||
/* Disable CRC checks */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/* Disable CRC checks */ |
if (ret < 0) | ||
return ret; | ||
|
||
/* Perform a calibration memory refresh */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/* Perform a calibration memory refresh */ |
|
||
st->spi = spi; | ||
|
||
mutex_init(&st->lock); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mutex_init(&st->lock); | |
ret = devm_mutex_init(&st->lock); | |
if (ret) | |
return ret; |
Not sure which kernel version this was introduced in, but is preferred in new code.
if (st->out_range.reg == AD5413_RANGE_PLUSMINUS_10_5V) { | ||
indio_dev->channels = ad5413_voltage_ch; | ||
} else { | ||
indio_dev->channels = ad5413_current_ch; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indentation needs fixing
Summary
This PR adds initial support for the Analog Devices AD5413, a 14-bit single-channel DAC capable of voltage and current output.
Key changes
ad5413.c
underdrivers/iio/dac/
adi,ad5413.yaml
underDocumentation/devicetree/bindings/iio/dac/
Datasheet:
https://www.analog.com/media/en/technical-documentation/data-sheets/ad5413.pdf
PR Description
necessary to understand them. List any dependencies required for this change.
any space), or simply check them after publishing the PR.
description and try to push all related PRs simultaneously.
PR Type
PR Checklist