Message ID | 7eb23146ad6bf6090183c6340e4d59cb269d83a7.1719686465.git.marcelo.schmitt@analog.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | Add support for AD4000 series of ADCs | expand |
On Sat, 29 Jun 2024 16:04:40 -0300 Marcelo Schmitt <marcelo.schmitt@analog.com> wrote: > 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> > Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com> I always like to see some nice ascii art. Very nice documentation. Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> > diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c > index 93f59ebb5b79..c8ba5e490850 100644 > --- a/drivers/spi/spi.c > +++ b/drivers/spi/spi.c > @@ -3950,6 +3956,7 @@ int spi_setup(struct spi_device *spi) > */ > bad_bits = spi->mode & ~(spi->controller->mode_bits | SPI_CS_WORD | > SPI_NO_TX | SPI_NO_RX); > + Trivial grumpy comment. Don't touch white space in unrelated code! > ugly_bits = bad_bits & > (SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL | > SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL);
On 06/30, Jonathan Cameron wrote: > On Sat, 29 Jun 2024 16:04:40 -0300 > Marcelo Schmitt <marcelo.schmitt@analog.com> wrote: > > > 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> > > Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com> > > I always like to see some nice ascii art. Very nice documentation. > Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> > > > diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c > > index 93f59ebb5b79..c8ba5e490850 100644 > > --- a/drivers/spi/spi.c > > +++ b/drivers/spi/spi.c > > > @@ -3950,6 +3956,7 @@ int spi_setup(struct spi_device *spi) > > */ > > bad_bits = spi->mode & ~(spi->controller->mode_bits | SPI_CS_WORD | > > SPI_NO_TX | SPI_NO_RX); > > + > > Trivial grumpy comment. Don't touch white space in unrelated code! Ouf, must have slipped through after messing around with spi_setup(). Didn't intend to add that. Fine if that can be removed when applying the patch. > > > ugly_bits = bad_bits & > > (SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL | > > SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL);
On 6/29/24 2:04 PM, Marcelo Schmitt wrote: > 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> > Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com> > --- Tested both valid and invalid combinations of flags and saw expected behavior/error messages in all cases. Reviewed-by: David Lechner <dlechner@baylibre.com> Tested-by: David Lechner <dlechner@baylibre.com>
diff --git a/Documentation/spi/spi-summary.rst b/Documentation/spi/spi-summary.rst index 7f8accfae6f9..6e21e6f86912 100644 --- a/Documentation/spi/spi-summary.rst +++ b/Documentation/spi/spi-summary.rst @@ -614,6 +614,89 @@ queue, and then start some asynchronous transfer engine (unless it's already running). +Extensions to the SPI protocol +------------------------------ +The fact that SPI doesn't have a formal specification or standard permits chip +manufacturers to implement the SPI protocol in slightly different ways. In most +cases, SPI protocol implementations from different vendors are compatible among +each other. For example, in SPI mode 0 (CPOL=0, CPHA=0) the bus lines may behave +like the following: + +:: + + nCSx ___ ___ + \_________________________________________________________________/ + • • + • • + SCLK ___ ___ ___ ___ ___ ___ ___ ___ + _______/ \___/ \___/ \___/ \___/ \___/ \___/ \___/ \_____ + • : ; : ; : ; : ; : ; : ; : ; : ; • + • : ; : ; : ; : ; : ; : ; : ; : ; • + MOSI XXX__________ _______ _______ ________XXX + 0xA5 XXX__/ 1 \_0_____/ 1 \_0_______0_____/ 1 \_0_____/ 1 \_XXX + • ; ; ; ; ; ; ; ; • + • ; ; ; ; ; ; ; ; • + MISO XXX__________ _______________________ _______ XXX + 0xBA XXX__/ 1 \_____0_/ 1 1 1 \_____0__/ 1 \____0__XXX + +Legend:: + + • marks the start/end of transmission; + : marks when data is clocked into the peripheral; + ; marks when data is clocked into the controller; + X marks when line states are not specified. + +In some few cases, chips extend the SPI protocol by specifying line behaviors +that other SPI protocols don't (e.g. data line state for when CS is not +asserted). Those distinct SPI protocols, modes, and configurations are supported +by different SPI mode flags. + +MOSI idle state configuration +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Common SPI protocol implementations don't specify any state or behavior for the +MOSI line when the controller is not clocking out data. However, there do exist +peripherals that require specific MOSI line state when data is not being clocked +out. For example, if the peripheral expects the MOSI line to be high when the +controller is not clocking out data (``SPI_MOSI_IDLE_HIGH``), then a transfer in +SPI mode 0 would look like the following: + +:: + + nCSx ___ ___ + \_________________________________________________________________/ + • • + • • + SCLK ___ ___ ___ ___ ___ ___ ___ ___ + _______/ \___/ \___/ \___/ \___/ \___/ \___/ \___/ \_____ + • : ; : ; : ; : ; : ; : ; : ; : ; • + • : ; : ; : ; : ; : ; : ; : ; : ; • + MOSI _____ _______ _______ _______________ ___ + 0x56 \_0_____/ 1 \_0_____/ 1 \_0_____/ 1 1 \_0_____/ + • ; ; ; ; ; ; ; ; • + • ; ; ; ; ; ; ; ; • + MISO XXX__________ _______________________ _______ XXX + 0xBA XXX__/ 1 \_____0_/ 1 1 1 \_____0__/ 1 \____0__XXX + +Legend:: + + • marks the start/end of transmission; + : marks when data is clocked into the peripheral; + ; marks when data is clocked into the controller; + X marks when line states are not specified. + +In this extension to the usual SPI protocol, the MOSI line state is specified to +be kept high when CS is asserted but the controller is not clocking out data to +the peripheral and also when CS is not asserted. + +Peripherals that require this extension must request it by setting the +``SPI_MOSI_IDLE_HIGH`` bit into the mode attribute of their ``struct +spi_device`` and call spi_setup(). Controllers that support this extension +should indicate it by setting ``SPI_MOSI_IDLE_HIGH`` in the mode_bits attribute +of their ``struct spi_controller``. The configuration to idle MOSI low is +analogous but uses the ``SPI_MOSI_IDLE_LOW`` mode bit. + + THANKS TO --------- Contributors to Linux-SPI discussions include (in alphabetical order, diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 93f59ebb5b79..c8ba5e490850 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -3942,6 +3942,12 @@ int spi_setup(struct spi_device *spi) (SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL | SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL))) return -EINVAL; + /* Check against conflicting MOSI idle configuration */ + if ((spi->mode & SPI_MOSI_IDLE_LOW) && (spi->mode & SPI_MOSI_IDLE_HIGH)) { + dev_err(&spi->dev, + "setup: MOSI configured to idle low and high at the same time.\n"); + return -EINVAL; + } /* * Help drivers fail *cleanly* when they need options * that aren't supported with their current controller. @@ -3950,6 +3956,7 @@ int spi_setup(struct spi_device *spi) */ bad_bits = spi->mode & ~(spi->controller->mode_bits | SPI_CS_WORD | SPI_NO_TX | SPI_NO_RX); + ugly_bits = bad_bits & (SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL | SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL); diff --git a/include/uapi/linux/spi/spi.h b/include/uapi/linux/spi/spi.h index ca56e477d161..ee4ac812b8f8 100644 --- a/include/uapi/linux/spi/spi.h +++ b/include/uapi/linux/spi/spi.h @@ -28,7 +28,8 @@ #define SPI_RX_OCTAL _BITUL(14) /* receive with 8 wires */ #define SPI_3WIRE_HIZ _BITUL(15) /* high impedance turnaround */ #define SPI_RX_CPHA_FLIP _BITUL(16) /* flip CPHA on Rx only xfer */ -#define SPI_MOSI_IDLE_LOW _BITUL(17) /* leave mosi line low when idle */ +#define SPI_MOSI_IDLE_LOW _BITUL(17) /* leave MOSI line low when idle */ +#define SPI_MOSI_IDLE_HIGH _BITUL(18) /* leave MOSI line high when idle */ /* * All the bits defined above should be covered by SPI_MODE_USER_MASK. @@ -38,6 +39,6 @@ * These bits must not overlap. A static assert check should make sure of that. * If adding extra bits, make sure to increase the bit index below as well. */ -#define SPI_MODE_USER_MASK (_BITUL(18) - 1) +#define SPI_MODE_USER_MASK (_BITUL(19) - 1) #endif /* _UAPI_SPI_H */