Skip to content
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

ad5791 offload #2616

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

ad5791 offload #2616

wants to merge 10 commits into from

Conversation

ahaslam2
Copy link
Collaborator

spi offload support for ad57xx dac

This adds offload support for the ad57xx dac to be able to send samples up to 1MSPS.

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)

@ahaslam2 ahaslam2 force-pushed the axelh/ad5791_offload branch 5 times, most recently from 802e9b1 to 3976d47 Compare October 15, 2024 15:55
@ahaslam2 ahaslam2 changed the title Axelh/ad5791 offload ad5791 offload Oct 15, 2024
@ahaslam2 ahaslam2 force-pushed the axelh/ad5791_offload branch 2 times, most recently from 03d271e to 65e5a18 Compare October 16, 2024 10:14
@ahaslam2 ahaslam2 marked this pull request as ready for review October 16, 2024 10:16
@ahaslam2 ahaslam2 requested a review from dlech October 16, 2024 10:17
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 my review. Note that I'm expecting some stuff to be sent upstream (like gpio reset)... Also it seems this driver could use a proper refactor if you are willing to do that 😄

st->gpio_ldac = devm_gpiod_get_optional(&spi->dev, "ldac",
GPIOD_OUT_LOW);
if (IS_ERR(st->gpio_ldac))
return PTR_ERR(st->gpio_ldac);
Copy link
Collaborator

Choose a reason for hiding this comment

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

What's the intent of the above two gpio's? I would say, if we're not using them now, don't bother in adding them. Still ok to leave them in the bindings though.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

they are actually on the eval board and if i dont drive them they are set as input. we need to make sure they are on the right state: CLR high and LDAC low (datasheet table9 p21) for the output to be set according to the register value when we write on spi xfer. I think we need to keep them.

st->gpio_reset = devm_gpiod_get_optional(&spi->dev, "reset",
GPIOD_OUT_LOW);
if (IS_ERR(st->gpio_reset))
return PTR_ERR(st->gpio_reset);
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 makes sense to have already. But do a reset in case we have it. Typical pattern is:

gpio_reset = devm_gpiod_get_optional(&spi->dev, "reset",  GPIOD_OUT_HIGH);
if (IS_ERR(gpio_reset))
    return PTR_ERR(gpio_reset);

if (gpio_reset) {
    // typically there's some time we need to wait for the reset to happen
    fseep(x);
    // get it out of reset
    gpiod_set_value_cansleep(gpio_reset, 0);
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ok

drivers/iio/dac/ad5791.c Show resolved Hide resolved
st->pwr_down = pwr_down;

ret = ad5791_spi_write(st, AD5791_ADDR_CTRL, st->ctrl);
ret = __ad5791_dac_powerdown(indio_dev, pwr_down);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Unrelated change. Not disagreeing with it but should be in a separate patch. If you want to take it one step further, it even seems that some proper locking is missing... Moreover, we should set st->pwr_down after we actually do ad5791_spi_write(st, AD5791_ADDR_CTRL, st->ctrl)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

i will drop this change and only check the power status in pre-enable. as you suggested below.


if (spi_engine_ex_offload_supported(spi)) {
indio_dev->channels =
&ad5791_channels[spi_get_device_id(spi)->driver_data];
Copy link
Collaborator

@nunojsa nunojsa Oct 16, 2024

Choose a reason for hiding this comment

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

The above could also be an opportunity for a nice cleanup. Adding a chip_info structure and actual OF support. Thus getting rid of the id enum

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ok

struct ad5791_state *st = iio_priv(indio_dev);
int ret;

ret = __ad5791_dac_powerdown(indio_dev, false);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I see now it's related but see below...

pwm_disable(st->cnv_trigger);
spi_bus_unlock(st->spi->master);

return __ad5791_dac_powerdown(indio_dev, true);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Any reason to assume we want to powerdown the DAC? Since it's a user control I would rather check it and return error or something in ad5791_buffer_preenable() in case it's in a powerdown state. This would also mean that we can't power it down while in buffer mode. Thus, using iio_device_claim_direct_mode()

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ok.

int ret;

if (!st->cnv_trigger)
return -ENODEV;
Copy link
Collaborator

Choose a reason for hiding this comment

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

AFAICT, this is only available for offload support and cnv_trigger is mandatory (otherwise we fail to probe). So, seems like a redundant check.

drivers/iio/dac/ad5791.c Show resolved Hide resolved
Copy link
Collaborator

@dlech dlech left a comment

Choose a reason for hiding this comment

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

A couple more suggestions for upstream "cleanup":

  • Use devm_regulator_get_enable_read_voltage() to simplify the regulator code.
  • Drop the driver remove callback by using more devm_.

@@ -31,6 +31,17 @@ properties:
gain of two configuration.
type: boolean

reset-gpios:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Jonathan also likes to have all of the power supplies in the bindings, so we can add vcc-suppy, vrefp-supply, vrefn-supply and iovcc-supply when we submit this upstream.

arch/arm/boot/dts/socfpga_cyclone5_de10_nano.dtsi Outdated Show resolved Hide resolved
arch/arm/boot/dts/socfpga_cyclone5_de10_nano_ad57xx.dts Outdated Show resolved Hide resolved
Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml Outdated Show resolved Hide resolved
drivers/iio/dac/ad5791.c Outdated Show resolved Hide resolved
drivers/iio/dac/ad5791.c Outdated Show resolved Hide resolved
@ahaslam2
Copy link
Collaborator Author

changes in V2:

implement new suggested driver simplifications:

  • Include chip_info in device match tables / remove chip id enum
  • use devm_regulator_get_enable_read_voltage on probe.

Fixes related to comments:

  • drop pwm DT binding
  • use devm_spi_optimize_message
  • dont power_up/down on enable
  • remove redundant trigger check
  • us hw pin reset if available
  • factor out offload setup from probe.
  • rebase after de10nano DT changes from uwe.

arch/arm/boot/dts/socfpga_cyclone5_de10_nano_ad57xx.dts Outdated Show resolved Hide resolved
drivers/iio/dac/ad5791.c Outdated Show resolved Hide resolved
drivers/iio/dac/ad5791.c Outdated Show resolved Hide resolved
drivers/iio/dac/ad5791.c Outdated Show resolved Hide resolved
drivers/iio/dac/ad5791.c Show resolved Hide resolved
@@ -430,30 +412,9 @@ static int ad5791_probe(struct spi_device *spi)
indio_dev->name = st->chip_info->name;
ret = iio_device_register(indio_dev);
if (ret)
goto error_disable_reg_neg;
return dev_err_probe(&spi->dev, ret, "unable to register iio device\n");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Most drivers will just return devm_iio_device_register() directly, so don't usually have the dev_err_probe() here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ok

@ahaslam2 ahaslam2 force-pushed the axelh/ad5791_offload branch 2 times, most recently from 0c0d193 to 9c53b59 Compare October 22, 2024 13:47
@ahaslam2
Copy link
Collaborator Author

changes in V3:

  • add patch to remove altr,gpio-bank-width in dt nodes
  • remove adi,channels node
  • fix macro style.
  • use fsleep
  • remove spi_set_drvdata
  • use devm_iio_device_register and delete remove callback.

drivers/iio/dac/ad5791.c Outdated Show resolved Hide resolved
Depending on board layout, the ad57xx may need control of reset, clear,
and ldac pins by the host driver. Add optional bindings for these gpios.

Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
Include a chip info struct in device SPI and device OF match tables to
provide channel definitions for each particular ADC model and eliminate
device enum.

Suggested-by: Nuno Sa <nuno.sa@analog.com>
Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
The ad7591 has reset, clr and ldac gpios. For the DAC to output data
writen to the data register the state of these gpios has to be:
 	RESET=1, CLR=1, LDAC=0

Add these gpios to the driver making them optional in case they
are fixed on the pcb.

Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
Simplify probe by using of the devm_regulator_get_enable_read_voltage.

Suggested-by: David Lechner <dlechner@baylibre.com>
Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
Use devm_iio_device_register to automatically free resources.

Suggested-by: David Lechner <dlechner@baylibre.com>
Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
This property is not defined on the binidngs, and is not used by the
driver. Remove it

Suggested-by: David Lechner <dlechner@baylibre.com>
Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
This adds the bi-directional gpio block to the d10 nano

Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
Add devicetree for ad57xx on de10nano.

Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
To allow offload to stream a "tx" type of xfer we need the write flag
set but no messages on the SDO memory of the offload engine. but the
current code relies on the tx_buf pointer for both of these operations,
so there is no way to separate the two.

The offload patches currently on development for upstream add flags on
core spi structures to flag an offload xfer as a streaming xfer.

While those patches get review and are ready to backport to the adi
tree, Workaround this limitation by checking if the tx_buf address is
-1 to flag it as "streaming type".

Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
Add spi offload support to stream tx buffers using dma.
This allows loading samples to the  dac with a rate of 1 MSPS.

Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
@ahaslam2
Copy link
Collaborator Author

Changes V4

  • remove ref_clk from dts
  • ldac gpio is active low
  • use spi->dev instead of indio_dev->dev.parent
  • more links in dts.

Copy link
Collaborator

@dlech dlech left a comment

Choose a reason for hiding this comment

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

LGTM. I think it would be best to upstream the first 5 patches first before merging this in case there are additional changes there. And I still think it would be a good idea to also add the power supplies to the DT bindings since we are touching this anyway.

adc_trigger: pwm@0x00050000 {
compatible = "adi,axi-pwmgen-2.00.a";
reg = <0x00050000 0x1000>;
#pwm-cells = <2>;
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ok.


dmas = <&tx_dma 0>;
dma-names = "tx";
pwms = <&adc_trigger 0 0>;
Copy link
Contributor

Choose a reason for hiding this comment

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

How unusual to have the default period 0. I'd rather expect to see a period that matches the max freq for that chip here (or something bigger).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ok. just for the record, i could not clearly make out a max frequency clearly mentioned on the datasheet.
only the spi speed of 35Mbps is mentioned. if we calculate 24 bits, i think a sample rate of 1Mbps is "reasonable"

Comment on lines +250 to +270
static int ad5791_get_sampling_freq(struct ad5791_state *st)
{
return DIV_ROUND_CLOSEST_ULL(NSEC_PER_SEC,
pwm_get_period(st->cnv_trigger));
}

static int __ad5791_set_sampling_freq(struct ad5791_state *st, int freq)
{
struct pwm_state cnv_state;
u32 rem;

pwm_init_state(st->cnv_trigger, &cnv_state);
cnv_state.period = div_u64_rem((u64)DIV_ROUND_UP(st->ref_clk_rate, freq) * NSEC_PER_SEC,
st->ref_clk_rate, &rem);
if (rem)
cnv_state.period += 1;

cnv_state.duty_cycle = DIV_ROUND_UP(NSEC_PER_SEC, st->ref_clk_rate);

return pwm_apply_state(st->cnv_trigger, &cnv_state);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

It's strange to use up-rounding when calculating the period from the frequency, but round-closest for the other direction.

The calculation freq -> period isn't very intuitive, a comment would be nice to explain the details. (I hope you didn't copy that formula from a driver where I introduced that without a comment :-))

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ok. i copied were you had the comment. i just did not copy the comment itself. setting pwm in the driver should go away when the offload stuff is backpacked to mainline, thats why i did not bother. but ill add it.

return PTR_ERR(st->cnv_trigger);

ret = devm_add_action_or_reset(&spi->dev, ad5791_pwm_diasble,
st->cnv_trigger);
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo: s/diasble/disable/

Registering that devm action before enabling the PWM is wrong.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ok.

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.

4 participants