On Thu, Nov 30, 2023 at 5:54 PM David Lechner <dlechner@xxxxxxxxxxxx> wrote: > > On Tue, Nov 21, 2023 at 4:17 AM Nuno Sa via B4 Relay > <devnull+nuno.sa.analog.com@xxxxxxxxxx> wrote: > > > > Hi all, > > > > This is a Framework to handle complex IIO aggregate devices. > > > > The typical architecture is to have one device as the frontend device which > > can be "linked" against one or multiple backend devices. All the IIO and > > userspace interface is expected to be registers/managed by the frontend > > device which will callback into the backends when needed (to get/set > > some configuration that it does not directly control). > > > > The basic framework interface is pretty simple: > > - Backends should register themselves with @devm_iio_backend_register() > > - Frontend devices should get backends with @devm_iio_backend_get() > > > > (typical provider - consumer stuff) > > > > The "typical provider - consumer stuff" seems pretty straight forward > for finding and connecting two different devices, but the definition > of what is a frontend and what is a backend seems a bit nebulous. It > would be nice to seem some example devicetree to be able to get a > better picture of how this will be used in practices (links to the the > hardware docs for those examples would be nice too). > Fulfilling my own request here... Since AD9467 is being use as the example first user of the IIO offload framework I did a deep dive into how it is actually being used. It looks like this: ---------------------------------------------------------------------------- Hardware ---------------------------------------------------------------------------- AD9467 ------ High-speed ADC that uses SPI for configuration and LVDS for data capture. https://www.analog.com/media/en/technical-documentation/data-sheets/AD9467.pdf Pins: Supplies: - AVDD1 (1.8V analog supply) - AVDD2 (3.3V analog supply) - AVDD3 (1.8V analog supply) - SPIVDD (1.8V or 3.3V SPI supply) - DRVDD (1.8V digital output driver supply) - XVREF (optional reference voltage) SPI: - CSB - SDIO - SCLK Analog input: - VIN+/VIN- Clock input: - CLK+/CLK- Digital output: - Dn-/Dn+ (parallel digital output) - DCO+/DCO- (data clock output) - OR+/OR- (out of range output) ADI AXI ADC ----------- FPGA IP core for interfacing an ADC device with a high speed serial (JESD204B) or source synchronous parallel interface (LVDS/CMOS). https://wiki.analog.com/resources/fpga/docs/axi_adc_ip Interfaces: LVDS: - rx_clk_in_[p|n] clock input - rx_data_in_[p|n] parallel data input - rx_frame_in_[p|n] frame input signal (optional/device specific) - rx_or_in_[p|n] over range input (optional/device specific) Write FIFO: - see link for details, this consists of multiple signals that connect to a "sink module" MMIO: - memory mapped registers (detailed in link) "sink module" ------------- FPGA IP core for piping a data stream to DMA. https://wiki.analog.com/resources/fpga/docs/util_var_fifo Interfaces: Data Input: - data_in Data to be stored - data_in_valid Valid for the input data Data Output: - data_out Data forwarded to the DMA - data_out_valid Valid for the output data There are additional interfaces but they probably don't concern devicetree since software doesn't interact with them (AFAIK). Schematic --------- +----------------------------+ +---------------+ +-------------------+ | SOC/FPGA | | ADC | | Signal generator | | | | | | | | +--------------------+ | | VIN+/- xxxxxxxx VOUT+/- | | | SPI | | | | | | | | SDIO ------------ SDIO | +-------------------+ | | SCLK ------------ SCLK | | | CS ------------ CSB | +-------------------+ | | | | | | | External clock | | +--------------------+ | | | | | | | AXI ADC | | | CLK+/- xxxxxxxxx CLKOUT+/- | | | | | | | | | | | rx_data_in_[p|n] xxxxxxxxxxxxx Dn+/- | +-------------------+ | | rx_clk_in_[p|n] xxxxxxxxxxxxx DCO+/DCO- | | | rx_or_in_[p|n] xxxxxxxxxxxxx OR+/- | +-------------------+ | | | | | | | Power supplies | | | Write FIFO ===# | | | | | | +--------------------+ H | | AVDD1 --------- 1.8V | | | "sink module" | H | | AVDD2 --------- 2.2V | | | | H | | AVDD3 --------- 1.8V | | | Data Input ===# | | SPIVDD --------- 3.3V | | | | | | DRVDD --------- 1.8V | | | Data Output ===# | | XVREF --------- 1.2V | | +--------------------+ H | | | | | | | DMA controller | H | +---------------+ +-------------------+ | | | H | | | channel 0 ===# | | | | | | +--------------------+ | | | +----------------------------+ ---------------------------------------------------------------------------- Devicetree ---------------------------------------------------------------------------- Current situation: &soc: { spi { ... spi_adc: adc@0 { compatible = "adi,ad9467"; reg = <0>; clocks = <&adc_clk>; clock-names = "adc-clk"; }; }; fpga { ... /* IIO device is associated with this node. */ axi-adc@44a00000 { compatible = "adi,axi-adc-10.0.a"; reg = <0x44a00000 0x10000>; /* Not sure dmas belong here since it is a property of the * "sink module" which is separate from AXI ADC module. */ dmas = <&rx_dma 0>; dma-names = "rx"; adi,adc-dev = <&spi_adc>; }; }; }; --- Proposed IIO backend framework (inferred from v1 patches): &soc: { spi { ... /* IIO device is associated with this node. */ adc@0 { compatible = "adi,ad9467"; reg = <0>; clocks = <&adc_clk>; clock-names = "adc-clk"; /* As discussed already, this isn't really the right place for * dmas either. */ dmas = <&rx_dma 0>; dma-names = "rx"; io-backends = <&axi_adc>; }; }; fpga { ... axi_adc: axi-adc@44a00000 { compatible = "adi,axi-adc-10.0.a"; reg = <0x44a00000 0x10000>; }; }; }; --- Composite device? /* IIO device is associated with this node. */ adc { compatible = "adi,ad9467"; io-backends = <&adc_spi_backend>, <&adc_lvds_backend>; clocks = <&adc_clk>; clock-names = "adc-clk"; xvref-supply = <&ref_voltage>; avdd1-supply = <®ulator_1_8V>; avdd2-supply = <®ulator_3_3V>; avdd3-supply = <®ulator_1_8V>; }; &soc: { spi { ... /* This node describes only the SPI aspects of the ADC chip */ adc_spi_backend: adc@0 { compatible = "adi,ad9467-spi-io-backend"; reg = <0>; spi-3wire; spi-max-frequency = <25000000>; spivdd-supply = <®ulator_1_8V>; }; }; fpga { ... /* This node is an LVDS bus, analogous to a SPI bus or I2C bus */ axi-adc@44a00000 { compatible = "adi,axi-adc-10.0.a"; reg = <0x44a00000 0x10000>; ... /* This node describes all sink modules that are connected to * the AXI ADC controller through the FPGA fabric. */ sink-modules { ... /* This node describes the FIFO to DMA sink module used by * our ADC. */ adc_dma: module@0 { compatible = "adi,dma-fifo-1.0.a"; reg = <0>; dmas = <&rx_dma 0>; dma-names = "rx"; }; }; /* Then we describe what is connected to each channel of the * controller (reg == channel number). */ /* This node describes only the digital output (LVDS) aspects of * the ADC chip */ adc_lvds_backend: adc@0 { compatible = "adi,ad9467-lvds-io-backend"; reg = <0>; drvdd-supply = <®ulator_1_8V>; /* This is a LVDS bus peripheral property that can only be used * with peripheral nodes that are children of a compatible = * "adi,axi-adc-10.0.a" node. This works exactly like the * controller-specific SPI bus peripheral properties, e.g. * like samsung,spi-peripheral-props.yaml. */ adi,sink-modules = <&adc_dma>; } }; }; }; ---------------------------------------------------------------------------- Discussion ---------------------------------------------------------------------------- After reviewing the existing device tree bindings, it appears the current adi,ad9467.yaml is incomplete. It lacks the supplies and even though the example shows that it is a child of a spi node, it is missing a reference to /schemas/spi/spi-peripheral-props.yaml# and spi properties like spi-3wire and spi-max-frequency. It also misses a description of what is connected to the digital output, but that I think that is the main thing we are trying to solve here - if it belongs there or somewhere else. Having read more about the AXI ADC IP block, it seems to me like it should just be considered an LVDS bus controller with generic bindings similar to how we have SPI and I2C buses. Following that line of thought, if the compatible = "adi,axi-adc-10.0.a" node is a bus node, then logically, the ADC device node should be a child node of that LVDS bus node. But since the ADC is also a SPI device it also needs to be a child node of the SPI bus node. But is can't be a child of two different nodes, so where does it go? This is where the IIO backend framework can come in. We can create a "composite" device as seen in the example dts above. This is just a platform device (in Linux-speak) and it composes the two "io-backend" devices from the the two busses to create a logical iio/adc device. To solve the mystery of "where does the dmas property belong?", I have taken a page out of the work I am preparing the AXI SPI Engine offload support [1]. (This hasn't been submitted to a mailing list yet because I'm still working on the driver, but the bindings are finished and I ran the idea by Rob on IRC a while back who suggested doing it this way, so maybe it works here too?) [1]: https://github.com/analogdevicesinc/linux/pull/2341/commits/57bb1998371f61f4144689136aba5dd6d16a2a66 Since the "sink module" is really a separate IP block from the AXI ADC, it gets its own node and compatible string. Since these "sink modules" are connected to the AXI ADC, they get listed as child nodes, but we group them together under a single sink-modules node to separate them from the LVDS peripherals nodes. Then they get associated with a peripheral with the adi,sink-modules property (also see comment on that property in the example above). My "composite" device example evolved quite a bit as I was writing this but I'm pretty happy with where it ended up. I think adding child nodes to the axi-adc node answers Nuno's concerns about how to keep a generic axi-adc binding while accounting for the fact that it changes slightly depending on what it is attached to. And having a separate platform device solves my questions about the ambiguity of which should be the front end, the spi node or the axi-adc node. It turns out, perhaps the answer is neither.