LKML Archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 00/10] iio: add support for the ad3552r AXI DAC IP
@ 2024-09-19  9:19 Angelo Dureghello
  2024-09-19  9:19 ` [PATCH v3 01/10] iio: backend: adi-axi-dac: fix wrong register bitfield Angelo Dureghello
                   ` (9 more replies)
  0 siblings, 10 replies; 59+ messages in thread
From: Angelo Dureghello @ 2024-09-19  9:19 UTC (permalink / raw)
  To: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Jonathan Cameron,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan
  Cc: linux-iio, linux-kernel, devicetree, dlechner, Angelo Dureghello

Purpose is to add ad3552r AXI DAC (fpga-based) support.

The "ad3552r" AXI IP, a variant of the generic "DAC" AXI IP,
has been created to reach the maximum speed (33MUPS) supported
from the ad3552r. To obtain the maximum transfer rate, the custom
module has been implemented with a QSPI interface with DDR mode.

The design is actually using the DAC backend since the register
map is the same of the generic DAC IP, except for some customized
bitfields. For this reason, a new "compatible" has been added
in adi-axi-dac.c.

Also, backend has been extended with all the needed functions
for this use case, keeping the names gneric.

The following patch is actually applying to linux-iio/testing.

---
Changes in v2: 
- use unsigned int on bus_reg_read/write
- add a compatible in axi-dac backend for the ad3552r DAC IP
- minor code alignment fixes
- fix a return value not checked
- change devicetree structure setting ad3552r-axi as a backend
  subnode
- add synchronous_mode_available in the ABI doc

Changes in v3: 
- changing AXI backend approach using a dac ip compatible
- fdt bindings updates accordingly
- fdt, ad3552r device must be a subnode of the backend
- allow probe of child devices
- passing QSPI bus access function by platform data
- move synchronous mode as a fdt parameter
- reorganizing defines in proper patches
- fix make dt_binding_check errors
- fix ad3552r maximum SPI speed
- fix samplerate calulcation
- minor code style fixes

Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>

---
Angelo Dureghello (10):
      iio: backend: adi-axi-dac: fix wrong register bitfield
      dt-bindings: iio: dac: axi-dac: add ad3552r axi variant
      dt-bindings: iio: dac: ad3552r: fix maximum spi speed
      dt-bindings: iio: dac: ad3552r: add io-backend support
      iio: backend: extend features
      iio: backend: adi-axi-dac: extend features
      iio: dac: ad3552r: changes to use FIELD_PREP
      iio: dac: ad3552r: extract common code (no changes in behavior intended)
      iio: dac: ad3552r: add axi platform driver
      iio: backend: adi-axi-dac: add registering of child fdt node

 .../devicetree/bindings/iio/dac/adi,ad3552r.yaml   |  44 +-
 .../devicetree/bindings/iio/dac/adi,axi-dac.yaml   |  40 +-
 drivers/iio/dac/Kconfig                            |  11 +
 drivers/iio/dac/Makefile                           |   3 +-
 drivers/iio/dac/ad3552r-axi.c                      | 567 +++++++++++++++++++++
 drivers/iio/dac/ad3552r-common.c                   | 173 +++++++
 drivers/iio/dac/ad3552r.c                          | 451 +++-------------
 drivers/iio/dac/ad3552r.h                          | 199 ++++++++
 drivers/iio/dac/adi-axi-dac.c                      | 328 +++++++++++-
 drivers/iio/industrialio-backend.c                 | 111 ++++
 include/linux/iio/backend.h                        |  23 +
 include/linux/platform_data/ad3552r-axi.h          |  18 +
 12 files changed, 1572 insertions(+), 396 deletions(-)
---
base-commit: 4ff29e5af68e081473240420d5ba8fe1c410239f
change-id: 20240919-wip-bl-ad3552r-axi-v0-iio-testing-79937010e1cf

Best regards,
-- 

  o/ QW5nZWxvIER1cmVnaGVsbG8=
   www.kernel-space.org
    e: angelo at kernel-space.org
      c: +39 388 8550663
       


^ permalink raw reply	[flat|nested] 59+ messages in thread

* [PATCH v3 01/10] iio: backend: adi-axi-dac: fix wrong register bitfield
  2024-09-19  9:19 [PATCH v3 00/10] iio: add support for the ad3552r AXI DAC IP Angelo Dureghello
@ 2024-09-19  9:19 ` Angelo Dureghello
  2024-09-20 12:45   ` Nuno Sá
  2024-09-19  9:19 ` [PATCH v3 02/10] dt-bindings: iio: dac: axi-dac: add ad3552r axi variant Angelo Dureghello
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 59+ messages in thread
From: Angelo Dureghello @ 2024-09-19  9:19 UTC (permalink / raw)
  To: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Jonathan Cameron,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan
  Cc: linux-iio, linux-kernel, devicetree, dlechner, Angelo Dureghello

From: Angelo Dureghello <adureghello@baylibre.com>

Fix ADI_DAC_R1_MODE of AXI_DAC_REG_CNTRL_2.

Both generic DAC and ad3552r DAC IPs docs are reporting
bit 5 for it.

https://wiki.analog.com/resources/fpga/docs/axi_dac_ip
https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html

Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
---
 drivers/iio/dac/adi-axi-dac.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c
index 0cb00f3bec04..b8b4171b8043 100644
--- a/drivers/iio/dac/adi-axi-dac.c
+++ b/drivers/iio/dac/adi-axi-dac.c
@@ -46,7 +46,7 @@
 #define AXI_DAC_REG_CNTRL_1		0x0044
 #define   AXI_DAC_SYNC			BIT(0)
 #define AXI_DAC_REG_CNTRL_2		0x0048
-#define	  ADI_DAC_R1_MODE		BIT(4)
+#define	  ADI_DAC_R1_MODE		BIT(5)
 #define AXI_DAC_DRP_STATUS		0x0074
 #define   AXI_DAC_DRP_LOCKED		BIT(17)
 /* DAC Channel controls */

-- 
2.45.0.rc1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v3 02/10] dt-bindings: iio: dac: axi-dac: add ad3552r axi variant
  2024-09-19  9:19 [PATCH v3 00/10] iio: add support for the ad3552r AXI DAC IP Angelo Dureghello
  2024-09-19  9:19 ` [PATCH v3 01/10] iio: backend: adi-axi-dac: fix wrong register bitfield Angelo Dureghello
@ 2024-09-19  9:19 ` Angelo Dureghello
  2024-09-20 12:47   ` Nuno Sá
                     ` (2 more replies)
  2024-09-19  9:19 ` [PATCH v3 03/10] dt-bindings: iio: dac: ad3552r: fix maximum spi speed Angelo Dureghello
                   ` (7 subsequent siblings)
  9 siblings, 3 replies; 59+ messages in thread
From: Angelo Dureghello @ 2024-09-19  9:19 UTC (permalink / raw)
  To: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Jonathan Cameron,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan
  Cc: linux-iio, linux-kernel, devicetree, dlechner, Angelo Dureghello

From: Angelo Dureghello <adureghello@baylibre.com>

Add a new compatible and related bindigns for the fpga-based
"ad3552r" AXI IP core, a variant of the generic AXI DAC IP.

The AXI "ad3552r" IP is a very similar HDL (fpga) variant of the
generic AXI "DAC" IP, intended to control ad3552r and similar chips,
mainly to reach high speed transfer rates using an additional QSPI
DDR interface.

The ad3552r device is defined as a child of the AXI DAC, that in
this case is acting as an SPI controller.

Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
---
 .../devicetree/bindings/iio/dac/adi,axi-dac.yaml   | 40 ++++++++++++++++++++--
 1 file changed, 37 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml b/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml
index a55e9bfc66d7..6cf0c2cb84e7 100644
--- a/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml
+++ b/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml
@@ -19,11 +19,13 @@ description: |
   memory via DMA into the DAC.
 
   https://wiki.analog.com/resources/fpga/docs/axi_dac_ip
+  https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
 
 properties:
   compatible:
     enum:
       - adi,axi-dac-9.1.b
+      - adi,axi-ad3552r
 
   reg:
     maxItems: 1
@@ -41,22 +43,54 @@ properties:
   '#io-backend-cells':
     const: 0
 
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
 required:
   - compatible
   - dmas
   - reg
   - clocks
 
+patternProperties:
+  "^.*@([0-9])$":
+    type: object
+    additionalProperties: true
+    properties:
+      io-backends:
+        description: |
+          AXI backend reference
+    required:
+      - io-backends
+
 additionalProperties: false
 
 examples:
   - |
     dac@44a00000 {
-        compatible = "adi,axi-dac-9.1.b";
-        reg = <0x44a00000 0x10000>;
-        dmas = <&tx_dma 0>;
+      compatible = "adi,axi-dac-9.1.b";
+      reg = <0x44a00000 0x10000>;
+      dmas = <&tx_dma 0>;
+      dma-names = "tx";
+      #io-backend-cells = <0>;
+      clocks = <&axi_clk>;
+    };
+
+  - |
+    axi_dac: spi@44a70000 {
+        compatible = "adi,axi-ad3552r";
+        reg = <0x44a70000 0x1000>;
+        dmas = <&dac_tx_dma 0>;
         dma-names = "tx";
         #io-backend-cells = <0>;
         clocks = <&axi_clk>;
+
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        /* DAC devices */
     };
 ...

-- 
2.45.0.rc1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v3 03/10] dt-bindings: iio: dac: ad3552r: fix maximum spi speed
  2024-09-19  9:19 [PATCH v3 00/10] iio: add support for the ad3552r AXI DAC IP Angelo Dureghello
  2024-09-19  9:19 ` [PATCH v3 01/10] iio: backend: adi-axi-dac: fix wrong register bitfield Angelo Dureghello
  2024-09-19  9:19 ` [PATCH v3 02/10] dt-bindings: iio: dac: axi-dac: add ad3552r axi variant Angelo Dureghello
@ 2024-09-19  9:19 ` Angelo Dureghello
  2024-09-22 20:59   ` Krzysztof Kozlowski
  2024-09-19  9:20 ` [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support Angelo Dureghello
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 59+ messages in thread
From: Angelo Dureghello @ 2024-09-19  9:19 UTC (permalink / raw)
  To: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Jonathan Cameron,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan
  Cc: linux-iio, linux-kernel, devicetree, dlechner, Angelo Dureghello

From: Angelo Dureghello <adureghello@baylibre.com>

Fix maximum SPI clock speed, as per datasheet (Rev. B, page 6).

Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
---
 Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
index fc8b97f82077..41fe00034742 100644
--- a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
+++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
@@ -30,7 +30,7 @@ properties:
     maxItems: 1
 
   spi-max-frequency:
-    maximum: 30000000
+    maximum: 66000000
 
   reset-gpios:
     maxItems: 1

-- 
2.45.0.rc1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support
  2024-09-19  9:19 [PATCH v3 00/10] iio: add support for the ad3552r AXI DAC IP Angelo Dureghello
                   ` (2 preceding siblings ...)
  2024-09-19  9:19 ` [PATCH v3 03/10] dt-bindings: iio: dac: ad3552r: fix maximum spi speed Angelo Dureghello
@ 2024-09-19  9:20 ` Angelo Dureghello
  2024-09-22 21:02   ` Krzysztof Kozlowski
  2024-09-29 10:51   ` Jonathan Cameron
  2024-09-19  9:20 ` [PATCH v3 05/10] iio: backend: extend features Angelo Dureghello
                   ` (5 subsequent siblings)
  9 siblings, 2 replies; 59+ messages in thread
From: Angelo Dureghello @ 2024-09-19  9:20 UTC (permalink / raw)
  To: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Jonathan Cameron,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan
  Cc: linux-iio, linux-kernel, devicetree, dlechner, Angelo Dureghello

From: Angelo Dureghello <adureghello@baylibre.com>

There is a version AXI DAC IP block (for FPGAs) that provides
a physical bus for AD3552R and similar chips, and acts as
an SPI controller.

For this case, the binding is modified to include some
additional properties.

Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
---
 .../devicetree/bindings/iio/dac/adi,ad3552r.yaml   | 42 ++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
index 41fe00034742..aca4a41c2633 100644
--- a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
+++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
@@ -60,6 +60,18 @@ properties:
     $ref: /schemas/types.yaml#/definitions/uint32
     enum: [0, 1, 2, 3]
 
+  io-backends:
+    description: The iio backend reference.
+      An example backend can be found at
+        https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
+    maxItems: 1
+
+  adi,synchronous-mode:
+    description: Enable waiting for external synchronization signal.
+      Some AXI IP configuration can implement a dual-IP layout, with internal
+      wirings for streaming synchronization.
+    type: boolean
+
   '#address-cells':
     const: 1
 
@@ -128,6 +140,7 @@ patternProperties:
           - custom-output-range-config
 
 allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
   - if:
       properties:
         compatible:
@@ -238,4 +251,33 @@ examples:
             };
         };
     };
+
+  - |
+    axi_dac: spi@44a70000 {
+        compatible = "adi,axi-ad3552r";
+        reg = <0x44a70000 0x1000>;
+        dmas = <&dac_tx_dma 0>;
+        dma-names = "tx";
+        #io-backend-cells = <0>;
+        clocks = <&ref_clk>;
+
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        dac@0 {
+            compatible = "adi,ad3552r";
+            reg = <0>;
+            reset-gpios = <&gpio0 92 0>;
+            io-backends = <&axi_dac>;
+            spi-max-frequency = <66000000>;
+
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            channel@0 {
+                reg = <0>;
+                adi,output-range-microvolt = <(-10000000) (10000000)>;
+            };
+        };
+    };
 ...

-- 
2.45.0.rc1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v3 05/10] iio: backend: extend features
  2024-09-19  9:19 [PATCH v3 00/10] iio: add support for the ad3552r AXI DAC IP Angelo Dureghello
                   ` (3 preceding siblings ...)
  2024-09-19  9:20 ` [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support Angelo Dureghello
@ 2024-09-19  9:20 ` Angelo Dureghello
  2024-09-20 12:50   ` Nuno Sá
  2024-09-29 11:05   ` Jonathan Cameron
  2024-09-19  9:20 ` [PATCH v3 06/10] iio: backend: adi-axi-dac: " Angelo Dureghello
                   ` (4 subsequent siblings)
  9 siblings, 2 replies; 59+ messages in thread
From: Angelo Dureghello @ 2024-09-19  9:20 UTC (permalink / raw)
  To: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Jonathan Cameron,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan
  Cc: linux-iio, linux-kernel, devicetree, dlechner, Angelo Dureghello

From: Angelo Dureghello <adureghello@baylibre.com>

Extend backend features with new calls needed later on this
patchset from axi version of ad3552r.

The follwoing calls are added:

iio_backend_ext_sync_enable
	enable synchronize channels on external trigger
iio_backend_ext_sync_disable
	disable synchronize channels on external trigger
iio_backend_ddr_enable
	enable ddr bus transfer
iio_backend_ddr_disable
	disable ddr bus transfer
iio_backend_set_bus_mode
	select the type of bus, so that specific read / write
	operations are performed accordingly
iio_backend_buffer_enable
	enable buffer
iio_backend_buffer_disable
	disable buffer
iio_backend_data_transfer_addr
	define the target register address where the DAC sample
	will be written.

Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
---
 drivers/iio/industrialio-backend.c | 111 +++++++++++++++++++++++++++++++++++++
 include/linux/iio/backend.h        |  23 ++++++++
 2 files changed, 134 insertions(+)

diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c
index 20b3b5212da7..f4802c422dbf 100644
--- a/drivers/iio/industrialio-backend.c
+++ b/drivers/iio/industrialio-backend.c
@@ -718,6 +718,117 @@ static int __devm_iio_backend_get(struct device *dev, struct iio_backend *back)
 	return 0;
 }
 
+/**
+ * iio_backend_ext_sync_enable - Enable external synchronization
+ * @back: Backend device
+ *
+ * Enable synchronization by external signal.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_ext_sync_enable(struct iio_backend *back)
+{
+	return iio_backend_op_call(back, ext_sync_enable);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_ext_sync_enable, IIO_BACKEND);
+
+/**
+ * iio_backend_ext_sync_disable - Disable external synchronization
+ * @back: Backend device
+ *
+ * Disable synchronization by external signal.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_ext_sync_disable(struct iio_backend *back)
+{
+	return iio_backend_op_call(back, ext_sync_disable);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_ext_sync_disable, IIO_BACKEND);
+
+/**
+ * iio_backend_ddr_enable - Enable interface DDR (Double Data Rate) mode
+ * @back: Backend device
+ *
+ * Enabling DDR, data is generated by the IP at each front
+ * (raising and falling) of the bus clock signal.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_ddr_enable(struct iio_backend *back)
+{
+	return iio_backend_op_call(back, ddr_enable);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_ddr_enable, IIO_BACKEND);
+
+/**
+ * iio_backend_ddr_disable - Disable interface DDR (Double Data Rate) mode
+ * @back: Backend device
+ *
+ * Disabling DDR data is generated byt the IP at rising or falling front
+ * of the interface clock signal (SDR, Single Data Rate).
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_ddr_disable(struct iio_backend *back)
+{
+	return iio_backend_op_call(back, ddr_disable);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_ddr_disable, IIO_BACKEND);
+
+/**
+ * iio_backend_buffer_enable - Enable iio buffering
+ * @back: Backend device
+ *
+ * Enabling the buffer, buffer data is processed and sent out from the
+ * bus interface.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_buffer_enable(struct iio_backend *back)
+{
+	return iio_backend_op_call(back, buffer_enable);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_buffer_enable, IIO_BACKEND);
+
+/**
+ * iio_backend_buffer_disable - Disable iio buffering
+ * @back: Backend device
+ *
+ * Disabling the buffer, buffer data transfer on the bus interface
+ * is stopped.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_buffer_disable(struct iio_backend *back)
+{
+	return iio_backend_op_call(back, buffer_disable);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_buffer_disable, IIO_BACKEND);
+
+/**
+ * iio_backend_data_transfer_addr - Set data address.
+ * @back: Backend device
+ * @address: Data register address
+ *
+ * Some devices may need to inform the backend about an address
+ * where to read or write the data.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_data_transfer_addr(struct iio_backend *back, u32 address)
+{
+	return iio_backend_op_call(back, data_transfer_addr, address);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_data_transfer_addr, IIO_BACKEND);
+
 static struct iio_backend *__devm_iio_backend_fwnode_get(struct device *dev, const char *name,
 							 struct fwnode_handle *fwnode)
 {
diff --git a/include/linux/iio/backend.h b/include/linux/iio/backend.h
index 37d56914d485..41619b803cd6 100644
--- a/include/linux/iio/backend.h
+++ b/include/linux/iio/backend.h
@@ -14,12 +14,14 @@ struct iio_dev;
 enum iio_backend_data_type {
 	IIO_BACKEND_TWOS_COMPLEMENT,
 	IIO_BACKEND_OFFSET_BINARY,
+	IIO_BACKEND_DATA_UNSIGNED,
 	IIO_BACKEND_DATA_TYPE_MAX
 };
 
 enum iio_backend_data_source {
 	IIO_BACKEND_INTERNAL_CONTINUOUS_WAVE,
 	IIO_BACKEND_EXTERNAL,
+	IIO_BACKEND_INTERNAL_RAMP_16BIT,
 	IIO_BACKEND_DATA_SOURCE_MAX
 };
 
@@ -89,6 +91,13 @@ enum iio_backend_sample_trigger {
  * @read_raw: Read a channel attribute from a backend device
  * @debugfs_print_chan_status: Print channel status into a buffer.
  * @debugfs_reg_access: Read or write register value of backend.
+ * @ext_sync_enable: Enable external synchronization.
+ * @ext_sync_disable: Disable external synchronization.
+ * @ddr_enable: Enable interface DDR (Double Data Rate) mode.
+ * @ddr_disable: Disable interface DDR (Double Data Rate) mode.
+ * @buffer_enable: Enable data buffer.
+ * @buffer_disable: Disable data buffer.
+ * @data_transfer_addr: Set data address.
  **/
 struct iio_backend_ops {
 	int (*enable)(struct iio_backend *back);
@@ -129,6 +138,13 @@ struct iio_backend_ops {
 					 size_t len);
 	int (*debugfs_reg_access)(struct iio_backend *back, unsigned int reg,
 				  unsigned int writeval, unsigned int *readval);
+	int (*ext_sync_enable)(struct iio_backend *back);
+	int (*ext_sync_disable)(struct iio_backend *back);
+	int (*ddr_enable)(struct iio_backend *back);
+	int (*ddr_disable)(struct iio_backend *back);
+	int (*buffer_enable)(struct iio_backend *back);
+	int (*buffer_disable)(struct iio_backend *back);
+	int (*data_transfer_addr)(struct iio_backend *back, u32 address);
 };
 
 /**
@@ -164,6 +180,13 @@ int iio_backend_data_sample_trigger(struct iio_backend *back,
 int devm_iio_backend_request_buffer(struct device *dev,
 				    struct iio_backend *back,
 				    struct iio_dev *indio_dev);
+int iio_backend_ext_sync_enable(struct iio_backend *back);
+int iio_backend_ext_sync_disable(struct iio_backend *back);
+int iio_backend_ddr_enable(struct iio_backend *back);
+int iio_backend_ddr_disable(struct iio_backend *back);
+int iio_backend_buffer_enable(struct iio_backend *back);
+int iio_backend_buffer_disable(struct iio_backend *back);
+int iio_backend_data_transfer_addr(struct iio_backend *back, u32 address);
 ssize_t iio_backend_ext_info_set(struct iio_dev *indio_dev, uintptr_t private,
 				 const struct iio_chan_spec *chan,
 				 const char *buf, size_t len);

-- 
2.45.0.rc1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v3 06/10] iio: backend: adi-axi-dac: extend features
  2024-09-19  9:19 [PATCH v3 00/10] iio: add support for the ad3552r AXI DAC IP Angelo Dureghello
                   ` (4 preceding siblings ...)
  2024-09-19  9:20 ` [PATCH v3 05/10] iio: backend: extend features Angelo Dureghello
@ 2024-09-19  9:20 ` Angelo Dureghello
  2024-09-20 13:10   ` Nuno Sá
  2024-09-29 11:28   ` Jonathan Cameron
  2024-09-19  9:20 ` [PATCH v3 07/10] iio: dac: ad3552r: changes to use FIELD_PREP Angelo Dureghello
                   ` (3 subsequent siblings)
  9 siblings, 2 replies; 59+ messages in thread
From: Angelo Dureghello @ 2024-09-19  9:20 UTC (permalink / raw)
  To: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Jonathan Cameron,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan
  Cc: linux-iio, linux-kernel, devicetree, dlechner, Angelo Dureghello

From: Angelo Dureghello <adureghello@baylibre.com>

Extend AXI-DAC backend with new features required to interface
to the ad3552r DAC. Mainly, a new compatible string is added to
support the ad3552r-axi DAC IP, very similar to the generic DAC
IP but with some customizations to work with the ad3552r.

Then, a serie of generic functions has been added to match with
ad3552r needs. Function names has been kept generic as much as
possible, to allow re-utilization from other frontend drivers.

Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
---
 drivers/iio/dac/adi-axi-dac.c | 274 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 265 insertions(+), 9 deletions(-)

diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c
index b8b4171b8043..3ca3a14c575b 100644
--- a/drivers/iio/dac/adi-axi-dac.c
+++ b/drivers/iio/dac/adi-axi-dac.c
@@ -44,11 +44,34 @@
 #define   AXI_DAC_RSTN_MMCM_RSTN	BIT(1)
 #define   AXI_DAC_RSTN_RSTN		BIT(0)
 #define AXI_DAC_REG_CNTRL_1		0x0044
+#define   AXI_DAC_EXT_SYNC_ARM		BIT(1)
+#define   AXI_DAC_EXT_SYNC_DISARM	BIT(2)
 #define   AXI_DAC_SYNC			BIT(0)
 #define AXI_DAC_REG_CNTRL_2		0x0048
+#define   AXI_DAC_SDR_DDR_N		BIT(16)
+#define   AXI_DAC_SYMB_8B		BIT(14)
 #define	  ADI_DAC_R1_MODE		BIT(5)
+#define   AXI_DAC_UNSIGNED_DATA		BIT(4)
+#define AXI_DAC_REG_STATUS_1		0x54
+#define AXI_DAC_REG_STATUS_2		0x58
 #define AXI_DAC_DRP_STATUS		0x0074
 #define   AXI_DAC_DRP_LOCKED		BIT(17)
+#define AXI_DAC_CNTRL_DATA_RD		0x0080
+#define   AXI_DAC_DATA_RD_8		GENMASK(7, 0)
+#define   AXI_DAC_DATA_RD_16		GENMASK(15, 0)
+#define AXI_DAC_CNTRL_DATA_WR		0x0084
+#define   AXI_DAC_DATA_WR_8		GENMASK(23, 16)
+#define   AXI_DAC_DATA_WR_16		GENMASK(23, 8)
+#define AXI_DAC_UI_STATUS		0x0088
+#define   AXI_DAC_BUSY			BIT(4)
+#define AXI_DAC_REG_CUSTOM_CTRL		0x008C
+#define   AXI_DAC_ADDRESS		GENMASK(31, 24)
+#define   AXI_DAC_SYNCED_TRANSFER	BIT(2)
+#define   AXI_DAC_STREAM		BIT(1)
+#define   AXI_DAC_TRANSFER_DATA		BIT(0)
+
+#define AXI_DAC_STREAM_ENABLE		(AXI_DAC_TRANSFER_DATA | AXI_DAC_STREAM)
+
 /* DAC Channel controls */
 #define AXI_DAC_REG_CHAN_CNTRL_1(c)	(0x0400 + (c) * 0x40)
 #define AXI_DAC_REG_CHAN_CNTRL_3(c)	(0x0408 + (c) * 0x40)
@@ -62,11 +85,25 @@
 #define AXI_DAC_REG_CHAN_CNTRL_7(c)	(0x0418 + (c) * 0x40)
 #define   AXI_DAC_DATA_SEL		GENMASK(3, 0)
 
+#define AXI_DAC_RD_ADDR(x)		(BIT(7) | (x))
+
 /* 360 degrees in rad */
 #define AXI_DAC_2_PI_MEGA		6283190
+
 enum {
 	AXI_DAC_DATA_INTERNAL_TONE,
 	AXI_DAC_DATA_DMA = 2,
+	AXI_DAC_DATA_INTERNAL_RAMP_16BIT = 11,
+};
+
+enum {
+	AXI_DAC_BUS_TYPE_NONE,
+	AXI_DAC_BUS_TYPE_DDR_QSPI,
+};
+
+struct axi_dac_info {
+	unsigned int version;
+	int bus_type;
 };
 
 struct axi_dac_state {
@@ -77,6 +114,7 @@ struct axi_dac_state {
 	 * data/variables.
 	 */
 	struct mutex lock;
+	const struct axi_dac_info *info;
 	u64 dac_clk;
 	u32 reg_config;
 	bool int_tone;
@@ -461,6 +499,11 @@ static int axi_dac_data_source_set(struct iio_backend *back, unsigned int chan,
 		return regmap_update_bits(st->regmap,
 					  AXI_DAC_REG_CHAN_CNTRL_7(chan),
 					  AXI_DAC_DATA_SEL, AXI_DAC_DATA_DMA);
+	case IIO_BACKEND_INTERNAL_RAMP_16BIT:
+		return regmap_update_bits(st->regmap,
+					  AXI_DAC_REG_CHAN_CNTRL_7(chan),
+					  AXI_DAC_DATA_SEL,
+					  AXI_DAC_DATA_INTERNAL_RAMP_16BIT);
 	default:
 		return -EINVAL;
 	}
@@ -518,9 +561,206 @@ static int axi_dac_reg_access(struct iio_backend *back, unsigned int reg,
 	return regmap_write(st->regmap, reg, writeval);
 }
 
+static int axi_dac_ext_sync_enable(struct iio_backend *back)
+{
+	struct axi_dac_state *st = iio_backend_get_priv(back);
+
+	return regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_1,
+			       AXI_DAC_EXT_SYNC_ARM);
+}
+
+static int axi_dac_ext_sync_disable(struct iio_backend *back)
+{
+	struct axi_dac_state *st = iio_backend_get_priv(back);
+
+	return regmap_clear_bits(st->regmap, AXI_DAC_REG_CNTRL_1,
+				 AXI_DAC_EXT_SYNC_DISARM);
+}
+
+static int axi_dac_ddr_enable(struct iio_backend *back)
+{
+	struct axi_dac_state *st = iio_backend_get_priv(back);
+
+	return regmap_clear_bits(st->regmap, AXI_DAC_REG_CNTRL_2,
+				 AXI_DAC_SDR_DDR_N);
+}
+
+static int axi_dac_ddr_disable(struct iio_backend *back)
+{
+	struct axi_dac_state *st = iio_backend_get_priv(back);
+
+	return regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_2,
+			       AXI_DAC_SDR_DDR_N);
+}
+
+static int axi_dac_buffer_enable(struct iio_backend *back)
+{
+	struct axi_dac_state *st = iio_backend_get_priv(back);
+
+	return regmap_set_bits(st->regmap, AXI_DAC_REG_CUSTOM_CTRL,
+			       AXI_DAC_STREAM_ENABLE);
+}
+
+static int axi_dac_buffer_disable(struct iio_backend *back)
+{
+	struct axi_dac_state *st = iio_backend_get_priv(back);
+
+	return regmap_clear_bits(st->regmap, AXI_DAC_REG_CUSTOM_CTRL,
+				 AXI_DAC_STREAM_ENABLE);
+}
+
+static int axi_dac_data_transfer_addr(struct iio_backend *back, u32 address)
+{
+	struct axi_dac_state *st = iio_backend_get_priv(back);
+
+	/*
+	 * Sample register address, when the DAC is configured, or stream
+	 * start address when the FSM is in stream state.
+	 */
+	return regmap_update_bits(st->regmap, AXI_DAC_REG_CUSTOM_CTRL,
+				  AXI_DAC_ADDRESS,
+				  FIELD_PREP(AXI_DAC_ADDRESS, address));
+}
+
+static int axi_dac_data_format_set(struct iio_backend *back, unsigned int ch,
+				   const struct iio_backend_data_fmt *data)
+{
+	struct axi_dac_state *st = iio_backend_get_priv(back);
+
+	if (data->type == IIO_BACKEND_DATA_UNSIGNED)
+		return regmap_clear_bits(st->regmap, AXI_DAC_REG_CNTRL_2,
+					 AXI_DAC_UNSIGNED_DATA);
+
+	return -EINVAL;
+}
+
+static int axi_dac_read_raw(struct iio_backend *back,
+			    struct iio_chan_spec const *chan,
+			    int *val, int *val2, long mask)
+{
+	struct axi_dac_state *st = iio_backend_get_priv(back);
+	int err;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_FREQUENCY: {
+		int clk_in, reg;
+
+		/*
+		 * As from AXI IP documentation,
+		 * returning the SCLK depending on the stream mode.
+		 */
+		clk_in = clk_get_rate(clk_get(st->dev, 0));
+
+		err = regmap_read(st->regmap, AXI_DAC_REG_CUSTOM_CTRL, &reg);
+		if (err)
+			return err;
+
+		if (reg & AXI_DAC_STREAM)
+			*val = clk_in / 2;
+		else
+			*val = clk_in / 8;
+
+		return IIO_VAL_INT;
+		}
+	default:
+		return -EINVAL;
+	}
+}
+
+static int axi_dac_bus_reg_write(struct iio_backend *back, u32 reg,
+				 unsigned int val, size_t data_size)
+{
+	struct axi_dac_state *st = iio_backend_get_priv(back);
+
+	switch (st->info->bus_type) {
+	case AXI_DAC_BUS_TYPE_DDR_QSPI: {
+		int ret;
+		u32 ival;
+
+		if (data_size == 2)
+			ival = FIELD_PREP(AXI_DAC_DATA_WR_16, val);
+		else
+			ival = FIELD_PREP(AXI_DAC_DATA_WR_8, val);
+
+		ret = regmap_write(st->regmap, AXI_DAC_CNTRL_DATA_WR, ival);
+		if (ret)
+			return ret;
+
+		/*
+		 * Both REG_CNTRL_2 and AXI_DAC_CNTRL_DATA_WR need to know
+		 * the data size. So keeping data size control here only,
+		 * since data size is mandatory for the current transfer.
+		 * DDR state handled separately by specific backend calls,
+		 * generally all raw register writes are SDR.
+		 */
+		if (data_size == 1)
+			ret = regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_2,
+					      AXI_DAC_SYMB_8B);
+		else
+			ret = regmap_clear_bits(st->regmap, AXI_DAC_REG_CNTRL_2,
+						AXI_DAC_SYMB_8B);
+		if (ret)
+			return ret;
+
+		ret = regmap_update_bits(st->regmap, AXI_DAC_REG_CUSTOM_CTRL,
+					 AXI_DAC_ADDRESS,
+					 FIELD_PREP(AXI_DAC_ADDRESS, reg));
+		if (ret)
+			return ret;
+
+		ret = regmap_update_bits(st->regmap, AXI_DAC_REG_CUSTOM_CTRL,
+					 AXI_DAC_TRANSFER_DATA,
+					 AXI_DAC_TRANSFER_DATA);
+		if (ret)
+			return ret;
+
+		ret = regmap_read_poll_timeout(st->regmap,
+					       AXI_DAC_REG_CUSTOM_CTRL, ival,
+					       ival & AXI_DAC_TRANSFER_DATA,
+					       10, 100 * KILO);
+		if (ret)
+			return ret;
+
+		return regmap_clear_bits(st->regmap, AXI_DAC_REG_CUSTOM_CTRL,
+					  AXI_DAC_TRANSFER_DATA);
+	}
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static int axi_dac_bus_reg_read(struct iio_backend *back, u32 reg,
+				unsigned int *val, size_t data_size)
+{
+	struct axi_dac_state *st = iio_backend_get_priv(back);
+
+	switch (st->info->bus_type) {
+	case AXI_DAC_BUS_TYPE_DDR_QSPI: {
+		int ret;
+		u32 bval;
+
+		ret = axi_dac_bus_reg_write(back, AXI_DAC_RD_ADDR(reg), 0,
+					    data_size);
+		if (ret)
+			return ret;
+
+		ret = regmap_read_poll_timeout(st->regmap, AXI_DAC_UI_STATUS,
+					       bval, bval != AXI_DAC_BUSY,
+					       10, 100);
+		if (ret)
+			return ret;
+
+		return regmap_read(st->regmap, AXI_DAC_CNTRL_DATA_RD, val);
+	}
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
 static const struct iio_backend_ops axi_dac_generic_ops = {
 	.enable = axi_dac_enable,
 	.disable = axi_dac_disable,
+	.read_raw = axi_dac_read_raw,
 	.request_buffer = axi_dac_request_buffer,
 	.free_buffer = axi_dac_free_buffer,
 	.extend_chan_spec = axi_dac_extend_chan,
@@ -528,6 +768,14 @@ static const struct iio_backend_ops axi_dac_generic_ops = {
 	.ext_info_get = axi_dac_ext_info_get,
 	.data_source_set = axi_dac_data_source_set,
 	.set_sample_rate = axi_dac_set_sample_rate,
+	.ext_sync_enable = axi_dac_ext_sync_enable,
+	.ext_sync_disable = axi_dac_ext_sync_disable,
+	.ddr_enable = axi_dac_ddr_enable,
+	.ddr_disable = axi_dac_ddr_disable,
+	.buffer_enable = axi_dac_buffer_enable,
+	.buffer_disable = axi_dac_buffer_disable,
+	.data_format_set = axi_dac_data_format_set,
+	.data_transfer_addr = axi_dac_data_transfer_addr,
 	.debugfs_reg_access = iio_backend_debugfs_ptr(axi_dac_reg_access),
 };
 
@@ -545,7 +793,6 @@ static const struct regmap_config axi_dac_regmap_config = {
 
 static int axi_dac_probe(struct platform_device *pdev)
 {
-	const unsigned int *expected_ver;
 	struct axi_dac_state *st;
 	void __iomem *base;
 	unsigned int ver;
@@ -556,8 +803,8 @@ static int axi_dac_probe(struct platform_device *pdev)
 	if (!st)
 		return -ENOMEM;
 
-	expected_ver = device_get_match_data(&pdev->dev);
-	if (!expected_ver)
+	st->info = device_get_match_data(&pdev->dev);
+	if (!st->info)
 		return -ENODEV;
 
 	clk = devm_clk_get_enabled(&pdev->dev, NULL);
@@ -588,12 +835,13 @@ static int axi_dac_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	if (ADI_AXI_PCORE_VER_MAJOR(ver) != ADI_AXI_PCORE_VER_MAJOR(*expected_ver)) {
+	if (ADI_AXI_PCORE_VER_MAJOR(ver) !=
+		ADI_AXI_PCORE_VER_MAJOR(st->info->version)) {
 		dev_err(&pdev->dev,
 			"Major version mismatch. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n",
-			ADI_AXI_PCORE_VER_MAJOR(*expected_ver),
-			ADI_AXI_PCORE_VER_MINOR(*expected_ver),
-			ADI_AXI_PCORE_VER_PATCH(*expected_ver),
+			ADI_AXI_PCORE_VER_MAJOR(st->info->version),
+			ADI_AXI_PCORE_VER_MINOR(st->info->version),
+			ADI_AXI_PCORE_VER_PATCH(st->info->version),
 			ADI_AXI_PCORE_VER_MAJOR(ver),
 			ADI_AXI_PCORE_VER_MINOR(ver),
 			ADI_AXI_PCORE_VER_PATCH(ver));
@@ -631,10 +879,18 @@ static int axi_dac_probe(struct platform_device *pdev)
 	return 0;
 }
 
-static unsigned int axi_dac_9_1_b_info = ADI_AXI_PCORE_VER(9, 1, 'b');
+static const struct axi_dac_info dac_generic = {
+	.version = ADI_AXI_PCORE_VER(9, 1, 'b'),
+};
+
+static const struct axi_dac_info dac_ad3552r = {
+	.version = ADI_AXI_PCORE_VER(9, 1, 'b'),
+	.bus_type = AXI_DAC_BUS_TYPE_DDR_QSPI,
+};
 
 static const struct of_device_id axi_dac_of_match[] = {
-	{ .compatible = "adi,axi-dac-9.1.b", .data = &axi_dac_9_1_b_info },
+	{ .compatible = "adi,axi-dac-9.1.b", .data = &dac_generic },
+	{ .compatible = "adi,axi-ad3552r", .data = &dac_ad3552r },
 	{}
 };
 MODULE_DEVICE_TABLE(of, axi_dac_of_match);

-- 
2.45.0.rc1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v3 07/10] iio: dac: ad3552r: changes to use FIELD_PREP
  2024-09-19  9:19 [PATCH v3 00/10] iio: add support for the ad3552r AXI DAC IP Angelo Dureghello
                   ` (5 preceding siblings ...)
  2024-09-19  9:20 ` [PATCH v3 06/10] iio: backend: adi-axi-dac: " Angelo Dureghello
@ 2024-09-19  9:20 ` Angelo Dureghello
  2024-09-19  9:20 ` [PATCH v3 08/10] iio: dac: ad3552r: extract common code (no changes in behavior intended) Angelo Dureghello
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 59+ messages in thread
From: Angelo Dureghello @ 2024-09-19  9:20 UTC (permalink / raw)
  To: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Jonathan Cameron,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan
  Cc: linux-iio, linux-kernel, devicetree, dlechner, Angelo Dureghello

From: Angelo Dureghello <adureghello@baylibre.com>

Changes to use FIELD_PREP, so that driver-specific ad3552r_field_prep
is removed. Variables (arrays) that was used to call ad3552r_field_prep
are removed too.

Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
---
 drivers/iio/dac/ad3552r.c | 166 ++++++++++++++--------------------------------
 1 file changed, 49 insertions(+), 117 deletions(-)

diff --git a/drivers/iio/dac/ad3552r.c b/drivers/iio/dac/ad3552r.c
index bd37d304ca70..c27706c5ba10 100644
--- a/drivers/iio/dac/ad3552r.c
+++ b/drivers/iio/dac/ad3552r.c
@@ -210,46 +210,6 @@ static const s32 gains_scaling_table[] = {
 	[AD3552R_CH_GAIN_SCALING_0_125]		= 125
 };
 
-enum ad3552r_dev_attributes {
-	/* - Direct register values */
-	/* From 0-3 */
-	AD3552R_SDO_DRIVE_STRENGTH,
-	/*
-	 * 0 -> Internal Vref, vref_io pin floating (default)
-	 * 1 -> Internal Vref, vref_io driven by internal vref
-	 * 2 or 3 -> External Vref
-	 */
-	AD3552R_VREF_SELECT,
-	/* Read registers in ascending order if set. Else descending */
-	AD3552R_ADDR_ASCENSION,
-};
-
-enum ad3552r_ch_attributes {
-	/* DAC powerdown */
-	AD3552R_CH_DAC_POWERDOWN,
-	/* DAC amplifier powerdown */
-	AD3552R_CH_AMPLIFIER_POWERDOWN,
-	/* Select the output range. Select from enum ad3552r_ch_output_range */
-	AD3552R_CH_OUTPUT_RANGE_SEL,
-	/*
-	 * Over-rider the range selector in order to manually set the output
-	 * voltage range
-	 */
-	AD3552R_CH_RANGE_OVERRIDE,
-	/* Manually set the offset voltage */
-	AD3552R_CH_GAIN_OFFSET,
-	/* Sets the polarity of the offset. */
-	AD3552R_CH_GAIN_OFFSET_POLARITY,
-	/* PDAC gain scaling */
-	AD3552R_CH_GAIN_SCALING_P,
-	/* NDAC gain scaling */
-	AD3552R_CH_GAIN_SCALING_N,
-	/* Rfb value */
-	AD3552R_CH_RFB,
-	/* Channel select. When set allow Input -> DAC and Mask -> DAC */
-	AD3552R_CH_SELECT,
-};
-
 struct ad3552r_ch_data {
 	s32	scale_int;
 	s32	scale_dec;
@@ -285,45 +245,6 @@ struct ad3552r_desc {
 	unsigned int		num_ch;
 };
 
-static const u16 addr_mask_map[][2] = {
-	[AD3552R_ADDR_ASCENSION] = {
-			AD3552R_REG_ADDR_INTERFACE_CONFIG_A,
-			AD3552R_MASK_ADDR_ASCENSION
-	},
-	[AD3552R_SDO_DRIVE_STRENGTH] = {
-			AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
-			AD3552R_MASK_SDO_DRIVE_STRENGTH
-	},
-	[AD3552R_VREF_SELECT] = {
-			AD3552R_REG_ADDR_SH_REFERENCE_CONFIG,
-			AD3552R_MASK_REFERENCE_VOLTAGE_SEL
-	},
-};
-
-/* 0 -> reg addr, 1->ch0 mask, 2->ch1 mask */
-static const u16 addr_mask_map_ch[][3] = {
-	[AD3552R_CH_DAC_POWERDOWN] = {
-			AD3552R_REG_ADDR_POWERDOWN_CONFIG,
-			AD3552R_MASK_CH_DAC_POWERDOWN(0),
-			AD3552R_MASK_CH_DAC_POWERDOWN(1)
-	},
-	[AD3552R_CH_AMPLIFIER_POWERDOWN] = {
-			AD3552R_REG_ADDR_POWERDOWN_CONFIG,
-			AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(0),
-			AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(1)
-	},
-	[AD3552R_CH_OUTPUT_RANGE_SEL] = {
-			AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE,
-			AD3552R_MASK_CH_OUTPUT_RANGE_SEL(0),
-			AD3552R_MASK_CH_OUTPUT_RANGE_SEL(1)
-	},
-	[AD3552R_CH_SELECT] = {
-			AD3552R_REG_ADDR_CH_SELECT_16B,
-			AD3552R_MASK_CH(0),
-			AD3552R_MASK_CH(1)
-	}
-};
-
 static u8 _ad3552r_reg_len(u8 addr)
 {
 	switch (addr) {
@@ -399,11 +320,6 @@ static int ad3552r_read_reg(struct ad3552r_desc *dac, u8 addr, u16 *val)
 	return 0;
 }
 
-static u16 ad3552r_field_prep(u16 val, u16 mask)
-{
-	return (val << __ffs(mask)) & mask;
-}
-
 /* Update field of a register, shift val if needed */
 static int ad3552r_update_reg_field(struct ad3552r_desc *dac, u8 addr, u16 mask,
 				    u16 val)
@@ -416,21 +332,11 @@ static int ad3552r_update_reg_field(struct ad3552r_desc *dac, u8 addr, u16 mask,
 		return ret;
 
 	reg &= ~mask;
-	reg |= ad3552r_field_prep(val, mask);
+	reg |= val;
 
 	return ad3552r_write_reg(dac, addr, reg);
 }
 
-static int ad3552r_set_ch_value(struct ad3552r_desc *dac,
-				enum ad3552r_ch_attributes attr,
-				u8 ch,
-				u16 val)
-{
-	/* Update register related to attributes in chip */
-	return ad3552r_update_reg_field(dac, addr_mask_map_ch[attr][0],
-				       addr_mask_map_ch[attr][ch + 1], val);
-}
-
 #define AD3552R_CH_DAC(_idx) ((struct iio_chan_spec) {		\
 	.type = IIO_VOLTAGE,					\
 	.output = true,						\
@@ -510,8 +416,14 @@ static int ad3552r_write_raw(struct iio_dev *indio_dev,
 					val);
 		break;
 	case IIO_CHAN_INFO_ENABLE:
-		err = ad3552r_set_ch_value(dac, AD3552R_CH_DAC_POWERDOWN,
-					   chan->channel, !val);
+		if (chan->channel == 0)
+			val = FIELD_PREP(AD3552R_MASK_CH_DAC_POWERDOWN(0), !val);
+		else
+			val = FIELD_PREP(AD3552R_MASK_CH_DAC_POWERDOWN(1), !val);
+
+		err = ad3552r_update_reg_field(dac, AD3552R_REG_ADDR_POWERDOWN_CONFIG,
+					       AD3552R_MASK_CH_DAC_POWERDOWN(chan->channel),
+					       val);
 		break;
 	default:
 		err = -EINVAL;
@@ -715,9 +627,9 @@ static int ad3552r_reset(struct ad3552r_desc *dac)
 	}
 
 	return ad3552r_update_reg_field(dac,
-					addr_mask_map[AD3552R_ADDR_ASCENSION][0],
-					addr_mask_map[AD3552R_ADDR_ASCENSION][1],
-					val);
+					AD3552R_REG_ADDR_INTERFACE_CONFIG_A,
+					AD3552R_MASK_ADDR_ASCENSION,
+					FIELD_PREP(AD3552R_MASK_ADDR_ASCENSION, val));
 }
 
 static void ad3552r_get_custom_range(struct ad3552r_desc *dac, s32 i, s32 *v_min,
@@ -812,20 +724,20 @@ static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac,
 				     "mandatory custom-output-range-config property missing\n");
 
 	dac->ch_data[ch].range_override = 1;
-	reg |= ad3552r_field_prep(1, AD3552R_MASK_CH_RANGE_OVERRIDE);
+	reg |= FIELD_PREP(AD3552R_MASK_CH_RANGE_OVERRIDE, 1);
 
 	err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-p", &val);
 	if (err)
 		return dev_err_probe(dev, err,
 				     "mandatory adi,gain-scaling-p property missing\n");
-	reg |= ad3552r_field_prep(val, AD3552R_MASK_CH_GAIN_SCALING_P);
+	reg |= FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_P, val);
 	dac->ch_data[ch].p = val;
 
 	err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-n", &val);
 	if (err)
 		return dev_err_probe(dev, err,
 				     "mandatory adi,gain-scaling-n property missing\n");
-	reg |= ad3552r_field_prep(val, AD3552R_MASK_CH_GAIN_SCALING_N);
+	reg |= FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_N, val);
 	dac->ch_data[ch].n = val;
 
 	err = fwnode_property_read_u32(gain_child, "adi,rfb-ohms", &val);
@@ -841,9 +753,9 @@ static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac,
 	dac->ch_data[ch].gain_offset = val;
 
 	offset = abs((s32)val);
-	reg |= ad3552r_field_prep((offset >> 8), AD3552R_MASK_CH_OFFSET_BIT_8);
+	reg |= FIELD_PREP(AD3552R_MASK_CH_OFFSET_BIT_8, (offset >> 8));
 
-	reg |= ad3552r_field_prep((s32)val < 0, AD3552R_MASK_CH_OFFSET_POLARITY);
+	reg |= FIELD_PREP(AD3552R_MASK_CH_OFFSET_POLARITY, (s32)val < 0);
 	addr = AD3552R_REG_ADDR_CH_GAIN(ch);
 	err = ad3552r_write_reg(dac, addr,
 				offset & AD3552R_MASK_CH_OFFSET_BITS_0_7);
@@ -886,9 +798,9 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
 	}
 
 	err = ad3552r_update_reg_field(dac,
-				       addr_mask_map[AD3552R_VREF_SELECT][0],
-				       addr_mask_map[AD3552R_VREF_SELECT][1],
-				       val);
+				       AD3552R_REG_ADDR_SH_REFERENCE_CONFIG,
+				       AD3552R_MASK_REFERENCE_VOLTAGE_SEL,
+				       FIELD_PREP(AD3552R_MASK_REFERENCE_VOLTAGE_SEL, val));
 	if (err)
 		return err;
 
@@ -900,9 +812,9 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
 		}
 
 		err = ad3552r_update_reg_field(dac,
-					       addr_mask_map[AD3552R_SDO_DRIVE_STRENGTH][0],
-					       addr_mask_map[AD3552R_SDO_DRIVE_STRENGTH][1],
-					       val);
+					       AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
+					       AD3552R_MASK_SDO_DRIVE_STRENGTH,
+					       FIELD_PREP(AD3552R_MASK_SDO_DRIVE_STRENGTH, val));
 		if (err)
 			return err;
 	}
@@ -938,9 +850,15 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
 						     "Invalid adi,output-range-microvolt value\n");
 
 			val = err;
-			err = ad3552r_set_ch_value(dac,
-						   AD3552R_CH_OUTPUT_RANGE_SEL,
-						   ch, val);
+			if (ch == 0)
+				val = FIELD_PREP(AD3552R_MASK_CH_OUTPUT_RANGE_SEL(0), val);
+			else
+				val = FIELD_PREP(AD3552R_MASK_CH_OUTPUT_RANGE_SEL(1), val);
+
+			err = ad3552r_update_reg_field(dac,
+						       AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE,
+						       AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch),
+						       val);
 			if (err)
 				return err;
 
@@ -958,7 +876,14 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
 		ad3552r_calc_gain_and_offset(dac, ch);
 		dac->enabled_ch |= BIT(ch);
 
-		err = ad3552r_set_ch_value(dac, AD3552R_CH_SELECT, ch, 1);
+		if (ch == 0)
+			val = FIELD_PREP(AD3552R_MASK_CH(0), 1);
+		else
+			val = FIELD_PREP(AD3552R_MASK_CH(1), 1);
+
+		err = ad3552r_update_reg_field(dac,
+					       AD3552R_REG_ADDR_CH_SELECT_16B,
+					       AD3552R_MASK_CH(ch), val);
 		if (err < 0)
 			return err;
 
@@ -970,8 +895,15 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
 	/* Disable unused channels */
 	for_each_clear_bit(ch, &dac->enabled_ch,
 			   dac->model_data->num_hw_channels) {
-		err = ad3552r_set_ch_value(dac, AD3552R_CH_AMPLIFIER_POWERDOWN,
-					   ch, 1);
+		if (ch == 0)
+			val = FIELD_PREP(AD3552R_MASK_CH_OUTPUT_RANGE_SEL(0), 1);
+		else
+			val = FIELD_PREP(AD3552R_MASK_CH_OUTPUT_RANGE_SEL(1), 1);
+
+		err = ad3552r_update_reg_field(dac,
+					       AD3552R_REG_ADDR_POWERDOWN_CONFIG,
+					       AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch),
+					       val);
 		if (err)
 			return err;
 	}

-- 
2.45.0.rc1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v3 08/10] iio: dac: ad3552r: extract common code (no changes in behavior intended)
  2024-09-19  9:19 [PATCH v3 00/10] iio: add support for the ad3552r AXI DAC IP Angelo Dureghello
                   ` (6 preceding siblings ...)
  2024-09-19  9:20 ` [PATCH v3 07/10] iio: dac: ad3552r: changes to use FIELD_PREP Angelo Dureghello
@ 2024-09-19  9:20 ` Angelo Dureghello
  2024-09-29 11:57   ` Jonathan Cameron
  2024-09-19  9:20 ` [PATCH v3 09/10] iio: dac: ad3552r: add axi platform driver Angelo Dureghello
  2024-09-19  9:20 ` [PATCH v3 10/10] iio: backend: adi-axi-dac: add registering of child fdt node Angelo Dureghello
  9 siblings, 1 reply; 59+ messages in thread
From: Angelo Dureghello @ 2024-09-19  9:20 UTC (permalink / raw)
  To: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Jonathan Cameron,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan
  Cc: linux-iio, linux-kernel, devicetree, dlechner, Angelo Dureghello

From: Angelo Dureghello <adureghello@baylibre.com>

Extracting common code, to share common code to be used later
by the AXI driver version (ad3552r-axi.c).

Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
---
 drivers/iio/dac/Makefile         |   2 +-
 drivers/iio/dac/ad3552r-common.c | 173 +++++++++++++++++++++++
 drivers/iio/dac/ad3552r.c        | 293 ++++-----------------------------------
 drivers/iio/dac/ad3552r.h        | 190 +++++++++++++++++++++++++
 4 files changed, 390 insertions(+), 268 deletions(-)

diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index 2cf148f16306..56a125f56284 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -4,7 +4,7 @@
 #
 
 # When adding new entries keep the list in alphabetical order
-obj-$(CONFIG_AD3552R) += ad3552r.o
+obj-$(CONFIG_AD3552R) += ad3552r.o ad3552r-common.o
 obj-$(CONFIG_AD5360) += ad5360.o
 obj-$(CONFIG_AD5380) += ad5380.o
 obj-$(CONFIG_AD5421) += ad5421.o
diff --git a/drivers/iio/dac/ad3552r-common.c b/drivers/iio/dac/ad3552r-common.c
new file mode 100644
index 000000000000..624f3f97cdea
--- /dev/null
+++ b/drivers/iio/dac/ad3552r-common.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright (c) 2010-2024 Analog Devices Inc.
+// Copyright (c) 2024 Baylibre, SAS
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+
+#include "ad3552r.h"
+
+const s32 ad3552r_ch_ranges[AD3552R_MAX_RANGES][2] = {
+	[AD3552R_CH_OUTPUT_RANGE_0__2P5V]	= { 0, 2500 },
+	[AD3552R_CH_OUTPUT_RANGE_0__5V]		= { 0, 5000 },
+	[AD3552R_CH_OUTPUT_RANGE_0__10V]	= { 0, 10000 },
+	[AD3552R_CH_OUTPUT_RANGE_NEG_5__5V]	= { -5000, 5000 },
+	[AD3552R_CH_OUTPUT_RANGE_NEG_10__10V]	= { -10000, 10000 }
+};
+EXPORT_SYMBOL(ad3552r_ch_ranges);
+
+const s32 ad3542r_ch_ranges[AD3542R_MAX_RANGES][2] = {
+	[AD3542R_CH_OUTPUT_RANGE_0__2P5V]	= { 0, 2500 },
+	[AD3542R_CH_OUTPUT_RANGE_0__3V]		= { 0, 3000 },
+	[AD3542R_CH_OUTPUT_RANGE_0__5V]		= { 0, 5000 },
+	[AD3542R_CH_OUTPUT_RANGE_0__10V]	= { 0, 10000 },
+	[AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V]	= { -2500, 7500 },
+	[AD3542R_CH_OUTPUT_RANGE_NEG_5__5V]	= { -5000, 5000 }
+};
+EXPORT_SYMBOL(ad3542r_ch_ranges);
+
+u16 ad3552r_calc_custom_gain(u8 p, u8 n, s16 goffs)
+{
+	u16 reg;
+
+	reg = FIELD_PREP(AD3552R_MASK_CH_RANGE_OVERRIDE, 1);
+	reg |= FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_P, p);
+	reg |= FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_N, n);
+	reg |= FIELD_PREP(AD3552R_MASK_CH_OFFSET_BIT_8, abs((s32)goffs) >> 8);
+	reg |= FIELD_PREP(AD3552R_MASK_CH_OFFSET_POLARITY, (s32)goffs < 0);
+
+	return reg;
+}
+
+int ad3552r_get_ref_voltage(struct device *dev)
+{
+	int voltage;
+	int delta = 100000;
+
+	voltage = devm_regulator_get_enable_read_voltage(dev, "vref");
+	if (voltage < 0 && voltage != -ENODEV)
+		return dev_err_probe(dev, voltage,
+				     "Error getting vref voltage\n");
+
+	if (voltage == -ENODEV) {
+		if (device_property_read_bool(dev, "adi,vref-out-en"))
+			return AD3552R_INTERNAL_VREF_PIN_2P5V;
+		else
+			return AD3552R_INTERNAL_VREF_PIN_FLOATING;
+	}
+
+	if (voltage > 2500000 + delta || voltage < 2500000 - delta) {
+		dev_warn(dev, "vref-supply must be 2.5V");
+		return -EINVAL;
+	}
+
+	return AD3552R_EXTERNAL_VREF_PIN_INPUT;
+}
+
+int ad3552r_get_drive_strength(struct device *dev, u32 *val)
+{
+	int err;
+
+	err = device_property_read_u32(dev, "adi,sdo-drive-strength", val);
+	if (err)
+		return err;
+
+	if (*val > 3) {
+		dev_err(dev,
+			"adi,sdo-drive-strength must be less than 4\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int ad3552r_get_custom_gain(struct device *dev, struct fwnode_handle *child,
+			    u8 *gs_p, u8 *gs_n, u16 *rfb, s16 *goffs)
+{
+	int err;
+	u32 val;
+	struct fwnode_handle *gain_child __free(fwnode_handle) =
+				fwnode_get_named_child_node(child,
+				"custom-output-range-config");
+
+	if (!gain_child)
+		return dev_err_probe(dev, -EINVAL,
+				     "custom-output-range-config mandatory\n");
+
+	err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-p", &val);
+	if (err)
+		return dev_err_probe(dev, err,
+				     "adi,gain-scaling-p mandatory\n");
+	*gs_p = val;
+
+	err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-n", &val);
+	if (err)
+		return dev_err_probe(dev, err,
+				     "adi,gain-scaling-n property mandatory\n");
+	*gs_n = val;
+
+	err = fwnode_property_read_u32(gain_child, "adi,rfb-ohms", &val);
+	if (err)
+		return dev_err_probe(dev, err,
+				     "adi,rfb-ohms mandatory\n");
+	*rfb = val;
+
+	err = fwnode_property_read_u32(gain_child, "adi,gain-offset", &val);
+	if (err)
+		return dev_err_probe(dev, err,
+				     "adi,gain-offset mandatory\n");
+	*goffs = val;
+
+	return 0;
+}
+
+static int ad3552r_find_range(u16 id, s32 *vals)
+{
+	int i, len;
+	const s32 (*ranges)[2];
+
+	if (id == AD3542R_ID) {
+		len = ARRAY_SIZE(ad3542r_ch_ranges);
+		ranges = ad3542r_ch_ranges;
+	} else {
+		len = ARRAY_SIZE(ad3552r_ch_ranges);
+		ranges = ad3552r_ch_ranges;
+	}
+
+	for (i = 0; i < len; i++)
+		if (vals[0] == ranges[i][0] * 1000 &&
+		    vals[1] == ranges[i][1] * 1000)
+			return i;
+
+	return -EINVAL;
+}
+
+int ad3552r_get_output_range(struct device *dev, enum ad3552r_id chip_id,
+			     struct fwnode_handle *child, u32 *val)
+{
+	int ret;
+	s32 vals[2];
+
+	/* This property is optional, so returning -ENOENT if missing */
+	if (!fwnode_property_present(child, "adi,output-range-microvolt"))
+		return -ENOENT;
+
+	ret = fwnode_property_read_u32_array(child,
+					     "adi,output-range-microvolt",
+					     vals, 2);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				"invalid adi,output-range-microvolt\n");
+
+	ret = ad3552r_find_range(chip_id, vals);
+	if (ret < 0)
+		return dev_err_probe(dev, ret,
+			"invalid adi,output-range-microvolt value\n");
+
+	*val = ret;
+
+	return 0;
+}
diff --git a/drivers/iio/dac/ad3552r.c b/drivers/iio/dac/ad3552r.c
index c27706c5ba10..173282e5e1a1 100644
--- a/drivers/iio/dac/ad3552r.c
+++ b/drivers/iio/dac/ad3552r.c
@@ -11,185 +11,9 @@
 #include <linux/iio/trigger_consumer.h>
 #include <linux/iopoll.h>
 #include <linux/kernel.h>
-#include <linux/regulator/consumer.h>
 #include <linux/spi/spi.h>
 
-/* Register addresses */
-/* Primary address space */
-#define AD3552R_REG_ADDR_INTERFACE_CONFIG_A		0x00
-#define   AD3552R_MASK_SOFTWARE_RESET			(BIT(7) | BIT(0))
-#define   AD3552R_MASK_ADDR_ASCENSION			BIT(5)
-#define   AD3552R_MASK_SDO_ACTIVE			BIT(4)
-#define AD3552R_REG_ADDR_INTERFACE_CONFIG_B		0x01
-#define   AD3552R_MASK_SINGLE_INST			BIT(7)
-#define   AD3552R_MASK_SHORT_INSTRUCTION		BIT(3)
-#define AD3552R_REG_ADDR_DEVICE_CONFIG			0x02
-#define   AD3552R_MASK_DEVICE_STATUS(n)			BIT(4 + (n))
-#define   AD3552R_MASK_CUSTOM_MODES			GENMASK(3, 2)
-#define   AD3552R_MASK_OPERATING_MODES			GENMASK(1, 0)
-#define AD3552R_REG_ADDR_CHIP_TYPE			0x03
-#define   AD3552R_MASK_CLASS				GENMASK(7, 0)
-#define AD3552R_REG_ADDR_PRODUCT_ID_L			0x04
-#define AD3552R_REG_ADDR_PRODUCT_ID_H			0x05
-#define AD3552R_REG_ADDR_CHIP_GRADE			0x06
-#define   AD3552R_MASK_GRADE				GENMASK(7, 4)
-#define   AD3552R_MASK_DEVICE_REVISION			GENMASK(3, 0)
-#define AD3552R_REG_ADDR_SCRATCH_PAD			0x0A
-#define AD3552R_REG_ADDR_SPI_REVISION			0x0B
-#define AD3552R_REG_ADDR_VENDOR_L			0x0C
-#define AD3552R_REG_ADDR_VENDOR_H			0x0D
-#define AD3552R_REG_ADDR_STREAM_MODE			0x0E
-#define   AD3552R_MASK_LENGTH				GENMASK(7, 0)
-#define AD3552R_REG_ADDR_TRANSFER_REGISTER		0x0F
-#define   AD3552R_MASK_MULTI_IO_MODE			GENMASK(7, 6)
-#define   AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE		BIT(2)
-#define AD3552R_REG_ADDR_INTERFACE_CONFIG_C		0x10
-#define   AD3552R_MASK_CRC_ENABLE			(GENMASK(7, 6) |\
-							 GENMASK(1, 0))
-#define   AD3552R_MASK_STRICT_REGISTER_ACCESS		BIT(5)
-#define AD3552R_REG_ADDR_INTERFACE_STATUS_A		0x11
-#define   AD3552R_MASK_INTERFACE_NOT_READY		BIT(7)
-#define   AD3552R_MASK_CLOCK_COUNTING_ERROR		BIT(5)
-#define   AD3552R_MASK_INVALID_OR_NO_CRC		BIT(3)
-#define   AD3552R_MASK_WRITE_TO_READ_ONLY_REGISTER	BIT(2)
-#define   AD3552R_MASK_PARTIAL_REGISTER_ACCESS		BIT(1)
-#define   AD3552R_MASK_REGISTER_ADDRESS_INVALID		BIT(0)
-#define AD3552R_REG_ADDR_INTERFACE_CONFIG_D		0x14
-#define   AD3552R_MASK_ALERT_ENABLE_PULLUP		BIT(6)
-#define   AD3552R_MASK_MEM_CRC_EN			BIT(4)
-#define   AD3552R_MASK_SDO_DRIVE_STRENGTH		GENMASK(3, 2)
-#define   AD3552R_MASK_DUAL_SPI_SYNCHROUNOUS_EN		BIT(1)
-#define   AD3552R_MASK_SPI_CONFIG_DDR			BIT(0)
-#define AD3552R_REG_ADDR_SH_REFERENCE_CONFIG		0x15
-#define   AD3552R_MASK_IDUMP_FAST_MODE			BIT(6)
-#define   AD3552R_MASK_SAMPLE_HOLD_DIFFERENTIAL_USER_EN	BIT(5)
-#define   AD3552R_MASK_SAMPLE_HOLD_USER_TRIM		GENMASK(4, 3)
-#define   AD3552R_MASK_SAMPLE_HOLD_USER_ENABLE		BIT(2)
-#define   AD3552R_MASK_REFERENCE_VOLTAGE_SEL		GENMASK(1, 0)
-#define AD3552R_REG_ADDR_ERR_ALARM_MASK			0x16
-#define   AD3552R_MASK_REF_RANGE_ALARM			BIT(6)
-#define   AD3552R_MASK_CLOCK_COUNT_ERR_ALARM		BIT(5)
-#define   AD3552R_MASK_MEM_CRC_ERR_ALARM		BIT(4)
-#define   AD3552R_MASK_SPI_CRC_ERR_ALARM		BIT(3)
-#define   AD3552R_MASK_WRITE_TO_READ_ONLY_ALARM		BIT(2)
-#define   AD3552R_MASK_PARTIAL_REGISTER_ACCESS_ALARM	BIT(1)
-#define   AD3552R_MASK_REGISTER_ADDRESS_INVALID_ALARM	BIT(0)
-#define AD3552R_REG_ADDR_ERR_STATUS			0x17
-#define   AD3552R_MASK_REF_RANGE_ERR_STATUS			BIT(6)
-#define   AD3552R_MASK_DUAL_SPI_STREAM_EXCEEDS_DAC_ERR_STATUS	BIT(5)
-#define   AD3552R_MASK_MEM_CRC_ERR_STATUS			BIT(4)
-#define   AD3552R_MASK_RESET_STATUS				BIT(0)
-#define AD3552R_REG_ADDR_POWERDOWN_CONFIG		0x18
-#define   AD3552R_MASK_CH_DAC_POWERDOWN(ch)		BIT(4 + (ch))
-#define   AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(ch)	BIT(ch)
-#define AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE		0x19
-#define   AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch)		((ch) ? GENMASK(7, 4) :\
-							 GENMASK(3, 0))
-#define AD3552R_REG_ADDR_CH_OFFSET(ch)			(0x1B + (ch) * 2)
-#define   AD3552R_MASK_CH_OFFSET_BITS_0_7		GENMASK(7, 0)
-#define AD3552R_REG_ADDR_CH_GAIN(ch)			(0x1C + (ch) * 2)
-#define   AD3552R_MASK_CH_RANGE_OVERRIDE		BIT(7)
-#define   AD3552R_MASK_CH_GAIN_SCALING_N		GENMASK(6, 5)
-#define   AD3552R_MASK_CH_GAIN_SCALING_P		GENMASK(4, 3)
-#define   AD3552R_MASK_CH_OFFSET_POLARITY		BIT(2)
-#define   AD3552R_MASK_CH_OFFSET_BIT_8			BIT(0)
-/*
- * Secondary region
- * For multibyte registers specify the highest address because the access is
- * done in descending order
- */
-#define AD3552R_SECONDARY_REGION_START			0x28
-#define AD3552R_REG_ADDR_HW_LDAC_16B			0x28
-#define AD3552R_REG_ADDR_CH_DAC_16B(ch)			(0x2C - (1 - ch) * 2)
-#define AD3552R_REG_ADDR_DAC_PAGE_MASK_16B		0x2E
-#define AD3552R_REG_ADDR_CH_SELECT_16B			0x2F
-#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_16B		0x31
-#define AD3552R_REG_ADDR_SW_LDAC_16B			0x32
-#define AD3552R_REG_ADDR_CH_INPUT_16B(ch)		(0x36 - (1 - ch) * 2)
-/* 3 bytes registers */
-#define AD3552R_REG_START_24B				0x37
-#define AD3552R_REG_ADDR_HW_LDAC_24B			0x37
-#define AD3552R_REG_ADDR_CH_DAC_24B(ch)			(0x3D - (1 - ch) * 3)
-#define AD3552R_REG_ADDR_DAC_PAGE_MASK_24B		0x40
-#define AD3552R_REG_ADDR_CH_SELECT_24B			0x41
-#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_24B		0x44
-#define AD3552R_REG_ADDR_SW_LDAC_24B			0x45
-#define AD3552R_REG_ADDR_CH_INPUT_24B(ch)		(0x4B - (1 - ch) * 3)
-
-/* Useful defines */
-#define AD3552R_MAX_CH					2
-#define AD3552R_MASK_CH(ch)				BIT(ch)
-#define AD3552R_MASK_ALL_CH				GENMASK(1, 0)
-#define AD3552R_MAX_REG_SIZE				3
-#define AD3552R_READ_BIT				BIT(7)
-#define AD3552R_ADDR_MASK				GENMASK(6, 0)
-#define AD3552R_MASK_DAC_12B				0xFFF0
-#define AD3552R_DEFAULT_CONFIG_B_VALUE			0x8
-#define AD3552R_SCRATCH_PAD_TEST_VAL1			0x34
-#define AD3552R_SCRATCH_PAD_TEST_VAL2			0xB2
-#define AD3552R_GAIN_SCALE				1000
-#define AD3552R_LDAC_PULSE_US				100
-
-enum ad3552r_ch_vref_select {
-	/* Internal source with Vref I/O floating */
-	AD3552R_INTERNAL_VREF_PIN_FLOATING,
-	/* Internal source with Vref I/O at 2.5V */
-	AD3552R_INTERNAL_VREF_PIN_2P5V,
-	/* External source with Vref I/O as input */
-	AD3552R_EXTERNAL_VREF_PIN_INPUT
-};
-
-enum ad3552r_id {
-	AD3541R_ID = 0x400b,
-	AD3542R_ID = 0x4009,
-	AD3551R_ID = 0x400a,
-	AD3552R_ID = 0x4008,
-};
-
-enum ad3552r_ch_output_range {
-	/* Range from 0 V to 2.5 V. Requires Rfb1x connection */
-	AD3552R_CH_OUTPUT_RANGE_0__2P5V,
-	/* Range from 0 V to 5 V. Requires Rfb1x connection  */
-	AD3552R_CH_OUTPUT_RANGE_0__5V,
-	/* Range from 0 V to 10 V. Requires Rfb2x connection  */
-	AD3552R_CH_OUTPUT_RANGE_0__10V,
-	/* Range from -5 V to 5 V. Requires Rfb2x connection  */
-	AD3552R_CH_OUTPUT_RANGE_NEG_5__5V,
-	/* Range from -10 V to 10 V. Requires Rfb4x connection  */
-	AD3552R_CH_OUTPUT_RANGE_NEG_10__10V,
-};
-
-static const s32 ad3552r_ch_ranges[][2] = {
-	[AD3552R_CH_OUTPUT_RANGE_0__2P5V]	= {0, 2500},
-	[AD3552R_CH_OUTPUT_RANGE_0__5V]		= {0, 5000},
-	[AD3552R_CH_OUTPUT_RANGE_0__10V]	= {0, 10000},
-	[AD3552R_CH_OUTPUT_RANGE_NEG_5__5V]	= {-5000, 5000},
-	[AD3552R_CH_OUTPUT_RANGE_NEG_10__10V]	= {-10000, 10000}
-};
-
-enum ad3542r_ch_output_range {
-	/* Range from 0 V to 2.5 V. Requires Rfb1x connection */
-	AD3542R_CH_OUTPUT_RANGE_0__2P5V,
-	/* Range from 0 V to 3 V. Requires Rfb1x connection  */
-	AD3542R_CH_OUTPUT_RANGE_0__3V,
-	/* Range from 0 V to 5 V. Requires Rfb1x connection  */
-	AD3542R_CH_OUTPUT_RANGE_0__5V,
-	/* Range from 0 V to 10 V. Requires Rfb2x connection  */
-	AD3542R_CH_OUTPUT_RANGE_0__10V,
-	/* Range from -2.5 V to 7.5 V. Requires Rfb2x connection  */
-	AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V,
-	/* Range from -5 V to 5 V. Requires Rfb2x connection  */
-	AD3542R_CH_OUTPUT_RANGE_NEG_5__5V,
-};
-
-static const s32 ad3542r_ch_ranges[][2] = {
-	[AD3542R_CH_OUTPUT_RANGE_0__2P5V]	= {0, 2500},
-	[AD3542R_CH_OUTPUT_RANGE_0__3V]		= {0, 3000},
-	[AD3542R_CH_OUTPUT_RANGE_0__5V]		= {0, 5000},
-	[AD3542R_CH_OUTPUT_RANGE_0__10V]	= {0, 10000},
-	[AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V]	= {-2500, 7500},
-	[AD3542R_CH_OUTPUT_RANGE_NEG_5__5V]	= {-5000, 5000}
-};
+#include "ad3552r.h"
 
 enum ad3552r_ch_gain_scaling {
 	/* Gain scaling of 1 */
@@ -693,75 +517,35 @@ static void ad3552r_calc_gain_and_offset(struct ad3552r_desc *dac, s32 ch)
 	dac->ch_data[ch].offset_dec = div_s64(tmp, span);
 }
 
-static int ad3552r_find_range(const struct ad3552r_model_data *model_data,
-			      s32 *vals)
-{
-	int i;
-
-	for (i = 0; i < model_data->num_ranges; i++)
-		if (vals[0] == model_data->ranges_table[i][0] * 1000 &&
-		    vals[1] == model_data->ranges_table[i][1] * 1000)
-			return i;
-
-	return -EINVAL;
-}
-
 static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac,
 					 struct fwnode_handle *child,
 					 u32 ch)
 {
 	struct device *dev = &dac->spi->dev;
-	u32 val;
 	int err;
 	u8 addr;
-	u16 reg = 0, offset;
-
-	struct fwnode_handle *gain_child __free(fwnode_handle)
-		= fwnode_get_named_child_node(child,
-					      "custom-output-range-config");
-	if (!gain_child)
-		return dev_err_probe(dev, -EINVAL,
-				     "mandatory custom-output-range-config property missing\n");
-
-	dac->ch_data[ch].range_override = 1;
-	reg |= FIELD_PREP(AD3552R_MASK_CH_RANGE_OVERRIDE, 1);
-
-	err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-p", &val);
-	if (err)
-		return dev_err_probe(dev, err,
-				     "mandatory adi,gain-scaling-p property missing\n");
-	reg |= FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_P, val);
-	dac->ch_data[ch].p = val;
-
-	err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-n", &val);
-	if (err)
-		return dev_err_probe(dev, err,
-				     "mandatory adi,gain-scaling-n property missing\n");
-	reg |= FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_N, val);
-	dac->ch_data[ch].n = val;
-
-	err = fwnode_property_read_u32(gain_child, "adi,rfb-ohms", &val);
-	if (err)
-		return dev_err_probe(dev, err,
-				     "mandatory adi,rfb-ohms property missing\n");
-	dac->ch_data[ch].rfb = val;
+	u16 reg;
 
-	err = fwnode_property_read_u32(gain_child, "adi,gain-offset", &val);
+	err = ad3552r_get_custom_gain(dev, child,
+				      &dac->ch_data[ch].p,
+				      &dac->ch_data[ch].n,
+				      &dac->ch_data[ch].rfb,
+				      &dac->ch_data[ch].gain_offset);
 	if (err)
-		return dev_err_probe(dev, err,
-				     "mandatory adi,gain-offset property missing\n");
-	dac->ch_data[ch].gain_offset = val;
+		return err;
 
-	offset = abs((s32)val);
-	reg |= FIELD_PREP(AD3552R_MASK_CH_OFFSET_BIT_8, (offset >> 8));
+	dac->ch_data[ch].range_override = 1;
 
-	reg |= FIELD_PREP(AD3552R_MASK_CH_OFFSET_POLARITY, (s32)val < 0);
 	addr = AD3552R_REG_ADDR_CH_GAIN(ch);
 	err = ad3552r_write_reg(dac, addr,
-				offset & AD3552R_MASK_CH_OFFSET_BITS_0_7);
+				abs((s32)dac->ch_data[ch].gain_offset) &
+				AD3552R_MASK_CH_OFFSET_BITS_0_7);
 	if (err)
 		return dev_err_probe(dev, err, "Error writing register\n");
 
+	reg = ad3552r_calc_custom_gain(dac->ch_data[ch].p, dac->ch_data[ch].n,
+				       dac->ch_data[ch].gain_offset);
+
 	err = ad3552r_write_reg(dac, addr, reg);
 	if (err)
 		return dev_err_probe(dev, err, "Error writing register\n");
@@ -772,30 +556,19 @@ static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac,
 static int ad3552r_configure_device(struct ad3552r_desc *dac)
 {
 	struct device *dev = &dac->spi->dev;
-	int err, cnt = 0, voltage, delta = 100000;
-	u32 vals[2], val, ch;
+	int err, cnt = 0;
+	u32 val, ch;
 
 	dac->gpio_ldac = devm_gpiod_get_optional(dev, "ldac", GPIOD_OUT_HIGH);
 	if (IS_ERR(dac->gpio_ldac))
 		return dev_err_probe(dev, PTR_ERR(dac->gpio_ldac),
 				     "Error getting gpio ldac");
 
-	voltage = devm_regulator_get_enable_read_voltage(dev, "vref");
-	if (voltage < 0 && voltage != -ENODEV)
-		return dev_err_probe(dev, voltage, "Error getting vref voltage\n");
+	err = ad3552r_get_ref_voltage(dev);
+	if (err < 0)
+		return err;
 
-	if (voltage == -ENODEV) {
-		if (device_property_read_bool(dev, "adi,vref-out-en"))
-			val = AD3552R_INTERNAL_VREF_PIN_2P5V;
-		else
-			val = AD3552R_INTERNAL_VREF_PIN_FLOATING;
-	} else {
-		if (voltage > 2500000 + delta || voltage < 2500000 - delta) {
-			dev_warn(dev, "vref-supply must be 2.5V");
-			return -EINVAL;
-		}
-		val = AD3552R_EXTERNAL_VREF_PIN_INPUT;
-	}
+	val = err;
 
 	err = ad3552r_update_reg_field(dac,
 				       AD3552R_REG_ADDR_SH_REFERENCE_CONFIG,
@@ -804,13 +577,8 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
 	if (err)
 		return err;
 
-	err = device_property_read_u32(dev, "adi,sdo-drive-strength", &val);
+	err = ad3552r_get_drive_strength(dev, &val);
 	if (!err) {
-		if (val > 3) {
-			dev_err(dev, "adi,sdo-drive-strength must be less than 4\n");
-			return -EINVAL;
-		}
-
 		err = ad3552r_update_reg_field(dac,
 					       AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
 					       AD3552R_MASK_SDO_DRIVE_STRENGTH,
@@ -835,21 +603,12 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
 					     "reg must be less than %d\n",
 					     dac->model_data->num_hw_channels);
 
-		if (fwnode_property_present(child, "adi,output-range-microvolt")) {
-			err = fwnode_property_read_u32_array(child,
-							     "adi,output-range-microvolt",
-							     vals,
-							     2);
-			if (err)
-				return dev_err_probe(dev, err,
-					"adi,output-range-microvolt property could not be parsed\n");
-
-			err = ad3552r_find_range(dac->model_data, vals);
-			if (err < 0)
-				return dev_err_probe(dev, err,
-						     "Invalid adi,output-range-microvolt value\n");
+		err = ad3552r_get_output_range(dev, dac->model_data->chip_id,
+					       child, &val);
+		if (err && err != -ENOENT)
+			return err;
 
-			val = err;
+		if (!err) {
 			if (ch == 0)
 				val = FIELD_PREP(AD3552R_MASK_CH_OUTPUT_RANGE_SEL(0), val);
 			else
diff --git a/drivers/iio/dac/ad3552r.h b/drivers/iio/dac/ad3552r.h
new file mode 100644
index 000000000000..b1caa3c3e807
--- /dev/null
+++ b/drivers/iio/dac/ad3552r.h
@@ -0,0 +1,190 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * AD3552R Digital <-> Analog converters common header
+ *
+ * Copyright 2021-2024 Analog Devices Inc.
+ * Author: Angelo Dureghello <adureghello@baylibre.com>
+ */
+
+#ifndef __DRIVERS_IIO_DAC_AD3552R_H__
+#define __DRIVERS_IIO_DAC_AD3552R_H__
+
+/* Register addresses */
+/* Primary address space */
+#define AD3552R_REG_ADDR_INTERFACE_CONFIG_A		0x00
+#define   AD3552R_MASK_SOFTWARE_RESET			(BIT(7) | BIT(0))
+#define   AD3552R_MASK_ADDR_ASCENSION			BIT(5)
+#define   AD3552R_MASK_SDO_ACTIVE			BIT(4)
+#define AD3552R_REG_ADDR_INTERFACE_CONFIG_B		0x01
+#define   AD3552R_MASK_SINGLE_INST			BIT(7)
+#define   AD3552R_MASK_SHORT_INSTRUCTION		BIT(3)
+#define AD3552R_REG_ADDR_DEVICE_CONFIG			0x02
+#define   AD3552R_MASK_DEVICE_STATUS(n)			BIT(4 + (n))
+#define   AD3552R_MASK_CUSTOM_MODES			GENMASK(3, 2)
+#define   AD3552R_MASK_OPERATING_MODES			GENMASK(1, 0)
+#define AD3552R_REG_ADDR_CHIP_TYPE			0x03
+#define   AD3552R_MASK_CLASS				GENMASK(7, 0)
+#define AD3552R_REG_ADDR_PRODUCT_ID_L			0x04
+#define AD3552R_REG_ADDR_PRODUCT_ID_H			0x05
+#define AD3552R_REG_ADDR_CHIP_GRADE			0x06
+#define   AD3552R_MASK_GRADE				GENMASK(7, 4)
+#define   AD3552R_MASK_DEVICE_REVISION			GENMASK(3, 0)
+#define AD3552R_REG_ADDR_SCRATCH_PAD			0x0A
+#define AD3552R_REG_ADDR_SPI_REVISION			0x0B
+#define AD3552R_REG_ADDR_VENDOR_L			0x0C
+#define AD3552R_REG_ADDR_VENDOR_H			0x0D
+#define AD3552R_REG_ADDR_STREAM_MODE			0x0E
+#define   AD3552R_MASK_LENGTH				GENMASK(7, 0)
+#define AD3552R_REG_ADDR_TRANSFER_REGISTER		0x0F
+#define   AD3552R_MASK_MULTI_IO_MODE			GENMASK(7, 6)
+#define   AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE		BIT(2)
+#define AD3552R_REG_ADDR_INTERFACE_CONFIG_C		0x10
+#define   AD3552R_MASK_CRC_ENABLE			(GENMASK(7, 6) |\
+							 GENMASK(1, 0))
+#define   AD3552R_MASK_STRICT_REGISTER_ACCESS		BIT(5)
+#define AD3552R_REG_ADDR_INTERFACE_STATUS_A		0x11
+#define   AD3552R_MASK_INTERFACE_NOT_READY		BIT(7)
+#define   AD3552R_MASK_CLOCK_COUNTING_ERROR		BIT(5)
+#define   AD3552R_MASK_INVALID_OR_NO_CRC		BIT(3)
+#define   AD3552R_MASK_WRITE_TO_READ_ONLY_REGISTER	BIT(2)
+#define   AD3552R_MASK_PARTIAL_REGISTER_ACCESS		BIT(1)
+#define   AD3552R_MASK_REGISTER_ADDRESS_INVALID		BIT(0)
+#define AD3552R_REG_ADDR_INTERFACE_CONFIG_D		0x14
+#define   AD3552R_MASK_ALERT_ENABLE_PULLUP		BIT(6)
+#define   AD3552R_MASK_MEM_CRC_EN			BIT(4)
+#define   AD3552R_MASK_SDO_DRIVE_STRENGTH		GENMASK(3, 2)
+#define   AD3552R_MASK_DUAL_SPI_SYNCHROUNOUS_EN		BIT(1)
+#define   AD3552R_MASK_SPI_CONFIG_DDR			BIT(0)
+#define AD3552R_REG_ADDR_SH_REFERENCE_CONFIG		0x15
+#define   AD3552R_MASK_IDUMP_FAST_MODE			BIT(6)
+#define   AD3552R_MASK_SAMPLE_HOLD_DIFF_USER_EN		BIT(5)
+#define   AD3552R_MASK_SAMPLE_HOLD_USER_TRIM		GENMASK(4, 3)
+#define   AD3552R_MASK_SAMPLE_HOLD_USER_ENABLE		BIT(2)
+#define   AD3552R_MASK_REFERENCE_VOLTAGE_SEL		GENMASK(1, 0)
+#define AD3552R_REG_ADDR_ERR_ALARM_MASK			0x16
+#define   AD3552R_MASK_REF_RANGE_ALARM			BIT(6)
+#define   AD3552R_MASK_CLOCK_COUNT_ERR_ALARM		BIT(5)
+#define   AD3552R_MASK_MEM_CRC_ERR_ALARM		BIT(4)
+#define   AD3552R_MASK_SPI_CRC_ERR_ALARM		BIT(3)
+#define   AD3552R_MASK_WRITE_TO_READ_ONLY_ALARM		BIT(2)
+#define   AD3552R_MASK_PARTIAL_REGISTER_ACCESS_ALARM	BIT(1)
+#define   AD3552R_MASK_REGISTER_ADDRESS_INVALID_ALARM	BIT(0)
+#define AD3552R_REG_ADDR_ERR_STATUS			0x17
+#define   AD3552R_MASK_REF_RANGE_ERR_STATUS		BIT(6)
+#define   AD3552R_MASK_STREAM_EXCEEDS_DAC_ERR_STATUS	BIT(5)
+#define   AD3552R_MASK_MEM_CRC_ERR_STATUS		BIT(4)
+#define   AD3552R_MASK_RESET_STATUS			BIT(0)
+#define AD3552R_REG_ADDR_POWERDOWN_CONFIG		0x18
+#define   AD3552R_MASK_CH_DAC_POWERDOWN(ch)		BIT(4 + (ch))
+#define   AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(ch)	BIT(ch)
+#define AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE		0x19
+#define   AD3552R_MASK_CH0_RANGE			GENMASK(2, 0)
+#define   AD3552R_MASK_CH1_RANGE			GENMASK(6, 4)
+#define   AD3552R_MASK_CH_OUTPUT_RANGE			GENMASK(7, 0)
+#define   AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch)		((ch) ? \
+							 GENMASK(7, 4) : \
+							 GENMASK(3, 0))
+#define AD3552R_REG_ADDR_CH_OFFSET(ch)			(0x1B + (ch) * 2)
+#define   AD3552R_MASK_CH_OFFSET_BITS_0_7		GENMASK(7, 0)
+#define AD3552R_REG_ADDR_CH_GAIN(ch)			(0x1C + (ch) * 2)
+#define   AD3552R_MASK_CH_RANGE_OVERRIDE		BIT(7)
+#define   AD3552R_MASK_CH_GAIN_SCALING_N		GENMASK(6, 5)
+#define   AD3552R_MASK_CH_GAIN_SCALING_P		GENMASK(4, 3)
+#define   AD3552R_MASK_CH_OFFSET_POLARITY		BIT(2)
+#define   AD3552R_MASK_CH_OFFSET_BIT_8			BIT(0)
+/*
+ * Secondary region
+ * For multibyte registers specify the highest address because the access is
+ * done in descending order
+ */
+#define AD3552R_SECONDARY_REGION_START			0x28
+#define AD3552R_REG_ADDR_HW_LDAC_16B			0x28
+#define AD3552R_REG_ADDR_CH_DAC_16B(ch)			(0x2C - (1 - (ch)) * 2)
+#define AD3552R_REG_ADDR_DAC_PAGE_MASK_16B		0x2E
+#define AD3552R_REG_ADDR_CH_SELECT_16B			0x2F
+#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_16B		0x31
+#define AD3552R_REG_ADDR_SW_LDAC_16B			0x32
+#define AD3552R_REG_ADDR_CH_INPUT_16B(ch)		(0x36 - (1 - (ch)) * 2)
+/* 3 bytes registers */
+#define AD3552R_REG_START_24B				0x37
+#define AD3552R_REG_ADDR_HW_LDAC_24B			0x37
+#define AD3552R_REG_ADDR_CH_DAC_24B(ch)			(0x3D - (1 - (ch)) * 3)
+#define AD3552R_REG_ADDR_DAC_PAGE_MASK_24B		0x40
+#define AD3552R_REG_ADDR_CH_SELECT_24B			0x41
+#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_24B		0x44
+#define AD3552R_REG_ADDR_SW_LDAC_24B			0x45
+#define AD3552R_REG_ADDR_CH_INPUT_24B(ch)		(0x4B - (1 - (ch)) * 3)
+
+/* Useful defines */
+#define AD3552R_MAX_CH					2
+#define AD3552R_MASK_CH(ch)				BIT(ch)
+#define AD3552R_MASK_ALL_CH				GENMASK(1, 0)
+#define AD3552R_MAX_REG_SIZE				3
+#define AD3552R_READ_BIT				BIT(7)
+#define AD3552R_ADDR_MASK				GENMASK(6, 0)
+#define AD3552R_MASK_DAC_12B				GENMASK(15, 4)
+#define AD3552R_DEFAULT_CONFIG_B_VALUE			0x8
+#define AD3552R_SCRATCH_PAD_TEST_VAL1			0x34
+#define AD3552R_SCRATCH_PAD_TEST_VAL2			0xB2
+#define AD3552R_GAIN_SCALE				1000
+#define AD3552R_LDAC_PULSE_US				100
+
+#define AD3552R_MAX_RANGES	5
+#define AD3542R_MAX_RANGES	6
+
+extern const s32 ad3552r_ch_ranges[AD3552R_MAX_RANGES][2];
+extern const s32 ad3542r_ch_ranges[AD3542R_MAX_RANGES][2];
+
+enum ad3552r_id {
+	AD3541R_ID = 0x400b,
+	AD3542R_ID = 0x4009,
+	AD3551R_ID = 0x400a,
+	AD3552R_ID = 0x4008,
+};
+
+enum ad3552r_ch_vref_select {
+	/* Internal source with Vref I/O floating */
+	AD3552R_INTERNAL_VREF_PIN_FLOATING,
+	/* Internal source with Vref I/O at 2.5V */
+	AD3552R_INTERNAL_VREF_PIN_2P5V,
+	/* External source with Vref I/O as input */
+	AD3552R_EXTERNAL_VREF_PIN_INPUT
+};
+
+enum ad3542r_ch_output_range {
+	/* Range from 0 V to 2.5 V. Requires Rfb1x connection */
+	AD3542R_CH_OUTPUT_RANGE_0__2P5V,
+	/* Range from 0 V to 3 V. Requires Rfb1x connection  */
+	AD3542R_CH_OUTPUT_RANGE_0__3V,
+	/* Range from 0 V to 5 V. Requires Rfb1x connection  */
+	AD3542R_CH_OUTPUT_RANGE_0__5V,
+	/* Range from 0 V to 10 V. Requires Rfb2x connection  */
+	AD3542R_CH_OUTPUT_RANGE_0__10V,
+	/* Range from -2.5 V to 7.5 V. Requires Rfb2x connection  */
+	AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V,
+	/* Range from -5 V to 5 V. Requires Rfb2x connection  */
+	AD3542R_CH_OUTPUT_RANGE_NEG_5__5V,
+};
+
+enum ad3552r_ch_output_range {
+	/* Range from 0 V to 2.5 V. Requires Rfb1x connection */
+	AD3552R_CH_OUTPUT_RANGE_0__2P5V,
+	/* Range from 0 V to 5 V. Requires Rfb1x connection  */
+	AD3552R_CH_OUTPUT_RANGE_0__5V,
+	/* Range from 0 V to 10 V. Requires Rfb2x connection  */
+	AD3552R_CH_OUTPUT_RANGE_0__10V,
+	/* Range from -5 V to 5 V. Requires Rfb2x connection  */
+	AD3552R_CH_OUTPUT_RANGE_NEG_5__5V,
+	/* Range from -10 V to 10 V. Requires Rfb4x connection  */
+	AD3552R_CH_OUTPUT_RANGE_NEG_10__10V,
+};
+
+int ad3552r_get_output_range(struct device *dev, enum ad3552r_id id,
+			     struct fwnode_handle *child, u32 *val);
+int ad3552r_get_custom_gain(struct device *dev, struct fwnode_handle *child,
+			    u8 *gs_p, u8 *gs_n, u16 *rfb, s16 *goffs);
+u16 ad3552r_calc_custom_gain(u8 p, u8 n, s16 goffs);
+int ad3552r_get_ref_voltage(struct device *dev);
+int ad3552r_get_drive_strength(struct device *dev, u32 *val);
+
+#endif /* __DRIVERS_IIO_DAC_AD3552R_H__ */

-- 
2.45.0.rc1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v3 09/10] iio: dac: ad3552r: add axi platform driver
  2024-09-19  9:19 [PATCH v3 00/10] iio: add support for the ad3552r AXI DAC IP Angelo Dureghello
                   ` (7 preceding siblings ...)
  2024-09-19  9:20 ` [PATCH v3 08/10] iio: dac: ad3552r: extract common code (no changes in behavior intended) Angelo Dureghello
@ 2024-09-19  9:20 ` Angelo Dureghello
  2024-09-29 12:17   ` Jonathan Cameron
  2024-09-19  9:20 ` [PATCH v3 10/10] iio: backend: adi-axi-dac: add registering of child fdt node Angelo Dureghello
  9 siblings, 1 reply; 59+ messages in thread
From: Angelo Dureghello @ 2024-09-19  9:20 UTC (permalink / raw)
  To: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Jonathan Cameron,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan
  Cc: linux-iio, linux-kernel, devicetree, dlechner, Angelo Dureghello

From: Angelo Dureghello <adureghello@baylibre.com>

Add support for ad3552r-axi, where ad3552r has to be controlled
by the custom (fpga-based) ad3552r AXI DAC IP.

Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
---
 drivers/iio/dac/Kconfig                   |  11 +
 drivers/iio/dac/Makefile                  |   1 +
 drivers/iio/dac/ad3552r-axi.c             | 567 ++++++++++++++++++++++++++++++
 drivers/iio/dac/ad3552r.h                 |   9 +
 include/linux/platform_data/ad3552r-axi.h |  18 +
 5 files changed, 606 insertions(+)

diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index 1cfd7e2a622f..030af7702a3c 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -16,6 +16,17 @@ config AD3552R
 	  To compile this driver as a module, choose M here: the
 	  module will be called ad3552r.
 
+config AD3552R_AXI
+	tristate "Analog Devices AD3552R DAC driver, AXI version"
+	select IIO_BACKEND
+	help
+	  Say yes here to build support for Analog Devices AD3552R
+	  Digital to Analog Converter, connected through the Xilinx
+	  fpga AXI interface.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad3552r-axi.
+
 config AD5064
 	tristate "Analog Devices AD5064 and similar multi-channel DAC driver"
 	depends on (SPI_MASTER && I2C!=m) || I2C
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index 56a125f56284..cc2af3aa3f52 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -5,6 +5,7 @@
 
 # When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_AD3552R) += ad3552r.o ad3552r-common.o
+obj-$(CONFIG_AD3552R_AXI) += ad3552r-axi.o ad3552r-common.o
 obj-$(CONFIG_AD5360) += ad5360.o
 obj-$(CONFIG_AD5380) += ad5380.o
 obj-$(CONFIG_AD5421) += ad5421.o
diff --git a/drivers/iio/dac/ad3552r-axi.c b/drivers/iio/dac/ad3552r-axi.c
new file mode 100644
index 000000000000..85c594e149fa
--- /dev/null
+++ b/drivers/iio/dac/ad3552r-axi.c
@@ -0,0 +1,567 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Analog Devices AD3552R
+ * Digital to Analog converter driver, AXI DAC backend version
+ *
+ * Copyright 2024 Analog Devices Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/iio/backend.h>
+#include <linux/iio/buffer.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_data/ad3552r-axi.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/units.h>
+
+#include "ad3552r.h"
+
+#define AD3552R_QSPI_LANES	4
+
+struct ad3552r_axi_model_data {
+	const char *model_name;
+	enum ad3552r_id chip_id;
+	unsigned int num_hw_channels;
+	unsigned int sample_storage_bits;
+};
+
+struct ad3552r_axi_state {
+	const struct ad3552r_axi_model_data *model_data;
+	struct gpio_desc *reset_gpio;
+	struct device *dev;
+	struct iio_backend *back;
+	bool single_channel;
+	struct ad3552r_axi_platform_data *data;
+	bool ddr_mode;
+	bool synchronouos_mode;
+};
+
+static int ad3552r_qspi_update_reg_bits(struct ad3552r_axi_state *st,
+					u32 reg, u32 mask, u32 val,
+					size_t xfer_size)
+{
+	u32 rval;
+	int err;
+
+	err = st->data->bus_reg_read(st->back, reg, &rval, xfer_size);
+	if (err)
+		return err;
+
+	rval &= ~mask;
+	rval |= val;
+
+	return st->data->bus_reg_write(st->back, reg, rval, xfer_size);
+}
+
+static int ad3552r_axi_read_raw(struct iio_dev *indio_dev,
+				struct iio_chan_spec const *chan,
+				int *val, int *val2, long mask)
+{
+	struct ad3552r_axi_state *st = iio_priv(indio_dev);
+	int ch = chan->channel;
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SAMP_FREQ: {
+		int sclk;
+
+		ret = iio_backend_read_raw(st->back, chan, &sclk, 0,
+					   IIO_CHAN_INFO_FREQUENCY);
+		if (ret != IIO_VAL_INT)
+			return -EINVAL;
+
+		/* Using 4 lanes (QSPI) */
+		*val = DIV_ROUND_CLOSEST(sclk * AD3552R_QSPI_LANES *
+					 (1 + st->ddr_mode),
+					 chan->scan_type.storagebits);
+
+		return IIO_VAL_INT;
+	}
+	case IIO_CHAN_INFO_RAW:
+		ret = st->data->bus_reg_read(st->back,
+					     AD3552R_REG_ADDR_CH_DAC_16B(ch),
+					     val, 2);
+		if (ret)
+			return ret;
+
+		return IIO_VAL_INT;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int ad3552r_axi_write_raw(struct iio_dev *indio_dev,
+				 struct iio_chan_spec const *chan,
+				 int val, int val2, long mask)
+{
+	struct ad3552r_axi_state *st = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+			int ch = chan->channel;
+
+			return st->data->bus_reg_write(st->back,
+				    AD3552R_REG_ADDR_CH_DAC_16B(ch), val, 2);
+		}
+		unreachable();
+	default:
+		return -EINVAL;
+	}
+}
+
+static int ad3552r_axi_buffer_postenable(struct iio_dev *indio_dev)
+{
+	struct ad3552r_axi_state *st = iio_priv(indio_dev);
+	struct iio_backend_data_fmt fmt = {
+		.type = IIO_BACKEND_DATA_UNSIGNED
+	};
+	int loop_len, val, err;
+
+	/* Inform DAC chip to switch into DDR mode */
+	err = ad3552r_qspi_update_reg_bits(st,
+					   AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
+					   AD3552R_MASK_SPI_CONFIG_DDR,
+					   AD3552R_MASK_SPI_CONFIG_DDR, 1);
+	if (err)
+		return err;
+
+	/* Inform DAC IP to go for DDR mode from now on */
+	err = iio_backend_ddr_enable(st->back);
+	if (err) {
+		dev_warn(st->dev, "could not set DDR mode, not streaming");
+		goto exit_err;
+	}
+
+	st->ddr_mode = true;
+
+	switch (*indio_dev->active_scan_mask) {
+	case AD3552R_CH0_ACTIVE:
+		st->single_channel = true;
+		loop_len = AD3552R_STREAM_2BYTE_LOOP;
+		val = AD3552R_REG_ADDR_CH_DAC_16B(0);
+		break;
+	case AD3552R_CH1_ACTIVE:
+		st->single_channel = true;
+		loop_len = AD3552R_STREAM_2BYTE_LOOP;
+		val = AD3552R_REG_ADDR_CH_DAC_16B(1);
+		break;
+	case AD3552R_CH0_CH1_ACTIVE:
+		st->single_channel = false;
+		loop_len = AD3552R_STREAM_4BYTE_LOOP;
+		val = AD3552R_REG_ADDR_CH_DAC_16B(1);
+		break;
+	default:
+		err = -EINVAL;
+		goto exit_err_ddr;
+	}
+
+	err = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_STREAM_MODE,
+				      loop_len, 1);
+	if (err)
+		goto exit_err_ddr;
+
+	err = iio_backend_data_transfer_addr(st->back, val);
+	if (err)
+		goto exit_err_ddr;
+
+	/*
+	 * The EXT_SYNC is mandatory in the CN0585 project where 2 instances
+	 * of the IP are in the design and they need to generate the signals
+	 * synchronized.
+	 *
+	 * Note: in first IP implementations CONFIG EXT_SYNC (RO) can be 0,
+	 * but EXT_SYNC (ext synch ability) is enabled anyway.
+	 */
+	if (st->synchronouos_mode)
+		err = iio_backend_ext_sync_enable(st->back);
+	else
+		err = iio_backend_ext_sync_disable(st->back);
+	if (err)
+		goto exit_err_ddr;
+
+	err = iio_backend_data_format_set(st->back, 0, &fmt);
+	if (err)
+		goto exit_err_sync;
+
+	err = iio_backend_buffer_enable(st->back);
+	if (err)
+		goto exit_err_sync;
+
+	return 0;
+
+exit_err_sync:
+	iio_backend_ext_sync_disable(st->back);
+
+exit_err_ddr:
+	iio_backend_ddr_disable(st->back);
+
+exit_err:
+	ad3552r_qspi_update_reg_bits(st,
+				     AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
+				     AD3552R_MASK_SPI_CONFIG_DDR,
+				     0, 1);
+
+	iio_backend_ddr_disable(st->back);
+
+	st->ddr_mode = false;
+
+	return err;
+}
+
+static int ad3552r_axi_buffer_predisable(struct iio_dev *indio_dev)
+{
+	struct ad3552r_axi_state *st = iio_priv(indio_dev);
+	int err;
+
+	err = iio_backend_buffer_disable(st->back);
+	if (err)
+		return err;
+
+	if (st->synchronouos_mode) {
+		err = iio_backend_ext_sync_disable(st->back);
+		if (err)
+			return err;
+	}
+
+	/* Inform DAC to set in SDR mode */
+	err = ad3552r_qspi_update_reg_bits(st,
+					   AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
+					   AD3552R_MASK_SPI_CONFIG_DDR,
+					   0, 1);
+	if (err)
+		return err;
+
+	err = iio_backend_ddr_disable(st->back);
+	if (err)
+		return err;
+
+	st->ddr_mode = false;
+
+	return 0;
+}
+
+static int ad3552r_axi_set_output_range(struct ad3552r_axi_state *st,
+					unsigned int mode)
+{
+	return ad3552r_qspi_update_reg_bits(st,
+				AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE,
+				AD3552R_MASK_CH_OUTPUT_RANGE,
+				FIELD_PREP(AD3552R_MASK_CH0_RANGE, mode) |
+				FIELD_PREP(AD3552R_MASK_CH1_RANGE, mode),
+				1);
+}
+
+static int ad3552r_axi_reset(struct ad3552r_axi_state *st)
+{
+	int err;
+
+	st->reset_gpio = devm_gpiod_get_optional(st->dev,
+						 "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(st->reset_gpio))
+		return PTR_ERR(st->reset_gpio);
+
+	if (st->reset_gpio) {
+		fsleep(10);
+		gpiod_set_value_cansleep(st->reset_gpio, 1);
+	} else {
+		err = ad3552r_qspi_update_reg_bits(st,
+					AD3552R_REG_ADDR_INTERFACE_CONFIG_A,
+					AD3552R_MASK_SOFTWARE_RESET,
+					AD3552R_MASK_SOFTWARE_RESET, 1);
+		if (err)
+			return err;
+	}
+	msleep(100);
+
+	return 0;
+}
+
+static int ad3552r_axi_scratch_pad_test(struct ad3552r_axi_state *st)
+{
+	int err, val;
+
+	err = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_SCRATCH_PAD,
+				      AD3552R_SCRATCH_PAD_TEST_VAL1, 1);
+	if (err)
+		return err;
+
+	err = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_SCRATCH_PAD,
+				     &val, 1);
+	if (err)
+		return err;
+
+	if (val != AD3552R_SCRATCH_PAD_TEST_VAL1) {
+		dev_err(st->dev,
+			"SCRATCH_PAD_TEST mismatch. Expected 0x%x, Read 0x%x\n",
+			AD3552R_SCRATCH_PAD_TEST_VAL1, val);
+		return -EIO;
+	}
+
+	err = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_SCRATCH_PAD,
+				      AD3552R_SCRATCH_PAD_TEST_VAL2, 1);
+	if (err)
+		return err;
+
+	err = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_SCRATCH_PAD,
+				     &val, 1);
+	if (err)
+		return err;
+
+	if (val != AD3552R_SCRATCH_PAD_TEST_VAL2) {
+		dev_err(st->dev,
+			"SCRATCH_PAD_TEST mismatch. Expected 0x%x, Read 0x%x\n",
+			AD3552R_SCRATCH_PAD_TEST_VAL2, val);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int ad3552r_axi_setup_custom_gain(struct ad3552r_axi_state *st,
+					 u16 gain, u16 offset)
+{
+	int err;
+
+	err = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_CH_OFFSET(0),
+				      offset, 1);
+	if (err)
+		return dev_err_probe(st->dev, err, "Error writing register\n");
+
+	err = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_CH_OFFSET(1),
+				      offset, 1);
+	if (err)
+		return dev_err_probe(st->dev, err, "Error writing register\n");
+
+	err = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_CH_GAIN(0),
+				      gain, 1);
+	if (err)
+		return dev_err_probe(st->dev, err, "Error writing register\n");
+
+	err = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_CH_GAIN(1),
+				      gain, 1);
+	if (err)
+		return dev_err_probe(st->dev, err, "Error writing register\n");
+
+	return 0;
+}
+
+static int ad3552r_axi_setup(struct ad3552r_axi_state *st)
+{
+	struct fwnode_handle *child __free(fwnode_handle) = NULL;
+	u8 gs_p, gs_n;
+	s16 goffs;
+	u16 id, rfb;
+	u16 gain = 0, offset = 0;
+	u32 val, range;
+	int err;
+
+	err = ad3552r_axi_reset(st);
+	if (err)
+		return err;
+
+	err = iio_backend_ddr_disable(st->back);
+	if (err)
+		return err;
+
+	err = ad3552r_axi_scratch_pad_test(st);
+	if (err)
+		return err;
+
+	err = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_PRODUCT_ID_L,
+				     &val, 1);
+	if (err)
+		return err;
+
+	id = val;
+
+	err = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_PRODUCT_ID_H,
+				     &val, 1);
+	if (err)
+		return err;
+
+	id |= val << 8;
+	if (id != st->model_data->chip_id)
+		dev_info(st->dev, "Chip ID error. Expected 0x%x, Read 0x%x\n",
+			 AD3552R_ID, id);
+
+	err = st->data->bus_reg_write(st->back,
+				      AD3552R_REG_ADDR_SH_REFERENCE_CONFIG,
+				      0, 1);
+	if (err)
+		return err;
+
+	err = st->data->bus_reg_write(st->back,
+				      AD3552R_REG_ADDR_TRANSFER_REGISTER,
+				      AD3552R_MASK_QUAD_SPI |
+				      AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE, 1);
+	if (err)
+		return err;
+
+	err = iio_backend_data_source_set(st->back, 0, IIO_BACKEND_EXTERNAL);
+	if (err)
+		return err;
+
+	err = iio_backend_data_source_set(st->back, 1, IIO_BACKEND_EXTERNAL);
+	if (err)
+		return err;
+
+	err = ad3552r_get_ref_voltage(st->dev);
+	if (err < 0)
+		return err;
+
+	val = err;
+
+	err = ad3552r_qspi_update_reg_bits(st,
+				AD3552R_REG_ADDR_SH_REFERENCE_CONFIG,
+				AD3552R_MASK_REFERENCE_VOLTAGE_SEL,
+				val, 1);
+	if (err)
+		return err;
+
+	err = ad3552r_get_drive_strength(st->dev, &val);
+	if (!err) {
+		err = ad3552r_qspi_update_reg_bits(st,
+					AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
+					AD3552R_MASK_SDO_DRIVE_STRENGTH,
+					val, 1);
+		if (err)
+			return err;
+	}
+
+	st->synchronouos_mode =
+			fwnode_property_read_bool(dev_fwnode(st->dev),
+						  "adi,synchronous-mode");
+
+	child = device_get_named_child_node(st->dev, "channel");
+	if (!child)
+		return -EINVAL;
+
+	/*
+	 * One of "adi,output-range-microvolt" or "custom-output-range-config"
+	 * must be available in fdt.
+	 */
+	err = ad3552r_get_output_range(st->dev, st->model_data->chip_id,
+				       child, &range);
+	if (!err)
+		return ad3552r_axi_set_output_range(st, range);
+	if (err != -ENOENT)
+		return err;
+
+	err = ad3552r_get_custom_gain(st->dev, child, &gs_p, &gs_n, &rfb,
+				      &goffs);
+	if (err)
+		return err;
+
+	gain = ad3552r_calc_custom_gain(gs_p, gs_n, goffs);
+	offset = abs((s32)goffs);
+
+	return ad3552r_axi_setup_custom_gain(st, gain, offset);
+}
+
+static const struct iio_buffer_setup_ops ad3552r_axi_buffer_setup_ops = {
+	.postenable = ad3552r_axi_buffer_postenable,
+	.predisable = ad3552r_axi_buffer_predisable,
+};
+
+#define AD3552R_CHANNEL(ch) { \
+	.type = IIO_VOLTAGE, \
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+	.output = 1, \
+	.indexed = 1, \
+	.channel = (ch), \
+	.scan_index = (ch), \
+	.scan_type = { \
+		.sign = 'u', \
+		.realbits = 16, \
+		.storagebits = 16, \
+		.endianness = IIO_BE, \
+	} \
+}
+
+static const struct iio_chan_spec ad3552r_axi_channels[] = {
+	AD3552R_CHANNEL(0),
+	AD3552R_CHANNEL(1),
+};
+
+static const struct iio_info ad3552r_axi_info = {
+	.read_raw = &ad3552r_axi_read_raw,
+	.write_raw = &ad3552r_axi_write_raw,
+};
+
+static int ad3552r_axi_probe(struct platform_device *pdev)
+{
+	struct ad3552r_axi_state *st;
+	struct iio_dev *indio_dev;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	st = iio_priv(indio_dev);
+	st->dev = &pdev->dev;
+
+	st->data = pdev->dev.platform_data;
+	if (!st->data) {
+		dev_err(&pdev->dev, "no platform data!\n");
+		return -ENODEV;
+	}
+
+	st->back = devm_iio_backend_get(&pdev->dev, NULL);
+	if (IS_ERR(st->back))
+		return PTR_ERR(st->back);
+
+	ret = devm_iio_backend_enable(&pdev->dev, st->back);
+	if (ret)
+		return ret;
+
+	st->model_data = device_get_match_data(&pdev->dev);
+
+	indio_dev->name = "ad3552r";
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->setup_ops = &ad3552r_axi_buffer_setup_ops;
+	indio_dev->channels = ad3552r_axi_channels;
+	indio_dev->num_channels = ARRAY_SIZE(ad3552r_axi_channels);
+	indio_dev->info = &ad3552r_axi_info;
+
+	ret = devm_iio_backend_request_buffer(&pdev->dev, st->back, indio_dev);
+	if (ret)
+		return ret;
+
+	ret = ad3552r_axi_setup(st);
+	if (ret)
+		return ret;
+
+	return devm_iio_device_register(&pdev->dev, indio_dev);
+}
+
+static const struct ad3552r_axi_model_data ad3552r_model_data = {
+	.model_name = "ad3552r",
+	.chip_id = AD3552R_ID,
+	.num_hw_channels = 2,
+};
+
+static const struct of_device_id ad3552r_axi_of_id[] = {
+	{ .compatible = "adi,ad3552r", .data = &ad3552r_model_data },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ad3552r_axi_of_id);
+
+static struct platform_driver axi_ad3552r_driver = {
+	.driver = {
+		.name = "ad3552r-axi",
+		.of_match_table = ad3552r_axi_of_id,
+	},
+	.probe = ad3552r_axi_probe,
+};
+module_platform_driver(axi_ad3552r_driver);
+
+MODULE_AUTHOR("Dragos Bogdan <dragos.bogdan@analog.com>");
+MODULE_AUTHOR("Angelo Dureghello <adueghello@baylibre.com>");
+MODULE_DESCRIPTION("AD3552R Driver - AXI IP version");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/dac/ad3552r.h b/drivers/iio/dac/ad3552r.h
index b1caa3c3e807..02805eec69a5 100644
--- a/drivers/iio/dac/ad3552r.h
+++ b/drivers/iio/dac/ad3552r.h
@@ -38,6 +38,8 @@
 #define AD3552R_REG_ADDR_TRANSFER_REGISTER		0x0F
 #define   AD3552R_MASK_MULTI_IO_MODE			GENMASK(7, 6)
 #define   AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE		BIT(2)
+#define   AD3552R_MASK_DUAL_SPI				BIT(6)
+#define   AD3552R_MASK_QUAD_SPI				BIT(7)
 #define AD3552R_REG_ADDR_INTERFACE_CONFIG_C		0x10
 #define   AD3552R_MASK_CRC_ENABLE			(GENMASK(7, 6) |\
 							 GENMASK(1, 0))
@@ -129,6 +131,13 @@
 #define AD3552R_GAIN_SCALE				1000
 #define AD3552R_LDAC_PULSE_US				100
 
+#define AD3552R_STREAM_2BYTE_LOOP			0x02
+#define AD3552R_STREAM_4BYTE_LOOP			0x04
+#define AD3552R_CH0_ACTIVE				BIT(0)
+#define AD3552R_CH1_ACTIVE				BIT(1)
+#define AD3552R_CH0_CH1_ACTIVE				(AD3552R_CH0_ACTIVE | \
+							AD3552R_CH1_ACTIVE)
+
 #define AD3552R_MAX_RANGES	5
 #define AD3542R_MAX_RANGES	6
 
diff --git a/include/linux/platform_data/ad3552r-axi.h b/include/linux/platform_data/ad3552r-axi.h
new file mode 100644
index 000000000000..7c0db307102c
--- /dev/null
+++ b/include/linux/platform_data/ad3552r-axi.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2010-2024 Analog Devices Inc.
+ * Copyright (c) 2024 Baylibre, SAS
+ */
+#ifndef __LINUX_PLATFORM_DATA_AD3552R_AXI_H__
+#define __LINUX_PLATFORM_DATA_AD3552R_AXI_H__
+
+#include <linux/iio/backend.h>
+
+struct ad3552r_axi_platform_data {
+	int (*bus_reg_read)(struct iio_backend *back, u32 reg,
+			    unsigned int *val, size_t data_size);
+	int (*bus_reg_write)(struct iio_backend *back, u32 reg,
+			     unsigned int val, size_t data_size);
+};
+
+#endif /* __LINUX_PLATFORM_DATA_AD3552R_AXI_H__ */

-- 
2.45.0.rc1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v3 10/10] iio: backend: adi-axi-dac: add registering of child fdt node
  2024-09-19  9:19 [PATCH v3 00/10] iio: add support for the ad3552r AXI DAC IP Angelo Dureghello
                   ` (8 preceding siblings ...)
  2024-09-19  9:20 ` [PATCH v3 09/10] iio: dac: ad3552r: add axi platform driver Angelo Dureghello
@ 2024-09-19  9:20 ` Angelo Dureghello
  2024-09-29 12:21   ` Jonathan Cameron
  9 siblings, 1 reply; 59+ messages in thread
From: Angelo Dureghello @ 2024-09-19  9:20 UTC (permalink / raw)
  To: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Jonathan Cameron,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan
  Cc: linux-iio, linux-kernel, devicetree, dlechner, Angelo Dureghello

From: Angelo Dureghello <adureghello@baylibre.com>

Change to obtain the fdt use case as reported in the
adi,ad3552r.yaml file in this patchset.

The DAC device is defined as a child node of the backend.
Registering the child fdt node as a platform devices.

Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
---
 drivers/iio/dac/adi-axi-dac.c | 52 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 51 insertions(+), 1 deletion(-)

diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c
index 3ca3a14c575b..2afc1442cd5a 100644
--- a/drivers/iio/dac/adi-axi-dac.c
+++ b/drivers/iio/dac/adi-axi-dac.c
@@ -18,6 +18,7 @@
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 #include <linux/mutex.h>
+#include <linux/platform_data/ad3552r-axi.h>
 #include <linux/platform_device.h>
 #include <linux/property.h>
 #include <linux/regmap.h>
@@ -109,6 +110,8 @@ struct axi_dac_info {
 struct axi_dac_state {
 	struct regmap *regmap;
 	struct device *dev;
+	/* Target DAC platform device */
+	struct platform_device *dac_pdev;
 	/*
 	 * lock to protect multiple accesses to the device registers and global
 	 * data/variables.
@@ -757,6 +760,32 @@ static int axi_dac_bus_reg_read(struct iio_backend *back, u32 reg,
 	}
 }
 
+static int axi_dac_create_platform_device(struct axi_dac_state *st,
+					  struct fwnode_handle *child)
+{
+	struct ad3552r_axi_platform_data pdata = {
+		.bus_reg_read = axi_dac_bus_reg_read,
+		.bus_reg_write = axi_dac_bus_reg_write,
+	};
+	struct platform_device_info pi = {
+		.parent = st->dev,
+		.name = fwnode_get_name(child),
+		.id = PLATFORM_DEVID_AUTO,
+		.fwnode = child,
+		.data = &pdata,
+		.size_data = sizeof(pdata),
+	};
+	struct platform_device *pdev;
+
+	pdev = platform_device_register_full(&pi);
+	if (IS_ERR(pdev))
+		return PTR_ERR(pdev);
+
+	st->dac_pdev = pdev;
+
+	return 0;
+}
+
 static const struct iio_backend_ops axi_dac_generic_ops = {
 	.enable = axi_dac_enable,
 	.disable = axi_dac_disable,
@@ -791,13 +820,22 @@ static const struct regmap_config axi_dac_regmap_config = {
 	.max_register = 0x0800,
 };
 
+static void axi_dac_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct axi_dac_state *st = dev_get_drvdata(dev);
+
+	if (st->dac_pdev)
+		platform_device_unregister(st->dac_pdev);
+}
+
 static int axi_dac_probe(struct platform_device *pdev)
 {
 	struct axi_dac_state *st;
 	void __iomem *base;
 	unsigned int ver;
 	struct clk *clk;
-	int ret;
+	int ret, val;
 
 	st = devm_kzalloc(&pdev->dev, sizeof(*st), GFP_KERNEL);
 	if (!st)
@@ -871,6 +909,17 @@ static int axi_dac_probe(struct platform_device *pdev)
 		return dev_err_probe(&pdev->dev, ret,
 				     "failed to register iio backend\n");
 
+	device_for_each_child_node_scoped(&pdev->dev, child) {
+		/* Processing only reg 0 node */
+		ret = fwnode_property_read_u32(child, "reg", &val);
+		if (ret || val != 0)
+			continue;
+
+		ret = axi_dac_create_platform_device(st, child);
+		if (ret)
+			continue;
+	}
+
 	dev_info(&pdev->dev, "AXI DAC IP core (%d.%.2d.%c) probed\n",
 		 ADI_AXI_PCORE_VER_MAJOR(ver),
 		 ADI_AXI_PCORE_VER_MINOR(ver),
@@ -901,6 +950,7 @@ static struct platform_driver axi_dac_driver = {
 		.of_match_table = axi_dac_of_match,
 	},
 	.probe = axi_dac_probe,
+	.remove = axi_dac_remove,
 };
 module_platform_driver(axi_dac_driver);
 

-- 
2.45.0.rc1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 01/10] iio: backend: adi-axi-dac: fix wrong register bitfield
  2024-09-19  9:19 ` [PATCH v3 01/10] iio: backend: adi-axi-dac: fix wrong register bitfield Angelo Dureghello
@ 2024-09-20 12:45   ` Nuno Sá
  2024-09-29 10:38     ` Jonathan Cameron
  0 siblings, 1 reply; 59+ messages in thread
From: Nuno Sá @ 2024-09-20 12:45 UTC (permalink / raw)
  To: Angelo Dureghello, Lars-Peter Clausen, Michael Hennerich, Nuno Sa,
	Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Olivier Moysan
  Cc: linux-iio, linux-kernel, devicetree, dlechner

On Thu, 2024-09-19 at 11:19 +0200, Angelo Dureghello wrote:
> From: Angelo Dureghello <adureghello@baylibre.com>
> 
> Fix ADI_DAC_R1_MODE of AXI_DAC_REG_CNTRL_2.
> 
> Both generic DAC and ad3552r DAC IPs docs are reporting
> bit 5 for it.
> 
> https://wiki.analog.com/resources/fpga/docs/axi_dac_ip
> https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
> 
> Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> ---

Ouch... Missing Fixes tag. With that,

Reviewed-by: Nuno Sa <nuno.sa@analog.com>

>  drivers/iio/dac/adi-axi-dac.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c
> index 0cb00f3bec04..b8b4171b8043 100644
> --- a/drivers/iio/dac/adi-axi-dac.c
> +++ b/drivers/iio/dac/adi-axi-dac.c
> @@ -46,7 +46,7 @@
>  #define AXI_DAC_REG_CNTRL_1		0x0044
>  #define   AXI_DAC_SYNC			BIT(0)
>  #define AXI_DAC_REG_CNTRL_2		0x0048
> -#define	  ADI_DAC_R1_MODE		BIT(4)
> +#define	  ADI_DAC_R1_MODE		BIT(5)
>  #define AXI_DAC_DRP_STATUS		0x0074
>  #define   AXI_DAC_DRP_LOCKED		BIT(17)
>  /* DAC Channel controls */
> 


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 02/10] dt-bindings: iio: dac: axi-dac: add ad3552r axi variant
  2024-09-19  9:19 ` [PATCH v3 02/10] dt-bindings: iio: dac: axi-dac: add ad3552r axi variant Angelo Dureghello
@ 2024-09-20 12:47   ` Nuno Sá
  2024-09-22 20:59   ` Krzysztof Kozlowski
  2024-09-29 10:46   ` Jonathan Cameron
  2 siblings, 0 replies; 59+ messages in thread
From: Nuno Sá @ 2024-09-20 12:47 UTC (permalink / raw)
  To: Angelo Dureghello, Lars-Peter Clausen, Michael Hennerich, Nuno Sa,
	Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Olivier Moysan
  Cc: linux-iio, linux-kernel, devicetree, dlechner

On Thu, 2024-09-19 at 11:19 +0200, Angelo Dureghello wrote:
> From: Angelo Dureghello <adureghello@baylibre.com>
> 
> Add a new compatible and related bindigns for the fpga-based
> "ad3552r" AXI IP core, a variant of the generic AXI DAC IP.
> 
> The AXI "ad3552r" IP is a very similar HDL (fpga) variant of the
> generic AXI "DAC" IP, intended to control ad3552r and similar chips,
> mainly to reach high speed transfer rates using an additional QSPI
> DDR interface.
> 
> The ad3552r device is defined as a child of the AXI DAC, that in
> this case is acting as an SPI controller.
> 
> Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> ---
>  .../devicetree/bindings/iio/dac/adi,axi-dac.yaml   | 40 ++++++++++++++++++++--
>  1 file changed, 37 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml
> b/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml
> index a55e9bfc66d7..6cf0c2cb84e7 100644
> --- a/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml
> +++ b/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml
> @@ -19,11 +19,13 @@ description: |
>    memory via DMA into the DAC.
>  
>    https://wiki.analog.com/resources/fpga/docs/axi_dac_ip
> +  https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
>  
>  properties:
>    compatible:
>      enum:
>        - adi,axi-dac-9.1.b
> +      - adi,axi-ad3552r
>  
>    reg:
>      maxItems: 1
> @@ -41,22 +43,54 @@ properties:
>    '#io-backend-cells':
>      const: 0
>  
> +  '#address-cells':
> +    const: 1
> +
> +  '#size-cells':
> +    const: 0
> +
>  required:
>    - compatible
>    - dmas
>    - reg
>    - clocks
>  
> +patternProperties:
> +  "^.*@([0-9])$":
> +    type: object
> +    additionalProperties: true
> +    properties:
> +      io-backends:
> +        description: |
> +          AXI backend reference
> +    required:
> +      - io-backends
> +

I wonder if it makes sense to have these specific bits only for the new compatible?

- Nuno Sá



^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 05/10] iio: backend: extend features
  2024-09-19  9:20 ` [PATCH v3 05/10] iio: backend: extend features Angelo Dureghello
@ 2024-09-20 12:50   ` Nuno Sá
  2024-09-24 14:11     ` Angelo Dureghello
  2024-09-29 11:05   ` Jonathan Cameron
  1 sibling, 1 reply; 59+ messages in thread
From: Nuno Sá @ 2024-09-20 12:50 UTC (permalink / raw)
  To: Angelo Dureghello, Lars-Peter Clausen, Michael Hennerich, Nuno Sa,
	Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Olivier Moysan
  Cc: linux-iio, linux-kernel, devicetree, dlechner

On Thu, 2024-09-19 at 11:20 +0200, Angelo Dureghello wrote:
> From: Angelo Dureghello <adureghello@baylibre.com>
> 
> Extend backend features with new calls needed later on this
> patchset from axi version of ad3552r.
> 
> The follwoing calls are added:
> 
> iio_backend_ext_sync_enable
> 	enable synchronize channels on external trigger
> iio_backend_ext_sync_disable
> 	disable synchronize channels on external trigger
> iio_backend_ddr_enable
> 	enable ddr bus transfer
> iio_backend_ddr_disable
> 	disable ddr bus transfer
> iio_backend_set_bus_mode
> 	select the type of bus, so that specific read / write
> 	operations are performed accordingly
> iio_backend_buffer_enable
> 	enable buffer
> iio_backend_buffer_disable
> 	disable buffer
> iio_backend_data_transfer_addr
> 	define the target register address where the DAC sample
> 	will be written.
> 
> Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> ---
>  drivers/iio/industrialio-backend.c | 111 +++++++++++++++++++++++++++++++++++++
>  include/linux/iio/backend.h        |  23 ++++++++
>  2 files changed, 134 insertions(+)
> 
> diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-
> backend.c
> index 20b3b5212da7..f4802c422dbf 100644
> --- a/drivers/iio/industrialio-backend.c
> +++ b/drivers/iio/industrialio-backend.c
> @@ -718,6 +718,117 @@ static int __devm_iio_backend_get(struct device *dev, struct
> iio_backend *back)
>  	return 0;
>  }
>  
> +/**
> + * iio_backend_ext_sync_enable - Enable external synchronization
> + * @back: Backend device
> + *
> + * Enable synchronization by external signal.
> + *
> + * RETURNS:
> + * 0 on success, negative error number on failure.
> + */
> +int iio_backend_ext_sync_enable(struct iio_backend *back)
> +{
> +	return iio_backend_op_call(back, ext_sync_enable);
> +}
> +EXPORT_SYMBOL_NS_GPL(iio_backend_ext_sync_enable, IIO_BACKEND);
> +
> +/**
> + * iio_backend_ext_sync_disable - Disable external synchronization
> + * @back: Backend device
> + *
> + * Disable synchronization by external signal.
> + *
> + * RETURNS:
> + * 0 on success, negative error number on failure.
> + */
> +int iio_backend_ext_sync_disable(struct iio_backend *back)
> +{
> +	return iio_backend_op_call(back, ext_sync_disable);
> +}
> +EXPORT_SYMBOL_NS_GPL(iio_backend_ext_sync_disable, IIO_BACKEND);
> +
> +/**
> + * iio_backend_ddr_enable - Enable interface DDR (Double Data Rate) mode
> + * @back: Backend device
> + *
> + * Enabling DDR, data is generated by the IP at each front
> + * (raising and falling) of the bus clock signal.
> + *
> + * RETURNS:
> + * 0 on success, negative error number on failure.
> + */
> +int iio_backend_ddr_enable(struct iio_backend *back)
> +{
> +	return iio_backend_op_call(back, ddr_enable);
> +}
> +EXPORT_SYMBOL_NS_GPL(iio_backend_ddr_enable, IIO_BACKEND);
> +
> +/**
> + * iio_backend_ddr_disable - Disable interface DDR (Double Data Rate) mode
> + * @back: Backend device
> + *
> + * Disabling DDR data is generated byt the IP at rising or falling front
> + * of the interface clock signal (SDR, Single Data Rate).
> + *
> + * RETURNS:
> + * 0 on success, negative error number on failure.
> + */
> +int iio_backend_ddr_disable(struct iio_backend *back)
> +{
> +	return iio_backend_op_call(back, ddr_disable);
> +}
> +EXPORT_SYMBOL_NS_GPL(iio_backend_ddr_disable, IIO_BACKEND);
> +
> +/**
> + * iio_backend_buffer_enable - Enable iio buffering
> + * @back: Backend device
> + *
> + * Enabling the buffer, buffer data is processed and sent out from the
> + * bus interface.
> + *
> + * RETURNS:
> + * 0 on success, negative error number on failure.
> + */
> +int iio_backend_buffer_enable(struct iio_backend *back)
> +{
> +	return iio_backend_op_call(back, buffer_enable);
> +}
> +EXPORT_SYMBOL_NS_GPL(iio_backend_buffer_enable, IIO_BACKEND);
> +
> +/**
> + * iio_backend_buffer_disable - Disable iio buffering
> + * @back: Backend device
> + *
> + * Disabling the buffer, buffer data transfer on the bus interface
> + * is stopped.
> + *
> + * RETURNS:
> + * 0 on success, negative error number on failure.
> + */
> +int iio_backend_buffer_disable(struct iio_backend *back)
> +{
> +	return iio_backend_op_call(back, buffer_disable);
> +}
> +EXPORT_SYMBOL_NS_GPL(iio_backend_buffer_disable, IIO_BACKEND);
> +

IIRC, both me and Jonathan had some comments about the above 2 calls? Aren't they
about buffering? I think I mentioned something about using the same buffer ops as
typical IIO devices use.

- Nuno Sá


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 06/10] iio: backend: adi-axi-dac: extend features
  2024-09-19  9:20 ` [PATCH v3 06/10] iio: backend: adi-axi-dac: " Angelo Dureghello
@ 2024-09-20 13:10   ` Nuno Sá
  2024-09-29 11:28   ` Jonathan Cameron
  1 sibling, 0 replies; 59+ messages in thread
From: Nuno Sá @ 2024-09-20 13:10 UTC (permalink / raw)
  To: Angelo Dureghello, Lars-Peter Clausen, Michael Hennerich, Nuno Sa,
	Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Olivier Moysan
  Cc: linux-iio, linux-kernel, devicetree, dlechner

On Thu, 2024-09-19 at 11:20 +0200, Angelo Dureghello wrote:
> From: Angelo Dureghello <adureghello@baylibre.com>
> 
> Extend AXI-DAC backend with new features required to interface
> to the ad3552r DAC. Mainly, a new compatible string is added to
> support the ad3552r-axi DAC IP, very similar to the generic DAC
> IP but with some customizations to work with the ad3552r.
> 
> Then, a serie of generic functions has been added to match with
> ad3552r needs. Function names has been kept generic as much as
> possible, to allow re-utilization from other frontend drivers.
> 
> Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> ---

The commit title is not ok... iio: dac: adi-axi-dac: ...

>  drivers/iio/dac/adi-axi-dac.c | 274 ++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 265 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c
> index b8b4171b8043..3ca3a14c575b 100644
> --- a/drivers/iio/dac/adi-axi-dac.c
> +++ b/drivers/iio/dac/adi-axi-dac.c
> @@ -44,11 +44,34 @@
>  #define   AXI_DAC_RSTN_MMCM_RSTN	BIT(1)
>  #define   AXI_DAC_RSTN_RSTN		BIT(0)
>  #define AXI_DAC_REG_CNTRL_1		0x0044
> +#define   AXI_DAC_EXT_SYNC_ARM		BIT(1)
> +#define   AXI_DAC_EXT_SYNC_DISARM	BIT(2)
>  #define   AXI_DAC_SYNC			BIT(0)
>  #define AXI_DAC_REG_CNTRL_2		0x0048
> +#define   AXI_DAC_SDR_DDR_N		BIT(16)
> +#define   AXI_DAC_SYMB_8B		BIT(14)
>  #define	  ADI_DAC_R1_MODE		BIT(5)
> +#define   AXI_DAC_UNSIGNED_DATA		BIT(4)
> +#define AXI_DAC_REG_STATUS_1		0x54
> +#define AXI_DAC_REG_STATUS_2		0x58
>  #define AXI_DAC_DRP_STATUS		0x0074
>  #define   AXI_DAC_DRP_LOCKED		BIT(17)
> +#define AXI_DAC_CNTRL_DATA_RD		0x0080
> +#define   AXI_DAC_DATA_RD_8		GENMASK(7, 0)
> +#define   AXI_DAC_DATA_RD_16		GENMASK(15, 0)
> +#define AXI_DAC_CNTRL_DATA_WR		0x0084
> +#define   AXI_DAC_DATA_WR_8		GENMASK(23, 16)
> +#define   AXI_DAC_DATA_WR_16		GENMASK(23, 8)
> +#define AXI_DAC_UI_STATUS		0x0088
> +#define   AXI_DAC_BUSY			BIT(4)
> +#define AXI_DAC_REG_CUSTOM_CTRL		0x008C
> +#define   AXI_DAC_ADDRESS		GENMASK(31, 24)
> +#define   AXI_DAC_SYNCED_TRANSFER	BIT(2)
> +#define   AXI_DAC_STREAM		BIT(1)
> +#define   AXI_DAC_TRANSFER_DATA		BIT(0)
> +
> +#define AXI_DAC_STREAM_ENABLE		(AXI_DAC_TRANSFER_DATA | AXI_DAC_STREAM)
> +
>  /* DAC Channel controls */
>  #define AXI_DAC_REG_CHAN_CNTRL_1(c)	(0x0400 + (c) * 0x40)
>  #define AXI_DAC_REG_CHAN_CNTRL_3(c)	(0x0408 + (c) * 0x40)
> @@ -62,11 +85,25 @@
>  #define AXI_DAC_REG_CHAN_CNTRL_7(c)	(0x0418 + (c) * 0x40)
>  #define   AXI_DAC_DATA_SEL		GENMASK(3, 0)
>  
> +#define AXI_DAC_RD_ADDR(x)		(BIT(7) | (x))
> +
>  /* 360 degrees in rad */
>  #define AXI_DAC_2_PI_MEGA		6283190
> +
>  enum {
>  	AXI_DAC_DATA_INTERNAL_TONE,
>  	AXI_DAC_DATA_DMA = 2,
> +	AXI_DAC_DATA_INTERNAL_RAMP_16BIT = 11,
> +};
> +
> +enum {
> +	AXI_DAC_BUS_TYPE_NONE,
> +	AXI_DAC_BUS_TYPE_DDR_QSPI,
> +};
> +
> +struct axi_dac_info {
> +	unsigned int version;
> +	int bus_type;

Remove the bus_type... For now, let's just assume it's this QSPI implementation.
Let's worry with different buses when we actually have them. For now, let's implement
this one but only for the new compatible. Maybe have a boolean in here like
`bus_controller`. You'll also need a backend info structure per dac_info structure.
More on that below...

Also it makes sense to have a const char *name variable. If it has a different
compatible, we should name it accordingly.

>  };
>  
>  struct axi_dac_state {
> @@ -77,6 +114,7 @@ struct axi_dac_state {
>  	 * data/variables.
>  	 */
>  	struct mutex lock;
> +	const struct axi_dac_info *info;
>  	u64 dac_clk;
>  	u32 reg_config;
>  	bool int_tone;
> @@ -461,6 +499,11 @@ static int axi_dac_data_source_set(struct iio_backend *back,
> unsigned int chan,
>  		return regmap_update_bits(st->regmap,
>  					  AXI_DAC_REG_CHAN_CNTRL_7(chan),
>  					  AXI_DAC_DATA_SEL, AXI_DAC_DATA_DMA);
> +	case IIO_BACKEND_INTERNAL_RAMP_16BIT:
> +		return regmap_update_bits(st->regmap,
> +					  AXI_DAC_REG_CHAN_CNTRL_7(chan),
> +					  AXI_DAC_DATA_SEL,
> +					  AXI_DAC_DATA_INTERNAL_RAMP_16BIT);
>  	default:
>  		return -EINVAL;
>  	}
> @@ -518,9 +561,206 @@ static int axi_dac_reg_access(struct iio_backend *back,
> unsigned int reg,
>  	return regmap_write(st->regmap, reg, writeval);
>  }
>  
> +static int axi_dac_ext_sync_enable(struct iio_backend *back)
> +{
> +	struct axi_dac_state *st = iio_backend_get_priv(back);
> +
> +	return regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_1,
> +			       AXI_DAC_EXT_SYNC_ARM);
> +}
> +
> +static int axi_dac_ext_sync_disable(struct iio_backend *back)
> +{
> +	struct axi_dac_state *st = iio_backend_get_priv(back);
> +
> +	return regmap_clear_bits(st->regmap, AXI_DAC_REG_CNTRL_1,
> +				 AXI_DAC_EXT_SYNC_DISARM);
> +}
> +
> +static int axi_dac_ddr_enable(struct iio_backend *back)
> +{
> +	struct axi_dac_state *st = iio_backend_get_priv(back);
> +
> +	return regmap_clear_bits(st->regmap, AXI_DAC_REG_CNTRL_2,
> +				 AXI_DAC_SDR_DDR_N);
> +}
> +
> +static int axi_dac_ddr_disable(struct iio_backend *back)
> +{
> +	struct axi_dac_state *st = iio_backend_get_priv(back);
> +
> +	return regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_2,
> +			       AXI_DAC_SDR_DDR_N);
> +}
> +
> +static int axi_dac_buffer_enable(struct iio_backend *back)
> +{
> +	struct axi_dac_state *st = iio_backend_get_priv(back);
> +
> +	return regmap_set_bits(st->regmap, AXI_DAC_REG_CUSTOM_CTRL,
> +			       AXI_DAC_STREAM_ENABLE);
> +}
> +
> +static int axi_dac_buffer_disable(struct iio_backend *back)
> +{
> +	struct axi_dac_state *st = iio_backend_get_priv(back);
> +
> +	return regmap_clear_bits(st->regmap, AXI_DAC_REG_CUSTOM_CTRL,
> +				 AXI_DAC_STREAM_ENABLE);
> +}
> +
> +static int axi_dac_data_transfer_addr(struct iio_backend *back, u32 address)
> +{
> +	struct axi_dac_state *st = iio_backend_get_priv(back);
> +
> +	/*
> +	 * Sample register address, when the DAC is configured, or stream
> +	 * start address when the FSM is in stream state.
> +	 */
> +	return regmap_update_bits(st->regmap, AXI_DAC_REG_CUSTOM_CTRL,
> +				  AXI_DAC_ADDRESS,
> +				  FIELD_PREP(AXI_DAC_ADDRESS, address));
> +}
> +
> +static int axi_dac_data_format_set(struct iio_backend *back, unsigned int ch,
> +				   const struct iio_backend_data_fmt *data)
> +{
> +	struct axi_dac_state *st = iio_backend_get_priv(back);
> +
> +	if (data->type == IIO_BACKEND_DATA_UNSIGNED)
> +		return regmap_clear_bits(st->regmap, AXI_DAC_REG_CNTRL_2,
> +					 AXI_DAC_UNSIGNED_DATA);
> +
> +	return -EINVAL;

nit: I would prefer error handling. Or assuming we might have additional types in the
future, we can also make it a switch() case...

> +}
> +
> +static int axi_dac_read_raw(struct iio_backend *back,
> +			    struct iio_chan_spec const *chan,
> +			    int *val, int *val2, long mask)
> +{
> +	struct axi_dac_state *st = iio_backend_get_priv(back);
> +	int err;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_FREQUENCY: {
> +		int clk_in, reg;
> +
> +		/*
> +		 * As from AXI IP documentation,
> +		 * returning the SCLK depending on the stream mode.
> +		 */

This comment is very specific to the implementation. Make sure to refer to the actual
ip on it (axi-ad3552r).
> +		clk_in = clk_get_rate(clk_get(st->dev, 0));
> +

Nope.. You have several problems in here:

1) clk_get() every time the function get's called. This has leaks;
2) AFAIR, this IP already get's the AXI bus clock to enable it. You'll have to name
your clocks;
3) The clk_get() needs to be done on probe() (use the devm_ variant). And it is only
mandatory for the axi_ad3552r implementation. 
4) You're not enabling the clock (you can have it done in one call).
5) You need to return -EOPNOTSUPP or similar in case there's no support for this. We
have a dedicated compatible so we can make use of it (maybe for now the
bus_controller boolean is enough - again, let's assume it's qspi).
6) I don't think the refclk is expected to change so you can likely get on probe().

> +		err = regmap_read(st->regmap, AXI_DAC_REG_CUSTOM_CTRL, &reg);
> +		if (err)
> +			return err;
> +
> +		if (reg & AXI_DAC_STREAM)
> +			*val = clk_in / 2;
> +		else
> +			*val = clk_in / 8;
> +
> +		return IIO_VAL_INT;
> +		}
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int axi_dac_bus_reg_write(struct iio_backend *back, u32 reg,
> +				 unsigned int val, size_t data_size)
> +{

Be consistent... either two `u32` or two `unsigned int`

> +	struct axi_dac_state *st = iio_backend_get_priv(back);
> +
> +	switch (st->info->bus_type) {
> +	case AXI_DAC_BUS_TYPE_DDR_QSPI: {
> +		int ret;
> +		u32 ival;
> +
> +		if (data_size == 2)
> +			ival = FIELD_PREP(AXI_DAC_DATA_WR_16, val);
> +		else
> +			ival = FIELD_PREP(AXI_DAC_DATA_WR_8, val);
> +
> +		ret = regmap_write(st->regmap, AXI_DAC_CNTRL_DATA_WR, ival);
> +		if (ret)
> +			return ret;
> +
> +		/*
> +		 * Both REG_CNTRL_2 and AXI_DAC_CNTRL_DATA_WR need to know
> +		 * the data size. So keeping data size control here only,
> +		 * since data size is mandatory for the current transfer.
> +		 * DDR state handled separately by specific backend calls,
> +		 * generally all raw register writes are SDR.
> +		 */
> +		if (data_size == 1)
> +			ret = regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_2,
> +					      AXI_DAC_SYMB_8B);
> +		else
> +			ret = regmap_clear_bits(st->regmap, AXI_DAC_REG_CNTRL_2,
> +						AXI_DAC_SYMB_8B);
> +		if (ret)
> +			return ret;
> +
> +		ret = regmap_update_bits(st->regmap, AXI_DAC_REG_CUSTOM_CTRL,
> +					 AXI_DAC_ADDRESS,
> +					 FIELD_PREP(AXI_DAC_ADDRESS, reg));
> +		if (ret)
> +			return ret;
> +
> +		ret = regmap_update_bits(st->regmap, AXI_DAC_REG_CUSTOM_CTRL,
> +					 AXI_DAC_TRANSFER_DATA,
> +					 AXI_DAC_TRANSFER_DATA);
> +		if (ret)
> +			return ret;
> +
> +		ret = regmap_read_poll_timeout(st->regmap,
> +					       AXI_DAC_REG_CUSTOM_CTRL, ival,
> +					       ival & AXI_DAC_TRANSFER_DATA,
> +					       10, 100 * KILO);
> +		if (ret)
> +			return ret;
> +
> +		return regmap_clear_bits(st->regmap, AXI_DAC_REG_CUSTOM_CTRL,
> +					  AXI_DAC_TRANSFER_DATA);
> +	}
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +}
> +
> +static int axi_dac_bus_reg_read(struct iio_backend *back, u32 reg,
> +				unsigned int *val, size_t data_size)
> +{

ditto. Not sure if the backend ops are like this. If yes, same comment.

> +	struct axi_dac_state *st = iio_backend_get_priv(back);
> +
> +	switch (st->info->bus_type) {
> +	case AXI_DAC_BUS_TYPE_DDR_QSPI: {
> +		int ret;
> +		u32 bval;
> +
> +		ret = axi_dac_bus_reg_write(back, AXI_DAC_RD_ADDR(reg), 0,
> +					    data_size);
> +		if (ret)
> +			return ret;
> +
> +		ret = regmap_read_poll_timeout(st->regmap, AXI_DAC_UI_STATUS,
> +					       bval, bval != AXI_DAC_BUSY,
> +					       10, 100);
> +		if (ret)
> +			return ret;
> +
> +		return regmap_read(st->regmap, AXI_DAC_CNTRL_DATA_RD, val);
> +	}
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +}
> +

Both the above look mostly good... Just get rid of the bus_type id :)

>  static const struct iio_backend_ops axi_dac_generic_ops = {
>  	.enable = axi_dac_enable,
>  	.disable = axi_dac_disable,
> +	.read_raw = axi_dac_read_raw,
>  	.request_buffer = axi_dac_request_buffer,
>  	.free_buffer = axi_dac_free_buffer,
>  	.extend_chan_spec = axi_dac_extend_chan,
> @@ -528,6 +768,14 @@ static const struct iio_backend_ops axi_dac_generic_ops = {
>  	.ext_info_get = axi_dac_ext_info_get,
>  	.data_source_set = axi_dac_data_source_set,
>  	.set_sample_rate = axi_dac_set_sample_rate,
> +	.ext_sync_enable = axi_dac_ext_sync_enable,
> +	.ext_sync_disable = axi_dac_ext_sync_disable,
> +	.ddr_enable = axi_dac_ddr_enable,
> +	.ddr_disable = axi_dac_ddr_disable,
> +	.buffer_enable = axi_dac_buffer_enable,
> +	.buffer_disable = axi_dac_buffer_disable,
> +	.data_format_set = axi_dac_data_format_set,
> +	.data_transfer_addr = axi_dac_data_transfer_addr,
>  	.debugfs_reg_access = iio_backend_debugfs_ptr(axi_dac_reg_access),
>  };

Make sure to define a new struct iio_backend_ops with the ops this design needs and
leave the above untouched.

- Nuno Sá



^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 02/10] dt-bindings: iio: dac: axi-dac: add ad3552r axi variant
  2024-09-19  9:19 ` [PATCH v3 02/10] dt-bindings: iio: dac: axi-dac: add ad3552r axi variant Angelo Dureghello
  2024-09-20 12:47   ` Nuno Sá
@ 2024-09-22 20:59   ` Krzysztof Kozlowski
  2024-09-29 10:46   ` Jonathan Cameron
  2 siblings, 0 replies; 59+ messages in thread
From: Krzysztof Kozlowski @ 2024-09-22 20:59 UTC (permalink / raw)
  To: Angelo Dureghello
  Cc: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Jonathan Cameron,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan,
	linux-iio, linux-kernel, devicetree, dlechner

On Thu, Sep 19, 2024 at 11:19:58AM +0200, Angelo Dureghello wrote:
> From: Angelo Dureghello <adureghello@baylibre.com>
> 
> Add a new compatible and related bindigns for the fpga-based
> "ad3552r" AXI IP core, a variant of the generic AXI DAC IP.
> 
> The AXI "ad3552r" IP is a very similar HDL (fpga) variant of the
> generic AXI "DAC" IP, intended to control ad3552r and similar chips,
> mainly to reach high speed transfer rates using an additional QSPI
> DDR interface.
> 
> The ad3552r device is defined as a child of the AXI DAC, that in
> this case is acting as an SPI controller.


So who acts as an SPI controller? adi,axi-ad3552r? Why this is not
reflected in the binding?

> 
> Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> ---
>  .../devicetree/bindings/iio/dac/adi,axi-dac.yaml   | 40 ++++++++++++++++++++--
>  1 file changed, 37 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml b/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml
> index a55e9bfc66d7..6cf0c2cb84e7 100644
> --- a/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml
> +++ b/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml
> @@ -19,11 +19,13 @@ description: |
>    memory via DMA into the DAC.
>  
>    https://wiki.analog.com/resources/fpga/docs/axi_dac_ip
> +  https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
>  
>  properties:
>    compatible:
>      enum:
>        - adi,axi-dac-9.1.b
> +      - adi,axi-ad3552r
>  
>    reg:
>      maxItems: 1
> @@ -41,22 +43,54 @@ properties:
>    '#io-backend-cells':
>      const: 0
>  
> +  '#address-cells':
> +    const: 1
> +
> +  '#size-cells':
> +    const: 0
> +
>  required:
>    - compatible
>    - dmas
>    - reg
>    - clocks
>  
> +patternProperties:
> +  "^.*@([0-9])$":

No need for ()

but this is pattern is quite permissive, so looks like you want to
achieve something else. Maybe spi controller? Not sure, I am just
guessing because empty example does not help me.

> +    type: object
> +    additionalProperties: true

No, this cannot be true.

> +    properties:
> +      io-backends:
> +        description: |
> +          AXI backend reference
> +    required:
> +      - io-backends

I don't get the point. Nodes with only one property are not really
useful.

> +
>  additionalProperties: false
>  
>  examples:
>    - |
>      dac@44a00000 {
> -        compatible = "adi,axi-dac-9.1.b";
> -        reg = <0x44a00000 0x10000>;
> -        dmas = <&tx_dma 0>;
> +      compatible = "adi,axi-dac-9.1.b";
> +      reg = <0x44a00000 0x10000>;

Why are you changing this? It's even messier now - other example uses
different indentayion...

> +      dmas = <&tx_dma 0>;
> +      dma-names = "tx";
> +      #io-backend-cells = <0>;
> +      clocks = <&axi_clk>;
> +    };
> +
> +  - |
> +    axi_dac: spi@44a70000 {
> +        compatible = "adi,axi-ad3552r";
> +        reg = <0x44a70000 0x1000>;
> +        dmas = <&dac_tx_dma 0>;
>          dma-names = "tx";
>          #io-backend-cells = <0>;
>          clocks = <&axi_clk>;
> +
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +
> +        /* DAC devices */

Your schema must be complete, example as well (minus repetitive pieces).

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 03/10] dt-bindings: iio: dac: ad3552r: fix maximum spi speed
  2024-09-19  9:19 ` [PATCH v3 03/10] dt-bindings: iio: dac: ad3552r: fix maximum spi speed Angelo Dureghello
@ 2024-09-22 20:59   ` Krzysztof Kozlowski
  0 siblings, 0 replies; 59+ messages in thread
From: Krzysztof Kozlowski @ 2024-09-22 20:59 UTC (permalink / raw)
  To: Angelo Dureghello
  Cc: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Jonathan Cameron,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan,
	linux-iio, linux-kernel, devicetree, dlechner

On Thu, Sep 19, 2024 at 11:19:59AM +0200, Angelo Dureghello wrote:
> From: Angelo Dureghello <adureghello@baylibre.com>
> 
> Fix maximum SPI clock speed, as per datasheet (Rev. B, page 6).

Fixes tag and Cc-stable.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support
  2024-09-19  9:20 ` [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support Angelo Dureghello
@ 2024-09-22 21:02   ` Krzysztof Kozlowski
  2024-09-23 15:50     ` Angelo Dureghello
  2024-09-29 10:51   ` Jonathan Cameron
  1 sibling, 1 reply; 59+ messages in thread
From: Krzysztof Kozlowski @ 2024-09-22 21:02 UTC (permalink / raw)
  To: Angelo Dureghello
  Cc: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Jonathan Cameron,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan,
	linux-iio, linux-kernel, devicetree, dlechner

On Thu, Sep 19, 2024 at 11:20:00AM +0200, Angelo Dureghello wrote:
> From: Angelo Dureghello <adureghello@baylibre.com>
> 
> There is a version AXI DAC IP block (for FPGAs) that provides
> a physical bus for AD3552R and similar chips, and acts as
> an SPI controller.
> 
> For this case, the binding is modified to include some
> additional properties.
> 
> Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> ---
>  .../devicetree/bindings/iio/dac/adi,ad3552r.yaml   | 42 ++++++++++++++++++++++
>  1 file changed, 42 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> index 41fe00034742..aca4a41c2633 100644
> --- a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> @@ -60,6 +60,18 @@ properties:
>      $ref: /schemas/types.yaml#/definitions/uint32
>      enum: [0, 1, 2, 3]
>  
> +  io-backends:
> +    description: The iio backend reference.
> +      An example backend can be found at
> +        https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
> +    maxItems: 1
> +
> +  adi,synchronous-mode:
> +    description: Enable waiting for external synchronization signal.
> +      Some AXI IP configuration can implement a dual-IP layout, with internal
> +      wirings for streaming synchronization.
> +    type: boolean
> +
>    '#address-cells':
>      const: 1
>  
> @@ -128,6 +140,7 @@ patternProperties:
>            - custom-output-range-config
>  
>  allOf:
> +  - $ref: /schemas/spi/spi-peripheral-props.yaml#
>    - if:
>        properties:
>          compatible:
> @@ -238,4 +251,33 @@ examples:
>              };
>          };
>      };
> +
> +  - |
> +    axi_dac: spi@44a70000 {
> +        compatible = "adi,axi-ad3552r";

That is either redundant or entire example should go to the parent node,
if this device is fixed child of complex device (IOW, adi,ad3552r cannot
be used outside of adi,axi-ad3552r).


> +        reg = <0x44a70000 0x1000>;
> +        dmas = <&dac_tx_dma 0>;
> +        dma-names = "tx";
> +        #io-backend-cells = <0>;
> +        clocks = <&ref_clk>;
> +
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +
> +        dac@0 {
> +            compatible = "adi,ad3552r";
> +            reg = <0>;
> +            reset-gpios = <&gpio0 92 0>;

Use standard defines for GPIO flags.

> +            io-backends = <&axi_dac>;

Why do you need to point to the parent? How much coupled are these
devices? Child pointing to parent is not usually expected, because
that's obvious.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support
  2024-09-22 21:02   ` Krzysztof Kozlowski
@ 2024-09-23 15:50     ` Angelo Dureghello
  2024-09-24  8:02       ` Krzysztof Kozlowski
  0 siblings, 1 reply; 59+ messages in thread
From: Angelo Dureghello @ 2024-09-23 15:50 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Jonathan Cameron,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan,
	linux-iio, linux-kernel, devicetree, dlechner

Hi Krzysztof,

On 22/09/24 23:02, Krzysztof Kozlowski wrote:
> On Thu, Sep 19, 2024 at 11:20:00AM +0200, Angelo Dureghello wrote:
>> From: Angelo Dureghello <adureghello@baylibre.com>
>>
>> There is a version AXI DAC IP block (for FPGAs) that provides
>> a physical bus for AD3552R and similar chips, and acts as
>> an SPI controller.
>>
>> For this case, the binding is modified to include some
>> additional properties.
>>
>> Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
>> ---
>>   .../devicetree/bindings/iio/dac/adi,ad3552r.yaml   | 42 ++++++++++++++++++++++
>>   1 file changed, 42 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
>> index 41fe00034742..aca4a41c2633 100644
>> --- a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
>> +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
>> @@ -60,6 +60,18 @@ properties:
>>       $ref: /schemas/types.yaml#/definitions/uint32
>>       enum: [0, 1, 2, 3]
>>   
>> +  io-backends:
>> +    description: The iio backend reference.
>> +      An example backend can be found at
>> +        https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
>> +    maxItems: 1
>> +
>> +  adi,synchronous-mode:
>> +    description: Enable waiting for external synchronization signal.
>> +      Some AXI IP configuration can implement a dual-IP layout, with internal
>> +      wirings for streaming synchronization.
>> +    type: boolean
>> +
>>     '#address-cells':
>>       const: 1
>>   
>> @@ -128,6 +140,7 @@ patternProperties:
>>             - custom-output-range-config
>>   
>>   allOf:
>> +  - $ref: /schemas/spi/spi-peripheral-props.yaml#
>>     - if:
>>         properties:
>>           compatible:
>> @@ -238,4 +251,33 @@ examples:
>>               };
>>           };
>>       };
>> +
>> +  - |
>> +    axi_dac: spi@44a70000 {
>> +        compatible = "adi,axi-ad3552r";
> That is either redundant or entire example should go to the parent node,
> if this device is fixed child of complex device (IOW, adi,ad3552r cannot
> be used outside of adi,axi-ad3552r).

ad3552r can still be used by a generic "classic" spi
controller (SCLK/CS/MISO) but at a slower samplerate, fpga
controller only (axi-ad3552r) can reach 33MUPS.

>
>> +        reg = <0x44a70000 0x1000>;
>> +        dmas = <&dac_tx_dma 0>;
>> +        dma-names = "tx";
>> +        #io-backend-cells = <0>;
>> +        clocks = <&ref_clk>;
>> +
>> +        #address-cells = <1>;
>> +        #size-cells = <0>;
>> +
>> +        dac@0 {
>> +            compatible = "adi,ad3552r";
>> +            reg = <0>;
>> +            reset-gpios = <&gpio0 92 0>;
> Use standard defines for GPIO flags.

fixed, thanks

>> +            io-backends = <&axi_dac>;
> Why do you need to point to the parent? How much coupled are these
> devices? Child pointing to parent is not usually expected, because
> that's obvious.


"io-backends" is actually the way to refer to the backend module,
(used already for i.e. ad9739a),
it is needed because the backend is not only acting as spi-controller,
but is also providing some APIs for synchronization and bus setup support.

> Best regards,
> Krzysztof
>
Thanks,
Regards,
Angelo



^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support
  2024-09-23 15:50     ` Angelo Dureghello
@ 2024-09-24  8:02       ` Krzysztof Kozlowski
  2024-09-24 12:27         ` Nuno Sá
  0 siblings, 1 reply; 59+ messages in thread
From: Krzysztof Kozlowski @ 2024-09-24  8:02 UTC (permalink / raw)
  To: Angelo Dureghello
  Cc: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Jonathan Cameron,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan,
	linux-iio, linux-kernel, devicetree, dlechner

On 23/09/2024 17:50, Angelo Dureghello wrote:
> Hi Krzysztof,
> 
> On 22/09/24 23:02, Krzysztof Kozlowski wrote:
>> On Thu, Sep 19, 2024 at 11:20:00AM +0200, Angelo Dureghello wrote:
>>> From: Angelo Dureghello <adureghello@baylibre.com>
>>>
>>> There is a version AXI DAC IP block (for FPGAs) that provides
>>> a physical bus for AD3552R and similar chips, and acts as
>>> an SPI controller.
>>>
>>> For this case, the binding is modified to include some
>>> additional properties.
>>>
>>> Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
>>> ---
>>>   .../devicetree/bindings/iio/dac/adi,ad3552r.yaml   | 42 ++++++++++++++++++++++
>>>   1 file changed, 42 insertions(+)
>>>
>>> diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
>>> index 41fe00034742..aca4a41c2633 100644
>>> --- a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
>>> +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
>>> @@ -60,6 +60,18 @@ properties:
>>>       $ref: /schemas/types.yaml#/definitions/uint32
>>>       enum: [0, 1, 2, 3]
>>>   
>>> +  io-backends:
>>> +    description: The iio backend reference.
>>> +      An example backend can be found at
>>> +        https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
>>> +    maxItems: 1
>>> +
>>> +  adi,synchronous-mode:
>>> +    description: Enable waiting for external synchronization signal.
>>> +      Some AXI IP configuration can implement a dual-IP layout, with internal
>>> +      wirings for streaming synchronization.
>>> +    type: boolean
>>> +
>>>     '#address-cells':
>>>       const: 1
>>>   
>>> @@ -128,6 +140,7 @@ patternProperties:
>>>             - custom-output-range-config
>>>   
>>>   allOf:
>>> +  - $ref: /schemas/spi/spi-peripheral-props.yaml#
>>>     - if:
>>>         properties:
>>>           compatible:
>>> @@ -238,4 +251,33 @@ examples:
>>>               };
>>>           };
>>>       };
>>> +
>>> +  - |
>>> +    axi_dac: spi@44a70000 {
>>> +        compatible = "adi,axi-ad3552r";
>> That is either redundant or entire example should go to the parent node,
>> if this device is fixed child of complex device (IOW, adi,ad3552r cannot
>> be used outside of adi,axi-ad3552r).
> 
> ad3552r can still be used by a generic "classic" spi
> controller (SCLK/CS/MISO) but at a slower samplerate, fpga
> controller only (axi-ad3552r) can reach 33MUPS.

OK, then this is just redundant. Drop the node. Parent example should
contain the children, though.
> 
>>
>>> +        reg = <0x44a70000 0x1000>;
>>> +        dmas = <&dac_tx_dma 0>;
>>> +        dma-names = "tx";
>>> +        #io-backend-cells = <0>;
>>> +        clocks = <&ref_clk>;
>>> +
>>> +        #address-cells = <1>;
>>> +        #size-cells = <0>;
>>> +
>>> +        dac@0 {
>>> +            compatible = "adi,ad3552r";
>>> +            reg = <0>;
>>> +            reset-gpios = <&gpio0 92 0>;
>> Use standard defines for GPIO flags.
> 
> fixed, thanks
> 
>>> +            io-backends = <&axi_dac>;
>> Why do you need to point to the parent? How much coupled are these
>> devices? Child pointing to parent is not usually expected, because
>> that's obvious.
> 
> 
> "io-backends" is actually the way to refer to the backend module,
> (used already for i.e. ad9739a),
> it is needed because the backend is not only acting as spi-controller,
> but is also providing some APIs for synchronization and bus setup support.


But if backend is the parent, then this is redundant. You can take it
from the child-parent relationship. Is this pointing to other devices
(non-parent) in other ad3552r configurations?

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support
  2024-09-24  8:02       ` Krzysztof Kozlowski
@ 2024-09-24 12:27         ` Nuno Sá
  2024-09-25  7:22           ` Krzysztof Kozlowski
  0 siblings, 1 reply; 59+ messages in thread
From: Nuno Sá @ 2024-09-24 12:27 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Angelo Dureghello
  Cc: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Jonathan Cameron,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan,
	linux-iio, linux-kernel, devicetree, dlechner

On Tue, 2024-09-24 at 10:02 +0200, Krzysztof Kozlowski wrote:
> On 23/09/2024 17:50, Angelo Dureghello wrote:
> > Hi Krzysztof,
> > 
> > On 22/09/24 23:02, Krzysztof Kozlowski wrote:
> > > On Thu, Sep 19, 2024 at 11:20:00AM +0200, Angelo Dureghello wrote:
> > > > From: Angelo Dureghello <adureghello@baylibre.com>
> > > > 
> > > > There is a version AXI DAC IP block (for FPGAs) that provides
> > > > a physical bus for AD3552R and similar chips, and acts as
> > > > an SPI controller.
> > > > 
> > > > For this case, the binding is modified to include some
> > > > additional properties.
> > > > 
> > > > Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> > > > ---
> > > >   .../devicetree/bindings/iio/dac/adi,ad3552r.yaml   | 42
> > > > ++++++++++++++++++++++
> > > >   1 file changed, 42 insertions(+)
> > > > 
> > > > diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > > b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > > index 41fe00034742..aca4a41c2633 100644
> > > > --- a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > > +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > > @@ -60,6 +60,18 @@ properties:
> > > >       $ref: /schemas/types.yaml#/definitions/uint32
> > > >       enum: [0, 1, 2, 3]
> > > >   
> > > > +  io-backends:
> > > > +    description: The iio backend reference.
> > > > +      An example backend can be found at
> > > > +       
> > > > https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
> > > > +    maxItems: 1
> > > > +
> > > > +  adi,synchronous-mode:
> > > > +    description: Enable waiting for external synchronization signal.
> > > > +      Some AXI IP configuration can implement a dual-IP layout, with
> > > > internal
> > > > +      wirings for streaming synchronization.
> > > > +    type: boolean
> > > > +
> > > >     '#address-cells':
> > > >       const: 1
> > > >   
> > > > @@ -128,6 +140,7 @@ patternProperties:
> > > >             - custom-output-range-config
> > > >   
> > > >   allOf:
> > > > +  - $ref: /schemas/spi/spi-peripheral-props.yaml#
> > > >     - if:
> > > >         properties:
> > > >           compatible:
> > > > @@ -238,4 +251,33 @@ examples:
> > > >               };
> > > >           };
> > > >       };
> > > > +
> > > > +  - |
> > > > +    axi_dac: spi@44a70000 {
> > > > +        compatible = "adi,axi-ad3552r";
> > > That is either redundant or entire example should go to the parent node,
> > > if this device is fixed child of complex device (IOW, adi,ad3552r cannot
> > > be used outside of adi,axi-ad3552r).
> > 
> > ad3552r can still be used by a generic "classic" spi
> > controller (SCLK/CS/MISO) but at a slower samplerate, fpga
> > controller only (axi-ad3552r) can reach 33MUPS.
> 
> OK, then this is just redundant. Drop the node. Parent example should
> contain the children, though.
> > 
> > > 
> > > > +        reg = <0x44a70000 0x1000>;
> > > > +        dmas = <&dac_tx_dma 0>;
> > > > +        dma-names = "tx";
> > > > +        #io-backend-cells = <0>;
> > > > +        clocks = <&ref_clk>;
> > > > +
> > > > +        #address-cells = <1>;
> > > > +        #size-cells = <0>;
> > > > +
> > > > +        dac@0 {
> > > > +            compatible = "adi,ad3552r";
> > > > +            reg = <0>;
> > > > +            reset-gpios = <&gpio0 92 0>;
> > > Use standard defines for GPIO flags.
> > 
> > fixed, thanks
> > 
> > > > +            io-backends = <&axi_dac>;
> > > Why do you need to point to the parent? How much coupled are these
> > > devices? Child pointing to parent is not usually expected, because
> > > that's obvious.
> > 
> > 
> > "io-backends" is actually the way to refer to the backend module,
> > (used already for i.e. ad9739a),
> > it is needed because the backend is not only acting as spi-controller,
> > but is also providing some APIs for synchronization and bus setup support.
> 
> 
> But if backend is the parent, then this is redundant. You can take it
> from the child-parent relationship. Is this pointing to other devices
> (non-parent) in other ad3552r configurations?
> 

The backend is a provider-consumer type of API. On the consumer side (which is the
driver the child node will probe on), we need to call devm_iio_backend_get() to get
the backend object (which obviously is the parent). For that, 'io-backends' is being
used. We do have another API called __devm_iio_backend_get_from_fwnode_lookup() that
could be used with the parent fwnode and should work. However that was only added to
keep backward compatibility in the first user of the IIO backend framework and it's
not really meant to be used again. We are aware this is awkward at the very least [1]
but hopefully still acceptable.

[1]: https://lore.kernel.org/linux-iio/20240903203935.358a1423@jic23-huawei/
- Nuno Sá

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 05/10] iio: backend: extend features
  2024-09-20 12:50   ` Nuno Sá
@ 2024-09-24 14:11     ` Angelo Dureghello
  2024-09-25 11:59       ` Nuno Sá
  0 siblings, 1 reply; 59+ messages in thread
From: Angelo Dureghello @ 2024-09-24 14:11 UTC (permalink / raw)
  To: Nuno Sá, Lars-Peter Clausen, Michael Hennerich, Nuno Sa,
	Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Olivier Moysan
  Cc: linux-iio, linux-kernel, devicetree, dlechner


On 20/09/24 14:50, Nuno Sá wrote:
> On Thu, 2024-09-19 at 11:20 +0200, Angelo Dureghello wrote:
>> From: Angelo Dureghello <adureghello@baylibre.com>
>>
>> Extend backend features with new calls needed later on this
>> patchset from axi version of ad3552r.
>>
>> The follwoing calls are added:
>>
>> iio_backend_ext_sync_enable
>> 	enable synchronize channels on external trigger
>> iio_backend_ext_sync_disable
>> 	disable synchronize channels on external trigger
>> iio_backend_ddr_enable
>> 	enable ddr bus transfer
>> iio_backend_ddr_disable
>> 	disable ddr bus transfer
>> iio_backend_set_bus_mode
>> 	select the type of bus, so that specific read / write
>> 	operations are performed accordingly
>> iio_backend_buffer_enable
>> 	enable buffer
>> iio_backend_buffer_disable
>> 	disable buffer
>> iio_backend_data_transfer_addr
>> 	define the target register address where the DAC sample
>> 	will be written.
>>
>> Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
>> ---
>>   drivers/iio/industrialio-backend.c | 111 +++++++++++++++++++++++++++++++++++++
>>   include/linux/iio/backend.h        |  23 ++++++++
>>   2 files changed, 134 insertions(+)
>>
>> diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-
>> backend.c
>> index 20b3b5212da7..f4802c422dbf 100644
>> --- a/drivers/iio/industrialio-backend.c
>> +++ b/drivers/iio/industrialio-backend.c
>> @@ -718,6 +718,117 @@ static int __devm_iio_backend_get(struct device *dev, struct
>> iio_backend *back)
>>   	return 0;
>>   }
>>   
>> +/**
>> + * iio_backend_ext_sync_enable - Enable external synchronization
>> + * @back: Backend device
>> + *
>> + * Enable synchronization by external signal.
>> + *
>> + * RETURNS:
>> + * 0 on success, negative error number on failure.
>> + */
>> +int iio_backend_ext_sync_enable(struct iio_backend *back)
>> +{
>> +	return iio_backend_op_call(back, ext_sync_enable);
>> +}
>> +EXPORT_SYMBOL_NS_GPL(iio_backend_ext_sync_enable, IIO_BACKEND);
>> +
>> +/**
>> + * iio_backend_ext_sync_disable - Disable external synchronization
>> + * @back: Backend device
>> + *
>> + * Disable synchronization by external signal.
>> + *
>> + * RETURNS:
>> + * 0 on success, negative error number on failure.
>> + */
>> +int iio_backend_ext_sync_disable(struct iio_backend *back)
>> +{
>> +	return iio_backend_op_call(back, ext_sync_disable);
>> +}
>> +EXPORT_SYMBOL_NS_GPL(iio_backend_ext_sync_disable, IIO_BACKEND);
>> +
>> +/**
>> + * iio_backend_ddr_enable - Enable interface DDR (Double Data Rate) mode
>> + * @back: Backend device
>> + *
>> + * Enabling DDR, data is generated by the IP at each front
>> + * (raising and falling) of the bus clock signal.
>> + *
>> + * RETURNS:
>> + * 0 on success, negative error number on failure.
>> + */
>> +int iio_backend_ddr_enable(struct iio_backend *back)
>> +{
>> +	return iio_backend_op_call(back, ddr_enable);
>> +}
>> +EXPORT_SYMBOL_NS_GPL(iio_backend_ddr_enable, IIO_BACKEND);
>> +
>> +/**
>> + * iio_backend_ddr_disable - Disable interface DDR (Double Data Rate) mode
>> + * @back: Backend device
>> + *
>> + * Disabling DDR data is generated byt the IP at rising or falling front
>> + * of the interface clock signal (SDR, Single Data Rate).
>> + *
>> + * RETURNS:
>> + * 0 on success, negative error number on failure.
>> + */
>> +int iio_backend_ddr_disable(struct iio_backend *back)
>> +{
>> +	return iio_backend_op_call(back, ddr_disable);
>> +}
>> +EXPORT_SYMBOL_NS_GPL(iio_backend_ddr_disable, IIO_BACKEND);
>> +
>> +/**
>> + * iio_backend_buffer_enable - Enable iio buffering
>> + * @back: Backend device
>> + *
>> + * Enabling the buffer, buffer data is processed and sent out from the
>> + * bus interface.
>> + *
>> + * RETURNS:
>> + * 0 on success, negative error number on failure.
>> + */
>> +int iio_backend_buffer_enable(struct iio_backend *back)
>> +{
>> +	return iio_backend_op_call(back, buffer_enable);
>> +}
>> +EXPORT_SYMBOL_NS_GPL(iio_backend_buffer_enable, IIO_BACKEND);
>> +
>> +/**
>> + * iio_backend_buffer_disable - Disable iio buffering
>> + * @back: Backend device
>> + *
>> + * Disabling the buffer, buffer data transfer on the bus interface
>> + * is stopped.
>> + *
>> + * RETURNS:
>> + * 0 on success, negative error number on failure.
>> + */
>> +int iio_backend_buffer_disable(struct iio_backend *back)
>> +{
>> +	return iio_backend_op_call(back, buffer_disable);
>> +}
>> +EXPORT_SYMBOL_NS_GPL(iio_backend_buffer_disable, IIO_BACKEND);
>> +
> IIRC, both me and Jonathan had some comments about the above 2 calls? Aren't they
> about buffering? I think I mentioned something about using the same buffer ops as
> typical IIO devices use.

i have now separated iio_backend_ops, keeping buffer enable/disable
for axi-ad3352r case only,

static const struct iio_backend_ops axi_dac_generic_ops = {
     .enable = axi_dac_enable,
     .disable = axi_dac_disable,
     .request_buffer = axi_dac_request_buffer,
     .free_buffer = axi_dac_free_buffer,
     .extend_chan_spec = axi_dac_extend_chan,
     .ext_info_set = axi_dac_ext_info_set,
     .ext_info_get = axi_dac_ext_info_get,
     .data_source_set = axi_dac_data_source_set,
     .set_sample_rate = axi_dac_set_sample_rate,
     .debugfs_reg_access = iio_backend_debugfs_ptr(axi_dac_reg_access),
};

static const struct iio_backend_ops axi_ad3552r_ops = {
     .enable = axi_dac_enable,
     .read_raw = axi_dac_read_raw,
     .request_buffer = axi_dac_request_buffer,
     .data_source_set = axi_dac_data_source_set,
     .ext_sync_enable = axi_dac_ext_sync_enable,
     .ext_sync_disable = axi_dac_ext_sync_disable,
     .ddr_enable = axi_dac_ddr_enable,
     .ddr_disable = axi_dac_ddr_disable,
     .buffer_enable = axi_dac_buffer_enable,
     .buffer_disable = axi_dac_buffer_disable,
     .data_format_set = axi_dac_data_format_set,
     .data_transfer_addr = axi_dac_data_transfer_addr,
};


could this be good ?


> - Nuno Sá

Regards,
Angelo


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support
  2024-09-24 12:27         ` Nuno Sá
@ 2024-09-25  7:22           ` Krzysztof Kozlowski
  2024-09-25 11:55             ` Nuno Sá
  0 siblings, 1 reply; 59+ messages in thread
From: Krzysztof Kozlowski @ 2024-09-25  7:22 UTC (permalink / raw)
  To: Nuno Sá, Angelo Dureghello
  Cc: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Jonathan Cameron,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan,
	linux-iio, linux-kernel, devicetree, dlechner

On 24/09/2024 14:27, Nuno Sá wrote:
> On Tue, 2024-09-24 at 10:02 +0200, Krzysztof Kozlowski wrote:
>> On 23/09/2024 17:50, Angelo Dureghello wrote:
>>> Hi Krzysztof,
>>>
>>> On 22/09/24 23:02, Krzysztof Kozlowski wrote:
>>>> On Thu, Sep 19, 2024 at 11:20:00AM +0200, Angelo Dureghello wrote:
>>>>> From: Angelo Dureghello <adureghello@baylibre.com>
>>>>>
>>>>> There is a version AXI DAC IP block (for FPGAs) that provides
>>>>> a physical bus for AD3552R and similar chips, and acts as
>>>>> an SPI controller.
>>>>>
>>>>> For this case, the binding is modified to include some
>>>>> additional properties.
>>>>>
>>>>> Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
>>>>> ---
>>>>>   .../devicetree/bindings/iio/dac/adi,ad3552r.yaml   | 42
>>>>> ++++++++++++++++++++++
>>>>>   1 file changed, 42 insertions(+)
>>>>>
>>>>> diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
>>>>> b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
>>>>> index 41fe00034742..aca4a41c2633 100644
>>>>> --- a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
>>>>> +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
>>>>> @@ -60,6 +60,18 @@ properties:
>>>>>       $ref: /schemas/types.yaml#/definitions/uint32
>>>>>       enum: [0, 1, 2, 3]
>>>>>   
>>>>> +  io-backends:
>>>>> +    description: The iio backend reference.
>>>>> +      An example backend can be found at
>>>>> +       
>>>>> https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
>>>>> +    maxItems: 1
>>>>> +
>>>>> +  adi,synchronous-mode:
>>>>> +    description: Enable waiting for external synchronization signal.
>>>>> +      Some AXI IP configuration can implement a dual-IP layout, with
>>>>> internal
>>>>> +      wirings for streaming synchronization.
>>>>> +    type: boolean
>>>>> +
>>>>>     '#address-cells':
>>>>>       const: 1
>>>>>   
>>>>> @@ -128,6 +140,7 @@ patternProperties:
>>>>>             - custom-output-range-config
>>>>>   
>>>>>   allOf:
>>>>> +  - $ref: /schemas/spi/spi-peripheral-props.yaml#
>>>>>     - if:
>>>>>         properties:
>>>>>           compatible:
>>>>> @@ -238,4 +251,33 @@ examples:
>>>>>               };
>>>>>           };
>>>>>       };
>>>>> +
>>>>> +  - |
>>>>> +    axi_dac: spi@44a70000 {
>>>>> +        compatible = "adi,axi-ad3552r";
>>>> That is either redundant or entire example should go to the parent node,
>>>> if this device is fixed child of complex device (IOW, adi,ad3552r cannot
>>>> be used outside of adi,axi-ad3552r).
>>>
>>> ad3552r can still be used by a generic "classic" spi
>>> controller (SCLK/CS/MISO) but at a slower samplerate, fpga
>>> controller only (axi-ad3552r) can reach 33MUPS.
>>
>> OK, then this is just redundant. Drop the node. Parent example should
>> contain the children, though.
>>>
>>>>
>>>>> +        reg = <0x44a70000 0x1000>;
>>>>> +        dmas = <&dac_tx_dma 0>;
>>>>> +        dma-names = "tx";
>>>>> +        #io-backend-cells = <0>;
>>>>> +        clocks = <&ref_clk>;
>>>>> +
>>>>> +        #address-cells = <1>;
>>>>> +        #size-cells = <0>;
>>>>> +
>>>>> +        dac@0 {
>>>>> +            compatible = "adi,ad3552r";
>>>>> +            reg = <0>;
>>>>> +            reset-gpios = <&gpio0 92 0>;
>>>> Use standard defines for GPIO flags.
>>>
>>> fixed, thanks
>>>
>>>>> +            io-backends = <&axi_dac>;
>>>> Why do you need to point to the parent? How much coupled are these
>>>> devices? Child pointing to parent is not usually expected, because
>>>> that's obvious.
>>>
>>>
>>> "io-backends" is actually the way to refer to the backend module,
>>> (used already for i.e. ad9739a),
>>> it is needed because the backend is not only acting as spi-controller,
>>> but is also providing some APIs for synchronization and bus setup support.
>>
>>
>> But if backend is the parent, then this is redundant. You can take it
>> from the child-parent relationship. Is this pointing to other devices
>> (non-parent) in other ad3552r configurations?
>>
> 
> The backend is a provider-consumer type of API. On the consumer side (which is the
> driver the child node will probe on), we need to call devm_iio_backend_get() to get
> the backend object (which obviously is the parent). For that, 'io-backends' is being

You described the driver, so how does it matter? Driver can call
get_backend_from_parent(), right? Or get_backend_from_fwnode(parent)?

> used. We do have another API called __devm_iio_backend_get_from_fwnode_lookup() that
> could be used with the parent fwnode and should work. However that was only added to
> keep backward compatibility in the first user of the IIO backend framework and it's
> not really meant to be used again. We are aware this is awkward at the very least [1]
> but hopefully still acceptable.

Don't use driver reasons for discussing hardware. Answer my first
question, because it is still ignored.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support
  2024-09-25  7:22           ` Krzysztof Kozlowski
@ 2024-09-25 11:55             ` Nuno Sá
  2024-09-28 12:20               ` Krzysztof Kozlowski
  0 siblings, 1 reply; 59+ messages in thread
From: Nuno Sá @ 2024-09-25 11:55 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Angelo Dureghello
  Cc: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Jonathan Cameron,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan,
	linux-iio, linux-kernel, devicetree, dlechner

On Wed, 2024-09-25 at 09:22 +0200, Krzysztof Kozlowski wrote:
> On 24/09/2024 14:27, Nuno Sá wrote:
> > On Tue, 2024-09-24 at 10:02 +0200, Krzysztof Kozlowski wrote:
> > > On 23/09/2024 17:50, Angelo Dureghello wrote:
> > > > Hi Krzysztof,
> > > > 
> > > > On 22/09/24 23:02, Krzysztof Kozlowski wrote:
> > > > > On Thu, Sep 19, 2024 at 11:20:00AM +0200, Angelo Dureghello wrote:
> > > > > > From: Angelo Dureghello <adureghello@baylibre.com>
> > > > > > 
> > > > > > There is a version AXI DAC IP block (for FPGAs) that provides
> > > > > > a physical bus for AD3552R and similar chips, and acts as
> > > > > > an SPI controller.
> > > > > > 
> > > > > > For this case, the binding is modified to include some
> > > > > > additional properties.
> > > > > > 
> > > > > > Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> > > > > > ---
> > > > > >   .../devicetree/bindings/iio/dac/adi,ad3552r.yaml   | 42
> > > > > > ++++++++++++++++++++++
> > > > > >   1 file changed, 42 insertions(+)
> > > > > > 
> > > > > > diff --git
> > > > > > a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > > > > b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > > > > index 41fe00034742..aca4a41c2633 100644
> > > > > > --- a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > > > > +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > > > > @@ -60,6 +60,18 @@ properties:
> > > > > >       $ref: /schemas/types.yaml#/definitions/uint32
> > > > > >       enum: [0, 1, 2, 3]
> > > > > >   
> > > > > > +  io-backends:
> > > > > > +    description: The iio backend reference.
> > > > > > +      An example backend can be found at
> > > > > > +       
> > > > > > https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
> > > > > > +    maxItems: 1
> > > > > > +
> > > > > > +  adi,synchronous-mode:
> > > > > > +    description: Enable waiting for external synchronization
> > > > > > signal.
> > > > > > +      Some AXI IP configuration can implement a dual-IP layout,
> > > > > > with
> > > > > > internal
> > > > > > +      wirings for streaming synchronization.
> > > > > > +    type: boolean
> > > > > > +
> > > > > >     '#address-cells':
> > > > > >       const: 1
> > > > > >   
> > > > > > @@ -128,6 +140,7 @@ patternProperties:
> > > > > >             - custom-output-range-config
> > > > > >   
> > > > > >   allOf:
> > > > > > +  - $ref: /schemas/spi/spi-peripheral-props.yaml#
> > > > > >     - if:
> > > > > >         properties:
> > > > > >           compatible:
> > > > > > @@ -238,4 +251,33 @@ examples:
> > > > > >               };
> > > > > >           };
> > > > > >       };
> > > > > > +
> > > > > > +  - |
> > > > > > +    axi_dac: spi@44a70000 {
> > > > > > +        compatible = "adi,axi-ad3552r";
> > > > > That is either redundant or entire example should go to the parent
> > > > > node,
> > > > > if this device is fixed child of complex device (IOW, adi,ad3552r
> > > > > cannot
> > > > > be used outside of adi,axi-ad3552r).
> > > > 
> > > > ad3552r can still be used by a generic "classic" spi
> > > > controller (SCLK/CS/MISO) but at a slower samplerate, fpga
> > > > controller only (axi-ad3552r) can reach 33MUPS.
> > > 
> > > OK, then this is just redundant. Drop the node. Parent example should
> > > contain the children, though.
> > > > 
> > > > > 
> > > > > > +        reg = <0x44a70000 0x1000>;
> > > > > > +        dmas = <&dac_tx_dma 0>;
> > > > > > +        dma-names = "tx";
> > > > > > +        #io-backend-cells = <0>;
> > > > > > +        clocks = <&ref_clk>;
> > > > > > +
> > > > > > +        #address-cells = <1>;
> > > > > > +        #size-cells = <0>;
> > > > > > +
> > > > > > +        dac@0 {
> > > > > > +            compatible = "adi,ad3552r";
> > > > > > +            reg = <0>;
> > > > > > +            reset-gpios = <&gpio0 92 0>;
> > > > > Use standard defines for GPIO flags.
> > > > 
> > > > fixed, thanks
> > > > 
> > > > > > +            io-backends = <&axi_dac>;
> > > > > Why do you need to point to the parent? How much coupled are these
> > > > > devices? Child pointing to parent is not usually expected, because
> > > > > that's obvious.
> > > > 
> > > > 
> > > > "io-backends" is actually the way to refer to the backend module,
> > > > (used already for i.e. ad9739a),
> > > > it is needed because the backend is not only acting as spi-controller,
> > > > but is also providing some APIs for synchronization and bus setup
> > > > support.
> > > 
> > > 
> > > But if backend is the parent, then this is redundant. You can take it
> > > from the child-parent relationship. Is this pointing to other devices
> > > (non-parent) in other ad3552r configurations?
> > > 
> > 
> > The backend is a provider-consumer type of API. On the consumer side (which
> > is the
> > driver the child node will probe on), we need to call devm_iio_backend_get()
> > to get
> > the backend object (which obviously is the parent). For that, 'io-backends'
> > is being
> 
> You described the driver, so how does it matter? Driver can call
> get_backend_from_parent(), right? Or get_backend_from_fwnode(parent)?

Well yes, just stating what the framework (also in terms of bindings) is
expecting. Of course that on the driver side we can paper around it the way we
want. But my main point was that we can only paper around it if we use code that
is meant not to be used.

And, FWIW, I was (trying) replying to your comment

"You can take it from the child-parent relationship"

Again, we can only do that by introducing new code or use code that's not meant
to be used. The way we're supposed to reference backends is by explicitly using
the proper FW property.

Put it in another way and a completely hypothetical case. If we have a spi
controller which happens to export some clock and one of it's peripherals ends
up using that clock, wouldn't we still use 'clocks' to reference that clock?

Again, if this is too weird to be acceptable in the bindings we take it from the
child - parent relationship. 


- Nuno Sá

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 05/10] iio: backend: extend features
  2024-09-24 14:11     ` Angelo Dureghello
@ 2024-09-25 11:59       ` Nuno Sá
  2024-10-02  9:14         ` Angelo Dureghello
  0 siblings, 1 reply; 59+ messages in thread
From: Nuno Sá @ 2024-09-25 11:59 UTC (permalink / raw)
  To: Angelo Dureghello, Lars-Peter Clausen, Michael Hennerich, Nuno Sa,
	Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Olivier Moysan
  Cc: linux-iio, linux-kernel, devicetree, dlechner

On Tue, 2024-09-24 at 16:11 +0200, Angelo Dureghello wrote:
> 
> On 20/09/24 14:50, Nuno Sá wrote:
> > On Thu, 2024-09-19 at 11:20 +0200, Angelo Dureghello wrote:
> > > From: Angelo Dureghello <adureghello@baylibre.com>
> > > 
> > > Extend backend features with new calls needed later on this
> > > patchset from axi version of ad3552r.
> > > 
> > > The follwoing calls are added:
> > > 
> > > iio_backend_ext_sync_enable
> > > 	enable synchronize channels on external trigger
> > > iio_backend_ext_sync_disable
> > > 	disable synchronize channels on external trigger
> > > iio_backend_ddr_enable
> > > 	enable ddr bus transfer
> > > iio_backend_ddr_disable
> > > 	disable ddr bus transfer
> > > iio_backend_set_bus_mode
> > > 	select the type of bus, so that specific read / write
> > > 	operations are performed accordingly
> > > iio_backend_buffer_enable
> > > 	enable buffer
> > > iio_backend_buffer_disable
> > > 	disable buffer
> > > iio_backend_data_transfer_addr
> > > 	define the target register address where the DAC sample
> > > 	will be written.
> > > 
> > > Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> > > ---
> > >   drivers/iio/industrialio-backend.c | 111
> > > +++++++++++++++++++++++++++++++++++++
> > >   include/linux/iio/backend.h        |  23 ++++++++
> > >   2 files changed, 134 insertions(+)
> > > 
> > > diff --git a/drivers/iio/industrialio-backend.c
> > > b/drivers/iio/industrialio-
> > > backend.c
> > > index 20b3b5212da7..f4802c422dbf 100644
> > > --- a/drivers/iio/industrialio-backend.c
> > > +++ b/drivers/iio/industrialio-backend.c
> > > @@ -718,6 +718,117 @@ static int __devm_iio_backend_get(struct device
> > > *dev, struct
> > > iio_backend *back)
> > >   	return 0;
> > >   }
> > >   
> > > +/**
> > > + * iio_backend_ext_sync_enable - Enable external synchronization
> > > + * @back: Backend device
> > > + *
> > > + * Enable synchronization by external signal.
> > > + *
> > > + * RETURNS:
> > > + * 0 on success, negative error number on failure.
> > > + */
> > > +int iio_backend_ext_sync_enable(struct iio_backend *back)
> > > +{
> > > +	return iio_backend_op_call(back, ext_sync_enable);
> > > +}
> > > +EXPORT_SYMBOL_NS_GPL(iio_backend_ext_sync_enable, IIO_BACKEND);
> > > +
> > > +/**
> > > + * iio_backend_ext_sync_disable - Disable external synchronization
> > > + * @back: Backend device
> > > + *
> > > + * Disable synchronization by external signal.
> > > + *
> > > + * RETURNS:
> > > + * 0 on success, negative error number on failure.
> > > + */
> > > +int iio_backend_ext_sync_disable(struct iio_backend *back)
> > > +{
> > > +	return iio_backend_op_call(back, ext_sync_disable);
> > > +}
> > > +EXPORT_SYMBOL_NS_GPL(iio_backend_ext_sync_disable, IIO_BACKEND);
> > > +
> > > +/**
> > > + * iio_backend_ddr_enable - Enable interface DDR (Double Data Rate) mode
> > > + * @back: Backend device
> > > + *
> > > + * Enabling DDR, data is generated by the IP at each front
> > > + * (raising and falling) of the bus clock signal.
> > > + *
> > > + * RETURNS:
> > > + * 0 on success, negative error number on failure.
> > > + */
> > > +int iio_backend_ddr_enable(struct iio_backend *back)
> > > +{
> > > +	return iio_backend_op_call(back, ddr_enable);
> > > +}
> > > +EXPORT_SYMBOL_NS_GPL(iio_backend_ddr_enable, IIO_BACKEND);
> > > +
> > > +/**
> > > + * iio_backend_ddr_disable - Disable interface DDR (Double Data Rate)
> > > mode
> > > + * @back: Backend device
> > > + *
> > > + * Disabling DDR data is generated byt the IP at rising or falling front
> > > + * of the interface clock signal (SDR, Single Data Rate).
> > > + *
> > > + * RETURNS:
> > > + * 0 on success, negative error number on failure.
> > > + */
> > > +int iio_backend_ddr_disable(struct iio_backend *back)
> > > +{
> > > +	return iio_backend_op_call(back, ddr_disable);
> > > +}
> > > +EXPORT_SYMBOL_NS_GPL(iio_backend_ddr_disable, IIO_BACKEND);
> > > +
> > > +/**
> > > + * iio_backend_buffer_enable - Enable iio buffering
> > > + * @back: Backend device
> > > + *
> > > + * Enabling the buffer, buffer data is processed and sent out from the
> > > + * bus interface.
> > > + *
> > > + * RETURNS:
> > > + * 0 on success, negative error number on failure.
> > > + */
> > > +int iio_backend_buffer_enable(struct iio_backend *back)
> > > +{
> > > +	return iio_backend_op_call(back, buffer_enable);
> > > +}
> > > +EXPORT_SYMBOL_NS_GPL(iio_backend_buffer_enable, IIO_BACKEND);
> > > +
> > > +/**
> > > + * iio_backend_buffer_disable - Disable iio buffering
> > > + * @back: Backend device
> > > + *
> > > + * Disabling the buffer, buffer data transfer on the bus interface
> > > + * is stopped.
> > > + *
> > > + * RETURNS:
> > > + * 0 on success, negative error number on failure.
> > > + */
> > > +int iio_backend_buffer_disable(struct iio_backend *back)
> > > +{
> > > +	return iio_backend_op_call(back, buffer_disable);
> > > +}
> > > +EXPORT_SYMBOL_NS_GPL(iio_backend_buffer_disable, IIO_BACKEND);
> > > +
> > IIRC, both me and Jonathan had some comments about the above 2 calls? Aren't
> > they
> > about buffering? I think I mentioned something about using the same buffer
> > ops as
> > typical IIO devices use.
> 
> i have now separated iio_backend_ops, keeping buffer enable/disable
> for axi-ad3352r case only,
> 
> static const struct iio_backend_ops axi_dac_generic_ops = {
>      .enable = axi_dac_enable,
>      .disable = axi_dac_disable,
>      .request_buffer = axi_dac_request_buffer,
>      .free_buffer = axi_dac_free_buffer,
>      .extend_chan_spec = axi_dac_extend_chan,
>      .ext_info_set = axi_dac_ext_info_set,
>      .ext_info_get = axi_dac_ext_info_get,
>      .data_source_set = axi_dac_data_source_set,
>      .set_sample_rate = axi_dac_set_sample_rate,
>      .debugfs_reg_access = iio_backend_debugfs_ptr(axi_dac_reg_access),
> };
> 
> static const struct iio_backend_ops axi_ad3552r_ops = {
>      .enable = axi_dac_enable,
>      .read_raw = axi_dac_read_raw,
>      .request_buffer = axi_dac_request_buffer,
>      .data_source_set = axi_dac_data_source_set,
>      .ext_sync_enable = axi_dac_ext_sync_enable,
>      .ext_sync_disable = axi_dac_ext_sync_disable,
>      .ddr_enable = axi_dac_ddr_enable,
>      .ddr_disable = axi_dac_ddr_disable,
>      .buffer_enable = axi_dac_buffer_enable,
>      .buffer_disable = axi_dac_buffer_disable,
>      .data_format_set = axi_dac_data_format_set,
>      .data_transfer_addr = axi_dac_data_transfer_addr,
> };
> 
> 
> could this be good ?
> 

I think you're replying to the wrong email :). But yeah, I made a comment about
the above and that is something I'm also expecting.

Regarding the buffer_enable/disable() stuff, please go check past discussions (I
think on the RFC). I'm fairly sure I had (and Jonathan as well) some comments
about directly using IIO buffer options or replicating them in the backend_ops.
Likely the second option is the best one so we can take a reference to backend
object directly.

- Nuno Sá


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support
  2024-09-25 11:55             ` Nuno Sá
@ 2024-09-28 12:20               ` Krzysztof Kozlowski
  2024-09-29 10:59                 ` Jonathan Cameron
  0 siblings, 1 reply; 59+ messages in thread
From: Krzysztof Kozlowski @ 2024-09-28 12:20 UTC (permalink / raw)
  To: Nuno Sá, Angelo Dureghello
  Cc: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Jonathan Cameron,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan,
	linux-iio, linux-kernel, devicetree, dlechner

On 25/09/2024 13:55, Nuno Sá wrote:
> On Wed, 2024-09-25 at 09:22 +0200, Krzysztof Kozlowski wrote:
>> On 24/09/2024 14:27, Nuno Sá wrote:
>>> On Tue, 2024-09-24 at 10:02 +0200, Krzysztof Kozlowski wrote:
>>>> On 23/09/2024 17:50, Angelo Dureghello wrote:
>>>>> Hi Krzysztof,
>>>>>
>>>>> On 22/09/24 23:02, Krzysztof Kozlowski wrote:
>>>>>> On Thu, Sep 19, 2024 at 11:20:00AM +0200, Angelo Dureghello wrote:
>>>>>>> From: Angelo Dureghello <adureghello@baylibre.com>
>>>>>>>
>>>>>>> There is a version AXI DAC IP block (for FPGAs) that provides
>>>>>>> a physical bus for AD3552R and similar chips, and acts as
>>>>>>> an SPI controller.
>>>>>>>
>>>>>>> For this case, the binding is modified to include some
>>>>>>> additional properties.
>>>>>>>
>>>>>>> Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
>>>>>>> ---
>>>>>>>   .../devicetree/bindings/iio/dac/adi,ad3552r.yaml   | 42
>>>>>>> ++++++++++++++++++++++
>>>>>>>   1 file changed, 42 insertions(+)
>>>>>>>
>>>>>>> diff --git
>>>>>>> a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
>>>>>>> b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
>>>>>>> index 41fe00034742..aca4a41c2633 100644
>>>>>>> --- a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
>>>>>>> +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
>>>>>>> @@ -60,6 +60,18 @@ properties:
>>>>>>>       $ref: /schemas/types.yaml#/definitions/uint32
>>>>>>>       enum: [0, 1, 2, 3]
>>>>>>>   
>>>>>>> +  io-backends:
>>>>>>> +    description: The iio backend reference.
>>>>>>> +      An example backend can be found at
>>>>>>> +       
>>>>>>> https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
>>>>>>> +    maxItems: 1
>>>>>>> +
>>>>>>> +  adi,synchronous-mode:
>>>>>>> +    description: Enable waiting for external synchronization
>>>>>>> signal.
>>>>>>> +      Some AXI IP configuration can implement a dual-IP layout,
>>>>>>> with
>>>>>>> internal
>>>>>>> +      wirings for streaming synchronization.
>>>>>>> +    type: boolean
>>>>>>> +
>>>>>>>     '#address-cells':
>>>>>>>       const: 1
>>>>>>>   
>>>>>>> @@ -128,6 +140,7 @@ patternProperties:
>>>>>>>             - custom-output-range-config
>>>>>>>   
>>>>>>>   allOf:
>>>>>>> +  - $ref: /schemas/spi/spi-peripheral-props.yaml#
>>>>>>>     - if:
>>>>>>>         properties:
>>>>>>>           compatible:
>>>>>>> @@ -238,4 +251,33 @@ examples:
>>>>>>>               };
>>>>>>>           };
>>>>>>>       };
>>>>>>> +
>>>>>>> +  - |
>>>>>>> +    axi_dac: spi@44a70000 {
>>>>>>> +        compatible = "adi,axi-ad3552r";
>>>>>> That is either redundant or entire example should go to the parent
>>>>>> node,
>>>>>> if this device is fixed child of complex device (IOW, adi,ad3552r
>>>>>> cannot
>>>>>> be used outside of adi,axi-ad3552r).
>>>>>
>>>>> ad3552r can still be used by a generic "classic" spi
>>>>> controller (SCLK/CS/MISO) but at a slower samplerate, fpga
>>>>> controller only (axi-ad3552r) can reach 33MUPS.
>>>>
>>>> OK, then this is just redundant. Drop the node. Parent example should
>>>> contain the children, though.
>>>>>
>>>>>>
>>>>>>> +        reg = <0x44a70000 0x1000>;
>>>>>>> +        dmas = <&dac_tx_dma 0>;
>>>>>>> +        dma-names = "tx";
>>>>>>> +        #io-backend-cells = <0>;
>>>>>>> +        clocks = <&ref_clk>;
>>>>>>> +
>>>>>>> +        #address-cells = <1>;
>>>>>>> +        #size-cells = <0>;
>>>>>>> +
>>>>>>> +        dac@0 {
>>>>>>> +            compatible = "adi,ad3552r";
>>>>>>> +            reg = <0>;
>>>>>>> +            reset-gpios = <&gpio0 92 0>;
>>>>>> Use standard defines for GPIO flags.
>>>>>
>>>>> fixed, thanks
>>>>>
>>>>>>> +            io-backends = <&axi_dac>;
>>>>>> Why do you need to point to the parent? How much coupled are these
>>>>>> devices? Child pointing to parent is not usually expected, because
>>>>>> that's obvious.
>>>>>
>>>>>
>>>>> "io-backends" is actually the way to refer to the backend module,
>>>>> (used already for i.e. ad9739a),
>>>>> it is needed because the backend is not only acting as spi-controller,
>>>>> but is also providing some APIs for synchronization and bus setup
>>>>> support.
>>>>
>>>>
>>>> But if backend is the parent, then this is redundant. You can take it
>>>> from the child-parent relationship. Is this pointing to other devices
>>>> (non-parent) in other ad3552r configurations?
>>>>
>>>
>>> The backend is a provider-consumer type of API. On the consumer side (which
>>> is the
>>> driver the child node will probe on), we need to call devm_iio_backend_get()
>>> to get
>>> the backend object (which obviously is the parent). For that, 'io-backends'
>>> is being
>>
>> You described the driver, so how does it matter? Driver can call
>> get_backend_from_parent(), right? Or get_backend_from_fwnode(parent)?
> 
> Well yes, just stating what the framework (also in terms of bindings) is
> expecting. Of course that on the driver side we can paper around it the way we
> want. But my main point was that we can only paper around it if we use code that
> is meant not to be used.
> 
> And, FWIW, I was (trying) replying to your comment
> 
> "You can take it from the child-parent relationship"
> 
> Again, we can only do that by introducing new code or use code that's not meant
> to be used. The way we're supposed to reference backends is by explicitly using
> the proper FW property.
> 
> Put it in another way and a completely hypothetical case. If we have a spi
> controller which happens to export some clock and one of it's peripherals ends
> up using that clock, wouldn't we still use 'clocks' to reference that clock?

I asked how coupled are these devices. Never got the answer and you are
reflecting with question. Depends. Please do not create hypothetical,
generic scenarios and then apply them to your one particular opposite case.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 01/10] iio: backend: adi-axi-dac: fix wrong register bitfield
  2024-09-20 12:45   ` Nuno Sá
@ 2024-09-29 10:38     ` Jonathan Cameron
  0 siblings, 0 replies; 59+ messages in thread
From: Jonathan Cameron @ 2024-09-29 10:38 UTC (permalink / raw)
  To: Nuno Sá
  Cc: Angelo Dureghello, Lars-Peter Clausen, Michael Hennerich, Nuno Sa,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan,
	linux-iio, linux-kernel, devicetree, dlechner

On Fri, 20 Sep 2024 14:45:42 +0200
Nuno Sá <noname.nuno@gmail.com> wrote:

> On Thu, 2024-09-19 at 11:19 +0200, Angelo Dureghello wrote:
> > From: Angelo Dureghello <adureghello@baylibre.com>
> > 
> > Fix ADI_DAC_R1_MODE of AXI_DAC_REG_CNTRL_2.
> > 
> > Both generic DAC and ad3552r DAC IPs docs are reporting
> > bit 5 for it.
> > 
> > https://wiki.analog.com/resources/fpga/docs/axi_dac_ip
> > https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html

Can also turn these into Link: tags though that isn't particularly
important for reference links like these.  If you do, they are
part of the main tags block so no blank line between them
and your SoB.

> > 
> > Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> > ---  
> 
> Ouch... Missing Fixes tag. With that,
> 
> Reviewed-by: Nuno Sa <nuno.sa@analog.com>
> 
> >  drivers/iio/dac/adi-axi-dac.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c
> > index 0cb00f3bec04..b8b4171b8043 100644
> > --- a/drivers/iio/dac/adi-axi-dac.c
> > +++ b/drivers/iio/dac/adi-axi-dac.c
> > @@ -46,7 +46,7 @@
> >  #define AXI_DAC_REG_CNTRL_1		0x0044
> >  #define   AXI_DAC_SYNC			BIT(0)
> >  #define AXI_DAC_REG_CNTRL_2		0x0048
> > -#define	  ADI_DAC_R1_MODE		BIT(4)
> > +#define	  ADI_DAC_R1_MODE		BIT(5)
> >  #define AXI_DAC_DRP_STATUS		0x0074
> >  #define   AXI_DAC_DRP_LOCKED		BIT(17)
> >  /* DAC Channel controls */
> >   
> 


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 02/10] dt-bindings: iio: dac: axi-dac: add ad3552r axi variant
  2024-09-19  9:19 ` [PATCH v3 02/10] dt-bindings: iio: dac: axi-dac: add ad3552r axi variant Angelo Dureghello
  2024-09-20 12:47   ` Nuno Sá
  2024-09-22 20:59   ` Krzysztof Kozlowski
@ 2024-09-29 10:46   ` Jonathan Cameron
  2024-09-30 12:52     ` Angelo Dureghello
  2 siblings, 1 reply; 59+ messages in thread
From: Jonathan Cameron @ 2024-09-29 10:46 UTC (permalink / raw)
  To: Angelo Dureghello
  Cc: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Olivier Moysan, linux-iio,
	linux-kernel, devicetree, dlechner, Mark Brown, linux-spi

On Thu, 19 Sep 2024 11:19:58 +0200
Angelo Dureghello <adureghello@baylibre.com> wrote:

> From: Angelo Dureghello <adureghello@baylibre.com>
> 
> Add a new compatible and related bindigns for the fpga-based
> "ad3552r" AXI IP core, a variant of the generic AXI DAC IP.
> 
> The AXI "ad3552r" IP is a very similar HDL (fpga) variant of the
> generic AXI "DAC" IP, intended to control ad3552r and similar chips,
> mainly to reach high speed transfer rates using an additional QSPI

I'd drop the word additional as I assume it is an 'either/or' situation
for the interfaces.

Do we have other devices using this same IP?  I.e. does it make
sense to provide a more generic compatible as a fallback for this one
so that other devices would work without the need for explicit support?


I'd also ideally like a view point from Mark Brown as SPI maintainer
on how we should deal with this highly specialized spi controller.
Is he happy with us using an SPI like binding but not figuring out how
to fit this engine into the SPI subsystem.

Please +CC Mark and the spi list (done here) on future versions + provide
a clear description of what is going on for them.

Maybe with the binding fixed as spi compliant, we can figure out the
if we eventually want to treat this as an SPI controller from the
kernel driver point of view even if we initially do something 'special'.

Jonathan


> DDR interface.
> 
> The ad3552r device is defined as a child of the AXI DAC, that in
> this case is acting as an SPI controller.
> 
> Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> ---
>  .../devicetree/bindings/iio/dac/adi,axi-dac.yaml   | 40 ++++++++++++++++++++--
>  1 file changed, 37 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml b/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml
> index a55e9bfc66d7..6cf0c2cb84e7 100644
> --- a/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml
> +++ b/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml
> @@ -19,11 +19,13 @@ description: |
>    memory via DMA into the DAC.
>  
>    https://wiki.analog.com/resources/fpga/docs/axi_dac_ip
> +  https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
>  
>  properties:
>    compatible:
>      enum:
>        - adi,axi-dac-9.1.b
> +      - adi,axi-ad3552r
>  
>    reg:
>      maxItems: 1
> @@ -41,22 +43,54 @@ properties:
>    '#io-backend-cells':
>      const: 0
>  
> +  '#address-cells':
> +    const: 1
> +
> +  '#size-cells':
> +    const: 0
> +
>  required:
>    - compatible
>    - dmas
>    - reg
>    - clocks
>  
> +patternProperties:
> +  "^.*@([0-9])$":
> +    type: object
> +    additionalProperties: true
> +    properties:
> +      io-backends:
> +        description: |
> +          AXI backend reference
> +    required:
> +      - io-backends
> +
>  additionalProperties: false
>  
>  examples:
>    - |
>      dac@44a00000 {
> -        compatible = "adi,axi-dac-9.1.b";
> -        reg = <0x44a00000 0x10000>;
> -        dmas = <&tx_dma 0>;
> +      compatible = "adi,axi-dac-9.1.b";
> +      reg = <0x44a00000 0x10000>;
> +      dmas = <&tx_dma 0>;

If it makes sense to reformat then separate patch
please as this is hard to read as a result of this
change.  Also, as pointed out, be consistent with spacing.

> +      dma-names = "tx";
> +      #io-backend-cells = <0>;
> +      clocks = <&axi_clk>;
> +    };
> +
> +  - |
> +    axi_dac: spi@44a70000 {
> +        compatible = "adi,axi-ad3552r";
> +        reg = <0x44a70000 0x1000>;
> +        dmas = <&dac_tx_dma 0>;
>          dma-names = "tx";
>          #io-backend-cells = <0>;
>          clocks = <&axi_clk>;
> +
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +
> +        /* DAC devices */
>      };
>  ...
> 


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support
  2024-09-19  9:20 ` [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support Angelo Dureghello
  2024-09-22 21:02   ` Krzysztof Kozlowski
@ 2024-09-29 10:51   ` Jonathan Cameron
  2024-09-30 14:15     ` Angelo Dureghello
  1 sibling, 1 reply; 59+ messages in thread
From: Jonathan Cameron @ 2024-09-29 10:51 UTC (permalink / raw)
  To: Angelo Dureghello
  Cc: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Olivier Moysan, linux-iio,
	linux-kernel, devicetree, dlechner

On Thu, 19 Sep 2024 11:20:00 +0200
Angelo Dureghello <adureghello@baylibre.com> wrote:

> From: Angelo Dureghello <adureghello@baylibre.com>
> 
> There is a version AXI DAC IP block (for FPGAs) that provides
> a physical bus for AD3552R and similar chips, and acts as
> an SPI controller.

Wrap is a bit short. Aim for < 75 chars for patch descriptions.

> 
> For this case, the binding is modified to include some
> additional properties.
> 
> Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> ---
>  .../devicetree/bindings/iio/dac/adi,ad3552r.yaml   | 42 ++++++++++++++++++++++
>  1 file changed, 42 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> index 41fe00034742..aca4a41c2633 100644
> --- a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> @@ -60,6 +60,18 @@ properties:
>      $ref: /schemas/types.yaml#/definitions/uint32
>      enum: [0, 1, 2, 3]
>  
> +  io-backends:
> +    description: The iio backend reference.

Give a description of what the backend does in this case.  I.e. that it is
a qspi DDR backend with ...

> +      An example backend can be found at
> +        https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
> +    maxItems: 1
> +
> +  adi,synchronous-mode:
> +    description: Enable waiting for external synchronization signal.
> +      Some AXI IP configuration can implement a dual-IP layout, with internal
> +      wirings for streaming synchronization.

I've no idea what a dual-IP layout is.  Can you provide a little more info
here?  What are the two IPs?

> +    type: boolean
> +
>    '#address-cells':
>      const: 1
>  
> @@ -128,6 +140,7 @@ patternProperties:
>            - custom-output-range-config
>  
>  allOf:
> +  - $ref: /schemas/spi/spi-peripheral-props.yaml#
>    - if:
>        properties:
>          compatible:
> @@ -238,4 +251,33 @@ examples:
>              };
>          };
>      };
> +
> +  - |
> +    axi_dac: spi@44a70000 {
> +        compatible = "adi,axi-ad3552r";
> +        reg = <0x44a70000 0x1000>;
> +        dmas = <&dac_tx_dma 0>;
> +        dma-names = "tx";
> +        #io-backend-cells = <0>;
> +        clocks = <&ref_clk>;
> +
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +
> +        dac@0 {
> +            compatible = "adi,ad3552r";
> +            reg = <0>;
> +            reset-gpios = <&gpio0 92 0>;
> +            io-backends = <&axi_dac>;
> +            spi-max-frequency = <66000000>;
> +
> +            #address-cells = <1>;
> +            #size-cells = <0>;
> +
> +            channel@0 {
> +                reg = <0>;
> +                adi,output-range-microvolt = <(-10000000) (10000000)>;
> +            };
> +        };
> +    };
>  ...
> 


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support
  2024-09-28 12:20               ` Krzysztof Kozlowski
@ 2024-09-29 10:59                 ` Jonathan Cameron
  2024-09-30  7:20                   ` Nuno Sá
  0 siblings, 1 reply; 59+ messages in thread
From: Jonathan Cameron @ 2024-09-29 10:59 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Nuno Sá, Angelo Dureghello, Lars-Peter Clausen,
	Michael Hennerich, Nuno Sa, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Olivier Moysan, linux-iio, linux-kernel, devicetree,
	dlechner

On Sat, 28 Sep 2024 14:20:29 +0200
Krzysztof Kozlowski <krzk@kernel.org> wrote:

> On 25/09/2024 13:55, Nuno Sá wrote:
> > On Wed, 2024-09-25 at 09:22 +0200, Krzysztof Kozlowski wrote:  
> >> On 24/09/2024 14:27, Nuno Sá wrote:  
> >>> On Tue, 2024-09-24 at 10:02 +0200, Krzysztof Kozlowski wrote:  
> >>>> On 23/09/2024 17:50, Angelo Dureghello wrote:  
> >>>>> Hi Krzysztof,
> >>>>>
> >>>>> On 22/09/24 23:02, Krzysztof Kozlowski wrote:  
> >>>>>> On Thu, Sep 19, 2024 at 11:20:00AM +0200, Angelo Dureghello wrote:  
> >>>>>>> From: Angelo Dureghello <adureghello@baylibre.com>
> >>>>>>>
> >>>>>>> There is a version AXI DAC IP block (for FPGAs) that provides
> >>>>>>> a physical bus for AD3552R and similar chips, and acts as
> >>>>>>> an SPI controller.
> >>>>>>>
> >>>>>>> For this case, the binding is modified to include some
> >>>>>>> additional properties.
> >>>>>>>
> >>>>>>> Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> >>>>>>> ---
> >>>>>>>   .../devicetree/bindings/iio/dac/adi,ad3552r.yaml   | 42
> >>>>>>> ++++++++++++++++++++++
> >>>>>>>   1 file changed, 42 insertions(+)
> >>>>>>>
> >>>>>>> diff --git
> >>>>>>> a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> >>>>>>> b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> >>>>>>> index 41fe00034742..aca4a41c2633 100644
> >>>>>>> --- a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> >>>>>>> +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> >>>>>>> @@ -60,6 +60,18 @@ properties:
> >>>>>>>       $ref: /schemas/types.yaml#/definitions/uint32
> >>>>>>>       enum: [0, 1, 2, 3]
> >>>>>>>   
> >>>>>>> +  io-backends:
> >>>>>>> +    description: The iio backend reference.
> >>>>>>> +      An example backend can be found at
> >>>>>>> +       
> >>>>>>> https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
> >>>>>>> +    maxItems: 1
> >>>>>>> +
> >>>>>>> +  adi,synchronous-mode:
> >>>>>>> +    description: Enable waiting for external synchronization
> >>>>>>> signal.
> >>>>>>> +      Some AXI IP configuration can implement a dual-IP layout,
> >>>>>>> with
> >>>>>>> internal
> >>>>>>> +      wirings for streaming synchronization.
> >>>>>>> +    type: boolean
> >>>>>>> +
> >>>>>>>     '#address-cells':
> >>>>>>>       const: 1
> >>>>>>>   
> >>>>>>> @@ -128,6 +140,7 @@ patternProperties:
> >>>>>>>             - custom-output-range-config
> >>>>>>>   
> >>>>>>>   allOf:
> >>>>>>> +  - $ref: /schemas/spi/spi-peripheral-props.yaml#
> >>>>>>>     - if:
> >>>>>>>         properties:
> >>>>>>>           compatible:
> >>>>>>> @@ -238,4 +251,33 @@ examples:
> >>>>>>>               };
> >>>>>>>           };
> >>>>>>>       };
> >>>>>>> +
> >>>>>>> +  - |
> >>>>>>> +    axi_dac: spi@44a70000 {
> >>>>>>> +        compatible = "adi,axi-ad3552r";  
> >>>>>> That is either redundant or entire example should go to the parent
> >>>>>> node,
> >>>>>> if this device is fixed child of complex device (IOW, adi,ad3552r
> >>>>>> cannot
> >>>>>> be used outside of adi,axi-ad3552r).  
> >>>>>
> >>>>> ad3552r can still be used by a generic "classic" spi
> >>>>> controller (SCLK/CS/MISO) but at a slower samplerate, fpga
> >>>>> controller only (axi-ad3552r) can reach 33MUPS.  
> >>>>
> >>>> OK, then this is just redundant. Drop the node. Parent example should
> >>>> contain the children, though.  
> >>>>>  
> >>>>>>  
> >>>>>>> +        reg = <0x44a70000 0x1000>;
> >>>>>>> +        dmas = <&dac_tx_dma 0>;
> >>>>>>> +        dma-names = "tx";
> >>>>>>> +        #io-backend-cells = <0>;
> >>>>>>> +        clocks = <&ref_clk>;
> >>>>>>> +
> >>>>>>> +        #address-cells = <1>;
> >>>>>>> +        #size-cells = <0>;
> >>>>>>> +
> >>>>>>> +        dac@0 {
> >>>>>>> +            compatible = "adi,ad3552r";
> >>>>>>> +            reg = <0>;
> >>>>>>> +            reset-gpios = <&gpio0 92 0>;  
> >>>>>> Use standard defines for GPIO flags.  
> >>>>>
> >>>>> fixed, thanks
> >>>>>  
> >>>>>>> +            io-backends = <&axi_dac>;  
> >>>>>> Why do you need to point to the parent? How much coupled are these
> >>>>>> devices? Child pointing to parent is not usually expected, because
> >>>>>> that's obvious.  
> >>>>>
> >>>>>
> >>>>> "io-backends" is actually the way to refer to the backend module,
> >>>>> (used already for i.e. ad9739a),
> >>>>> it is needed because the backend is not only acting as spi-controller,
> >>>>> but is also providing some APIs for synchronization and bus setup
> >>>>> support.  
> >>>>
> >>>>
> >>>> But if backend is the parent, then this is redundant. You can take it
> >>>> from the child-parent relationship. Is this pointing to other devices
> >>>> (non-parent) in other ad3552r configurations?
> >>>>  
> >>>
> >>> The backend is a provider-consumer type of API. On the consumer side (which
> >>> is the
> >>> driver the child node will probe on), we need to call devm_iio_backend_get()
> >>> to get
> >>> the backend object (which obviously is the parent). For that, 'io-backends'
> >>> is being  
> >>
> >> You described the driver, so how does it matter? Driver can call
> >> get_backend_from_parent(), right? Or get_backend_from_fwnode(parent)?  
> > 
> > Well yes, just stating what the framework (also in terms of bindings) is
> > expecting. Of course that on the driver side we can paper around it the way we
> > want. But my main point was that we can only paper around it if we use code that
> > is meant not to be used.
> > 
> > And, FWIW, I was (trying) replying to your comment
> > 
> > "You can take it from the child-parent relationship"
> > 
> > Again, we can only do that by introducing new code or use code that's not meant
> > to be used. The way we're supposed to reference backends is by explicitly using
> > the proper FW property.
> > 
> > Put it in another way and a completely hypothetical case. If we have a spi
> > controller which happens to export some clock and one of it's peripherals ends
> > up using that clock, wouldn't we still use 'clocks' to reference that clock?  
> 
> I asked how coupled are these devices. Never got the answer and you are
> reflecting with question. Depends. Please do not create hypothetical,
> generic scenarios and then apply them to your one particular opposite case.

I'll throw a possible clarifying question in here.  Could we use this
device with a multimaster SPI setup such that the control is on a conventional
SPI controller (maybe a qspi capable one), and the data plane only goes through
a specific purpose backend?  If so, then they are not tightly coupled and
the reference makes sense.  Putting it another way, the difference between
this case and all the prior iio-backend bindings is the control and dataplanes
use the same pins.  Does that have to be the case at the host end?  If it does,
then the reference isn't strictly needed and this becomes a bit like
registering a single device on an spi bus or an i2c bus depending on who
does the registering (which is down to the parent in DT).

Jonathan


> 
> Best regards,
> Krzysztof
> 


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 05/10] iio: backend: extend features
  2024-09-19  9:20 ` [PATCH v3 05/10] iio: backend: extend features Angelo Dureghello
  2024-09-20 12:50   ` Nuno Sá
@ 2024-09-29 11:05   ` Jonathan Cameron
  2024-09-30 19:25     ` David Lechner
  1 sibling, 1 reply; 59+ messages in thread
From: Jonathan Cameron @ 2024-09-29 11:05 UTC (permalink / raw)
  To: Angelo Dureghello
  Cc: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Olivier Moysan, linux-iio,
	linux-kernel, devicetree, dlechner

On Thu, 19 Sep 2024 11:20:01 +0200
Angelo Dureghello <adureghello@baylibre.com> wrote:

> From: Angelo Dureghello <adureghello@baylibre.com>
> 
> Extend backend features with new calls needed later on this
> patchset from axi version of ad3552r.
> 
> The follwoing calls are added:
> 
> iio_backend_ext_sync_enable
> 	enable synchronize channels on external trigger
> iio_backend_ext_sync_disable
> 	disable synchronize channels on external trigger
> iio_backend_ddr_enable
> 	enable ddr bus transfer
> iio_backend_ddr_disable
> 	disable ddr bus transfer
> iio_backend_set_bus_mode
> 	select the type of bus, so that specific read / write
> 	operations are performed accordingly
> iio_backend_buffer_enable
> 	enable buffer
> iio_backend_buffer_disable
> 	disable buffer
> iio_backend_data_transfer_addr
> 	define the target register address where the DAC sample
> 	will be written.
> 
> Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
Hi Angelo,
A few trivial comments inline.

> ---
>  drivers/iio/industrialio-backend.c | 111 +++++++++++++++++++++++++++++++++++++
>  include/linux/iio/backend.h        |  23 ++++++++
>  2 files changed, 134 insertions(+)
> 
> diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c
> index 20b3b5212da7..f4802c422dbf 100644
> --- a/drivers/iio/industrialio-backend.c
> +++ b/drivers/iio/industrialio-backend.c
> @@ -718,6 +718,117 @@ static int __devm_iio_backend_get(struct device *dev, struct iio_backend *back)
...

> +/**
> + * iio_backend_ddr_disable - Disable interface DDR (Double Data Rate) mode
> + * @back: Backend device
> + *
> + * Disabling DDR data is generated byt the IP at rising or falling front

Spell check your comments.

> + * of the interface clock signal (SDR, Single Data Rate).
> + *
> + * RETURNS:
> + * 0 on success, negative error number on failure.
> + */
> +int iio_backend_ddr_disable(struct iio_backend *back)
> +{
> +	return iio_backend_op_call(back, ddr_disable);
> +}
> +EXPORT_SYMBOL_NS_GPL(iio_backend_ddr_disable, IIO_BACKEND);
				 struct fwnode_handle *fwnode)
>  {
> diff --git a/include/linux/iio/backend.h b/include/linux/iio/backend.h
> index 37d56914d485..41619b803cd6 100644
> --- a/include/linux/iio/backend.h
> +++ b/include/linux/iio/backend.h
> @@ -14,12 +14,14 @@ struct iio_dev;
>  enum iio_backend_data_type {
>  	IIO_BACKEND_TWOS_COMPLEMENT,
>  	IIO_BACKEND_OFFSET_BINARY,
> +	IIO_BACKEND_DATA_UNSIGNED,
>  	IIO_BACKEND_DATA_TYPE_MAX
>  };
>  
>  enum iio_backend_data_source {
>  	IIO_BACKEND_INTERNAL_CONTINUOUS_WAVE,
>  	IIO_BACKEND_EXTERNAL,
> +	IIO_BACKEND_INTERNAL_RAMP_16BIT,
>  	IIO_BACKEND_DATA_SOURCE_MAX
>  };
>  
> @@ -89,6 +91,13 @@ enum iio_backend_sample_trigger {
>   * @read_raw: Read a channel attribute from a backend device
>   * @debugfs_print_chan_status: Print channel status into a buffer.
>   * @debugfs_reg_access: Read or write register value of backend.
> + * @ext_sync_enable: Enable external synchronization.
> + * @ext_sync_disable: Disable external synchronization.
> + * @ddr_enable: Enable interface DDR (Double Data Rate) mode.
> + * @ddr_disable: Disable interface DDR (Double Data Rate) mode.
> + * @buffer_enable: Enable data buffer.
> + * @buffer_disable: Disable data buffer.

This needs more specific text. What buffer?  I think this came
up earlier but it needs to say something about the fact it's enabling
or disabling the actual capture of data into the DMA buffers that
userspace will read.

> + * @data_transfer_addr: Set data address.
>   **/
>  struct iio_backend_ops {
>  	int (*enable)(struct iio_backend *back);
> @@ -129,6 +138,13 @@ struct iio_backend_ops {
>  					 size_t len);
>  	int (*debugfs_reg_access)(struct iio_backend *back, unsigned int reg,
>  				  unsigned int writeval, unsigned int *readval);
> +	int (*ext_sync_enable)(struct iio_backend *back);
I know we've done it this way for existing items, but I wonder if we should
squish down the ops slightly and have new enable/disable pairs as
single functions.
	int (*ext_sync_set_state)(struct iio_backend *back, bool enable);
etc.  If nothing else reduces how many things need documentation ;)

Nuno, what do you think? Worth squashing these pairs into single
callbacks?

> +	int (*ext_sync_disable)(struct iio_backend *back);
> +	int (*ddr_enable)(struct iio_backend *back);
> +	int (*ddr_disable)(struct iio_backend *back);
> +	int (*buffer_enable)(struct iio_backend *back);
> +	int (*buffer_disable)(struct iio_backend *back);
> +	int (*data_transfer_addr)(struct iio_backend *back, u32 address);
>  };

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 06/10] iio: backend: adi-axi-dac: extend features
  2024-09-19  9:20 ` [PATCH v3 06/10] iio: backend: adi-axi-dac: " Angelo Dureghello
  2024-09-20 13:10   ` Nuno Sá
@ 2024-09-29 11:28   ` Jonathan Cameron
  1 sibling, 0 replies; 59+ messages in thread
From: Jonathan Cameron @ 2024-09-29 11:28 UTC (permalink / raw)
  To: Angelo Dureghello
  Cc: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Olivier Moysan, linux-iio,
	linux-kernel, devicetree, dlechner

On Thu, 19 Sep 2024 11:20:02 +0200
Angelo Dureghello <adureghello@baylibre.com> wrote:

> From: Angelo Dureghello <adureghello@baylibre.com>
> 
> Extend AXI-DAC backend with new features required to interface
> to the ad3552r DAC. Mainly, a new compatible string is added to
> support the ad3552r-axi DAC IP, very similar to the generic DAC
> IP but with some customizations to work with the ad3552r.
> 
> Then, a serie of generic functions has been added to match with
> ad3552r needs. Function names has been kept generic as much as
> possible, to allow re-utilization from other frontend drivers.
> 
> Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
Hi Angelo,

A few things in addition to Nuno's review.

> ---
>  drivers/iio/dac/adi-axi-dac.c | 274 ++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 265 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c
> index b8b4171b8043..3ca3a14c575b 100644
> --- a/drivers/iio/dac/adi-axi-dac.c
> +++ b/drivers/iio/dac/adi-axi-dac.c
> @@ -44,11 +44,34 @@
>  #define   AXI_DAC_RSTN_MMCM_RSTN	BIT(1)
>  #define   AXI_DAC_RSTN_RSTN		BIT(0)
>  #define AXI_DAC_REG_CNTRL_1		0x0044
> +#define   AXI_DAC_EXT_SYNC_ARM		BIT(1)
> +#define   AXI_DAC_EXT_SYNC_DISARM	BIT(2)

Probably want some sort of order in here!  Either do highest
to lowest bit or the other way around. Not a mixture.
I should probably have moaned about this earlier, but naming these
defines to make it clear what is the register address and which
fields belong to that register.  Right now that's not easy to tell
for most of these and means that more effort is needed in review
to check values are written to the relevant register and not some
other one.

Perhaps a precursor patch to clean that up would be a good idea.
(or do it right for the new stuff and chase this with a patch tidying
up the existing registers).

The exisint defines seem to have _REG_ in the middle which sort
of does this role but then the fields are not associated with the
register.

E.g. this one should be something like
#define    AXI_DAC_FIELD_CNTRL_1_EXT_SYNC_ARM	BIT(1)

More common would be to move _REG_ to the end and then just
have fields as the ones that aren't _REG

>  #define   AXI_DAC_SYNC			BIT(0)
>  #define AXI_DAC_REG_CNTRL_2		0x0048
> +#define   AXI_DAC_SDR_DDR_N		BIT(16)
> +#define   AXI_DAC_SYMB_8B		BIT(14)
>  #define	  ADI_DAC_R1_MODE		BIT(5)

Oddity of tabs vs spaces here that should be consistent.

> +#define   AXI_DAC_UNSIGNED_DATA		BIT(4)
> +#define AXI_DAC_REG_STATUS_1		0x54
> +#define AXI_DAC_REG_STATUS_2		0x58
>  #define AXI_DAC_DRP_STATUS		0x0074
>  #define   AXI_DAC_DRP_LOCKED		BIT(17)
> +#define AXI_DAC_CNTRL_DATA_RD		0x0080

Prior cases have _REG_ for the registers, this one doesn't.

> +#define   AXI_DAC_DATA_RD_8		GENMASK(7, 0)
> +#define   AXI_DAC_DATA_RD_16		GENMASK(15, 0)
> +#define AXI_DAC_CNTRL_DATA_WR		0x0084
> +#define   AXI_DAC_DATA_WR_8		GENMASK(23, 16)
> +#define   AXI_DAC_DATA_WR_16		GENMASK(23, 8)

Huh. interesting IP, it's aligned one way for read path and the opposite
for write. I bet that never introduces any bugs :)
I'd started commenting the DATA_RD cases seemed obvious enough not
to need defines before I read on a few lines!

> +#define AXI_DAC_UI_STATUS		0x0088
> +#define   AXI_DAC_BUSY			BIT(4)
> +#define AXI_DAC_REG_CUSTOM_CTRL		0x008C
> +#define   AXI_DAC_ADDRESS		GENMASK(31, 24)
> +#define   AXI_DAC_SYNCED_TRANSFER	BIT(2)
> +#define   AXI_DAC_STREAM		BIT(1)
> +#define   AXI_DAC_TRANSFER_DATA		BIT(0)


> +static int axi_dac_bus_reg_write(struct iio_backend *back, u32 reg,
> +				 unsigned int val, size_t data_size)
> +{
> +	struct axi_dac_state *st = iio_backend_get_priv(back);
> +
> +	switch (st->info->bus_type) {
> +	case AXI_DAC_BUS_TYPE_DDR_QSPI: {
> +		int ret;
> +		u32 ival;
> +
> +		if (data_size == 2)
> +			ival = FIELD_PREP(AXI_DAC_DATA_WR_16, val);
> +		else
> +			ival = FIELD_PREP(AXI_DAC_DATA_WR_8, val);
> +
> +		ret = regmap_write(st->regmap, AXI_DAC_CNTRL_DATA_WR, ival);
> +		if (ret)
> +			return ret;
> +
> +		/*
> +		 * Both REG_CNTRL_2 and AXI_DAC_CNTRL_DATA_WR need to know
> +		 * the data size. So keeping data size control here only,
> +		 * since data size is mandatory for the current transfer.
> +		 * DDR state handled separately by specific backend calls,
> +		 * generally all raw register writes are SDR.
> +		 */
> +		if (data_size == 1)
> +			ret = regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_2,
> +					      AXI_DAC_SYMB_8B);
> +		else
> +			ret = regmap_clear_bits(st->regmap, AXI_DAC_REG_CNTRL_2,
> +						AXI_DAC_SYMB_8B);
> +		if (ret)
> +			return ret;
> +
> +		ret = regmap_update_bits(st->regmap, AXI_DAC_REG_CUSTOM_CTRL,
> +					 AXI_DAC_ADDRESS,
> +					 FIELD_PREP(AXI_DAC_ADDRESS, reg));
> +		if (ret)
> +			return ret;
> +
> +		ret = regmap_update_bits(st->regmap, AXI_DAC_REG_CUSTOM_CTRL,
> +					 AXI_DAC_TRANSFER_DATA,
> +					 AXI_DAC_TRANSFER_DATA);
> +		if (ret)
> +			return ret;
> +
> +		ret = regmap_read_poll_timeout(st->regmap,
> +					       AXI_DAC_REG_CUSTOM_CTRL, ival,
> +					       ival & AXI_DAC_TRANSFER_DATA,
> +					       10, 100 * KILO);
> +		if (ret)
> +			return ret;
> +
> +		return regmap_clear_bits(st->regmap, AXI_DAC_REG_CUSTOM_CTRL,
> +					  AXI_DAC_TRANSFER_DATA);
> +	}
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +}
> +
> +static int axi_dac_bus_reg_read(struct iio_backend *back, u32 reg,
> +				unsigned int *val, size_t data_size)
> +{
> +	struct axi_dac_state *st = iio_backend_get_priv(back);
> +
> +	switch (st->info->bus_type) {
> +	case AXI_DAC_BUS_TYPE_DDR_QSPI: {
> +		int ret;
> +		u32 bval;
> +
> +		ret = axi_dac_bus_reg_write(back, AXI_DAC_RD_ADDR(reg), 0,
> +					    data_size);
> +		if (ret)

So the data size is in the write of the register not the read. That seems odd.
I guess this is about setting the bit that says how bit the read is going to be?
Maybe a comment would help here.


> +			return ret;
> +
> +		ret = regmap_read_poll_timeout(st->regmap, AXI_DAC_UI_STATUS,
> +					       bval, bval != AXI_DAC_BUSY,
> +					       10, 100);
> +		if (ret)
> +			return ret;
> +
> +		return regmap_read(st->regmap, AXI_DAC_CNTRL_DATA_RD, val);
I supposed datasize doesn't strictly matter here, but for ease of readability
I'd do FIELD_GET() to pull out only what was requested.

> +	}
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +}
> +
>  static const struct iio_backend_ops axi_dac_generic_ops = {
>  	.enable = axi_dac_enable,
>  	.disable = axi_dac_disable,
> +	.read_raw = axi_dac_read_raw,
>  	.request_buffer = axi_dac_request_buffer,
>  	.free_buffer = axi_dac_free_buffer,
>  	.extend_chan_spec = axi_dac_extend_chan,
> @@ -528,6 +768,14 @@ static const struct iio_backend_ops axi_dac_generic_ops = {
>  	.ext_info_get = axi_dac_ext_info_get,
>  	.data_source_set = axi_dac_data_source_set,
>  	.set_sample_rate = axi_dac_set_sample_rate,
> +	.ext_sync_enable = axi_dac_ext_sync_enable,
> +	.ext_sync_disable = axi_dac_ext_sync_disable,
> +	.ddr_enable = axi_dac_ddr_enable,
> +	.ddr_disable = axi_dac_ddr_disable,
> +	.buffer_enable = axi_dac_buffer_enable,
> +	.buffer_disable = axi_dac_buffer_disable,
> +	.data_format_set = axi_dac_data_format_set,
> +	.data_transfer_addr = axi_dac_data_transfer_addr,
>  	.debugfs_reg_access = iio_backend_debugfs_ptr(axi_dac_reg_access),
>  };
>  
> @@ -545,7 +793,6 @@ static const struct regmap_config axi_dac_regmap_config = {
>  
>  static int axi_dac_probe(struct platform_device *pdev)
>  {
> -	const unsigned int *expected_ver;
>  	struct axi_dac_state *st;
>  	void __iomem *base;
>  	unsigned int ver;
> @@ -556,8 +803,8 @@ static int axi_dac_probe(struct platform_device *pdev)
>  	if (!st)
>  		return -ENOMEM;
>  
> -	expected_ver = device_get_match_data(&pdev->dev);
> -	if (!expected_ver)
> +	st->info = device_get_match_data(&pdev->dev);
> +	if (!st->info)
>  		return -ENODEV;
>  
>  	clk = devm_clk_get_enabled(&pdev->dev, NULL);
> @@ -588,12 +835,13 @@ static int axi_dac_probe(struct platform_device *pdev)
>  	if (ret)
>  		return ret;
>  
> -	if (ADI_AXI_PCORE_VER_MAJOR(ver) != ADI_AXI_PCORE_VER_MAJOR(*expected_ver)) {
> +	if (ADI_AXI_PCORE_VER_MAJOR(ver) !=
> +		ADI_AXI_PCORE_VER_MAJOR(st->info->version)) {
>  		dev_err(&pdev->dev,
>  			"Major version mismatch. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n",
> -			ADI_AXI_PCORE_VER_MAJOR(*expected_ver),
> -			ADI_AXI_PCORE_VER_MINOR(*expected_ver),
> -			ADI_AXI_PCORE_VER_PATCH(*expected_ver),
> +			ADI_AXI_PCORE_VER_MAJOR(st->info->version),
> +			ADI_AXI_PCORE_VER_MINOR(st->info->version),
> +			ADI_AXI_PCORE_VER_PATCH(st->info->version),
>  			ADI_AXI_PCORE_VER_MAJOR(ver),
>  			ADI_AXI_PCORE_VER_MINOR(ver),
>  			ADI_AXI_PCORE_VER_PATCH(ver));
> @@ -631,10 +879,18 @@ static int axi_dac_probe(struct platform_device *pdev)
>  	return 0;
>  }
>  
> -static unsigned int axi_dac_9_1_b_info = ADI_AXI_PCORE_VER(9, 1, 'b');
> +static const struct axi_dac_info dac_generic = {
> +	.version = ADI_AXI_PCORE_VER(9, 1, 'b'),
> +};
> +
> +static const struct axi_dac_info dac_ad3552r = {
> +	.version = ADI_AXI_PCORE_VER(9, 1, 'b'),
> +	.bus_type = AXI_DAC_BUS_TYPE_DDR_QSPI,
> +};
>  
>  static const struct of_device_id axi_dac_of_match[] = {
> -	{ .compatible = "adi,axi-dac-9.1.b", .data = &axi_dac_9_1_b_info },
> +	{ .compatible = "adi,axi-dac-9.1.b", .data = &dac_generic },
> +	{ .compatible = "adi,axi-ad3552r", .data = &dac_ad3552r },
>  	{}
>  };
>  MODULE_DEVICE_TABLE(of, axi_dac_of_match);
> 


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 08/10] iio: dac: ad3552r: extract common code (no changes in behavior intended)
  2024-09-19  9:20 ` [PATCH v3 08/10] iio: dac: ad3552r: extract common code (no changes in behavior intended) Angelo Dureghello
@ 2024-09-29 11:57   ` Jonathan Cameron
  2024-10-02 15:50     ` Angelo Dureghello
  0 siblings, 1 reply; 59+ messages in thread
From: Jonathan Cameron @ 2024-09-29 11:57 UTC (permalink / raw)
  To: Angelo Dureghello
  Cc: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Olivier Moysan, linux-iio,
	linux-kernel, devicetree, dlechner

On Thu, 19 Sep 2024 11:20:04 +0200
Angelo Dureghello <adureghello@baylibre.com> wrote:

> From: Angelo Dureghello <adureghello@baylibre.com>
> 
> Extracting common code, to share common code to be used later
> by the AXI driver version (ad3552r-axi.c).
> 
> Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
For these, main request is to move them to a namespace + GPL is
probably the appropriate choice here.


> ---
>  drivers/iio/dac/Makefile         |   2 +-
>  drivers/iio/dac/ad3552r-common.c | 173 +++++++++++++++++++++++
>  drivers/iio/dac/ad3552r.c        | 293 ++++-----------------------------------
>  drivers/iio/dac/ad3552r.h        | 190 +++++++++++++++++++++++++
>  4 files changed, 390 insertions(+), 268 deletions(-)
> 
> diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
> index 2cf148f16306..56a125f56284 100644
> --- a/drivers/iio/dac/Makefile
> +++ b/drivers/iio/dac/Makefile
> @@ -4,7 +4,7 @@
>  #
>  
>  # When adding new entries keep the list in alphabetical order
> -obj-$(CONFIG_AD3552R) += ad3552r.o
> +obj-$(CONFIG_AD3552R) += ad3552r.o ad3552r-common.o
>  obj-$(CONFIG_AD5360) += ad5360.o
>  obj-$(CONFIG_AD5380) += ad5380.o
>  obj-$(CONFIG_AD5421) += ad5421.o
> diff --git a/drivers/iio/dac/ad3552r-common.c b/drivers/iio/dac/ad3552r-common.c
> new file mode 100644
> index 000000000000..624f3f97cdea
> --- /dev/null
> +++ b/drivers/iio/dac/ad3552r-common.c
> @@ -0,0 +1,173 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +//
> +// Copyright (c) 2010-2024 Analog Devices Inc.
> +// Copyright (c) 2024 Baylibre, SAS
> +
> +#include <linux/device.h>
> +#include <linux/module.h>
> +#include <linux/property.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include "ad3552r.h"
> +
> +const s32 ad3552r_ch_ranges[AD3552R_MAX_RANGES][2] = {
> +	[AD3552R_CH_OUTPUT_RANGE_0__2P5V]	= { 0, 2500 },
> +	[AD3552R_CH_OUTPUT_RANGE_0__5V]		= { 0, 5000 },
> +	[AD3552R_CH_OUTPUT_RANGE_0__10V]	= { 0, 10000 },
> +	[AD3552R_CH_OUTPUT_RANGE_NEG_5__5V]	= { -5000, 5000 },
> +	[AD3552R_CH_OUTPUT_RANGE_NEG_10__10V]	= { -10000, 10000 }
> +};
> +EXPORT_SYMBOL(ad3552r_ch_ranges);

GPL and namespace them to avoid poluting the general namespace with driver
specific exports.

EXPORT_SYMBOL_NS_GPL() etc.


> +
> +u16 ad3552r_calc_custom_gain(u8 p, u8 n, s16 goffs)
> +{
> +	u16 reg;
> +
> +	reg = FIELD_PREP(AD3552R_MASK_CH_RANGE_OVERRIDE, 1);
> +	reg |= FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_P, p);
> +	reg |= FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_N, n);
> +	reg |= FIELD_PREP(AD3552R_MASK_CH_OFFSET_BIT_8, abs((s32)goffs) >> 8);
Hmm. Not sure the s32 case does anything useful here.
Also this is a little messy from local view of code. It is not obvious
that only BIT(0) can be set here.  I'd be tempted to mask that
before passing to FIELD_PREP()

> +	reg |= FIELD_PREP(AD3552R_MASK_CH_OFFSET_POLARITY, (s32)goffs < 0);

Why do you need the s32 cast for this last line?

> +
> +	return reg;
> +}
> +
> +int ad3552r_get_ref_voltage(struct device *dev)
> +{
> +	int voltage;
> +	int delta = 100000;
> +
> +	voltage = devm_regulator_get_enable_read_voltage(dev, "vref");
> +	if (voltage < 0 && voltage != -ENODEV)
> +		return dev_err_probe(dev, voltage,
> +				     "Error getting vref voltage\n");
> +
> +	if (voltage == -ENODEV) {
> +		if (device_property_read_bool(dev, "adi,vref-out-en"))
> +			return AD3552R_INTERNAL_VREF_PIN_2P5V;
> +		else
> +			return AD3552R_INTERNAL_VREF_PIN_FLOATING;
> +	}
> +
> +	if (voltage > 2500000 + delta || voltage < 2500000 - delta) {
> +		dev_warn(dev, "vref-supply must be 2.5V");
> +		return -EINVAL;
> +	}

Obviously this is legacy code, but why do we care in the driver?
If someone has circuitry or configuration that is wrong, do we need to check
that?  I guess it does little harm though.

> +
> +	return AD3552R_EXTERNAL_VREF_PIN_INPUT;
> +}
> +
> +int ad3552r_get_drive_strength(struct device *dev, u32 *val)
> +{
> +	int err;
> +
> +	err = device_property_read_u32(dev, "adi,sdo-drive-strength", val);
> +	if (err)
> +		return err;
> +
> +	if (*val > 3) {

Usually we avoid setting values passed back on error if it is easy to do so.
I'd bounce via a local variable and only set *val = drive_strength
after you know it is in range.

> +		dev_err(dev,
> +			"adi,sdo-drive-strength must be less than 4\n");
> +		return -EINVAL;
Is dev_err_probe() appropriate here?  I haven't checked if this is called
from non probe paths so ignore this comment if it is.
> +	}
> +
> +	return 0;
> +}
> +
> +int ad3552r_get_custom_gain(struct device *dev, struct fwnode_handle *child,
> +			    u8 *gs_p, u8 *gs_n, u16 *rfb, s16 *goffs)
> +{
> +	int err;
> +	u32 val;
> +	struct fwnode_handle *gain_child __free(fwnode_handle) =
> +				fwnode_get_named_child_node(child,
One tab more than the line above is fine for cases like this and makes for
more readable code.

> +				"custom-output-range-config");

Align this final parameter with c of child.

> +
> +	if (!gain_child)
> +		return dev_err_probe(dev, -EINVAL,
> +				     "custom-output-range-config mandatory\n");
> +
> +	err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-p", &val);
> +	if (err)
> +		return dev_err_probe(dev, err,
> +				     "adi,gain-scaling-p mandatory\n");
> +	*gs_p = val;
> +
> +	err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-n", &val);
> +	if (err)
> +		return dev_err_probe(dev, err,
> +				     "adi,gain-scaling-n property mandatory\n");
> +	*gs_n = val;
> +
> +	err = fwnode_property_read_u32(gain_child, "adi,rfb-ohms", &val);
> +	if (err)
> +		return dev_err_probe(dev, err,
> +				     "adi,rfb-ohms mandatory\n");
> +	*rfb = val;
> +
> +	err = fwnode_property_read_u32(gain_child, "adi,gain-offset", &val);
> +	if (err)
> +		return dev_err_probe(dev, err,
> +				     "adi,gain-offset mandatory\n");
> +	*goffs = val;
> +
> +	return 0;
> +}
> +
> +static int ad3552r_find_range(u16 id, s32 *vals)
> +{
> +	int i, len;
> +	const s32 (*ranges)[2];
> +
> +	if (id == AD3542R_ID) {

This is already in your model_data. Use that not another lookup via
an ID enum.  The ID enum approach doesn't scale as we add more parts
as it scatters device specific code through the driver.


> +		len = ARRAY_SIZE(ad3542r_ch_ranges);
> +		ranges = ad3542r_ch_ranges;
> +	} else {
> +		len = ARRAY_SIZE(ad3552r_ch_ranges);
> +		ranges = ad3552r_ch_ranges;
> +	}
> +
> +	for (i = 0; i < len; i++)
> +		if (vals[0] == ranges[i][0] * 1000 &&
> +		    vals[1] == ranges[i][1] * 1000)
> +			return i;
> +
> +	return -EINVAL;
> +}
> +
> +int ad3552r_get_output_range(struct device *dev, enum ad3552r_id chip_id,
> +			     struct fwnode_handle *child, u32 *val)
As above, don't pass the enum. Either pass the model_data or pass the
actual stuff you need which is the ranges array and size of that array.

> +{
> +	int ret;
> +	s32 vals[2];
> +
> +	/* This property is optional, so returning -ENOENT if missing */
> +	if (!fwnode_property_present(child, "adi,output-range-microvolt"))
> +		return -ENOENT;
> +
> +	ret = fwnode_property_read_u32_array(child,
> +					     "adi,output-range-microvolt",
> +					     vals, 2);
> +	if (ret)
> +		return dev_err_probe(dev, ret,
> +				"invalid adi,output-range-microvolt\n");
> +
> +	ret = ad3552r_find_range(chip_id, vals);
> +	if (ret < 0)
> +		return dev_err_probe(dev, ret,
> +			"invalid adi,output-range-microvolt value\n");
> +
> +	*val = ret;
> +
> +	return 0;
> +}

Thanks,

Jonathan



^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 09/10] iio: dac: ad3552r: add axi platform driver
  2024-09-19  9:20 ` [PATCH v3 09/10] iio: dac: ad3552r: add axi platform driver Angelo Dureghello
@ 2024-09-29 12:17   ` Jonathan Cameron
  0 siblings, 0 replies; 59+ messages in thread
From: Jonathan Cameron @ 2024-09-29 12:17 UTC (permalink / raw)
  To: Angelo Dureghello
  Cc: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Olivier Moysan, linux-iio,
	linux-kernel, devicetree, dlechner

On Thu, 19 Sep 2024 11:20:05 +0200
Angelo Dureghello <adureghello@baylibre.com> wrote:

> From: Angelo Dureghello <adureghello@baylibre.com>
> 
> Add support for ad3552r-axi, where ad3552r has to be controlled

Give more on what you mean by controlled. This driver is controlling it...

> by the custom (fpga-based) ad3552r AXI DAC IP.

or similar IIO backend.

> 
> Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> ---
>  drivers/iio/dac/Kconfig                   |  11 +
>  drivers/iio/dac/Makefile                  |   1 +
>  drivers/iio/dac/ad3552r-axi.c             | 567 ++++++++++++++++++++++++++++++
>  drivers/iio/dac/ad3552r.h                 |   9 +
>  include/linux/platform_data/ad3552r-axi.h |  18 +
>  5 files changed, 606 insertions(+)
> 
> diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
> index 1cfd7e2a622f..030af7702a3c 100644
> --- a/drivers/iio/dac/Kconfig
> +++ b/drivers/iio/dac/Kconfig
> @@ -16,6 +16,17 @@ config AD3552R
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called ad3552r.
>  
> +config AD3552R_AXI
> +	tristate "Analog Devices AD3552R DAC driver, AXI version"
> +	select IIO_BACKEND
> +	help
> +	  Say yes here to build support for Analog Devices AD3552R
> +	  Digital to Analog Converter, connected through the Xilinx
> +	  fpga AXI interface.

This is stronger than it needs to be.  It's a driver for the DAC
when using a suitable IIO backend that does  DDR QSPI and offloading
of the main data acquisition.  May not be AXI related or Xilinx
related even though that is what you happen to be using today.

> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called ad3552r-axi.
I also wonder if this is appropriate. This driver uses a backend.
It doesn't strictly speaking have to be AXI based (which is the bus
off the back of the IP block, not this side).  Maybe
ad3552r-qspi-backend or something more generic like that?

> +
>  config AD5064
>  	tristate "Analog Devices AD5064 and similar multi-channel DAC driver"
>  	depends on (SPI_MASTER && I2C!=m) || I2C
> diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
> index 56a125f56284..cc2af3aa3f52 100644
> --- a/drivers/iio/dac/Makefile
> +++ b/drivers/iio/dac/Makefile
> @@ -5,6 +5,7 @@
>  
>  # When adding new entries keep the list in alphabetical order
>  obj-$(CONFIG_AD3552R) += ad3552r.o ad3552r-common.o
> +obj-$(CONFIG_AD3552R_AXI) += ad3552r-axi.o ad3552r-common.o
>  obj-$(CONFIG_AD5360) += ad5360.o
>  obj-$(CONFIG_AD5380) += ad5380.o
>  obj-$(CONFIG_AD5421) += ad5421.o
> diff --git a/drivers/iio/dac/ad3552r-axi.c b/drivers/iio/dac/ad3552r-axi.c
> new file mode 100644
> index 000000000000..85c594e149fa
> --- /dev/null
> +++ b/drivers/iio/dac/ad3552r-axi.c
> @@ -0,0 +1,567 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Analog Devices AD3552R
> + * Digital to Analog converter driver, AXI DAC backend version
> + *
> + * Copyright 2024 Analog Devices Inc.
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/iio/backend.h>
> +#include <linux/iio/buffer.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/platform_data/ad3552r-axi.h>
> +#include <linux/platform_device.h>
> +#include <linux/property.h>
> +#include <linux/units.h>
> +
> +#include "ad3552r.h"
> +
> +#define AD3552R_QSPI_LANES	4
Would be odd if it were anything else with a name like QUAD SPI.
Maybe this is obvious enough to just use the value 4 inline?
Particularly as you have a comment where it is used anyway.


> +static int ad3552r_axi_read_raw(struct iio_dev *indio_dev,
> +				struct iio_chan_spec const *chan,
> +				int *val, int *val2, long mask)
> +{
> +	struct ad3552r_axi_state *st = iio_priv(indio_dev);
> +	int ch = chan->channel;
> +	int ret;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_SAMP_FREQ: {
> +		int sclk;
> +
> +		ret = iio_backend_read_raw(st->back, chan, &sclk, 0,
> +					   IIO_CHAN_INFO_FREQUENCY);
> +		if (ret != IIO_VAL_INT)
> +			return -EINVAL;
> +
> +		/* Using 4 lanes (QSPI) */
> +		*val = DIV_ROUND_CLOSEST(sclk * AD3552R_QSPI_LANES *
> +					 (1 + st->ddr_mode),
> +					 chan->scan_type.storagebits);
> +
> +		return IIO_VAL_INT;
> +	}
> +	case IIO_CHAN_INFO_RAW:
> +		ret = st->data->bus_reg_read(st->back,
> +					     AD3552R_REG_ADDR_CH_DAC_16B(ch),

As below, I'd put chan->channel inline here and drop the local variable.

> +					     val, 2);
> +		if (ret)
> +			return ret;
> +
> +		return IIO_VAL_INT;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int ad3552r_axi_write_raw(struct iio_dev *indio_dev,
> +				 struct iio_chan_spec const *chan,
> +				 int val, int val2, long mask)
> +{
> +	struct ad3552r_axi_state *st = iio_priv(indio_dev);
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_RAW:
> +		iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
> +			int ch = chan->channel;

Just put chan->channel inline.  Not worth the local variable to save
going slightly over 80 chars.  This is one where I think readability
is slightly hurt by keeping to 80.

> +
> +			return st->data->bus_reg_write(st->back,
> +				    AD3552R_REG_ADDR_CH_DAC_16B(ch), val, 2);
> +		}
> +		unreachable();
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int ad3552r_axi_buffer_postenable(struct iio_dev *indio_dev)
> +{
> +	struct ad3552r_axi_state *st = iio_priv(indio_dev);
> +	struct iio_backend_data_fmt fmt = {
> +		.type = IIO_BACKEND_DATA_UNSIGNED
> +	};
> +	int loop_len, val, err;
> +
> +	/* Inform DAC chip to switch into DDR mode */
> +	err = ad3552r_qspi_update_reg_bits(st,
> +					   AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
> +					   AD3552R_MASK_SPI_CONFIG_DDR,
> +					   AD3552R_MASK_SPI_CONFIG_DDR, 1);
> +	if (err)
> +		return err;
> +
> +	/* Inform DAC IP to go for DDR mode from now on */
> +	err = iio_backend_ddr_enable(st->back);
> +	if (err) {
> +		dev_warn(st->dev, "could not set DDR mode, not streaming");
> +		goto exit_err;
> +	}
> +
> +	st->ddr_mode = true;
> +
> +	switch (*indio_dev->active_scan_mask) {
> +	case AD3552R_CH0_ACTIVE:
> +		st->single_channel = true;
> +		loop_len = AD3552R_STREAM_2BYTE_LOOP;

As below, = 2 is probably clearer.


> +		val = AD3552R_REG_ADDR_CH_DAC_16B(0);
> +		break;
> +	case AD3552R_CH1_ACTIVE:
> +		st->single_channel = true;
> +		loop_len = AD3552R_STREAM_2BYTE_LOOP;
> +		val = AD3552R_REG_ADDR_CH_DAC_16B(1);
> +		break;
> +	case AD3552R_CH0_CH1_ACTIVE:
> +		st->single_channel = false;
> +		loop_len = AD3552R_STREAM_4BYTE_LOOP;
> +		val = AD3552R_REG_ADDR_CH_DAC_16B(1);
> +		break;
> +	default:
> +		err = -EINVAL;
> +		goto exit_err_ddr;
> +	}
> +
> +	err = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_STREAM_MODE,
> +				      loop_len, 1);
> +	if (err)
> +		goto exit_err_ddr;
> +
> +	err = iio_backend_data_transfer_addr(st->back, val);
> +	if (err)
> +		goto exit_err_ddr;
> +
> +	/*
> +	 * The EXT_SYNC is mandatory in the CN0585 project where 2 instances
> +	 * of the IP are in the design and they need to generate the signals
> +	 * synchronized.
> +	 *
> +	 * Note: in first IP implementations CONFIG EXT_SYNC (RO) can be 0,
> +	 * but EXT_SYNC (ext synch ability) is enabled anyway.
> +	 */
> +	if (st->synchronouos_mode)
> +		err = iio_backend_ext_sync_enable(st->back);
> +	else
> +		err = iio_backend_ext_sync_disable(st->back);
> +	if (err)
> +		goto exit_err_ddr;
> +
> +	err = iio_backend_data_format_set(st->back, 0, &fmt);
> +	if (err)
> +		goto exit_err_sync;
> +
> +	err = iio_backend_buffer_enable(st->back);
> +	if (err)
> +		goto exit_err_sync;
> +
> +	return 0;
> +
> +exit_err_sync:
> +	iio_backend_ext_sync_disable(st->back);
> +
> +exit_err_ddr:
> +	iio_backend_ddr_disable(st->back);
> +
> +exit_err:
> +	ad3552r_qspi_update_reg_bits(st,
> +				     AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
> +				     AD3552R_MASK_SPI_CONFIG_DDR,
> +				     0, 1);
> +
> +	iio_backend_ddr_disable(st->back);
> +
> +	st->ddr_mode = false;
> +
> +	return err;
> +}


> +static int ad3552r_axi_setup(struct ad3552r_axi_state *st)
> +{
> +	struct fwnode_handle *child __free(fwnode_handle) = NULL;
Read the docs on how to use cleanup.h fun (should have merged this
cycle as they got stuck in review and everyone forgot about them :()

This should be inline where the constructor is not at the top of
the file.  That both helps readability and avoid unexpected reordering
of cleanup if multiple cleanup uses occur in one file.


> +	u8 gs_p, gs_n;
> +	s16 goffs;
> +	u16 id, rfb;
> +	u16 gain = 0, offset = 0;
> +	u32 val, range;
> +	int err;
> +
> +	err = ad3552r_axi_reset(st);
> +	if (err)
> +		return err;
> +
> +	err = iio_backend_ddr_disable(st->back);
> +	if (err)
> +		return err;
> +
> +	err = ad3552r_axi_scratch_pad_test(st);
> +	if (err)
> +		return err;
> +
> +	err = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_PRODUCT_ID_L,
> +				     &val, 1);
> +	if (err)
> +		return err;
> +
> +	id = val;
> +
> +	err = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_PRODUCT_ID_H,
> +				     &val, 1);
> +	if (err)
> +		return err;
> +
> +	id |= val << 8;
> +	if (id != st->model_data->chip_id)
> +		dev_info(st->dev, "Chip ID error. Expected 0x%x, Read 0x%x\n",
> +			 AD3552R_ID, id);
> +
> +	err = st->data->bus_reg_write(st->back,
> +				      AD3552R_REG_ADDR_SH_REFERENCE_CONFIG,
> +				      0, 1);
> +	if (err)
> +		return err;
> +
> +	err = st->data->bus_reg_write(st->back,
> +				      AD3552R_REG_ADDR_TRANSFER_REGISTER,
> +				      AD3552R_MASK_QUAD_SPI |
> +				      AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE, 1);
> +	if (err)
> +		return err;
> +
> +	err = iio_backend_data_source_set(st->back, 0, IIO_BACKEND_EXTERNAL);
> +	if (err)
> +		return err;
> +
> +	err = iio_backend_data_source_set(st->back, 1, IIO_BACKEND_EXTERNAL);
> +	if (err)
> +		return err;
> +
> +	err = ad3552r_get_ref_voltage(st->dev);
> +	if (err < 0)
> +		return err;
> +
> +	val = err;
> +
> +	err = ad3552r_qspi_update_reg_bits(st,
> +				AD3552R_REG_ADDR_SH_REFERENCE_CONFIG,
> +				AD3552R_MASK_REFERENCE_VOLTAGE_SEL,
> +				val, 1);
> +	if (err)
> +		return err;
> +
> +	err = ad3552r_get_drive_strength(st->dev, &val);
> +	if (!err) {
> +		err = ad3552r_qspi_update_reg_bits(st,
> +					AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
> +					AD3552R_MASK_SDO_DRIVE_STRENGTH,
> +					val, 1);
> +		if (err)
> +			return err;
> +	}
> +
> +	st->synchronouos_mode =
> +			fwnode_property_read_bool(dev_fwnode(st->dev),

device_property_read_bool()?


If doing this sort of wrapping, indent the line by only one tab more
than the line above.  This combination gives about the worst
of all the readabilty options as still requires lots of wrapping.

> +						  "adi,synchronous-mode");
> +
> +	child = device_get_named_child_node(st->dev, "channel");
> +	if (!child)
> +		return -EINVAL;
> +
> +	/*
> +	 * One of "adi,output-range-microvolt" or "custom-output-range-config"
> +	 * must be available in fdt.
> +	 */
> +	err = ad3552r_get_output_range(st->dev, st->model_data->chip_id,
As per the normal spi driver, embed the range data in your model_data structure.
If that requires you to export the structure contain that info then do so.



> +				       child, &range);
> +	if (!err)
> +		return ad3552r_axi_set_output_range(st, range);
> +	if (err != -ENOENT)
> +		return err;
> +
> +	err = ad3552r_get_custom_gain(st->dev, child, &gs_p, &gs_n, &rfb,
> +				      &goffs);
> +	if (err)
> +		return err;
> +
> +	gain = ad3552r_calc_custom_gain(gs_p, gs_n, goffs);
> +	offset = abs((s32)goffs);
> +
> +	return ad3552r_axi_setup_custom_gain(st, gain, offset);
> +}


> +
> +static const struct ad3552r_axi_model_data ad3552r_model_data = {
> +	.model_name = "ad3552r",
> +	.chip_id = AD3552R_ID,
> +	.num_hw_channels = 2,
> +};

why not reuse the existing ax3552r_model_data?
If conveys more information than you have here but includes everything here.
That data is about the ADC, not how it is wired up, so should be consistent
independent of the interface.

> +MODULE_LICENSE("GPL");
> diff --git a/drivers/iio/dac/ad3552r.h b/drivers/iio/dac/ad3552r.h
> index b1caa3c3e807..02805eec69a5 100644
> --- a/drivers/iio/dac/ad3552r.h
> +++ b/drivers/iio/dac/ad3552r.h
> @@ -38,6 +38,8 @@
>  #define AD3552R_REG_ADDR_TRANSFER_REGISTER		0x0F
>  #define   AD3552R_MASK_MULTI_IO_MODE			GENMASK(7, 6)
>  #define   AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE		BIT(2)
> +#define   AD3552R_MASK_DUAL_SPI				BIT(6)
> +#define   AD3552R_MASK_QUAD_SPI				BIT(7)
>  #define AD3552R_REG_ADDR_INTERFACE_CONFIG_C		0x10
>  #define   AD3552R_MASK_CRC_ENABLE			(GENMASK(7, 6) |\
>  							 GENMASK(1, 0))
> @@ -129,6 +131,13 @@
>  #define AD3552R_GAIN_SCALE				1000
>  #define AD3552R_LDAC_PULSE_US				100
>  
> +#define AD3552R_STREAM_2BYTE_LOOP			0x02
> +#define AD3552R_STREAM_4BYTE_LOOP			0x04

I think these two should just use the numbers given 2byte == 2 and
4byte == 4.  Defines seem to me to just add possible confusion!

Jonathan

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 10/10] iio: backend: adi-axi-dac: add registering of child fdt node
  2024-09-19  9:20 ` [PATCH v3 10/10] iio: backend: adi-axi-dac: add registering of child fdt node Angelo Dureghello
@ 2024-09-29 12:21   ` Jonathan Cameron
  0 siblings, 0 replies; 59+ messages in thread
From: Jonathan Cameron @ 2024-09-29 12:21 UTC (permalink / raw)
  To: Angelo Dureghello
  Cc: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Olivier Moysan, linux-iio,
	linux-kernel, devicetree, dlechner

On Thu, 19 Sep 2024 11:20:06 +0200
Angelo Dureghello <adureghello@baylibre.com> wrote:

> From: Angelo Dureghello <adureghello@baylibre.com>
> 
> Change to obtain the fdt use case as reported in the
> adi,ad3552r.yaml file in this patchset.
> 
> The DAC device is defined as a child node of the backend.
> Registering the child fdt node as a platform devices.
> 
> Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
A few minor comments inline. 
> ---
>  drivers/iio/dac/adi-axi-dac.c | 52 ++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 51 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c
> index 3ca3a14c575b..2afc1442cd5a 100644
> --- a/drivers/iio/dac/adi-axi-dac.c
> +++ b/drivers/iio/dac/adi-axi-dac.c
> @@ -18,6 +18,7 @@
>  #include <linux/module.h>
>  #include <linux/mod_devicetable.h>
>  #include <linux/mutex.h>
> +#include <linux/platform_data/ad3552r-axi.h>
>  #include <linux/platform_device.h>
>  #include <linux/property.h>
>  #include <linux/regmap.h>
> @@ -109,6 +110,8 @@ struct axi_dac_info {
>  struct axi_dac_state {
>  	struct regmap *regmap;
>  	struct device *dev;
> +	/* Target DAC platform device */
> +	struct platform_device *dac_pdev;
>  	/*
>  	 * lock to protect multiple accesses to the device registers and global
>  	 * data/variables.
> @@ -757,6 +760,32 @@ static int axi_dac_bus_reg_read(struct iio_backend *back, u32 reg,
>  	}
>  }
>  
> +static int axi_dac_create_platform_device(struct axi_dac_state *st,
> +					  struct fwnode_handle *child)
> +{
> +	struct ad3552r_axi_platform_data pdata = {
> +		.bus_reg_read = axi_dac_bus_reg_read,
> +		.bus_reg_write = axi_dac_bus_reg_write,
> +	};
> +	struct platform_device_info pi = {
> +		.parent = st->dev,
> +		.name = fwnode_get_name(child),
> +		.id = PLATFORM_DEVID_AUTO,
> +		.fwnode = child,
> +		.data = &pdata,
> +		.size_data = sizeof(pdata),
> +	};
> +	struct platform_device *pdev;
> +
> +	pdev = platform_device_register_full(&pi);
> +	if (IS_ERR(pdev))
> +		return PTR_ERR(pdev);
> +

Register a devm cleanup here via devm_add_action_or_reset()
(see below for why)

> +	st->dac_pdev = pdev;
> +
> +	return 0;
> +}
> +
>  static const struct iio_backend_ops axi_dac_generic_ops = {
>  	.enable = axi_dac_enable,
>  	.disable = axi_dac_disable,
> @@ -791,13 +820,22 @@ static const struct regmap_config axi_dac_regmap_config = {
>  	.max_register = 0x0800,
>  };
>  
> +static void axi_dac_remove(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct axi_dac_state *st = dev_get_drvdata(dev);
> +
> +	if (st->dac_pdev)
> +		platform_device_unregister(st->dac_pdev);

Use a devm_add_action_or_reset() So we don't need to introduce
a remove just to handle an optional bit of cleanup.
Also makes it much less likely we'll introduce ordering bugs
as the driver gets more complex in future.


> +}
> +
>  static int axi_dac_probe(struct platform_device *pdev)
>  {
>  	struct axi_dac_state *st;
>  	void __iomem *base;
>  	unsigned int ver;
>  	struct clk *clk;
> -	int ret;
> +	int ret, val;
>  
>  	st = devm_kzalloc(&pdev->dev, sizeof(*st), GFP_KERNEL);
>  	if (!st)
> @@ -871,6 +909,17 @@ static int axi_dac_probe(struct platform_device *pdev)
>  		return dev_err_probe(&pdev->dev, ret,
>  				     "failed to register iio backend\n");
>  
> +	device_for_each_child_node_scoped(&pdev->dev, child) {
> +		/* Processing only reg 0 node */

Pull int val; in here as not used outside of this scope.
Also, should only do this at all for compatibles that we know this
makes sense for.  Use some part specific flag to make that decision.


> +		ret = fwnode_property_read_u32(child, "reg", &val);
> +		if (ret || val != 0)
> +			continue;
> +
> +		ret = axi_dac_create_platform_device(st, child);
> +		if (ret)
> +			continue;
> +	}
> +
>  	dev_info(&pdev->dev, "AXI DAC IP core (%d.%.2d.%c) probed\n",
>  		 ADI_AXI_PCORE_VER_MAJOR(ver),
>  		 ADI_AXI_PCORE_VER_MINOR(ver),
> @@ -901,6 +950,7 @@ static struct platform_driver axi_dac_driver = {
>  		.of_match_table = axi_dac_of_match,
>  	},
>  	.probe = axi_dac_probe,
> +	.remove = axi_dac_remove,
>  };
>  module_platform_driver(axi_dac_driver);
>  
> 


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support
  2024-09-29 10:59                 ` Jonathan Cameron
@ 2024-09-30  7:20                   ` Nuno Sá
  2024-09-30  7:31                     ` Krzysztof Kozlowski
  2024-09-30 13:22                     ` Angelo Dureghello
  0 siblings, 2 replies; 59+ messages in thread
From: Nuno Sá @ 2024-09-30  7:20 UTC (permalink / raw)
  To: Jonathan Cameron, Krzysztof Kozlowski
  Cc: Angelo Dureghello, Lars-Peter Clausen, Michael Hennerich, Nuno Sa,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan,
	linux-iio, linux-kernel, devicetree, dlechner

On Sun, 2024-09-29 at 11:59 +0100, Jonathan Cameron wrote:
> On Sat, 28 Sep 2024 14:20:29 +0200
> Krzysztof Kozlowski <krzk@kernel.org> wrote:
> 
> > On 25/09/2024 13:55, Nuno Sá wrote:
> > > On Wed, 2024-09-25 at 09:22 +0200, Krzysztof Kozlowski wrote:  
> > > > On 24/09/2024 14:27, Nuno Sá wrote:  
> > > > > On Tue, 2024-09-24 at 10:02 +0200, Krzysztof Kozlowski wrote:  
> > > > > > On 23/09/2024 17:50, Angelo Dureghello wrote:  
> > > > > > > Hi Krzysztof,
> > > > > > > 
> > > > > > > On 22/09/24 23:02, Krzysztof Kozlowski wrote:  
> > > > > > > > On Thu, Sep 19, 2024 at 11:20:00AM +0200, Angelo Dureghello
> > > > > > > > wrote:  
> > > > > > > > > From: Angelo Dureghello <adureghello@baylibre.com>
> > > > > > > > > 
> > > > > > > > > There is a version AXI DAC IP block (for FPGAs) that provides
> > > > > > > > > a physical bus for AD3552R and similar chips, and acts as
> > > > > > > > > an SPI controller.
> > > > > > > > > 
> > > > > > > > > For this case, the binding is modified to include some
> > > > > > > > > additional properties.
> > > > > > > > > 
> > > > > > > > > Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> > > > > > > > > ---
> > > > > > > > >   .../devicetree/bindings/iio/dac/adi,ad3552r.yaml   | 42
> > > > > > > > > ++++++++++++++++++++++
> > > > > > > > >   1 file changed, 42 insertions(+)
> > > > > > > > > 
> > > > > > > > > diff --git
> > > > > > > > > a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > > > > > > > b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > > > > > > > index 41fe00034742..aca4a41c2633 100644
> > > > > > > > > ---
> > > > > > > > > a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > > > > > > > +++
> > > > > > > > > b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > > > > > > > @@ -60,6 +60,18 @@ properties:
> > > > > > > > >       $ref: /schemas/types.yaml#/definitions/uint32
> > > > > > > > >       enum: [0, 1, 2, 3]
> > > > > > > > >   
> > > > > > > > > +  io-backends:
> > > > > > > > > +    description: The iio backend reference.
> > > > > > > > > +      An example backend can be found at
> > > > > > > > > +       
> > > > > > > > > https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
> > > > > > > > > +    maxItems: 1
> > > > > > > > > +
> > > > > > > > > +  adi,synchronous-mode:
> > > > > > > > > +    description: Enable waiting for external synchronization
> > > > > > > > > signal.
> > > > > > > > > +      Some AXI IP configuration can implement a dual-IP
> > > > > > > > > layout,
> > > > > > > > > with
> > > > > > > > > internal
> > > > > > > > > +      wirings for streaming synchronization.
> > > > > > > > > +    type: boolean
> > > > > > > > > +
> > > > > > > > >     '#address-cells':
> > > > > > > > >       const: 1
> > > > > > > > >   
> > > > > > > > > @@ -128,6 +140,7 @@ patternProperties:
> > > > > > > > >             - custom-output-range-config
> > > > > > > > >   
> > > > > > > > >   allOf:
> > > > > > > > > +  - $ref: /schemas/spi/spi-peripheral-props.yaml#
> > > > > > > > >     - if:
> > > > > > > > >         properties:
> > > > > > > > >           compatible:
> > > > > > > > > @@ -238,4 +251,33 @@ examples:
> > > > > > > > >               };
> > > > > > > > >           };
> > > > > > > > >       };
> > > > > > > > > +
> > > > > > > > > +  - |
> > > > > > > > > +    axi_dac: spi@44a70000 {
> > > > > > > > > +        compatible = "adi,axi-ad3552r";  
> > > > > > > > That is either redundant or entire example should go to the
> > > > > > > > parent
> > > > > > > > node,
> > > > > > > > if this device is fixed child of complex device (IOW,
> > > > > > > > adi,ad3552r
> > > > > > > > cannot
> > > > > > > > be used outside of adi,axi-ad3552r).  
> > > > > > > 
> > > > > > > ad3552r can still be used by a generic "classic" spi
> > > > > > > controller (SCLK/CS/MISO) but at a slower samplerate, fpga
> > > > > > > controller only (axi-ad3552r) can reach 33MUPS.  
> > > > > > 
> > > > > > OK, then this is just redundant. Drop the node. Parent example
> > > > > > should
> > > > > > contain the children, though.  
> > > > > > >  
> > > > > > > >  
> > > > > > > > > +        reg = <0x44a70000 0x1000>;
> > > > > > > > > +        dmas = <&dac_tx_dma 0>;
> > > > > > > > > +        dma-names = "tx";
> > > > > > > > > +        #io-backend-cells = <0>;
> > > > > > > > > +        clocks = <&ref_clk>;
> > > > > > > > > +
> > > > > > > > > +        #address-cells = <1>;
> > > > > > > > > +        #size-cells = <0>;
> > > > > > > > > +
> > > > > > > > > +        dac@0 {
> > > > > > > > > +            compatible = "adi,ad3552r";
> > > > > > > > > +            reg = <0>;
> > > > > > > > > +            reset-gpios = <&gpio0 92 0>;  
> > > > > > > > Use standard defines for GPIO flags.  
> > > > > > > 
> > > > > > > fixed, thanks
> > > > > > >  
> > > > > > > > > +            io-backends = <&axi_dac>;  
> > > > > > > > Why do you need to point to the parent? How much coupled are
> > > > > > > > these
> > > > > > > > devices? Child pointing to parent is not usually expected,
> > > > > > > > because
> > > > > > > > that's obvious.  
> > > > > > > 
> > > > > > > 
> > > > > > > "io-backends" is actually the way to refer to the backend module,
> > > > > > > (used already for i.e. ad9739a),
> > > > > > > it is needed because the backend is not only acting as spi-
> > > > > > > controller,
> > > > > > > but is also providing some APIs for synchronization and bus setup
> > > > > > > support.  
> > > > > > 
> > > > > > 
> > > > > > But if backend is the parent, then this is redundant. You can take
> > > > > > it
> > > > > > from the child-parent relationship. Is this pointing to other
> > > > > > devices
> > > > > > (non-parent) in other ad3552r configurations?
> > > > > >  
> > > > > 
> > > > > The backend is a provider-consumer type of API. On the consumer side
> > > > > (which
> > > > > is the
> > > > > driver the child node will probe on), we need to call
> > > > > devm_iio_backend_get()
> > > > > to get
> > > > > the backend object (which obviously is the parent). For that, 'io-
> > > > > backends'
> > > > > is being  
> > > > 
> > > > You described the driver, so how does it matter? Driver can call
> > > > get_backend_from_parent(), right? Or get_backend_from_fwnode(parent)?  
> > > 
> > > Well yes, just stating what the framework (also in terms of bindings) is
> > > expecting. Of course that on the driver side we can paper around it the
> > > way we
> > > want. But my main point was that we can only paper around it if we use
> > > code that
> > > is meant not to be used.
> > > 
> > > And, FWIW, I was (trying) replying to your comment
> > > 
> > > "You can take it from the child-parent relationship"
> > > 
> > > Again, we can only do that by introducing new code or use code that's not
> > > meant
> > > to be used. The way we're supposed to reference backends is by explicitly
> > > using
> > > the proper FW property.
> > > 
> > > Put it in another way and a completely hypothetical case. If we have a spi
> > > controller which happens to export some clock and one of it's peripherals
> > > ends
> > > up using that clock, wouldn't we still use 'clocks' to reference that
> > > clock?  
> > 
> > I asked how coupled are these devices. Never got the answer and you are
> > reflecting with question. Depends. Please do not create hypothetical,
> > generic scenarios and then apply them to your one particular opposite case.
> 
> I'll throw a possible clarifying question in here.  Could we use this
> device with a multimaster SPI setup such that the control is on a conventional
> SPI controller (maybe a qspi capable one), and the data plane only goes
> through
> a specific purpose backend?  If so, then they are not tightly coupled and
> the reference makes sense.  Putting it another way, the difference between
> this case and all the prior iio-backend bindings is the control and dataplanes
> use the same pins.  Does that have to be the case at the host end?  If it
> does,
> then the reference isn't strictly needed and this becomes a bit like
> registering a single device on an spi bus or an i2c bus depending on who
> does the registering (which is down to the parent in DT).
> 

So, we currently have two drivers (with a new one being added in this series)
for the same device:

1) A SPI one tied to a typical spi controller. This is the "low speed"
implementation and does not use backends;
2) The new platform device that is connected like this to the backend.

So yes, my understanding (but Angelo should know better :)) is that they are
tightly coupled. Putting it in another way, the new platform device is very much
specific to this parent (and yeah, this is a very special usecase where control
and data planes are controlled by the IIO backend) and should not exist with it.

- Nuno Sá


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support
  2024-09-30  7:20                   ` Nuno Sá
@ 2024-09-30  7:31                     ` Krzysztof Kozlowski
  2024-09-30  8:24                       ` Nuno Sá
  2024-09-30 13:22                     ` Angelo Dureghello
  1 sibling, 1 reply; 59+ messages in thread
From: Krzysztof Kozlowski @ 2024-09-30  7:31 UTC (permalink / raw)
  To: Nuno Sá, Jonathan Cameron
  Cc: Angelo Dureghello, Lars-Peter Clausen, Michael Hennerich, Nuno Sa,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan,
	linux-iio, linux-kernel, devicetree, dlechner

On 30/09/2024 09:20, Nuno Sá wrote:
>>>>>
>>>>> You described the driver, so how does it matter? Driver can call
>>>>> get_backend_from_parent(), right? Or get_backend_from_fwnode(parent)?  
>>>>
>>>> Well yes, just stating what the framework (also in terms of bindings) is
>>>> expecting. Of course that on the driver side we can paper around it the
>>>> way we
>>>> want. But my main point was that we can only paper around it if we use
>>>> code that
>>>> is meant not to be used.
>>>>
>>>> And, FWIW, I was (trying) replying to your comment
>>>>
>>>> "You can take it from the child-parent relationship"
>>>>
>>>> Again, we can only do that by introducing new code or use code that's not
>>>> meant
>>>> to be used. The way we're supposed to reference backends is by explicitly
>>>> using
>>>> the proper FW property.
>>>>
>>>> Put it in another way and a completely hypothetical case. If we have a spi
>>>> controller which happens to export some clock and one of it's peripherals
>>>> ends
>>>> up using that clock, wouldn't we still use 'clocks' to reference that
>>>> clock?  
>>>
>>> I asked how coupled are these devices. Never got the answer and you are
>>> reflecting with question. Depends. Please do not create hypothetical,
>>> generic scenarios and then apply them to your one particular opposite case.
>>
>> I'll throw a possible clarifying question in here.  Could we use this
>> device with a multimaster SPI setup such that the control is on a conventional
>> SPI controller (maybe a qspi capable one), and the data plane only goes
>> through
>> a specific purpose backend?  If so, then they are not tightly coupled and
>> the reference makes sense.  Putting it another way, the difference between
>> this case and all the prior iio-backend bindings is the control and dataplanes
>> use the same pins.  Does that have to be the case at the host end?  If it
>> does,
>> then the reference isn't strictly needed and this becomes a bit like
>> registering a single device on an spi bus or an i2c bus depending on who
>> does the registering (which is down to the parent in DT).
>>
> 
> So, we currently have two drivers (with a new one being added in this series)
> for the same device:
> 
> 1) A SPI one tied to a typical spi controller. This is the "low speed"
> implementation and does not use backends;
> 2) The new platform device that is connected like this to the backend.

Drivers, platform devices are Linux specifics. These were not our
questions here. You are responding with description matching current
Linux code.

> 
> So yes, my understanding (but Angelo should know better :)) is that they are
> tightly coupled. Putting it in another way, the new platform device is very much
> specific to this parent (and yeah, this is a very special usecase where control

Again, Linux stuff.

> and data planes are controlled by the IIO backend) and should not exist with it.

I pointed this issue already in this thread. You keep describing
drivers, so of course they will be coupled as much as you write them.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support
  2024-09-30  7:31                     ` Krzysztof Kozlowski
@ 2024-09-30  8:24                       ` Nuno Sá
  0 siblings, 0 replies; 59+ messages in thread
From: Nuno Sá @ 2024-09-30  8:24 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Jonathan Cameron
  Cc: Angelo Dureghello, Lars-Peter Clausen, Michael Hennerich, Nuno Sa,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan,
	linux-iio, linux-kernel, devicetree, dlechner

On Mon, 2024-09-30 at 09:31 +0200, Krzysztof Kozlowski wrote:
> On 30/09/2024 09:20, Nuno Sá wrote:
> > > > > > 
> > > > > > You described the driver, so how does it matter? Driver can call
> > > > > > get_backend_from_parent(), right? Or
> > > > > > get_backend_from_fwnode(parent)?  
> > > > > 
> > > > > Well yes, just stating what the framework (also in terms of bindings)
> > > > > is
> > > > > expecting. Of course that on the driver side we can paper around it
> > > > > the
> > > > > way we
> > > > > want. But my main point was that we can only paper around it if we use
> > > > > code that
> > > > > is meant not to be used.
> > > > > 
> > > > > And, FWIW, I was (trying) replying to your comment
> > > > > 
> > > > > "You can take it from the child-parent relationship"
> > > > > 
> > > > > Again, we can only do that by introducing new code or use code that's
> > > > > not
> > > > > meant
> > > > > to be used. The way we're supposed to reference backends is by
> > > > > explicitly
> > > > > using
> > > > > the proper FW property.
> > > > > 
> > > > > Put it in another way and a completely hypothetical case. If we have a
> > > > > spi
> > > > > controller which happens to export some clock and one of it's
> > > > > peripherals
> > > > > ends
> > > > > up using that clock, wouldn't we still use 'clocks' to reference that
> > > > > clock?  
> > > > 
> > > > I asked how coupled are these devices. Never got the answer and you are
> > > > reflecting with question. Depends. Please do not create hypothetical,
> > > > generic scenarios and then apply them to your one particular opposite
> > > > case.
> > > 
> > > I'll throw a possible clarifying question in here.  Could we use this
> > > device with a multimaster SPI setup such that the control is on a
> > > conventional
> > > SPI controller (maybe a qspi capable one), and the data plane only goes
> > > through
> > > a specific purpose backend?  If so, then they are not tightly coupled and
> > > the reference makes sense.  Putting it another way, the difference between
> > > this case and all the prior iio-backend bindings is the control and
> > > dataplanes
> > > use the same pins.  Does that have to be the case at the host end?  If it
> > > does,
> > > then the reference isn't strictly needed and this becomes a bit like
> > > registering a single device on an spi bus or an i2c bus depending on who
> > > does the registering (which is down to the parent in DT).
> > > 
> > 
> > So, we currently have two drivers (with a new one being added in this
> > series)
> > for the same device:
> > 
> > 1) A SPI one tied to a typical spi controller. This is the "low speed"
> > implementation and does not use backends;
> > 2) The new platform device that is connected like this to the backend.
> 
> Drivers, platform devices are Linux specifics. These were not our
> questions here. You are responding with description matching current
> Linux code.
> 
> > 
> > So yes, my understanding (but Angelo should know better :)) is that they are
> > tightly coupled. Putting it in another way, the new platform device is very
> > much
> > specific to this parent (and yeah, this is a very special usecase where
> > control
> 
> Again, Linux stuff.
> 
> > and data planes are controlled by the IIO backend) and should not exist with
> > it.
> 
> I pointed this issue already in this thread. You keep describing
> drivers, so of course they will be coupled as much as you write them.
> 

Well, because this is how it's being used and it's easy for me to fall into the
implementation but ok, I get your point. Directly then replying in terms of HW,
this could be used in a way where we have a typical spi controller handling the
device and the data plane only going through the backend. In fact, the HW folks
first tried the SPI ENGINE IP (which is a typically controller) but could not
get the maximum sampling rate out of the device so they came up with this custom
design. So, in theory is possible, in practise will likely never happen but I
guess that does not matter for the bindings?

- Nuno Sá

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 02/10] dt-bindings: iio: dac: axi-dac: add ad3552r axi variant
  2024-09-29 10:46   ` Jonathan Cameron
@ 2024-09-30 12:52     ` Angelo Dureghello
  2024-09-30 13:15       ` Nuno Sá
  0 siblings, 1 reply; 59+ messages in thread
From: Angelo Dureghello @ 2024-09-30 12:52 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Olivier Moysan, linux-iio,
	linux-kernel, devicetree, dlechner, Mark Brown, linux-spi

On 29.09.2024 11:46, Jonathan Cameron wrote:
> On Thu, 19 Sep 2024 11:19:58 +0200
> Angelo Dureghello <adureghello@baylibre.com> wrote:
> 
> > From: Angelo Dureghello <adureghello@baylibre.com>
> > 
> > Add a new compatible and related bindigns for the fpga-based
> > "ad3552r" AXI IP core, a variant of the generic AXI DAC IP.
> > 
> > The AXI "ad3552r" IP is a very similar HDL (fpga) variant of the
> > generic AXI "DAC" IP, intended to control ad3552r and similar chips,
> > mainly to reach high speed transfer rates using an additional QSPI
> 
> I'd drop the word additional as I assume it is an 'either/or' situation
> for the interfaces.
> 
> Do we have other devices using this same IP?  I.e. does it make
> sense to provide a more generic compatible as a fallback for this one
> so that other devices would work without the need for explicit support?
> 
>
no, actually ad3552r-axi is only interfacing to ad3552r.
I could eventually set adi,axi-dac-9.1.b as a fallback, since it
is the "gneric" AXI implementation.
 
> I'd also ideally like a view point from Mark Brown as SPI maintainer
> on how we should deal with this highly specialized spi controller.
> Is he happy with us using an SPI like binding but not figuring out how
> to fit this engine into the SPI subsystem.
> 
> Please +CC Mark and the spi list (done here) on future versions + provide
> a clear description of what is going on for them.
> 

Ok.
Actually i fixed the bindings for v4 setting axi-ad3552r as an
spi-controller, and the target ad3552r as a spi-peripheral (child node).
This axi-ad3552r is not only a pure spi-controller since providing
some synchronization features not typical of a spi-controller. 

> Maybe with the binding fixed as spi compliant, we can figure out the
> if we eventually want to treat this as an SPI controller from the
> kernel driver point of view even if we initially do something 'special'.
>

> Jonathan
> 
> 
> > DDR interface.
> > 
> > The ad3552r device is defined as a child of the AXI DAC, that in
> > this case is acting as an SPI controller.
> > 
> > Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> > ---
> >  .../devicetree/bindings/iio/dac/adi,axi-dac.yaml   | 40 ++++++++++++++++++++--
> >  1 file changed, 37 insertions(+), 3 deletions(-)
> > 
> > diff --git a/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml b/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml
> > index a55e9bfc66d7..6cf0c2cb84e7 100644
> > --- a/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml
> > +++ b/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml
> > @@ -19,11 +19,13 @@ description: |
> >    memory via DMA into the DAC.
> >  
> >    https://wiki.analog.com/resources/fpga/docs/axi_dac_ip
> > +  https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
> >  
> >  properties:
> >    compatible:
> >      enum:
> >        - adi,axi-dac-9.1.b
> > +      - adi,axi-ad3552r
> >  
> >    reg:
> >      maxItems: 1
> > @@ -41,22 +43,54 @@ properties:
> >    '#io-backend-cells':
> >      const: 0
> >  
> > +  '#address-cells':
> > +    const: 1
> > +
> > +  '#size-cells':
> > +    const: 0
> > +
> >  required:
> >    - compatible
> >    - dmas
> >    - reg
> >    - clocks
> >  
> > +patternProperties:
> > +  "^.*@([0-9])$":
> > +    type: object
> > +    additionalProperties: true
> > +    properties:
> > +      io-backends:
> > +        description: |
> > +          AXI backend reference
> > +    required:
> > +      - io-backends
> > +
> >  additionalProperties: false
> >  
> >  examples:
> >    - |
> >      dac@44a00000 {
> > -        compatible = "adi,axi-dac-9.1.b";
> > -        reg = <0x44a00000 0x10000>;
> > -        dmas = <&tx_dma 0>;
> > +      compatible = "adi,axi-dac-9.1.b";
> > +      reg = <0x44a00000 0x10000>;
> > +      dmas = <&tx_dma 0>;
> 
> If it makes sense to reformat then separate patch
> please as this is hard to read as a result of this
> change.  Also, as pointed out, be consistent with spacing.
> 
> > +      dma-names = "tx";
> > +      #io-backend-cells = <0>;
> > +      clocks = <&axi_clk>;
> > +    };
> > +
> > +  - |
> > +    axi_dac: spi@44a70000 {
> > +        compatible = "adi,axi-ad3552r";
> > +        reg = <0x44a70000 0x1000>;
> > +        dmas = <&dac_tx_dma 0>;
> >          dma-names = "tx";
> >          #io-backend-cells = <0>;
> >          clocks = <&axi_clk>;
> > +
> > +        #address-cells = <1>;
> > +        #size-cells = <0>;
> > +
> > +        /* DAC devices */
> >      };
> >  ...
> > 
> 

-- 

  o/ QW5nZWxvIER1cmVnaGVsbG8=
   www.kernel-space.org
    e: angelo at kernel-space.org
      c: +39 388 8550663
       

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 02/10] dt-bindings: iio: dac: axi-dac: add ad3552r axi variant
  2024-09-30 12:52     ` Angelo Dureghello
@ 2024-09-30 13:15       ` Nuno Sá
  2024-09-30 14:52         ` Jonathan Cameron
  0 siblings, 1 reply; 59+ messages in thread
From: Nuno Sá @ 2024-09-30 13:15 UTC (permalink / raw)
  To: Angelo Dureghello, Jonathan Cameron
  Cc: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Olivier Moysan, linux-iio,
	linux-kernel, devicetree, dlechner, Mark Brown, linux-spi

On Mon, 2024-09-30 at 14:52 +0200, Angelo Dureghello wrote:
> On 29.09.2024 11:46, Jonathan Cameron wrote:
> > On Thu, 19 Sep 2024 11:19:58 +0200
> > Angelo Dureghello <adureghello@baylibre.com> wrote:
> > 
> > > From: Angelo Dureghello <adureghello@baylibre.com>
> > > 
> > > Add a new compatible and related bindigns for the fpga-based
> > > "ad3552r" AXI IP core, a variant of the generic AXI DAC IP.
> > > 
> > > The AXI "ad3552r" IP is a very similar HDL (fpga) variant of the
> > > generic AXI "DAC" IP, intended to control ad3552r and similar chips,
> > > mainly to reach high speed transfer rates using an additional QSPI
> > 
> > I'd drop the word additional as I assume it is an 'either/or' situation
> > for the interfaces.
> > 
> > Do we have other devices using this same IP?  I.e. does it make
> > sense to provide a more generic compatible as a fallback for this one
> > so that other devices would work without the need for explicit support?
> > 
> > 
> no, actually ad3552r-axi is only interfacing to ad3552r.
> I could eventually set adi,axi-dac-9.1.b as a fallback, since it
> is the "gneric" AXI implementation.

Yes but the generic IP does not have this spi bus implementation so the device
would be unusable (unless I'm missing something)

- Nuno Sá



^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support
  2024-09-30  7:20                   ` Nuno Sá
  2024-09-30  7:31                     ` Krzysztof Kozlowski
@ 2024-09-30 13:22                     ` Angelo Dureghello
  2024-09-30 15:09                       ` Jonathan Cameron
  1 sibling, 1 reply; 59+ messages in thread
From: Angelo Dureghello @ 2024-09-30 13:22 UTC (permalink / raw)
  To: Nuno Sá
  Cc: Jonathan Cameron, Krzysztof Kozlowski, Lars-Peter Clausen,
	Michael Hennerich, Nuno Sa, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Olivier Moysan, linux-iio, linux-kernel, devicetree,
	dlechner

On 30.09.2024 09:20, Nuno Sá wrote:
> On Sun, 2024-09-29 at 11:59 +0100, Jonathan Cameron wrote:
> > On Sat, 28 Sep 2024 14:20:29 +0200
> > Krzysztof Kozlowski <krzk@kernel.org> wrote:
> > 
> > > On 25/09/2024 13:55, Nuno Sá wrote:
> > > > On Wed, 2024-09-25 at 09:22 +0200, Krzysztof Kozlowski wrote:  
> > > > > On 24/09/2024 14:27, Nuno Sá wrote:  
> > > > > > On Tue, 2024-09-24 at 10:02 +0200, Krzysztof Kozlowski wrote:  
> > > > > > > On 23/09/2024 17:50, Angelo Dureghello wrote:  
> > > > > > > > Hi Krzysztof,
> > > > > > > > 
> > > > > > > > On 22/09/24 23:02, Krzysztof Kozlowski wrote:  
> > > > > > > > > On Thu, Sep 19, 2024 at 11:20:00AM +0200, Angelo Dureghello
> > > > > > > > > wrote:  
> > > > > > > > > > From: Angelo Dureghello <adureghello@baylibre.com>
> > > > > > > > > > 
> > > > > > > > > > There is a version AXI DAC IP block (for FPGAs) that provides
> > > > > > > > > > a physical bus for AD3552R and similar chips, and acts as
> > > > > > > > > > an SPI controller.
> > > > > > > > > > 
> > > > > > > > > > For this case, the binding is modified to include some
> > > > > > > > > > additional properties.
> > > > > > > > > > 
> > > > > > > > > > Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> > > > > > > > > > ---
> > > > > > > > > >   .../devicetree/bindings/iio/dac/adi,ad3552r.yaml   | 42
> > > > > > > > > > ++++++++++++++++++++++
> > > > > > > > > >   1 file changed, 42 insertions(+)
> > > > > > > > > > 
> > > > > > > > > > diff --git
> > > > > > > > > > a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > > > > > > > > b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > > > > > > > > index 41fe00034742..aca4a41c2633 100644
> > > > > > > > > > ---
> > > > > > > > > > a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > > > > > > > > +++
> > > > > > > > > > b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > > > > > > > > @@ -60,6 +60,18 @@ properties:
> > > > > > > > > >       $ref: /schemas/types.yaml#/definitions/uint32
> > > > > > > > > >       enum: [0, 1, 2, 3]
> > > > > > > > > >   
> > > > > > > > > > +  io-backends:
> > > > > > > > > > +    description: The iio backend reference.
> > > > > > > > > > +      An example backend can be found at
> > > > > > > > > > +       
> > > > > > > > > > https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
> > > > > > > > > > +    maxItems: 1
> > > > > > > > > > +
> > > > > > > > > > +  adi,synchronous-mode:
> > > > > > > > > > +    description: Enable waiting for external synchronization
> > > > > > > > > > signal.
> > > > > > > > > > +      Some AXI IP configuration can implement a dual-IP
> > > > > > > > > > layout,
> > > > > > > > > > with
> > > > > > > > > > internal
> > > > > > > > > > +      wirings for streaming synchronization.
> > > > > > > > > > +    type: boolean
> > > > > > > > > > +
> > > > > > > > > >     '#address-cells':
> > > > > > > > > >       const: 1
> > > > > > > > > >   
> > > > > > > > > > @@ -128,6 +140,7 @@ patternProperties:
> > > > > > > > > >             - custom-output-range-config
> > > > > > > > > >   
> > > > > > > > > >   allOf:
> > > > > > > > > > +  - $ref: /schemas/spi/spi-peripheral-props.yaml#
> > > > > > > > > >     - if:
> > > > > > > > > >         properties:
> > > > > > > > > >           compatible:
> > > > > > > > > > @@ -238,4 +251,33 @@ examples:
> > > > > > > > > >               };
> > > > > > > > > >           };
> > > > > > > > > >       };
> > > > > > > > > > +
> > > > > > > > > > +  - |
> > > > > > > > > > +    axi_dac: spi@44a70000 {
> > > > > > > > > > +        compatible = "adi,axi-ad3552r";  
> > > > > > > > > That is either redundant or entire example should go to the
> > > > > > > > > parent
> > > > > > > > > node,
> > > > > > > > > if this device is fixed child of complex device (IOW,
> > > > > > > > > adi,ad3552r
> > > > > > > > > cannot
> > > > > > > > > be used outside of adi,axi-ad3552r).  
> > > > > > > > 
> > > > > > > > ad3552r can still be used by a generic "classic" spi
> > > > > > > > controller (SCLK/CS/MISO) but at a slower samplerate, fpga
> > > > > > > > controller only (axi-ad3552r) can reach 33MUPS.  
> > > > > > > 
> > > > > > > OK, then this is just redundant. Drop the node. Parent example
> > > > > > > should
> > > > > > > contain the children, though.  
> > > > > > > >  
> > > > > > > > >  
> > > > > > > > > > +        reg = <0x44a70000 0x1000>;
> > > > > > > > > > +        dmas = <&dac_tx_dma 0>;
> > > > > > > > > > +        dma-names = "tx";
> > > > > > > > > > +        #io-backend-cells = <0>;
> > > > > > > > > > +        clocks = <&ref_clk>;
> > > > > > > > > > +
> > > > > > > > > > +        #address-cells = <1>;
> > > > > > > > > > +        #size-cells = <0>;
> > > > > > > > > > +
> > > > > > > > > > +        dac@0 {
> > > > > > > > > > +            compatible = "adi,ad3552r";
> > > > > > > > > > +            reg = <0>;
> > > > > > > > > > +            reset-gpios = <&gpio0 92 0>;  
> > > > > > > > > Use standard defines for GPIO flags.  
> > > > > > > > 
> > > > > > > > fixed, thanks
> > > > > > > >  
> > > > > > > > > > +            io-backends = <&axi_dac>;  
> > > > > > > > > Why do you need to point to the parent? How much coupled are
> > > > > > > > > these
> > > > > > > > > devices? Child pointing to parent is not usually expected,
> > > > > > > > > because
> > > > > > > > > that's obvious.  
> > > > > > > > 
> > > > > > > > 
> > > > > > > > "io-backends" is actually the way to refer to the backend module,
> > > > > > > > (used already for i.e. ad9739a),
> > > > > > > > it is needed because the backend is not only acting as spi-
> > > > > > > > controller,
> > > > > > > > but is also providing some APIs for synchronization and bus setup
> > > > > > > > support.  
> > > > > > > 
> > > > > > > 
> > > > > > > But if backend is the parent, then this is redundant. You can take
> > > > > > > it
> > > > > > > from the child-parent relationship. Is this pointing to other
> > > > > > > devices
> > > > > > > (non-parent) in other ad3552r configurations?
> > > > > > >  
> > > > > > 
> > > > > > The backend is a provider-consumer type of API. On the consumer side
> > > > > > (which
> > > > > > is the
> > > > > > driver the child node will probe on), we need to call
> > > > > > devm_iio_backend_get()
> > > > > > to get
> > > > > > the backend object (which obviously is the parent). For that, 'io-
> > > > > > backends'
> > > > > > is being  
> > > > > 
> > > > > You described the driver, so how does it matter? Driver can call
> > > > > get_backend_from_parent(), right? Or get_backend_from_fwnode(parent)?  
> > > > 
> > > > Well yes, just stating what the framework (also in terms of bindings) is
> > > > expecting. Of course that on the driver side we can paper around it the
> > > > way we
> > > > want. But my main point was that we can only paper around it if we use
> > > > code that
> > > > is meant not to be used.
> > > > 
> > > > And, FWIW, I was (trying) replying to your comment
> > > > 
> > > > "You can take it from the child-parent relationship"
> > > > 
> > > > Again, we can only do that by introducing new code or use code that's not
> > > > meant
> > > > to be used. The way we're supposed to reference backends is by explicitly
> > > > using
> > > > the proper FW property.
> > > > 
> > > > Put it in another way and a completely hypothetical case. If we have a spi
> > > > controller which happens to export some clock and one of it's peripherals
> > > > ends
> > > > up using that clock, wouldn't we still use 'clocks' to reference that
> > > > clock?  
> > > 
> > > I asked how coupled are these devices. Never got the answer and you are
> > > reflecting with question. Depends. Please do not create hypothetical,
> > > generic scenarios and then apply them to your one particular opposite case.
> > 
> > I'll throw a possible clarifying question in here.  Could we use this
> > device with a multimaster SPI setup such that the control is on a conventional
> > SPI controller (maybe a qspi capable one), and the data plane only goes
> > through
> > a specific purpose backend?  If so, then they are not tightly coupled and
> > the reference makes sense.  Putting it another way, the difference between
> > this case and all the prior iio-backend bindings is the control and dataplanes
> > use the same pins.  Does that have to be the case at the host end?  If it
> > does,
> > then the reference isn't strictly needed and this becomes a bit like
> > registering a single device on an spi bus or an i2c bus depending on who
> > does the registering (which is down to the parent in DT).
> > 
> 
> So, we currently have two drivers (with a new one being added in this series)
> for the same device:
> 
> 1) A SPI one tied to a typical spi controller. This is the "low speed"
> implementation and does not use backends;
> 2) The new platform device that is connected like this to the backend.
> 
> So yes, my understanding (but Angelo should know better :)) is that they are
> tightly coupled. Putting it in another way, the new platform device is very much
> specific to this parent (and yeah, this is a very special usecase where control
> and data planes are controlled by the IIO backend) and should not exist with it.

ad3552r device can be coupled to the axi-ad3552r controller or to a generic 
spi controler.

We have actually 2 drivers, SPI and platform (for AXI controller, in this patch).

Scenario 1 (SPI):
ad3522r can hypotetically work with whatever simple spi controller that can
read/write registers in raw mode. On simple SPI (CS, SCLK, MOSI), due to ad3552r
chip limitation of 66Mhz clock, the maximum 33MUPS (16 bit samples) cannot be
reached. Some QSPI DDR controller seems to be around, in that case, ad3552r
may work extending the SPI driver. 

Scenario 2 (AXI):
From an hardware-only point ov view axi-ad3552r IP acts as QSPI+DDR controller
plus some additional features for stream synchronization.
From a sowftware point of view, really different from a spi controller driver.
It's just a backend with APIes that can be called from the child driver.


> 
> - Nuno Sá
> 

Regards,
Angelo

-- 

  o/ QW5nZWxvIER1cmVnaGVsbG8=
   www.kernel-space.org
    e: angelo at kernel-space.org
      c: +39 388 8550663
       

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support
  2024-09-29 10:51   ` Jonathan Cameron
@ 2024-09-30 14:15     ` Angelo Dureghello
  2024-09-30 14:49       ` Jonathan Cameron
  0 siblings, 1 reply; 59+ messages in thread
From: Angelo Dureghello @ 2024-09-30 14:15 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Olivier Moysan, linux-iio,
	linux-kernel, devicetree, dlechner

On 29.09.2024 11:51, Jonathan Cameron wrote:
> On Thu, 19 Sep 2024 11:20:00 +0200
> Angelo Dureghello <adureghello@baylibre.com> wrote:
> 
> > From: Angelo Dureghello <adureghello@baylibre.com>
> > 
> > There is a version AXI DAC IP block (for FPGAs) that provides
> > a physical bus for AD3552R and similar chips, and acts as
> > an SPI controller.
> 
> Wrap is a bit short. Aim for < 75 chars for patch descriptions.
> 
> > 
> > For this case, the binding is modified to include some
> > additional properties.
> > 
> > Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> > ---
> >  .../devicetree/bindings/iio/dac/adi,ad3552r.yaml   | 42 ++++++++++++++++++++++
> >  1 file changed, 42 insertions(+)
> > 
> > diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > index 41fe00034742..aca4a41c2633 100644
> > --- a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > @@ -60,6 +60,18 @@ properties:
> >      $ref: /schemas/types.yaml#/definitions/uint32
> >      enum: [0, 1, 2, 3]
> >  
> > +  io-backends:
> > +    description: The iio backend reference.
> 
> Give a description of what the backend does in this case.  I.e. that it is
> a qspi DDR backend with ...
> 
> > +      An example backend can be found at
> > +        https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
> > +    maxItems: 1
> > +
> > +  adi,synchronous-mode:
> > +    description: Enable waiting for external synchronization signal.
> > +      Some AXI IP configuration can implement a dual-IP layout, with internal
> > +      wirings for streaming synchronization.
> 
> I've no idea what a dual-IP layout is.  Can you provide a little more info
> here?  What are the two IPs?
>
IP is a term used in fpga design as "intellectual property", that is
intended as a functional block of logic or data used to make a 
field-programmable gate array module.

A dual layout is just 2 same fpga modules in place of one.
 
I can add a "fpga" regerence to be more clear.

> > +    type: boolean
> > +
> >    '#address-cells':
> >      const: 1
> >  
> > @@ -128,6 +140,7 @@ patternProperties:
> >            - custom-output-range-config
> >  
> >  allOf:
> > +  - $ref: /schemas/spi/spi-peripheral-props.yaml#
> >    - if:
> >        properties:
> >          compatible:
> > @@ -238,4 +251,33 @@ examples:
> >              };
> >          };
> >      };
> > +
> > +  - |
> > +    axi_dac: spi@44a70000 {
> > +        compatible = "adi,axi-ad3552r";
> > +        reg = <0x44a70000 0x1000>;
> > +        dmas = <&dac_tx_dma 0>;
> > +        dma-names = "tx";
> > +        #io-backend-cells = <0>;
> > +        clocks = <&ref_clk>;
> > +
> > +        #address-cells = <1>;
> > +        #size-cells = <0>;
> > +
> > +        dac@0 {
> > +            compatible = "adi,ad3552r";
> > +            reg = <0>;
> > +            reset-gpios = <&gpio0 92 0>;
> > +            io-backends = <&axi_dac>;
> > +            spi-max-frequency = <66000000>;
> > +
> > +            #address-cells = <1>;
> > +            #size-cells = <0>;
> > +
> > +            channel@0 {
> > +                reg = <0>;
> > +                adi,output-range-microvolt = <(-10000000) (10000000)>;
> > +            };
> > +        };
> > +    };
> >  ...
> > 
> 

Regards,
Angelo

-- 

  o/ QW5nZWxvIER1cmVnaGVsbG8=
   www.kernel-space.org
    e: angelo at kernel-space.org
      c: +39 388 8550663
       

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support
  2024-09-30 14:15     ` Angelo Dureghello
@ 2024-09-30 14:49       ` Jonathan Cameron
  2024-09-30 15:08         ` Angelo Dureghello
  0 siblings, 1 reply; 59+ messages in thread
From: Jonathan Cameron @ 2024-09-30 14:49 UTC (permalink / raw)
  To: Angelo Dureghello
  Cc: Jonathan Cameron, Lars-Peter Clausen, Michael Hennerich, Nuno Sa,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan,
	linux-iio, linux-kernel, devicetree, dlechner

On Mon, 30 Sep 2024 16:15:41 +0200
Angelo Dureghello <adureghello@baylibre.com> wrote:

> On 29.09.2024 11:51, Jonathan Cameron wrote:
> > On Thu, 19 Sep 2024 11:20:00 +0200
> > Angelo Dureghello <adureghello@baylibre.com> wrote:
> >   
> > > From: Angelo Dureghello <adureghello@baylibre.com>
> > > 
> > > There is a version AXI DAC IP block (for FPGAs) that provides
> > > a physical bus for AD3552R and similar chips, and acts as
> > > an SPI controller.  
> > 
> > Wrap is a bit short. Aim for < 75 chars for patch descriptions.
> >   
> > > 
> > > For this case, the binding is modified to include some
> > > additional properties.
> > > 
> > > Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> > > ---
> > >  .../devicetree/bindings/iio/dac/adi,ad3552r.yaml   | 42 ++++++++++++++++++++++
> > >  1 file changed, 42 insertions(+)
> > > 
> > > diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > index 41fe00034742..aca4a41c2633 100644
> > > --- a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > @@ -60,6 +60,18 @@ properties:
> > >      $ref: /schemas/types.yaml#/definitions/uint32
> > >      enum: [0, 1, 2, 3]
> > >  
> > > +  io-backends:
> > > +    description: The iio backend reference.  
> > 
> > Give a description of what the backend does in this case.  I.e. that it is
> > a qspi DDR backend with ...
> >   
> > > +      An example backend can be found at
> > > +        https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
> > > +    maxItems: 1
> > > +
> > > +  adi,synchronous-mode:
> > > +    description: Enable waiting for external synchronization signal.
> > > +      Some AXI IP configuration can implement a dual-IP layout, with internal
> > > +      wirings for streaming synchronization.  
> > 
> > I've no idea what a dual-IP layout is.  Can you provide a little more info
> > here?  What are the two IPs?
> >  
> IP is a term used in fpga design as "intellectual property", that is
> intended as a functional block of logic or data used to make a 
> field-programmable gate array module.
> 
> A dual layout is just 2 same fpga modules in place of one.
>  
> I can add a "fpga" regerence to be more clear.

IP I was familiar with.  I'm more interested in what each IP is doing in this
case.  Or at least an example of what sort of split of functionality might
make use of this.

Jonathan

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 02/10] dt-bindings: iio: dac: axi-dac: add ad3552r axi variant
  2024-09-30 13:15       ` Nuno Sá
@ 2024-09-30 14:52         ` Jonathan Cameron
  0 siblings, 0 replies; 59+ messages in thread
From: Jonathan Cameron @ 2024-09-30 14:52 UTC (permalink / raw)
  To: Nuno Sá
  Cc: Angelo Dureghello, Jonathan Cameron, Lars-Peter Clausen,
	Michael Hennerich, Nuno Sa, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Olivier Moysan, linux-iio, linux-kernel, devicetree,
	dlechner, Mark Brown, linux-spi

On Mon, 30 Sep 2024 15:15:03 +0200
Nuno Sá <noname.nuno@gmail.com> wrote:

> On Mon, 2024-09-30 at 14:52 +0200, Angelo Dureghello wrote:
> > On 29.09.2024 11:46, Jonathan Cameron wrote:  
> > > On Thu, 19 Sep 2024 11:19:58 +0200
> > > Angelo Dureghello <adureghello@baylibre.com> wrote:
> > >   
> > > > From: Angelo Dureghello <adureghello@baylibre.com>
> > > > 
> > > > Add a new compatible and related bindigns for the fpga-based
> > > > "ad3552r" AXI IP core, a variant of the generic AXI DAC IP.
> > > > 
> > > > The AXI "ad3552r" IP is a very similar HDL (fpga) variant of the
> > > > generic AXI "DAC" IP, intended to control ad3552r and similar chips,
> > > > mainly to reach high speed transfer rates using an additional QSPI  
> > > 
> > > I'd drop the word additional as I assume it is an 'either/or' situation
> > > for the interfaces.
> > > 
> > > Do we have other devices using this same IP?  I.e. does it make
> > > sense to provide a more generic compatible as a fallback for this one
> > > so that other devices would work without the need for explicit support?
> > > 
> > >   
> > no, actually ad3552r-axi is only interfacing to ad3552r.
> > I could eventually set adi,axi-dac-9.1.b as a fallback, since it
> > is the "gneric" AXI implementation.  
> 
> Yes but the generic IP does not have this spi bus implementation so the device
> would be unusable (unless I'm missing something)
Falling back to the generic IP doesn't make sense as they aren't compatible.

I'd more expect some future device support that happens to need the same
sort of bus support might be able to use this FPGA IP.  Anyhow, it is fine
to fallback to this specific compatible anyway, so lets go with this rather
than trying for a generic name.

Jonathan

> 
> - Nuno Sá
> 
> 
> 


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support
  2024-09-30 14:49       ` Jonathan Cameron
@ 2024-09-30 15:08         ` Angelo Dureghello
  2024-09-30 19:20           ` David Lechner
  0 siblings, 1 reply; 59+ messages in thread
From: Angelo Dureghello @ 2024-09-30 15:08 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Jonathan Cameron, Lars-Peter Clausen, Michael Hennerich, Nuno Sa,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan,
	linux-iio, linux-kernel, devicetree, dlechner

On 30.09.2024 15:49, Jonathan Cameron wrote:
> On Mon, 30 Sep 2024 16:15:41 +0200
> Angelo Dureghello <adureghello@baylibre.com> wrote:
> 
> > On 29.09.2024 11:51, Jonathan Cameron wrote:
> > > On Thu, 19 Sep 2024 11:20:00 +0200
> > > Angelo Dureghello <adureghello@baylibre.com> wrote:
> > >   
> > > > From: Angelo Dureghello <adureghello@baylibre.com>
> > > > 
> > > > There is a version AXI DAC IP block (for FPGAs) that provides
> > > > a physical bus for AD3552R and similar chips, and acts as
> > > > an SPI controller.  
> > > 
> > > Wrap is a bit short. Aim for < 75 chars for patch descriptions.
> > >   
> > > > 
> > > > For this case, the binding is modified to include some
> > > > additional properties.
> > > > 
> > > > Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> > > > ---
> > > >  .../devicetree/bindings/iio/dac/adi,ad3552r.yaml   | 42 ++++++++++++++++++++++
> > > >  1 file changed, 42 insertions(+)
> > > > 
> > > > diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > > index 41fe00034742..aca4a41c2633 100644
> > > > --- a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > > +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > > @@ -60,6 +60,18 @@ properties:
> > > >      $ref: /schemas/types.yaml#/definitions/uint32
> > > >      enum: [0, 1, 2, 3]
> > > >  
> > > > +  io-backends:
> > > > +    description: The iio backend reference.  
> > > 
> > > Give a description of what the backend does in this case.  I.e. that it is
> > > a qspi DDR backend with ...
> > >   
> > > > +      An example backend can be found at
> > > > +        https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
> > > > +    maxItems: 1
> > > > +
> > > > +  adi,synchronous-mode:
> > > > +    description: Enable waiting for external synchronization signal.
> > > > +      Some AXI IP configuration can implement a dual-IP layout, with internal
> > > > +      wirings for streaming synchronization.  
> > > 
> > > I've no idea what a dual-IP layout is.  Can you provide a little more info
> > > here?  What are the two IPs?
> > >  
> > IP is a term used in fpga design as "intellectual property", that is
> > intended as a functional block of logic or data used to make a 
> > field-programmable gate array module.
> > 
> > A dual layout is just 2 same fpga modules in place of one.
> >  
> > I can add a "fpga" regerence to be more clear.
> 
> IP I was familiar with.  I'm more interested in what each IP is doing in this
> case.  Or at least an example of what sort of split of functionality might
> make use of this.
>

I have an image of the project (that is under development or testing now),
not sure how to attach the image here, btw, something as
 
          axi_ad3552r_0  ----------->---- qspi0
              sync_ext_device --.
       .- external_sync          |
       |                         |
       |-------------<-----------                        
       |
       |   axi_ad3552r_1 ----------->---- qspi1
       `- external_sync
 
My understanding is that it's just a method to use a octal spi,
duplicating the transfer rate. I can collect more info in case.


> Jonathan

Regards,
Angelo

-- 

  o/ QW5nZWxvIER1cmVnaGVsbG8=
   www.kernel-space.org
    e: angelo at kernel-space.org
      c: +39 388 8550663
       

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support
  2024-09-30 13:22                     ` Angelo Dureghello
@ 2024-09-30 15:09                       ` Jonathan Cameron
  2024-10-01  8:23                         ` Nuno Sá
  0 siblings, 1 reply; 59+ messages in thread
From: Jonathan Cameron @ 2024-09-30 15:09 UTC (permalink / raw)
  To: Angelo Dureghello
  Cc: Nuno Sá, Jonathan Cameron, Krzysztof Kozlowski,
	Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Olivier Moysan, linux-iio,
	linux-kernel, devicetree, dlechner

On Mon, 30 Sep 2024 15:22:01 +0200
Angelo Dureghello <adureghello@baylibre.com> wrote:

> On 30.09.2024 09:20, Nuno Sá wrote:
> > On Sun, 2024-09-29 at 11:59 +0100, Jonathan Cameron wrote:  
> > > On Sat, 28 Sep 2024 14:20:29 +0200
> > > Krzysztof Kozlowski <krzk@kernel.org> wrote:
> > >   
> > > > On 25/09/2024 13:55, Nuno Sá wrote:  
> > > > > On Wed, 2024-09-25 at 09:22 +0200, Krzysztof Kozlowski wrote:    
> > > > > > On 24/09/2024 14:27, Nuno Sá wrote:    
> > > > > > > On Tue, 2024-09-24 at 10:02 +0200, Krzysztof Kozlowski wrote:    
> > > > > > > > On 23/09/2024 17:50, Angelo Dureghello wrote:    
> > > > > > > > > Hi Krzysztof,
> > > > > > > > > 
> > > > > > > > > On 22/09/24 23:02, Krzysztof Kozlowski wrote:    
> > > > > > > > > > On Thu, Sep 19, 2024 at 11:20:00AM +0200, Angelo Dureghello
> > > > > > > > > > wrote:    
> > > > > > > > > > > From: Angelo Dureghello <adureghello@baylibre.com>
> > > > > > > > > > > 
> > > > > > > > > > > There is a version AXI DAC IP block (for FPGAs) that provides
> > > > > > > > > > > a physical bus for AD3552R and similar chips, and acts as
> > > > > > > > > > > an SPI controller.
> > > > > > > > > > > 
> > > > > > > > > > > For this case, the binding is modified to include some
> > > > > > > > > > > additional properties.
> > > > > > > > > > > 
> > > > > > > > > > > Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> > > > > > > > > > > ---
> > > > > > > > > > >   .../devicetree/bindings/iio/dac/adi,ad3552r.yaml   | 42
> > > > > > > > > > > ++++++++++++++++++++++
> > > > > > > > > > >   1 file changed, 42 insertions(+)
> > > > > > > > > > > 
> > > > > > > > > > > diff --git
> > > > > > > > > > > a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > > > > > > > > > b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > > > > > > > > > index 41fe00034742..aca4a41c2633 100644
> > > > > > > > > > > ---
> > > > > > > > > > > a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > > > > > > > > > +++
> > > > > > > > > > > b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> > > > > > > > > > > @@ -60,6 +60,18 @@ properties:
> > > > > > > > > > >       $ref: /schemas/types.yaml#/definitions/uint32
> > > > > > > > > > >       enum: [0, 1, 2, 3]
> > > > > > > > > > >   
> > > > > > > > > > > +  io-backends:
> > > > > > > > > > > +    description: The iio backend reference.
> > > > > > > > > > > +      An example backend can be found at
> > > > > > > > > > > +       
> > > > > > > > > > > https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
> > > > > > > > > > > +    maxItems: 1
> > > > > > > > > > > +
> > > > > > > > > > > +  adi,synchronous-mode:
> > > > > > > > > > > +    description: Enable waiting for external synchronization
> > > > > > > > > > > signal.
> > > > > > > > > > > +      Some AXI IP configuration can implement a dual-IP
> > > > > > > > > > > layout,
> > > > > > > > > > > with
> > > > > > > > > > > internal
> > > > > > > > > > > +      wirings for streaming synchronization.
> > > > > > > > > > > +    type: boolean
> > > > > > > > > > > +
> > > > > > > > > > >     '#address-cells':
> > > > > > > > > > >       const: 1
> > > > > > > > > > >   
> > > > > > > > > > > @@ -128,6 +140,7 @@ patternProperties:
> > > > > > > > > > >             - custom-output-range-config
> > > > > > > > > > >   
> > > > > > > > > > >   allOf:
> > > > > > > > > > > +  - $ref: /schemas/spi/spi-peripheral-props.yaml#
> > > > > > > > > > >     - if:
> > > > > > > > > > >         properties:
> > > > > > > > > > >           compatible:
> > > > > > > > > > > @@ -238,4 +251,33 @@ examples:
> > > > > > > > > > >               };
> > > > > > > > > > >           };
> > > > > > > > > > >       };
> > > > > > > > > > > +
> > > > > > > > > > > +  - |
> > > > > > > > > > > +    axi_dac: spi@44a70000 {
> > > > > > > > > > > +        compatible = "adi,axi-ad3552r";    
> > > > > > > > > > That is either redundant or entire example should go to the
> > > > > > > > > > parent
> > > > > > > > > > node,
> > > > > > > > > > if this device is fixed child of complex device (IOW,
> > > > > > > > > > adi,ad3552r
> > > > > > > > > > cannot
> > > > > > > > > > be used outside of adi,axi-ad3552r).    
> > > > > > > > > 
> > > > > > > > > ad3552r can still be used by a generic "classic" spi
> > > > > > > > > controller (SCLK/CS/MISO) but at a slower samplerate, fpga
> > > > > > > > > controller only (axi-ad3552r) can reach 33MUPS.    
> > > > > > > > 
> > > > > > > > OK, then this is just redundant. Drop the node. Parent example
> > > > > > > > should
> > > > > > > > contain the children, though.    
> > > > > > > > >    
> > > > > > > > > >    
> > > > > > > > > > > +        reg = <0x44a70000 0x1000>;
> > > > > > > > > > > +        dmas = <&dac_tx_dma 0>;
> > > > > > > > > > > +        dma-names = "tx";
> > > > > > > > > > > +        #io-backend-cells = <0>;
> > > > > > > > > > > +        clocks = <&ref_clk>;
> > > > > > > > > > > +
> > > > > > > > > > > +        #address-cells = <1>;
> > > > > > > > > > > +        #size-cells = <0>;
> > > > > > > > > > > +
> > > > > > > > > > > +        dac@0 {
> > > > > > > > > > > +            compatible = "adi,ad3552r";
> > > > > > > > > > > +            reg = <0>;
> > > > > > > > > > > +            reset-gpios = <&gpio0 92 0>;    
> > > > > > > > > > Use standard defines for GPIO flags.    
> > > > > > > > > 
> > > > > > > > > fixed, thanks
> > > > > > > > >    
> > > > > > > > > > > +            io-backends = <&axi_dac>;    
> > > > > > > > > > Why do you need to point to the parent? How much coupled are
> > > > > > > > > > these
> > > > > > > > > > devices? Child pointing to parent is not usually expected,
> > > > > > > > > > because
> > > > > > > > > > that's obvious.    
> > > > > > > > > 
> > > > > > > > > 
> > > > > > > > > "io-backends" is actually the way to refer to the backend module,
> > > > > > > > > (used already for i.e. ad9739a),
> > > > > > > > > it is needed because the backend is not only acting as spi-
> > > > > > > > > controller,
> > > > > > > > > but is also providing some APIs for synchronization and bus setup
> > > > > > > > > support.    
> > > > > > > > 
> > > > > > > > 
> > > > > > > > But if backend is the parent, then this is redundant. You can take
> > > > > > > > it
> > > > > > > > from the child-parent relationship. Is this pointing to other
> > > > > > > > devices
> > > > > > > > (non-parent) in other ad3552r configurations?
> > > > > > > >    
> > > > > > > 
> > > > > > > The backend is a provider-consumer type of API. On the consumer side
> > > > > > > (which
> > > > > > > is the
> > > > > > > driver the child node will probe on), we need to call
> > > > > > > devm_iio_backend_get()
> > > > > > > to get
> > > > > > > the backend object (which obviously is the parent). For that, 'io-
> > > > > > > backends'
> > > > > > > is being    
> > > > > > 
> > > > > > You described the driver, so how does it matter? Driver can call
> > > > > > get_backend_from_parent(), right? Or get_backend_from_fwnode(parent)?    
> > > > > 
> > > > > Well yes, just stating what the framework (also in terms of bindings) is
> > > > > expecting. Of course that on the driver side we can paper around it the
> > > > > way we
> > > > > want. But my main point was that we can only paper around it if we use
> > > > > code that
> > > > > is meant not to be used.
> > > > > 
> > > > > And, FWIW, I was (trying) replying to your comment
> > > > > 
> > > > > "You can take it from the child-parent relationship"
> > > > > 
> > > > > Again, we can only do that by introducing new code or use code that's not
> > > > > meant
> > > > > to be used. The way we're supposed to reference backends is by explicitly
> > > > > using
> > > > > the proper FW property.
> > > > > 
> > > > > Put it in another way and a completely hypothetical case. If we have a spi
> > > > > controller which happens to export some clock and one of it's peripherals
> > > > > ends
> > > > > up using that clock, wouldn't we still use 'clocks' to reference that
> > > > > clock?    
> > > > 
> > > > I asked how coupled are these devices. Never got the answer and you are
> > > > reflecting with question. Depends. Please do not create hypothetical,
> > > > generic scenarios and then apply them to your one particular opposite case.  
> > > 
> > > I'll throw a possible clarifying question in here.  Could we use this
> > > device with a multimaster SPI setup such that the control is on a conventional
> > > SPI controller (maybe a qspi capable one), and the data plane only goes
> > > through
> > > a specific purpose backend?  If so, then they are not tightly coupled and
> > > the reference makes sense.  Putting it another way, the difference between
> > > this case and all the prior iio-backend bindings is the control and dataplanes
> > > use the same pins.  Does that have to be the case at the host end?  If it
> > > does,
> > > then the reference isn't strictly needed and this becomes a bit like
> > > registering a single device on an spi bus or an i2c bus depending on who
> > > does the registering (which is down to the parent in DT).
> > >   
> > 
> > So, we currently have two drivers (with a new one being added in this series)
> > for the same device:
> > 
> > 1) A SPI one tied to a typical spi controller. This is the "low speed"
> > implementation and does not use backends;
> > 2) The new platform device that is connected like this to the backend.
> > 
> > So yes, my understanding (but Angelo should know better :)) is that they are
> > tightly coupled. Putting it in another way, the new platform device is very much
> > specific to this parent (and yeah, this is a very special usecase where control
> > and data planes are controlled by the IIO backend) and should not exist with it.  
> 
> ad3552r device can be coupled to the axi-ad3552r controller or to a generic 
> spi controler.
> 
> We have actually 2 drivers, SPI and platform (for AXI controller, in this patch).
> 
> Scenario 1 (SPI):
> ad3522r can hypotetically work with whatever simple spi controller that can
> read/write registers in raw mode. On simple SPI (CS, SCLK, MOSI), due to ad3552r
> chip limitation of 66Mhz clock, the maximum 33MUPS (16 bit samples) cannot be
> reached. Some QSPI DDR controller seems to be around, in that case, ad3552r
> may work extending the SPI driver. 
> 
> Scenario 2 (AXI):
> From an hardware-only point ov view axi-ad3552r IP acts as QSPI+DDR controller
> plus some additional features for stream synchronization.
> From a sowftware point of view, really different from a spi controller driver.
> It's just a backend with APIes that can be called from the child driver.

Potential? scenario 3 is the one that interested me.

ad3552 double wired to a normal SPI controller (so like option 1) and
to a an offload engine (so like option 2).  With a few pull up resistors
(cs and clk?) and some care it should electrically work I think.
In that case we'd need the io-backend reference because the parent
would be the option 1 like SPI bus and the io-backend would not be
the parent.

_______________________
Host       SPI MOSI    |-------------------\
hard       SPI MISO 0-3|----------------\  |
QSPI       SPI CLK     |--------------\  | |
           SPI CS      |----------\    | | |
                       |           |   | | |
FPGA                   |           |   | | |   |
Soft       SPI MOSI    |-----------|---|-|-x---|
QSPI       SPI MISO 0-3|-----------|---|-x-----|  DAC
Offload    SPI CLK     |-----------|---x-------|
with DDR   SPI CS      |-----------x-----------|
_______________________|

Makes all sorts of assumptions about the SPI controllers being designed
for multi controllers on the same SPI buses but I'm not aware of a reason
you can't do that.

As the only control message that would need to go over the offload engine
would be the exit DDR (I think) that might be hard coded into a slightly
simpler soft IP along with the bulk data transfer stuff.

You could even avoid ever disabling DDR by just resetting the device
whenever the configuration changes.  That there is only one message
sent which is the streaming DAC updates.

Point being that it may be tightly couple for your current backend
but I'm not sure it has to be or indeed that all implementers will do it
that way and we need a binding that caters for reasonable configurations.
The question is, is the above reasonable?

Jonathan

> 
> 
> > 
> > - Nuno Sá
> >   
> 
> Regards,
> Angelo
> 


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support
  2024-09-30 15:08         ` Angelo Dureghello
@ 2024-09-30 19:20           ` David Lechner
  2024-10-01  8:09             ` Angelo Dureghello
  0 siblings, 1 reply; 59+ messages in thread
From: David Lechner @ 2024-09-30 19:20 UTC (permalink / raw)
  To: Angelo Dureghello, Jonathan Cameron
  Cc: Jonathan Cameron, Lars-Peter Clausen, Michael Hennerich, Nuno Sa,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan,
	linux-iio, linux-kernel, devicetree

On 9/30/24 10:08 AM, Angelo Dureghello wrote:
> On 30.09.2024 15:49, Jonathan Cameron wrote:
>> On Mon, 30 Sep 2024 16:15:41 +0200
>> Angelo Dureghello <adureghello@baylibre.com> wrote:
>>
>>> On 29.09.2024 11:51, Jonathan Cameron wrote:
>>>> On Thu, 19 Sep 2024 11:20:00 +0200
>>>> Angelo Dureghello <adureghello@baylibre.com> wrote:
>>>>   
>>>>> From: Angelo Dureghello <adureghello@baylibre.com>
>>>>>
>>>>> There is a version AXI DAC IP block (for FPGAs) that provides
>>>>> a physical bus for AD3552R and similar chips, and acts as
>>>>> an SPI controller.  
>>>>
>>>> Wrap is a bit short. Aim for < 75 chars for patch descriptions.
>>>>   
>>>>>
>>>>> For this case, the binding is modified to include some
>>>>> additional properties.
>>>>>
>>>>> Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
>>>>> ---
>>>>>  .../devicetree/bindings/iio/dac/adi,ad3552r.yaml   | 42 ++++++++++++++++++++++
>>>>>  1 file changed, 42 insertions(+)
>>>>>
>>>>> diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
>>>>> index 41fe00034742..aca4a41c2633 100644
>>>>> --- a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
>>>>> +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
>>>>> @@ -60,6 +60,18 @@ properties:
>>>>>      $ref: /schemas/types.yaml#/definitions/uint32
>>>>>      enum: [0, 1, 2, 3]
>>>>>  
>>>>> +  io-backends:
>>>>> +    description: The iio backend reference.  
>>>>
>>>> Give a description of what the backend does in this case.  I.e. that it is
>>>> a qspi DDR backend with ...
>>>>   
>>>>> +      An example backend can be found at
>>>>> +        https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
>>>>> +    maxItems: 1
>>>>> +
>>>>> +  adi,synchronous-mode:
>>>>> +    description: Enable waiting for external synchronization signal.
>>>>> +      Some AXI IP configuration can implement a dual-IP layout, with internal
>>>>> +      wirings for streaming synchronization.  
>>>>
>>>> I've no idea what a dual-IP layout is.  Can you provide a little more info
>>>> here?  What are the two IPs?
>>>>  
>>> IP is a term used in fpga design as "intellectual property", that is
>>> intended as a functional block of logic or data used to make a 
>>> field-programmable gate array module.
>>>
>>> A dual layout is just 2 same fpga modules in place of one.
>>>  
>>> I can add a "fpga" regerence to be more clear.
>>
>> IP I was familiar with.  I'm more interested in what each IP is doing in this
>> case.  Or at least an example of what sort of split of functionality might
>> make use of this.
>>
> 
> I have an image of the project (that is under development or testing now),
> not sure how to attach the image here, btw, something as
>  
>           axi_ad3552r_0  ----------->---- qspi0
>               sync_ext_device --.
>        .- external_sync          |
>        |                         |
>        |-------------<-----------                        
>        |
>        |   axi_ad3552r_1 ----------->---- qspi1
>        `- external_sync
>  
> My understanding is that it's just a method to use a octal spi,
> duplicating the transfer rate. I can collect more info in case.
> 

No, it's not for octal SPI. It is for synchronizing the data
transfer to two different DAC chips.

I think we need a bit more in the DT bindings for this to fully
describe the wiring shown. We need to indicate that both of the
two AXI AD3552R IP blocks have external_sync connected, so a
adi,external-sync flag could be used for this. Then we also need
to describe that sync_ext_device is only wired up on one of the
IP blocks. So we would need a separate adi,sync-ext-device flag.

Then the driver would use this information to A) know that we
need to set the external sync arm bit when starting buffered
reads and B) know that the buffered read for the IP block
instance with sync_ext_device needs to be started last so that
the data streams for both DACs will be synchronized.

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 05/10] iio: backend: extend features
  2024-09-29 11:05   ` Jonathan Cameron
@ 2024-09-30 19:25     ` David Lechner
  2024-10-01  8:14       ` Nuno Sá
  0 siblings, 1 reply; 59+ messages in thread
From: David Lechner @ 2024-09-30 19:25 UTC (permalink / raw)
  To: Jonathan Cameron, Angelo Dureghello
  Cc: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Olivier Moysan, linux-iio,
	linux-kernel, devicetree

On 9/29/24 6:05 AM, Jonathan Cameron wrote:
> On Thu, 19 Sep 2024 11:20:01 +0200
> Angelo Dureghello <adureghello@baylibre.com> wrote:
> 
>> From: Angelo Dureghello <adureghello@baylibre.com>
>>
>> Extend backend features with new calls needed later on this
>> patchset from axi version of ad3552r.
>>
>> The follwoing calls are added:
>>
>> iio_backend_ext_sync_enable
>> 	enable synchronize channels on external trigger
>> iio_backend_ext_sync_disable
>> 	disable synchronize channels on external trigger
>> iio_backend_ddr_enable
>> 	enable ddr bus transfer
>> iio_backend_ddr_disable
>> 	disable ddr bus transfer
>> iio_backend_set_bus_mode
>> 	select the type of bus, so that specific read / write
>> 	operations are performed accordingly
>> iio_backend_buffer_enable
>> 	enable buffer
>> iio_backend_buffer_disable
>> 	disable buffer
>> iio_backend_data_transfer_addr
>> 	define the target register address where the DAC sample
>> 	will be written.
>>
>> Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> Hi Angelo,
> A few trivial comments inline.
> 
>> ---
>>  drivers/iio/industrialio-backend.c | 111 +++++++++++++++++++++++++++++++++++++
>>  include/linux/iio/backend.h        |  23 ++++++++
>>  2 files changed, 134 insertions(+)
>>
>> diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c
>> index 20b3b5212da7..f4802c422dbf 100644
>> --- a/drivers/iio/industrialio-backend.c
>> +++ b/drivers/iio/industrialio-backend.c
>> @@ -718,6 +718,117 @@ static int __devm_iio_backend_get(struct device *dev, struct iio_backend *back)
> ...
> 
>> +/**
>> + * iio_backend_ddr_disable - Disable interface DDR (Double Data Rate) mode
>> + * @back: Backend device
>> + *
>> + * Disabling DDR data is generated byt the IP at rising or falling front
> 
> Spell check your comments.
> 
>> + * of the interface clock signal (SDR, Single Data Rate).
>> + *
>> + * RETURNS:
>> + * 0 on success, negative error number on failure.
>> + */
>> +int iio_backend_ddr_disable(struct iio_backend *back)
>> +{
>> +	return iio_backend_op_call(back, ddr_disable);
>> +}
>> +EXPORT_SYMBOL_NS_GPL(iio_backend_ddr_disable, IIO_BACKEND);
> 				 struct fwnode_handle *fwnode)
>>  {
>> diff --git a/include/linux/iio/backend.h b/include/linux/iio/backend.h
>> index 37d56914d485..41619b803cd6 100644
>> --- a/include/linux/iio/backend.h
>> +++ b/include/linux/iio/backend.h
>> @@ -14,12 +14,14 @@ struct iio_dev;
>>  enum iio_backend_data_type {
>>  	IIO_BACKEND_TWOS_COMPLEMENT,
>>  	IIO_BACKEND_OFFSET_BINARY,
>> +	IIO_BACKEND_DATA_UNSIGNED,
>>  	IIO_BACKEND_DATA_TYPE_MAX
>>  };
>>  
>>  enum iio_backend_data_source {
>>  	IIO_BACKEND_INTERNAL_CONTINUOUS_WAVE,
>>  	IIO_BACKEND_EXTERNAL,
>> +	IIO_BACKEND_INTERNAL_RAMP_16BIT,
>>  	IIO_BACKEND_DATA_SOURCE_MAX
>>  };
>>  
>> @@ -89,6 +91,13 @@ enum iio_backend_sample_trigger {
>>   * @read_raw: Read a channel attribute from a backend device
>>   * @debugfs_print_chan_status: Print channel status into a buffer.
>>   * @debugfs_reg_access: Read or write register value of backend.
>> + * @ext_sync_enable: Enable external synchronization.
>> + * @ext_sync_disable: Disable external synchronization.
>> + * @ddr_enable: Enable interface DDR (Double Data Rate) mode.
>> + * @ddr_disable: Disable interface DDR (Double Data Rate) mode.
>> + * @buffer_enable: Enable data buffer.
>> + * @buffer_disable: Disable data buffer.
> 
> This needs more specific text. What buffer?  I think this came
> up earlier but it needs to say something about the fact it's enabling
> or disabling the actual capture of data into the DMA buffers that
> userspace will read.
> 
>> + * @data_transfer_addr: Set data address.
>>   **/
>>  struct iio_backend_ops {
>>  	int (*enable)(struct iio_backend *back);
>> @@ -129,6 +138,13 @@ struct iio_backend_ops {
>>  					 size_t len);
>>  	int (*debugfs_reg_access)(struct iio_backend *back, unsigned int reg,
>>  				  unsigned int writeval, unsigned int *readval);
>> +	int (*ext_sync_enable)(struct iio_backend *back);
> I know we've done it this way for existing items, but I wonder if we should
> squish down the ops slightly and have new enable/disable pairs as
> single functions.
> 	int (*ext_sync_set_state)(struct iio_backend *back, bool enable);
> etc.  If nothing else reduces how many things need documentation ;)
> 
> Nuno, what do you think? Worth squashing these pairs into single
> callbacks?

I'm not a fan of combining enable and disable functions into one function.

The implementation will pretty much always be:

if (enabled) {
        /* so stuff */
} else {
        /* do other stuff */
}

Which just adds indent and makes code harder to read.

> 
>> +	int (*ext_sync_disable)(struct iio_backend *back);
>> +	int (*ddr_enable)(struct iio_backend *back);
>> +	int (*ddr_disable)(struct iio_backend *back);
>> +	int (*buffer_enable)(struct iio_backend *back);
>> +	int (*buffer_disable)(struct iio_backend *back);
>> +	int (*data_transfer_addr)(struct iio_backend *back, u32 address);
>>  };


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support
  2024-09-30 19:20           ` David Lechner
@ 2024-10-01  8:09             ` Angelo Dureghello
  0 siblings, 0 replies; 59+ messages in thread
From: Angelo Dureghello @ 2024-10-01  8:09 UTC (permalink / raw)
  To: David Lechner
  Cc: Jonathan Cameron, Jonathan Cameron, Lars-Peter Clausen,
	Michael Hennerich, Nuno Sa, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Olivier Moysan, linux-iio, linux-kernel, devicetree

On 30.09.2024 14:20, David Lechner wrote:
> On 9/30/24 10:08 AM, Angelo Dureghello wrote:
> > On 30.09.2024 15:49, Jonathan Cameron wrote:
> >> On Mon, 30 Sep 2024 16:15:41 +0200
> >> Angelo Dureghello <adureghello@baylibre.com> wrote:
> >>
> >>> On 29.09.2024 11:51, Jonathan Cameron wrote:
> >>>> On Thu, 19 Sep 2024 11:20:00 +0200
> >>>> Angelo Dureghello <adureghello@baylibre.com> wrote:
> >>>>   
> >>>>> From: Angelo Dureghello <adureghello@baylibre.com>
> >>>>>
> >>>>> There is a version AXI DAC IP block (for FPGAs) that provides
> >>>>> a physical bus for AD3552R and similar chips, and acts as
> >>>>> an SPI controller.  
> >>>>
> >>>> Wrap is a bit short. Aim for < 75 chars for patch descriptions.
> >>>>   
> >>>>>
> >>>>> For this case, the binding is modified to include some
> >>>>> additional properties.
> >>>>>
> >>>>> Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> >>>>> ---
> >>>>>  .../devicetree/bindings/iio/dac/adi,ad3552r.yaml   | 42 ++++++++++++++++++++++
> >>>>>  1 file changed, 42 insertions(+)
> >>>>>
> >>>>> diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> >>>>> index 41fe00034742..aca4a41c2633 100644
> >>>>> --- a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> >>>>> +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
> >>>>> @@ -60,6 +60,18 @@ properties:
> >>>>>      $ref: /schemas/types.yaml#/definitions/uint32
> >>>>>      enum: [0, 1, 2, 3]
> >>>>>  
> >>>>> +  io-backends:
> >>>>> +    description: The iio backend reference.  
> >>>>
> >>>> Give a description of what the backend does in this case.  I.e. that it is
> >>>> a qspi DDR backend with ...
> >>>>   
> >>>>> +      An example backend can be found at
> >>>>> +        https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
> >>>>> +    maxItems: 1
> >>>>> +
> >>>>> +  adi,synchronous-mode:
> >>>>> +    description: Enable waiting for external synchronization signal.
> >>>>> +      Some AXI IP configuration can implement a dual-IP layout, with internal
> >>>>> +      wirings for streaming synchronization.  
> >>>>
> >>>> I've no idea what a dual-IP layout is.  Can you provide a little more info
> >>>> here?  What are the two IPs?
> >>>>  
> >>> IP is a term used in fpga design as "intellectual property", that is
> >>> intended as a functional block of logic or data used to make a 
> >>> field-programmable gate array module.
> >>>
> >>> A dual layout is just 2 same fpga modules in place of one.
> >>>  
> >>> I can add a "fpga" regerence to be more clear.
> >>
> >> IP I was familiar with.  I'm more interested in what each IP is doing in this
> >> case.  Or at least an example of what sort of split of functionality might
> >> make use of this.
> >>
> > 
> > I have an image of the project (that is under development or testing now),
> > not sure how to attach the image here, btw, something as
> >  
> >           axi_ad3552r_0  ----------->---- qspi0
> >               sync_ext_device --.
> >        .- external_sync          |
> >        |                         |
> >        |-------------<-----------                        
> >        |
> >        |   axi_ad3552r_1 ----------->---- qspi1
> >        `- external_sync
> >  
> > My understanding is that it's just a method to use a octal spi,
> > duplicating the transfer rate. I can collect more info in case.
> > 
> 
> No, it's not for octal SPI. It is for synchronizing the data
> transfer to two different DAC chips.
> 
> I think we need a bit more in the DT bindings for this to fully
> describe the wiring shown. We need to indicate that both of the
> two AXI AD3552R IP blocks have external_sync connected, so a
> adi,external-sync flag could be used for this. Then we also need
> to describe that sync_ext_device is only wired up on one of the
> IP blocks. So we would need a separate adi,sync-ext-device flag.
> 
> Then the driver would use this information to A) know that we
> need to set the external sync arm bit when starting buffered
> reads and B) know that the buffered read for the IP block
> instance with sync_ext_device needs to be started last so that
> the data streams for both DACs will be synchronized.

I thought to add this sync stuff thinking that it will be needed
soon, btw, it is not used right now for a single IP. 
I suggest to remove it entirely, since it is actually dead code,
and this hopefully can fast up things.

-- 

Regards,
  Angelo
       

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 05/10] iio: backend: extend features
  2024-09-30 19:25     ` David Lechner
@ 2024-10-01  8:14       ` Nuno Sá
  2024-10-01  8:35         ` Angelo Dureghello
  0 siblings, 1 reply; 59+ messages in thread
From: Nuno Sá @ 2024-10-01  8:14 UTC (permalink / raw)
  To: David Lechner, Jonathan Cameron, Angelo Dureghello
  Cc: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Olivier Moysan, linux-iio,
	linux-kernel, devicetree

On Mon, 2024-09-30 at 14:25 -0500, David Lechner wrote:
> On 9/29/24 6:05 AM, Jonathan Cameron wrote:
> > On Thu, 19 Sep 2024 11:20:01 +0200
> > Angelo Dureghello <adureghello@baylibre.com> wrote:
> > 
> > > From: Angelo Dureghello <adureghello@baylibre.com>
> > > 
> > > Extend backend features with new calls needed later on this
> > > patchset from axi version of ad3552r.
> > > 
> > > The follwoing calls are added:
> > > 
> > > iio_backend_ext_sync_enable
> > > 	enable synchronize channels on external trigger
> > > iio_backend_ext_sync_disable
> > > 	disable synchronize channels on external trigger
> > > iio_backend_ddr_enable
> > > 	enable ddr bus transfer
> > > iio_backend_ddr_disable
> > > 	disable ddr bus transfer
> > > iio_backend_set_bus_mode
> > > 	select the type of bus, so that specific read / write
> > > 	operations are performed accordingly
> > > iio_backend_buffer_enable
> > > 	enable buffer
> > > iio_backend_buffer_disable
> > > 	disable buffer
> > > iio_backend_data_transfer_addr
> > > 	define the target register address where the DAC sample
> > > 	will be written.
> > > 
> > > Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> > Hi Angelo,
> > A few trivial comments inline.
> > 
> > > ---
> > >  drivers/iio/industrialio-backend.c | 111
> > > +++++++++++++++++++++++++++++++++++++
> > >  include/linux/iio/backend.h        |  23 ++++++++
> > >  2 files changed, 134 insertions(+)
> > > 
> > > diff --git a/drivers/iio/industrialio-backend.c
> > > b/drivers/iio/industrialio-backend.c
> > > index 20b3b5212da7..f4802c422dbf 100644
> > > --- a/drivers/iio/industrialio-backend.c
> > > +++ b/drivers/iio/industrialio-backend.c
> > > @@ -718,6 +718,117 @@ static int __devm_iio_backend_get(struct device
> > > *dev, struct iio_backend *back)
> > ...
> > 
> > > +/**
> > > + * iio_backend_ddr_disable - Disable interface DDR (Double Data Rate)
> > > mode
> > > + * @back: Backend device
> > > + *
> > > + * Disabling DDR data is generated byt the IP at rising or falling front
> > 
> > Spell check your comments.
> > 
> > > + * of the interface clock signal (SDR, Single Data Rate).
> > > + *
> > > + * RETURNS:
> > > + * 0 on success, negative error number on failure.
> > > + */
> > > +int iio_backend_ddr_disable(struct iio_backend *back)
> > > +{
> > > +	return iio_backend_op_call(back, ddr_disable);
> > > +}
> > > +EXPORT_SYMBOL_NS_GPL(iio_backend_ddr_disable, IIO_BACKEND);
> > 				 struct fwnode_handle *fwnode)
> > >  {
> > > diff --git a/include/linux/iio/backend.h b/include/linux/iio/backend.h
> > > index 37d56914d485..41619b803cd6 100644
> > > --- a/include/linux/iio/backend.h
> > > +++ b/include/linux/iio/backend.h
> > > @@ -14,12 +14,14 @@ struct iio_dev;
> > >  enum iio_backend_data_type {
> > >  	IIO_BACKEND_TWOS_COMPLEMENT,
> > >  	IIO_BACKEND_OFFSET_BINARY,
> > > +	IIO_BACKEND_DATA_UNSIGNED,
> > >  	IIO_BACKEND_DATA_TYPE_MAX
> > >  };
> > >  
> > >  enum iio_backend_data_source {
> > >  	IIO_BACKEND_INTERNAL_CONTINUOUS_WAVE,
> > >  	IIO_BACKEND_EXTERNAL,
> > > +	IIO_BACKEND_INTERNAL_RAMP_16BIT,
> > >  	IIO_BACKEND_DATA_SOURCE_MAX
> > >  };
> > >  
> > > @@ -89,6 +91,13 @@ enum iio_backend_sample_trigger {
> > >   * @read_raw: Read a channel attribute from a backend device
> > >   * @debugfs_print_chan_status: Print channel status into a buffer.
> > >   * @debugfs_reg_access: Read or write register value of backend.
> > > + * @ext_sync_enable: Enable external synchronization.
> > > + * @ext_sync_disable: Disable external synchronization.
> > > + * @ddr_enable: Enable interface DDR (Double Data Rate) mode.
> > > + * @ddr_disable: Disable interface DDR (Double Data Rate) mode.
> > > + * @buffer_enable: Enable data buffer.
> > > + * @buffer_disable: Disable data buffer.
> > 
> > This needs more specific text. What buffer?  I think this came
> > up earlier but it needs to say something about the fact it's enabling
> > or disabling the actual capture of data into the DMA buffers that
> > userspace will read.
> > 
> > > + * @data_transfer_addr: Set data address.
> > >   **/
> > >  struct iio_backend_ops {
> > >  	int (*enable)(struct iio_backend *back);
> > > @@ -129,6 +138,13 @@ struct iio_backend_ops {
> > >  					 size_t len);
> > >  	int (*debugfs_reg_access)(struct iio_backend *back, unsigned int
> > > reg,
> > >  				  unsigned int writeval, unsigned int
> > > *readval);
> > > +	int (*ext_sync_enable)(struct iio_backend *back);
> > I know we've done it this way for existing items, but I wonder if we should
> > squish down the ops slightly and have new enable/disable pairs as
> > single functions.
> > 	int (*ext_sync_set_state)(struct iio_backend *back, bool enable);
> > etc.  If nothing else reduces how many things need documentation ;)
> > 
> > Nuno, what do you think? Worth squashing these pairs into single
> > callbacks?
> 
> I'm not a fan of combining enable and disable functions into one function.
> 
> The implementation will pretty much always be:
> 
> if (enabled) {
>         /* so stuff */
> } else {
>         /* do other stuff */
> }
> 
> Which just adds indent and makes code harder to read.
> 

Hi Jonathan and David,

Yeah, I have this on my todo list and to be fair with Angelo, he already had
something like you're suggesting. I kind of asked him to postpone that so we
don't have mixed styles in the file for now. Then I would convert them all. My
plan would be to squash the .ops into one and then have inline
enable()/disable() helpers (at least for the current users in order to keep
things easier to convert).

As for David's comment, I see your point but one can always improve things a bit

if (enable) {
	/* do stuff */
	return;
}

/* do disable stuff */
return 0

I'm aware the above is always not that straight... but I do think there's always
ways to rearrange things a bit to make it better. Because even with the
enable()/disable() approach, if you start to have a lot of common code, likely
you'll add an helper function. In some cases, one can even add the helper right
away with an 'enable' argument effectively doing what is being suggested in
here. It always depends on the person implementing the ops :)

Anyways, I really don't have a strong feeling about this. I had in my mind to do
something like this. It feels that Jonathan would already be ok with it. If it's
not that awful for David, I'll eventually send the patches (unless Angelo wants
to take care if it in this series).

- Nuno Sá
> 

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support
  2024-09-30 15:09                       ` Jonathan Cameron
@ 2024-10-01  8:23                         ` Nuno Sá
  2024-10-01 18:29                           ` Jonathan Cameron
  0 siblings, 1 reply; 59+ messages in thread
From: Nuno Sá @ 2024-10-01  8:23 UTC (permalink / raw)
  To: Jonathan Cameron, Angelo Dureghello
  Cc: Jonathan Cameron, Krzysztof Kozlowski, Lars-Peter Clausen,
	Michael Hennerich, Nuno Sa, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Olivier Moysan, linux-iio, linux-kernel, devicetree,
	dlechner

On Mon, 2024-09-30 at 16:09 +0100, Jonathan Cameron wrote:
> On Mon, 30 Sep 2024 15:22:01 +0200
> Angelo Dureghello <adureghello@baylibre.com> wrote:
> 
> > On 30.09.2024 09:20, Nuno Sá wrote:
> > > On Sun, 2024-09-29 at 11:59 +0100, Jonathan Cameron wrote:  
> > > > On Sat, 28 Sep 2024 14:20:29 +0200
> > > > Krzysztof Kozlowski <krzk@kernel.org> wrote:
> > > >   
> > > > > On 25/09/2024 13:55, Nuno Sá wrote:  
> > > > > > On Wed, 2024-09-25 at 09:22 +0200, Krzysztof Kozlowski wrote:    
> > > > > > > On 24/09/2024 14:27, Nuno Sá wrote:    
> > > > > > > > On Tue, 2024-09-24 at 10:02 +0200, Krzysztof Kozlowski wrote:   
> > > > > > > > > On 23/09/2024 17:50, Angelo Dureghello wrote:    
> > > > > > > > > > Hi Krzysztof,
> > > > > > > > > > 
> > > > > > > > > > On 22/09/24 23:02, Krzysztof Kozlowski wrote:    
> > > > > > > > > > > On Thu, Sep 19, 2024 at 11:20:00AM +0200, Angelo
> > > > > > > > > > > Dureghello
> > > > > > > > > > > wrote:    
> > > > > > > > > > > > From: Angelo Dureghello <adureghello@baylibre.com>
> > > > > > > > > > > > 
> > > > > > > > > > > > There is a version AXI DAC IP block (for FPGAs) that
> > > > > > > > > > > > provides
> > > > > > > > > > > > a physical bus for AD3552R and similar chips, and acts
> > > > > > > > > > > > as
> > > > > > > > > > > > an SPI controller.
> > > > > > > > > > > > 
> > > > > > > > > > > > For this case, the binding is modified to include some
> > > > > > > > > > > > additional properties.
> > > > > > > > > > > > 
> > > > > > > > > > > > Signed-off-by: Angelo Dureghello
> > > > > > > > > > > > <adureghello@baylibre.com>
> > > > > > > > > > > > ---
> > > > > > > > > > > >   .../devicetree/bindings/iio/dac/adi,ad3552r.yaml   |
> > > > > > > > > > > > 42
> > > > > > > > > > > > ++++++++++++++++++++++
> > > > > > > > > > > >   1 file changed, 42 insertions(+)
> > > > > > > > > > > > 
> > > > > > > > > > > > diff --git
> > > > > > > > > > > > a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.
> > > > > > > > > > > > yaml
> > > > > > > > > > > > b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.
> > > > > > > > > > > > yaml
> > > > > > > > > > > > index 41fe00034742..aca4a41c2633 100644
> > > > > > > > > > > > ---
> > > > > > > > > > > > a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.
> > > > > > > > > > > > yaml
> > > > > > > > > > > > +++
> > > > > > > > > > > > b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.
> > > > > > > > > > > > yaml
> > > > > > > > > > > > @@ -60,6 +60,18 @@ properties:
> > > > > > > > > > > >       $ref: /schemas/types.yaml#/definitions/uint32
> > > > > > > > > > > >       enum: [0, 1, 2, 3]
> > > > > > > > > > > >   
> > > > > > > > > > > > +  io-backends:
> > > > > > > > > > > > +    description: The iio backend reference.
> > > > > > > > > > > > +      An example backend can be found at
> > > > > > > > > > > > +       
> > > > > > > > > > > > https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
> > > > > > > > > > > > +    maxItems: 1
> > > > > > > > > > > > +
> > > > > > > > > > > > +  adi,synchronous-mode:
> > > > > > > > > > > > +    description: Enable waiting for external
> > > > > > > > > > > > synchronization
> > > > > > > > > > > > signal.
> > > > > > > > > > > > +      Some AXI IP configuration can implement a dual-IP
> > > > > > > > > > > > layout,
> > > > > > > > > > > > with
> > > > > > > > > > > > internal
> > > > > > > > > > > > +      wirings for streaming synchronization.
> > > > > > > > > > > > +    type: boolean
> > > > > > > > > > > > +
> > > > > > > > > > > >     '#address-cells':
> > > > > > > > > > > >       const: 1
> > > > > > > > > > > >   
> > > > > > > > > > > > @@ -128,6 +140,7 @@ patternProperties:
> > > > > > > > > > > >             - custom-output-range-config
> > > > > > > > > > > >   
> > > > > > > > > > > >   allOf:
> > > > > > > > > > > > +  - $ref: /schemas/spi/spi-peripheral-props.yaml#
> > > > > > > > > > > >     - if:
> > > > > > > > > > > >         properties:
> > > > > > > > > > > >           compatible:
> > > > > > > > > > > > @@ -238,4 +251,33 @@ examples:
> > > > > > > > > > > >               };
> > > > > > > > > > > >           };
> > > > > > > > > > > >       };
> > > > > > > > > > > > +
> > > > > > > > > > > > +  - |
> > > > > > > > > > > > +    axi_dac: spi@44a70000 {
> > > > > > > > > > > > +        compatible = "adi,axi-ad3552r";    
> > > > > > > > > > > That is either redundant or entire example should go to
> > > > > > > > > > > the
> > > > > > > > > > > parent
> > > > > > > > > > > node,
> > > > > > > > > > > if this device is fixed child of complex device (IOW,
> > > > > > > > > > > adi,ad3552r
> > > > > > > > > > > cannot
> > > > > > > > > > > be used outside of adi,axi-ad3552r).    
> > > > > > > > > > 
> > > > > > > > > > ad3552r can still be used by a generic "classic" spi
> > > > > > > > > > controller (SCLK/CS/MISO) but at a slower samplerate, fpga
> > > > > > > > > > controller only (axi-ad3552r) can reach 33MUPS.    
> > > > > > > > > 
> > > > > > > > > OK, then this is just redundant. Drop the node. Parent example
> > > > > > > > > should
> > > > > > > > > contain the children, though.    
> > > > > > > > > >    
> > > > > > > > > > >    
> > > > > > > > > > > > +        reg = <0x44a70000 0x1000>;
> > > > > > > > > > > > +        dmas = <&dac_tx_dma 0>;
> > > > > > > > > > > > +        dma-names = "tx";
> > > > > > > > > > > > +        #io-backend-cells = <0>;
> > > > > > > > > > > > +        clocks = <&ref_clk>;
> > > > > > > > > > > > +
> > > > > > > > > > > > +        #address-cells = <1>;
> > > > > > > > > > > > +        #size-cells = <0>;
> > > > > > > > > > > > +
> > > > > > > > > > > > +        dac@0 {
> > > > > > > > > > > > +            compatible = "adi,ad3552r";
> > > > > > > > > > > > +            reg = <0>;
> > > > > > > > > > > > +            reset-gpios = <&gpio0 92 0>;    
> > > > > > > > > > > Use standard defines for GPIO flags.    
> > > > > > > > > > 
> > > > > > > > > > fixed, thanks
> > > > > > > > > >    
> > > > > > > > > > > > +            io-backends = <&axi_dac>;    
> > > > > > > > > > > Why do you need to point to the parent? How much coupled
> > > > > > > > > > > are
> > > > > > > > > > > these
> > > > > > > > > > > devices? Child pointing to parent is not usually expected,
> > > > > > > > > > > because
> > > > > > > > > > > that's obvious.    
> > > > > > > > > > 
> > > > > > > > > > 
> > > > > > > > > > "io-backends" is actually the way to refer to the backend
> > > > > > > > > > module,
> > > > > > > > > > (used already for i.e. ad9739a),
> > > > > > > > > > it is needed because the backend is not only acting as spi-
> > > > > > > > > > controller,
> > > > > > > > > > but is also providing some APIs for synchronization and bus
> > > > > > > > > > setup
> > > > > > > > > > support.    
> > > > > > > > > 
> > > > > > > > > 
> > > > > > > > > But if backend is the parent, then this is redundant. You can
> > > > > > > > > take
> > > > > > > > > it
> > > > > > > > > from the child-parent relationship. Is this pointing to other
> > > > > > > > > devices
> > > > > > > > > (non-parent) in other ad3552r configurations?
> > > > > > > > >    
> > > > > > > > 
> > > > > > > > The backend is a provider-consumer type of API. On the consumer
> > > > > > > > side
> > > > > > > > (which
> > > > > > > > is the
> > > > > > > > driver the child node will probe on), we need to call
> > > > > > > > devm_iio_backend_get()
> > > > > > > > to get
> > > > > > > > the backend object (which obviously is the parent). For that,
> > > > > > > > 'io-
> > > > > > > > backends'
> > > > > > > > is being    
> > > > > > > 
> > > > > > > You described the driver, so how does it matter? Driver can call
> > > > > > > get_backend_from_parent(), right? Or
> > > > > > > get_backend_from_fwnode(parent)?    
> > > > > > 
> > > > > > Well yes, just stating what the framework (also in terms of
> > > > > > bindings) is
> > > > > > expecting. Of course that on the driver side we can paper around it
> > > > > > the
> > > > > > way we
> > > > > > want. But my main point was that we can only paper around it if we
> > > > > > use
> > > > > > code that
> > > > > > is meant not to be used.
> > > > > > 
> > > > > > And, FWIW, I was (trying) replying to your comment
> > > > > > 
> > > > > > "You can take it from the child-parent relationship"
> > > > > > 
> > > > > > Again, we can only do that by introducing new code or use code
> > > > > > that's not
> > > > > > meant
> > > > > > to be used. The way we're supposed to reference backends is by
> > > > > > explicitly
> > > > > > using
> > > > > > the proper FW property.
> > > > > > 
> > > > > > Put it in another way and a completely hypothetical case. If we have
> > > > > > a spi
> > > > > > controller which happens to export some clock and one of it's
> > > > > > peripherals
> > > > > > ends
> > > > > > up using that clock, wouldn't we still use 'clocks' to reference
> > > > > > that
> > > > > > clock?    
> > > > > 
> > > > > I asked how coupled are these devices. Never got the answer and you
> > > > > are
> > > > > reflecting with question. Depends. Please do not create hypothetical,
> > > > > generic scenarios and then apply them to your one particular opposite
> > > > > case.  
> > > > 
> > > > I'll throw a possible clarifying question in here.  Could we use this
> > > > device with a multimaster SPI setup such that the control is on a
> > > > conventional
> > > > SPI controller (maybe a qspi capable one), and the data plane only goes
> > > > through
> > > > a specific purpose backend?  If so, then they are not tightly coupled
> > > > and
> > > > the reference makes sense.  Putting it another way, the difference
> > > > between
> > > > this case and all the prior iio-backend bindings is the control and
> > > > dataplanes
> > > > use the same pins.  Does that have to be the case at the host end?  If
> > > > it
> > > > does,
> > > > then the reference isn't strictly needed and this becomes a bit like
> > > > registering a single device on an spi bus or an i2c bus depending on who
> > > > does the registering (which is down to the parent in DT).
> > > >   
> > > 
> > > So, we currently have two drivers (with a new one being added in this
> > > series)
> > > for the same device:
> > > 
> > > 1) A SPI one tied to a typical spi controller. This is the "low speed"
> > > implementation and does not use backends;
> > > 2) The new platform device that is connected like this to the backend.
> > > 
> > > So yes, my understanding (but Angelo should know better :)) is that they
> > > are
> > > tightly coupled. Putting it in another way, the new platform device is
> > > very much
> > > specific to this parent (and yeah, this is a very special usecase where
> > > control
> > > and data planes are controlled by the IIO backend) and should not exist
> > > with it.  
> > 
> > ad3552r device can be coupled to the axi-ad3552r controller or to a generic 
> > spi controler.
> > 
> > We have actually 2 drivers, SPI and platform (for AXI controller, in this
> > patch).
> > 
> > Scenario 1 (SPI):
> > ad3522r can hypotetically work with whatever simple spi controller that can
> > read/write registers in raw mode. On simple SPI (CS, SCLK, MOSI), due to
> > ad3552r
> > chip limitation of 66Mhz clock, the maximum 33MUPS (16 bit samples) cannot
> > be
> > reached. Some QSPI DDR controller seems to be around, in that case, ad3552r
> > may work extending the SPI driver. 
> > 
> > Scenario 2 (AXI):
> > From an hardware-only point ov view axi-ad3552r IP acts as QSPI+DDR
> > controller
> > plus some additional features for stream synchronization.
> > From a sowftware point of view, really different from a spi controller
> > driver.
> > It's just a backend with APIes that can be called from the child driver.
> 
> Potential? scenario 3 is the one that interested me.
> 
> ad3552 double wired to a normal SPI controller (so like option 1) and
> to a an offload engine (so like option 2).  With a few pull up resistors
> (cs and clk?) and some care it should electrically work I think.
> In that case we'd need the io-backend reference because the parent
> would be the option 1 like SPI bus and the io-backend would not be
> the parent.
> 
> _______________________
> Host       SPI MOSI    |-------------------\
> hard       SPI MISO 0-3|----------------\  |
> QSPI       SPI CLK     |--------------\  | |
>            SPI CS      |----------\    | | |
>                        |           |   | | |
> FPGA                   |           |   | | |   |
> Soft       SPI MOSI    |-----------|---|-|-x---|
> QSPI       SPI MISO 0-3|-----------|---|-x-----|  DAC
> Offload    SPI CLK     |-----------|---x-------|
> with DDR   SPI CS      |-----------x-----------|
> _______________________|
> 
> Makes all sorts of assumptions about the SPI controllers being designed
> for multi controllers on the same SPI buses but I'm not aware of a reason
> you can't do that.
> 
> As the only control message that would need to go over the offload engine
> would be the exit DDR (I think) that might be hard coded into a slightly
> simpler soft IP along with the bulk data transfer stuff.
> 

Not even sure if DDR would be a problem. Right now, I __think__ we need to
enable DDR both the peripheral and on the backend. On the peripheral we could
use the control link on the non offload controller. On the offload controller,
we would set it through IIO backend and that would be a backend config and not
go over the bus.

To make a correction on my previous reply to Krzysztof, the HW folks made some
experiments with the SPI ENIGINE IP (with the offload engine) but without the
AXI DAC IP. So, effectively only one controller in place. That said, I'm also
not seeing any reason why something like the above would not be possible.

- Nuno Sá


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 05/10] iio: backend: extend features
  2024-10-01  8:14       ` Nuno Sá
@ 2024-10-01  8:35         ` Angelo Dureghello
  2024-10-01 18:32           ` Jonathan Cameron
  0 siblings, 1 reply; 59+ messages in thread
From: Angelo Dureghello @ 2024-10-01  8:35 UTC (permalink / raw)
  To: Nuno Sá
  Cc: David Lechner, Jonathan Cameron, Lars-Peter Clausen,
	Michael Hennerich, Nuno Sa, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Olivier Moysan, linux-iio, linux-kernel, devicetree

On 01.10.2024 10:14, Nuno Sá wrote:
> On Mon, 2024-09-30 at 14:25 -0500, David Lechner wrote:
> > On 9/29/24 6:05 AM, Jonathan Cameron wrote:
> > > On Thu, 19 Sep 2024 11:20:01 +0200
> > > Angelo Dureghello <adureghello@baylibre.com> wrote:
> > > 
> > > > From: Angelo Dureghello <adureghello@baylibre.com>
> > > > 
> > > > Extend backend features with new calls needed later on this
> > > > patchset from axi version of ad3552r.
> > > > 
> > > > The follwoing calls are added:
> > > > 
> > > > iio_backend_ext_sync_enable
> > > > 	enable synchronize channels on external trigger
> > > > iio_backend_ext_sync_disable
> > > > 	disable synchronize channels on external trigger
> > > > iio_backend_ddr_enable
> > > > 	enable ddr bus transfer
> > > > iio_backend_ddr_disable
> > > > 	disable ddr bus transfer
> > > > iio_backend_set_bus_mode
> > > > 	select the type of bus, so that specific read / write
> > > > 	operations are performed accordingly
> > > > iio_backend_buffer_enable
> > > > 	enable buffer
> > > > iio_backend_buffer_disable
> > > > 	disable buffer
> > > > iio_backend_data_transfer_addr
> > > > 	define the target register address where the DAC sample
> > > > 	will be written.
> > > > 
> > > > Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> > > Hi Angelo,
> > > A few trivial comments inline.
> > > 
> > > > ---
> > > >  drivers/iio/industrialio-backend.c | 111
> > > > +++++++++++++++++++++++++++++++++++++
> > > >  include/linux/iio/backend.h        |  23 ++++++++
> > > >  2 files changed, 134 insertions(+)
> > > > 
> > > > diff --git a/drivers/iio/industrialio-backend.c
> > > > b/drivers/iio/industrialio-backend.c
> > > > index 20b3b5212da7..f4802c422dbf 100644
> > > > --- a/drivers/iio/industrialio-backend.c
> > > > +++ b/drivers/iio/industrialio-backend.c
> > > > @@ -718,6 +718,117 @@ static int __devm_iio_backend_get(struct device
> > > > *dev, struct iio_backend *back)
> > > ...
> > > 
> > > > +/**
> > > > + * iio_backend_ddr_disable - Disable interface DDR (Double Data Rate)
> > > > mode
> > > > + * @back: Backend device
> > > > + *
> > > > + * Disabling DDR data is generated byt the IP at rising or falling front
> > > 
> > > Spell check your comments.
> > > 
> > > > + * of the interface clock signal (SDR, Single Data Rate).
> > > > + *
> > > > + * RETURNS:
> > > > + * 0 on success, negative error number on failure.
> > > > + */
> > > > +int iio_backend_ddr_disable(struct iio_backend *back)
> > > > +{
> > > > +	return iio_backend_op_call(back, ddr_disable);
> > > > +}
> > > > +EXPORT_SYMBOL_NS_GPL(iio_backend_ddr_disable, IIO_BACKEND);
> > > 				 struct fwnode_handle *fwnode)
> > > >  {
> > > > diff --git a/include/linux/iio/backend.h b/include/linux/iio/backend.h
> > > > index 37d56914d485..41619b803cd6 100644
> > > > --- a/include/linux/iio/backend.h
> > > > +++ b/include/linux/iio/backend.h
> > > > @@ -14,12 +14,14 @@ struct iio_dev;
> > > >  enum iio_backend_data_type {
> > > >  	IIO_BACKEND_TWOS_COMPLEMENT,
> > > >  	IIO_BACKEND_OFFSET_BINARY,
> > > > +	IIO_BACKEND_DATA_UNSIGNED,
> > > >  	IIO_BACKEND_DATA_TYPE_MAX
> > > >  };
> > > >  
> > > >  enum iio_backend_data_source {
> > > >  	IIO_BACKEND_INTERNAL_CONTINUOUS_WAVE,
> > > >  	IIO_BACKEND_EXTERNAL,
> > > > +	IIO_BACKEND_INTERNAL_RAMP_16BIT,
> > > >  	IIO_BACKEND_DATA_SOURCE_MAX
> > > >  };
> > > >  
> > > > @@ -89,6 +91,13 @@ enum iio_backend_sample_trigger {
> > > >   * @read_raw: Read a channel attribute from a backend device
> > > >   * @debugfs_print_chan_status: Print channel status into a buffer.
> > > >   * @debugfs_reg_access: Read or write register value of backend.
> > > > + * @ext_sync_enable: Enable external synchronization.
> > > > + * @ext_sync_disable: Disable external synchronization.
> > > > + * @ddr_enable: Enable interface DDR (Double Data Rate) mode.
> > > > + * @ddr_disable: Disable interface DDR (Double Data Rate) mode.
> > > > + * @buffer_enable: Enable data buffer.
> > > > + * @buffer_disable: Disable data buffer.
> > > 
> > > This needs more specific text. What buffer?  I think this came
> > > up earlier but it needs to say something about the fact it's enabling
> > > or disabling the actual capture of data into the DMA buffers that
> > > userspace will read.
> > > 
> > > > + * @data_transfer_addr: Set data address.
> > > >   **/
> > > >  struct iio_backend_ops {
> > > >  	int (*enable)(struct iio_backend *back);
> > > > @@ -129,6 +138,13 @@ struct iio_backend_ops {
> > > >  					 size_t len);
> > > >  	int (*debugfs_reg_access)(struct iio_backend *back, unsigned int
> > > > reg,
> > > >  				  unsigned int writeval, unsigned int
> > > > *readval);
> > > > +	int (*ext_sync_enable)(struct iio_backend *back);
> > > I know we've done it this way for existing items, but I wonder if we should
> > > squish down the ops slightly and have new enable/disable pairs as
> > > single functions.
> > > 	int (*ext_sync_set_state)(struct iio_backend *back, bool enable);
> > > etc.  If nothing else reduces how many things need documentation ;)
> > > 
> > > Nuno, what do you think? Worth squashing these pairs into single
> > > callbacks?
> > 
> > I'm not a fan of combining enable and disable functions into one function.
> > 
> > The implementation will pretty much always be:
> > 
> > if (enabled) {
> >         /* so stuff */
> > } else {
> >         /* do other stuff */
> > }
> > 
> > Which just adds indent and makes code harder to read.
> > 
> 
> Hi Jonathan and David,
> 
> Yeah, I have this on my todo list and to be fair with Angelo, he already had
> something like you're suggesting. I kind of asked him to postpone that so we
> don't have mixed styles in the file for now. Then I would convert them all. My
> plan would be to squash the .ops into one and then have inline
> enable()/disable() helpers (at least for the current users in order to keep
> things easier to convert).
> 
> As for David's comment, I see your point but one can always improve things a bit
> 
> if (enable) {
> 	/* do stuff */
> 	return;
> }
> 
> /* do disable stuff */
> return 0
> 
> I'm aware the above is always not that straight... but I do think there's always
> ways to rearrange things a bit to make it better. Because even with the
> enable()/disable() approach, if you start to have a lot of common code, likely
> you'll add an helper function. In some cases, one can even add the helper right
> away with an 'enable' argument effectively doing what is being suggested in
> here. It always depends on the person implementing the ops :)
> 
> Anyways, I really don't have a strong feeling about this. I had in my mind to do
> something like this. It feels that Jonathan would already be ok with it. If it's
> not that awful for David, I'll eventually send the patches (unless Angelo wants
> to take care if it in this series).
>

I agree a single function for enable/disable may be good, reducing the calls and
also the code size should benefit of some few bytes.

Honestly, i would not do this in this patchset since i am a bit in difficulties
to have this job accepted as is, and also cannot retest all of them properly
right now.
 
> - Nuno Sá
> > 

-- 
Regards,
  Angelo
       

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support
  2024-10-01  8:23                         ` Nuno Sá
@ 2024-10-01 18:29                           ` Jonathan Cameron
  2024-10-02  5:54                             ` Krzysztof Kozlowski
  2024-10-02  9:00                             ` Nuno Sá
  0 siblings, 2 replies; 59+ messages in thread
From: Jonathan Cameron @ 2024-10-01 18:29 UTC (permalink / raw)
  To: Nuno Sá
  Cc: Jonathan Cameron, Angelo Dureghello, Krzysztof Kozlowski,
	Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Olivier Moysan, linux-iio,
	linux-kernel, devicetree, dlechner

On Tue, 01 Oct 2024 10:23:45 +0200
Nuno Sá <noname.nuno@gmail.com> wrote:

> On Mon, 2024-09-30 at 16:09 +0100, Jonathan Cameron wrote:
> > On Mon, 30 Sep 2024 15:22:01 +0200
> > Angelo Dureghello <adureghello@baylibre.com> wrote:
> >   
> > > On 30.09.2024 09:20, Nuno Sá wrote:  
> > > > On Sun, 2024-09-29 at 11:59 +0100, Jonathan Cameron wrote:    
> > > > > On Sat, 28 Sep 2024 14:20:29 +0200
> > > > > Krzysztof Kozlowski <krzk@kernel.org> wrote:
> > > > >     
> > > > > > On 25/09/2024 13:55, Nuno Sá wrote:    
> > > > > > > On Wed, 2024-09-25 at 09:22 +0200, Krzysztof Kozlowski wrote:      
> > > > > > > > On 24/09/2024 14:27, Nuno Sá wrote:      
> > > > > > > > > On Tue, 2024-09-24 at 10:02 +0200, Krzysztof Kozlowski wrote:     
> > > > > > > > > > On 23/09/2024 17:50, Angelo Dureghello wrote:      
> > > > > > > > > > > Hi Krzysztof,
> > > > > > > > > > > 
> > > > > > > > > > > On 22/09/24 23:02, Krzysztof Kozlowski wrote:      
> > > > > > > > > > > > On Thu, Sep 19, 2024 at 11:20:00AM +0200, Angelo
> > > > > > > > > > > > Dureghello
> > > > > > > > > > > > wrote:      
> > > > > > > > > > > > > From: Angelo Dureghello <adureghello@baylibre.com>
> > > > > > > > > > > > > 
> > > > > > > > > > > > > There is a version AXI DAC IP block (for FPGAs) that
> > > > > > > > > > > > > provides
> > > > > > > > > > > > > a physical bus for AD3552R and similar chips, and acts
> > > > > > > > > > > > > as
> > > > > > > > > > > > > an SPI controller.
> > > > > > > > > > > > > 
> > > > > > > > > > > > > For this case, the binding is modified to include some
> > > > > > > > > > > > > additional properties.
> > > > > > > > > > > > > 
> > > > > > > > > > > > > Signed-off-by: Angelo Dureghello
> > > > > > > > > > > > > <adureghello@baylibre.com>
> > > > > > > > > > > > > ---
> > > > > > > > > > > > >   .../devicetree/bindings/iio/dac/adi,ad3552r.yaml   |
> > > > > > > > > > > > > 42
> > > > > > > > > > > > > ++++++++++++++++++++++
> > > > > > > > > > > > >   1 file changed, 42 insertions(+)
> > > > > > > > > > > > > 
> > > > > > > > > > > > > diff --git
> > > > > > > > > > > > > a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.
> > > > > > > > > > > > > yaml
> > > > > > > > > > > > > b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.
> > > > > > > > > > > > > yaml
> > > > > > > > > > > > > index 41fe00034742..aca4a41c2633 100644
> > > > > > > > > > > > > ---
> > > > > > > > > > > > > a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.
> > > > > > > > > > > > > yaml
> > > > > > > > > > > > > +++
> > > > > > > > > > > > > b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.
> > > > > > > > > > > > > yaml
> > > > > > > > > > > > > @@ -60,6 +60,18 @@ properties:
> > > > > > > > > > > > >       $ref: /schemas/types.yaml#/definitions/uint32
> > > > > > > > > > > > >       enum: [0, 1, 2, 3]
> > > > > > > > > > > > >   
> > > > > > > > > > > > > +  io-backends:
> > > > > > > > > > > > > +    description: The iio backend reference.
> > > > > > > > > > > > > +      An example backend can be found at
> > > > > > > > > > > > > +       
> > > > > > > > > > > > > https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
> > > > > > > > > > > > > +    maxItems: 1
> > > > > > > > > > > > > +
> > > > > > > > > > > > > +  adi,synchronous-mode:
> > > > > > > > > > > > > +    description: Enable waiting for external
> > > > > > > > > > > > > synchronization
> > > > > > > > > > > > > signal.
> > > > > > > > > > > > > +      Some AXI IP configuration can implement a dual-IP
> > > > > > > > > > > > > layout,
> > > > > > > > > > > > > with
> > > > > > > > > > > > > internal
> > > > > > > > > > > > > +      wirings for streaming synchronization.
> > > > > > > > > > > > > +    type: boolean
> > > > > > > > > > > > > +
> > > > > > > > > > > > >     '#address-cells':
> > > > > > > > > > > > >       const: 1
> > > > > > > > > > > > >   
> > > > > > > > > > > > > @@ -128,6 +140,7 @@ patternProperties:
> > > > > > > > > > > > >             - custom-output-range-config
> > > > > > > > > > > > >   
> > > > > > > > > > > > >   allOf:
> > > > > > > > > > > > > +  - $ref: /schemas/spi/spi-peripheral-props.yaml#
> > > > > > > > > > > > >     - if:
> > > > > > > > > > > > >         properties:
> > > > > > > > > > > > >           compatible:
> > > > > > > > > > > > > @@ -238,4 +251,33 @@ examples:
> > > > > > > > > > > > >               };
> > > > > > > > > > > > >           };
> > > > > > > > > > > > >       };
> > > > > > > > > > > > > +
> > > > > > > > > > > > > +  - |
> > > > > > > > > > > > > +    axi_dac: spi@44a70000 {
> > > > > > > > > > > > > +        compatible = "adi,axi-ad3552r";      
> > > > > > > > > > > > That is either redundant or entire example should go to
> > > > > > > > > > > > the
> > > > > > > > > > > > parent
> > > > > > > > > > > > node,
> > > > > > > > > > > > if this device is fixed child of complex device (IOW,
> > > > > > > > > > > > adi,ad3552r
> > > > > > > > > > > > cannot
> > > > > > > > > > > > be used outside of adi,axi-ad3552r).      
> > > > > > > > > > > 
> > > > > > > > > > > ad3552r can still be used by a generic "classic" spi
> > > > > > > > > > > controller (SCLK/CS/MISO) but at a slower samplerate, fpga
> > > > > > > > > > > controller only (axi-ad3552r) can reach 33MUPS.      
> > > > > > > > > > 
> > > > > > > > > > OK, then this is just redundant. Drop the node. Parent example
> > > > > > > > > > should
> > > > > > > > > > contain the children, though.      
> > > > > > > > > > >      
> > > > > > > > > > > >      
> > > > > > > > > > > > > +        reg = <0x44a70000 0x1000>;
> > > > > > > > > > > > > +        dmas = <&dac_tx_dma 0>;
> > > > > > > > > > > > > +        dma-names = "tx";
> > > > > > > > > > > > > +        #io-backend-cells = <0>;
> > > > > > > > > > > > > +        clocks = <&ref_clk>;
> > > > > > > > > > > > > +
> > > > > > > > > > > > > +        #address-cells = <1>;
> > > > > > > > > > > > > +        #size-cells = <0>;
> > > > > > > > > > > > > +
> > > > > > > > > > > > > +        dac@0 {
> > > > > > > > > > > > > +            compatible = "adi,ad3552r";
> > > > > > > > > > > > > +            reg = <0>;
> > > > > > > > > > > > > +            reset-gpios = <&gpio0 92 0>;      
> > > > > > > > > > > > Use standard defines for GPIO flags.      
> > > > > > > > > > > 
> > > > > > > > > > > fixed, thanks
> > > > > > > > > > >      
> > > > > > > > > > > > > +            io-backends = <&axi_dac>;      
> > > > > > > > > > > > Why do you need to point to the parent? How much coupled
> > > > > > > > > > > > are
> > > > > > > > > > > > these
> > > > > > > > > > > > devices? Child pointing to parent is not usually expected,
> > > > > > > > > > > > because
> > > > > > > > > > > > that's obvious.      
> > > > > > > > > > > 
> > > > > > > > > > > 
> > > > > > > > > > > "io-backends" is actually the way to refer to the backend
> > > > > > > > > > > module,
> > > > > > > > > > > (used already for i.e. ad9739a),
> > > > > > > > > > > it is needed because the backend is not only acting as spi-
> > > > > > > > > > > controller,
> > > > > > > > > > > but is also providing some APIs for synchronization and bus
> > > > > > > > > > > setup
> > > > > > > > > > > support.      
> > > > > > > > > > 
> > > > > > > > > > 
> > > > > > > > > > But if backend is the parent, then this is redundant. You can
> > > > > > > > > > take
> > > > > > > > > > it
> > > > > > > > > > from the child-parent relationship. Is this pointing to other
> > > > > > > > > > devices
> > > > > > > > > > (non-parent) in other ad3552r configurations?
> > > > > > > > > >      
> > > > > > > > > 
> > > > > > > > > The backend is a provider-consumer type of API. On the consumer
> > > > > > > > > side
> > > > > > > > > (which
> > > > > > > > > is the
> > > > > > > > > driver the child node will probe on), we need to call
> > > > > > > > > devm_iio_backend_get()
> > > > > > > > > to get
> > > > > > > > > the backend object (which obviously is the parent). For that,
> > > > > > > > > 'io-
> > > > > > > > > backends'
> > > > > > > > > is being      
> > > > > > > > 
> > > > > > > > You described the driver, so how does it matter? Driver can call
> > > > > > > > get_backend_from_parent(), right? Or
> > > > > > > > get_backend_from_fwnode(parent)?      
> > > > > > > 
> > > > > > > Well yes, just stating what the framework (also in terms of
> > > > > > > bindings) is
> > > > > > > expecting. Of course that on the driver side we can paper around it
> > > > > > > the
> > > > > > > way we
> > > > > > > want. But my main point was that we can only paper around it if we
> > > > > > > use
> > > > > > > code that
> > > > > > > is meant not to be used.
> > > > > > > 
> > > > > > > And, FWIW, I was (trying) replying to your comment
> > > > > > > 
> > > > > > > "You can take it from the child-parent relationship"
> > > > > > > 
> > > > > > > Again, we can only do that by introducing new code or use code
> > > > > > > that's not
> > > > > > > meant
> > > > > > > to be used. The way we're supposed to reference backends is by
> > > > > > > explicitly
> > > > > > > using
> > > > > > > the proper FW property.
> > > > > > > 
> > > > > > > Put it in another way and a completely hypothetical case. If we have
> > > > > > > a spi
> > > > > > > controller which happens to export some clock and one of it's
> > > > > > > peripherals
> > > > > > > ends
> > > > > > > up using that clock, wouldn't we still use 'clocks' to reference
> > > > > > > that
> > > > > > > clock?      
> > > > > > 
> > > > > > I asked how coupled are these devices. Never got the answer and you
> > > > > > are
> > > > > > reflecting with question. Depends. Please do not create hypothetical,
> > > > > > generic scenarios and then apply them to your one particular opposite
> > > > > > case.    
> > > > > 
> > > > > I'll throw a possible clarifying question in here.  Could we use this
> > > > > device with a multimaster SPI setup such that the control is on a
> > > > > conventional
> > > > > SPI controller (maybe a qspi capable one), and the data plane only goes
> > > > > through
> > > > > a specific purpose backend?  If so, then they are not tightly coupled
> > > > > and
> > > > > the reference makes sense.  Putting it another way, the difference
> > > > > between
> > > > > this case and all the prior iio-backend bindings is the control and
> > > > > dataplanes
> > > > > use the same pins.  Does that have to be the case at the host end?  If
> > > > > it
> > > > > does,
> > > > > then the reference isn't strictly needed and this becomes a bit like
> > > > > registering a single device on an spi bus or an i2c bus depending on who
> > > > > does the registering (which is down to the parent in DT).
> > > > >     
> > > > 
> > > > So, we currently have two drivers (with a new one being added in this
> > > > series)
> > > > for the same device:
> > > > 
> > > > 1) A SPI one tied to a typical spi controller. This is the "low speed"
> > > > implementation and does not use backends;
> > > > 2) The new platform device that is connected like this to the backend.
> > > > 
> > > > So yes, my understanding (but Angelo should know better :)) is that they
> > > > are
> > > > tightly coupled. Putting it in another way, the new platform device is
> > > > very much
> > > > specific to this parent (and yeah, this is a very special usecase where
> > > > control
> > > > and data planes are controlled by the IIO backend) and should not exist
> > > > with it.    
> > > 
> > > ad3552r device can be coupled to the axi-ad3552r controller or to a generic 
> > > spi controler.
> > > 
> > > We have actually 2 drivers, SPI and platform (for AXI controller, in this
> > > patch).
> > > 
> > > Scenario 1 (SPI):
> > > ad3522r can hypotetically work with whatever simple spi controller that can
> > > read/write registers in raw mode. On simple SPI (CS, SCLK, MOSI), due to
> > > ad3552r
> > > chip limitation of 66Mhz clock, the maximum 33MUPS (16 bit samples) cannot
> > > be
> > > reached. Some QSPI DDR controller seems to be around, in that case, ad3552r
> > > may work extending the SPI driver. 
> > > 
> > > Scenario 2 (AXI):
> > > From an hardware-only point ov view axi-ad3552r IP acts as QSPI+DDR
> > > controller
> > > plus some additional features for stream synchronization.
> > > From a sowftware point of view, really different from a spi controller
> > > driver.
> > > It's just a backend with APIes that can be called from the child driver.  
> > 
> > Potential? scenario 3 is the one that interested me.
> > 
> > ad3552 double wired to a normal SPI controller (so like option 1) and
> > to a an offload engine (so like option 2).  With a few pull up resistors
> > (cs and clk?) and some care it should electrically work I think.
> > In that case we'd need the io-backend reference because the parent
> > would be the option 1 like SPI bus and the io-backend would not be
> > the parent.
> > 
> > _______________________
> > Host       SPI MOSI    |-------------------\
> > hard       SPI MISO 0-3|----------------\  |
> > QSPI       SPI CLK     |--------------\  | |
> >            SPI CS      |----------\    | | |
> >                        |           |   | | |
> > FPGA                   |           |   | | |   |
> > Soft       SPI MOSI    |-----------|---|-|-x---|
> > QSPI       SPI MISO 0-3|-----------|---|-x-----|  DAC
> > Offload    SPI CLK     |-----------|---x-------|
> > with DDR   SPI CS      |-----------x-----------|
> > _______________________|
> > 
> > Makes all sorts of assumptions about the SPI controllers being designed
> > for multi controllers on the same SPI buses but I'm not aware of a reason
> > you can't do that.
> > 
> > As the only control message that would need to go over the offload engine
> > would be the exit DDR (I think) that might be hard coded into a slightly
> > simpler soft IP along with the bulk data transfer stuff.
> >   
> 
> Not even sure if DDR would be a problem. Right now, I __think__ we need to
> enable DDR both the peripheral and on the backend. On the peripheral we could
> use the control link on the non offload controller. On the offload controller,
> we would set it through IIO backend and that would be a backend config and not
> go over the bus.

It's the path back to SDR that I wasn't sure about as it might need a
DDR register write?

> 
> To make a correction on my previous reply to Krzysztof, the HW folks made some
> experiments with the SPI ENIGINE IP (with the offload engine) but without the
> AXI DAC IP. So, effectively only one controller in place. That said, I'm also
> not seeing any reason why something like the above would not be possible.

Conclusion / summary for Krzystoff and other DT binding
folk. It's possible to use this with another backend (which no one has
written the IP for yet) so I (at least) think the reference is needed
even though the only one we have right now is also the parent.

Driver wise, we could in theory poke the parent if the property isn't there
on the off chance it is a suitable backend, but we can't assume that's
the one in use even if it has some suitable support.  Maybe there
is a more capable one double wired?

So I'd like to keep the io-backend phandle there.

Jonathan


> 
> - Nuno Sá
> 


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 05/10] iio: backend: extend features
  2024-10-01  8:35         ` Angelo Dureghello
@ 2024-10-01 18:32           ` Jonathan Cameron
  0 siblings, 0 replies; 59+ messages in thread
From: Jonathan Cameron @ 2024-10-01 18:32 UTC (permalink / raw)
  To: Angelo Dureghello
  Cc: Nuno Sá, David Lechner, Lars-Peter Clausen,
	Michael Hennerich, Nuno Sa, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Olivier Moysan, linux-iio, linux-kernel, devicetree

On Tue, 1 Oct 2024 10:35:17 +0200
Angelo Dureghello <adureghello@baylibre.com> wrote:

> On 01.10.2024 10:14, Nuno Sá wrote:
> > On Mon, 2024-09-30 at 14:25 -0500, David Lechner wrote:  
> > > On 9/29/24 6:05 AM, Jonathan Cameron wrote:  
> > > > On Thu, 19 Sep 2024 11:20:01 +0200
> > > > Angelo Dureghello <adureghello@baylibre.com> wrote:
> > > >   
> > > > > From: Angelo Dureghello <adureghello@baylibre.com>
> > > > > 
> > > > > Extend backend features with new calls needed later on this
> > > > > patchset from axi version of ad3552r.
> > > > > 
> > > > > The follwoing calls are added:
> > > > > 
> > > > > iio_backend_ext_sync_enable
> > > > > 	enable synchronize channels on external trigger
> > > > > iio_backend_ext_sync_disable
> > > > > 	disable synchronize channels on external trigger
> > > > > iio_backend_ddr_enable
> > > > > 	enable ddr bus transfer
> > > > > iio_backend_ddr_disable
> > > > > 	disable ddr bus transfer
> > > > > iio_backend_set_bus_mode
> > > > > 	select the type of bus, so that specific read / write
> > > > > 	operations are performed accordingly
> > > > > iio_backend_buffer_enable
> > > > > 	enable buffer
> > > > > iio_backend_buffer_disable
> > > > > 	disable buffer
> > > > > iio_backend_data_transfer_addr
> > > > > 	define the target register address where the DAC sample
> > > > > 	will be written.
> > > > > 
> > > > > Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>  
> > > > Hi Angelo,
> > > > A few trivial comments inline.
> > > >   
> > > > > ---
> > > > >  drivers/iio/industrialio-backend.c | 111
> > > > > +++++++++++++++++++++++++++++++++++++
> > > > >  include/linux/iio/backend.h        |  23 ++++++++
> > > > >  2 files changed, 134 insertions(+)
> > > > > 
> > > > > diff --git a/drivers/iio/industrialio-backend.c
> > > > > b/drivers/iio/industrialio-backend.c
> > > > > index 20b3b5212da7..f4802c422dbf 100644
> > > > > --- a/drivers/iio/industrialio-backend.c
> > > > > +++ b/drivers/iio/industrialio-backend.c
> > > > > @@ -718,6 +718,117 @@ static int __devm_iio_backend_get(struct device
> > > > > *dev, struct iio_backend *back)  
> > > > ...
> > > >   
> > > > > +/**
> > > > > + * iio_backend_ddr_disable - Disable interface DDR (Double Data Rate)
> > > > > mode
> > > > > + * @back: Backend device
> > > > > + *
> > > > > + * Disabling DDR data is generated byt the IP at rising or falling front  
> > > > 
> > > > Spell check your comments.
> > > >   
> > > > > + * of the interface clock signal (SDR, Single Data Rate).
> > > > > + *
> > > > > + * RETURNS:
> > > > > + * 0 on success, negative error number on failure.
> > > > > + */
> > > > > +int iio_backend_ddr_disable(struct iio_backend *back)
> > > > > +{
> > > > > +	return iio_backend_op_call(back, ddr_disable);
> > > > > +}
> > > > > +EXPORT_SYMBOL_NS_GPL(iio_backend_ddr_disable, IIO_BACKEND);  
> > > > 				 struct fwnode_handle *fwnode)  
> > > > >  {
> > > > > diff --git a/include/linux/iio/backend.h b/include/linux/iio/backend.h
> > > > > index 37d56914d485..41619b803cd6 100644
> > > > > --- a/include/linux/iio/backend.h
> > > > > +++ b/include/linux/iio/backend.h
> > > > > @@ -14,12 +14,14 @@ struct iio_dev;
> > > > >  enum iio_backend_data_type {
> > > > >  	IIO_BACKEND_TWOS_COMPLEMENT,
> > > > >  	IIO_BACKEND_OFFSET_BINARY,
> > > > > +	IIO_BACKEND_DATA_UNSIGNED,
> > > > >  	IIO_BACKEND_DATA_TYPE_MAX
> > > > >  };
> > > > >  
> > > > >  enum iio_backend_data_source {
> > > > >  	IIO_BACKEND_INTERNAL_CONTINUOUS_WAVE,
> > > > >  	IIO_BACKEND_EXTERNAL,
> > > > > +	IIO_BACKEND_INTERNAL_RAMP_16BIT,
> > > > >  	IIO_BACKEND_DATA_SOURCE_MAX
> > > > >  };
> > > > >  
> > > > > @@ -89,6 +91,13 @@ enum iio_backend_sample_trigger {
> > > > >   * @read_raw: Read a channel attribute from a backend device
> > > > >   * @debugfs_print_chan_status: Print channel status into a buffer.
> > > > >   * @debugfs_reg_access: Read or write register value of backend.
> > > > > + * @ext_sync_enable: Enable external synchronization.
> > > > > + * @ext_sync_disable: Disable external synchronization.
> > > > > + * @ddr_enable: Enable interface DDR (Double Data Rate) mode.
> > > > > + * @ddr_disable: Disable interface DDR (Double Data Rate) mode.
> > > > > + * @buffer_enable: Enable data buffer.
> > > > > + * @buffer_disable: Disable data buffer.  
> > > > 
> > > > This needs more specific text. What buffer?  I think this came
> > > > up earlier but it needs to say something about the fact it's enabling
> > > > or disabling the actual capture of data into the DMA buffers that
> > > > userspace will read.
> > > >   
> > > > > + * @data_transfer_addr: Set data address.
> > > > >   **/
> > > > >  struct iio_backend_ops {
> > > > >  	int (*enable)(struct iio_backend *back);
> > > > > @@ -129,6 +138,13 @@ struct iio_backend_ops {
> > > > >  					 size_t len);
> > > > >  	int (*debugfs_reg_access)(struct iio_backend *back, unsigned int
> > > > > reg,
> > > > >  				  unsigned int writeval, unsigned int
> > > > > *readval);
> > > > > +	int (*ext_sync_enable)(struct iio_backend *back);  
> > > > I know we've done it this way for existing items, but I wonder if we should
> > > > squish down the ops slightly and have new enable/disable pairs as
> > > > single functions.
> > > > 	int (*ext_sync_set_state)(struct iio_backend *back, bool enable);
> > > > etc.  If nothing else reduces how many things need documentation ;)
> > > > 
> > > > Nuno, what do you think? Worth squashing these pairs into single
> > > > callbacks?  
> > > 
> > > I'm not a fan of combining enable and disable functions into one function.
> > > 
> > > The implementation will pretty much always be:
> > > 
> > > if (enabled) {
> > >         /* so stuff */
> > > } else {
> > >         /* do other stuff */
> > > }
> > > 
> > > Which just adds indent and makes code harder to read.
> > >   
> > 
> > Hi Jonathan and David,
> > 
> > Yeah, I have this on my todo list and to be fair with Angelo, he already had
> > something like you're suggesting. I kind of asked him to postpone that so we
> > don't have mixed styles in the file for now. Then I would convert them all. My
> > plan would be to squash the .ops into one and then have inline
> > enable()/disable() helpers (at least for the current users in order to keep
> > things easier to convert).
> > 
> > As for David's comment, I see your point but one can always improve things a bit
> > 
> > if (enable) {
> > 	/* do stuff */
> > 	return;
> > }
> > 
> > /* do disable stuff */
> > return 0
> > 
> > I'm aware the above is always not that straight... but I do think there's always
> > ways to rearrange things a bit to make it better. Because even with the
> > enable()/disable() approach, if you start to have a lot of common code, likely
> > you'll add an helper function. In some cases, one can even add the helper right
> > away with an 'enable' argument effectively doing what is being suggested in
> > here. It always depends on the person implementing the ops :)
> > 
> > Anyways, I really don't have a strong feeling about this. I had in my mind to do
> > something like this. It feels that Jonathan would already be ok with it. If it's
> > not that awful for David, I'll eventually send the patches (unless Angelo wants
> > to take care if it in this series).
> >  
> 
> I agree a single function for enable/disable may be good, reducing the calls and
> also the code size should benefit of some few bytes.

Normally I'd be on David's side on this but I don't really want to end up
with hundreds of callbacks (vs a single hundred). Thinking more about it, maybe
I don't care about keeping them split.

> 
> Honestly, i would not do this in this patchset since i am a bit in difficulties
> to have this job accepted as is, and also cannot retest all of them properly
> right now.

That's fine given it's an open question on whether it is even a good idea
and not really related to your work here.

Jonathan

>  
> > - Nuno Sá  
> > >   
> 


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support
  2024-10-01 18:29                           ` Jonathan Cameron
@ 2024-10-02  5:54                             ` Krzysztof Kozlowski
  2024-10-02  9:00                             ` Nuno Sá
  1 sibling, 0 replies; 59+ messages in thread
From: Krzysztof Kozlowski @ 2024-10-02  5:54 UTC (permalink / raw)
  To: Jonathan Cameron, Nuno Sá
  Cc: Jonathan Cameron, Angelo Dureghello, Lars-Peter Clausen,
	Michael Hennerich, Nuno Sa, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Olivier Moysan, linux-iio, linux-kernel, devicetree,
	dlechner

On 01/10/2024 20:29, Jonathan Cameron wrote:
>>>
>>> Makes all sorts of assumptions about the SPI controllers being designed
>>> for multi controllers on the same SPI buses but I'm not aware of a reason
>>> you can't do that.
>>>
>>> As the only control message that would need to go over the offload engine
>>> would be the exit DDR (I think) that might be hard coded into a slightly
>>> simpler soft IP along with the bulk data transfer stuff.
>>>   
>>
>> Not even sure if DDR would be a problem. Right now, I __think__ we need to
>> enable DDR both the peripheral and on the backend. On the peripheral we could
>> use the control link on the non offload controller. On the offload controller,
>> we would set it through IIO backend and that would be a backend config and not
>> go over the bus.
> 
> It's the path back to SDR that I wasn't sure about as it might need a
> DDR register write?
> 
>>
>> To make a correction on my previous reply to Krzysztof, the HW folks made some
>> experiments with the SPI ENIGINE IP (with the offload engine) but without the
>> AXI DAC IP. So, effectively only one controller in place. That said, I'm also
>> not seeing any reason why something like the above would not be possible.
> 
> Conclusion / summary for Krzystoff and other DT binding
> folk. It's possible to use this with another backend (which no one has
> written the IP for yet) so I (at least) think the reference is needed
> even though the only one we have right now is also the parent.
> 
> Driver wise, we could in theory poke the parent if the property isn't there
> on the off chance it is a suitable backend, but we can't assume that's
> the one in use even if it has some suitable support.  Maybe there
> is a more capable one double wired?
> 
> So I'd like to keep the io-backend phandle there.

Ack.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support
  2024-10-01 18:29                           ` Jonathan Cameron
  2024-10-02  5:54                             ` Krzysztof Kozlowski
@ 2024-10-02  9:00                             ` Nuno Sá
  1 sibling, 0 replies; 59+ messages in thread
From: Nuno Sá @ 2024-10-02  9:00 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Jonathan Cameron, Angelo Dureghello, Krzysztof Kozlowski,
	Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Olivier Moysan, linux-iio,
	linux-kernel, devicetree, dlechner

On Tue, 2024-10-01 at 19:29 +0100, Jonathan Cameron wrote:
> On Tue, 01 Oct 2024 10:23:45 +0200
> Nuno Sá <noname.nuno@gmail.com> wrote:
> 
> > On Mon, 2024-09-30 at 16:09 +0100, Jonathan Cameron wrote:
> > > On Mon, 30 Sep 2024 15:22:01 +0200
> > > Angelo Dureghello <adureghello@baylibre.com> wrote:
> > >   
> > > > On 30.09.2024 09:20, Nuno Sá wrote:  
> > > > > On Sun, 2024-09-29 at 11:59 +0100, Jonathan Cameron wrote:    
> > > > > > On Sat, 28 Sep 2024 14:20:29 +0200
> > > > > > Krzysztof Kozlowski <krzk@kernel.org> wrote:
> > > > > >     
> > > > > > > On 25/09/2024 13:55, Nuno Sá wrote:    
> > > > > > > > On Wed, 2024-09-25 at 09:22 +0200, Krzysztof Kozlowski wrote:      
> > > > > > > > > On 24/09/2024 14:27, Nuno Sá wrote:      
> > > > > > > > > > On Tue, 2024-09-24 at 10:02 +0200, Krzysztof Kozlowski wrote:    
> > > > > > > > > > > On 23/09/2024 17:50, Angelo Dureghello wrote:      
> > > > > > > > > > > > Hi Krzysztof,
> > > > > > > > > > > > 
> > > > > > > > > > > > On 22/09/24 23:02, Krzysztof Kozlowski wrote:      
> > > > > > > > > > > > > On Thu, Sep 19, 2024 at 11:20:00AM +0200, Angelo
> > > > > > > > > > > > > Dureghello
> > > > > > > > > > > > > wrote:      
> > > > > > > > > > > > > > From: Angelo Dureghello <adureghello@baylibre.com>
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > There is a version AXI DAC IP block (for FPGAs) that
> > > > > > > > > > > > > > provides
> > > > > > > > > > > > > > a physical bus for AD3552R and similar chips, and acts
> > > > > > > > > > > > > > as
> > > > > > > > > > > > > > an SPI controller.
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > For this case, the binding is modified to include some
> > > > > > > > > > > > > > additional properties.
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > Signed-off-by: Angelo Dureghello
> > > > > > > > > > > > > > <adureghello@baylibre.com>
> > > > > > > > > > > > > > ---
> > > > > > > > > > > > > >   .../devicetree/bindings/iio/dac/adi,ad3552r.yaml   |
> > > > > > > > > > > > > > 42
> > > > > > > > > > > > > > ++++++++++++++++++++++
> > > > > > > > > > > > > >   1 file changed, 42 insertions(+)
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > diff --git
> > > > > > > > > > > > > > a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.
> > > > > > > > > > > > > > yaml
> > > > > > > > > > > > > > b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.
> > > > > > > > > > > > > > yaml
> > > > > > > > > > > > > > index 41fe00034742..aca4a41c2633 100644
> > > > > > > > > > > > > > ---
> > > > > > > > > > > > > > a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.
> > > > > > > > > > > > > > yaml
> > > > > > > > > > > > > > +++
> > > > > > > > > > > > > > b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.
> > > > > > > > > > > > > > yaml
> > > > > > > > > > > > > > @@ -60,6 +60,18 @@ properties:
> > > > > > > > > > > > > >       $ref: /schemas/types.yaml#/definitions/uint32
> > > > > > > > > > > > > >       enum: [0, 1, 2, 3]
> > > > > > > > > > > > > >   
> > > > > > > > > > > > > > +  io-backends:
> > > > > > > > > > > > > > +    description: The iio backend reference.
> > > > > > > > > > > > > > +      An example backend can be found at
> > > > > > > > > > > > > > +       
> > > > > > > > > > > > > > https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
> > > > > > > > > > > > > > +    maxItems: 1
> > > > > > > > > > > > > > +
> > > > > > > > > > > > > > +  adi,synchronous-mode:
> > > > > > > > > > > > > > +    description: Enable waiting for external
> > > > > > > > > > > > > > synchronization
> > > > > > > > > > > > > > signal.
> > > > > > > > > > > > > > +      Some AXI IP configuration can implement a dual-IP
> > > > > > > > > > > > > > layout,
> > > > > > > > > > > > > > with
> > > > > > > > > > > > > > internal
> > > > > > > > > > > > > > +      wirings for streaming synchronization.
> > > > > > > > > > > > > > +    type: boolean
> > > > > > > > > > > > > > +
> > > > > > > > > > > > > >     '#address-cells':
> > > > > > > > > > > > > >       const: 1
> > > > > > > > > > > > > >   
> > > > > > > > > > > > > > @@ -128,6 +140,7 @@ patternProperties:
> > > > > > > > > > > > > >             - custom-output-range-config
> > > > > > > > > > > > > >   
> > > > > > > > > > > > > >   allOf:
> > > > > > > > > > > > > > +  - $ref: /schemas/spi/spi-peripheral-props.yaml#
> > > > > > > > > > > > > >     - if:
> > > > > > > > > > > > > >         properties:
> > > > > > > > > > > > > >           compatible:
> > > > > > > > > > > > > > @@ -238,4 +251,33 @@ examples:
> > > > > > > > > > > > > >               };
> > > > > > > > > > > > > >           };
> > > > > > > > > > > > > >       };
> > > > > > > > > > > > > > +
> > > > > > > > > > > > > > +  - |
> > > > > > > > > > > > > > +    axi_dac: spi@44a70000 {
> > > > > > > > > > > > > > +        compatible = "adi,axi-ad3552r";      
> > > > > > > > > > > > > That is either redundant or entire example should go to
> > > > > > > > > > > > > the
> > > > > > > > > > > > > parent
> > > > > > > > > > > > > node,
> > > > > > > > > > > > > if this device is fixed child of complex device (IOW,
> > > > > > > > > > > > > adi,ad3552r
> > > > > > > > > > > > > cannot
> > > > > > > > > > > > > be used outside of adi,axi-ad3552r).      
> > > > > > > > > > > > 
> > > > > > > > > > > > ad3552r can still be used by a generic "classic" spi
> > > > > > > > > > > > controller (SCLK/CS/MISO) but at a slower samplerate, fpga
> > > > > > > > > > > > controller only (axi-ad3552r) can reach 33MUPS.      
> > > > > > > > > > > 
> > > > > > > > > > > OK, then this is just redundant. Drop the node. Parent example
> > > > > > > > > > > should
> > > > > > > > > > > contain the children, though.      
> > > > > > > > > > > >      
> > > > > > > > > > > > >      
> > > > > > > > > > > > > > +        reg = <0x44a70000 0x1000>;
> > > > > > > > > > > > > > +        dmas = <&dac_tx_dma 0>;
> > > > > > > > > > > > > > +        dma-names = "tx";
> > > > > > > > > > > > > > +        #io-backend-cells = <0>;
> > > > > > > > > > > > > > +        clocks = <&ref_clk>;
> > > > > > > > > > > > > > +
> > > > > > > > > > > > > > +        #address-cells = <1>;
> > > > > > > > > > > > > > +        #size-cells = <0>;
> > > > > > > > > > > > > > +
> > > > > > > > > > > > > > +        dac@0 {
> > > > > > > > > > > > > > +            compatible = "adi,ad3552r";
> > > > > > > > > > > > > > +            reg = <0>;
> > > > > > > > > > > > > > +            reset-gpios = <&gpio0 92 0>;      
> > > > > > > > > > > > > Use standard defines for GPIO flags.      
> > > > > > > > > > > > 
> > > > > > > > > > > > fixed, thanks
> > > > > > > > > > > >      
> > > > > > > > > > > > > > +            io-backends = <&axi_dac>;      
> > > > > > > > > > > > > Why do you need to point to the parent? How much coupled
> > > > > > > > > > > > > are
> > > > > > > > > > > > > these
> > > > > > > > > > > > > devices? Child pointing to parent is not usually expected,
> > > > > > > > > > > > > because
> > > > > > > > > > > > > that's obvious.      
> > > > > > > > > > > > 
> > > > > > > > > > > > 
> > > > > > > > > > > > "io-backends" is actually the way to refer to the backend
> > > > > > > > > > > > module,
> > > > > > > > > > > > (used already for i.e. ad9739a),
> > > > > > > > > > > > it is needed because the backend is not only acting as spi-
> > > > > > > > > > > > controller,
> > > > > > > > > > > > but is also providing some APIs for synchronization and bus
> > > > > > > > > > > > setup
> > > > > > > > > > > > support.      
> > > > > > > > > > > 
> > > > > > > > > > > 
> > > > > > > > > > > But if backend is the parent, then this is redundant. You can
> > > > > > > > > > > take
> > > > > > > > > > > it
> > > > > > > > > > > from the child-parent relationship. Is this pointing to other
> > > > > > > > > > > devices
> > > > > > > > > > > (non-parent) in other ad3552r configurations?
> > > > > > > > > > >      
> > > > > > > > > > 
> > > > > > > > > > The backend is a provider-consumer type of API. On the consumer
> > > > > > > > > > side
> > > > > > > > > > (which
> > > > > > > > > > is the
> > > > > > > > > > driver the child node will probe on), we need to call
> > > > > > > > > > devm_iio_backend_get()
> > > > > > > > > > to get
> > > > > > > > > > the backend object (which obviously is the parent). For that,
> > > > > > > > > > 'io-
> > > > > > > > > > backends'
> > > > > > > > > > is being      
> > > > > > > > > 
> > > > > > > > > You described the driver, so how does it matter? Driver can call
> > > > > > > > > get_backend_from_parent(), right? Or
> > > > > > > > > get_backend_from_fwnode(parent)?      
> > > > > > > > 
> > > > > > > > Well yes, just stating what the framework (also in terms of
> > > > > > > > bindings) is
> > > > > > > > expecting. Of course that on the driver side we can paper around it
> > > > > > > > the
> > > > > > > > way we
> > > > > > > > want. But my main point was that we can only paper around it if we
> > > > > > > > use
> > > > > > > > code that
> > > > > > > > is meant not to be used.
> > > > > > > > 
> > > > > > > > And, FWIW, I was (trying) replying to your comment
> > > > > > > > 
> > > > > > > > "You can take it from the child-parent relationship"
> > > > > > > > 
> > > > > > > > Again, we can only do that by introducing new code or use code
> > > > > > > > that's not
> > > > > > > > meant
> > > > > > > > to be used. The way we're supposed to reference backends is by
> > > > > > > > explicitly
> > > > > > > > using
> > > > > > > > the proper FW property.
> > > > > > > > 
> > > > > > > > Put it in another way and a completely hypothetical case. If we have
> > > > > > > > a spi
> > > > > > > > controller which happens to export some clock and one of it's
> > > > > > > > peripherals
> > > > > > > > ends
> > > > > > > > up using that clock, wouldn't we still use 'clocks' to reference
> > > > > > > > that
> > > > > > > > clock?      
> > > > > > > 
> > > > > > > I asked how coupled are these devices. Never got the answer and you
> > > > > > > are
> > > > > > > reflecting with question. Depends. Please do not create hypothetical,
> > > > > > > generic scenarios and then apply them to your one particular opposite
> > > > > > > case.    
> > > > > > 
> > > > > > I'll throw a possible clarifying question in here.  Could we use this
> > > > > > device with a multimaster SPI setup such that the control is on a
> > > > > > conventional
> > > > > > SPI controller (maybe a qspi capable one), and the data plane only goes
> > > > > > through
> > > > > > a specific purpose backend?  If so, then they are not tightly coupled
> > > > > > and
> > > > > > the reference makes sense.  Putting it another way, the difference
> > > > > > between
> > > > > > this case and all the prior iio-backend bindings is the control and
> > > > > > dataplanes
> > > > > > use the same pins.  Does that have to be the case at the host end?  If
> > > > > > it
> > > > > > does,
> > > > > > then the reference isn't strictly needed and this becomes a bit like
> > > > > > registering a single device on an spi bus or an i2c bus depending on who
> > > > > > does the registering (which is down to the parent in DT).
> > > > > >     
> > > > > 
> > > > > So, we currently have two drivers (with a new one being added in this
> > > > > series)
> > > > > for the same device:
> > > > > 
> > > > > 1) A SPI one tied to a typical spi controller. This is the "low speed"
> > > > > implementation and does not use backends;
> > > > > 2) The new platform device that is connected like this to the backend.
> > > > > 
> > > > > So yes, my understanding (but Angelo should know better :)) is that they
> > > > > are
> > > > > tightly coupled. Putting it in another way, the new platform device is
> > > > > very much
> > > > > specific to this parent (and yeah, this is a very special usecase where
> > > > > control
> > > > > and data planes are controlled by the IIO backend) and should not exist
> > > > > with it.    
> > > > 
> > > > ad3552r device can be coupled to the axi-ad3552r controller or to a generic 
> > > > spi controler.
> > > > 
> > > > We have actually 2 drivers, SPI and platform (for AXI controller, in this
> > > > patch).
> > > > 
> > > > Scenario 1 (SPI):
> > > > ad3522r can hypotetically work with whatever simple spi controller that can
> > > > read/write registers in raw mode. On simple SPI (CS, SCLK, MOSI), due to
> > > > ad3552r
> > > > chip limitation of 66Mhz clock, the maximum 33MUPS (16 bit samples) cannot
> > > > be
> > > > reached. Some QSPI DDR controller seems to be around, in that case, ad3552r
> > > > may work extending the SPI driver. 
> > > > 
> > > > Scenario 2 (AXI):
> > > > From an hardware-only point ov view axi-ad3552r IP acts as QSPI+DDR
> > > > controller
> > > > plus some additional features for stream synchronization.
> > > > From a sowftware point of view, really different from a spi controller
> > > > driver.
> > > > It's just a backend with APIes that can be called from the child driver.  
> > > 
> > > Potential? scenario 3 is the one that interested me.
> > > 
> > > ad3552 double wired to a normal SPI controller (so like option 1) and
> > > to a an offload engine (so like option 2).  With a few pull up resistors
> > > (cs and clk?) and some care it should electrically work I think.
> > > In that case we'd need the io-backend reference because the parent
> > > would be the option 1 like SPI bus and the io-backend would not be
> > > the parent.
> > > 
> > > _______________________
> > > Host       SPI MOSI    |-------------------\
> > > hard       SPI MISO 0-3|----------------\  |
> > > QSPI       SPI CLK     |--------------\  | |
> > >            SPI CS      |----------\    | | |
> > >                        |           |   | | |
> > > FPGA                   |           |   | | |   |
> > > Soft       SPI MOSI    |-----------|---|-|-x---|
> > > QSPI       SPI MISO 0-3|-----------|---|-x-----|  DAC
> > > Offload    SPI CLK     |-----------|---x-------|
> > > with DDR   SPI CS      |-----------x-----------|
> > > _______________________|
> > > 
> > > Makes all sorts of assumptions about the SPI controllers being designed
> > > for multi controllers on the same SPI buses but I'm not aware of a reason
> > > you can't do that.
> > > 
> > > As the only control message that would need to go over the offload engine
> > > would be the exit DDR (I think) that might be hard coded into a slightly
> > > simpler soft IP along with the bulk data transfer stuff.
> > >   
> > 
> > Not even sure if DDR would be a problem. Right now, I __think__ we need to
> > enable DDR both the peripheral and on the backend. On the peripheral we could
> > use the control link on the non offload controller. On the offload controller,
> > we would set it through IIO backend and that would be a backend config and not
> > go over the bus.
> 
> It's the path back to SDR that I wasn't sure about as it might need a
> DDR register write?

Ah yeah, I see what you mean now. Yeah, that one access would likely have to go
through the offload capable controller.

- Nuno Sá



^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 05/10] iio: backend: extend features
  2024-09-25 11:59       ` Nuno Sá
@ 2024-10-02  9:14         ` Angelo Dureghello
  0 siblings, 0 replies; 59+ messages in thread
From: Angelo Dureghello @ 2024-10-02  9:14 UTC (permalink / raw)
  To: Nuno Sá
  Cc: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Jonathan Cameron,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan,
	linux-iio, linux-kernel, devicetree, dlechner

On 25.09.2024 13:59, Nuno Sá wrote:
> On Tue, 2024-09-24 at 16:11 +0200, Angelo Dureghello wrote:
> > 
> > On 20/09/24 14:50, Nuno Sá wrote:
> > > On Thu, 2024-09-19 at 11:20 +0200, Angelo Dureghello wrote:
> > > > From: Angelo Dureghello <adureghello@baylibre.com>
> > > > 
> > > > Extend backend features with new calls needed later on this
> > > > patchset from axi version of ad3552r.
> > > > 
> > > > The follwoing calls are added:
> > > > 
> > > > iio_backend_ext_sync_enable
> > > > 	enable synchronize channels on external trigger
> > > > iio_backend_ext_sync_disable
> > > > 	disable synchronize channels on external trigger
> > > > iio_backend_ddr_enable
> > > > 	enable ddr bus transfer
> > > > iio_backend_ddr_disable
> > > > 	disable ddr bus transfer
> > > > iio_backend_set_bus_mode
> > > > 	select the type of bus, so that specific read / write
> > > > 	operations are performed accordingly
> > > > iio_backend_buffer_enable
> > > > 	enable buffer
> > > > iio_backend_buffer_disable
> > > > 	disable buffer
> > > > iio_backend_data_transfer_addr
> > > > 	define the target register address where the DAC sample
> > > > 	will be written.
> > > > 
> > > > Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> > > > ---
> > > >   drivers/iio/industrialio-backend.c | 111
> > > > +++++++++++++++++++++++++++++++++++++
> > > >   include/linux/iio/backend.h        |  23 ++++++++
> > > >   2 files changed, 134 insertions(+)
> > > > 
> > > > diff --git a/drivers/iio/industrialio-backend.c
> > > > b/drivers/iio/industrialio-
> > > > backend.c
> > > > index 20b3b5212da7..f4802c422dbf 100644
> > > > --- a/drivers/iio/industrialio-backend.c
> > > > +++ b/drivers/iio/industrialio-backend.c
> > > > @@ -718,6 +718,117 @@ static int __devm_iio_backend_get(struct device
> > > > *dev, struct
> > > > iio_backend *back)
> > > >   	return 0;
> > > >   }
> > > >   
> > > > +/**
> > > > + * iio_backend_ext_sync_enable - Enable external synchronization
> > > > + * @back: Backend device
> > > > + *
> > > > + * Enable synchronization by external signal.
> > > > + *
> > > > + * RETURNS:
> > > > + * 0 on success, negative error number on failure.
> > > > + */
> > > > +int iio_backend_ext_sync_enable(struct iio_backend *back)
> > > > +{
> > > > +	return iio_backend_op_call(back, ext_sync_enable);
> > > > +}
> > > > +EXPORT_SYMBOL_NS_GPL(iio_backend_ext_sync_enable, IIO_BACKEND);
> > > > +
> > > > +/**
> > > > + * iio_backend_ext_sync_disable - Disable external synchronization
> > > > + * @back: Backend device
> > > > + *
> > > > + * Disable synchronization by external signal.
> > > > + *
> > > > + * RETURNS:
> > > > + * 0 on success, negative error number on failure.
> > > > + */
> > > > +int iio_backend_ext_sync_disable(struct iio_backend *back)
> > > > +{
> > > > +	return iio_backend_op_call(back, ext_sync_disable);
> > > > +}
> > > > +EXPORT_SYMBOL_NS_GPL(iio_backend_ext_sync_disable, IIO_BACKEND);
> > > > +
> > > > +/**
> > > > + * iio_backend_ddr_enable - Enable interface DDR (Double Data Rate) mode
> > > > + * @back: Backend device
> > > > + *
> > > > + * Enabling DDR, data is generated by the IP at each front
> > > > + * (raising and falling) of the bus clock signal.
> > > > + *
> > > > + * RETURNS:
> > > > + * 0 on success, negative error number on failure.
> > > > + */
> > > > +int iio_backend_ddr_enable(struct iio_backend *back)
> > > > +{
> > > > +	return iio_backend_op_call(back, ddr_enable);
> > > > +}
> > > > +EXPORT_SYMBOL_NS_GPL(iio_backend_ddr_enable, IIO_BACKEND);
> > > > +
> > > > +/**
> > > > + * iio_backend_ddr_disable - Disable interface DDR (Double Data Rate)
> > > > mode
> > > > + * @back: Backend device
> > > > + *
> > > > + * Disabling DDR data is generated byt the IP at rising or falling front
> > > > + * of the interface clock signal (SDR, Single Data Rate).
> > > > + *
> > > > + * RETURNS:
> > > > + * 0 on success, negative error number on failure.
> > > > + */
> > > > +int iio_backend_ddr_disable(struct iio_backend *back)
> > > > +{
> > > > +	return iio_backend_op_call(back, ddr_disable);
> > > > +}
> > > > +EXPORT_SYMBOL_NS_GPL(iio_backend_ddr_disable, IIO_BACKEND);
> > > > +
> > > > +/**
> > > > + * iio_backend_buffer_enable - Enable iio buffering
> > > > + * @back: Backend device
> > > > + *
> > > > + * Enabling the buffer, buffer data is processed and sent out from the
> > > > + * bus interface.
> > > > + *
> > > > + * RETURNS:
> > > > + * 0 on success, negative error number on failure.
> > > > + */
> > > > +int iio_backend_buffer_enable(struct iio_backend *back)
> > > > +{
> > > > +	return iio_backend_op_call(back, buffer_enable);
> > > > +}
> > > > +EXPORT_SYMBOL_NS_GPL(iio_backend_buffer_enable, IIO_BACKEND);
> > > > +
> > > > +/**
> > > > + * iio_backend_buffer_disable - Disable iio buffering
> > > > + * @back: Backend device
> > > > + *
> > > > + * Disabling the buffer, buffer data transfer on the bus interface
> > > > + * is stopped.
> > > > + *
> > > > + * RETURNS:
> > > > + * 0 on success, negative error number on failure.
> > > > + */
> > > > +int iio_backend_buffer_disable(struct iio_backend *back)
> > > > +{
> > > > +	return iio_backend_op_call(back, buffer_disable);
> > > > +}
> > > > +EXPORT_SYMBOL_NS_GPL(iio_backend_buffer_disable, IIO_BACKEND);
> > > > +
> > > IIRC, both me and Jonathan had some comments about the above 2 calls? Aren't
> > > they
> > > about buffering? I think I mentioned something about using the same buffer
> > > ops as
> > > typical IIO devices use.
> > 
> > i have now separated iio_backend_ops, keeping buffer enable/disable
> > for axi-ad3352r case only,
> > 
> > static const struct iio_backend_ops axi_dac_generic_ops = {
> >      .enable = axi_dac_enable,
> >      .disable = axi_dac_disable,
> >      .request_buffer = axi_dac_request_buffer,
> >      .free_buffer = axi_dac_free_buffer,
> >      .extend_chan_spec = axi_dac_extend_chan,
> >      .ext_info_set = axi_dac_ext_info_set,
> >      .ext_info_get = axi_dac_ext_info_get,
> >      .data_source_set = axi_dac_data_source_set,
> >      .set_sample_rate = axi_dac_set_sample_rate,
> >      .debugfs_reg_access = iio_backend_debugfs_ptr(axi_dac_reg_access),
> > };
> > 
> > static const struct iio_backend_ops axi_ad3552r_ops = {
> >      .enable = axi_dac_enable,
> >      .read_raw = axi_dac_read_raw,
> >      .request_buffer = axi_dac_request_buffer,
> >      .data_source_set = axi_dac_data_source_set,
> >      .ext_sync_enable = axi_dac_ext_sync_enable,
> >      .ext_sync_disable = axi_dac_ext_sync_disable,
> >      .ddr_enable = axi_dac_ddr_enable,
> >      .ddr_disable = axi_dac_ddr_disable,
> >      .buffer_enable = axi_dac_buffer_enable,
> >      .buffer_disable = axi_dac_buffer_disable,
> >      .data_format_set = axi_dac_data_format_set,
> >      .data_transfer_addr = axi_dac_data_transfer_addr,
> > };
> > 
> > 
> > could this be good ?
> > 
> 
> I think you're replying to the wrong email :). But yeah, I made a comment about
> the above and that is something I'm also expecting.
> 
> Regarding the buffer_enable/disable() stuff, please go check past discussions (I
> think on the RFC). I'm fairly sure I had (and Jonathan as well) some comments
> about directly using IIO buffer options or replicating them in the backend_ops.
> Likely the second option is the best one so we can take a reference to backend
> object directly.
> 
> - Nuno Sá
> 

Hi Nuno,

trying to fix this now as (hopefully :) ) last point for v4, looking the RFC
i find:

1) Embed struct iio_buffer_setup_ops in the backend ops struct;
2) Or just define directly the ones we need now in backend ops

About 1,
looks like that then the frontend cannot customize the buffer ops.

About 2,
i already setup a specific backend structure only for axi-ad3552r.
Removed the sync stuff, we have now only 5 new APIs. 

What i can do here is a better naming, and better description as asked from
Jonathan. 

Mainly, this functions are starting and stopping the stream from dma to the chip.

Proposals may be
static int axi_dac_dma_stream_ebable(struct iio_backend *back)
static int axi_dac_dma_stream_disaable(struct iio_backend *back)

or 
static int axi_dac_data_stream_ebable(struct iio_backend *back)
static int axi_dac_data_stream_disaable(struct iio_backend *back)

or still more generic
static int axi_dac_bus_ebable(struct iio_backend *back)
static int axi_dac_bus_disaable(struct iio_backend *back)
(or bus_transfer_enable)

-- 

Regards,
  Angelo

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 08/10] iio: dac: ad3552r: extract common code (no changes in behavior intended)
  2024-09-29 11:57   ` Jonathan Cameron
@ 2024-10-02 15:50     ` Angelo Dureghello
  2024-10-04 14:21       ` Jonathan Cameron
  0 siblings, 1 reply; 59+ messages in thread
From: Angelo Dureghello @ 2024-10-02 15:50 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Lars-Peter Clausen, Michael Hennerich, Nuno Sa, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Olivier Moysan, linux-iio,
	linux-kernel, devicetree, dlechner

Hi Jonathan,

On 29.09.2024 12:57, Jonathan Cameron wrote:
> On Thu, 19 Sep 2024 11:20:04 +0200
> Angelo Dureghello <adureghello@baylibre.com> wrote:
> 
> > From: Angelo Dureghello <adureghello@baylibre.com>
> > 
> > Extracting common code, to share common code to be used later
> > by the AXI driver version (ad3552r-axi.c).
> > 
> > Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
> For these, main request is to move them to a namespace + GPL is
> probably the appropriate choice here.
> 
> 
> > ---
> >  drivers/iio/dac/Makefile         |   2 +-
> >  drivers/iio/dac/ad3552r-common.c | 173 +++++++++++++++++++++++
> >  drivers/iio/dac/ad3552r.c        | 293 ++++-----------------------------------
> >  drivers/iio/dac/ad3552r.h        | 190 +++++++++++++++++++++++++
> >  4 files changed, 390 insertions(+), 268 deletions(-)
> > 
> > diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
> > index 2cf148f16306..56a125f56284 100644
> > --- a/drivers/iio/dac/Makefile
> > +++ b/drivers/iio/dac/Makefile
> > @@ -4,7 +4,7 @@
> >  #
> >  
> >  # When adding new entries keep the list in alphabetical order
> > -obj-$(CONFIG_AD3552R) += ad3552r.o
> > +obj-$(CONFIG_AD3552R) += ad3552r.o ad3552r-common.o
> >  obj-$(CONFIG_AD5360) += ad5360.o
> >  obj-$(CONFIG_AD5380) += ad5380.o
> >  obj-$(CONFIG_AD5421) += ad5421.o
> > diff --git a/drivers/iio/dac/ad3552r-common.c b/drivers/iio/dac/ad3552r-common.c
> > new file mode 100644
> > index 000000000000..624f3f97cdea
> > --- /dev/null
> > +++ b/drivers/iio/dac/ad3552r-common.c
> > @@ -0,0 +1,173 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +//
> > +// Copyright (c) 2010-2024 Analog Devices Inc.
> > +// Copyright (c) 2024 Baylibre, SAS
> > +
> > +#include <linux/device.h>
> > +#include <linux/module.h>
> > +#include <linux/property.h>
> > +#include <linux/regulator/consumer.h>
> > +
> > +#include "ad3552r.h"
> > +
> > +const s32 ad3552r_ch_ranges[AD3552R_MAX_RANGES][2] = {
> > +	[AD3552R_CH_OUTPUT_RANGE_0__2P5V]	= { 0, 2500 },
> > +	[AD3552R_CH_OUTPUT_RANGE_0__5V]		= { 0, 5000 },
> > +	[AD3552R_CH_OUTPUT_RANGE_0__10V]	= { 0, 10000 },
> > +	[AD3552R_CH_OUTPUT_RANGE_NEG_5__5V]	= { -5000, 5000 },
> > +	[AD3552R_CH_OUTPUT_RANGE_NEG_10__10V]	= { -10000, 10000 }
> > +};
> > +EXPORT_SYMBOL(ad3552r_ch_ranges);
> 
> GPL and namespace them to avoid poluting the general namespace with driver
> specific exports.
> 
> EXPORT_SYMBOL_NS_GPL() etc.
> 
> 
> > +
> > +u16 ad3552r_calc_custom_gain(u8 p, u8 n, s16 goffs)
> > +{
> > +	u16 reg;
> > +
> > +	reg = FIELD_PREP(AD3552R_MASK_CH_RANGE_OVERRIDE, 1);
> > +	reg |= FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_P, p);
> > +	reg |= FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_N, n);
> > +	reg |= FIELD_PREP(AD3552R_MASK_CH_OFFSET_BIT_8, abs((s32)goffs) >> 8);
> Hmm. Not sure the s32 case does anything useful here.
> Also this is a little messy from local view of code. It is not obvious
> that only BIT(0) can be set here.  I'd be tempted to mask that
> before passing to FIELD_PREP()
> 
> > +	reg |= FIELD_PREP(AD3552R_MASK_CH_OFFSET_POLARITY, (s32)goffs < 0);
> 
> Why do you need the s32 cast for this last line?
> 
> > +
> > +	return reg;
> > +}
> > +
> > +int ad3552r_get_ref_voltage(struct device *dev)
> > +{
> > +	int voltage;
> > +	int delta = 100000;
> > +
> > +	voltage = devm_regulator_get_enable_read_voltage(dev, "vref");
> > +	if (voltage < 0 && voltage != -ENODEV)
> > +		return dev_err_probe(dev, voltage,
> > +				     "Error getting vref voltage\n");
> > +
> > +	if (voltage == -ENODEV) {
> > +		if (device_property_read_bool(dev, "adi,vref-out-en"))
> > +			return AD3552R_INTERNAL_VREF_PIN_2P5V;
> > +		else
> > +			return AD3552R_INTERNAL_VREF_PIN_FLOATING;
> > +	}
> > +
> > +	if (voltage > 2500000 + delta || voltage < 2500000 - delta) {
> > +		dev_warn(dev, "vref-supply must be 2.5V");
> > +		return -EINVAL;
> > +	}
> 
> Obviously this is legacy code, but why do we care in the driver?
> If someone has circuitry or configuration that is wrong, do we need to check
> that?  I guess it does little harm though.
> 
> > +
> > +	return AD3552R_EXTERNAL_VREF_PIN_INPUT;
> > +}
> > +
> > +int ad3552r_get_drive_strength(struct device *dev, u32 *val)
> > +{
> > +	int err;
> > +
> > +	err = device_property_read_u32(dev, "adi,sdo-drive-strength", val);
> > +	if (err)
> > +		return err;
> > +
> > +	if (*val > 3) {
>


 
> Usually we avoid setting values passed back on error if it is easy to do so.
> I'd bounce via a local variable and only set *val = drive_strength
> after you know it is in range.
> 
> > +		dev_err(dev,
> > +			"adi,sdo-drive-strength must be less than 4\n");
> > +		return -EINVAL;
> Is dev_err_probe() appropriate here?  I haven't checked if this is called
> from non probe paths so ignore this comment if it is.
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +int ad3552r_get_custom_gain(struct device *dev, struct fwnode_handle *child,
> > +			    u8 *gs_p, u8 *gs_n, u16 *rfb, s16 *goffs)
> > +{
> > +	int err;
> > +	u32 val;
> > +	struct fwnode_handle *gain_child __free(fwnode_handle) =
> > +				fwnode_get_named_child_node(child,
> One tab more than the line above is fine for cases like this and makes for
> more readable code.
>
Aligning with c then line comes to long. 
I can offer, as in other drivers:

int ad3552r_get_custom_gain(struct device *dev, struct fwnode_handle *child,
			    u8 *gs_p, u8 *gs_n, u16 *rfb, s16 *goffs)
{
	int err;
	u32 val;
	struct fwnode_handle *gain_child __free(fwnode_handle) =
		fwnode_get_named_child_node(child,
					    "custom-output-range-config");

Also, do you prefer 80 or 100 as eol limit ?

 
> > +				"custom-output-range-config");
> 
> Align this final parameter with c of child.
> 
> > +
> > +	if (!gain_child)
> > +		return dev_err_probe(dev, -EINVAL,
> > +				     "custom-output-range-config mandatory\n");
> > +
> > +	err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-p", &val);
> > +	if (err)
> > +		return dev_err_probe(dev, err,
> > +				     "adi,gain-scaling-p mandatory\n");
> > +	*gs_p = val;
> > +
> > +	err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-n", &val);
> > +	if (err)
> > +		return dev_err_probe(dev, err,
> > +				     "adi,gain-scaling-n property mandatory\n");
> > +	*gs_n = val;
> > +
> > +	err = fwnode_property_read_u32(gain_child, "adi,rfb-ohms", &val);
> > +	if (err)
> > +		return dev_err_probe(dev, err,
> > +				     "adi,rfb-ohms mandatory\n");
> > +	*rfb = val;
> > +
> > +	err = fwnode_property_read_u32(gain_child, "adi,gain-offset", &val);
> > +	if (err)
> > +		return dev_err_probe(dev, err,
> > +				     "adi,gain-offset mandatory\n");
> > +	*goffs = val;
> > +
> > +	return 0;
> > +}
> > +
> > +static int ad3552r_find_range(u16 id, s32 *vals)
> > +{
> > +	int i, len;
> > +	const s32 (*ranges)[2];
> > +
> > +	if (id == AD3542R_ID) {
> 
> This is already in your model_data. Use that not another lookup via
> an ID enum.  The ID enum approach doesn't scale as we add more parts
> as it scatters device specific code through the driver.
>

This function is only used internally to this common part.
 
> 
> > +		len = ARRAY_SIZE(ad3542r_ch_ranges);
> > +		ranges = ad3542r_ch_ranges;
> > +	} else {
> > +		len = ARRAY_SIZE(ad3552r_ch_ranges);
> > +		ranges = ad3552r_ch_ranges;
> > +	}
> > +
> > +	for (i = 0; i < len; i++)
> > +		if (vals[0] == ranges[i][0] * 1000 &&
> > +		    vals[1] == ranges[i][1] * 1000)
> > +			return i;
> > +
> > +	return -EINVAL;
> > +}
> > +
> > +int ad3552r_get_output_range(struct device *dev, enum ad3552r_id chip_id,
> > +			     struct fwnode_handle *child, u32 *val)
> As above, don't pass the enum. Either pass the model_data or pass the
> actual stuff you need which is the ranges array and size of that array.
>

Cannot pass model data, structures of the 2 drviers are different.
If i pass arrays, the logic of deciding what array (checking the id)
must be done in the drivers, but in this way, there will be less
common code.
 
> > +{
> > +	int ret;
> > +	s32 vals[2];
> > +
> > +	/* This property is optional, so returning -ENOENT if missing */
> > +	if (!fwnode_property_present(child, "adi,output-range-microvolt"))
> > +		return -ENOENT;
> > +
> > +	ret = fwnode_property_read_u32_array(child,
> > +					     "adi,output-range-microvolt",
> > +					     vals, 2);
> > +	if (ret)
> > +		return dev_err_probe(dev, ret,
> > +				"invalid adi,output-range-microvolt\n");
> > +
> > +	ret = ad3552r_find_range(chip_id, vals);
> > +	if (ret < 0)
> > +		return dev_err_probe(dev, ret,
> > +			"invalid adi,output-range-microvolt value\n");
> > +
> > +	*val = ret;
> > +
> > +	return 0;
> > +}
> 
> Thanks,
> 
> Jonathan
> 
> 

Thanks,

-- 
Regards,
  Angelo

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v3 08/10] iio: dac: ad3552r: extract common code (no changes in behavior intended)
  2024-10-02 15:50     ` Angelo Dureghello
@ 2024-10-04 14:21       ` Jonathan Cameron
  0 siblings, 0 replies; 59+ messages in thread
From: Jonathan Cameron @ 2024-10-04 14:21 UTC (permalink / raw)
  To: Angelo Dureghello
  Cc: Jonathan Cameron, Lars-Peter Clausen, Michael Hennerich, Nuno Sa,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan,
	linux-iio, linux-kernel, devicetree, dlechner

> > > +int ad3552r_get_custom_gain(struct device *dev, struct fwnode_handle *child,
> > > +			    u8 *gs_p, u8 *gs_n, u16 *rfb, s16 *goffs)
> > > +{
> > > +	int err;
> > > +	u32 val;
> > > +	struct fwnode_handle *gain_child __free(fwnode_handle) =
> > > +				fwnode_get_named_child_node(child,  
> > One tab more than the line above is fine for cases like this and makes for
> > more readable code.
> >  
> Aligning with c then line comes to long. 
> I can offer, as in other drivers:
> 
> int ad3552r_get_custom_gain(struct device *dev, struct fwnode_handle *child,
> 			    u8 *gs_p, u8 *gs_n, u16 *rfb, s16 *goffs)
> {
> 	int err;
> 	u32 val;
> 	struct fwnode_handle *gain_child __free(fwnode_handle) =
> 		fwnode_get_named_child_node(child,
> 					    "custom-output-range-config");

That looks good to me

> 
> Also, do you prefer 80 or 100 as eol limit ?

Prefer 80, but not at the cost of readability

> 
>  
> > > +				"custom-output-range-config");  
> > 
> > Align this final parameter with c of child.
> >   
>

> > > +static int ad3552r_find_range(u16 id, s32 *vals)
> > > +{
> > > +	int i, len;
> > > +	const s32 (*ranges)[2];
> > > +
> > > +	if (id == AD3542R_ID) {  
> > 
> > This is already in your model_data. Use that not another lookup via
> > an ID enum.  The ID enum approach doesn't scale as we add more parts
> > as it scatters device specific code through the driver.
> >  
> 
> This function is only used internally to this common part.
>  
> >   
> > > +		len = ARRAY_SIZE(ad3542r_ch_ranges);
> > > +		ranges = ad3542r_ch_ranges;
> > > +	} else {
> > > +		len = ARRAY_SIZE(ad3552r_ch_ranges);
> > > +		ranges = ad3552r_ch_ranges;
> > > +	}
> > > +
> > > +	for (i = 0; i < len; i++)
> > > +		if (vals[0] == ranges[i][0] * 1000 &&
> > > +		    vals[1] == ranges[i][1] * 1000)
> > > +			return i;
> > > +
> > > +	return -EINVAL;
> > > +}
> > > +
> > > +int ad3552r_get_output_range(struct device *dev, enum ad3552r_id chip_id,
> > > +			     struct fwnode_handle *child, u32 *val)  
> > As above, don't pass the enum. Either pass the model_data or pass the
> > actual stuff you need which is the ranges array and size of that array.
> >  
> 
> Cannot pass model data, structures of the 2 drviers are different.
> If i pass arrays, the logic of deciding what array (checking the id)
> must be done in the drivers, but in this way, there will be less
> common code.

I'd prefer that to having an ID register look up in here.

Roughly speaking looking up by ID is almost always the wrong
way to go for long term scalability of a driver as more parts
are added.

Jonathan


^ permalink raw reply	[flat|nested] 59+ messages in thread

end of thread, other threads:[~2024-10-04 14:21 UTC | newest]

Thread overview: 59+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-19  9:19 [PATCH v3 00/10] iio: add support for the ad3552r AXI DAC IP Angelo Dureghello
2024-09-19  9:19 ` [PATCH v3 01/10] iio: backend: adi-axi-dac: fix wrong register bitfield Angelo Dureghello
2024-09-20 12:45   ` Nuno Sá
2024-09-29 10:38     ` Jonathan Cameron
2024-09-19  9:19 ` [PATCH v3 02/10] dt-bindings: iio: dac: axi-dac: add ad3552r axi variant Angelo Dureghello
2024-09-20 12:47   ` Nuno Sá
2024-09-22 20:59   ` Krzysztof Kozlowski
2024-09-29 10:46   ` Jonathan Cameron
2024-09-30 12:52     ` Angelo Dureghello
2024-09-30 13:15       ` Nuno Sá
2024-09-30 14:52         ` Jonathan Cameron
2024-09-19  9:19 ` [PATCH v3 03/10] dt-bindings: iio: dac: ad3552r: fix maximum spi speed Angelo Dureghello
2024-09-22 20:59   ` Krzysztof Kozlowski
2024-09-19  9:20 ` [PATCH v3 04/10] dt-bindings: iio: dac: ad3552r: add io-backend support Angelo Dureghello
2024-09-22 21:02   ` Krzysztof Kozlowski
2024-09-23 15:50     ` Angelo Dureghello
2024-09-24  8:02       ` Krzysztof Kozlowski
2024-09-24 12:27         ` Nuno Sá
2024-09-25  7:22           ` Krzysztof Kozlowski
2024-09-25 11:55             ` Nuno Sá
2024-09-28 12:20               ` Krzysztof Kozlowski
2024-09-29 10:59                 ` Jonathan Cameron
2024-09-30  7:20                   ` Nuno Sá
2024-09-30  7:31                     ` Krzysztof Kozlowski
2024-09-30  8:24                       ` Nuno Sá
2024-09-30 13:22                     ` Angelo Dureghello
2024-09-30 15:09                       ` Jonathan Cameron
2024-10-01  8:23                         ` Nuno Sá
2024-10-01 18:29                           ` Jonathan Cameron
2024-10-02  5:54                             ` Krzysztof Kozlowski
2024-10-02  9:00                             ` Nuno Sá
2024-09-29 10:51   ` Jonathan Cameron
2024-09-30 14:15     ` Angelo Dureghello
2024-09-30 14:49       ` Jonathan Cameron
2024-09-30 15:08         ` Angelo Dureghello
2024-09-30 19:20           ` David Lechner
2024-10-01  8:09             ` Angelo Dureghello
2024-09-19  9:20 ` [PATCH v3 05/10] iio: backend: extend features Angelo Dureghello
2024-09-20 12:50   ` Nuno Sá
2024-09-24 14:11     ` Angelo Dureghello
2024-09-25 11:59       ` Nuno Sá
2024-10-02  9:14         ` Angelo Dureghello
2024-09-29 11:05   ` Jonathan Cameron
2024-09-30 19:25     ` David Lechner
2024-10-01  8:14       ` Nuno Sá
2024-10-01  8:35         ` Angelo Dureghello
2024-10-01 18:32           ` Jonathan Cameron
2024-09-19  9:20 ` [PATCH v3 06/10] iio: backend: adi-axi-dac: " Angelo Dureghello
2024-09-20 13:10   ` Nuno Sá
2024-09-29 11:28   ` Jonathan Cameron
2024-09-19  9:20 ` [PATCH v3 07/10] iio: dac: ad3552r: changes to use FIELD_PREP Angelo Dureghello
2024-09-19  9:20 ` [PATCH v3 08/10] iio: dac: ad3552r: extract common code (no changes in behavior intended) Angelo Dureghello
2024-09-29 11:57   ` Jonathan Cameron
2024-10-02 15:50     ` Angelo Dureghello
2024-10-04 14:21       ` Jonathan Cameron
2024-09-19  9:20 ` [PATCH v3 09/10] iio: dac: ad3552r: add axi platform driver Angelo Dureghello
2024-09-29 12:17   ` Jonathan Cameron
2024-09-19  9:20 ` [PATCH v3 10/10] iio: backend: adi-axi-dac: add registering of child fdt node Angelo Dureghello
2024-09-29 12:21   ` Jonathan Cameron

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).