Re: [PATCH] spi/omap2_mcspi: Verify TX reg is empty after TX only xfer with DMA
On Wed, Oct 20, 2010 at 09:23:57AM -0700, Tony Lindgren wrote: > * Ilkka Koskinen [101019 06:55]: > > In case of TX only with DMA, the driver assumes that the data > > has been transferred once DMA callback in invoked. However, > > SPI's shift register may still contain data. Thus, the driver > > is supposed to verify that the register is empty and the end of > > the SPI transfer has been reached. > > > > Signed-off-by: Ilkka Koskinen > > Tested-by: Tuomas Katila > > Grant, can you please queue this one? > > Acked-by: Tony Lindgren Applied, thanks. g. > > > > --- > > drivers/spi/omap2_mcspi.c | 39 ++- > > 1 files changed, 26 insertions(+), 13 deletions(-) > > > > diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c > > index b3a94ca..a2e053c 100644 > > --- a/drivers/spi/omap2_mcspi.c > > +++ b/drivers/spi/omap2_mcspi.c > > @@ -296,6 +296,19 @@ static int omap2_mcspi_enable_clocks(struct > > omap2_mcspi *mcspi) > > return 0; > > } > > > > +static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit) > > +{ > > + unsigned long timeout; > > + > > + timeout = jiffies + msecs_to_jiffies(1000); > > + while (!(__raw_readl(reg) & bit)) { > > + if (time_after(jiffies, timeout)) > > + return -1; > > + cpu_relax(); > > + } > > + return 0; > > +} > > + > > static unsigned > > omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) > > { > > @@ -309,11 +322,14 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct > > spi_transfer *xfer) > > u32 l; > > u8 * rx; > > const u8* tx; > > + void __iomem*chstat_reg; > > > > mcspi = spi_master_get_devdata(spi->master); > > mcspi_dma = &mcspi->dma_channels[spi->chip_select]; > > l = mcspi_cached_chconf0(spi); > > > > + chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0; > > + > > count = xfer->len; > > c = count; > > word_len = cs->word_len; > > @@ -382,6 +398,16 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct > > spi_transfer *xfer) > > if (tx != NULL) { > > wait_for_completion(&mcspi_dma->dma_tx_completion); > > dma_unmap_single(NULL, xfer->tx_dma, count, DMA_TO_DEVICE); > > + > > + /* for TX_ONLY mode, be sure all words have shifted out */ > > + if (rx == NULL) { > > + if (mcspi_wait_for_reg_bit(chstat_reg, > > + OMAP2_MCSPI_CHSTAT_TXS) < 0) > > + dev_err(&spi->dev, "TXS timed out\n"); > > + else if (mcspi_wait_for_reg_bit(chstat_reg, > > + OMAP2_MCSPI_CHSTAT_EOT) < 0) > > + dev_err(&spi->dev, "EOT timed out\n"); > > + } > > } > > > > if (rx != NULL) { > > @@ -435,19 +461,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct > > spi_transfer *xfer) > > return count; > > } > > > > -static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit) > > -{ > > - unsigned long timeout; > > - > > - timeout = jiffies + msecs_to_jiffies(1000); > > - while (!(__raw_readl(reg) & bit)) { > > - if (time_after(jiffies, timeout)) > > - return -1; > > - cpu_relax(); > > - } > > - return 0; > > -} > > - > > static unsigned > > omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) > > { > > -- > > 1.6.0.4 > > -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] spi/omap2_mcspi: Verify TX reg is empty after TX only xfer with DMA
* Ilkka Koskinen [101019 06:55]: > In case of TX only with DMA, the driver assumes that the data > has been transferred once DMA callback in invoked. However, > SPI's shift register may still contain data. Thus, the driver > is supposed to verify that the register is empty and the end of > the SPI transfer has been reached. > > Signed-off-by: Ilkka Koskinen > Tested-by: Tuomas Katila Grant, can you please queue this one? Acked-by: Tony Lindgren > --- > drivers/spi/omap2_mcspi.c | 39 ++- > 1 files changed, 26 insertions(+), 13 deletions(-) > > diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c > index b3a94ca..a2e053c 100644 > --- a/drivers/spi/omap2_mcspi.c > +++ b/drivers/spi/omap2_mcspi.c > @@ -296,6 +296,19 @@ static int omap2_mcspi_enable_clocks(struct omap2_mcspi > *mcspi) > return 0; > } > > +static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit) > +{ > + unsigned long timeout; > + > + timeout = jiffies + msecs_to_jiffies(1000); > + while (!(__raw_readl(reg) & bit)) { > + if (time_after(jiffies, timeout)) > + return -1; > + cpu_relax(); > + } > + return 0; > +} > + > static unsigned > omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) > { > @@ -309,11 +322,14 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct > spi_transfer *xfer) > u32 l; > u8 * rx; > const u8* tx; > + void __iomem*chstat_reg; > > mcspi = spi_master_get_devdata(spi->master); > mcspi_dma = &mcspi->dma_channels[spi->chip_select]; > l = mcspi_cached_chconf0(spi); > > + chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0; > + > count = xfer->len; > c = count; > word_len = cs->word_len; > @@ -382,6 +398,16 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct > spi_transfer *xfer) > if (tx != NULL) { > wait_for_completion(&mcspi_dma->dma_tx_completion); > dma_unmap_single(NULL, xfer->tx_dma, count, DMA_TO_DEVICE); > + > + /* for TX_ONLY mode, be sure all words have shifted out */ > + if (rx == NULL) { > + if (mcspi_wait_for_reg_bit(chstat_reg, > + OMAP2_MCSPI_CHSTAT_TXS) < 0) > + dev_err(&spi->dev, "TXS timed out\n"); > + else if (mcspi_wait_for_reg_bit(chstat_reg, > + OMAP2_MCSPI_CHSTAT_EOT) < 0) > + dev_err(&spi->dev, "EOT timed out\n"); > + } > } > > if (rx != NULL) { > @@ -435,19 +461,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct > spi_transfer *xfer) > return count; > } > > -static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit) > -{ > - unsigned long timeout; > - > - timeout = jiffies + msecs_to_jiffies(1000); > - while (!(__raw_readl(reg) & bit)) { > - if (time_after(jiffies, timeout)) > - return -1; > - cpu_relax(); > - } > - return 0; > -} > - > static unsigned > omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) > { > -- > 1.6.0.4 > -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] spi/omap2_mcspi: Verify TX reg is empty after TX only xfer with DMA
In case of TX only with DMA, the driver assumes that the data has been transferred once DMA callback in invoked. However, SPI's shift register may still contain data. Thus, the driver is supposed to verify that the register is empty and the end of the SPI transfer has been reached. Signed-off-by: Ilkka Koskinen Tested-by: Tuomas Katila --- drivers/spi/omap2_mcspi.c | 39 ++- 1 files changed, 26 insertions(+), 13 deletions(-) diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c index b3a94ca..a2e053c 100644 --- a/drivers/spi/omap2_mcspi.c +++ b/drivers/spi/omap2_mcspi.c @@ -296,6 +296,19 @@ static int omap2_mcspi_enable_clocks(struct omap2_mcspi *mcspi) return 0; } +static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit) +{ + unsigned long timeout; + + timeout = jiffies + msecs_to_jiffies(1000); + while (!(__raw_readl(reg) & bit)) { + if (time_after(jiffies, timeout)) + return -1; + cpu_relax(); + } + return 0; +} + static unsigned omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) { @@ -309,11 +322,14 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) u32 l; u8 * rx; const u8* tx; + void __iomem*chstat_reg; mcspi = spi_master_get_devdata(spi->master); mcspi_dma = &mcspi->dma_channels[spi->chip_select]; l = mcspi_cached_chconf0(spi); + chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0; + count = xfer->len; c = count; word_len = cs->word_len; @@ -382,6 +398,16 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) if (tx != NULL) { wait_for_completion(&mcspi_dma->dma_tx_completion); dma_unmap_single(NULL, xfer->tx_dma, count, DMA_TO_DEVICE); + + /* for TX_ONLY mode, be sure all words have shifted out */ + if (rx == NULL) { + if (mcspi_wait_for_reg_bit(chstat_reg, + OMAP2_MCSPI_CHSTAT_TXS) < 0) + dev_err(&spi->dev, "TXS timed out\n"); + else if (mcspi_wait_for_reg_bit(chstat_reg, + OMAP2_MCSPI_CHSTAT_EOT) < 0) + dev_err(&spi->dev, "EOT timed out\n"); + } } if (rx != NULL) { @@ -435,19 +461,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) return count; } -static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit) -{ - unsigned long timeout; - - timeout = jiffies + msecs_to_jiffies(1000); - while (!(__raw_readl(reg) & bit)) { - if (time_after(jiffies, timeout)) - return -1; - cpu_relax(); - } - return 0; -} - static unsigned omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) { -- 1.6.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html