|
@@ -26,206 +26,6 @@
|
|
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
|
|
-#ifndef CONFIG_DM_SPI
|
|
|
-
|
|
|
-static int spi_has_wdrbt(struct atmel_spi_slave *slave)
|
|
|
-{
|
|
|
- unsigned int ver;
|
|
|
-
|
|
|
- ver = spi_readl(slave, VERSION);
|
|
|
-
|
|
|
- return (ATMEL_SPI_VERSION_REV(ver) >= 0x210);
|
|
|
-}
|
|
|
-
|
|
|
-void spi_init()
|
|
|
-{
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
|
|
|
- unsigned int max_hz, unsigned int mode)
|
|
|
-{
|
|
|
- struct atmel_spi_slave *as;
|
|
|
- unsigned int scbr;
|
|
|
- u32 csrx;
|
|
|
- void *regs;
|
|
|
-
|
|
|
- if (!spi_cs_is_valid(bus, cs))
|
|
|
- return NULL;
|
|
|
-
|
|
|
- switch (bus) {
|
|
|
- case 0:
|
|
|
- regs = (void *)ATMEL_BASE_SPI0;
|
|
|
- break;
|
|
|
-#ifdef ATMEL_BASE_SPI1
|
|
|
- case 1:
|
|
|
- regs = (void *)ATMEL_BASE_SPI1;
|
|
|
- break;
|
|
|
-#endif
|
|
|
-#ifdef ATMEL_BASE_SPI2
|
|
|
- case 2:
|
|
|
- regs = (void *)ATMEL_BASE_SPI2;
|
|
|
- break;
|
|
|
-#endif
|
|
|
-#ifdef ATMEL_BASE_SPI3
|
|
|
- case 3:
|
|
|
- regs = (void *)ATMEL_BASE_SPI3;
|
|
|
- break;
|
|
|
-#endif
|
|
|
- default:
|
|
|
- return NULL;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- scbr = (get_spi_clk_rate(bus) + max_hz - 1) / max_hz;
|
|
|
- if (scbr > ATMEL_SPI_CSRx_SCBR_MAX)
|
|
|
- /* Too low max SCK rate */
|
|
|
- return NULL;
|
|
|
- if (scbr < 1)
|
|
|
- scbr = 1;
|
|
|
-
|
|
|
- csrx = ATMEL_SPI_CSRx_SCBR(scbr);
|
|
|
- csrx |= ATMEL_SPI_CSRx_BITS(ATMEL_SPI_BITS_8);
|
|
|
- if (!(mode & SPI_CPHA))
|
|
|
- csrx |= ATMEL_SPI_CSRx_NCPHA;
|
|
|
- if (mode & SPI_CPOL)
|
|
|
- csrx |= ATMEL_SPI_CSRx_CPOL;
|
|
|
-
|
|
|
- as = spi_alloc_slave(struct atmel_spi_slave, bus, cs);
|
|
|
- if (!as)
|
|
|
- return NULL;
|
|
|
-
|
|
|
- as->regs = regs;
|
|
|
- as->mr = ATMEL_SPI_MR_MSTR | ATMEL_SPI_MR_MODFDIS
|
|
|
- | ATMEL_SPI_MR_PCS(~(1 << cs) & 0xf);
|
|
|
- if (spi_has_wdrbt(as))
|
|
|
- as->mr |= ATMEL_SPI_MR_WDRBT;
|
|
|
-
|
|
|
- spi_writel(as, CSR(cs), csrx);
|
|
|
-
|
|
|
- return &as->slave;
|
|
|
-}
|
|
|
-
|
|
|
-void spi_free_slave(struct spi_slave *slave)
|
|
|
-{
|
|
|
- struct atmel_spi_slave *as = to_atmel_spi(slave);
|
|
|
-
|
|
|
- free(as);
|
|
|
-}
|
|
|
-
|
|
|
-int spi_claim_bus(struct spi_slave *slave)
|
|
|
-{
|
|
|
- struct atmel_spi_slave *as = to_atmel_spi(slave);
|
|
|
-
|
|
|
- /* Enable the SPI hardware */
|
|
|
- spi_writel(as, CR, ATMEL_SPI_CR_SPIEN);
|
|
|
-
|
|
|
- /*
|
|
|
- * Select the slave. This should set SCK to the correct
|
|
|
- * initial state, etc.
|
|
|
- */
|
|
|
- spi_writel(as, MR, as->mr);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-void spi_release_bus(struct spi_slave *slave)
|
|
|
-{
|
|
|
- struct atmel_spi_slave *as = to_atmel_spi(slave);
|
|
|
-
|
|
|
- /* Disable the SPI hardware */
|
|
|
- spi_writel(as, CR, ATMEL_SPI_CR_SPIDIS);
|
|
|
-}
|
|
|
-
|
|
|
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
|
|
|
- const void *dout, void *din, unsigned long flags)
|
|
|
-{
|
|
|
- struct atmel_spi_slave *as = to_atmel_spi(slave);
|
|
|
- unsigned int len_tx;
|
|
|
- unsigned int len_rx;
|
|
|
- unsigned int len;
|
|
|
- u32 status;
|
|
|
- const u8 *txp = dout;
|
|
|
- u8 *rxp = din;
|
|
|
- u8 value;
|
|
|
-
|
|
|
- if (bitlen == 0)
|
|
|
- /* Finish any previously submitted transfers */
|
|
|
- goto out;
|
|
|
-
|
|
|
- /*
|
|
|
- * TODO: The controller can do non-multiple-of-8 bit
|
|
|
- * transfers, but this driver currently doesn't support it.
|
|
|
- *
|
|
|
- * It's also not clear how such transfers are supposed to be
|
|
|
- * represented as a stream of bytes...this is a limitation of
|
|
|
- * the current SPI interface.
|
|
|
- */
|
|
|
- if (bitlen % 8) {
|
|
|
- /* Errors always terminate an ongoing transfer */
|
|
|
- flags |= SPI_XFER_END;
|
|
|
- goto out;
|
|
|
- }
|
|
|
-
|
|
|
- len = bitlen / 8;
|
|
|
-
|
|
|
- /*
|
|
|
- * The controller can do automatic CS control, but it is
|
|
|
- * somewhat quirky, and it doesn't really buy us much anyway
|
|
|
- * in the context of U-Boot.
|
|
|
- */
|
|
|
- if (flags & SPI_XFER_BEGIN) {
|
|
|
- spi_cs_activate(slave);
|
|
|
- /*
|
|
|
- * sometimes the RDR is not empty when we get here,
|
|
|
- * in theory that should not happen, but it DOES happen.
|
|
|
- * Read it here to be on the safe side.
|
|
|
- * That also clears the OVRES flag. Required if the
|
|
|
- * following loop exits due to OVRES!
|
|
|
- */
|
|
|
- spi_readl(as, RDR);
|
|
|
- }
|
|
|
-
|
|
|
- for (len_tx = 0, len_rx = 0; len_rx < len; ) {
|
|
|
- status = spi_readl(as, SR);
|
|
|
-
|
|
|
- if (status & ATMEL_SPI_SR_OVRES)
|
|
|
- return -1;
|
|
|
-
|
|
|
- if (len_tx < len && (status & ATMEL_SPI_SR_TDRE)) {
|
|
|
- if (txp)
|
|
|
- value = *txp++;
|
|
|
- else
|
|
|
- value = 0;
|
|
|
- spi_writel(as, TDR, value);
|
|
|
- len_tx++;
|
|
|
- }
|
|
|
- if (status & ATMEL_SPI_SR_RDRF) {
|
|
|
- value = spi_readl(as, RDR);
|
|
|
- if (rxp)
|
|
|
- *rxp++ = value;
|
|
|
- len_rx++;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-out:
|
|
|
- if (flags & SPI_XFER_END) {
|
|
|
- /*
|
|
|
- * Wait until the transfer is completely done before
|
|
|
- * we deactivate CS.
|
|
|
- */
|
|
|
- do {
|
|
|
- status = spi_readl(as, SR);
|
|
|
- } while (!(status & ATMEL_SPI_SR_TXEMPTY));
|
|
|
-
|
|
|
- spi_cs_deactivate(slave);
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-#else
|
|
|
-
|
|
|
#define MAX_CS_COUNT 4
|
|
|
|
|
|
struct atmel_spi_platdata {
|
|
@@ -515,4 +315,3 @@ U_BOOT_DRIVER(atmel_spi) = {
|
|
|
.priv_auto_alloc_size = sizeof(struct atmel_spi_priv),
|
|
|
.probe = atmel_spi_probe,
|
|
|
};
|
|
|
-#endif
|