Add support for components requiring trailing clock after transfer
Subsystems (2)
cover Add support for components requiring trailing clock after transfer
Some components require a few clock cycles with chipselect off before or/and after the data transfer done with CS on.
Typically IDT 801034 QUAD PCM CODEC datasheet states "Note *: CCLK should have one cycle before CS goes low, and two cycles after CS goes high".
The cycles "before" are implicitely provided by all previous activity on the SPI bus. But the cycles "after" must be provided in order to achieve the SPI transfer.
In order to use that kind of component, implement a new option for SPI slaves in order to implement a trailing clock of a few bits with ChipSelect off at the end of the transfer.
This is based on a discussion we had a few years ago, see
https://lore.kernel.org/linux-spi/[email protected]/
IDT 801034 QUAD PCM CODEC datasheet can be found at
https://www.renesas.com/eu/en/document/dst/821034-data-sheet?language=en&r=24763
Christophe Leroy (2):
spi: Add new mode to generate additional clock cycles
spi: fsl-spi: Implement trailing clock mode
.../bindings/spi/spi-peripheral-props.yaml | 4 ++++ drivers/spi/spi-fsl-lib.c | 2 +- drivers/spi/spi-fsl-spi.c | 15 +++++++++++++-- drivers/spi/spi.c | 5 ++++- include/uapi/linux/spi/spi.h | 3 ++- 5 files changed, 24 insertions(+), 5 deletions(-)
Signature · 1 line
2.34.1
PATCH 1/2 spi: Add new mode to generate additional clock cycles
Some components require a few clock cycles with chipselect off before or/and after the data transfer done with CS on.
Typically IDT 801034 QUAD PCM CODEC datasheet states "Note *: CCLK should have one cycle before CS goes low, and two cycles after CS goes high".
The cycles "before" are implicitely provided by all previous activity on the SPI bus. But the cycles "after" must be provided in order to achieve the SPI transfer.
In order to use that kind of component, implement a new option for SPI slaves in order to implement a trailing clock of a few bits with ChipSelect off at the end of the transfer.
--- .../devicetree/bindings/spi/spi-peripheral-props.yaml | 4 ++++ drivers/spi/spi.c | 5 ++++- include/uapi/linux/spi/spi.h | 3 ++- 3 files changed, 10 insertions(+), 2 deletions(-)
Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml +4 -0
@@ -82,6 +82,10 @@ properties: description: Delay, in microseconds, after a write transfer. + spi-trailing-clock: + description: + Add a few clock cycles (minimum 2) with chipselect OFF after transfers. + # The controller specific properties go here. allOf: - $ref: cdns,qspi-nor-peripheral-props.yaml#
drivers/spi/spi.c +4 -1
@@ -2109,6 +2109,8 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi, spi->mode |=SPI_LSB_FIRST ;if (of_property_read_bool (nc,"spi-cs-high" )) spi->mode |=SPI_CS_HIGH ; +if (of_property_read_bool (nc,"spi-trailing-clock" )) + spi->mode |=SPI_TRAILING ;/* Device DUAL/QUAD mode */ if (!of_property_read_u32 (nc,"spi-tx-bus-width" , &value)) {
@@ -3538,12 +3540,13 @@ int spi_setup(struct spi_device *spi)trace_spi_setup (spi, status); -dev_dbg (&spi->dev,"setup mode %lu, %s%s%s%s%u bits/w, %u Hz max --> %d\n" , +dev_dbg (&spi->dev,"setup mode %lu, %s%s%s%s%s%u bits/w, %u Hz max --> %d\n" , spi->mode &SPI_MODE_X_MASK , (spi->mode &SPI_CS_HIGH ) ?"cs_high, " :"" , (spi->mode &SPI_LSB_FIRST ) ?"lsb, " :"" , (spi->mode &SPI_3WIRE ) ?"3wire, " :"" , (spi->mode &SPI_LOOP ) ?"loopback, " :"" , + (spi->mode &SPI_TRAILING ) ?"trailing clock, " :"" , spi->bits_per_word, spi->max_speed_hz, status);
include/uapi/linux/spi/spi.h +2 -1
@@ -27,6 +27,7 @@#define SPI_TX_OCTAL _BITUL(13)/* transmit with 8 wires */ #define SPI_RX_OCTAL _BITUL(14)/* receive with 8 wires */ #define SPI_3WIRE_HIZ _BITUL(15)/* high impedance turnaround */ +#define SPI_TRAILING _BITUL(16)/* trailing clock needed */ /* * All the bits defined above should be covered by SPI_MODE_USER_MASK.
@@ -36,6 +37,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(16) - 1) +#define SPI_MODE_USER_MASK (_BITUL(17) - 1)#endif /* _UAPI_SPI_H */
Signature · 1 line
2.34.1
Mark Brown
maintainerRe: [PATCH v1 1/2] spi: Add new mode to generate additional clock cycles
Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml properties: · line 88
Quoted 4 lines · Christophe Leroy
Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml +4
-0+ spi-trailing-clock: + description: + Add a few clock cycles (minimum 2) with chipselect OFF after transfers. +
We should make this a specification of the actual requirement, not just a boolean with a vague "a few" requirement - with the above we'd have to add a new property if some device turns up which requires three clocks instead of two.
PATCH 2/2 spi: fsl-spi: Implement trailing clock mode
In reply to Christophe LeroyIn order to support IDT 801034 QUAD PCM CODEC, implement the trailing clock mode.
On fsl SPI, the minimum we can implement is a 4 bits shot.
--- drivers/spi/spi-fsl-lib.c | 2 +- drivers/spi/spi-fsl-spi.c | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-)
drivers/spi/spi-fsl-lib.c +1 -1
@@ -88,7 +88,7 @@ void mpc8xxx_spi_probe(struct device *dev, struct resource *mem,/* the spi->mode bits understood by this driver: */ master->mode_bits =SPI_CPOL |SPI_CPHA |SPI_CS_HIGH - |SPI_LSB_FIRST |SPI_LOOP ; + |SPI_LSB_FIRST |SPI_LOOP |SPI_TRAILING ; master->dev.of_node = dev->of_node;
drivers/spi/spi-fsl-spi.c +13 -2
@@ -424,13 +424,24 @@ static int fsl_spi_do_one_msg(struct spi_master *master, } } - m->status = status; -if (status || !cs_change) {ndelay (nsecs);fsl_spi_chipselect (spi,BITBANG_CS_INACTIVE ); } +if (!status && spi->mode &SPI_TRAILING ) { +struct spi_transfer t = { + .len =1 , + .tx_buf ="" , + .bits_per_word =4 + }; + + status =fsl_spi_setup_transfer (spi, &t); +if (!status) + status =fsl_spi_bufs (spi, &t,0 ); + } + m->status = status; +fsl_spi_setup_transfer (spi,NULL );spi_finalize_current_message (master);return 0 ;
Signature · 1 line
2.34.1
Mark Brown
maintainerRe: [PATCH v1 2/2] spi: fsl-spi: Implement trailing clock mode
drivers/spi/spi-fsl-spi.c static int fsl_spi_do_one_msg(struct spi_master *master, · line 443
Quoted 12 lines · Christophe Leroy
drivers/spi/spi-fsl-spi.c +12
-0+if (!status && spi->mode &SPI_TRAILING ) { +struct spi_transfer t = { + .len =1 , + .tx_buf ="" , + .bits_per_word =4 + }; + + status =fsl_spi_setup_transfer (spi, &t); +if (!status) + status =fsl_spi_bufs (spi, &t,0 ); + } + m->status = status;
This seems to be begging for a generic implementation in the core rather than being driver specific - drivers would for the most part need updating to advertise less than 8 bit per word transfers but the basic operation isn't really device specific and it pretty much fits with the existing interfaces.