[U-Boot] [PATCH v1 1/3] spi: sh_qspi: DM conversion

Akash Gajjar gajjar04akash at gmail.com
Thu Apr 26 16:46:51 UTC 2018


This patch adds support for DM to the sh_qspi SPI driver.

The legacy functionality is removed in this version, so old boards in
the tree is not working with legacy SPI driver functionality.
Some TODOs are left over for later, These would be enhancements to the
original functionality, and can come later.

This patch is not tested on board as well compile tested yet.

Signed-off-by: Akash Gajjar <akash at openedev.com>
---
 drivers/spi/sh_qspi.c              | 199 ++++++++++++++++++-------------------
 include/dm/platform_data/qspi_sh.h |  20 ++++
 2 files changed, 119 insertions(+), 100 deletions(-)
 create mode 100644 include/dm/platform_data/qspi_sh.h

diff --git a/drivers/spi/sh_qspi.c b/drivers/spi/sh_qspi.c
index 5075be3..5fdd52e 100644
--- a/drivers/spi/sh_qspi.c
+++ b/drivers/spi/sh_qspi.c
@@ -1,6 +1,10 @@
 /*
  * SH QSPI (Quad SPI) driver
  *
+ * Support for device model:
+ * Copyright (C) 2018 Akash Gajjar <akash at openedev.com>
+ *		      Harshit Shah <shahharshitr at gmail.com>
+ *
  * Copyright (C) 2013 Renesas Electronics Corporation
  * Copyright (C) 2013 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj at renesas.com>
  *
@@ -14,6 +18,8 @@
 #include <wait_bit.h>
 #include <asm/arch/rmobile.h>
 #include <asm/io.h>
+#include <dm.h>
+#include <dm/platform_data/qspi_sh.h>
 
 /* SH QSPI register bit masks <REG>_<BIT> */
 #define SPCR_MSTR	0x08
@@ -67,151 +73,90 @@ struct sh_qspi_regs {
 	u32	spbmul3;
 };
 
-struct sh_qspi_slave {
-	struct spi_slave	slave;
-	struct sh_qspi_regs	*regs;
+struct sh_qspi_priv {
+	struct sh_qspi_regs *regs;
 };
 
-static inline struct sh_qspi_slave *to_sh_qspi(struct spi_slave *slave)
-{
-	return container_of(slave, struct sh_qspi_slave, slave);
-}
-
-static void sh_qspi_init(struct sh_qspi_slave *ss)
+static int __sh_qspi_setup(struct sh_qspi_priv *priv)
 {
 	/* QSPI initialize */
+	priv->regs = (struct sh_qspi_regs *)SH_QSPI_BASE;
+
 	/* Set master mode only */
-	writeb(SPCR_MSTR, &ss->regs->spcr);
+	writeb(SPCR_MSTR, &priv->regs->spcr);
 
 	/* Set SSL signal level */
-	writeb(0x00, &ss->regs->sslp);
+	writeb(0x00, &priv->regs->sslp);
 
 	/* Set MOSI signal value when transfer is in idle state */
-	writeb(SPPCR_IO3FV|SPPCR_IO2FV, &ss->regs->sppcr);
+	writeb(SPPCR_IO3FV | SPPCR_IO2FV, &priv->regs->sppcr);
 
 	/* Set bit rate. See 58.3.8 Quad Serial Peripheral Interface */
-	writeb(0x01, &ss->regs->spbr);
+	writeb(0x01, &priv->regs->spbr);
 
 	/* Disable Dummy Data Transmission */
-	writeb(0x00, &ss->regs->spdcr);
+	writeb(0x00, &priv->regs->spdcr);
 
 	/* Set clock delay value */
-	writeb(0x00, &ss->regs->spckd);
+	writeb(0x00, &priv->regs->spckd);
 
 	/* Set SSL negation delay value */
-	writeb(0x00, &ss->regs->sslnd);
+	writeb(0x00, &priv->regs->sslnd);
 
 	/* Set next-access delay value */
-	writeb(0x00, &ss->regs->spnd);
+	writeb(0x00, &priv->regs->spnd);
 
 	/* Set equence command */
-	writew(SPCMD_INIT2, &ss->regs->spcmd0);
+	writew(SPCMD_INIT2, &priv->regs->spcmd0);
 
 	/* Reset transfer and receive Buffer */
-	setbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST);
+	setbits_8(&priv->regs->spbfcr, SPBFCR_TXRST | SPBFCR_RXRST);
 
 	/* Clear transfer and receive Buffer control bit */
-	clrbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST);
+	clrbits_8(&priv->regs->spbfcr, SPBFCR_TXRST | SPBFCR_RXRST);
 
 	/* Set equence control method. Use equence0 only */
-	writeb(0x00, &ss->regs->spscr);
+	writeb(0x00, &priv->regs->spscr);
 
 	/* Enable SPI function */
-	setbits_8(&ss->regs->spcr, SPCR_SPE);
-}
-
-int spi_cs_is_valid(unsigned int bus, unsigned int cs)
-{
-	return 1;
-}
-
-void spi_cs_activate(struct spi_slave *slave)
-{
-	struct sh_qspi_slave *ss = to_sh_qspi(slave);
-
-	/* Set master mode only */
-	writeb(SPCR_MSTR, &ss->regs->spcr);
-
-	/* Set command */
-	writew(SPCMD_INIT1, &ss->regs->spcmd0);
-
-	/* Reset transfer and receive Buffer */
-	setbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST);
-
-	/* Clear transfer and receive Buffer control bit */
-	clrbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST);
-
-	/* Set equence control method. Use equence0 only */
-	writeb(0x00, &ss->regs->spscr);
-
-	/* Enable SPI function */
-	setbits_8(&ss->regs->spcr, SPCR_SPE);
-}
-
-void spi_cs_deactivate(struct spi_slave *slave)
-{
-	struct sh_qspi_slave *ss = to_sh_qspi(slave);
-
-	/* Disable SPI Function */
-	clrbits_8(&ss->regs->spcr, SPCR_SPE);
-}
-
-void spi_init(void)
-{
-	/* nothing to do */
+	setbits_8(&priv->regs->spcr, SPCR_SPE);
 }
 
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
-		unsigned int max_hz, unsigned int mode)
+static int sh_qspi_set_speed(struct udevice *bus, uint hz)
 {
-	struct sh_qspi_slave *ss;
-
-	if (!spi_cs_is_valid(bus, cs))
-		return NULL;
-
-	ss = spi_alloc_slave(struct sh_qspi_slave, bus, cs);
-	if (!ss) {
-		printf("SPI_error: Fail to allocate sh_qspi_slave\n");
-		return NULL;
-	}
-
-	ss->regs = (struct sh_qspi_regs *)SH_QSPI_BASE;
-
-	/* Init SH QSPI */
-	sh_qspi_init(ss);
-
-	return &ss->slave;
+	return 0;
 }
 
-void spi_free_slave(struct spi_slave *slave)
+static int sh_qspi_set_mode(struct udevice *bus, uint mode)
 {
-	struct sh_qspi_slave *spi = to_sh_qspi(slave);
-
-	free(spi);
+	return 0;
 }
 
-int spi_claim_bus(struct spi_slave *slave)
+static int sh_qspi_claim_bus(struct udevice *dev)
 {
 	return 0;
 }
 
-void spi_release_bus(struct spi_slave *slave)
+static int sh_qspi_release_bus(struct udevice *dev)
 {
+	return 0;
 }
 
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
-	     void *din, unsigned long flags)
+static int sh_qspi_xfer(struct udevice *dev, unsigned int bitlen,
+			  const void *dout, void *din, unsigned long flags)
 {
-	struct sh_qspi_slave *ss = to_sh_qspi(slave);
+	struct udevice *bus = dev_get_parent(dev);
+	struct sh_qspi_priv *priv = dev_get_priv(bus);
+	struct sh_qspi_regs *regs = priv->regs;
 	u32 nbyte, chunk;
 	int i, ret = 0;
 	u8 dtdata = 0, drdata;
 	u8 *tdata = &dtdata, *rdata = &drdata;
-	u32 *spbmul0 = &ss->regs->spbmul0;
+	u32 *spbmul0 = &regs->spbmul0;
 
 	if (dout == NULL && din == NULL) {
 		if (flags & SPI_XFER_END)
-			spi_cs_deactivate(slave);
+			spi_cs_deactivate(regs);
 		return 0;
 	}
 
@@ -223,7 +168,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
 	nbyte = bitlen / 8;
 
 	if (flags & SPI_XFER_BEGIN) {
-		spi_cs_activate(slave);
+		spi_cs_activate(regs);
 
 		/* Set 1048576 byte */
 		writel(0x100000, spbmul0);
@@ -245,27 +190,27 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
 		 */
 		chunk = (nbyte >= 32) ? 32 : 1;
 
-		clrsetbits_8(&ss->regs->spbfcr, SPBFCR_TXTRG | SPBFCR_RXTRG,
+		clrsetbits_8(&regs->spbfcr, SPBFCR_TXTRG | SPBFCR_RXTRG,
 			     chunk == 32 ? SPBFCR_TXTRG | SPBFCR_RXTRG : 0);
 
-		ret = wait_for_bit_8(&ss->regs->spsr, SPSR_SPTEF,
+		ret = wait_for_bit_8(&regs->spsr, SPSR_SPTEF,
 				     true, 1000, true);
 		if (ret)
 			return ret;
 
 		for (i = 0; i < chunk; i++) {
-			writeb(*tdata, &ss->regs->spdr);
+			writeb(*tdata, &regs->spdr);
 			if (dout != NULL)
 				tdata++;
 		}
 
-		ret = wait_for_bit_8(&ss->regs->spsr, SPSR_SPRFF,
+		ret = wait_for_bit_8(&regs->spsr, SPSR_SPRFF,
 				     true, 1000, true);
 		if (ret)
 			return ret;
 
 		for (i = 0; i < chunk; i++) {
-			*rdata = readb(&ss->regs->spdr);
+			*rdata = readb(&regs->spdr);
 			if (din != NULL)
 				rdata++;
 		}
@@ -274,7 +219,61 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
 	}
 
 	if (flags & SPI_XFER_END)
-		spi_cs_deactivate(slave);
+		spi_cs_deactivate(regs);
 
 	return ret;
 }
+
+static int sh_qspi_probe(struct udevice *bus)
+{
+	struct sh_qspi_platdata *plat = bus->platdata;
+	struct sh_qspi_priv *priv = dev_get_priv(bus);
+
+	__sh_qspi_setup(priv);
+
+	return 0;
+}
+
+static const struct dm_spi_ops sh_qspi_ops = {
+	.claim_bus	= sh_qspi_claim_bus,
+	.release_bus	= sh_qspi_release_bus,
+	.xfer		= sh_qspi_xfer,
+	.set_speed	= sh_qspi_set_speed,
+	.set_mode	= sh_qspi_set_mode,
+};
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+static int sh_qspi_ofdata_to_platadata(struct udevice *bus)
+{
+	struct sh_qspi_platdata *plat = bus->platdata;
+	fdt_addr_t addr;
+
+	addr = devfdt_get_addr(bus);
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	plat->cs = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus),
+			"num-cs", 4);
+
+	return 0;
+}
+
+static const struct udevice_id davinci_spi_ids[] = {
+	{ .compatible = "sh,sh-qspi" },
+	{ }
+};
+#endif
+
+U_BOOT_DRIVER(sh_qspi) = {
+	.name = "sh_qspi",
+	.id = UCLASS_SPI,
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+	.of_match = sh_qspi_ids,
+	.ofdata_to_platdata = sh_qspi_ofdata_to_platadata,
+	.platdata_auto_alloc_size = sizeof(struct sh_qspi_platdata),
+#endif
+	.ops = &sh_qspi_ops,
+	.priv_auto_alloc_size = sizeof(struct sh_qspi_priv),
+	.probe = sh_qspi_probe,
+};
+#endif
diff --git a/include/dm/platform_data/qspi_sh.h b/include/dm/platform_data/qspi_sh.h
new file mode 100644
index 0000000..1a8529c
--- /dev/null
+++ b/include/dm/platform_data/qspi_sh.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2018  Akash Gajjar <akash at openedev.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __qspi_sh_h
+#define __qspi_sh_h
+
+/*
+ * struct sh_qspi_platdata - information about a sh qspi module
+ *
+ */
+struct sh_qspi_platdata {
+	struct sh_qspi_regs *regs;
+	uint cs;
+};
+
+#endif /* __qspi_sh_h */
+
-- 
1.9.1



More information about the U-Boot mailing list