*
* Copyright (C) 2014 Stefan Roese <sr@denx.de>
*
- * Very loosly based on the Linux driver version which is:
+ * Very loosely based on the Linux driver:
+ * drivers/spi/spi-dw.c, which is:
* Copyright (c) 2009, Intel Corporation.
*
* SPDX-License-Identifier: GPL-2.0
#include <fdtdec.h>
#include <linux/compat.h>
#include <asm/io.h>
+#include <asm/arch/clock_manager.h>
DECLARE_GLOBAL_DATA_PTR;
#define SR_TX_ERR (1 << 5)
#define SR_DCOL (1 << 6)
-#define RX_TIMEOUT 1000
+#define RX_TIMEOUT 1000 /* timeout in ms */
struct dw_spi_platdata {
s32 frequency; /* Default clock frequency, -1 for none */
int bits_per_word;
u8 cs; /* chip select pin */
- u8 n_bytes; /* current is a 1/2/4 byte op */
u8 tmode; /* TR/TO/RO/EEPROM */
u8 type; /* SPI/SSP/MicroWire */
int len;
const void *blob = gd->fdt_blob;
int node = bus->of_offset;
- plat->regs = (struct dw_spi *)fdtdec_get_addr(blob, node, "reg");
+ plat->regs = (struct dw_spi *)dev_get_addr(bus);
/* Use 500KHz as a suitable default */
plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
if (!priv->fifo_len) {
u32 fifo;
- for (fifo = 2; fifo <= 257; fifo++) {
+ for (fifo = 1; fifo < 256; fifo++) {
dw_writew(priv, DW_SPI_TXFLTR, fifo);
if (fifo != dw_readw(priv, DW_SPI_TXFLTR))
break;
}
- priv->fifo_len = (fifo == 257) ? 0 : fifo;
+ priv->fifo_len = (fifo == 1) ? 0 : fifo;
dw_writew(priv, DW_SPI_TXFLTR, 0);
}
debug("%s: fifo_len=%d\n", __func__, priv->fifo_len);
/* Currently only bits_per_word == 8 supported */
priv->bits_per_word = 8;
- priv->n_bytes = 1;
priv->tmode = 0; /* Tx & Rx */
{
u32 tx_left, tx_room, rxtx_gap;
- tx_left = (priv->tx_end - priv->tx) / priv->n_bytes;
+ tx_left = (priv->tx_end - priv->tx) / (priv->bits_per_word >> 3);
tx_room = priv->fifo_len - dw_readw(priv, DW_SPI_TXFLR);
/*
* Another concern is about the tx/rx mismatch, we
- * though to use (priv->fifo_len - rxflr - txflr) as
+ * thought about using (priv->fifo_len - rxflr - txflr) 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 control from sw point of
* view is taken.
*/
rxtx_gap = ((priv->rx_end - priv->rx) - (priv->tx_end - priv->tx)) /
- priv->n_bytes;
+ (priv->bits_per_word >> 3);
return min3(tx_left, tx_room, (u32)(priv->fifo_len - rxtx_gap));
}
/* Return the max entries we should read out of rx fifo */
static inline u32 rx_max(struct dw_spi_priv *priv)
{
- u32 rx_left = (priv->rx_end - priv->rx) / priv->n_bytes;
+ u32 rx_left = (priv->rx_end - priv->rx) / (priv->bits_per_word >> 3);
return min_t(u32, rx_left, dw_readw(priv, DW_SPI_RXFLR));
}
while (max--) {
/* Set the tx word if the transfer's original "tx" is not null */
if (priv->tx_end - priv->len) {
- if (priv->n_bytes == 1)
+ if (priv->bits_per_word == 8)
txw = *(u8 *)(priv->tx);
else
txw = *(u16 *)(priv->tx);
}
dw_writew(priv, DW_SPI_DR, txw);
debug("%s: tx=0x%02x\n", __func__, txw);
- priv->tx += priv->n_bytes;
+ priv->tx += priv->bits_per_word >> 3;
}
}
while (max--) {
rxw = dw_readw(priv, DW_SPI_DR);
debug("%s: rx=0x%02x\n", __func__, rxw);
- /* Care rx only if the transfer's original "rx" is not null */
+
+ /*
+ * Care about rx only if the transfer's original "rx" is
+ * not null
+ */
if (priv->rx_end - priv->len) {
- if (priv->n_bytes == 1)
+ if (priv->bits_per_word == 8)
*(u8 *)(priv->rx) = rxw;
else
*(u16 *)(priv->rx) = rxw;
}
- priv->rx += priv->n_bytes;
+ priv->rx += priv->bits_per_word >> 3;
}
return 0;
u8 *rx = din;
int ret = 0;
u32 cr0 = 0;
- u8 bits = 0;
u32 cs;
/* spi core configured to do 8 bit transfers */
return -1;
}
- bits = priv->bits_per_word;
- priv->n_bytes = bits >> 3;
- cr0 = (bits - 1) | (priv->type << SPI_FRF_OFFSET) |
+ cr0 = (priv->bits_per_word - 1) | (priv->type << SPI_FRF_OFFSET) |
(priv->mode << SPI_MODE_OFFSET) |
(priv->tmode << SPI_TMOD_OFFSET);
cr0 &= ~SPI_TMOD_MASK;
cr0 |= (priv->tmode << SPI_TMOD_OFFSET);
- priv->len = bitlen / 8;
+ priv->len = bitlen >> 3;
debug("%s: rx=%p tx=%p len=%d [bytes]\n", __func__, rx, tx, priv->len);
priv->tx = (void *)tx;
spi_enable_chip(priv, 0);
/* clk_div doesn't support odd number */
- clk_div = CONFIG_DW_SPI_REF_CLK / speed;
+ clk_div = cm_get_spi_controller_clk_hz() / speed;
clk_div = (clk_div + 1) & 0xfffe;
dw_writel(priv, DW_SPI_BAUDR, clk_div);
};
static const struct udevice_id dw_spi_ids[] = {
- { .compatible = "snps,dw-spi-mmio" },
+ { .compatible = "snps,dw-apb-ssi" },
{ }
};
.ofdata_to_platdata = dw_spi_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct dw_spi_platdata),
.priv_auto_alloc_size = sizeof(struct dw_spi_priv),
- .per_child_auto_alloc_size = sizeof(struct spi_slave),
.probe = dw_spi_probe,
};