+// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2007 Atmel Corporation
- *
- * SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <clk.h>
#include <asm/gpio.h>
#endif
-DECLARE_GLOBAL_DATA_PTR;
-
-/* Register offsets */
-#define ATMEL_SPI_CR 0x0000
-#define ATMEL_SPI_MR 0x0004
-#define ATMEL_SPI_RDR 0x0008
-#define ATMEL_SPI_TDR 0x000c
-#define ATMEL_SPI_SR 0x0010
-#define ATMEL_SPI_IER 0x0014
-#define ATMEL_SPI_IDR 0x0018
-#define ATMEL_SPI_IMR 0x001c
-#define ATMEL_SPI_CSR(x) (0x0030 + 4 * (x))
-#define ATMEL_SPI_VERSION 0x00fc
-
-/* Bits in CR */
-#define ATMEL_SPI_CR_SPIEN BIT(0)
-#define ATMEL_SPI_CR_SPIDIS BIT(1)
-#define ATMEL_SPI_CR_SWRST BIT(7)
-#define ATMEL_SPI_CR_LASTXFER BIT(24)
-
-/* Bits in MR */
-#define ATMEL_SPI_MR_MSTR BIT(0)
-#define ATMEL_SPI_MR_PS BIT(1)
-#define ATMEL_SPI_MR_PCSDEC BIT(2)
-#define ATMEL_SPI_MR_FDIV BIT(3)
-#define ATMEL_SPI_MR_MODFDIS BIT(4)
-#define ATMEL_SPI_MR_WDRBT BIT(5)
-#define ATMEL_SPI_MR_LLB BIT(7)
-#define ATMEL_SPI_MR_PCS(x) (((x) & 15) << 16)
-#define ATMEL_SPI_MR_DLYBCS(x) ((x) << 24)
-
-/* Bits in RDR */
-#define ATMEL_SPI_RDR_RD(x) (x)
-#define ATMEL_SPI_RDR_PCS(x) ((x) << 16)
-
-/* Bits in TDR */
-#define ATMEL_SPI_TDR_TD(x) (x)
-#define ATMEL_SPI_TDR_PCS(x) ((x) << 16)
-#define ATMEL_SPI_TDR_LASTXFER BIT(24)
-
-/* Bits in SR/IER/IDR/IMR */
-#define ATMEL_SPI_SR_RDRF BIT(0)
-#define ATMEL_SPI_SR_TDRE BIT(1)
-#define ATMEL_SPI_SR_MODF BIT(2)
-#define ATMEL_SPI_SR_OVRES BIT(3)
-#define ATMEL_SPI_SR_ENDRX BIT(4)
-#define ATMEL_SPI_SR_ENDTX BIT(5)
-#define ATMEL_SPI_SR_RXBUFF BIT(6)
-#define ATMEL_SPI_SR_TXBUFE BIT(7)
-#define ATMEL_SPI_SR_NSSR BIT(8)
-#define ATMEL_SPI_SR_TXEMPTY BIT(9)
-#define ATMEL_SPI_SR_SPIENS BIT(16)
-
-/* Bits in CSRx */
-#define ATMEL_SPI_CSR_CPOL BIT(0)
-#define ATMEL_SPI_CSR_NCPHA BIT(1)
-#define ATMEL_SPI_CSR_CSAAT BIT(3)
-#define ATMEL_SPI_CSR_BITS(x) ((x) << 4)
-#define ATMEL_SPI_CSR_SCBR(x) ((x) << 8)
-#define ATMEL_SPI_CSR_SCBR_MAX GENMASK(7, 0)
-#define ATMEL_SPI_CSR_DLYBS(x) ((x) << 16)
-#define ATMEL_SPI_CSR_DLYBCT(x) ((x) << 24)
-
-/* Bits in VERSION */
-#define ATMEL_SPI_VERSION_REV(x) ((x) & 0xfff)
-#define ATMEL_SPI_VERSION_MFN(x) ((x) << 16)
-
-/* Constants for CSRx:BITS */
-#define ATMEL_SPI_BITS_8 0
-#define ATMEL_SPI_BITS_9 1
-#define ATMEL_SPI_BITS_10 2
-#define ATMEL_SPI_BITS_11 3
-#define ATMEL_SPI_BITS_12 4
-#define ATMEL_SPI_BITS_13 5
-#define ATMEL_SPI_BITS_14 6
-#define ATMEL_SPI_BITS_15 7
-#define ATMEL_SPI_BITS_16 8
-
-#define MAX_CS_COUNT 4
-
-struct atmel_spi_slave {
- void *regs;
- u32 mr;
-};
+#include "atmel_spi.h"
+
+#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 {
struct at91_spi *regs;
u32 scbr, csrx, mode;
scbr = (priv->bus_clk_rate + freq - 1) / freq;
- if (scbr > ATMEL_SPI_CSR_SCBR_MAX)
+ if (scbr > ATMEL_SPI_CSRx_SCBR_MAX)
return -EINVAL;
if (scbr < 1)
scbr = 1;
- csrx = ATMEL_SPI_CSR_SCBR(scbr);
- csrx |= ATMEL_SPI_CSR_BITS(ATMEL_SPI_BITS_8);
+ csrx = ATMEL_SPI_CSRx_SCBR(scbr);
+ csrx |= ATMEL_SPI_CSRx_BITS(ATMEL_SPI_BITS_8);
if (!(priv->mode & SPI_CPHA))
- csrx |= ATMEL_SPI_CSR_NCPHA;
+ csrx |= ATMEL_SPI_CSRx_NCPHA;
if (priv->mode & SPI_CPOL)
- csrx |= ATMEL_SPI_CSR_CPOL;
+ csrx |= ATMEL_SPI_CSRx_CPOL;
writel(csrx, ®_base->csr[cs]);
return ret;
}
- for (i = 0; i < ARRAY_SIZE(priv->cs_gpios); i++) {
+ for(i = 0; i < ARRAY_SIZE(priv->cs_gpios); i++) {
if (!dm_gpio_is_valid(&priv->cs_gpios[i]))
continue;
.priv_auto_alloc_size = sizeof(struct atmel_spi_priv),
.probe = atmel_spi_probe,
};
+#endif