// SPDX-License-Identifier: GPL-2.0 // // Apple SoC SPI device driver // // Copyright The Asahi Linux Contributors // // Based on spi-sifive.c, Copyright 2018 SiFive, Inc.
/* * The slowest refclock available is 24MHz, the highest divider is 0x7ff, * the largest word size is 32 bits, the FIFO depth is 16, the maximum * intra-word delay is 0xffff refclocks. So the maximum time a transfer * cycle can take is: * * (0x7ff * 32 + 0xffff) * 16 / 24e6 Hz ~= 87ms * * Double it and round it up to 200ms for good measure.
*/ #define APPLE_SPI_TIMEOUT_MS 200
/* Calculate and program the clock rate */
cr = DIV_ROUND_UP(clk_get_rate(spi->clk), t->speed_hz);
reg_write(spi, APPLE_SPI_CLKDIV, min_t(u32, cr, APPLE_SPI_CLKDIV_MAX));
/* Update bits per word */
reg_mask(spi, APPLE_SPI_SHIFTCFG, APPLE_SPI_SHIFTCFG_BITS,
FIELD_PREP(APPLE_SPI_SHIFTCFG_BITS, t->bits_per_word));
/* We will want to poll if the time we need to wait is * less than the context switching time. * Let's call that threshold 5us. The operation will take: * bits_per_word * fifo_threshold / hz <= 5 * 10^-6 * 200000 * bits_per_word * fifo_threshold <= hz
*/
fifo_threshold = APPLE_SPI_FIFO_DEPTH / 2; return (200000 * t->bits_per_word * fifo_threshold) <= t->speed_hz;
}
/* Determine transfer completion flags we wait for */ if (tx_ptr)
xfer_flags |= APPLE_SPI_XFER_TXCOMPLETE; if (rx_ptr)
xfer_flags |= APPLE_SPI_XFER_RXCOMPLETE;
/* Set transfer length */
reg_write(spi, APPLE_SPI_TXCNT, remaining_tx);
reg_write(spi, APPLE_SPI_RXCNT, remaining_rx);
/* Prime transmit FIFO */
apple_spi_tx(spi, &tx_ptr, &remaining_tx, bytes_per_word);
/* Start transfer */
reg_write(spi, APPLE_SPI_CTRL, APPLE_SPI_CTRL_RUN);
/* TX again since a few words get popped off immediately */
apple_spi_tx(spi, &tx_ptr, &remaining_tx, bytes_per_word);
while (xfer_flags) {
fifo_flags = 0;
if (remaining_tx)
fifo_flags |= APPLE_SPI_FIFO_TXTHRESH; if (remaining_rx)
fifo_flags |= APPLE_SPI_FIFO_RXTHRESH;
/* Wait for anything to happen */
ret = apple_spi_wait(spi, fifo_flags, xfer_flags, poll); if (ret) {
dev_err(&ctlr->dev, "transfer timed out (remaining %d tx, %d rx)\n",
remaining_tx, remaining_rx); goto err;
}
/* Stop waiting on transfer halves once they complete */
xfer_flags &= ~reg_read(spi, APPLE_SPI_IF_XFER);
/* Transmit and receive everything we can */
apple_spi_tx(spi, &tx_ptr, &remaining_tx, bytes_per_word);
apple_spi_rx(spi, &rx_ptr, &remaining_rx, bytes_per_word);
}
/* * Sometimes the transfer completes before the last word is in the RX FIFO. * Normally one retry is all it takes to get the last word out.
*/ while (remaining_rx && retries--)
apple_spi_rx(spi, &rx_ptr, &remaining_rx, bytes_per_word);
if (remaining_tx)
dev_err(&ctlr->dev, "transfer completed with %d words left to transmit\n",
remaining_tx); if (remaining_rx)
dev_err(&ctlr->dev, "transfer completed with %d words left to receive\n",
remaining_rx);
spi->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(spi->regs)) return PTR_ERR(spi->regs);
spi->clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(spi->clk)) return dev_err_probe(&pdev->dev, PTR_ERR(spi->clk), "Unable to find or enable bus clock\n");
irq = platform_get_irq(pdev, 0); if (irq < 0) return irq;
ret = devm_request_irq(&pdev->dev, irq, apple_spi_irq, 0,
dev_name(&pdev->dev), spi); if (ret) return dev_err_probe(&pdev->dev, ret, "Unable to bind to interrupt\n");
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.