mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 01:04:41 +01:00
Add a new page to Documentation/spi/ describing how multi-lane SPI support works. This is uncommon functionality so it deserves its own documentation page. Reviewed-by: Marcelo Schmitt <marcelo.schmitt@analog.com> Signed-off-by: David Lechner <dlechner@baylibre.com> Link: https://patch.msgid.link/20260123-spi-add-multi-bus-support-v6-5-12af183c06eb@baylibre.com Signed-off-by: Mark Brown <broonie@kernel.org>
217 lines
7.1 KiB
ReStructuredText
217 lines
7.1 KiB
ReStructuredText
====================================
|
|
SPI devices with multiple data lanes
|
|
====================================
|
|
|
|
Some specialized SPI controllers and peripherals support multiple data lanes
|
|
that allow reading more than one word at a time in parallel. This is different
|
|
from dual/quad/octal SPI where multiple bits of a single word are transferred
|
|
simultaneously.
|
|
|
|
For example, controllers that support parallel flash memories have this feature
|
|
as do some simultaneous-sampling ADCs where each channel has its own data lane.
|
|
|
|
---------------------
|
|
Describing the wiring
|
|
---------------------
|
|
|
|
The ``spi-tx-bus-width`` and ``spi-rx-bus-width`` properties in the devicetree
|
|
are used to describe how many data lanes are connected between the controller
|
|
and how wide each lane is. The number of items in the array indicates how many
|
|
lanes there are, and the value of each item indicates how many bits wide that
|
|
lane is.
|
|
|
|
For example, a dual-simultaneous-sampling ADC with two 4-bit lanes might be
|
|
wired up like this::
|
|
|
|
+--------------+ +----------+
|
|
| SPI | | AD4630 |
|
|
| Controller | | ADC |
|
|
| | | |
|
|
| CS0 |--->| CS |
|
|
| SCK |--->| SCK |
|
|
| SDO |--->| SDI |
|
|
| | | |
|
|
| SDIA0 |<---| SDOA0 |
|
|
| SDIA1 |<---| SDOA1 |
|
|
| SDIA2 |<---| SDOA2 |
|
|
| SDIA3 |<---| SDOA3 |
|
|
| | | |
|
|
| SDIB0 |<---| SDOB0 |
|
|
| SDIB1 |<---| SDOB1 |
|
|
| SDIB2 |<---| SDOB2 |
|
|
| SDIB3 |<---| SDOB3 |
|
|
| | | |
|
|
+--------------+ +----------+
|
|
|
|
It is described in a devicetree like this::
|
|
|
|
spi {
|
|
compatible = "my,spi-controller";
|
|
|
|
...
|
|
|
|
adc@0 {
|
|
compatible = "adi,ad4630";
|
|
reg = <0>;
|
|
...
|
|
spi-rx-bus-width = <4>, <4>; /* 2 lanes of 4 bits each */
|
|
...
|
|
};
|
|
};
|
|
|
|
In most cases, lanes will be wired up symmetrically (A to A, B to B, etc). If
|
|
this isn't the case, extra ``spi-rx-lane-map`` and ``spi-tx-lane-map``
|
|
properties are needed to provide a mapping between controller lanes and the
|
|
physical lane wires.
|
|
|
|
Here is an example where a multi-lane SPI controller has each lane wired to
|
|
separate single-lane peripherals::
|
|
|
|
+--------------+ +----------+
|
|
| SPI | | Thing 1 |
|
|
| Controller | | |
|
|
| | | |
|
|
| CS0 |--->| CS |
|
|
| SDO0 |--->| SDI |
|
|
| SDI0 |<---| SDO |
|
|
| SCLK0 |--->| SCLK |
|
|
| | | |
|
|
| | +----------+
|
|
| |
|
|
| | +----------+
|
|
| | | Thing 2 |
|
|
| | | |
|
|
| CS1 |--->| CS |
|
|
| SDO1 |--->| SDI |
|
|
| SDI1 |<---| SDO |
|
|
| SCLK1 |--->| SCLK |
|
|
| | | |
|
|
+--------------+ +----------+
|
|
|
|
This is described in a devicetree like this::
|
|
|
|
spi {
|
|
compatible = "my,spi-controller";
|
|
|
|
...
|
|
|
|
thing1@0 {
|
|
compatible = "my,thing1";
|
|
reg = <0>;
|
|
...
|
|
};
|
|
|
|
thing2@1 {
|
|
compatible = "my,thing2";
|
|
reg = <1>;
|
|
...
|
|
spi-tx-lane-map = <1>; /* lane 0 is not used, lane 1 is used for tx wire */
|
|
spi-rx-lane-map = <1>; /* lane 0 is not used, lane 1 is used for rx wire */
|
|
...
|
|
};
|
|
};
|
|
|
|
|
|
The default values of ``spi-rx-bus-width`` and ``spi-tx-bus-width`` are ``<1>``,
|
|
so these properties can still be omitted even when ``spi-rx-lane-map`` and
|
|
``spi-tx-lane-map`` are used.
|
|
|
|
----------------------------
|
|
Usage in a peripheral driver
|
|
----------------------------
|
|
|
|
These types of SPI controllers generally do not support arbitrary use of the
|
|
multiple lanes. Instead, they operate in one of a few defined modes. Peripheral
|
|
drivers should set the :c:type:`struct spi_transfer.multi_lane_mode <spi_transfer>`
|
|
field to indicate which mode they want to use for a given transfer.
|
|
|
|
The possible values for this field have the following semantics:
|
|
|
|
- :c:macro:`SPI_MULTI_BUS_MODE_SINGLE`: Only use the first lane. Other lanes are
|
|
ignored. This means that it is operating just like a conventional SPI
|
|
peripheral. This is the default, so it does not need to be explicitly set.
|
|
|
|
Example::
|
|
|
|
tx_buf[0] = 0x88;
|
|
|
|
struct spi_transfer xfer = {
|
|
.tx_buf = tx_buf,
|
|
.len = 1,
|
|
};
|
|
|
|
spi_sync_transfer(spi, &xfer, 1);
|
|
|
|
Assuming the controller is sending the MSB first, the sequence of bits
|
|
sent over the tx wire would be (right-most bit is sent first)::
|
|
|
|
controller > data bits > peripheral
|
|
---------- ---------------- ----------
|
|
SDO 0 0-0-0-1-0-0-0-1 SDI 0
|
|
|
|
- :c:macro:`SPI_MULTI_BUS_MODE_MIRROR`: Send a single data word over all of the
|
|
lanes at the same time. This only makes sense for writes and not
|
|
for reads.
|
|
|
|
Example::
|
|
|
|
tx_buf[0] = 0x88;
|
|
|
|
struct spi_transfer xfer = {
|
|
.tx_buf = tx_buf,
|
|
.len = 1,
|
|
.multi_lane_mode = SPI_MULTI_BUS_MODE_MIRROR,
|
|
};
|
|
|
|
spi_sync_transfer(spi, &xfer, 1);
|
|
|
|
The data is mirrored on each tx wire::
|
|
|
|
controller > data bits > peripheral
|
|
---------- ---------------- ----------
|
|
SDO 0 0-0-0-1-0-0-0-1 SDI 0
|
|
SDO 1 0-0-0-1-0-0-0-1 SDI 1
|
|
|
|
- :c:macro:`SPI_MULTI_BUS_MODE_STRIPE`: Send or receive two different data words
|
|
at the same time, one on each lane. This means that the buffer needs to be
|
|
sized to hold data for all lanes. Data is interleaved in the buffer, with
|
|
the first word corresponding to lane 0, the second to lane 1, and so on.
|
|
Once the last lane is used, the next word in the buffer corresponds to lane
|
|
0 again. Accordingly, the buffer size must be a multiple of the number of
|
|
lanes. This mode works for both reads and writes.
|
|
|
|
Example::
|
|
|
|
struct spi_transfer xfer = {
|
|
.rx_buf = rx_buf,
|
|
.len = 2,
|
|
.multi_lane_mode = SPI_MULTI_BUS_MODE_STRIPE,
|
|
};
|
|
|
|
spi_sync_transfer(spi, &xfer, 1);
|
|
|
|
Each rx wire has a different data word sent simultaneously::
|
|
|
|
controller < data bits < peripheral
|
|
---------- ---------------- ----------
|
|
SDI 0 0-0-0-1-0-0-0-1 SDO 0
|
|
SDI 1 1-0-0-0-1-0-0-0 SDO 1
|
|
|
|
After the transfer, ``rx_buf[0] == 0x11`` (word from SDO 0) and
|
|
``rx_buf[1] == 0x88`` (word from SDO 1).
|
|
|
|
|
|
-----------------------------
|
|
SPI controller driver support
|
|
-----------------------------
|
|
|
|
To support multiple data lanes, SPI controller drivers need to set
|
|
:c:type:`struct spi_controller.num_data_lanes <spi_controller>` to a value
|
|
greater than 1.
|
|
|
|
Then the part of the driver that handles SPI transfers needs to check the
|
|
:c:type:`struct spi_transfer.multi_lane_mode <spi_transfer>` field and implement
|
|
the appropriate behavior for each supported mode and return an error for
|
|
unsupported modes.
|
|
|
|
The core SPI code should handle the rest.
|