This partially reverts 22bc630d9f94d0eb4a38a0adc0910a70570f7500 because it is *not* safe to write 8- or 16-bit. The write to PUSHR does *not* depend on the state of the FIFO enabled/disabled.
cmd_info is new uint32_t member added to the kinetis_spidev_s struct. Then, ((priv->cmd_info & 0xffff0000) | SPI_PUSHR_TXDATA(word)) is being written to the PUSHR when sending word via SPI. Why? K60 Reference Manual (K60P144M150SF3RM.pdf) states that 8- or 16-bit write access to the PUSHR transfers all 32 bits to the TX FIFO (53.3.7). My observation is that 8-bit 0xff (or 16-bit 0xffff) write to the PUSHR results in 0xfcffffff in the TX FIFO (these two 0 are reserved in the PUSHR; read to PUSHR returns topmost TX FIFO.) In the SPI Master mode, top 16 bits are command information (different timing and frame size given by CTAS, which periphery to assert given by PCS) and low 16 bits are used for data. The unfortunate thing is that when sending data in the kinetis_spi.c's spi_writeword procedure, we use spi_putreg16, effectively re-using data as command information. With cmd_info, 32-bit write to the PUSHR is explicit. Then, set PCS procedure kinetis_spisetpcs is used to update the cmd_info to reflect what Periphary Chip Select (PCS) to use; we need some way to set PCS from within the kinetis_spi[n]select procedures. Signed-off-by: Jiri Vlasak <[email protected]> --- arch/arm/src/kinetis/kinetis_spi.c | 72 +++++++++++++++++++++--------- arch/arm/src/kinetis/kinetis_spi.h | 29 ++++++++++++ 2 files changed, 81 insertions(+), 20 deletions(-) diff --git a/arch/arm/src/kinetis/kinetis_spi.c b/arch/arm/src/kinetis/kinetis_spi.c index e66fc7603f..216640f8e1 100644 --- a/arch/arm/src/kinetis/kinetis_spi.c +++ b/arch/arm/src/kinetis/kinetis_spi.c @@ -99,6 +99,7 @@ struct kinetis_spidev_s struct spi_dev_s spidev; /* Externally visible part of the SPI interface */ uint32_t spibase; /* Base address of SPI registers */ mutex_t lock; /* Held while chip is selected for mutual exclusion */ + uint32_t cmd_info; /* Upper 16 bits of PUSHR register. */ uint32_t frequency; /* Requested clock frequency */ uint32_t actual; /* Actual clock frequency */ uint8_t nbits; /* Width of word in bits (8 to 16) */ @@ -235,6 +236,7 @@ static struct kinetis_spidev_s g_spi0dev = }, .spibase = KINETIS_SPI0_BASE, .lock = NXMUTEX_INITIALIZER, + .cmd_info = 0, .ctarsel = KINETIS_SPI_CTAR0_OFFSET, #ifdef CONFIG_KINETIS_SPI_DMA # ifdef CONFIG_KINETIS_SPI0_DMA @@ -290,6 +292,7 @@ static struct kinetis_spidev_s g_spi1dev = }, .spibase = KINETIS_SPI1_BASE, .lock = NXMUTEX_INITIALIZER, + .cmd_info = 0, .ctarsel = KINETIS_SPI_CTAR0_OFFSET, #ifdef CONFIG_KINETIS_SPI_DMA # ifdef CONFIG_KINETIS_SPI1_DMA @@ -345,6 +348,7 @@ static struct kinetis_spidev_s g_spi2dev = }, .spibase = KINETIS_SPI2_BASE, .lock = NXMUTEX_INITIALIZER, + .cmd_info = 0, .ctarsel = KINETIS_SPI_CTAR0_OFFSET, #ifdef CONFIG_KINETIS_SPI_DMA # ifdef CONFIG_KINETIS_SPI2_DMA @@ -597,27 +601,10 @@ static inline void spi_writeword(struct kinetis_spidev_s *priv, spi_wait_status(priv, SPI_SR_TFFF); - if (mcr & SPI_MCR_DIS_TXF) - { - /* FIFO disabled: 32-bit write including control + data */ + /* Write the data to transmitted to the SPI Data Register */ - pushr_val = SPI_PUSHR_TXDATA(word); - - if (first_word) - { - /* Set Control word */ - - pushr_val |= SPI_PUSHR_CTAS_CTAR0 | SPI_PUSHR_CTCNT; - } - - spi_putreg(priv, KINETIS_SPI_PUSHR_OFFSET, pushr_val); - } - else - { - /* FIFO enabled: write only data; control handled separately */ - - spi_putreg16(priv, KINETIS_SPI_PUSHR_OFFSET, SPI_PUSHR_TXDATA(word)); - } + spi_putreg(priv, KINETIS_SPI_PUSHR_OFFSET, + (priv->cmd_info & 0xffff0000) | SPI_PUSHR_TXDATA(word)); } /**************************************************************************** @@ -1942,4 +1929,49 @@ struct spi_dev_s *kinetis_spibus_initialize(int port) return &priv->spidev; } +/**************************************************************************** + * Name: kinetis_spisetpcs + * + * Description: + * Set which Periphery Chip Select (PCS, 0-5) to use for the given SPI dev. + * + * We can use PCS field of the Kinetis' PUSHR register to select periphery + * chips, provided that the relevant PIN is set with the appropriate ALT + * configuration. + * + * However, both, command information and data, must be written to the PUSHR + * at once; this is the reason for cmd_info of the kinetis_spidev_s struct. + * But kinetis_spidev_s is private and so we need some public way to set + * wanted PCS. + * + * kinetis_spisetpcs is to be used from within the kinetis_spi[n]select + * procedures when Kinetis' PCS are to be used. + * + * Input Parameters: + * dev - Device-specific state data + * which - Which Periphery Chip Select (PCS, 0-5) to use or -1. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void kinetis_spisetpcs(struct spi_dev_s *dev, int8_t which) +{ + struct kinetis_spidev_s *priv = (struct kinetis_spidev_s *)dev; + + if (-1 <= which && which <= 5) + { + priv->cmd_info &= ~SPI_PUSHR_PCS_MASK; + if (0 <= which) + { + priv->cmd_info |= SPI_PUSHR_PCS(which); + } + } + else + { + spierr("ERROR: -1 <= which PCS <= 5 but %d provided", which); + } +} + #endif /* CONFIG_KINETIS_SPI0 || CONFIG_KINETIS_SPI1 || CONFIG_KINETIS_SPI2 */ diff --git a/arch/arm/src/kinetis/kinetis_spi.h b/arch/arm/src/kinetis/kinetis_spi.h index 972d35b1c6..2f69c19eca 100644 --- a/arch/arm/src/kinetis/kinetis_spi.h +++ b/arch/arm/src/kinetis/kinetis_spi.h @@ -72,6 +72,35 @@ struct spi_dev_s; struct spi_dev_s *kinetis_spibus_initialize(int bus); +/**************************************************************************** + * Name: kinetis_spisetpcs + * + * Description: + * Set which Periphery Chip Select (PCS, 0-5) to use for the given SPI dev. + * + * We can use PCS field of the Kinetis' PUSHR register to select periphery + * chips, provided that the relevant PIN is set with the appropriate ALT + * configuration. + * + * However, both, command information and data, must be written to the PUSHR + * at once; this is the reason for cmd_info of the kinetis_spidev_s struct. + * But kinetis_spidev_s is private and so we need some public way to set + * wanted PCS. + * + * kinetis_spisetpcs is to be used from within the kinetis_spi[n]select + * procedures when Kinetis' PCS are to be used. + * + * Input Parameters: + * dev - Device-specific state data + * which - Which Periphery Chip Select (PCS, 0-5) to use or -1. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void kinetis_spisetpcs(struct spi_dev_s *dev, int8_t which); + /**************************************************************************** * Name: * kinetis_spi[n]select, kinetis_spi[n]status, and kinetis_spi[n]cmddata -- 2.47.3
