[U-Boot] [PATCH 2/2] spi: kirkwood_spi.c: Add driver model support

Stefan Roese sr at denx.de
Fri Nov 27 11:24:57 CET 2015


This patch adds driver model support to the kirkwood SPI driver. Which
is also used on the MVEBU SoC's, now being converted to DM. Non-DM
support is still available for the "older" platforms using this
driver, like kirkwood.

Signed-off-by: Stefan Roese <sr at denx.de>
Cc: Valentin Longchamp <valentin.longchamp at keymile.com>
Cc: Luka Perkov <luka.perkov at sartura.hr>
Cc: Jagan Teki <jteki at openedev.com>
Cc: Simon Glass <sjg at chromium.org>
---
 drivers/spi/kirkwood_spi.c | 222 ++++++++++++++++++++++++++++++++-------------
 1 file changed, 159 insertions(+), 63 deletions(-)

diff --git a/drivers/spi/kirkwood_spi.c b/drivers/spi/kirkwood_spi.c
index 08bf432..7890796 100644
--- a/drivers/spi/kirkwood_spi.c
+++ b/drivers/spi/kirkwood_spi.c
@@ -9,6 +9,7 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <malloc.h>
 #include <spi.h>
 #include <asm/io.h>
@@ -18,6 +19,83 @@
 #endif
 #include <asm/arch-mvebu/spi.h>
 
+static void _spi_cs_activate(struct kwspi_registers *reg)
+{
+	setbits_le32(&reg->ctrl, KWSPI_CSN_ACT);
+}
+
+static void _spi_cs_deactivate(struct kwspi_registers *reg)
+{
+	clrbits_le32(&reg->ctrl, KWSPI_CSN_ACT);
+}
+
+static int _spi_xfer(struct kwspi_registers *reg, unsigned int bitlen,
+		     const void *dout, void *din, unsigned long flags)
+{
+	unsigned int tmpdout, tmpdin;
+	int tm, isread = 0;
+
+	debug("spi_xfer: dout %p din %p bitlen %u\n", dout, din, bitlen);
+
+	if (flags & SPI_XFER_BEGIN)
+		_spi_cs_activate(reg);
+
+	/*
+	 * handle data in 8-bit chunks
+	 * TBD: 2byte xfer mode to be enabled
+	 */
+	clrsetbits_le32(&reg->cfg, KWSPI_XFERLEN_MASK, KWSPI_XFERLEN_1BYTE);
+
+	while (bitlen > 4) {
+		debug("loopstart bitlen %d\n", bitlen);
+		tmpdout = 0;
+
+		/* Shift data so it's msb-justified */
+		if (dout)
+			tmpdout = *(u32 *)dout & 0xff;
+
+		clrbits_le32(&reg->irq_cause, KWSPI_SMEMRDIRQ);
+		writel(tmpdout, &reg->dout);	/* Write the data out */
+		debug("*** spi_xfer: ... %08x written, bitlen %d\n",
+		      tmpdout, bitlen);
+
+		/*
+		 * Wait for SPI transmit to get out
+		 * or time out (1 second = 1000 ms)
+		 * The NE event must be read and cleared first
+		 */
+		for (tm = 0, isread = 0; tm < KWSPI_TIMEOUT; ++tm) {
+			if (readl(&reg->irq_cause) & KWSPI_SMEMRDIRQ) {
+				isread = 1;
+				tmpdin = readl(&reg->din);
+				debug("spi_xfer: din %p..%08x read\n",
+				      din, tmpdin);
+
+				if (din) {
+					*((u8 *)din) = (u8)tmpdin;
+					din += 1;
+				}
+				if (dout)
+					dout += 1;
+				bitlen -= 8;
+			}
+			if (isread)
+				break;
+		}
+		if (tm >= KWSPI_TIMEOUT)
+			printf("*** spi_xfer: Time out during SPI transfer\n");
+
+		debug("loopend bitlen %d\n", bitlen);
+	}
+
+	if (flags & SPI_XFER_END)
+		_spi_cs_deactivate(reg);
+
+	return 0;
+}
+
+#ifndef CONFIG_DM_SPI
+
 static struct kwspi_registers *spireg =
 	(struct kwspi_registers *)MVEBU_SPI_BASE;
 
@@ -145,16 +223,6 @@ void spi_init(void)
 {
 }
 
-static void _spi_cs_activate(struct kwspi_registers *reg)
-{
-	setbits_le32(&reg->ctrl, KWSPI_CSN_ACT);
-}
-
-static void _spi_cs_deactivate(struct kwspi_registers *reg)
-{
-	clrbits_le32(&reg->ctrl, KWSPI_CSN_ACT);
-}
-
 void spi_cs_activate(struct spi_slave *slave)
 {
 	_spi_cs_activate(spireg);
@@ -165,73 +233,101 @@ void spi_cs_deactivate(struct spi_slave *slave)
 	_spi_cs_deactivate(spireg);
 }
 
-static int _spi_xfer(struct kwspi_registers *reg, unsigned int bitlen,
-		     const void *dout, void *din, unsigned long flags)
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+	     const void *dout, void *din, unsigned long flags)
 {
-	unsigned int tmpdout, tmpdin;
-	int tm, isread = 0;
+	return _spi_xfer(spireg, bitlen, dout, din, flags);
+}
 
-	debug("spi_xfer: dout %p din %p bitlen %u\n", dout, din, bitlen);
+#else
 
-	if (flags & SPI_XFER_BEGIN)
-		_spi_cs_activate(reg);
+/* Here now the DM part */
 
-	/*
-	 * handle data in 8-bit chunks
-	 * TBD: 2byte xfer mode to be enabled
-	 */
-	clrsetbits_le32(&reg->cfg, KWSPI_XFERLEN_MASK, KWSPI_XFERLEN_1BYTE);
+struct mvebu_spi_platdata {
+	struct kwspi_registers *spireg;
+};
 
-	while (bitlen > 4) {
-		debug("loopstart bitlen %d\n", bitlen);
-		tmpdout = 0;
+struct mvebu_spi_priv {
+	struct kwspi_registers *spireg;
+};
 
-		/* Shift data so it's msb-justified */
-		if (dout)
-			tmpdout = *(u32 *)dout & 0xff;
+static int mvebu_spi_set_speed(struct udevice *bus, uint hz)
+{
+	struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
+	struct kwspi_registers *reg = plat->spireg;
+	u32 data;
 
-		clrbits_le32(&reg->irq_cause, KWSPI_SMEMRDIRQ);
-		writel(tmpdout, &reg->dout);	/* Write the data out */
-		debug("*** spi_xfer: ... %08x written, bitlen %d\n",
-		      tmpdout, bitlen);
+	/* calculate spi clock prescaller using max_hz */
+	data = ((CONFIG_SYS_TCLK / 2) / hz) + 0x10;
+	data = data < KWSPI_CLKPRESCL_MIN ? KWSPI_CLKPRESCL_MIN : data;
+	data = data > KWSPI_CLKPRESCL_MASK ? KWSPI_CLKPRESCL_MASK : data;
 
-		/*
-		 * Wait for SPI transmit to get out
-		 * or time out (1 second = 1000 ms)
-		 * The NE event must be read and cleared first
-		 */
-		for (tm = 0, isread = 0; tm < KWSPI_TIMEOUT; ++tm) {
-			if (readl(&reg->irq_cause) & KWSPI_SMEMRDIRQ) {
-				isread = 1;
-				tmpdin = readl(&reg->din);
-				debug("spi_xfer: din %p..%08x read\n",
-				      din, tmpdin);
+	/* program spi clock prescaler using max_hz */
+	writel(KWSPI_ADRLEN_3BYTE | data, &reg->cfg);
+	debug("data = 0x%08x\n", data);
 
-				if (din) {
-					*((u8 *)din) = (u8)tmpdin;
-					din += 1;
-				}
-				if (dout)
-					dout += 1;
-				bitlen -= 8;
-			}
-			if (isread)
-				break;
-		}
-		if (tm >= KWSPI_TIMEOUT)
-			printf("*** spi_xfer: Time out during SPI transfer\n");
+	return 0;
+}
 
-		debug("loopend bitlen %d\n", bitlen);
-	}
+static int mvebu_spi_set_mode(struct udevice *bus, uint mode)
+{
+	return 0;
+}
 
-	if (flags & SPI_XFER_END)
-		_spi_cs_deactivate(reg);
+static int mvebu_spi_xfer(struct udevice *dev, unsigned int bitlen,
+			  const void *dout, void *din, unsigned long flags)
+{
+	struct udevice *bus = dev->parent;
+	struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
+
+	return _spi_xfer(plat->spireg, bitlen, dout, din, flags);
+}
+
+static int mvebu_spi_probe(struct udevice *bus)
+{
+	struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
+	struct kwspi_registers *reg = plat->spireg;
+
+	writel(KWSPI_SMEMRDY, &reg->ctrl);
+	writel(KWSPI_SMEMRDIRQ, &reg->irq_cause);
+	writel(KWSPI_IRQMASK, &reg->irq_mask);
 
 	return 0;
 }
 
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
-	     const void *dout, void *din, unsigned long flags)
+static int mvebu_spi_ofdata_to_platdata(struct udevice *bus)
 {
-	return _spi_xfer(spireg, bitlen, dout, din, flags);
+	struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
+
+	plat->spireg = (struct kwspi_registers *)dev_get_addr(bus);
+
+	return 0;
 }
+
+static const struct dm_spi_ops mvebu_spi_ops = {
+	.xfer		= mvebu_spi_xfer,
+	.set_speed	= mvebu_spi_set_speed,
+	.set_mode	= mvebu_spi_set_mode,
+	/*
+	 * cs_info is not needed, since we require all chip selects to be
+	 * in the device tree explicitly
+	 */
+};
+
+static const struct udevice_id mvebu_spi_ids[] = {
+	{ .compatible = "marvell,armada-380-spi" },
+	{ .compatible = "marvell,armada-xp-spi" },
+	{ }
+};
+
+U_BOOT_DRIVER(mvebu_spi) = {
+	.name = "mvebu_spi",
+	.id = UCLASS_SPI,
+	.of_match = mvebu_spi_ids,
+	.ops = &mvebu_spi_ops,
+	.ofdata_to_platdata = mvebu_spi_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct mvebu_spi_platdata),
+	.priv_auto_alloc_size = sizeof(struct mvebu_spi_priv),
+	.probe = mvebu_spi_probe,
+};
+#endif
-- 
2.6.3



More information about the U-Boot mailing list