[U-Boot] [PATCH v3 00/12] Convert davinci_spi to DM

This series converts davinci_spi driver to adapt to driver model framework. And enables the driver on k2l, k2e, k2hk evms. Also, added support for davinci_spi on k2g evm.
Tested on k2l, k2e, k2hk and k2g evms.
Rebased on top of v2016.05-rc3
Vignesh R (12): dm: core: implement dev_map_phsymem() spi: davinci_spi: Convert to driver to adapt to DM keystone2: spi: do not define DM_SPI and DM_SPI_FLASH for SPL build ARM: dts: keystone2: add SPI aliases for davinci SPI nodes ARM: dts: k2hk: Enable Davinci SPI controller defconfig: k2hk_evm_defconfig: enable SPI driver model ARM: dts: k2e: Enable Davinci SPI controller defconfig: k2e_evm_defconfig: enable SPI driver model ARM: dts: k2l: Enable Davinci SPI controller defconfig: k2l_evm_defconfig: enable SPI driver model ARM: dts: k2g: add support for Davinci SPI controller defconfig: k2g_evm_defconfig: enable SPI driver model
arch/arm/dts/k2e-evm.dts | 3 +- arch/arm/dts/k2g-evm.dts | 24 +++ arch/arm/dts/k2g.dtsi | 47 +++++ arch/arm/dts/k2hk-evm.dts | 3 +- arch/arm/dts/k2l-evm.dts | 3 +- arch/arm/dts/keystone.dtsi | 3 + configs/k2e_evm_defconfig | 2 + configs/k2g_evm_defconfig | 2 + configs/k2hk_evm_defconfig | 2 + configs/k2l_evm_defconfig | 2 + drivers/core/device.c | 6 + drivers/spi/davinci_spi.c | 327 +++++++++++++++++++++++++---------- include/configs/ti_armv7_keystone2.h | 4 + include/dm/device.h | 9 + 14 files changed, 344 insertions(+), 93 deletions(-)

This API helps to map physical register addresss pace of device to virtual address space easily. Its just a wrapper around map_physmem() with MAP_NOCACHE flag.
Signed-off-by: Vignesh R vigneshr@ti.com Suggested-by: Simon Glass sjg@chromium.org ---
v3: Explicitly include header file
v2: New patch
drivers/core/device.c | 6 ++++++ include/dm/device.h | 9 +++++++++ 2 files changed, 15 insertions(+)
diff --git a/drivers/core/device.c b/drivers/core/device.c index 1322991d6c7b..6b19b4b8c7a0 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -10,6 +10,7 @@ */
#include <common.h> +#include <asm/io.h> #include <fdtdec.h> #include <fdt_support.h> #include <malloc.h> @@ -678,6 +679,11 @@ void *dev_get_addr_ptr(struct udevice *dev) return (void *)(uintptr_t)dev_get_addr_index(dev, 0); }
+void *dev_map_physmem(struct udevice *dev, unsigned long size) +{ + return map_physmem(dev_get_addr(dev), size, MAP_NOCACHE); +} + bool device_has_children(struct udevice *dev) { return !list_empty(&dev->child_head); diff --git a/include/dm/device.h b/include/dm/device.h index 8970fc015c7e..5253b5410d9a 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -463,6 +463,15 @@ fdt_addr_t dev_get_addr(struct udevice *dev); */ void *dev_get_addr_ptr(struct udevice *dev);
+/* * dev_map_physmem() - Map bus memory into CPU space + * + * @dev: Pointer to device + * @size: size of the memory to map + * + * @return addr + */ +void *dev_map_physmem(struct udevice *dev, unsigned long size); + /** * dev_get_addr_index() - Get the indexed reg property of a device *

On 4 May 2016 at 16:49, Vignesh R vigneshr@ti.com wrote:
This API helps to map physical register addresss pace of device to virtual address space easily. Its just a wrapper around map_physmem() with MAP_NOCACHE flag.
Signed-off-by: Vignesh R vigneshr@ti.com Suggested-by: Simon Glass sjg@chromium.org
Reviewed-by: Jagan Teki jteki@openedev.com

This API helps to map physical register addresss pace of device to virtual address space easily. Its just a wrapper around map_physmem() with MAP_NOCACHE flag.
Signed-off-by: Vignesh R vigneshr@ti.com Suggested-by: Simon Glass sjg@chromium.org Reviewed-by: Jagan Teki jteki@openedev.com
---
v4: Reorder include files to avoid build warning on dra7xx.
drivers/core/device.c | 6 ++++++ include/dm/device.h | 9 +++++++++ 2 files changed, 15 insertions(+)
diff --git a/drivers/core/device.c b/drivers/core/device.c index 1322991d6c7b..6b19b4b8c7a0 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -10,6 +10,7 @@ */
#include <common.h> +#include <asm/io.h> #include <fdtdec.h> #include <fdt_support.h> #include <malloc.h> @@ -678,6 +679,11 @@ void *dev_get_addr_ptr(struct udevice *dev) return (void *)(uintptr_t)dev_get_addr_index(dev, 0); }
+void *dev_map_physmem(struct udevice *dev, unsigned long size) +{ + return map_physmem(dev_get_addr(dev), size, MAP_NOCACHE); +} + bool device_has_children(struct udevice *dev) { return !list_empty(&dev->child_head); diff --git a/include/dm/device.h b/include/dm/device.h index 8970fc015c7e..5253b5410d9a 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -463,6 +463,15 @@ fdt_addr_t dev_get_addr(struct udevice *dev); */ void *dev_get_addr_ptr(struct udevice *dev);
+/* * dev_map_physmem() - Map bus memory into CPU space + * + * @dev: Pointer to device + * @size: size of the memory to map + * + * @return addr + */ +void *dev_map_physmem(struct udevice *dev, unsigned long size); + /** * dev_get_addr_index() - Get the indexed reg property of a device *

On 6 May 2016 at 09:28, Vignesh R vigneshr@ti.com wrote:
This API helps to map physical register addresss pace of device to virtual address space easily. Its just a wrapper around map_physmem() with MAP_NOCACHE flag.
Signed-off-by: Vignesh R vigneshr@ti.com Suggested-by: Simon Glass sjg@chromium.org Reviewed-by: Jagan Teki jteki@openedev.com
v4: Reorder include files to avoid build warning on dra7xx.
drivers/core/device.c | 6 ++++++ include/dm/device.h | 9 +++++++++ 2 files changed, 15 insertions(+)
diff --git a/drivers/core/device.c b/drivers/core/device.c index 1322991d6c7b..6b19b4b8c7a0 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -10,6 +10,7 @@ */
#include <common.h> +#include <asm/io.h>
I think this look same as v3 [1] please check?
#include <fdtdec.h> #include <fdt_support.h> #include <malloc.h>
[1] https://patchwork.ozlabs.org/patch/618361/

On 5/6/2016 9:00 PM, Jagan Teki wrote:
On 6 May 2016 at 09:28, Vignesh R vigneshr@ti.com wrote:
This API helps to map physical register addresss pace of device to virtual address space easily. Its just a wrapper around map_physmem() with MAP_NOCACHE flag.
Signed-off-by: Vignesh R vigneshr@ti.com Suggested-by: Simon Glass sjg@chromium.org Reviewed-by: Jagan Teki jteki@openedev.com
v4: Reorder include files to avoid build warning on dra7xx.
drivers/core/device.c | 6 ++++++ include/dm/device.h | 9 +++++++++ 2 files changed, 15 insertions(+)
diff --git a/drivers/core/device.c b/drivers/core/device.c index 1322991d6c7b..6b19b4b8c7a0 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -10,6 +10,7 @@ */
#include <common.h> +#include <asm/io.h>
I think this look same as v3 [1] please check?
Yeah, v3 has the include files in correct. Please ignore this patch. Sorry for the spam.
Regards Vignesh.

On 6 May 2016 at 21:16, R, Vignesh vigneshr@ti.com wrote:
On 5/6/2016 9:00 PM, Jagan Teki wrote:
On 6 May 2016 at 09:28, Vignesh R vigneshr@ti.com wrote:
This API helps to map physical register addresss pace of device to virtual address space easily. Its just a wrapper around map_physmem() with MAP_NOCACHE flag.
Signed-off-by: Vignesh R vigneshr@ti.com Suggested-by: Simon Glass sjg@chromium.org Reviewed-by: Jagan Teki jteki@openedev.com
v4: Reorder include files to avoid build warning on dra7xx.
drivers/core/device.c | 6 ++++++ include/dm/device.h | 9 +++++++++ 2 files changed, 15 insertions(+)
diff --git a/drivers/core/device.c b/drivers/core/device.c index 1322991d6c7b..6b19b4b8c7a0 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -10,6 +10,7 @@ */
#include <common.h> +#include <asm/io.h>
I think this look same as v3 [1] please check?
Yeah, v3 has the include files in correct. Please ignore this patch. Sorry for the spam.
Did you test this series on top of master?

On 05/06/2016 10:00 PM, Jagan Teki wrote:
On 6 May 2016 at 21:16, R, Vignesh vigneshr@ti.com wrote:
On 5/6/2016 9:00 PM, Jagan Teki wrote:
On 6 May 2016 at 09:28, Vignesh R vigneshr@ti.com wrote:
This API helps to map physical register addresss pace of device to virtual address space easily. Its just a wrapper around map_physmem() with MAP_NOCACHE flag.
Signed-off-by: Vignesh R vigneshr@ti.com Suggested-by: Simon Glass sjg@chromium.org Reviewed-by: Jagan Teki jteki@openedev.com
v4: Reorder include files to avoid build warning on dra7xx.
drivers/core/device.c | 6 ++++++ include/dm/device.h | 9 +++++++++ 2 files changed, 15 insertions(+)
diff --git a/drivers/core/device.c b/drivers/core/device.c index 1322991d6c7b..6b19b4b8c7a0 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -10,6 +10,7 @@ */
#include <common.h> +#include <asm/io.h>
I think this look same as v3 [1] please check?
Yeah, v3 has the include files in correct. Please ignore this patch. Sorry for the spam.
Did you test this series on top of master?
Yes, this is tested on top of 2016.05-rc3

Hi,
On 4 May 2016 at 05:19, Vignesh R vigneshr@ti.com wrote:
This API helps to map physical register addresss pace of device to virtual address space easily. Its just a wrapper around map_physmem() with MAP_NOCACHE flag.
Signed-off-by: Vignesh R vigneshr@ti.com Suggested-by: Simon Glass sjg@chromium.org
v3: Explicitly include header file
A few nits, sorry this review is late.
Please fix spelling of dev_map_phsymemin the commit subject.
v2: New patch
drivers/core/device.c | 6 ++++++ include/dm/device.h | 9 +++++++++ 2 files changed, 15 insertions(+)
diff --git a/drivers/core/device.c b/drivers/core/device.c index 1322991d6c7b..6b19b4b8c7a0 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -10,6 +10,7 @@ */
#include <common.h> +#include <asm/io.h> #include <fdtdec.h> #include <fdt_support.h> #include <malloc.h> @@ -678,6 +679,11 @@ void *dev_get_addr_ptr(struct udevice *dev) return (void *)(uintptr_t)dev_get_addr_index(dev, 0); }
+void *dev_map_physmem(struct udevice *dev, unsigned long size) +{
return map_physmem(dev_get_addr(dev), size, MAP_NOCACHE);
What happens if dev_get_addr() returns 0. Does it work OK? If not, please add a check for it.
+}
bool device_has_children(struct udevice *dev) { return !list_empty(&dev->child_head); diff --git a/include/dm/device.h b/include/dm/device.h index 8970fc015c7e..5253b5410d9a 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -463,6 +463,15 @@ fdt_addr_t dev_get_addr(struct udevice *dev); */ void *dev_get_addr_ptr(struct udevice *dev);
+/* * dev_map_physmem() - Map bus memory into CPU space
This is fine, but please add more detail on following lines. You need to mention that it reads the device address from the 'reg' property using dev_get_addr().
- @dev: Pointer to device
- @size: size of the memory to map
- @return addr
Something like:
@return mapped address, or 0 if the device does not have an address or the mapping failed
- */
+void *dev_map_physmem(struct udevice *dev, unsigned long size);
/**
- dev_get_addr_index() - Get the indexed reg property of a device
-- 2.8.2
Regards, Simon

On 05/15/2016 01:04 AM, Simon Glass wrote:
Hi,
On 4 May 2016 at 05:19, Vignesh R vigneshr@ti.com wrote:
This API helps to map physical register addresss pace of device to virtual address space easily. Its just a wrapper around map_physmem() with MAP_NOCACHE flag.
Signed-off-by: Vignesh R vigneshr@ti.com Suggested-by: Simon Glass sjg@chromium.org
v3: Explicitly include header file
A few nits, sorry this review is late.
Posted a v5 in reply to this thread.

This API helps to map physical register addresss pace of device to virtual address space easily. Its just a wrapper around map_physmem() with MAP_NOCACHE flag.
Signed-off-by: Vignesh R vigneshr@ti.com Suggested-by: Simon Glass sjg@chromium.org Reviewed-by: Jagan Teki jteki@openedev.com ---
v5: Fix comments by Simon Glass sjg@chromium.org
drivers/core/device.c | 11 +++++++++++ include/dm/device.h | 13 +++++++++++++ 2 files changed, 24 insertions(+)
diff --git a/drivers/core/device.c b/drivers/core/device.c index 1322991d6c7b..0406fc82f8d1 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -10,6 +10,7 @@ */
#include <common.h> +#include <asm/io.h> #include <fdtdec.h> #include <fdt_support.h> #include <malloc.h> @@ -678,6 +679,16 @@ void *dev_get_addr_ptr(struct udevice *dev) return (void *)(uintptr_t)dev_get_addr_index(dev, 0); }
+void *dev_map_physmem(struct udevice *dev, unsigned long size) +{ + fdt_addr_t addr = dev_get_addr(dev); + + if (addr == FDT_ADDR_T_NONE) + return NULL; + + return map_physmem(addr, size, MAP_NOCACHE); +} + bool device_has_children(struct udevice *dev) { return !list_empty(&dev->child_head); diff --git a/include/dm/device.h b/include/dm/device.h index 8970fc015c7e..9509c0b72ccb 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -464,6 +464,19 @@ fdt_addr_t dev_get_addr(struct udevice *dev); void *dev_get_addr_ptr(struct udevice *dev);
/** + * dev_map_physmem() - Read device address from reg property of the + * device node and map the address into CPU address + * space. + * + * @dev: Pointer to device + * @size: size of the memory to map + * + * @return mapped address, or NULL if the device does not have reg + * property. + */ +void *dev_map_physmem(struct udevice *dev, unsigned long size); + +/** * dev_get_addr_index() - Get the indexed reg property of a device * * @dev: Pointer to a device

On 16 May 2016 at 03:16, Vignesh R vigneshr@ti.com wrote:
This API helps to map physical register addresss pace of device to virtual address space easily. Its just a wrapper around map_physmem() with MAP_NOCACHE flag.
Signed-off-by: Vignesh R vigneshr@ti.com Suggested-by: Simon Glass sjg@chromium.org Reviewed-by: Jagan Teki jteki@openedev.com
v5: Fix comments by Simon Glass sjg@chromium.org
drivers/core/device.c | 11 +++++++++++ include/dm/device.h | 13 +++++++++++++ 2 files changed, 24 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

Convert davinci_spi driver so that it complies with SPI DM framework.
Signed-off-by: Vignesh R vigneshr@ti.com ---
v3: No changes
v2: Add comments to struct davinci_spi_slave members. Use dev_map_physmem() added by previous patch.
drivers/spi/davinci_spi.c | 327 +++++++++++++++++++++++++++++++++------------- 1 file changed, 237 insertions(+), 90 deletions(-)
diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index 0bd4f88926f1..75c8681d4e93 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -14,6 +14,7 @@ #include <malloc.h> #include <asm/io.h> #include <asm/arch/hardware.h> +#include <dm.h>
/* SPIGCR0 */ #define SPIGCR0_SPIENA_MASK 0x1 @@ -51,6 +52,7 @@ /* SPIDEF */ #define SPIDEF_CSDEF0_MASK BIT(0)
+#ifndef CONFIG_DM_SPI #define SPI0_BUS 0 #define SPI0_BASE CONFIG_SYS_SPI_BASE /* @@ -83,6 +85,9 @@ #define SPI2_NUM_CS CONFIG_SYS_SPI2_NUM_CS #define SPI2_BASE CONFIG_SYS_SPI2_BASE #endif +#endif + +DECLARE_GLOBAL_DATA_PTR;
/* davinci spi register set */ struct davinci_spi_regs { @@ -114,16 +119,17 @@ struct davinci_spi_regs {
/* davinci spi slave */ struct davinci_spi_slave { +#ifndef CONFIG_DM_SPI struct spi_slave slave; +#endif struct davinci_spi_regs *regs; - unsigned int freq; + unsigned int freq; /* current SPI bus frequency */ + unsigned int mode; /* current SPI mode used */ + u8 num_cs; /* total no. of CS available */ + u8 cur_cs; /* CS of current slave */ + bool half_duplex; /* true, if master is half-duplex only */ };
-static inline struct davinci_spi_slave *to_davinci_spi(struct spi_slave *slave) -{ - return container_of(slave, struct davinci_spi_slave, slave); -} - /* * This functions needs to act like a macro to avoid pipeline reloads in the * loops below. Use always_inline. This gains us about 160KiB/s and the bloat @@ -144,15 +150,14 @@ static inline u32 davinci_spi_xfer_data(struct davinci_spi_slave *ds, u32 data) return buf_reg_val; }
-static int davinci_spi_read(struct spi_slave *slave, unsigned int len, +static int davinci_spi_read(struct davinci_spi_slave *ds, unsigned int len, u8 *rxp, unsigned long flags) { - struct davinci_spi_slave *ds = to_davinci_spi(slave); unsigned int data1_reg_val;
/* enable CS hold, CS[n] and clear the data bits */ data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) | - (slave->cs << SPIDAT1_CSNR_SHIFT)); + (ds->cur_cs << SPIDAT1_CSNR_SHIFT));
/* wait till TXFULL is deasserted */ while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK) @@ -175,15 +180,14 @@ static int davinci_spi_read(struct spi_slave *slave, unsigned int len, return 0; }
-static int davinci_spi_write(struct spi_slave *slave, unsigned int len, +static int davinci_spi_write(struct davinci_spi_slave *ds, unsigned int len, const u8 *txp, unsigned long flags) { - struct davinci_spi_slave *ds = to_davinci_spi(slave); unsigned int data1_reg_val;
/* enable CS hold and clear the data bits */ data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) | - (slave->cs << SPIDAT1_CSNR_SHIFT)); + (ds->cur_cs << SPIDAT1_CSNR_SHIFT));
/* wait till TXFULL is deasserted */ while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK) @@ -209,16 +213,15 @@ static int davinci_spi_write(struct spi_slave *slave, unsigned int len, return 0; }
-#ifndef CONFIG_SPI_HALF_DUPLEX -static int davinci_spi_read_write(struct spi_slave *slave, unsigned int len, - u8 *rxp, const u8 *txp, unsigned long flags) +static int davinci_spi_read_write(struct davinci_spi_slave *ds, unsigned + int len, u8 *rxp, const u8 *txp, + unsigned long flags) { - struct davinci_spi_slave *ds = to_davinci_spi(slave); unsigned int data1_reg_val;
/* enable CS hold and clear the data bits */ data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) | - (slave->cs << SPIDAT1_CSNR_SHIFT)); + (ds->cur_cs << SPIDAT1_CSNR_SHIFT));
/* wait till TXFULL is deasserted */ while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK) @@ -237,7 +240,115 @@ static int davinci_spi_read_write(struct spi_slave *slave, unsigned int len,
return 0; } -#endif + + +static int __davinci_spi_claim_bus(struct davinci_spi_slave *ds, int cs) +{ + unsigned int mode = 0, scalar; + + /* Enable the SPI hardware */ + writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0); + udelay(1000); + writel(SPIGCR0_SPIENA_MASK, &ds->regs->gcr0); + + /* Set master mode, powered up and not activated */ + writel(SPIGCR1_MASTER_MASK | SPIGCR1_CLKMOD_MASK, &ds->regs->gcr1); + + /* CS, CLK, SIMO and SOMI are functional pins */ + writel(((1 << cs) | SPIPC0_CLKFUN_MASK | + SPIPC0_DOFUN_MASK | SPIPC0_DIFUN_MASK), &ds->regs->pc0); + + /* setup format */ + scalar = ((CONFIG_SYS_SPI_CLK / ds->freq) - 1) & 0xFF; + + /* + * Use following format: + * character length = 8, + * MSB shifted out first + */ + if (ds->mode & SPI_CPOL) + mode |= SPI_CPOL; + if (!(ds->mode & SPI_CPHA)) + mode |= SPI_CPHA; + writel(8 | (scalar << SPIFMT_PRESCALE_SHIFT) | + (mode << SPIFMT_PHASE_SHIFT), &ds->regs->fmt0); + + /* + * Including a minor delay. No science here. Should be good even with + * no delay + */ + writel((50 << SPI_C2TDELAY_SHIFT) | + (50 << SPI_T2CDELAY_SHIFT), &ds->regs->delay); + + /* default chip select register */ + writel(SPIDEF_CSDEF0_MASK, &ds->regs->def); + + /* no interrupts */ + writel(0, &ds->regs->int0); + writel(0, &ds->regs->lvl); + + /* enable SPI */ + writel((readl(&ds->regs->gcr1) | SPIGCR1_SPIENA_MASK), &ds->regs->gcr1); + + return 0; +} + +static int __davinci_spi_release_bus(struct davinci_spi_slave *ds) +{ + /* Disable the SPI hardware */ + writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0); + + return 0; +} + +static int __davinci_spi_xfer(struct davinci_spi_slave *ds, + unsigned int bitlen, const void *dout, void *din, + unsigned long flags) +{ + unsigned int len; + + if (bitlen == 0) + /* Finish any previously submitted transfers */ + goto out; + + /* + * It's not clear how non-8-bit-aligned transfers are supposed to be + * represented as a stream of bytes...this is a limitation of + * the current SPI interface - here we terminate on receiving such a + * transfer request. + */ + if (bitlen % 8) { + /* Errors always terminate an ongoing transfer */ + flags |= SPI_XFER_END; + goto out; + } + + len = bitlen / 8; + + if (!dout) + return davinci_spi_read(ds, len, din, flags); + if (!din) + return davinci_spi_write(ds, len, dout, flags); + if (!ds->half_duplex) + return davinci_spi_read_write(ds, len, din, dout, flags); + + printf("SPI full duplex not supported\n"); + flags |= SPI_XFER_END; + +out: + if (flags & SPI_XFER_END) { + u8 dummy = 0; + davinci_spi_write(ds, 1, &dummy, flags); + } + return 0; +} + +#ifndef CONFIG_DM_SPI + +static inline struct davinci_spi_slave *to_davinci_spi(struct spi_slave *slave) +{ + return container_of(slave, struct davinci_spi_slave, slave); +}
int spi_cs_is_valid(unsigned int bus, unsigned int cs) { @@ -313,6 +424,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, }
ds->freq = max_hz; + ds->mode = mode;
return &ds->slave; } @@ -324,104 +436,139 @@ void spi_free_slave(struct spi_slave *slave) free(ds); }
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct davinci_spi_slave *ds = to_davinci_spi(slave); + + ds->cur_cs = slave->cs; + + return __davinci_spi_xfer(ds, bitlen, dout, din, flags); +} + int spi_claim_bus(struct spi_slave *slave) { struct davinci_spi_slave *ds = to_davinci_spi(slave); - unsigned int scalar;
- /* Enable the SPI hardware */ - writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0); - udelay(1000); - writel(SPIGCR0_SPIENA_MASK, &ds->regs->gcr0); +#ifdef CONFIG_SPI_HALF_DUPLEX + ds->half_duplex = true; +#else + ds->half_duplex = false; +#endif + return __davinci_spi_claim_bus(ds, ds->slave.cs); +}
- /* Set master mode, powered up and not activated */ - writel(SPIGCR1_MASTER_MASK | SPIGCR1_CLKMOD_MASK, &ds->regs->gcr1); +void spi_release_bus(struct spi_slave *slave) +{ + struct davinci_spi_slave *ds = to_davinci_spi(slave);
- /* CS, CLK, SIMO and SOMI are functional pins */ - writel(((1 << slave->cs) | SPIPC0_CLKFUN_MASK | - SPIPC0_DOFUN_MASK | SPIPC0_DIFUN_MASK), &ds->regs->pc0); + __davinci_spi_release_bus(ds); +}
- /* setup format */ - scalar = ((CONFIG_SYS_SPI_CLK / ds->freq) - 1) & 0xFF; +#else +static int davinci_spi_set_speed(struct udevice *bus, uint max_hz) +{ + struct davinci_spi_slave *ds = dev_get_priv(bus);
- /* - * Use following format: - * character length = 8, - * clock signal delayed by half clk cycle, - * clock low in idle state - Mode 0, - * MSB shifted out first - */ - writel(8 | (scalar << SPIFMT_PRESCALE_SHIFT) | - (1 << SPIFMT_PHASE_SHIFT), &ds->regs->fmt0); + debug("%s speed %u\n", __func__, max_hz); + if (max_hz > CONFIG_SYS_SPI_CLK / 2) + return -EINVAL;
- /* - * Including a minor delay. No science here. Should be good even with - * no delay - */ - writel((50 << SPI_C2TDELAY_SHIFT) | - (50 << SPI_T2CDELAY_SHIFT), &ds->regs->delay); + ds->freq = max_hz;
- /* default chip select register */ - writel(SPIDEF_CSDEF0_MASK, &ds->regs->def); + return 0; +}
- /* no interrupts */ - writel(0, &ds->regs->int0); - writel(0, &ds->regs->lvl); +static int davinci_spi_set_mode(struct udevice *bus, uint mode) +{ + struct davinci_spi_slave *ds = dev_get_priv(bus);
- /* enable SPI */ - writel((readl(&ds->regs->gcr1) | SPIGCR1_SPIENA_MASK), &ds->regs->gcr1); + debug("%s mode %u\n", __func__, mode); + ds->mode = mode;
return 0; }
-void spi_release_bus(struct spi_slave *slave) +static int davinci_spi_claim_bus(struct udevice *dev) { - struct davinci_spi_slave *ds = to_davinci_spi(slave); + struct dm_spi_slave_platdata *slave_plat = + dev_get_parent_platdata(dev); + struct udevice *bus = dev->parent; + struct davinci_spi_slave *ds = dev_get_priv(bus); + + if (slave_plat->cs >= ds->num_cs) { + printf("Invalid SPI chipselect\n"); + return -EINVAL; + } + ds->half_duplex = slave_plat->mode & SPI_PREAMBLE;
- /* Disable the SPI hardware */ - writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0); + return __davinci_spi_claim_bus(ds, slave_plat->cs); }
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen, - const void *dout, void *din, unsigned long flags) +static int davinci_spi_release_bus(struct udevice *dev) { - unsigned int len; + struct davinci_spi_slave *ds = dev_get_priv(dev->parent);
- if (bitlen == 0) - /* Finish any previously submitted transfers */ - goto out; + return __davinci_spi_release_bus(ds); +}
- /* - * It's not clear how non-8-bit-aligned transfers are supposed to be - * represented as a stream of bytes...this is a limitation of - * the current SPI interface - here we terminate on receiving such a - * transfer request. - */ - if (bitlen % 8) { - /* Errors always terminate an ongoing transfer */ - flags |= SPI_XFER_END; - goto out; +static int davinci_spi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, + unsigned long flags) +{ + struct dm_spi_slave_platdata *slave = + dev_get_parent_platdata(dev); + struct udevice *bus = dev->parent; + struct davinci_spi_slave *ds = dev_get_priv(bus); + + if (slave->cs >= ds->num_cs) { + printf("Invalid SPI chipselect\n"); + return -EINVAL; } + ds->cur_cs = slave->cs;
- len = bitlen / 8; + return __davinci_spi_xfer(ds, bitlen, dout, din, flags); +}
- if (!dout) - return davinci_spi_read(slave, len, din, flags); - else if (!din) - return davinci_spi_write(slave, len, dout, flags); -#ifndef CONFIG_SPI_HALF_DUPLEX - else - return davinci_spi_read_write(slave, len, din, dout, flags); -#else - printf("SPI full duplex transaction requested with " - "CONFIG_SPI_HALF_DUPLEX defined.\n"); - flags |= SPI_XFER_END; -#endif +static int davinci_spi_probe(struct udevice *bus) +{ + /* Nothing to do */ + return 0; +} + +static int davinci_ofdata_to_platadata(struct udevice *bus) +{ + struct davinci_spi_slave *ds = dev_get_priv(bus); + const void *blob = gd->fdt_blob; + int node = bus->of_offset; + + ds->regs = dev_map_physmem(bus, sizeof(struct davinci_spi_regs)); + ds->num_cs = fdtdec_get_int(blob, node, "num-cs", 4);
-out: - if (flags & SPI_XFER_END) { - u8 dummy = 0; - davinci_spi_write(slave, 1, &dummy, flags); - } return 0; } + +static const struct dm_spi_ops davinci_spi_ops = { + .claim_bus = davinci_spi_claim_bus, + .release_bus = davinci_spi_release_bus, + .xfer = davinci_spi_xfer, + .set_speed = davinci_spi_set_speed, + .set_mode = davinci_spi_set_mode, +}; + +static const struct udevice_id davinci_spi_ids[] = { + { .compatible = "ti,keystone-spi" }, + { .compatible = "ti,dm6441-spi" }, + { } +}; + +U_BOOT_DRIVER(davinci_spi) = { + .name = "davinci_spi", + .id = UCLASS_SPI, + .of_match = davinci_spi_ids, + .ops = &davinci_spi_ops, + .ofdata_to_platdata = davinci_ofdata_to_platadata, + .priv_auto_alloc_size = sizeof(struct davinci_spi_slave), + .probe = davinci_spi_probe, +}; +#endif

On Wed, May 04, 2016 at 04:49:22PM +0530, Vignesh R wrote:
Convert davinci_spi driver so that it complies with SPI DM framework.
Signed-off-by: Vignesh R vigneshr@ti.com
Reviewed-by: Tom Rini trini@konsulko.com

Convert davinci_spi driver so that it complies with SPI DM framework.
Signed-off-by: Vignesh R vigneshr@ti.com Reviewed-by: Tom Rini trini@konsulko.com ---
v4: Check error returned by dev_map_physmem().
v3: No changes
v2: Add comments to struct davinci_spi_slave members. Use dev_map_physmem() added by previous patch.
drivers/spi/davinci_spi.c | 329 +++++++++++++++++++++++++++++++++------------- 1 file changed, 240 insertions(+), 89 deletions(-)
diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index 0bd4f88926f1..39a3801df231 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -14,6 +14,7 @@ #include <malloc.h> #include <asm/io.h> #include <asm/arch/hardware.h> +#include <dm.h>
/* SPIGCR0 */ #define SPIGCR0_SPIENA_MASK 0x1 @@ -51,6 +52,7 @@ /* SPIDEF */ #define SPIDEF_CSDEF0_MASK BIT(0)
+#ifndef CONFIG_DM_SPI #define SPI0_BUS 0 #define SPI0_BASE CONFIG_SYS_SPI_BASE /* @@ -83,6 +85,9 @@ #define SPI2_NUM_CS CONFIG_SYS_SPI2_NUM_CS #define SPI2_BASE CONFIG_SYS_SPI2_BASE #endif +#endif + +DECLARE_GLOBAL_DATA_PTR;
/* davinci spi register set */ struct davinci_spi_regs { @@ -114,16 +119,17 @@ struct davinci_spi_regs {
/* davinci spi slave */ struct davinci_spi_slave { +#ifndef CONFIG_DM_SPI struct spi_slave slave; +#endif struct davinci_spi_regs *regs; - unsigned int freq; + unsigned int freq; /* current SPI bus frequency */ + unsigned int mode; /* current SPI mode used */ + u8 num_cs; /* total no. of CS available */ + u8 cur_cs; /* CS of current slave */ + bool half_duplex; /* true, if master is half-duplex only */ };
-static inline struct davinci_spi_slave *to_davinci_spi(struct spi_slave *slave) -{ - return container_of(slave, struct davinci_spi_slave, slave); -} - /* * This functions needs to act like a macro to avoid pipeline reloads in the * loops below. Use always_inline. This gains us about 160KiB/s and the bloat @@ -144,15 +150,14 @@ static inline u32 davinci_spi_xfer_data(struct davinci_spi_slave *ds, u32 data) return buf_reg_val; }
-static int davinci_spi_read(struct spi_slave *slave, unsigned int len, +static int davinci_spi_read(struct davinci_spi_slave *ds, unsigned int len, u8 *rxp, unsigned long flags) { - struct davinci_spi_slave *ds = to_davinci_spi(slave); unsigned int data1_reg_val;
/* enable CS hold, CS[n] and clear the data bits */ data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) | - (slave->cs << SPIDAT1_CSNR_SHIFT)); + (ds->cur_cs << SPIDAT1_CSNR_SHIFT));
/* wait till TXFULL is deasserted */ while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK) @@ -175,15 +180,14 @@ static int davinci_spi_read(struct spi_slave *slave, unsigned int len, return 0; }
-static int davinci_spi_write(struct spi_slave *slave, unsigned int len, +static int davinci_spi_write(struct davinci_spi_slave *ds, unsigned int len, const u8 *txp, unsigned long flags) { - struct davinci_spi_slave *ds = to_davinci_spi(slave); unsigned int data1_reg_val;
/* enable CS hold and clear the data bits */ data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) | - (slave->cs << SPIDAT1_CSNR_SHIFT)); + (ds->cur_cs << SPIDAT1_CSNR_SHIFT));
/* wait till TXFULL is deasserted */ while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK) @@ -209,16 +213,15 @@ static int davinci_spi_write(struct spi_slave *slave, unsigned int len, return 0; }
-#ifndef CONFIG_SPI_HALF_DUPLEX -static int davinci_spi_read_write(struct spi_slave *slave, unsigned int len, - u8 *rxp, const u8 *txp, unsigned long flags) +static int davinci_spi_read_write(struct davinci_spi_slave *ds, unsigned + int len, u8 *rxp, const u8 *txp, + unsigned long flags) { - struct davinci_spi_slave *ds = to_davinci_spi(slave); unsigned int data1_reg_val;
/* enable CS hold and clear the data bits */ data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) | - (slave->cs << SPIDAT1_CSNR_SHIFT)); + (ds->cur_cs << SPIDAT1_CSNR_SHIFT));
/* wait till TXFULL is deasserted */ while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK) @@ -237,7 +240,115 @@ static int davinci_spi_read_write(struct spi_slave *slave, unsigned int len,
return 0; } -#endif + + +static int __davinci_spi_claim_bus(struct davinci_spi_slave *ds, int cs) +{ + unsigned int mode = 0, scalar; + + /* Enable the SPI hardware */ + writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0); + udelay(1000); + writel(SPIGCR0_SPIENA_MASK, &ds->regs->gcr0); + + /* Set master mode, powered up and not activated */ + writel(SPIGCR1_MASTER_MASK | SPIGCR1_CLKMOD_MASK, &ds->regs->gcr1); + + /* CS, CLK, SIMO and SOMI are functional pins */ + writel(((1 << cs) | SPIPC0_CLKFUN_MASK | + SPIPC0_DOFUN_MASK | SPIPC0_DIFUN_MASK), &ds->regs->pc0); + + /* setup format */ + scalar = ((CONFIG_SYS_SPI_CLK / ds->freq) - 1) & 0xFF; + + /* + * Use following format: + * character length = 8, + * MSB shifted out first + */ + if (ds->mode & SPI_CPOL) + mode |= SPI_CPOL; + if (!(ds->mode & SPI_CPHA)) + mode |= SPI_CPHA; + writel(8 | (scalar << SPIFMT_PRESCALE_SHIFT) | + (mode << SPIFMT_PHASE_SHIFT), &ds->regs->fmt0); + + /* + * Including a minor delay. No science here. Should be good even with + * no delay + */ + writel((50 << SPI_C2TDELAY_SHIFT) | + (50 << SPI_T2CDELAY_SHIFT), &ds->regs->delay); + + /* default chip select register */ + writel(SPIDEF_CSDEF0_MASK, &ds->regs->def); + + /* no interrupts */ + writel(0, &ds->regs->int0); + writel(0, &ds->regs->lvl); + + /* enable SPI */ + writel((readl(&ds->regs->gcr1) | SPIGCR1_SPIENA_MASK), &ds->regs->gcr1); + + return 0; +} + +static int __davinci_spi_release_bus(struct davinci_spi_slave *ds) +{ + /* Disable the SPI hardware */ + writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0); + + return 0; +} + +static int __davinci_spi_xfer(struct davinci_spi_slave *ds, + unsigned int bitlen, const void *dout, void *din, + unsigned long flags) +{ + unsigned int len; + + if (bitlen == 0) + /* Finish any previously submitted transfers */ + goto out; + + /* + * It's not clear how non-8-bit-aligned transfers are supposed to be + * represented as a stream of bytes...this is a limitation of + * the current SPI interface - here we terminate on receiving such a + * transfer request. + */ + if (bitlen % 8) { + /* Errors always terminate an ongoing transfer */ + flags |= SPI_XFER_END; + goto out; + } + + len = bitlen / 8; + + if (!dout) + return davinci_spi_read(ds, len, din, flags); + if (!din) + return davinci_spi_write(ds, len, dout, flags); + if (!ds->half_duplex) + return davinci_spi_read_write(ds, len, din, dout, flags); + + printf("SPI full duplex not supported\n"); + flags |= SPI_XFER_END; + +out: + if (flags & SPI_XFER_END) { + u8 dummy = 0; + davinci_spi_write(ds, 1, &dummy, flags); + } + return 0; +} + +#ifndef CONFIG_DM_SPI + +static inline struct davinci_spi_slave *to_davinci_spi(struct spi_slave *slave) +{ + return container_of(slave, struct davinci_spi_slave, slave); +}
int spi_cs_is_valid(unsigned int bus, unsigned int cs) { @@ -313,6 +424,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, }
ds->freq = max_hz; + ds->mode = mode;
return &ds->slave; } @@ -324,104 +436,143 @@ void spi_free_slave(struct spi_slave *slave) free(ds); }
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct davinci_spi_slave *ds = to_davinci_spi(slave); + + ds->cur_cs = slave->cs; + + return __davinci_spi_xfer(ds, bitlen, dout, din, flags); +} + int spi_claim_bus(struct spi_slave *slave) { struct davinci_spi_slave *ds = to_davinci_spi(slave); - unsigned int scalar;
- /* Enable the SPI hardware */ - writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0); - udelay(1000); - writel(SPIGCR0_SPIENA_MASK, &ds->regs->gcr0); +#ifdef CONFIG_SPI_HALF_DUPLEX + ds->half_duplex = true; +#else + ds->half_duplex = false; +#endif + return __davinci_spi_claim_bus(ds, ds->slave.cs); +}
- /* Set master mode, powered up and not activated */ - writel(SPIGCR1_MASTER_MASK | SPIGCR1_CLKMOD_MASK, &ds->regs->gcr1); +void spi_release_bus(struct spi_slave *slave) +{ + struct davinci_spi_slave *ds = to_davinci_spi(slave);
- /* CS, CLK, SIMO and SOMI are functional pins */ - writel(((1 << slave->cs) | SPIPC0_CLKFUN_MASK | - SPIPC0_DOFUN_MASK | SPIPC0_DIFUN_MASK), &ds->regs->pc0); + __davinci_spi_release_bus(ds); +}
- /* setup format */ - scalar = ((CONFIG_SYS_SPI_CLK / ds->freq) - 1) & 0xFF; +#else +static int davinci_spi_set_speed(struct udevice *bus, uint max_hz) +{ + struct davinci_spi_slave *ds = dev_get_priv(bus);
- /* - * Use following format: - * character length = 8, - * clock signal delayed by half clk cycle, - * clock low in idle state - Mode 0, - * MSB shifted out first - */ - writel(8 | (scalar << SPIFMT_PRESCALE_SHIFT) | - (1 << SPIFMT_PHASE_SHIFT), &ds->regs->fmt0); + debug("%s speed %u\n", __func__, max_hz); + if (max_hz > CONFIG_SYS_SPI_CLK / 2) + return -EINVAL;
- /* - * Including a minor delay. No science here. Should be good even with - * no delay - */ - writel((50 << SPI_C2TDELAY_SHIFT) | - (50 << SPI_T2CDELAY_SHIFT), &ds->regs->delay); + ds->freq = max_hz;
- /* default chip select register */ - writel(SPIDEF_CSDEF0_MASK, &ds->regs->def); + return 0; +}
- /* no interrupts */ - writel(0, &ds->regs->int0); - writel(0, &ds->regs->lvl); +static int davinci_spi_set_mode(struct udevice *bus, uint mode) +{ + struct davinci_spi_slave *ds = dev_get_priv(bus);
- /* enable SPI */ - writel((readl(&ds->regs->gcr1) | SPIGCR1_SPIENA_MASK), &ds->regs->gcr1); + debug("%s mode %u\n", __func__, mode); + ds->mode = mode;
return 0; }
-void spi_release_bus(struct spi_slave *slave) +static int davinci_spi_claim_bus(struct udevice *dev) { - struct davinci_spi_slave *ds = to_davinci_spi(slave); + struct dm_spi_slave_platdata *slave_plat = + dev_get_parent_platdata(dev); + struct udevice *bus = dev->parent; + struct davinci_spi_slave *ds = dev_get_priv(bus); + + if (slave_plat->cs >= ds->num_cs) { + printf("Invalid SPI chipselect\n"); + return -EINVAL; + } + ds->half_duplex = slave_plat->mode & SPI_PREAMBLE;
- /* Disable the SPI hardware */ - writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0); + return __davinci_spi_claim_bus(ds, slave_plat->cs); }
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen, - const void *dout, void *din, unsigned long flags) +static int davinci_spi_release_bus(struct udevice *dev) { - unsigned int len; + struct davinci_spi_slave *ds = dev_get_priv(dev->parent);
- if (bitlen == 0) - /* Finish any previously submitted transfers */ - goto out; + return __davinci_spi_release_bus(ds); +}
- /* - * It's not clear how non-8-bit-aligned transfers are supposed to be - * represented as a stream of bytes...this is a limitation of - * the current SPI interface - here we terminate on receiving such a - * transfer request. - */ - if (bitlen % 8) { - /* Errors always terminate an ongoing transfer */ - flags |= SPI_XFER_END; - goto out; +static int davinci_spi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, + unsigned long flags) +{ + struct dm_spi_slave_platdata *slave = + dev_get_parent_platdata(dev); + struct udevice *bus = dev->parent; + struct davinci_spi_slave *ds = dev_get_priv(bus); + + if (slave->cs >= ds->num_cs) { + printf("Invalid SPI chipselect\n"); + return -EINVAL; } + ds->cur_cs = slave->cs;
- len = bitlen / 8; + return __davinci_spi_xfer(ds, bitlen, dout, din, flags); +}
- if (!dout) - return davinci_spi_read(slave, len, din, flags); - else if (!din) - return davinci_spi_write(slave, len, dout, flags); -#ifndef CONFIG_SPI_HALF_DUPLEX - else - return davinci_spi_read_write(slave, len, din, dout, flags); -#else - printf("SPI full duplex transaction requested with " - "CONFIG_SPI_HALF_DUPLEX defined.\n"); - flags |= SPI_XFER_END; -#endif +static int davinci_spi_probe(struct udevice *bus) +{ + /* Nothing to do */ + return 0; +}
-out: - if (flags & SPI_XFER_END) { - u8 dummy = 0; - davinci_spi_write(slave, 1, &dummy, flags); +static int davinci_ofdata_to_platadata(struct udevice *bus) +{ + struct davinci_spi_slave *ds = dev_get_priv(bus); + const void *blob = gd->fdt_blob; + int node = bus->of_offset; + + ds->regs = dev_map_physmem(bus, sizeof(struct davinci_spi_regs)); + if (!ds->regs) { + printf("%s: could not map device address\n"); + return -ENODEV; } + ds->num_cs = fdtdec_get_int(blob, node, "num-cs", 4); + return 0; } + +static const struct dm_spi_ops davinci_spi_ops = { + .claim_bus = davinci_spi_claim_bus, + .release_bus = davinci_spi_release_bus, + .xfer = davinci_spi_xfer, + .set_speed = davinci_spi_set_speed, + .set_mode = davinci_spi_set_mode, +}; + +static const struct udevice_id davinci_spi_ids[] = { + { .compatible = "ti,keystone-spi" }, + { .compatible = "ti,dm6441-spi" }, + { } +}; + +U_BOOT_DRIVER(davinci_spi) = { + .name = "davinci_spi", + .id = UCLASS_SPI, + .of_match = davinci_spi_ids, + .ops = &davinci_spi_ops, + .ofdata_to_platdata = davinci_ofdata_to_platadata, + .priv_auto_alloc_size = sizeof(struct davinci_spi_slave), + .probe = davinci_spi_probe, +}; +#endif

On 16 May 2016 at 03:38, Vignesh R vigneshr@ti.com wrote:
Convert davinci_spi driver so that it complies with SPI DM framework.
Signed-off-by: Vignesh R vigneshr@ti.com Reviewed-by: Tom Rini trini@konsulko.com
v4: Check error returned by dev_map_physmem().
v3: No changes
v2: Add comments to struct davinci_spi_slave members. Use dev_map_physmem() added by previous patch.
drivers/spi/davinci_spi.c | 329 +++++++++++++++++++++++++++++++++------------- 1 file changed, 240 insertions(+), 89 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

Convert davinci_spi driver so that it complies with SPI DM framework.
Signed-off-by: Vignesh R vigneshr@ti.com Reviewed-by: Tom Rini trini@konsulko.com ---
v5: correct error message.
v4: Check error returned by dev_map_physmem().
v3: No changes
v2: Add comments to struct davinci_spi_slave members. Use dev_map_physmem() added by previous patch.
drivers/spi/davinci_spi.c | 329 +++++++++++++++++++++++++++++++++------------- 1 file changed, 240 insertions(+), 89 deletions(-)
diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index 0bd4f88926f1..22274c91a2f1 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -14,6 +14,7 @@ #include <malloc.h> #include <asm/io.h> #include <asm/arch/hardware.h> +#include <dm.h>
/* SPIGCR0 */ #define SPIGCR0_SPIENA_MASK 0x1 @@ -51,6 +52,7 @@ /* SPIDEF */ #define SPIDEF_CSDEF0_MASK BIT(0)
+#ifndef CONFIG_DM_SPI #define SPI0_BUS 0 #define SPI0_BASE CONFIG_SYS_SPI_BASE /* @@ -83,6 +85,9 @@ #define SPI2_NUM_CS CONFIG_SYS_SPI2_NUM_CS #define SPI2_BASE CONFIG_SYS_SPI2_BASE #endif +#endif + +DECLARE_GLOBAL_DATA_PTR;
/* davinci spi register set */ struct davinci_spi_regs { @@ -114,16 +119,17 @@ struct davinci_spi_regs {
/* davinci spi slave */ struct davinci_spi_slave { +#ifndef CONFIG_DM_SPI struct spi_slave slave; +#endif struct davinci_spi_regs *regs; - unsigned int freq; + unsigned int freq; /* current SPI bus frequency */ + unsigned int mode; /* current SPI mode used */ + u8 num_cs; /* total no. of CS available */ + u8 cur_cs; /* CS of current slave */ + bool half_duplex; /* true, if master is half-duplex only */ };
-static inline struct davinci_spi_slave *to_davinci_spi(struct spi_slave *slave) -{ - return container_of(slave, struct davinci_spi_slave, slave); -} - /* * This functions needs to act like a macro to avoid pipeline reloads in the * loops below. Use always_inline. This gains us about 160KiB/s and the bloat @@ -144,15 +150,14 @@ static inline u32 davinci_spi_xfer_data(struct davinci_spi_slave *ds, u32 data) return buf_reg_val; }
-static int davinci_spi_read(struct spi_slave *slave, unsigned int len, +static int davinci_spi_read(struct davinci_spi_slave *ds, unsigned int len, u8 *rxp, unsigned long flags) { - struct davinci_spi_slave *ds = to_davinci_spi(slave); unsigned int data1_reg_val;
/* enable CS hold, CS[n] and clear the data bits */ data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) | - (slave->cs << SPIDAT1_CSNR_SHIFT)); + (ds->cur_cs << SPIDAT1_CSNR_SHIFT));
/* wait till TXFULL is deasserted */ while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK) @@ -175,15 +180,14 @@ static int davinci_spi_read(struct spi_slave *slave, unsigned int len, return 0; }
-static int davinci_spi_write(struct spi_slave *slave, unsigned int len, +static int davinci_spi_write(struct davinci_spi_slave *ds, unsigned int len, const u8 *txp, unsigned long flags) { - struct davinci_spi_slave *ds = to_davinci_spi(slave); unsigned int data1_reg_val;
/* enable CS hold and clear the data bits */ data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) | - (slave->cs << SPIDAT1_CSNR_SHIFT)); + (ds->cur_cs << SPIDAT1_CSNR_SHIFT));
/* wait till TXFULL is deasserted */ while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK) @@ -209,16 +213,15 @@ static int davinci_spi_write(struct spi_slave *slave, unsigned int len, return 0; }
-#ifndef CONFIG_SPI_HALF_DUPLEX -static int davinci_spi_read_write(struct spi_slave *slave, unsigned int len, - u8 *rxp, const u8 *txp, unsigned long flags) +static int davinci_spi_read_write(struct davinci_spi_slave *ds, unsigned + int len, u8 *rxp, const u8 *txp, + unsigned long flags) { - struct davinci_spi_slave *ds = to_davinci_spi(slave); unsigned int data1_reg_val;
/* enable CS hold and clear the data bits */ data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) | - (slave->cs << SPIDAT1_CSNR_SHIFT)); + (ds->cur_cs << SPIDAT1_CSNR_SHIFT));
/* wait till TXFULL is deasserted */ while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK) @@ -237,7 +240,115 @@ static int davinci_spi_read_write(struct spi_slave *slave, unsigned int len,
return 0; } -#endif + + +static int __davinci_spi_claim_bus(struct davinci_spi_slave *ds, int cs) +{ + unsigned int mode = 0, scalar; + + /* Enable the SPI hardware */ + writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0); + udelay(1000); + writel(SPIGCR0_SPIENA_MASK, &ds->regs->gcr0); + + /* Set master mode, powered up and not activated */ + writel(SPIGCR1_MASTER_MASK | SPIGCR1_CLKMOD_MASK, &ds->regs->gcr1); + + /* CS, CLK, SIMO and SOMI are functional pins */ + writel(((1 << cs) | SPIPC0_CLKFUN_MASK | + SPIPC0_DOFUN_MASK | SPIPC0_DIFUN_MASK), &ds->regs->pc0); + + /* setup format */ + scalar = ((CONFIG_SYS_SPI_CLK / ds->freq) - 1) & 0xFF; + + /* + * Use following format: + * character length = 8, + * MSB shifted out first + */ + if (ds->mode & SPI_CPOL) + mode |= SPI_CPOL; + if (!(ds->mode & SPI_CPHA)) + mode |= SPI_CPHA; + writel(8 | (scalar << SPIFMT_PRESCALE_SHIFT) | + (mode << SPIFMT_PHASE_SHIFT), &ds->regs->fmt0); + + /* + * Including a minor delay. No science here. Should be good even with + * no delay + */ + writel((50 << SPI_C2TDELAY_SHIFT) | + (50 << SPI_T2CDELAY_SHIFT), &ds->regs->delay); + + /* default chip select register */ + writel(SPIDEF_CSDEF0_MASK, &ds->regs->def); + + /* no interrupts */ + writel(0, &ds->regs->int0); + writel(0, &ds->regs->lvl); + + /* enable SPI */ + writel((readl(&ds->regs->gcr1) | SPIGCR1_SPIENA_MASK), &ds->regs->gcr1); + + return 0; +} + +static int __davinci_spi_release_bus(struct davinci_spi_slave *ds) +{ + /* Disable the SPI hardware */ + writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0); + + return 0; +} + +static int __davinci_spi_xfer(struct davinci_spi_slave *ds, + unsigned int bitlen, const void *dout, void *din, + unsigned long flags) +{ + unsigned int len; + + if (bitlen == 0) + /* Finish any previously submitted transfers */ + goto out; + + /* + * It's not clear how non-8-bit-aligned transfers are supposed to be + * represented as a stream of bytes...this is a limitation of + * the current SPI interface - here we terminate on receiving such a + * transfer request. + */ + if (bitlen % 8) { + /* Errors always terminate an ongoing transfer */ + flags |= SPI_XFER_END; + goto out; + } + + len = bitlen / 8; + + if (!dout) + return davinci_spi_read(ds, len, din, flags); + if (!din) + return davinci_spi_write(ds, len, dout, flags); + if (!ds->half_duplex) + return davinci_spi_read_write(ds, len, din, dout, flags); + + printf("SPI full duplex not supported\n"); + flags |= SPI_XFER_END; + +out: + if (flags & SPI_XFER_END) { + u8 dummy = 0; + davinci_spi_write(ds, 1, &dummy, flags); + } + return 0; +} + +#ifndef CONFIG_DM_SPI + +static inline struct davinci_spi_slave *to_davinci_spi(struct spi_slave *slave) +{ + return container_of(slave, struct davinci_spi_slave, slave); +}
int spi_cs_is_valid(unsigned int bus, unsigned int cs) { @@ -313,6 +424,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, }
ds->freq = max_hz; + ds->mode = mode;
return &ds->slave; } @@ -324,104 +436,143 @@ void spi_free_slave(struct spi_slave *slave) free(ds); }
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct davinci_spi_slave *ds = to_davinci_spi(slave); + + ds->cur_cs = slave->cs; + + return __davinci_spi_xfer(ds, bitlen, dout, din, flags); +} + int spi_claim_bus(struct spi_slave *slave) { struct davinci_spi_slave *ds = to_davinci_spi(slave); - unsigned int scalar;
- /* Enable the SPI hardware */ - writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0); - udelay(1000); - writel(SPIGCR0_SPIENA_MASK, &ds->regs->gcr0); +#ifdef CONFIG_SPI_HALF_DUPLEX + ds->half_duplex = true; +#else + ds->half_duplex = false; +#endif + return __davinci_spi_claim_bus(ds, ds->slave.cs); +}
- /* Set master mode, powered up and not activated */ - writel(SPIGCR1_MASTER_MASK | SPIGCR1_CLKMOD_MASK, &ds->regs->gcr1); +void spi_release_bus(struct spi_slave *slave) +{ + struct davinci_spi_slave *ds = to_davinci_spi(slave);
- /* CS, CLK, SIMO and SOMI are functional pins */ - writel(((1 << slave->cs) | SPIPC0_CLKFUN_MASK | - SPIPC0_DOFUN_MASK | SPIPC0_DIFUN_MASK), &ds->regs->pc0); + __davinci_spi_release_bus(ds); +}
- /* setup format */ - scalar = ((CONFIG_SYS_SPI_CLK / ds->freq) - 1) & 0xFF; +#else +static int davinci_spi_set_speed(struct udevice *bus, uint max_hz) +{ + struct davinci_spi_slave *ds = dev_get_priv(bus);
- /* - * Use following format: - * character length = 8, - * clock signal delayed by half clk cycle, - * clock low in idle state - Mode 0, - * MSB shifted out first - */ - writel(8 | (scalar << SPIFMT_PRESCALE_SHIFT) | - (1 << SPIFMT_PHASE_SHIFT), &ds->regs->fmt0); + debug("%s speed %u\n", __func__, max_hz); + if (max_hz > CONFIG_SYS_SPI_CLK / 2) + return -EINVAL;
- /* - * Including a minor delay. No science here. Should be good even with - * no delay - */ - writel((50 << SPI_C2TDELAY_SHIFT) | - (50 << SPI_T2CDELAY_SHIFT), &ds->regs->delay); + ds->freq = max_hz;
- /* default chip select register */ - writel(SPIDEF_CSDEF0_MASK, &ds->regs->def); + return 0; +}
- /* no interrupts */ - writel(0, &ds->regs->int0); - writel(0, &ds->regs->lvl); +static int davinci_spi_set_mode(struct udevice *bus, uint mode) +{ + struct davinci_spi_slave *ds = dev_get_priv(bus);
- /* enable SPI */ - writel((readl(&ds->regs->gcr1) | SPIGCR1_SPIENA_MASK), &ds->regs->gcr1); + debug("%s mode %u\n", __func__, mode); + ds->mode = mode;
return 0; }
-void spi_release_bus(struct spi_slave *slave) +static int davinci_spi_claim_bus(struct udevice *dev) { - struct davinci_spi_slave *ds = to_davinci_spi(slave); + struct dm_spi_slave_platdata *slave_plat = + dev_get_parent_platdata(dev); + struct udevice *bus = dev->parent; + struct davinci_spi_slave *ds = dev_get_priv(bus); + + if (slave_plat->cs >= ds->num_cs) { + printf("Invalid SPI chipselect\n"); + return -EINVAL; + } + ds->half_duplex = slave_plat->mode & SPI_PREAMBLE;
- /* Disable the SPI hardware */ - writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0); + return __davinci_spi_claim_bus(ds, slave_plat->cs); }
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen, - const void *dout, void *din, unsigned long flags) +static int davinci_spi_release_bus(struct udevice *dev) { - unsigned int len; + struct davinci_spi_slave *ds = dev_get_priv(dev->parent);
- if (bitlen == 0) - /* Finish any previously submitted transfers */ - goto out; + return __davinci_spi_release_bus(ds); +}
- /* - * It's not clear how non-8-bit-aligned transfers are supposed to be - * represented as a stream of bytes...this is a limitation of - * the current SPI interface - here we terminate on receiving such a - * transfer request. - */ - if (bitlen % 8) { - /* Errors always terminate an ongoing transfer */ - flags |= SPI_XFER_END; - goto out; +static int davinci_spi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, + unsigned long flags) +{ + struct dm_spi_slave_platdata *slave = + dev_get_parent_platdata(dev); + struct udevice *bus = dev->parent; + struct davinci_spi_slave *ds = dev_get_priv(bus); + + if (slave->cs >= ds->num_cs) { + printf("Invalid SPI chipselect\n"); + return -EINVAL; } + ds->cur_cs = slave->cs;
- len = bitlen / 8; + return __davinci_spi_xfer(ds, bitlen, dout, din, flags); +}
- if (!dout) - return davinci_spi_read(slave, len, din, flags); - else if (!din) - return davinci_spi_write(slave, len, dout, flags); -#ifndef CONFIG_SPI_HALF_DUPLEX - else - return davinci_spi_read_write(slave, len, din, dout, flags); -#else - printf("SPI full duplex transaction requested with " - "CONFIG_SPI_HALF_DUPLEX defined.\n"); - flags |= SPI_XFER_END; -#endif +static int davinci_spi_probe(struct udevice *bus) +{ + /* Nothing to do */ + return 0; +}
-out: - if (flags & SPI_XFER_END) { - u8 dummy = 0; - davinci_spi_write(slave, 1, &dummy, flags); +static int davinci_ofdata_to_platadata(struct udevice *bus) +{ + struct davinci_spi_slave *ds = dev_get_priv(bus); + const void *blob = gd->fdt_blob; + int node = bus->of_offset; + + ds->regs = dev_map_physmem(bus, sizeof(struct davinci_spi_regs)); + if (!ds->regs) { + printf("%s: could not map device address\n", __func__); + return -ENODEV; } + ds->num_cs = fdtdec_get_int(blob, node, "num-cs", 4); + return 0; } + +static const struct dm_spi_ops davinci_spi_ops = { + .claim_bus = davinci_spi_claim_bus, + .release_bus = davinci_spi_release_bus, + .xfer = davinci_spi_xfer, + .set_speed = davinci_spi_set_speed, + .set_mode = davinci_spi_set_mode, +}; + +static const struct udevice_id davinci_spi_ids[] = { + { .compatible = "ti,keystone-spi" }, + { .compatible = "ti,dm6441-spi" }, + { } +}; + +U_BOOT_DRIVER(davinci_spi) = { + .name = "davinci_spi", + .id = UCLASS_SPI, + .of_match = davinci_spi_ids, + .ops = &davinci_spi_ops, + .ofdata_to_platdata = davinci_ofdata_to_platadata, + .priv_auto_alloc_size = sizeof(struct davinci_spi_slave), + .probe = davinci_spi_probe, +}; +#endif

Hi Vignesh,
On 19 May 2016 at 23:01, Vignesh R vigneshr@ti.com wrote:
Convert davinci_spi driver so that it complies with SPI DM framework.
Signed-off-by: Vignesh R vigneshr@ti.com Reviewed-by: Tom Rini trini@konsulko.com
v5: correct error message.
v4: Check error returned by dev_map_physmem().
v3: No changes
v2: Add comments to struct davinci_spi_slave members. Use dev_map_physmem() added by previous patch.
drivers/spi/davinci_spi.c | 329 +++++++++++++++++++++++++++++++++------------- 1 file changed, 240 insertions(+), 89 deletions(-)
Sorry I missed something below. [snip]
+static int davinci_ofdata_to_platadata(struct udevice *bus) +{
struct davinci_spi_slave *ds = dev_get_priv(bus);
const void *blob = gd->fdt_blob;
int node = bus->of_offset;
ds->regs = dev_map_physmem(bus, sizeof(struct davinci_spi_regs));
if (!ds->regs) {
printf("%s: could not map device address\n", __func__);
return -ENODEV;
-EINVAL
We use -ENODEV to say there is no device. Here, we have a device but the configuration is wrong.
}
ds->num_cs = fdtdec_get_int(blob, node, "num-cs", 4);
return 0;
}
+static const struct dm_spi_ops davinci_spi_ops = {
.claim_bus = davinci_spi_claim_bus,
.release_bus = davinci_spi_release_bus,
.xfer = davinci_spi_xfer,
.set_speed = davinci_spi_set_speed,
.set_mode = davinci_spi_set_mode,
+};
+static const struct udevice_id davinci_spi_ids[] = {
{ .compatible = "ti,keystone-spi" },
{ .compatible = "ti,dm6441-spi" },
{ }
+};
+U_BOOT_DRIVER(davinci_spi) = {
.name = "davinci_spi",
.id = UCLASS_SPI,
.of_match = davinci_spi_ids,
.ops = &davinci_spi_ops,
.ofdata_to_platdata = davinci_ofdata_to_platadata,
.priv_auto_alloc_size = sizeof(struct davinci_spi_slave),
.probe = davinci_spi_probe,
+};
+#endif
2.8.3

On 05/20/2016 08:54 PM, Simon Glass wrote:
Hi Vignesh,
On 19 May 2016 at 23:01, Vignesh R vigneshr@ti.com wrote:
Convert davinci_spi driver so that it complies with SPI DM framework.
Signed-off-by: Vignesh R vigneshr@ti.com Reviewed-by: Tom Rini trini@konsulko.com
v5: correct error message.
v4: Check error returned by dev_map_physmem().
v3: No changes
v2: Add comments to struct davinci_spi_slave members. Use dev_map_physmem() added by previous patch.
drivers/spi/davinci_spi.c | 329 +++++++++++++++++++++++++++++++++------------- 1 file changed, 240 insertions(+), 89 deletions(-)
Sorry I missed something below. [snip]
+static int davinci_ofdata_to_platadata(struct udevice *bus) +{
struct davinci_spi_slave *ds = dev_get_priv(bus);
const void *blob = gd->fdt_blob;
int node = bus->of_offset;
ds->regs = dev_map_physmem(bus, sizeof(struct davinci_spi_regs));
if (!ds->regs) {
printf("%s: could not map device address\n", __func__);
return -ENODEV;
-EINVAL
We use -ENODEV to say there is no device. Here, we have a device but the configuration is wrong.
Ok, I posted in v6 with above change.

Convert davinci_spi driver so that it complies with SPI DM framework.
Signed-off-by: Vignesh R vigneshr@ti.com ---
v6: Fix retval on dev_map_physmem() failure.
drivers/spi/davinci_spi.c | 329 +++++++++++++++++++++++++++++++++------------- 1 file changed, 240 insertions(+), 89 deletions(-)
diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index 0bd4f88926f1..20aa99a451dc 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -14,6 +14,7 @@ #include <malloc.h> #include <asm/io.h> #include <asm/arch/hardware.h> +#include <dm.h>
/* SPIGCR0 */ #define SPIGCR0_SPIENA_MASK 0x1 @@ -51,6 +52,7 @@ /* SPIDEF */ #define SPIDEF_CSDEF0_MASK BIT(0)
+#ifndef CONFIG_DM_SPI #define SPI0_BUS 0 #define SPI0_BASE CONFIG_SYS_SPI_BASE /* @@ -83,6 +85,9 @@ #define SPI2_NUM_CS CONFIG_SYS_SPI2_NUM_CS #define SPI2_BASE CONFIG_SYS_SPI2_BASE #endif +#endif + +DECLARE_GLOBAL_DATA_PTR;
/* davinci spi register set */ struct davinci_spi_regs { @@ -114,16 +119,17 @@ struct davinci_spi_regs {
/* davinci spi slave */ struct davinci_spi_slave { +#ifndef CONFIG_DM_SPI struct spi_slave slave; +#endif struct davinci_spi_regs *regs; - unsigned int freq; + unsigned int freq; /* current SPI bus frequency */ + unsigned int mode; /* current SPI mode used */ + u8 num_cs; /* total no. of CS available */ + u8 cur_cs; /* CS of current slave */ + bool half_duplex; /* true, if master is half-duplex only */ };
-static inline struct davinci_spi_slave *to_davinci_spi(struct spi_slave *slave) -{ - return container_of(slave, struct davinci_spi_slave, slave); -} - /* * This functions needs to act like a macro to avoid pipeline reloads in the * loops below. Use always_inline. This gains us about 160KiB/s and the bloat @@ -144,15 +150,14 @@ static inline u32 davinci_spi_xfer_data(struct davinci_spi_slave *ds, u32 data) return buf_reg_val; }
-static int davinci_spi_read(struct spi_slave *slave, unsigned int len, +static int davinci_spi_read(struct davinci_spi_slave *ds, unsigned int len, u8 *rxp, unsigned long flags) { - struct davinci_spi_slave *ds = to_davinci_spi(slave); unsigned int data1_reg_val;
/* enable CS hold, CS[n] and clear the data bits */ data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) | - (slave->cs << SPIDAT1_CSNR_SHIFT)); + (ds->cur_cs << SPIDAT1_CSNR_SHIFT));
/* wait till TXFULL is deasserted */ while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK) @@ -175,15 +180,14 @@ static int davinci_spi_read(struct spi_slave *slave, unsigned int len, return 0; }
-static int davinci_spi_write(struct spi_slave *slave, unsigned int len, +static int davinci_spi_write(struct davinci_spi_slave *ds, unsigned int len, const u8 *txp, unsigned long flags) { - struct davinci_spi_slave *ds = to_davinci_spi(slave); unsigned int data1_reg_val;
/* enable CS hold and clear the data bits */ data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) | - (slave->cs << SPIDAT1_CSNR_SHIFT)); + (ds->cur_cs << SPIDAT1_CSNR_SHIFT));
/* wait till TXFULL is deasserted */ while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK) @@ -209,16 +213,15 @@ static int davinci_spi_write(struct spi_slave *slave, unsigned int len, return 0; }
-#ifndef CONFIG_SPI_HALF_DUPLEX -static int davinci_spi_read_write(struct spi_slave *slave, unsigned int len, - u8 *rxp, const u8 *txp, unsigned long flags) +static int davinci_spi_read_write(struct davinci_spi_slave *ds, unsigned + int len, u8 *rxp, const u8 *txp, + unsigned long flags) { - struct davinci_spi_slave *ds = to_davinci_spi(slave); unsigned int data1_reg_val;
/* enable CS hold and clear the data bits */ data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) | - (slave->cs << SPIDAT1_CSNR_SHIFT)); + (ds->cur_cs << SPIDAT1_CSNR_SHIFT));
/* wait till TXFULL is deasserted */ while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK) @@ -237,7 +240,115 @@ static int davinci_spi_read_write(struct spi_slave *slave, unsigned int len,
return 0; } -#endif + + +static int __davinci_spi_claim_bus(struct davinci_spi_slave *ds, int cs) +{ + unsigned int mode = 0, scalar; + + /* Enable the SPI hardware */ + writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0); + udelay(1000); + writel(SPIGCR0_SPIENA_MASK, &ds->regs->gcr0); + + /* Set master mode, powered up and not activated */ + writel(SPIGCR1_MASTER_MASK | SPIGCR1_CLKMOD_MASK, &ds->regs->gcr1); + + /* CS, CLK, SIMO and SOMI are functional pins */ + writel(((1 << cs) | SPIPC0_CLKFUN_MASK | + SPIPC0_DOFUN_MASK | SPIPC0_DIFUN_MASK), &ds->regs->pc0); + + /* setup format */ + scalar = ((CONFIG_SYS_SPI_CLK / ds->freq) - 1) & 0xFF; + + /* + * Use following format: + * character length = 8, + * MSB shifted out first + */ + if (ds->mode & SPI_CPOL) + mode |= SPI_CPOL; + if (!(ds->mode & SPI_CPHA)) + mode |= SPI_CPHA; + writel(8 | (scalar << SPIFMT_PRESCALE_SHIFT) | + (mode << SPIFMT_PHASE_SHIFT), &ds->regs->fmt0); + + /* + * Including a minor delay. No science here. Should be good even with + * no delay + */ + writel((50 << SPI_C2TDELAY_SHIFT) | + (50 << SPI_T2CDELAY_SHIFT), &ds->regs->delay); + + /* default chip select register */ + writel(SPIDEF_CSDEF0_MASK, &ds->regs->def); + + /* no interrupts */ + writel(0, &ds->regs->int0); + writel(0, &ds->regs->lvl); + + /* enable SPI */ + writel((readl(&ds->regs->gcr1) | SPIGCR1_SPIENA_MASK), &ds->regs->gcr1); + + return 0; +} + +static int __davinci_spi_release_bus(struct davinci_spi_slave *ds) +{ + /* Disable the SPI hardware */ + writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0); + + return 0; +} + +static int __davinci_spi_xfer(struct davinci_spi_slave *ds, + unsigned int bitlen, const void *dout, void *din, + unsigned long flags) +{ + unsigned int len; + + if (bitlen == 0) + /* Finish any previously submitted transfers */ + goto out; + + /* + * It's not clear how non-8-bit-aligned transfers are supposed to be + * represented as a stream of bytes...this is a limitation of + * the current SPI interface - here we terminate on receiving such a + * transfer request. + */ + if (bitlen % 8) { + /* Errors always terminate an ongoing transfer */ + flags |= SPI_XFER_END; + goto out; + } + + len = bitlen / 8; + + if (!dout) + return davinci_spi_read(ds, len, din, flags); + if (!din) + return davinci_spi_write(ds, len, dout, flags); + if (!ds->half_duplex) + return davinci_spi_read_write(ds, len, din, dout, flags); + + printf("SPI full duplex not supported\n"); + flags |= SPI_XFER_END; + +out: + if (flags & SPI_XFER_END) { + u8 dummy = 0; + davinci_spi_write(ds, 1, &dummy, flags); + } + return 0; +} + +#ifndef CONFIG_DM_SPI + +static inline struct davinci_spi_slave *to_davinci_spi(struct spi_slave *slave) +{ + return container_of(slave, struct davinci_spi_slave, slave); +}
int spi_cs_is_valid(unsigned int bus, unsigned int cs) { @@ -313,6 +424,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, }
ds->freq = max_hz; + ds->mode = mode;
return &ds->slave; } @@ -324,104 +436,143 @@ void spi_free_slave(struct spi_slave *slave) free(ds); }
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct davinci_spi_slave *ds = to_davinci_spi(slave); + + ds->cur_cs = slave->cs; + + return __davinci_spi_xfer(ds, bitlen, dout, din, flags); +} + int spi_claim_bus(struct spi_slave *slave) { struct davinci_spi_slave *ds = to_davinci_spi(slave); - unsigned int scalar;
- /* Enable the SPI hardware */ - writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0); - udelay(1000); - writel(SPIGCR0_SPIENA_MASK, &ds->regs->gcr0); +#ifdef CONFIG_SPI_HALF_DUPLEX + ds->half_duplex = true; +#else + ds->half_duplex = false; +#endif + return __davinci_spi_claim_bus(ds, ds->slave.cs); +}
- /* Set master mode, powered up and not activated */ - writel(SPIGCR1_MASTER_MASK | SPIGCR1_CLKMOD_MASK, &ds->regs->gcr1); +void spi_release_bus(struct spi_slave *slave) +{ + struct davinci_spi_slave *ds = to_davinci_spi(slave);
- /* CS, CLK, SIMO and SOMI are functional pins */ - writel(((1 << slave->cs) | SPIPC0_CLKFUN_MASK | - SPIPC0_DOFUN_MASK | SPIPC0_DIFUN_MASK), &ds->regs->pc0); + __davinci_spi_release_bus(ds); +}
- /* setup format */ - scalar = ((CONFIG_SYS_SPI_CLK / ds->freq) - 1) & 0xFF; +#else +static int davinci_spi_set_speed(struct udevice *bus, uint max_hz) +{ + struct davinci_spi_slave *ds = dev_get_priv(bus);
- /* - * Use following format: - * character length = 8, - * clock signal delayed by half clk cycle, - * clock low in idle state - Mode 0, - * MSB shifted out first - */ - writel(8 | (scalar << SPIFMT_PRESCALE_SHIFT) | - (1 << SPIFMT_PHASE_SHIFT), &ds->regs->fmt0); + debug("%s speed %u\n", __func__, max_hz); + if (max_hz > CONFIG_SYS_SPI_CLK / 2) + return -EINVAL;
- /* - * Including a minor delay. No science here. Should be good even with - * no delay - */ - writel((50 << SPI_C2TDELAY_SHIFT) | - (50 << SPI_T2CDELAY_SHIFT), &ds->regs->delay); + ds->freq = max_hz;
- /* default chip select register */ - writel(SPIDEF_CSDEF0_MASK, &ds->regs->def); + return 0; +}
- /* no interrupts */ - writel(0, &ds->regs->int0); - writel(0, &ds->regs->lvl); +static int davinci_spi_set_mode(struct udevice *bus, uint mode) +{ + struct davinci_spi_slave *ds = dev_get_priv(bus);
- /* enable SPI */ - writel((readl(&ds->regs->gcr1) | SPIGCR1_SPIENA_MASK), &ds->regs->gcr1); + debug("%s mode %u\n", __func__, mode); + ds->mode = mode;
return 0; }
-void spi_release_bus(struct spi_slave *slave) +static int davinci_spi_claim_bus(struct udevice *dev) { - struct davinci_spi_slave *ds = to_davinci_spi(slave); + struct dm_spi_slave_platdata *slave_plat = + dev_get_parent_platdata(dev); + struct udevice *bus = dev->parent; + struct davinci_spi_slave *ds = dev_get_priv(bus); + + if (slave_plat->cs >= ds->num_cs) { + printf("Invalid SPI chipselect\n"); + return -EINVAL; + } + ds->half_duplex = slave_plat->mode & SPI_PREAMBLE;
- /* Disable the SPI hardware */ - writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0); + return __davinci_spi_claim_bus(ds, slave_plat->cs); }
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen, - const void *dout, void *din, unsigned long flags) +static int davinci_spi_release_bus(struct udevice *dev) { - unsigned int len; + struct davinci_spi_slave *ds = dev_get_priv(dev->parent);
- if (bitlen == 0) - /* Finish any previously submitted transfers */ - goto out; + return __davinci_spi_release_bus(ds); +}
- /* - * It's not clear how non-8-bit-aligned transfers are supposed to be - * represented as a stream of bytes...this is a limitation of - * the current SPI interface - here we terminate on receiving such a - * transfer request. - */ - if (bitlen % 8) { - /* Errors always terminate an ongoing transfer */ - flags |= SPI_XFER_END; - goto out; +static int davinci_spi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, + unsigned long flags) +{ + struct dm_spi_slave_platdata *slave = + dev_get_parent_platdata(dev); + struct udevice *bus = dev->parent; + struct davinci_spi_slave *ds = dev_get_priv(bus); + + if (slave->cs >= ds->num_cs) { + printf("Invalid SPI chipselect\n"); + return -EINVAL; } + ds->cur_cs = slave->cs;
- len = bitlen / 8; + return __davinci_spi_xfer(ds, bitlen, dout, din, flags); +}
- if (!dout) - return davinci_spi_read(slave, len, din, flags); - else if (!din) - return davinci_spi_write(slave, len, dout, flags); -#ifndef CONFIG_SPI_HALF_DUPLEX - else - return davinci_spi_read_write(slave, len, din, dout, flags); -#else - printf("SPI full duplex transaction requested with " - "CONFIG_SPI_HALF_DUPLEX defined.\n"); - flags |= SPI_XFER_END; -#endif +static int davinci_spi_probe(struct udevice *bus) +{ + /* Nothing to do */ + return 0; +}
-out: - if (flags & SPI_XFER_END) { - u8 dummy = 0; - davinci_spi_write(slave, 1, &dummy, flags); +static int davinci_ofdata_to_platadata(struct udevice *bus) +{ + struct davinci_spi_slave *ds = dev_get_priv(bus); + const void *blob = gd->fdt_blob; + int node = bus->of_offset; + + ds->regs = dev_map_physmem(bus, sizeof(struct davinci_spi_regs)); + if (!ds->regs) { + printf("%s: could not map device address\n", __func__); + return -EINVAL; } + ds->num_cs = fdtdec_get_int(blob, node, "num-cs", 4); + return 0; } + +static const struct dm_spi_ops davinci_spi_ops = { + .claim_bus = davinci_spi_claim_bus, + .release_bus = davinci_spi_release_bus, + .xfer = davinci_spi_xfer, + .set_speed = davinci_spi_set_speed, + .set_mode = davinci_spi_set_mode, +}; + +static const struct udevice_id davinci_spi_ids[] = { + { .compatible = "ti,keystone-spi" }, + { .compatible = "ti,dm6441-spi" }, + { } +}; + +U_BOOT_DRIVER(davinci_spi) = { + .name = "davinci_spi", + .id = UCLASS_SPI, + .of_match = davinci_spi_ids, + .ops = &davinci_spi_ops, + .ofdata_to_platdata = davinci_ofdata_to_platadata, + .priv_auto_alloc_size = sizeof(struct davinci_spi_slave), + .probe = davinci_spi_probe, +}; +#endif

On Tuesday 24 May 2016 09:54 AM, Vignesh R wrote:
Convert davinci_spi driver so that it complies with SPI DM framework.
Signed-off-by: Vignesh R vigneshr@ti.com
v6: Fix retval on dev_map_physmem() failure.
Gentle ping....
drivers/spi/davinci_spi.c | 329 +++++++++++++++++++++++++++++++++------------- 1 file changed, 240 insertions(+), 89 deletions(-)
diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index 0bd4f88926f1..20aa99a451dc 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -14,6 +14,7 @@ #include <malloc.h> #include <asm/io.h> #include <asm/arch/hardware.h> +#include <dm.h>
/* SPIGCR0 */ #define SPIGCR0_SPIENA_MASK 0x1 @@ -51,6 +52,7 @@ /* SPIDEF */ #define SPIDEF_CSDEF0_MASK BIT(0)
+#ifndef CONFIG_DM_SPI #define SPI0_BUS 0 #define SPI0_BASE CONFIG_SYS_SPI_BASE /* @@ -83,6 +85,9 @@ #define SPI2_NUM_CS CONFIG_SYS_SPI2_NUM_CS #define SPI2_BASE CONFIG_SYS_SPI2_BASE #endif +#endif
+DECLARE_GLOBAL_DATA_PTR;
/* davinci spi register set */ struct davinci_spi_regs { @@ -114,16 +119,17 @@ struct davinci_spi_regs {
/* davinci spi slave */ struct davinci_spi_slave { +#ifndef CONFIG_DM_SPI struct spi_slave slave; +#endif struct davinci_spi_regs *regs;
- unsigned int freq;
- unsigned int freq; /* current SPI bus frequency */
- unsigned int mode; /* current SPI mode used */
- u8 num_cs; /* total no. of CS available */
- u8 cur_cs; /* CS of current slave */
- bool half_duplex; /* true, if master is half-duplex only */
};
-static inline struct davinci_spi_slave *to_davinci_spi(struct spi_slave *slave) -{
- return container_of(slave, struct davinci_spi_slave, slave);
-}
/*
- This functions needs to act like a macro to avoid pipeline reloads in the
- loops below. Use always_inline. This gains us about 160KiB/s and the bloat
@@ -144,15 +150,14 @@ static inline u32 davinci_spi_xfer_data(struct davinci_spi_slave *ds, u32 data) return buf_reg_val; }
-static int davinci_spi_read(struct spi_slave *slave, unsigned int len, +static int davinci_spi_read(struct davinci_spi_slave *ds, unsigned int len, u8 *rxp, unsigned long flags) {
struct davinci_spi_slave *ds = to_davinci_spi(slave); unsigned int data1_reg_val;
/* enable CS hold, CS[n] and clear the data bits */ data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) |
(slave->cs << SPIDAT1_CSNR_SHIFT));
(ds->cur_cs << SPIDAT1_CSNR_SHIFT));
/* wait till TXFULL is deasserted */ while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK)
@@ -175,15 +180,14 @@ static int davinci_spi_read(struct spi_slave *slave, unsigned int len, return 0; }
-static int davinci_spi_write(struct spi_slave *slave, unsigned int len, +static int davinci_spi_write(struct davinci_spi_slave *ds, unsigned int len, const u8 *txp, unsigned long flags) {
struct davinci_spi_slave *ds = to_davinci_spi(slave); unsigned int data1_reg_val;
/* enable CS hold and clear the data bits */ data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) |
(slave->cs << SPIDAT1_CSNR_SHIFT));
(ds->cur_cs << SPIDAT1_CSNR_SHIFT));
/* wait till TXFULL is deasserted */ while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK)
@@ -209,16 +213,15 @@ static int davinci_spi_write(struct spi_slave *slave, unsigned int len, return 0; }
-#ifndef CONFIG_SPI_HALF_DUPLEX -static int davinci_spi_read_write(struct spi_slave *slave, unsigned int len,
u8 *rxp, const u8 *txp, unsigned long flags)
+static int davinci_spi_read_write(struct davinci_spi_slave *ds, unsigned
int len, u8 *rxp, const u8 *txp,
unsigned long flags)
{
struct davinci_spi_slave *ds = to_davinci_spi(slave); unsigned int data1_reg_val;
/* enable CS hold and clear the data bits */ data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) |
(slave->cs << SPIDAT1_CSNR_SHIFT));
(ds->cur_cs << SPIDAT1_CSNR_SHIFT));
/* wait till TXFULL is deasserted */ while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK)
@@ -237,7 +240,115 @@ static int davinci_spi_read_write(struct spi_slave *slave, unsigned int len,
return 0; } -#endif
+static int __davinci_spi_claim_bus(struct davinci_spi_slave *ds, int cs) +{
- unsigned int mode = 0, scalar;
- /* Enable the SPI hardware */
- writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0);
- udelay(1000);
- writel(SPIGCR0_SPIENA_MASK, &ds->regs->gcr0);
- /* Set master mode, powered up and not activated */
- writel(SPIGCR1_MASTER_MASK | SPIGCR1_CLKMOD_MASK, &ds->regs->gcr1);
- /* CS, CLK, SIMO and SOMI are functional pins */
- writel(((1 << cs) | SPIPC0_CLKFUN_MASK |
SPIPC0_DOFUN_MASK | SPIPC0_DIFUN_MASK), &ds->regs->pc0);
- /* setup format */
- scalar = ((CONFIG_SYS_SPI_CLK / ds->freq) - 1) & 0xFF;
- /*
* Use following format:
* character length = 8,
* MSB shifted out first
*/
- if (ds->mode & SPI_CPOL)
mode |= SPI_CPOL;
- if (!(ds->mode & SPI_CPHA))
mode |= SPI_CPHA;
- writel(8 | (scalar << SPIFMT_PRESCALE_SHIFT) |
(mode << SPIFMT_PHASE_SHIFT), &ds->regs->fmt0);
- /*
* Including a minor delay. No science here. Should be good even with
* no delay
*/
- writel((50 << SPI_C2TDELAY_SHIFT) |
(50 << SPI_T2CDELAY_SHIFT), &ds->regs->delay);
- /* default chip select register */
- writel(SPIDEF_CSDEF0_MASK, &ds->regs->def);
- /* no interrupts */
- writel(0, &ds->regs->int0);
- writel(0, &ds->regs->lvl);
- /* enable SPI */
- writel((readl(&ds->regs->gcr1) | SPIGCR1_SPIENA_MASK), &ds->regs->gcr1);
- return 0;
+}
+static int __davinci_spi_release_bus(struct davinci_spi_slave *ds) +{
- /* Disable the SPI hardware */
- writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0);
- return 0;
+}
+static int __davinci_spi_xfer(struct davinci_spi_slave *ds,
unsigned int bitlen, const void *dout, void *din,
unsigned long flags)
+{
- unsigned int len;
- if (bitlen == 0)
/* Finish any previously submitted transfers */
goto out;
- /*
* It's not clear how non-8-bit-aligned transfers are supposed to be
* represented as a stream of bytes...this is a limitation of
* the current SPI interface - here we terminate on receiving such a
* transfer request.
*/
- if (bitlen % 8) {
/* Errors always terminate an ongoing transfer */
flags |= SPI_XFER_END;
goto out;
- }
- len = bitlen / 8;
- if (!dout)
return davinci_spi_read(ds, len, din, flags);
- if (!din)
return davinci_spi_write(ds, len, dout, flags);
- if (!ds->half_duplex)
return davinci_spi_read_write(ds, len, din, dout, flags);
- printf("SPI full duplex not supported\n");
- flags |= SPI_XFER_END;
+out:
- if (flags & SPI_XFER_END) {
u8 dummy = 0;
davinci_spi_write(ds, 1, &dummy, flags);
- }
- return 0;
+}
+#ifndef CONFIG_DM_SPI
+static inline struct davinci_spi_slave *to_davinci_spi(struct spi_slave *slave) +{
- return container_of(slave, struct davinci_spi_slave, slave);
+}
int spi_cs_is_valid(unsigned int bus, unsigned int cs) { @@ -313,6 +424,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, }
ds->freq = max_hz;
ds->mode = mode;
return &ds->slave;
} @@ -324,104 +436,143 @@ void spi_free_slave(struct spi_slave *slave) free(ds); }
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
const void *dout, void *din, unsigned long flags)
+{
- struct davinci_spi_slave *ds = to_davinci_spi(slave);
- ds->cur_cs = slave->cs;
- return __davinci_spi_xfer(ds, bitlen, dout, din, flags);
+}
int spi_claim_bus(struct spi_slave *slave) { struct davinci_spi_slave *ds = to_davinci_spi(slave);
unsigned int scalar;
/* Enable the SPI hardware */
writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0);
udelay(1000);
writel(SPIGCR0_SPIENA_MASK, &ds->regs->gcr0);
+#ifdef CONFIG_SPI_HALF_DUPLEX
- ds->half_duplex = true;
+#else
- ds->half_duplex = false;
+#endif
- return __davinci_spi_claim_bus(ds, ds->slave.cs);
+}
- /* Set master mode, powered up and not activated */
- writel(SPIGCR1_MASTER_MASK | SPIGCR1_CLKMOD_MASK, &ds->regs->gcr1);
+void spi_release_bus(struct spi_slave *slave) +{
- struct davinci_spi_slave *ds = to_davinci_spi(slave);
- /* CS, CLK, SIMO and SOMI are functional pins */
- writel(((1 << slave->cs) | SPIPC0_CLKFUN_MASK |
SPIPC0_DOFUN_MASK | SPIPC0_DIFUN_MASK), &ds->regs->pc0);
- __davinci_spi_release_bus(ds);
+}
- /* setup format */
- scalar = ((CONFIG_SYS_SPI_CLK / ds->freq) - 1) & 0xFF;
+#else +static int davinci_spi_set_speed(struct udevice *bus, uint max_hz) +{
- struct davinci_spi_slave *ds = dev_get_priv(bus);
- /*
* Use following format:
* character length = 8,
* clock signal delayed by half clk cycle,
* clock low in idle state - Mode 0,
* MSB shifted out first
*/
- writel(8 | (scalar << SPIFMT_PRESCALE_SHIFT) |
(1 << SPIFMT_PHASE_SHIFT), &ds->regs->fmt0);
- debug("%s speed %u\n", __func__, max_hz);
- if (max_hz > CONFIG_SYS_SPI_CLK / 2)
return -EINVAL;
- /*
* Including a minor delay. No science here. Should be good even with
* no delay
*/
- writel((50 << SPI_C2TDELAY_SHIFT) |
(50 << SPI_T2CDELAY_SHIFT), &ds->regs->delay);
- ds->freq = max_hz;
- /* default chip select register */
- writel(SPIDEF_CSDEF0_MASK, &ds->regs->def);
- return 0;
+}
- /* no interrupts */
- writel(0, &ds->regs->int0);
- writel(0, &ds->regs->lvl);
+static int davinci_spi_set_mode(struct udevice *bus, uint mode) +{
- struct davinci_spi_slave *ds = dev_get_priv(bus);
- /* enable SPI */
- writel((readl(&ds->regs->gcr1) | SPIGCR1_SPIENA_MASK), &ds->regs->gcr1);
debug("%s mode %u\n", __func__, mode);
ds->mode = mode;
return 0;
}
-void spi_release_bus(struct spi_slave *slave) +static int davinci_spi_claim_bus(struct udevice *dev) {
- struct davinci_spi_slave *ds = to_davinci_spi(slave);
- struct dm_spi_slave_platdata *slave_plat =
dev_get_parent_platdata(dev);
- struct udevice *bus = dev->parent;
- struct davinci_spi_slave *ds = dev_get_priv(bus);
- if (slave_plat->cs >= ds->num_cs) {
printf("Invalid SPI chipselect\n");
return -EINVAL;
- }
- ds->half_duplex = slave_plat->mode & SPI_PREAMBLE;
- /* Disable the SPI hardware */
- writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0);
- return __davinci_spi_claim_bus(ds, slave_plat->cs);
}
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
const void *dout, void *din, unsigned long flags)
+static int davinci_spi_release_bus(struct udevice *dev) {
- unsigned int len;
- struct davinci_spi_slave *ds = dev_get_priv(dev->parent);
- if (bitlen == 0)
/* Finish any previously submitted transfers */
goto out;
- return __davinci_spi_release_bus(ds);
+}
- /*
* It's not clear how non-8-bit-aligned transfers are supposed to be
* represented as a stream of bytes...this is a limitation of
* the current SPI interface - here we terminate on receiving such a
* transfer request.
*/
- if (bitlen % 8) {
/* Errors always terminate an ongoing transfer */
flags |= SPI_XFER_END;
goto out;
+static int davinci_spi_xfer(struct udevice *dev, unsigned int bitlen,
const void *dout, void *din,
unsigned long flags)
+{
- struct dm_spi_slave_platdata *slave =
dev_get_parent_platdata(dev);
- struct udevice *bus = dev->parent;
- struct davinci_spi_slave *ds = dev_get_priv(bus);
- if (slave->cs >= ds->num_cs) {
printf("Invalid SPI chipselect\n");
}return -EINVAL;
- ds->cur_cs = slave->cs;
- len = bitlen / 8;
- return __davinci_spi_xfer(ds, bitlen, dout, din, flags);
+}
- if (!dout)
return davinci_spi_read(slave, len, din, flags);
- else if (!din)
return davinci_spi_write(slave, len, dout, flags);
-#ifndef CONFIG_SPI_HALF_DUPLEX
- else
return davinci_spi_read_write(slave, len, din, dout, flags);
-#else
- printf("SPI full duplex transaction requested with "
"CONFIG_SPI_HALF_DUPLEX defined.\n");
- flags |= SPI_XFER_END;
-#endif +static int davinci_spi_probe(struct udevice *bus) +{
- /* Nothing to do */
- return 0;
+}
-out:
- if (flags & SPI_XFER_END) {
u8 dummy = 0;
davinci_spi_write(slave, 1, &dummy, flags);
+static int davinci_ofdata_to_platadata(struct udevice *bus) +{
- struct davinci_spi_slave *ds = dev_get_priv(bus);
- const void *blob = gd->fdt_blob;
- int node = bus->of_offset;
- ds->regs = dev_map_physmem(bus, sizeof(struct davinci_spi_regs));
- if (!ds->regs) {
printf("%s: could not map device address\n", __func__);
}return -EINVAL;
- ds->num_cs = fdtdec_get_int(blob, node, "num-cs", 4);
- return 0;
}
+static const struct dm_spi_ops davinci_spi_ops = {
- .claim_bus = davinci_spi_claim_bus,
- .release_bus = davinci_spi_release_bus,
- .xfer = davinci_spi_xfer,
- .set_speed = davinci_spi_set_speed,
- .set_mode = davinci_spi_set_mode,
+};
+static const struct udevice_id davinci_spi_ids[] = {
- { .compatible = "ti,keystone-spi" },
- { .compatible = "ti,dm6441-spi" },
- { }
+};
+U_BOOT_DRIVER(davinci_spi) = {
- .name = "davinci_spi",
- .id = UCLASS_SPI,
- .of_match = davinci_spi_ids,
- .ops = &davinci_spi_ops,
- .ofdata_to_platdata = davinci_ofdata_to_platadata,
- .priv_auto_alloc_size = sizeof(struct davinci_spi_slave),
- .probe = davinci_spi_probe,
+}; +#endif

Hi Vignesh,
On 23 May 2016 at 22:24, Vignesh R vigneshr@ti.com wrote:
Convert davinci_spi driver so that it complies with SPI DM framework.
Signed-off-by: Vignesh R vigneshr@ti.com
v6: Fix retval on dev_map_physmem() failure.
drivers/spi/davinci_spi.c | 329 +++++++++++++++++++++++++++++++++------------- 1 file changed, 240 insertions(+), 89 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
Who is picking this one up? I can pull it into dm if you like, but I assumed it would be a SPI patch.
Regards, Simon

Since Keystone2 devices do not have support DM in SPL, do not define DM_SPI and DM_SPI_FLASH for SPL build.
Signed-off-by: Vignesh R vigneshr@ti.com Reviewed-by: Tom Rini trini@konsulko.com --- include/configs/ti_armv7_keystone2.h | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/include/configs/ti_armv7_keystone2.h b/include/configs/ti_armv7_keystone2.h index 2c9028c73558..985dd0625ab0 100644 --- a/include/configs/ti_armv7_keystone2.h +++ b/include/configs/ti_armv7_keystone2.h @@ -89,6 +89,10 @@ #define CONFIG_SYS_SPI2 #define CONFIG_SYS_SPI2_BASE KS2_SPI2_BASE #define CONFIG_SYS_SPI2_NUM_CS 4 +#ifdef CONFIG_SPL_BUILD +#undef CONFIG_DM_SPI +#undef CONFIG_DM_SPI_FLASH +#endif
/* Network Configuration */ #define CONFIG_PHYLIB

Add aliases for SPI nodes in order for it to be probed by the DM framework.
Signed-off-by: Vignesh R vigneshr@ti.com Reviewed-by: Tom Rini trini@konsulko.com --- arch/arm/dts/keystone.dtsi | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/arch/arm/dts/keystone.dtsi b/arch/arm/dts/keystone.dtsi index f39b969f8d43..be97f3f21f92 100644 --- a/arch/arm/dts/keystone.dtsi +++ b/arch/arm/dts/keystone.dtsi @@ -19,6 +19,9 @@
aliases { serial0 = &uart0; + spi0 = &spi0; + spi1 = &spi1; + spi2 = &spi2; };
chosen {

Now that davinci_spi driver has been converted to DM framework, enable the same in DT. Also add "spi-flash" as compatible property to n25q128a11 node as it is required for flash device to be probed in U-Boot.
Signed-off-by: Vignesh R vigneshr@ti.com Reviewed-by: Tom Rini trini@konsulko.com --- arch/arm/dts/k2hk-evm.dts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/arm/dts/k2hk-evm.dts b/arch/arm/dts/k2hk-evm.dts index 660ebf58d547..c5cad2c9da80 100644 --- a/arch/arm/dts/k2hk-evm.dts +++ b/arch/arm/dts/k2hk-evm.dts @@ -147,10 +147,11 @@ };
&spi0 { + status = "okay"; nor_flash: n25q128a11@0 { #address-cells = <1>; #size-cells = <1>; - compatible = "Micron,n25q128a11"; + compatible = "Micron,n25q128a11", "spi-flash"; spi-max-frequency = <54000000>; m25p,fast-read; reg = <0>;

Enable SPI and SPI Flash driver model as K2HK SPI controller driver supports driver model.
Signed-off-by: Vignesh R vigneshr@ti.com Reviewed-by: Tom Rini trini@konsulko.com --- configs/k2hk_evm_defconfig | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/configs/k2hk_evm_defconfig b/configs/k2hk_evm_defconfig index 3975e804e534..21b8e1d2d383 100644 --- a/configs/k2hk_evm_defconfig +++ b/configs/k2hk_evm_defconfig @@ -28,6 +28,8 @@ CONFIG_CMD_FS_GENERIC=y CONFIG_OF_CONTROL=y CONFIG_DM=y CONFIG_TI_AEMIF=y +CONFIG_DM_SPI=y +CONFIG_DM_SPI_FLASH=y CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_STMICRO=y CONFIG_DM_ETH=y

Now that davinci_spi driver has been converted to DM framework, enable the same in DT. Also add "spi-flash" as compatible property to n25q128a11 node as it is required for flash device to be probed in U-Boot.
Signed-off-by: Vignesh R vigneshr@ti.com Reviewed-by: Tom Rini trini@konsulko.com --- arch/arm/dts/k2e-evm.dts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/arm/dts/k2e-evm.dts b/arch/arm/dts/k2e-evm.dts index 50c83c21d911..e2c3fb49102a 100644 --- a/arch/arm/dts/k2e-evm.dts +++ b/arch/arm/dts/k2e-evm.dts @@ -119,10 +119,11 @@ };
&spi0 { + status = "okay"; nor_flash: n25q128a11@0 { #address-cells = <1>; #size-cells = <1>; - compatible = "Micron,n25q128a11"; + compatible = "Micron,n25q128a11", "spi-flash"; spi-max-frequency = <54000000>; m25p,fast-read; reg = <0>;

Enable SPI and SPI Flash driver model as K2E SPI controller driver supports driver model.
Signed-off-by: Vignesh R vigneshr@ti.com Reviewed-by: Tom Rini trini@konsulko.com --- configs/k2e_evm_defconfig | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/configs/k2e_evm_defconfig b/configs/k2e_evm_defconfig index 044a9bf5b6e3..1e5003e8d23c 100644 --- a/configs/k2e_evm_defconfig +++ b/configs/k2e_evm_defconfig @@ -28,6 +28,8 @@ CONFIG_CMD_FS_GENERIC=y CONFIG_OF_CONTROL=y CONFIG_DM=y CONFIG_TI_AEMIF=y +CONFIG_DM_SPI=y +CONFIG_DM_SPI_FLASH=y CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_STMICRO=y CONFIG_DM_ETH=y

Now that davinci_spi driver has been converted to DM framework, enable the same in DT. Also add "spi-flash" as compatible property to n25q128a11 node as it is required for flash device to be probed in U-Boot.
Signed-off-by: Vignesh R vigneshr@ti.com Reviewed-by: Tom Rini trini@konsulko.com --- arch/arm/dts/k2l-evm.dts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/arm/dts/k2l-evm.dts b/arch/arm/dts/k2l-evm.dts index 9a69a6b55374..da0661ba3e8a 100644 --- a/arch/arm/dts/k2l-evm.dts +++ b/arch/arm/dts/k2l-evm.dts @@ -96,10 +96,11 @@ };
&spi0 { + status ="okay"; nor_flash: n25q128a11@0 { #address-cells = <1>; #size-cells = <1>; - compatible = "Micron,n25q128a11"; + compatible = "Micron,n25q128a11", "spi-flash"; spi-max-frequency = <54000000>; m25p,fast-read; reg = <0>;

Enable SPI and SPI Flash driver model as K2L SPI controller driver supports driver model.
Signed-off-by: Vignesh R vigneshr@ti.com Reviewed-by: Tom Rini trini@konsulko.com --- configs/k2l_evm_defconfig | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/configs/k2l_evm_defconfig b/configs/k2l_evm_defconfig index 844dd57163f5..1ba7d23e9c78 100644 --- a/configs/k2l_evm_defconfig +++ b/configs/k2l_evm_defconfig @@ -28,6 +28,8 @@ CONFIG_CMD_FS_GENERIC=y CONFIG_OF_CONTROL=y CONFIG_DM=y CONFIG_TI_AEMIF=y +CONFIG_DM_SPI=y +CONFIG_DM_SPI_FLASH=y CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_STMICRO=y CONFIG_DM_ETH=y

K2G SoC has 4 SPI instances that are compatible with davinci_spi controller(present on previous generation of Keystone2 devices). Add DT nodes for the same. K2G EVM has a N25Q128A13 SPI NOR flash connected on SPI-1. Add DT bindings for the same.
Signed-off-by: Vignesh R vigneshr@ti.com Reviewed-by: Tom Rini trini@konsulko.com --- arch/arm/dts/k2g-evm.dts | 24 ++++++++++++++++++++++++ arch/arm/dts/k2g.dtsi | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+)
diff --git a/arch/arm/dts/k2g-evm.dts b/arch/arm/dts/k2g-evm.dts index 0ca36ef39ad3..38ca7ae1b6b9 100644 --- a/arch/arm/dts/k2g-evm.dts +++ b/arch/arm/dts/k2g-evm.dts @@ -31,3 +31,27 @@ &gbe0 { phy-handle = <ðphy0>; }; + +&spi1 { + status = "okay"; + + spi_nor: flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spi-flash"; + spi-max-frequency = <50000000>; + m25p,fast-read; + reg = <0>; + + partition@0 { + label = "u-boot-spl"; + reg = <0x0 0x80000>; + read-only; + }; + + partition@1 { + label = "misc"; + reg = <0x80000 0xf80000>; + }; + }; +}; diff --git a/arch/arm/dts/k2g.dtsi b/arch/arm/dts/k2g.dtsi index a3ed444d3c31..88b1a8e998ac 100644 --- a/arch/arm/dts/k2g.dtsi +++ b/arch/arm/dts/k2g.dtsi @@ -19,6 +19,10 @@
aliases { serial0 = &uart0; + spi0 = &spi0; + spi1 = &spi1; + spi2 = &spi2; + spi3 = &spi3; };
memory { @@ -88,5 +92,48 @@ ti,lpsc_module = <1>; };
+ spi0: spi@21805400 { + compatible = "ti,keystone-spi", "ti,dm6441-spi"; + reg = <0x21805400 0x200>; + num-cs = <4>; + ti,davinci-spi-intr-line = <0>; + interrupts = <GIC_SPI 64 IRQ_TYPE_EDGE_RISING>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi1: spi@21805800 { + compatible = "ti,keystone-spi", "ti,dm6441-spi"; + reg = <0x21805800 0x200>; + num-cs = <4>; + ti,davinci-spi-intr-line = <0>; + interrupts = <GIC_SPI 66 IRQ_TYPE_EDGE_RISING>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi2: spi@21805c00 { + compatible = "ti,keystone-spi", "ti,dm6441-spi"; + reg = <0x21805C00 0x200>; + num-cs = <4>; + ti,davinci-spi-intr-line = <0>; + interrupts = <GIC_SPI 68 IRQ_TYPE_EDGE_RISING>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi3: spi@21806000 { + compatible = "ti,keystone-spi", "ti,dm6441-spi"; + reg = <0x21806000 0x200>; + num-cs = <4>; + ti,davinci-spi-intr-line = <0>; + interrupts = <GIC_SPI 70 IRQ_TYPE_EDGE_RISING>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; }; };

Enable SPI and SPI Flash driver model as K2G SPI controller driver supports driver model.
Signed-off-by: Vignesh R vigneshr@ti.com Reviewed-by: Tom Rini trini@konsulko.com --- configs/k2g_evm_defconfig | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/configs/k2g_evm_defconfig b/configs/k2g_evm_defconfig index d0b45ce3f8a5..33722ce9c421 100644 --- a/configs/k2g_evm_defconfig +++ b/configs/k2g_evm_defconfig @@ -27,6 +27,8 @@ CONFIG_CMD_FAT=y CONFIG_CMD_FS_GENERIC=y CONFIG_OF_CONTROL=y CONFIG_DM=y +CONFIG_DM_SPI=y +CONFIG_DM_SPI_FLASH=y CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_STMICRO=y CONFIG_DM_ETH=y

On 4 May 2016 at 16:49, Vignesh R vigneshr@ti.com wrote:
This series converts davinci_spi driver to adapt to driver model framework. And enables the driver on k2l, k2e, k2hk evms. Also, added support for davinci_spi on k2g evm.
Tested on k2l, k2e, k2hk and k2g evms.
Rebased on top of v2016.05-rc3
Vignesh R (12): dm: core: implement dev_map_phsymem() spi: davinci_spi: Convert to driver to adapt to DM keystone2: spi: do not define DM_SPI and DM_SPI_FLASH for SPL build ARM: dts: keystone2: add SPI aliases for davinci SPI nodes ARM: dts: k2hk: Enable Davinci SPI controller defconfig: k2hk_evm_defconfig: enable SPI driver model ARM: dts: k2e: Enable Davinci SPI controller defconfig: k2e_evm_defconfig: enable SPI driver model ARM: dts: k2l: Enable Davinci SPI controller defconfig: k2l_evm_defconfig: enable SPI driver model ARM: dts: k2g: add support for Davinci SPI controller defconfig: k2g_evm_defconfig: enable SPI driver model
arch/arm/dts/k2e-evm.dts | 3 +- arch/arm/dts/k2g-evm.dts | 24 +++ arch/arm/dts/k2g.dtsi | 47 +++++ arch/arm/dts/k2hk-evm.dts | 3 +- arch/arm/dts/k2l-evm.dts | 3 +- arch/arm/dts/keystone.dtsi | 3 + configs/k2e_evm_defconfig | 2 + configs/k2g_evm_defconfig | 2 + configs/k2hk_evm_defconfig | 2 + configs/k2l_evm_defconfig | 2 + drivers/core/device.c | 6 + drivers/spi/davinci_spi.c | 327 +++++++++++++++++++++++++--
Reviewed-by: Jagan Teki jteki@openedev.com

On 05/04/2016 04:49 PM, Vignesh R wrote:
This series converts davinci_spi driver to adapt to driver model framework. And enables the driver on k2l, k2e, k2hk evms. Also, added support for davinci_spi on k2g evm.
Tested on k2l, k2e, k2hk and k2g evms.
Rebased on top of v2016.05-rc3
Gentle ping on the series...
Vignesh R (12): dm: core: implement dev_map_phsymem() spi: davinci_spi: Convert to driver to adapt to DM keystone2: spi: do not define DM_SPI and DM_SPI_FLASH for SPL build ARM: dts: keystone2: add SPI aliases for davinci SPI nodes ARM: dts: k2hk: Enable Davinci SPI controller defconfig: k2hk_evm_defconfig: enable SPI driver model ARM: dts: k2e: Enable Davinci SPI controller defconfig: k2e_evm_defconfig: enable SPI driver model ARM: dts: k2l: Enable Davinci SPI controller defconfig: k2l_evm_defconfig: enable SPI driver model ARM: dts: k2g: add support for Davinci SPI controller defconfig: k2g_evm_defconfig: enable SPI driver model
arch/arm/dts/k2e-evm.dts | 3 +- arch/arm/dts/k2g-evm.dts | 24 +++ arch/arm/dts/k2g.dtsi | 47 +++++ arch/arm/dts/k2hk-evm.dts | 3 +- arch/arm/dts/k2l-evm.dts | 3 +- arch/arm/dts/keystone.dtsi | 3 + configs/k2e_evm_defconfig | 2 + configs/k2g_evm_defconfig | 2 + configs/k2hk_evm_defconfig | 2 + configs/k2l_evm_defconfig | 2 + drivers/core/device.c | 6 + drivers/spi/davinci_spi.c | 327 +++++++++++++++++++++++++---------- include/configs/ti_armv7_keystone2.h | 4 + include/dm/device.h | 9 + 14 files changed, 344 insertions(+), 93 deletions(-)
participants (5)
-
Jagan Teki
-
R, Vignesh
-
Simon Glass
-
Tom Rini
-
Vignesh R