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:
committed by
Oleg Karfich
parent
b272da5243
commit
22ca77d65a
+74
-3
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user