/* Bit fields of SPI Control Register */ #define CTRL_RX_INT_SHIFT 0 /* Rx interrupt generation */ #define RX_FIFO_EMPTY 0 #define RX_FIFO_NOT_EMPTY 1 /* not empty */ #define RX_FIFO_HALF_FULL 2 /* full by half or more */ #define RX_FIFO_FULL 3 /* completely full */
#define CTRL_TX_INT_SHIFT 2 /* TX interrupt generation */ #define TX_FIFO_ALL_EMPTY 0 /* completely empty */ #define TX_FIFO_EMPTY 1 /* empty */ #define TX_FIFO_HALF_EMPTY 2 /* empty by half or more */ #define TX_FIFO_NOT_FULL 3 /* atleast one empty */
/* * Another concern is about the tx/rx mismatch, we * though to use (pic32s->fifo_n_byte - rxfl - txfl) as * one maximum value for tx, but it doesn't cover the * data which is out of tx/rx fifo and inside the * shift registers. So a ctrl from sw point of * view is taken.
*/
rxtx_gap = ((pic32s->rx_end - pic32s->rx) -
(pic32s->tx_end - pic32s->tx)) / n_bytes; return min3(tx_left, tx_room, (u32)(pic32s->fifo_n_elm - rxtx_gap));
}
/* Return the max entries we should read out of rx fifo */ static u32 pic32_rx_max(struct pic32_spi *pic32s, int n_bytes)
{
u32 rx_left = (pic32s->rx_end - pic32s->rx) / n_bytes;
/* Show err message and abort xfer with err */
dev_err(&pic32s->host->dev, "%s\n", msg); if (pic32s->host->cur_msg)
pic32s->host->cur_msg->status = -EIO;
complete(&pic32s->xfer_done);
}
/* calculate maximum number of words fifos can hold */
pic32s->fifo_n_elm = DIV_ROUND_UP(pic32s->fifo_n_byte,
bits_per_word / 8); /* set word size */
v = readl(&pic32s->regs->ctrl);
v &= ~(CTRL_BPW_MASK << CTRL_BPW_SHIFT);
v |= buswidth << CTRL_BPW_SHIFT;
writel(v, &pic32s->regs->ctrl);
/* re-configure dma width, if required */ if (test_bit(PIC32F_DMA_PREP, &pic32s->flags))
pic32_spi_dma_config(pic32s, dmawidth);
/* set device specific bits_per_word */ if (pic32s->bits_per_word != spi->bits_per_word) {
pic32_spi_set_word_size(pic32s, spi->bits_per_word);
pic32s->bits_per_word = spi->bits_per_word;
}
/* device specific speed change */ if (pic32s->speed_hz != spi->max_speed_hz) {
pic32_spi_set_clk_rate(pic32s, spi->max_speed_hz);
pic32s->speed_hz = spi->max_speed_hz;
}
/* device specific mode change */ if (pic32s->mode != spi->mode) {
val = readl(&pic32s->regs->ctrl); /* active low */ if (spi->mode & SPI_CPOL)
val |= CTRL_CKP; else
val &= ~CTRL_CKP; /* tx on rising edge */ if (spi->mode & SPI_CPHA)
val &= ~CTRL_CKE; else
val |= CTRL_CKE;
/* rx at end of tx */
val |= CTRL_SMP;
writel(val, &pic32s->regs->ctrl);
pic32s->mode = spi->mode;
}
/* handle transfer specific word size change */ if (transfer->bits_per_word &&
(transfer->bits_per_word != pic32s->bits_per_word)) {
ret = pic32_spi_set_word_size(pic32s, transfer->bits_per_word); if (ret) return ret;
pic32s->bits_per_word = transfer->bits_per_word;
}
/* handle transfer specific speed change */ if (transfer->speed_hz && (transfer->speed_hz != pic32s->speed_hz)) {
pic32_spi_set_clk_rate(pic32s, transfer->speed_hz);
pic32s->speed_hz = transfer->speed_hz;
}
reinit_completion(&pic32s->xfer_done);
/* transact by DMA mode */ if (transfer->rx_sg.nents && transfer->tx_sg.nents) {
ret = pic32_spi_dma_transfer(pic32s, transfer); if (ret) {
dev_err(&spi->dev, "dma submit error\n"); return ret;
}
/* DMA issued */
dma_issued = true;
} else { /* set current transfer information */
pic32s->tx = (constvoid *)transfer->tx_buf;
pic32s->rx = (constvoid *)transfer->rx_buf;
pic32s->tx_end = pic32s->tx + transfer->len;
pic32s->rx_end = pic32s->rx + transfer->len;
pic32s->len = transfer->len;
/* transact by interrupt driven PIO */
enable_irq(pic32s->fault_irq);
enable_irq(pic32s->rx_irq);
enable_irq(pic32s->tx_irq);
}
/* wait for completion */
time_left = wait_for_completion_timeout(&pic32s->xfer_done, 2 * HZ); if (time_left == 0) {
dev_err(&spi->dev, "wait error/timedout\n"); if (dma_issued) {
dmaengine_terminate_all(host->dma_rx);
dmaengine_terminate_all(host->dma_tx);
}
ret = -ETIMEDOUT;
} else {
ret = 0;
}
return ret;
}
staticint pic32_spi_unprepare_message(struct spi_controller *host, struct spi_message *msg)
{ /* nothing to do */ return 0;
}
/* This may be called multiple times by same spi dev */ staticint pic32_spi_setup(struct spi_device *spi)
{ if (!spi->max_speed_hz) {
dev_err(&spi->dev, "No max speed HZ parameter\n"); return -EINVAL;
}
/* PIC32 spi controller can drive /CS during transfer depending * on tx fifo fill-level. /CS will stay asserted as long as TX * fifo is non-empty, else will be deasserted indicating * completion of the ongoing transfer. This might result into * unreliable/erroneous SPI transactions. * To avoid that we will always handle /CS by toggling GPIO.
*/ if (!spi_get_csgpiod(spi, 0)) return -EINVAL;
staticint pic32_spi_dma_prep(struct pic32_spi *pic32s, struct device *dev)
{ struct spi_controller *host = pic32s->host; int ret = 0;
host->dma_rx = dma_request_chan(dev, "spi-rx"); if (IS_ERR(host->dma_rx)) { if (PTR_ERR(host->dma_rx) == -EPROBE_DEFER)
ret = -EPROBE_DEFER; else
dev_warn(dev, "RX channel not found.\n");
host->dma_rx = NULL; goto out_err;
}
host->dma_tx = dma_request_chan(dev, "spi-tx"); if (IS_ERR(host->dma_tx)) { if (PTR_ERR(host->dma_tx) == -EPROBE_DEFER)
ret = -EPROBE_DEFER; else
dev_warn(dev, "TX channel not found.\n");
host->dma_tx = NULL; goto out_err;
}
if (pic32_spi_dma_config(pic32s, DMA_SLAVE_BUSWIDTH_1_BYTE)) goto out_err;
/* DMA chnls allocated and prepared */
set_bit(PIC32F_DMA_PREP, &pic32s->flags);
return 0;
out_err: if (host->dma_rx) {
dma_release_channel(host->dma_rx);
host->dma_rx = NULL;
}
if (host->dma_tx) {
dma_release_channel(host->dma_tx);
host->dma_tx = NULL;
}
return ret;
}
staticvoid pic32_spi_dma_unprep(struct pic32_spi *pic32s)
{ if (!test_bit(PIC32F_DMA_PREP, &pic32s->flags)) return;
clear_bit(PIC32F_DMA_PREP, &pic32s->flags); if (pic32s->host->dma_rx)
dma_release_channel(pic32s->host->dma_rx);
if (pic32s->host->dma_tx)
dma_release_channel(pic32s->host->dma_tx);
}
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.