/* * This macro abstracts the differences in the PSC register layout between * MPC5121 (which uses a struct mpc52xx_psc) and MPC5125 (using mpc5125_psc).
*/ #define psc_addr(mps, regname) ({ \ void *__ret = NULL; \ switch (mps->type) { \ case TYPE_MPC5121: { \ struct mpc52xx_psc __iomem *psc = mps->psc; \
__ret = &psc->regname; \
}; \ break; \ case TYPE_MPC5125: { \ struct mpc5125_psc __iomem *psc = mps->psc; \
__ret = &psc->regname; \
}; \ break; \
} \
__ret; })
struct mpc512x_psc_spi { /* driver internal data */ int type; void __iomem *psc; struct mpc512x_psc_fifo __iomem *fifo; int irq;
u8 bits_per_word;
u32 mclk_rate;
struct completion txisrdone;
};
/* controller state */ struct mpc512x_psc_spi_cs { int bits_per_word; int speed_hz;
};
/* set clock freq, clock ramp, bits per work * if t is NULL then reset the values to the default values
*/ staticint mpc512x_psc_spi_transfer_setup(struct spi_device *spi, struct spi_transfer *t)
{ struct mpc512x_psc_spi_cs *cs = spi->controller_state;
while (rx_len || tx_len) {
size_t txcount;
u8 data;
size_t fifosz;
size_t rxcount; int rxtries;
/* * send the TX bytes in as large a chunk as possible * but neither exceed the TX nor the RX FIFOs
*/
fifosz = MPC512x_PSC_FIFO_SZ(in_be32(&fifo->txsz));
txcount = min(fifosz, tx_len);
fifosz = MPC512x_PSC_FIFO_SZ(in_be32(&fifo->rxsz));
fifosz -= in_be32(&fifo->rxcnt) + 1;
txcount = min(fifosz, txcount); if (txcount) {
/* fill the TX FIFO */ while (txcount-- > 0) {
data = tx_buf ? *tx_buf++ : 0; if (tx_len == EOFBYTE && t->cs_change)
setbits32(&fifo->txcmd,
MPC512x_PSC_FIFO_EOF);
out_8(&fifo->txdata_8, data);
tx_len--;
}
/* have the ISR trigger when the TX FIFO is empty */
reinit_completion(&mps->txisrdone);
out_be32(&fifo->txisr, MPC512x_PSC_FIFO_EMPTY);
out_be32(&fifo->tximr, MPC512x_PSC_FIFO_EMPTY);
wait_for_completion(&mps->txisrdone);
}
/* * consume as much RX data as the FIFO holds, while we * iterate over the transfer's TX data length * * only insist in draining all the remaining RX bytes * when the TX bytes were exhausted (that's at the very * end of this transfer, not when still iterating over * the transfer's chunks)
*/
rxtries = 50; do {
/* * grab whatever was in the FIFO when we started * looking, don't bother fetching what was added to * the FIFO while we read from it -- we'll return * here eventually and prefer sending out remaining * TX data
*/
fifosz = in_be32(&fifo->rxcnt);
rxcount = min(fifosz, rx_len); while (rxcount-- > 0) {
data = in_8(&fifo->rxdata_8); if (rx_buf)
*rx_buf++ = data;
rx_len--;
}
/* * come back later if there still is TX data to send, * bail out of the RX drain loop if all of the TX data * was sent and all of the RX data was received (i.e. * when the transmission has completed)
*/ if (tx_len) break; if (!rx_len) break;
/* * TX data transmission has completed while RX data * is still pending -- that's a transient situation * which depends on wire speed and specific * hardware implementation details (buffering) yet * should resolve very quickly * * just yield for a moment to not hog the CPU for * too long when running SPI at low speed * * the timeout range is rather arbitrary and tries * to balance throughput against system load; the * chosen values result in a minimal timeout of 50 * times 10us and thus work at speeds as low as * some 20kbps, while the maximum timeout at the * transfer's end could be 5ms _if_ nothing else * ticks in the system _and_ RX data still wasn't * received, which only occurs in situations that * are exceptional; removing the unpredictability * of the timeout either decreases throughput * (longer timeouts), or puts more load on the * system (fixed short timeouts) or requires the * use of a timeout API instead of a counter and an * unknown inner delay
*/
usleep_range(10, 100);
} while (--rxtries > 0); if (!tx_len && rx_len && !rxtries) { /* * not enough RX bytes even after several retries * and the resulting rather long timeout?
*/
rxcount = in_be32(&fifo->rxcnt);
dev_warn(&spi->dev, "short xfer, missing %zd RX bytes, FIFO level %zd\n",
rx_len, rxcount);
}
/* * drain and drop RX data which "should not be there" in * the first place, for undisturbed transmission this turns * into a NOP (except for the FIFO level fetch)
*/ if (!tx_len && !rx_len) { while (in_be32(&fifo->rxcnt))
in_8(&fifo->rxdata_8);
}
/* Reset the PSC into a known state */
out_8(psc_addr(mps, command), MPC52xx_PSC_RST_RX);
out_8(psc_addr(mps, command), MPC52xx_PSC_RST_TX);
out_8(psc_addr(mps, command), MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
/* Disable psc interrupts all useful interrupts are in fifo */
out_be16(psc_addr(mps, isr_imr.imr), 0);
/* Disable fifo interrupts, will be enabled later */
out_be32(&fifo->tximr, 0);
out_be32(&fifo->rximr, 0);
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.