drivers: spi: spi-stm32.c: add dali fec spi functionality

Signed-off-by: Philipp Hundsdörfer <Philipp.Hundsdoerfer@who-ing.de>
This commit is contained in:
Philipp Hundsdörfer
2025-03-24 11:52:25 +01:00
committed by Oleg Karfich
parent b272da5243
commit 22ca77d65a
+74 -3
View File
@@ -4,7 +4,7 @@
//
// Copyright (C) 2017, STMicroelectronics - All Rights Reserved
// Author(s): Amelie Delaunay <amelie.delaunay@st.com> for STMicroelectronics.
// Altered to support slave byte handshaking for DALI-FEC protocol
#include <linux/bitfield.h>
#include <linux/debugfs.h>
#include <linux/clk.h>
@@ -18,9 +18,16 @@
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/spi/spi.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#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);