val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
val &= ~(A3700_SPI_INST_PIN | A3700_SPI_ADDR_PIN);
val &= ~(A3700_SPI_DATA_PIN0 | A3700_SPI_DATA_PIN1);
switch (pin_mode) { case SPI_NBITS_SINGLE: break; case SPI_NBITS_DUAL:
val |= A3700_SPI_DATA_PIN0; break; case SPI_NBITS_QUAD:
val |= A3700_SPI_DATA_PIN1; /* RX during address reception uses 4-pin */ if (receiving)
val |= A3700_SPI_ADDR_PIN; break; default:
dev_err(&a3700_spi->host->dev, "wrong pin mode %u", pin_mode); return -EINVAL;
}
val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG); if (enable)
val |= A3700_SPI_FIFO_MODE; else
val &= ~A3700_SPI_FIFO_MODE;
spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
}
/* For prescaler values over 15, we can only set it by steps of 2. * Starting from A3700_SPI_CLK_EVEN_OFFS, we set values from 0 up to * 30. We only use this range from 16 to 30.
*/ if (prescale > 15)
prescale = A3700_SPI_CLK_EVEN_OFFS + DIV_ROUND_UP(prescale, 2);
val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
val = val & ~A3700_SPI_CLK_PRESCALE_MASK;
val = val | (prescale & A3700_SPI_CLK_PRESCALE_MASK);
spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
if (prescale <= 2) {
val = spireg_read(a3700_spi, A3700_SPI_IF_TIME_REG);
val |= A3700_SPI_CLK_CAPT_EDGE;
spireg_write(a3700_spi, A3700_SPI_IF_TIME_REG, val);
}
}
val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG); if (len == 4)
val |= A3700_SPI_BYTE_LEN; else
val &= ~A3700_SPI_BYTE_LEN;
spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
/* Reset SPI unit */
val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
val |= A3700_SPI_SRST;
spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
udelay(A3700_SPI_TIMEOUT);
val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
val &= ~A3700_SPI_SRST;
spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
/* Disable AUTO_CS and deactivate all chip-selects */
a3700_spi_auto_cs_unset(a3700_spi); for (i = 0; i < host->num_chipselect; i++)
a3700_spi_deactivate_cs(a3700_spi, i);
/* SPI interrupt is edge-triggered, which means an interrupt will * be generated only when detecting a specific status bit changed * from '0' to '1'. So when we start waiting for a interrupt, we * need to check status bit in control reg first, if it is already 1, * then we do not need to wait for interrupt
*/
ctrl_reg = spireg_read(a3700_spi, A3700_SPI_IF_CTRL_REG); if (a3700_spi->wait_mask & ctrl_reg) returntrue;
/* there might be the case that right after we checked the * status bits in this routine and before start to wait for * interrupt by wait_for_completion_timeout, the interrupt * happens, to avoid missing it we need to double check * status bits in control reg, if it is already 1, then * consider that we have the interrupt successfully and * return true.
*/
ctrl_reg = spireg_read(a3700_spi, A3700_SPI_IF_CTRL_REG); if (a3700_spi->wait_mask & ctrl_reg) returntrue;
/* Use 4 bytes long transfers. Each transfer method has its way to deal * with the remaining bytes for non 4-bytes aligned transfers.
*/
a3700_spi_bytelen_set(a3700_spi, 4);
/* Initialize the working buffers */
a3700_spi->tx_buf = xfer->tx_buf;
a3700_spi->rx_buf = xfer->rx_buf;
a3700_spi->buf_len = xfer->len;
}
/* Set header counters */ if (a3700_spi->tx_buf) { /* * when tx data is not 4 bytes aligned, there will be unexpected * bytes out of SPI output register, since it always shifts out * as whole 4 bytes. This might cause incorrect transaction with * some devices. To avoid that, use SPI header count feature to * transfer up to 3 bytes of data first, and then make the rest * of data 4-byte aligned.
*/
addr_cnt = a3700_spi->buf_len % 4; if (addr_cnt) {
val = (addr_cnt & A3700_SPI_ADDR_CNT_MASK)
<< A3700_SPI_ADDR_CNT_BIT;
spireg_write(a3700_spi, A3700_SPI_IF_HDR_CNT_REG, val);
/* Update the buffer length to be transferred */
a3700_spi->buf_len -= addr_cnt;
/* transfer 1~3 bytes through address count */
val = 0; while (addr_cnt--) {
val = (val << 8) | a3700_spi->tx_buf[0];
a3700_spi->tx_buf++;
}
spireg_write(a3700_spi, A3700_SPI_IF_ADDR_REG, val);
}
}
}
while (!a3700_is_rfifo_empty(a3700_spi) && a3700_spi->buf_len) {
val = spireg_read(a3700_spi, A3700_SPI_DATA_IN_REG); if (a3700_spi->buf_len >= 4) {
val = le32_to_cpu(val);
memcpy(a3700_spi->rx_buf, &val, 4);
a3700_spi->buf_len -= 4;
a3700_spi->rx_buf += 4;
} else { /* * When remain bytes is not larger than 4, we should * avoid memory overwriting and just write the left rx * buffer bytes.
*/ while (a3700_spi->buf_len) {
*a3700_spi->rx_buf = val & 0xff;
val >>= 8;
/* Flush the FIFOs */
a3700_spi_fifo_flush(a3700_spi);
/* Transfer first bytes of data when buffer is not 4-byte aligned */
a3700_spi_header_set(a3700_spi);
if (xfer->rx_buf) { /* Clear WFIFO, since it's last 2 bytes are shifted out during * a read operation
*/
spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, 0);
/* Set read data length */
spireg_write(a3700_spi, A3700_SPI_IF_DIN_CNT_REG,
a3700_spi->buf_len); /* Start READ transfer */
val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
val &= ~A3700_SPI_RW_EN;
val |= A3700_SPI_XFER_START;
spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
} elseif (xfer->tx_buf) { /* Start Write transfer */
val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
val |= (A3700_SPI_XFER_START | A3700_SPI_RW_EN);
spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
/* * If there are data to be written to the SPI device, xmit_data * flag is set true; otherwise the instruction in SPI_INSTR does * not require data to be written to the SPI device, then * xmit_data flag is set false.
*/
a3700_spi->xmit_data = (a3700_spi->buf_len != 0);
}
while (a3700_spi->buf_len) { if (a3700_spi->tx_buf) { /* Wait wfifo ready */ if (!a3700_spi_transfer_wait(spi,
A3700_SPI_WFIFO_RDY)) {
dev_err(&spi->dev, "wait wfifo ready timed out\n");
ret = -ETIMEDOUT; goto error;
} /* Fill up the wfifo */
ret = a3700_spi_fifo_write(a3700_spi); if (ret) goto error;
} elseif (a3700_spi->rx_buf) { /* Wait rfifo ready */ if (!a3700_spi_transfer_wait(spi,
A3700_SPI_RFIFO_RDY)) {
dev_err(&spi->dev, "wait rfifo ready timed out\n");
ret = -ETIMEDOUT; goto error;
} /* Drain out the rfifo */
ret = a3700_spi_fifo_read(a3700_spi); if (ret) goto error;
}
}
/* * Stop a write transfer in fifo mode: * - wait all the bytes in wfifo to be shifted out * - set XFER_STOP bit * - wait XFER_START bit clear * - clear XFER_STOP bit * Stop a read transfer in fifo mode: * - the hardware is to reset the XFER_START bit * after the number of bytes indicated in DIN_CNT * register * - just wait XFER_START bit clear
*/ if (a3700_spi->tx_buf) { if (a3700_spi->xmit_data) { /* * If there are data written to the SPI device, wait * until SPI_WFIFO_EMPTY is 1 to wait for all data to * transfer out of write FIFO.
*/ if (!a3700_spi_transfer_wait(spi,
A3700_SPI_WFIFO_EMPTY)) {
dev_err(&spi->dev, "wait wfifo empty timed out\n"); return -ETIMEDOUT;
}
}
/* When we have less than 4 bytes to transfer, switch to 1 byte * mode. This is reset after each transfer
*/ if (a3700_spi->buf_len < 4)
a3700_spi_bytelen_set(a3700_spi, 1);
if (a3700_spi->byte_len == 1)
val = *a3700_spi->tx_buf; else
val = *(u32 *)a3700_spi->tx_buf;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.