Skip to content

Commit f58872f

Browse files
machschmittbroonie
authored andcommitted
spi: Enable controllers to extend the SPI protocol with MOSI idle configuration
The behavior of an SPI controller data output line (SDO or MOSI or COPI (Controller Output Peripheral Input) for disambiguation) is usually not specified when the controller is not clocking out data on SCLK edges. However, there do exist SPI peripherals that require specific MOSI line state when data is not being clocked out of the controller. Conventional SPI controllers may set the MOSI line on SCLK edges then bring it low when no data is going out or leave the line the state of the last transfer bit. More elaborated controllers are capable to set the MOSI idle state according to different configurable levels and thus are more suitable for interfacing with demanding peripherals. Add SPI mode bits to allow peripherals to request explicit MOSI idle state when needed. When supporting a particular MOSI idle configuration, the data output line state is expected to remain at the configured level when the controller is not clocking out data. When a device that needs a specific MOSI idle state is identified, its driver should request the MOSI idle configuration by setting the proper SPI mode bit. Acked-by: Nuno Sa <nuno.sa@analog.com> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Reviewed-by: David Lechner <dlechner@baylibre.com> Tested-by: David Lechner <dlechner@baylibre.com> Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com> Link: https://patch.msgid.link/9802160b5e5baed7f83ee43ac819cb757a19be55.1720810545.git.marcelo.schmitt@analog.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 8400291 commit f58872f

File tree

3 files changed

+92
-2
lines changed

3 files changed

+92
-2
lines changed

Documentation/spi/spi-summary.rst

+83
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,89 @@ queue, and then start some asynchronous transfer engine (unless it's
614614
already running).
615615

616616

617+
Extensions to the SPI protocol
618+
------------------------------
619+
The fact that SPI doesn't have a formal specification or standard permits chip
620+
manufacturers to implement the SPI protocol in slightly different ways. In most
621+
cases, SPI protocol implementations from different vendors are compatible among
622+
each other. For example, in SPI mode 0 (CPOL=0, CPHA=0) the bus lines may behave
623+
like the following:
624+
625+
::
626+
627+
nCSx ___ ___
628+
\_________________________________________________________________/
629+
• •
630+
• •
631+
SCLK ___ ___ ___ ___ ___ ___ ___ ___
632+
_______/ \___/ \___/ \___/ \___/ \___/ \___/ \___/ \_____
633+
• : ; : ; : ; : ; : ; : ; : ; : ; •
634+
• : ; : ; : ; : ; : ; : ; : ; : ; •
635+
MOSI XXX__________ _______ _______ ________XXX
636+
0xA5 XXX__/ 1 \_0_____/ 1 \_0_______0_____/ 1 \_0_____/ 1 \_XXX
637+
• ; ; ; ; ; ; ; ; •
638+
• ; ; ; ; ; ; ; ; •
639+
MISO XXX__________ _______________________ _______ XXX
640+
0xBA XXX__/ 1 \_____0_/ 1 1 1 \_____0__/ 1 \____0__XXX
641+
642+
Legend::
643+
644+
• marks the start/end of transmission;
645+
: marks when data is clocked into the peripheral;
646+
; marks when data is clocked into the controller;
647+
X marks when line states are not specified.
648+
649+
In some few cases, chips extend the SPI protocol by specifying line behaviors
650+
that other SPI protocols don't (e.g. data line state for when CS is not
651+
asserted). Those distinct SPI protocols, modes, and configurations are supported
652+
by different SPI mode flags.
653+
654+
MOSI idle state configuration
655+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
656+
657+
Common SPI protocol implementations don't specify any state or behavior for the
658+
MOSI line when the controller is not clocking out data. However, there do exist
659+
peripherals that require specific MOSI line state when data is not being clocked
660+
out. For example, if the peripheral expects the MOSI line to be high when the
661+
controller is not clocking out data (``SPI_MOSI_IDLE_HIGH``), then a transfer in
662+
SPI mode 0 would look like the following:
663+
664+
::
665+
666+
nCSx ___ ___
667+
\_________________________________________________________________/
668+
• •
669+
• •
670+
SCLK ___ ___ ___ ___ ___ ___ ___ ___
671+
_______/ \___/ \___/ \___/ \___/ \___/ \___/ \___/ \_____
672+
• : ; : ; : ; : ; : ; : ; : ; : ; •
673+
• : ; : ; : ; : ; : ; : ; : ; : ; •
674+
MOSI _____ _______ _______ _______________ ___
675+
0x56 \_0_____/ 1 \_0_____/ 1 \_0_____/ 1 1 \_0_____/
676+
• ; ; ; ; ; ; ; ; •
677+
• ; ; ; ; ; ; ; ; •
678+
MISO XXX__________ _______________________ _______ XXX
679+
0xBA XXX__/ 1 \_____0_/ 1 1 1 \_____0__/ 1 \____0__XXX
680+
681+
Legend::
682+
683+
• marks the start/end of transmission;
684+
: marks when data is clocked into the peripheral;
685+
; marks when data is clocked into the controller;
686+
X marks when line states are not specified.
687+
688+
In this extension to the usual SPI protocol, the MOSI line state is specified to
689+
be kept high when CS is asserted but the controller is not clocking out data to
690+
the peripheral and also when CS is not asserted.
691+
692+
Peripherals that require this extension must request it by setting the
693+
``SPI_MOSI_IDLE_HIGH`` bit into the mode attribute of their ``struct
694+
spi_device`` and call spi_setup(). Controllers that support this extension
695+
should indicate it by setting ``SPI_MOSI_IDLE_HIGH`` in the mode_bits attribute
696+
of their ``struct spi_controller``. The configuration to idle MOSI low is
697+
analogous but uses the ``SPI_MOSI_IDLE_LOW`` mode bit.
698+
699+
617700
THANKS TO
618701
---------
619702
Contributors to Linux-SPI discussions include (in alphabetical order,

drivers/spi/spi.c

+6
Original file line numberDiff line numberDiff line change
@@ -3921,6 +3921,12 @@ int spi_setup(struct spi_device *spi)
39213921
(SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL |
39223922
SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL)))
39233923
return -EINVAL;
3924+
/* Check against conflicting MOSI idle configuration */
3925+
if ((spi->mode & SPI_MOSI_IDLE_LOW) && (spi->mode & SPI_MOSI_IDLE_HIGH)) {
3926+
dev_err(&spi->dev,
3927+
"setup: MOSI configured to idle low and high at the same time.\n");
3928+
return -EINVAL;
3929+
}
39243930
/*
39253931
* Help drivers fail *cleanly* when they need options
39263932
* that aren't supported with their current controller.

include/uapi/linux/spi/spi.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828
#define SPI_RX_OCTAL _BITUL(14) /* receive with 8 wires */
2929
#define SPI_3WIRE_HIZ _BITUL(15) /* high impedance turnaround */
3030
#define SPI_RX_CPHA_FLIP _BITUL(16) /* flip CPHA on Rx only xfer */
31-
#define SPI_MOSI_IDLE_LOW _BITUL(17) /* leave mosi line low when idle */
31+
#define SPI_MOSI_IDLE_LOW _BITUL(17) /* leave MOSI line low when idle */
32+
#define SPI_MOSI_IDLE_HIGH _BITUL(18) /* leave MOSI line high when idle */
3233

3334
/*
3435
* All the bits defined above should be covered by SPI_MODE_USER_MASK.
@@ -38,6 +39,6 @@
3839
* These bits must not overlap. A static assert check should make sure of that.
3940
* If adding extra bits, make sure to increase the bit index below as well.
4041
*/
41-
#define SPI_MODE_USER_MASK (_BITUL(18) - 1)
42+
#define SPI_MODE_USER_MASK (_BITUL(19) - 1)
4243

4344
#endif /* _UAPI_SPI_H */

0 commit comments

Comments
 (0)