Skip to content

Add support for AD4052 ADC Family #2642

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

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open

Add support for AD4052 ADC Family #2642

wants to merge 9 commits into from

Conversation

gastmaier
Copy link
Contributor

@gastmaier gastmaier commented Nov 1, 2024

PR Description

Add:

  • driver support for AD4052/AD4058/AD4050/AD4056 (16-bit/12-bit SAR ADC SPI)
  • devicetree binding

Optional:

  • sample devicetree for coraz7s
  • kconfig imply driver

Features:

  • Single shot using gpio as ADC CNV
  • Buffer readings using AXI PWM ADC CNV and ADC GP1 Data Ready as AXI SPI Engine Offload Trigger
  • Monitor mode with ADC GP0 as interrupt trigger (either IIO threshold direction event)
    • User should do register access to get event details.
  • Functional modes via oversampling config: Sample Mode (0/1) or Burst Averaging Mode (>1)
    • Burst Avg enables configuring averaging filter length value (AVG_CONFIG.AVG_WIN_LEN)
  • DEVICE_CONFIG.POWER_MODE : put device on sleep at pm_runtime ops.
  • TIMER_CONFIG.FS_BURST_AUTO : configure burst avg enable and trigger mode sample rates via channel sampling frequency config.

Overall, the highlight of this device is the monitor capability, leveraged by the autonomous trigger mode and exposed as IIO Event.

Linux driver doc:

HDL: analogdevicesinc/hdl#1504
Datasheet: www.analog.com/ad4052
Tested on Coraz7s

PR Type

  • Bug fix (a change that fixes an issue)
  • New feature (a change that adds new functionality)
  • Breaking change (a change that affects other repos or cause CIs to fail)

PR Checklist

  • I have conducted a self-review of my own code changes
  • I have tested the changes on the relevant hardware
  • I have updated the documentation outside this repo accordingly (if there is the case)

@gastmaier
Copy link
Contributor Author

gastmaier commented Nov 4, 2024

Forced pushed to:

  • Add support to TIMER_CONFIG.FS_BURST_AUTO
  • Only write GP during probe.
  • Simplify IRQ Handler, leave to the user to clear the irq, because:
    • Entering config mode causes the irq to unset.
    • Re-entering monitor mode sets the irq back if still outside the threshold range, causing new handler calls.
    • "Ignoring next interrupt" would generate obnoxious logic.

Forced pushed (2) to:

  • Invert fs_burst_auto array entries, default all devices to 2MSPS (Yes, this value is -EINVAL for ad4056/ad4058, but is the datasheet reset value)

Forced pushed (3) to:

  • Clean-up unused enums.
  • Rename ad405x to ad4052 in the dts

@gastmaier gastmaier force-pushed the staging/ad4052 branch 3 times, most recently from 1f5b827 to 9611c42 Compare November 6, 2024 19:03
Copy link
Collaborator

@nunojsa nunojsa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here it goes first round of review...

I think this one can be upstreamed without the offload bits

gastmaier

This comment was marked as duplicate.

@gastmaier gastmaier force-pushed the staging/ad4052 branch 2 times, most recently from 4b81da9 to 494d89f Compare November 12, 2024 00:15
@gastmaier
Copy link
Contributor Author

gastmaier commented Nov 12, 2024

Change log v0 -> v1

Review changes:

  • Move functional modes from devicetree entry to different OVERSAMPLING_RATIO values, affecting RAW read and buffered.
  • Documentation YAML fixes, removal of functional mode.
  • Header on alphabetical order.
  • Use field_prep
  • Remove forward declaration, reorder methods instead.
  • Fix cache line aligment.
  • Use devm runtime enable, remove manual remove.
  • Use dev_err_probe
  • General Documentation/.yaml fixes
  • Make all regmap_bulk dma safe.
  • Remove/simplify switch cases where not needed.
  • Instead of using of_node, use spi->irq directly
  • Use regmap update bits.
  • Use fsleep
  • Use oversampling iio property (value 0 is invalid, 1 put on Sample Mode, > 1 Burst Averaging mode)

New:

  • Add regmap access tables

Design changes:

  • Under IIO Event thrshold enabled (device Monitor Mode), return device access busy for every other access, simplifying logic by not requiring exiting and re-entering mode and having an obscure "monitoring downtime" during access.
  • Use oversampling iio prop instead of devicetree entry to switch functional modes.

tristate "Analog Devices AD4052 Driver"
depends on SPI
depends on PWM
depends on GPIOLIB
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm also not sure if gpio is something you should depend on or just select it. I think the single shot reading could be something useful to have even more to make this driver more upstreamable without offload support (we can still some questions about it though).

tristate "Analog Devices AD4052 Driver"
depends on SPI
depends on PWM
depends on GPIOLIB
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also one not on the commit message. Style is iio: adc: .... Drop the drivers:

if (val == 0) {
st->mode = AD4052_SAMPLE_MODE;
} else {
st->mode = AD4052_BURST_AVERAGING_MODE;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would double check other examples of oversampling. To me this is a 1 or 0 thing. Either it's enabled it not. Your mode variable also just seems to have two states here so the way you're handling val raises some questions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The device supports from 2 to 4096 in powers of 2 samples for avg mode.
Decided to reserve 0 and 1 to disable the feature (return to sample mode)

@gastmaier
Copy link
Contributor Author

gastmaier commented Nov 17, 2024

Change log v1 -> v2

Review changes:

  • Include all peripheral properties
  • Drop cnv-gpio description
  • Updated dt-binding commit description
  • Replace d32 array by d16/d32 union (requires ignoring misleading checkpatch warning).
  • Remove MODULE_IMPORT_NS(IIO_AD4052);
  • Add error handling where missing
  • remove {} in single statement ifs, coherent style
  • Use multiple scan masks for changing precision due to oversampling
  • Move all if (st->mode == AD4052_MONITOR_MODE) inside the IIO mutex claim.
  • Drop switches where there is only one channel/event type
  • Remove unused AD4052_AVERAGING_MODE (would require a timed trigger) and AD4052_CONFIG_MODE (implicit mode outside any reading)
  • ad4052_set_avg_filter pass st directly.
  • Use different variables instead of the array for the chip_info

Changes:

  • Use GPIO interrupt instead of PS IRQ
  • All GPIOs are optional, does not require GPIO on KConfig. The user shall bring his own external trigger or short the CS and CNV, for example.
  • Move PWM sampling rate to IIO_ATTR
  • Move ext fs_burst_auto to channel sampling freq
  • Use Data Ready assertions for single shot readings, timeout after 1 second

Extra force push to resolve merge conflict

@gastmaier gastmaier requested a review from nunojsa November 25, 2024 13:20
@gastmaier gastmaier force-pushed the staging/ad4052 branch 2 times, most recently from eb23140 to 0506d4c Compare November 27, 2024 17:18
@gastmaier gastmaier requested a review from nunojsa February 26, 2025 08:22
spi_message_init_with_transfers(&st->msg, &st->xfer, 1);
ret = spi_optimize_message(st->spi, &st->msg);
if (ret)
return ret;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

__spi_unoptimize_message cannot be called on a message that is not currently optimized and spi_unoptimize_message only checks for defer_optimize_message, that just indicates the controller doesn't really optimize until the transfer is actually done.

Am I missing something here?

https://elixir.bootlin.com/linux/v6.13.4/source/drivers/spi/spi.c#L4344

AFAICT, it will just be called and then anything can happen... You should not make any assumption on how core code and even more importantly how a spi controller will handle this. The docs clearly stated that the calls should be balanced. Not doing so is clearly a driver bug IMO.

If I call devm_optimize_message, it will add the spi_unoptimize_message action to the list of managed resources over and over again, which is a no-no as explained in the last paragraph.

yes, since this function is also called from an userspace interface, indeed devm_action is also not the way to go...

@gastmaier
Copy link
Contributor Author

gastmaier commented Feb 28, 2025

V8

Applies changes from previous discussion.

  • Drop ".yaml" from commit title dt-bindings: iio: adc: Add adi,ad4052
  • Heap soft reset array pattern
  • Reorder ad4052_update_xfers and devm_iio_device_register to ensure no races.
  • Drop raw read optimize due to awkward un-balance (1).
  • Balance offload xfer optimize, as usual.
# V7..V8
git range-diff  7ff88f0cf1f902d62b757b6fef9032fbcfb4f0cc~..9d68079b812aca6eda93ce960843b3d96cfe8e87  7ff88f0cf1f902d62b757b6fef9032fbcfb4f0cc~..af2cdc23c1068cfcdbc0a413e1e4668b67fd449f
# driver only
git diff eeea804d53fa1cc9a77c5e05a541093d3e9e1f54..2d865d174b43e0c39a6008153394f1be4e478645

(1) The source of the unbalance was the raw read, because the message needed to be re-optimized on oversampling write to be ready for the raw read, or balance on the raw read, which makes no sense from the optimization point-of-view.
So I removed optimization for raw read and balanced the offload_xfer on the buffer ops.
Now without the raw xfer optimization, .remove was also removed.

Counter-intuitive behaviour: io_buffer_enabled(indio_dev)) does return true during buffer_preenable, so the requested scan type obtained is correct, even though the counterintuitive naming/sequence.

Another point in favor of dropping raw xfer optimization is that oversampling set optimization could fail, setting the xfer in the un-optimized state, and on remove it would indeed call un-optimized on a un-optimized message, which in my tests do cause panic.

@gastmaier gastmaier requested a review from nunojsa March 4, 2025 11:33
Copy link
Collaborator

@nunojsa nunojsa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some minor comment... Looks ready to go upstream

#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the above header looks suspicious? Leftover?

struct device *dev = &st->spi->dev;
int ret = 0;

ret = of_irq_get(st->spi->dev.of_node, 0);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, you have it in here... Please use device property APIs. fwnode_irq_get()

@gastmaier
Copy link
Contributor Author

gastmaier commented Mar 5, 2025

V9

  • replace of_node with fwnode_irq_get, dropping the include.
  • replaced iio_device_claim_direct_scoped with ad4052_iio_device_claim_direct because is more similar with the current upstream recommended, resulting in fewer touched lines
  • move iio_device_claim_direct_scoped, wait_event to an auxiliary method, explaning why it is needed.
  • add __maybe_unused to pm methods, since without the PM enabled, they are unused
V8..V9
# driver only
git diff 2d865d174b43e0c39a6008153394f1be4e478645..71e7eefdc99352e634527d5ad4d61d543319d9cb

@nunojsa
Copy link
Collaborator

nunojsa commented Mar 6, 2025

I'm not doing another round but saw this in the log which got my attention:

add __maybe_unused to pm methods, since without the PM enabled, they are unused

pm_ptr() should prevent that... Maybe that means you should instead use pm_sleep_ptr()? This macros were introduced exactly to avoid marking PM function with maybe_unused as the compiler/linker should be able to detect and remove "dead" code.

@gastmaier
Copy link
Contributor Author

gastmaier commented Mar 6, 2025

If CONF_PM is disabled the methods are sinked/discarted and the relation between the .pm and the method is never created

If CONFIG_PM or CONFIG_PM_SLEEP are enabled (respectively), these macros will resolve to their argument, otherwise to NULL.

https://lore.kernel.org/all/[email protected]/

with pm_sleep_ptr, if CONF_PM and CONF_PM_SLEEP are unset, the pointer is NULL and the warning is raised.
If I am overthinking and we just don't care about PM being disable, we sure can remove that.

@nunojsa
Copy link
Collaborator

nunojsa commented Mar 6, 2025

Can you test with RUNTIME_PM_OPS() instead of SET_RUNTIME_PM_OPS()? The reason I'm pushing a bit is because, as you saw, this pm_sleep() macros were indeed introduced to avoid those __maybe_unused.

BTW, I think pm_ptr() is indeed the right one to use (as you're using runtime PM)

@gastmaier
Copy link
Contributor Author

Yep, you are right, the modern way is RUNTIME_PM_OPS not SET_RUNTIME_PM_OPS .
Tested.
https://patchwork.kernel.org/project/linux-media/patch/[email protected]/

@gastmaier
Copy link
Contributor Author

gastmaier commented Mar 6, 2025

V10

  • replace SET_RUNTIME_PM_OPS with the RUNTIME_PM_OPS.
  • Fixup aux iio_device_claim
V9..V10
# driver only
git diff 71e7eefdc99352e634527d5ad4d61d543319d9cb..455d4985a811f8d0a7b1344238bd1b208a092e64

@gastmaier
Copy link
Contributor Author

gastmaier commented Mar 9, 2025

Up-streaming at https://lore.kernel.org/all/[email protected]/

Below is a small bash script to convert from 'current' upstream and adi-linux

driver=drivers/iio/adc/ad4052.c
doc=Documentation/iio/ad4052.rst
bin=Documentation/devicetree/bindings/iio/adc/adi,ad4052.yaml
abi=Documentation/ABI/testing/sysfs-bus-iio
adi=.
up=../../linux-upstream

up2adi () {
        cp $up/$driver $adi/$driver
        cp $up/$doc $adi/$doc
        cp $up/$bin $adi/$bin
        cp $up/$abi $adi/$abi
        sed -i -e 's/iio_device_release_direct(/iio_device_release_direct_mode(/g' \
               -e 's/\!iio_device_claim_direct(/iio_device_claim_direct_mode(/g' \
               -e 's/bool state/int state/' \
               -e 's/("IIO_DMAENGINE_BUFFER")/(IIO_DMAENGINE_BUFFER)/' $adi/$driver
}

adi2up () {
        cp $adi/$driver $up/$driver
        cp $adi/$doc $up/$doc
        cp $adi/$bin $up/$bin
        #cp $adi/$abi $up/$abi
        sed -i -e 's/iio_device_release_direct_mode(/iio_device_release_direct(/g' \
               -e 's/iio_device_claim_direct_mode(/\!iio_device_claim_direct(/g' \
               -e 's/int state/bool state/' \
               -e 's/(IIO_DMAENGINE_BUFFER)/("IIO_DMAENGINE_BUFFER")/' $up/$driver
}

"$@"

@gastmaier gastmaier force-pushed the staging/ad4052 branch 3 times, most recently from e5d6aa3 to 60210a9 Compare March 14, 2025 17:17
The AD4052/AD4058/AD4050/AD4056 are versatile, 16-bit/12-bit,
successive approximation register (SAR) analog-to-digital converter (ADC).

The series starts with marking iio_dev as const in iio_buffer_enabled,
to not discard the qualifier when calling from get_current_can_type.
This is required since the size of storage bytes varies if the offload
buffer is used or not.

The scan_type also depends if the oversampling feature is enabled, since
the 16-bit device increases the SPI word size from 16-bit to 24-bit.
Also due to this, the spi message optimization is balanced on the buffer ops,
instead of once per probe.
SPI messages related to exiting the ADC mode, and reading raw values are
never optimized.

The device has autonomous monitoring capabilities, that are exposed as IIO
events. Since register access requires leaving the monitoring
state and returning, device access is blocked until the IIO event is disabled.
An auxiliary method ad4052_iio_device_claim_direct manages the IIO claim
direct as well as the required wait_event boolean.
The device has an internal sampling rate for the autonomous modes,
exposed as the sample_rate attribute.

The device contains two required outputs:

* gp0: Threshold event interrupt on the rising edge.
* gp1: ADC conversion ready signal on the falling edge.
       The user should either invert the signal or set the IRQ as falling edge.

And one optional input:

* cnv: Triggers a conversion, can be replaced by shortening the CNV and
  SPI CS trace.

The devices utilizes PM to enter the low power mode.

The driver can be used with SPI controllers with and without offload support.

A FPGA design is available:
https://analogdevicesinc.github.io/hdl/projects/ad4052_ardz/

The devices datasheet:
https://www.analog.com/media/en/technical-documentation/data-sheets/ad4050-ad4056.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad4052-ad4058.pdf

The unique monitoring capabilities and multiple GPIOs where the decision factor
to have a standalone driver for this device family.

Non-implemented features:

* Status word: First byte of the SPI transfer aligned to the register
  address.
* Averaging mode: Similar to burst averaging mode used in the
  oversampling, but requiring a sequence of CNV triggers for each
  conversion.
* Monitor mode: Similar to trigger mode used in the monitoring mode, but
  doesn't exit to configuration mode on event, being awkward to expose
  to user space.
An auxiliary method ad4052_iio_device_claim_direct manages the IIO claim
direct as well as the required wait_event boolean.
The device has an internal sampling rate for the autonomous modes,
exposed as the sample_rate attribute.

The device contains two required outputs:

* gp0: Threshold event interrupt on the rising edge.
* gp1: ADC conversion ready signal on the falling edge.
       The user should either invert the signal or set the IRQ as falling edge.

And one optional input:

* cnv: Triggers a conversion, can be replaced by shortening the CNV and
  SPI CS trace.

The devices utilizes PM to enter the low power mode.

The driver can be used with SPI controllers with and without offload support.

A FPGA design is available:
https://analogdevicesinc.github.io/hdl/projects/ad4052_ardz/

The devices datasheet:
https://www.analog.com/media/en/technical-documentation/data-sheets/ad4050-ad4056.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad4052-ad4058.pdf

The unique monitoring capabilities and multiple GPIOs where the decision factor
to have a standalone driver for this device family.

Non-implemented features:

* Status word: First byte of the SPI transfer aligned to the register
  address.
* Averaging mode: Similar to burst averaging mode used in the
  oversampling, but requiring a sequence of CNV triggers for each
  conversion.
* Monitor mode: Similar to trigger mode used in the monitoring mode, but
  doesn't exit to configuration mode on event, being awkward to expose
  to user space.

Signed-off-by: Jorge Marques <[email protected]>
Some devices have an internal clock used by the events to space the conversions.
Examples of devices with this internal clock are: max1363 and ad4052.
The max1363 introduced the option in
168c9d9 (3.10).

Signed-off-by: Jorge Marques <[email protected]>
Some devices have an internal clock used to space the conversion trigger
for the oversampling filter.
Examples of devices with this internal clock are: ad4052 and ad7606c.

Signed-off-by: Jorge Marques <[email protected]>
The iio_dev struct is never modified inside the method, mark it as
const.
This allows to be called from get_current_scan_type, and is useful
when the scan_type depends on the buffer state.

Signed-off-by: Jorge Marques <[email protected]>
Add dt-bindings for AD4052 family, devices AD4050/AD4052/AD4056/AD4058,
low-power with monitor capabilities SAR ADCs.
Each variant of the family differs in speed and resolution, resulting
in different scan types and spi word sizes, that are matched by the
compatible with the chip_info.
The device conatins one input (cnv) and two outputs (gp0, gp1).

Signed-off-by: Jorge Marques <[email protected]>
The AD4052 CNV pin is driven by a GPIO for single shot readings and
by a PWM for buffer readings.
The functional-mode entry allows to set Sample Mode (0) or Burst
Averaging Mode (1).
During runtime, it is possible to enter Trigger Mode through IIO Events.

Signed-off-by: Jorge Marques <[email protected]>
This adds a new page to document how to use the ad4052 ADC driver.

Signed-off-by: Jorge Marques <[email protected]>
The AD4052/AD4058/AD4050/AD4056 are versatile, 16-bit/12-bit,
successive approximation register (SAR) analog-to-digital converter (ADC)
that enables low-power, high-density data acquisition solutions without
sacrificing precision.
This ADC offers a unique balance of performance and power efficiency,
plus innovative features for seamlessly switching between high-resolution
and low-power modes tailored to the immediate needs of the system.
The AD4052/AD4058/AD4050/AD4056 are ideal for battery-powered,
compact data acquisition and edge sensing applications.

Signed-off-by: Jorge Marques <[email protected]>
Add entry for the AD4052 ADC family driver.

Signed-off-by: Jorge Marques <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants