From 22ca77d65a28a6c16df96601fe7f54f975e332a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Hundsd=C3=B6rfer?= Date: Mon, 24 Mar 2025 11:52:25 +0100 Subject: [PATCH] drivers: spi: spi-stm32.c: add dali fec spi functionality MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philipp Hundsdörfer --- drivers/spi/spi-stm32.c | 77 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index 40680b5fffc9..03c890a34e79 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -4,7 +4,7 @@ // // Copyright (C) 2017, STMicroelectronics - All Rights Reserved // Author(s): Amelie Delaunay for STMicroelectronics. - +// Altered to support slave byte handshaking for DALI-FEC protocol #include #include #include @@ -18,9 +18,16 @@ #include #include #include +#include +#include #define DRIVER_NAME "spi_stm32" +// Maximum retries for detection of DALI-FEC byte handshaking +#define DALI_FEC_SYNC_CYCLES 30 +// Sleep time between retries for detection of DALI-FEC byte handshaking in µs +#define DALI_FEC_SYNC_SLEEP_US 10 + /* STM32F4 SPI registers */ #define STM32F4_SPI_CR1 0x00 #define STM32F4_SPI_CR2 0x04 @@ -321,6 +328,8 @@ struct stm32_spi { dma_addr_t phys_addr; bool device_mode; + // slave gpio for optional handshaking + struct gpio_desc *gpio_slave; }; static const struct stm32_spi_regspec stm32f4_spi_regspec = { @@ -373,6 +382,24 @@ static inline void stm32_spi_clr_bits(struct stm32_spi *spi, spi->base + offset); } +/** + * wait_for_gpio_change - check for change of gpio state + * @gpio: pointer to the gpio descriptor + */ +int wait_for_gpio_change(struct gpio_desc *gpio) +{ + int cnt = 0, initialstate = gpiod_get_value(gpio); + + for (cnt = 0; cnt < DALI_FEC_SYNC_CYCLES; cnt++) { + usleep_range(DALI_FEC_SYNC_SLEEP_US, DALI_FEC_SYNC_SLEEP_US + DIV_ROUND_UP(DALI_FEC_SYNC_SLEEP_US, 2)); + // test for signal change + if (gpiod_get_value(gpio) != initialstate) + break; + } + + return 0; +} + /** * stm32h7_spi_get_fifo_size - Return fifo size * @spi: pointer to the spi controller data structure @@ -556,6 +583,39 @@ static void stm32h7_spi_write_txfifo(struct stm32_spi *spi) dev_dbg(spi->dev, "%s: %d bytes left\n", __func__, spi->tx_len); } + +/** + * stm32h7_spi_write_txfifo_gpio_slave - Write bytes in Transmit Data Register + * @spi: pointer to the spi controller data structure + * + * Read from tx_buf depends on remaining bytes to avoid to read beyond + * tx_buf end. + * Use gpio slave handshaking when transferring data. + */ +static void stm32h7_spi_write_txfifo_gpio_slave(struct stm32_spi *spi) +{ + // wait for dali fec byte request + wait_for_gpio_change(spi->gpio_slave); + + // transmit single bytes with delay + while ((spi->tx_len > 0) && + (readl_relaxed(spi->base + STM32H7_SPI_SR) & STM32H7_SPI_SR_TXP)) { + u32 offs = spi->cur_xferlen - spi->tx_len; + const u8 *tx_buf8 = (const u8 *)(spi->tx_buf + offs); + + writeb_relaxed(*tx_buf8, spi->base + STM32H7_SPI_TXDR); + spi->tx_len -= sizeof(u8); + + stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_CSTART); + + // for dali fec byte request + wait_for_gpio_change(spi->gpio_slave); + } + usleep_range(300, 330); + + dev_dbg(spi->dev, "%s: %d bytes left\n", __func__, spi->tx_len); +} + /** * stm32f4_spi_read_rx - Read bytes from Receive Data Register * @spi: pointer to the spi controller data structure @@ -1185,8 +1245,16 @@ static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi) stm32_spi_enable(spi); /* Be sure to have data in fifo before starting data transfer */ - if (spi->tx_buf) - stm32h7_spi_write_txfifo(spi); + if (spi->tx_buf) { + // check for gpio slave handshake activation + if (spi->gpio_slave) { + // gpio slave handshaking activate + stm32h7_spi_write_txfifo_gpio_slave(spi); + } else { + // gpio slave handshaking not activated + stm32h7_spi_write_txfifo(spi); + } + } if (STM32_SPI_MASTER_MODE(spi)) stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_CSTART); @@ -1834,6 +1902,9 @@ static int stm32_spi_probe(struct platform_device *pdev) spi->device_mode = device_mode; spin_lock_init(&spi->lock); + // allocate optional slave handshake gpio if available + spi->gpio_slave = devm_gpiod_get_optional(spi->dev, "dalifec,slave", GPIOD_IN); + spi->cfg = cfg; spi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);