forked from luck/tmp_suning_uos_patched
spi: Fixes for v4.0
A collection of driver specific fixes to which the usual comments about them being important if you see them mostly apply (except for the comment fix). The pl022 one is particularly nasty for anyone affected by it. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJU+tr0AAoJECTWi3JdVIfQ4HIH/2p3AR8VJ1NzmqKslFUaC7SQ CT6iIiV+1gT+Q/2CLtTwY04gVJrmbO85pl4aotefxuCsb8YFGPCEo3f0lYU/3XwK ZQuC/7LFpWCqQCtSxoat9XQBHoFkWMrFDdsesQJLg9F46bCx/vVUuMaPrTXwSPLG DA6isoNZgEBJeKAxKhOdwT/nJUrVJhNwEX8fa/vuISnde4ckVuX+34O60V0N0/S2 7hEw3LQFZW0IPsnkmEygd5ATonK/+s7BXLwoAZWJGpZeWB1YsBUiHV7fLunj6gVy DMbKI3Fp1Yy/q0h6J+DzzbLvQxj0WTAX8EUz8PCh2QYRvUNiKeJdbKLbLUjGZgA= =Lpqm -----END PGP SIGNATURE----- Merge tag 'spi-v4.0-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi Pull spi fixes from Mark Brown: "A collection of driver specific fixes to which the usual comments about them being important if you see them mostly apply (except for the comment fix). The pl022 one is particularly nasty for anyone affected by it" * tag 'spi-v4.0-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: spi: pl022: Fix race in giveback() leading to driver lock-up spi: dw-mid: avoid potential NULL dereference spi: img-spfi: Verify max spfi transfer length spi: fix a typo in comment. spi: atmel: Fix interrupt setup for PDC transfers spi: dw: revisit FIFO size detection again spi: dw-pci: correct number of chip selects drivers: spi: ti-qspi: wait for busy bit clear before data write/read
This commit is contained in:
commit
d08edd8f09
|
@ -764,17 +764,17 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master,
|
|||
(unsigned long long)xfer->rx_dma);
|
||||
}
|
||||
|
||||
/* REVISIT: We're waiting for ENDRX before we start the next
|
||||
/* REVISIT: We're waiting for RXBUFF before we start the next
|
||||
* transfer because we need to handle some difficult timing
|
||||
* issues otherwise. If we wait for ENDTX in one transfer and
|
||||
* then starts waiting for ENDRX in the next, it's difficult
|
||||
* to tell the difference between the ENDRX interrupt we're
|
||||
* actually waiting for and the ENDRX interrupt of the
|
||||
* issues otherwise. If we wait for TXBUFE in one transfer and
|
||||
* then starts waiting for RXBUFF in the next, it's difficult
|
||||
* to tell the difference between the RXBUFF interrupt we're
|
||||
* actually waiting for and the RXBUFF interrupt of the
|
||||
* previous transfer.
|
||||
*
|
||||
* It should be doable, though. Just not now...
|
||||
*/
|
||||
spi_writel(as, IER, SPI_BIT(ENDRX) | SPI_BIT(OVRES));
|
||||
spi_writel(as, IER, SPI_BIT(RXBUFF) | SPI_BIT(OVRES));
|
||||
spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN));
|
||||
}
|
||||
|
||||
|
|
|
@ -139,6 +139,9 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_tx(struct dw_spi *dws)
|
|||
1,
|
||||
DMA_MEM_TO_DEV,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!txdesc)
|
||||
return NULL;
|
||||
|
||||
txdesc->callback = dw_spi_dma_tx_done;
|
||||
txdesc->callback_param = dws;
|
||||
|
||||
|
@ -184,6 +187,9 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx(struct dw_spi *dws)
|
|||
1,
|
||||
DMA_DEV_TO_MEM,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!rxdesc)
|
||||
return NULL;
|
||||
|
||||
rxdesc->callback = dw_spi_dma_rx_done;
|
||||
rxdesc->callback_param = dws;
|
||||
|
||||
|
|
|
@ -36,13 +36,13 @@ struct spi_pci_desc {
|
|||
|
||||
static struct spi_pci_desc spi_pci_mid_desc_1 = {
|
||||
.setup = dw_spi_mid_init,
|
||||
.num_cs = 32,
|
||||
.num_cs = 5,
|
||||
.bus_num = 0,
|
||||
};
|
||||
|
||||
static struct spi_pci_desc spi_pci_mid_desc_2 = {
|
||||
.setup = dw_spi_mid_init,
|
||||
.num_cs = 4,
|
||||
.num_cs = 2,
|
||||
.bus_num = 1,
|
||||
};
|
||||
|
||||
|
|
|
@ -621,14 +621,14 @@ static void spi_hw_init(struct device *dev, struct dw_spi *dws)
|
|||
if (!dws->fifo_len) {
|
||||
u32 fifo;
|
||||
|
||||
for (fifo = 2; fifo <= 256; fifo++) {
|
||||
for (fifo = 1; fifo < 256; fifo++) {
|
||||
dw_writew(dws, DW_SPI_TXFLTR, fifo);
|
||||
if (fifo != dw_readw(dws, DW_SPI_TXFLTR))
|
||||
break;
|
||||
}
|
||||
dw_writew(dws, DW_SPI_TXFLTR, 0);
|
||||
|
||||
dws->fifo_len = (fifo == 2) ? 0 : fifo - 1;
|
||||
dws->fifo_len = (fifo == 1) ? 0 : fifo;
|
||||
dev_dbg(dev, "Detected FIFO size: %u bytes\n", dws->fifo_len);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -459,6 +459,13 @@ static int img_spfi_transfer_one(struct spi_master *master,
|
|||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
if (xfer->len > SPFI_TRANSACTION_TSIZE_MASK) {
|
||||
dev_err(spfi->dev,
|
||||
"Transfer length (%d) is greater than the max supported (%d)",
|
||||
xfer->len, SPFI_TRANSACTION_TSIZE_MASK);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop all DMA and reset the controller if the previous transaction
|
||||
* timed-out and never completed it's DMA.
|
||||
|
|
|
@ -534,12 +534,12 @@ static void giveback(struct pl022 *pl022)
|
|||
pl022->cur_msg = NULL;
|
||||
pl022->cur_transfer = NULL;
|
||||
pl022->cur_chip = NULL;
|
||||
spi_finalize_current_message(pl022->master);
|
||||
|
||||
/* disable the SPI/SSP operation */
|
||||
writew((readw(SSP_CR1(pl022->virtbase)) &
|
||||
(~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase));
|
||||
|
||||
spi_finalize_current_message(pl022->master);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -101,6 +101,7 @@ struct ti_qspi {
|
|||
#define QSPI_FLEN(n) ((n - 1) << 0)
|
||||
|
||||
/* STATUS REGISTER */
|
||||
#define BUSY 0x01
|
||||
#define WC 0x02
|
||||
|
||||
/* INTERRUPT REGISTER */
|
||||
|
@ -199,6 +200,21 @@ static void ti_qspi_restore_ctx(struct ti_qspi *qspi)
|
|||
ti_qspi_write(qspi, ctx_reg->clkctrl, QSPI_SPI_CLOCK_CNTRL_REG);
|
||||
}
|
||||
|
||||
static inline u32 qspi_is_busy(struct ti_qspi *qspi)
|
||||
{
|
||||
u32 stat;
|
||||
unsigned long timeout = jiffies + QSPI_COMPLETION_TIMEOUT;
|
||||
|
||||
stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG);
|
||||
while ((stat & BUSY) && time_after(timeout, jiffies)) {
|
||||
cpu_relax();
|
||||
stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG);
|
||||
}
|
||||
|
||||
WARN(stat & BUSY, "qspi busy\n");
|
||||
return stat & BUSY;
|
||||
}
|
||||
|
||||
static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t)
|
||||
{
|
||||
int wlen, count;
|
||||
|
@ -211,6 +227,9 @@ static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t)
|
|||
wlen = t->bits_per_word >> 3; /* in bytes */
|
||||
|
||||
while (count) {
|
||||
if (qspi_is_busy(qspi))
|
||||
return -EBUSY;
|
||||
|
||||
switch (wlen) {
|
||||
case 1:
|
||||
dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %02x\n",
|
||||
|
@ -266,6 +285,9 @@ static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t)
|
|||
|
||||
while (count) {
|
||||
dev_dbg(qspi->dev, "rx cmd %08x dc %08x\n", cmd, qspi->dc);
|
||||
if (qspi_is_busy(qspi))
|
||||
return -EBUSY;
|
||||
|
||||
ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG);
|
||||
if (!wait_for_completion_timeout(&qspi->transfer_complete,
|
||||
QSPI_COMPLETION_TIMEOUT)) {
|
||||
|
|
|
@ -649,7 +649,7 @@ struct spi_transfer {
|
|||
* sequence completes. On some systems, many such sequences can execute as
|
||||
* as single programmed DMA transfer. On all systems, these messages are
|
||||
* queued, and might complete after transactions to other devices. Messages
|
||||
* sent to a given spi_device are alway executed in FIFO order.
|
||||
* sent to a given spi_device are always executed in FIFO order.
|
||||
*
|
||||
* The code that submits an spi_message (and its spi_transfers)
|
||||
* to the lower layers is responsible for managing its memory.
|
||||
|
|
Loading…
Reference in New Issue
Block a user