]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
iio: dac: ad3552r-hs: add ad3541/2r support
authorAngelo Dureghello <adureghello@baylibre.com>
Tue, 14 Jan 2025 15:30:17 +0000 (16:30 +0100)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Sat, 8 Feb 2025 15:10:15 +0000 (15:10 +0000)
A new FPGA HDL has been developed from ADI to support ad354xr
devices.

Add support for ad3541r and ad3542r with following additions:

- use common device_info structures for hs and non hs drivers,
- DMA buffering, use DSPI mode for ad354xr and QSPI for ad355xr,
- change sample rate to respect number of lanes.

Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
Link: https://patch.msgid.link/20250114-wip-bl-ad3552r-axi-v0-iio-testing-carlos-v4-8-979402e33545@baylibre.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
drivers/iio/dac/ad3552r-common.c
drivers/iio/dac/ad3552r-hs.c
drivers/iio/dac/ad3552r.h

index ded90bf57baf00863b4732ecf75f597e4eede379..b8807e54fa057fe02afd9734ad67a4eb0a498e3a 100644 (file)
@@ -42,6 +42,7 @@ const struct ad3552r_model_data ad3541r_model_data = {
        .ranges_table = ad3542r_ch_ranges,
        .num_ranges = ARRAY_SIZE(ad3542r_ch_ranges),
        .requires_output_range = true,
+       .num_spi_data_lanes = 2,
 };
 EXPORT_SYMBOL_NS_GPL(ad3541r_model_data, "IIO_AD3552R");
 
@@ -52,6 +53,7 @@ const struct ad3552r_model_data ad3542r_model_data = {
        .ranges_table = ad3542r_ch_ranges,
        .num_ranges = ARRAY_SIZE(ad3542r_ch_ranges),
        .requires_output_range = true,
+       .num_spi_data_lanes = 2,
 };
 EXPORT_SYMBOL_NS_GPL(ad3542r_model_data, "IIO_AD3552R");
 
@@ -62,6 +64,7 @@ const struct ad3552r_model_data ad3551r_model_data = {
        .ranges_table = ad3552r_ch_ranges,
        .num_ranges = ARRAY_SIZE(ad3552r_ch_ranges),
        .requires_output_range = false,
+       .num_spi_data_lanes = 4,
 };
 EXPORT_SYMBOL_NS_GPL(ad3551r_model_data, "IIO_AD3552R");
 
@@ -72,6 +75,7 @@ const struct ad3552r_model_data ad3552r_model_data = {
        .ranges_table = ad3552r_ch_ranges,
        .num_ranges = ARRAY_SIZE(ad3552r_ch_ranges),
        .requires_output_range = false,
+       .num_spi_data_lanes = 4,
 };
 EXPORT_SYMBOL_NS_GPL(ad3552r_model_data, "IIO_AD3552R");
 
index 98711f742c701e62ef4f3f16d142377e715dbde8..e8e309046f11cd83b17af31d973a770d9151912b 100644 (file)
 #include "ad3552r.h"
 #include "ad3552r-hs.h"
 
+/*
+ * Important notes for register map access:
+ * ========================================
+ *
+ * Register address space is divided in 2 regions, primary (config) and
+ * secondary (DAC). Primary region can only be accessed in simple SPI mode,
+ * with exception for ad355x models where setting QSPI pin high allows QSPI
+ * access to both the regions.
+ *
+ * Due to the fact that ad3541/2r do not implement QSPI, for proper device
+ * detection, HDL keeps "QSPI" pin level low at boot (see ad3552r manual, rev B
+ * table 7, pin 31, digital input). For this reason, actually the working mode
+ * between SPI, DSPI and QSPI must be set via software, configuring the target
+ * DAC appropriately, together with the backend API to configure the bus mode
+ * accordingly.
+ *
+ * Also, important to note that none of the three modes allow to read in DDR.
+ *
+ * In non-buffering operations, mode is set to simple SPI SDR for all primary
+ * and secondary region r/w accesses, to avoid to switch the mode each time DAC
+ * register is accessed (raw accesses, r/w), and to be able to dump registers
+ * content (possible as non DDR only).
+ * In buffering mode, driver sets best possible mode, D/QSPI and DDR.
+ */
+
 struct ad3552r_hs_state {
        const struct ad3552r_model_data *model_data;
        struct gpio_desc *reset_gpio;
@@ -27,8 +52,19 @@ struct ad3552r_hs_state {
        bool single_channel;
        struct ad3552r_ch_data ch_data[AD3552R_MAX_CH];
        struct ad3552r_hs_platform_data *data;
+       /* INTERFACE_CONFIG_D register cache, in DDR we cannot read values. */
+       u32 config_d;
 };
 
+static int ad3552r_hs_reg_read(struct ad3552r_hs_state *st, u32 reg, u32 *val,
+                              size_t xfer_size)
+{
+       /* No chip in the family supports DDR read. Informing of this. */
+       WARN_ON_ONCE(st->config_d & AD3552R_MASK_SPI_CONFIG_DDR);
+
+       return st->data->bus_reg_read(st->back, reg, val, xfer_size);
+}
+
 static int ad3552r_qspi_update_reg_bits(struct ad3552r_hs_state *st,
                                        u32 reg, u32 mask, u32 val,
                                        size_t xfer_size)
@@ -36,7 +72,7 @@ static int ad3552r_qspi_update_reg_bits(struct ad3552r_hs_state *st,
        u32 rval;
        int ret;
 
-       ret = st->data->bus_reg_read(st->back, reg, &rval, xfer_size);
+       ret = ad3552r_hs_reg_read(st, reg, &rval, xfer_size);
        if (ret)
                return ret;
 
@@ -56,16 +92,20 @@ static int ad3552r_hs_read_raw(struct iio_dev *indio_dev,
        switch (mask) {
        case IIO_CHAN_INFO_SAMP_FREQ:
                /*
-                * Using 4 lanes (QSPI), then using 2 as DDR mode is
-                * considered always on (considering buffering mode always).
+                * Using a "num_spi_data_lanes" variable since ad3541/2 have
+                * only DSPI interface, while ad355x is QSPI. Then using 2 as
+                * DDR mode is considered always on (considering buffering
+                * mode always).
                 */
                *val = DIV_ROUND_CLOSEST(st->data->bus_sample_data_clock_hz *
-                                        4 * 2, chan->scan_type.realbits);
+                                        st->model_data->num_spi_data_lanes * 2,
+                                        chan->scan_type.realbits);
 
                return IIO_VAL_INT;
 
        case IIO_CHAN_INFO_RAW:
-               ret = st->data->bus_reg_read(st->back,
+               /* For RAW accesses, stay always in simple-spi. */
+               ret = ad3552r_hs_reg_read(st,
                                AD3552R_REG_ADDR_CH_DAC_16B(chan->channel),
                                val, 2);
                if (ret)
@@ -93,6 +133,7 @@ static int ad3552r_hs_write_raw(struct iio_dev *indio_dev,
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
+               /* For RAW accesses, stay always in simple-spi. */
                iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
                        return st->data->bus_reg_write(st->back,
                                    AD3552R_REG_ADDR_CH_DAC_16B(chan->channel),
@@ -104,6 +145,42 @@ static int ad3552r_hs_write_raw(struct iio_dev *indio_dev,
        }
 }
 
+static int ad3552r_hs_set_bus_io_mode_hs(struct ad3552r_hs_state *st)
+{
+       int bus_mode;
+
+       if (st->model_data->num_spi_data_lanes == 4)
+               bus_mode = AD3552R_IO_MODE_QSPI;
+       else
+               bus_mode = AD3552R_IO_MODE_DSPI;
+
+       return st->data->bus_set_io_mode(st->back, bus_mode);
+}
+
+static int ad3552r_hs_set_target_io_mode_hs(struct ad3552r_hs_state *st)
+{
+       u32 mode_target;
+
+       /*
+        * Best access for secondary reg area, QSPI where possible,
+        * else as DSPI.
+        */
+       if (st->model_data->num_spi_data_lanes == 4)
+               mode_target = AD3552R_QUAD_SPI;
+       else
+               mode_target = AD3552R_DUAL_SPI;
+
+       /*
+        * Better to not use update here, since generally it is already
+        * set as DDR mode, and it's not possible to read in DDR mode.
+        */
+       return st->data->bus_reg_write(st->back,
+                               AD3552R_REG_ADDR_TRANSFER_REGISTER,
+                               FIELD_PREP(AD3552R_MASK_MULTI_IO_MODE,
+                                          mode_target) |
+                               AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE, 1);
+}
+
 static int ad3552r_hs_buffer_postenable(struct iio_dev *indio_dev)
 {
        struct ad3552r_hs_state *st = iio_priv(indio_dev);
@@ -132,10 +209,10 @@ static int ad3552r_hs_buffer_postenable(struct iio_dev *indio_dev)
                return -EINVAL;
        }
 
-       ret = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_STREAM_MODE,
-                                     loop_len, 1);
-       if (ret)
-               return ret;
+       /*
+        * With ad3541/2r support, QSPI pin is held low at reset from HDL,
+        * streaming start sequence must respect strictly the order below.
+        */
 
        /* Primary region access, set streaming mode (now in SPI + SDR). */
        ret = ad3552r_qspi_update_reg_bits(st,
@@ -144,47 +221,98 @@ static int ad3552r_hs_buffer_postenable(struct iio_dev *indio_dev)
        if (ret)
                return ret;
 
-       /* Inform DAC chip to switch into DDR mode */
+       /*
+        * Set target loop len, keeping the value: streaming writes at address
+        * 0x2c or 0x2a, in descending loop (2 or 4 bytes), keeping loop len
+        * value so that it's not cleared hereafter when _CS is deasserted.
+        */
        ret = ad3552r_qspi_update_reg_bits(st,
-                                          AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
-                                          AD3552R_MASK_SPI_CONFIG_DDR,
-                                          AD3552R_MASK_SPI_CONFIG_DDR, 1);
+               AD3552R_REG_ADDR_TRANSFER_REGISTER,
+               AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE,
+               AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE, 1);
        if (ret)
-               goto exit_err_ddr;
+               goto exit_err_streaming;
+
+       ret = st->data->bus_reg_write(st->back,
+                                     AD3552R_REG_ADDR_STREAM_MODE,
+                                     loop_len, 1);
+       if (ret)
+               goto exit_err_streaming;
+
+       st->config_d |= AD3552R_MASK_SPI_CONFIG_DDR;
+       ret = st->data->bus_reg_write(st->back,
+                                     AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
+                                     st->config_d, 1);
+       if (ret)
+               goto exit_err_streaming;
 
-       /* Inform DAC IP to go for DDR mode from now on */
        ret = iio_backend_ddr_enable(st->back);
-       if (ret) {
-               dev_err(st->dev, "could not set DDR mode, not streaming");
-               goto exit_err;
-       }
+       if (ret)
+               goto exit_err_ddr_mode_target;
 
+       /*
+        * From here onward mode is DDR, so reading any register is not possible
+        * anymore, including calling "ad3552r_qspi_update_reg_bits" function.
+        */
+
+       /* Set target to best high speed mode (D or QSPI). */
+       ret = ad3552r_hs_set_target_io_mode_hs(st);
+       if (ret)
+               goto exit_err_ddr_mode;
+
+       /* Set bus to best high speed mode (D or QSPI). */
+       ret = ad3552r_hs_set_bus_io_mode_hs(st);
+       if (ret)
+               goto exit_err_bus_mode_target;
+
+       /*
+        * Backend setup must be done now only, or related register values will
+        * be disrupted by previous bus accesses.
+        */
        ret = iio_backend_data_transfer_addr(st->back, val);
        if (ret)
-               goto exit_err;
+               goto exit_err_bus_mode_target;
 
        ret = iio_backend_data_format_set(st->back, 0, &fmt);
        if (ret)
-               goto exit_err;
+               goto exit_err_bus_mode_target;
 
        ret = iio_backend_data_stream_enable(st->back);
        if (ret)
-               goto exit_err;
+               goto exit_err_bus_mode_target;
 
        return 0;
 
-exit_err:
-       ad3552r_qspi_update_reg_bits(st,
-                                    AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
-                                    AD3552R_MASK_SPI_CONFIG_DDR,
-                                    0, 1);
+exit_err_bus_mode_target:
+       /* Back to simple SPI, not using update to avoid read. */
+       st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_TRANSFER_REGISTER,
+                               FIELD_PREP(AD3552R_MASK_MULTI_IO_MODE,
+                                          AD3552R_SPI) |
+                               AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE, 1);
 
+       /*
+        * Back bus to simple SPI, this must be executed together with above
+        * target mode unwind, and can be done only after it.
+        */
+       st->data->bus_set_io_mode(st->back, AD3552R_IO_MODE_SPI);
+
+exit_err_ddr_mode:
        iio_backend_ddr_disable(st->back);
 
-exit_err_ddr:
-       ad3552r_qspi_update_reg_bits(st, AD3552R_REG_ADDR_INTERFACE_CONFIG_B,
-                                    AD3552R_MASK_SINGLE_INST,
-                                    AD3552R_MASK_SINGLE_INST, 1);
+exit_err_ddr_mode_target:
+       /*
+        * Back to SDR. In DDR we cannot read, whatever the mode is, so not
+        * using update.
+        */
+       st->config_d &= ~AD3552R_MASK_SPI_CONFIG_DDR;
+       st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
+                               st->config_d, 1);
+
+exit_err_streaming:
+       /* Back to single instruction mode, disabling loop. */
+       st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_INTERFACE_CONFIG_B,
+                               AD3552R_MASK_SINGLE_INST |
+                               AD3552R_MASK_SHORT_INSTRUCTION, 1);
 
        return ret;
 }
@@ -198,11 +326,22 @@ static int ad3552r_hs_buffer_predisable(struct iio_dev *indio_dev)
        if (ret)
                return ret;
 
-       /* Inform DAC to set in SDR mode */
-       ret = ad3552r_qspi_update_reg_bits(st,
-                                          AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
-                                          AD3552R_MASK_SPI_CONFIG_DDR,
-                                          0, 1);
+       /*
+        * Set us to simple SPI, even if still in ddr, so to be able to write
+        * in primary region.
+        */
+       ret = st->data->bus_set_io_mode(st->back, AD3552R_IO_MODE_SPI);
+       if (ret)
+               return ret;
+
+       /*
+        * Back to SDR (in DDR we cannot read, whatever the mode is, so not
+        * using update).
+        */
+       st->config_d &= ~AD3552R_MASK_SPI_CONFIG_DDR;
+       ret = st->data->bus_reg_write(st->back,
+                                     AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
+                                     st->config_d, 1);
        if (ret)
                return ret;
 
@@ -210,6 +349,17 @@ static int ad3552r_hs_buffer_predisable(struct iio_dev *indio_dev)
        if (ret)
                return ret;
 
+       /*
+        * Back to simple SPI for secondary region too now, so to be able to
+        * dump/read registers there too if needed.
+        */
+       ret = ad3552r_qspi_update_reg_bits(st,
+                                          AD3552R_REG_ADDR_TRANSFER_REGISTER,
+                                          AD3552R_MASK_MULTI_IO_MODE,
+                                          AD3552R_SPI, 1);
+       if (ret)
+               return ret;
+
        /* Back to single instruction mode, disabling loop. */
        ret = ad3552r_qspi_update_reg_bits(st,
                                           AD3552R_REG_ADDR_INTERFACE_CONFIG_B,
@@ -324,6 +474,7 @@ static int ad3552r_hs_setup(struct ad3552r_hs_state *st)
        if (ret)
                return ret;
 
+       /* HDL starts with DDR enabled, disabling it. */
        ret = iio_backend_ddr_disable(st->back);
        if (ret)
                return ret;
@@ -339,15 +490,23 @@ static int ad3552r_hs_setup(struct ad3552r_hs_state *st)
        if (ret)
                return ret;
 
-       ret = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_PRODUCT_ID_L,
-                                    &val, 1);
+       /*
+        * Caching config_d, needed to restore it after streaming,
+        * and also, to detect possible DDR read, that's not allowed.
+        */
+       ret = st->data->bus_reg_read(st->back,
+                                    AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
+                                    &st->config_d, 1);
+       if (ret)
+               return ret;
+
+       ret = ad3552r_hs_reg_read(st, AD3552R_REG_ADDR_PRODUCT_ID_L, &val, 1);
        if (ret)
                return ret;
 
        id = val;
 
-       ret = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_PRODUCT_ID_H,
-                                    &val, 1);
+       ret = ad3552r_hs_reg_read(st, AD3552R_REG_ADDR_PRODUCT_ID_H, &val, 1);
        if (ret)
                return ret;
 
@@ -357,6 +516,8 @@ static int ad3552r_hs_setup(struct ad3552r_hs_state *st)
                         "chip ID mismatch, detected 0x%x but expected 0x%x\n",
                         id, st->model_data->chip_id);
 
+       dev_dbg(st->dev, "chip id %s detected", st->model_data->model_name);
+
        /* Clear reset error flag, see ad3552r manual, rev B table 38. */
        ret = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_ERR_STATUS,
                                      AD3552R_MASK_RESET_STATUS, 1);
@@ -369,14 +530,6 @@ static int ad3552r_hs_setup(struct ad3552r_hs_state *st)
        if (ret)
                return ret;
 
-       ret = st->data->bus_reg_write(st->back,
-                               AD3552R_REG_ADDR_TRANSFER_REGISTER,
-                               FIELD_PREP(AD3552R_MASK_MULTI_IO_MODE,
-                                          AD3552R_QUAD_SPI) |
-                               AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE, 1);
-       if (ret)
-               return ret;
-
        ret = iio_backend_data_source_set(st->back, 0, IIO_BACKEND_EXTERNAL);
        if (ret)
                return ret;
@@ -400,10 +553,12 @@ static int ad3552r_hs_setup(struct ad3552r_hs_state *st)
 
        ret = ad3552r_get_drive_strength(st->dev, &val);
        if (!ret) {
-               ret = ad3552r_qspi_update_reg_bits(st,
+               st->config_d |=
+                       FIELD_PREP(AD3552R_MASK_SDO_DRIVE_STRENGTH, val);
+
+               ret = st->data->bus_reg_write(st->back,
                                        AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
-                                       AD3552R_MASK_SDO_DRIVE_STRENGTH,
-                                       val, 1);
+                                       st->config_d, 1);
                if (ret)
                        return ret;
        }
@@ -533,6 +688,9 @@ static int ad3552r_hs_probe(struct platform_device *pdev)
 }
 
 static const struct of_device_id ad3552r_hs_of_id[] = {
+       { .compatible = "adi,ad3541r", .data = &ad3541r_model_data },
+       { .compatible = "adi,ad3542r", .data = &ad3542r_model_data },
+       { .compatible = "adi,ad3551r", .data = &ad3551r_model_data },
        { .compatible = "adi,ad3552r", .data = &ad3552r_model_data },
        { }
 };
index 3dc8d1d9c0f9f5d0d7e60bb50cc28ff10699aad2..768fa264d39e9e6d517aeb4098382e072f153543 100644 (file)
 
 #define AD3552R_MAX_RANGES     5
 #define AD3542R_MAX_RANGES     5
+#define AD3552R_SPI            0
+#define AD3552R_DUAL_SPI       1
 #define AD3552R_QUAD_SPI       2
 
 extern const struct ad3552r_model_data ad3541r_model_data;
@@ -153,6 +155,7 @@ struct ad3552r_model_data {
        const s32 (*ranges_table)[2];
        int num_ranges;
        bool requires_output_range;
+       int num_spi_data_lanes;
 };
 
 struct ad3552r_ch_data {