mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2026-05-02 03:11:04 +02:00
spi: stm32: add support for bits-per-word setting
Implement the set_wordlen operation to allow dynamic bus width configuration. This is required for peripherals with non-standard requirements, such as display panels that need 9-bit word transfers during the initialization and setup phase. Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com> Reviewed-by: Patrice Chotard <patrice.chotard@foss.st.com>
This commit is contained in:
parent
dd5002856a
commit
011feb0028
@ -384,6 +384,44 @@ static int stm32_spi_set_speed(struct udevice *bus, uint hz)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _stm32_spi_set_wordlen(struct udevice *bus, unsigned int wordlen)
|
||||
{
|
||||
struct stm32_spi_priv *priv = dev_get_priv(bus);
|
||||
struct stm32_spi_plat *plat = dev_get_plat(bus);
|
||||
void __iomem *base = plat->base;
|
||||
bool spi_enabled;
|
||||
|
||||
if ((wordlen - 1) < SPI_CFG1_DSIZE_MIN ||
|
||||
(wordlen - 1) > SPI_CFG1_DSIZE) {
|
||||
dev_err(bus, "Cannot set wordlen to %u [%d - %ld]\n",
|
||||
wordlen, SPI_CFG1_DSIZE_MIN + 1,
|
||||
SPI_CFG1_DSIZE + 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spi_enabled = stm32_spi_is_enabled(plat->base);
|
||||
if (spi_enabled)
|
||||
stm32_spi_disable(plat->base);
|
||||
|
||||
dev_dbg(bus, "bits_per_word=%d\n", wordlen);
|
||||
|
||||
priv->cur_bpw = wordlen;
|
||||
clrsetbits_le32(base + STM32_SPI_CFG1, SPI_CFG1_DSIZE,
|
||||
priv->cur_bpw - 1);
|
||||
|
||||
if (spi_enabled)
|
||||
stm32_spi_enable(plat->base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_spi_set_wordlen(struct udevice *slave, unsigned int wordlen)
|
||||
{
|
||||
struct udevice *bus = dev_get_parent(slave);
|
||||
|
||||
return _stm32_spi_set_wordlen(bus, wordlen);
|
||||
}
|
||||
|
||||
static int stm32_spi_xfer(struct udevice *slave, unsigned int bitlen,
|
||||
const void *dout, void *din, unsigned long flags)
|
||||
{
|
||||
@ -397,11 +435,19 @@ static int stm32_spi_xfer(struct udevice *slave, unsigned int bitlen,
|
||||
u32 xferlen;
|
||||
u32 mode;
|
||||
int xfer_status = 0;
|
||||
int nb_words;
|
||||
|
||||
xferlen = bitlen / 8;
|
||||
|
||||
if (xferlen <= SPI_CR2_TSIZE)
|
||||
writel(xferlen, base + STM32_SPI_CR2);
|
||||
if (priv->cur_bpw <= 8)
|
||||
nb_words = xferlen;
|
||||
else if (priv->cur_bpw <= 16)
|
||||
nb_words = DIV_ROUND_UP(xferlen * 8, 16);
|
||||
else
|
||||
nb_words = DIV_ROUND_UP(xferlen * 8, 32);
|
||||
|
||||
if (nb_words <= SPI_CR2_TSIZE)
|
||||
writel(nb_words, base + STM32_SPI_CR2);
|
||||
else
|
||||
return -EMSGSIZE;
|
||||
|
||||
@ -409,6 +455,8 @@ static int stm32_spi_xfer(struct udevice *slave, unsigned int bitlen,
|
||||
priv->rx_buf = din;
|
||||
priv->tx_len = priv->tx_buf ? xferlen : 0;
|
||||
priv->rx_len = priv->rx_buf ? xferlen : 0;
|
||||
dev_dbg(bus, "bitlen: %d, xferlen: %d, nb_words: %d\n",
|
||||
bitlen, xferlen, nb_words);
|
||||
|
||||
mode = SPI_FULL_DUPLEX;
|
||||
if (!priv->tx_buf)
|
||||
@ -570,9 +618,7 @@ static int stm32_spi_probe(struct udevice *dev)
|
||||
priv->fifo_size = stm32_spi_get_fifo_size(dev);
|
||||
priv->cur_mode = SPI_FULL_DUPLEX;
|
||||
priv->cur_xferlen = 0;
|
||||
priv->cur_bpw = SPI_DEFAULT_WORDLEN;
|
||||
clrsetbits_le32(base + STM32_SPI_CFG1, SPI_CFG1_DSIZE,
|
||||
priv->cur_bpw - 1);
|
||||
_stm32_spi_set_wordlen(dev, SPI_DEFAULT_WORDLEN);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(plat->cs_gpios); i++) {
|
||||
if (!dm_gpio_is_valid(&plat->cs_gpios[i]))
|
||||
@ -633,6 +679,7 @@ static const struct dm_spi_ops stm32_spi_ops = {
|
||||
.release_bus = stm32_spi_release_bus,
|
||||
.set_mode = stm32_spi_set_mode,
|
||||
.set_speed = stm32_spi_set_speed,
|
||||
.set_wordlen = stm32_spi_set_wordlen,
|
||||
.xfer = stm32_spi_xfer,
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user