[U-Boot] [PATCH v6] spi: add TI QSPI driver

From: Matt Porter matt.porter@linaro.org
Adds a SPI master driver for the TI QSPI peripheral. - Added quad read support. - Added memory mapped support.
Signed-off-by: Matt Porter matt.porter@linaro.org Signed-off-by: Sourav Poddar sourav.poddar@ti.com Signed-off-by: Jagannadha Sutradharudu Teki jaganna@xilinx.com --- Changes for v6: - Added ti related comments - Created ti spec func for ti code - Fixed few checkpatch.pl errors - Rearranged the code. v4->v5: - use tabs wherever required. - remove stray character in license line - remove "get_spi_bus" api - move device control stuff to spi_claim_bus - Put prints according to the reference driver from jagan - Move macros below header.files.
drivers/spi/Makefile | 1 + drivers/spi/ti_qspi.c | 313 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 314 insertions(+) create mode 100644 drivers/spi/ti_qspi.c
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 91d24ce..e5941b0 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -38,6 +38,7 @@ COBJS-$(CONFIG_FDT_SPI) += fdt_spi.o COBJS-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o COBJS-$(CONFIG_TEGRA20_SLINK) += tegra20_slink.o COBJS-$(CONFIG_TEGRA114_SPI) += tegra114_spi.o +COBJS-$(CONFIG_TI_QSPI) += ti_qspi.o COBJS-$(CONFIG_XILINX_SPI) += xilinx_spi.o COBJS-$(CONFIG_ZYNQ_SPI) += zynq_spi.o
diff --git a/drivers/spi/ti_qspi.c b/drivers/spi/ti_qspi.c new file mode 100644 index 0000000..91a37aa --- /dev/null +++ b/drivers/spi/ti_qspi.c @@ -0,0 +1,313 @@ +/* + * TI QSPI driver + * + * Copyright (C) 2013, Texas Instruments, Incorporated + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/omap.h> +#include <malloc.h> +#include <spi.h> + +/* ti qpsi register bit masks */ +#define QSPI_TIMEOUT 2000000 +#define QSPI_FCLK 192000000 +/* clock control */ +#define QSPI_CLK_EN (1 << 31) +#define QSPI_CLK_DIV_MAX 0xffff +/* command */ +#define QSPI_EN_CS(n) (n << 28) +#define QSPI_WLEN(n) ((n-1) << 19) +#define QSPI_3_PIN (1 << 18) +#define QSPI_RD_SNGL (1 << 16) +#define QSPI_WR_SNGL (2 << 16) +#define QSPI_INVAL (4 << 16) +#define QSPI_RD_QUAD (7 << 16) +/* device control */ +#define QSPI_DD(m, n) (m << (3 + n*8)) +#define QSPI_CKPHA(n) (1 << (2 + n*8)) +#define QSPI_CSPOL(n) (1 << (1 + n*8)) +#define QSPI_CKPOL(n) (1 << (n*8)) +/* status */ +#define QSPI_WC (1 << 1) +#define QSPI_BUSY (1 << 0) +#define QSPI_WC_BUSY (QSPI_WC | QSPI_BUSY) +#define QSPI_XFER_DONE QSPI_WC +#define MM_SWITCH 0x01 +#define MEM_CS 0x100 +#define MEM_CS_UNSELECT 0xfffff0ff +#define MMAP_START_ADDR 0x5c000000 +#define CORE_CTRL_IO 0x4a002558 + +#define QSPI_CMD_READ (0x3 << 0) +#define QSPI_CMD_READ_QUAD (0x6b << 0) +#define QSPI_CMD_READ_FAST (0x0b << 0) +#define QSPI_SETUP0_NUM_A_BYTES (0x2 << 8) +#define QSPI_SETUP0_NUM_D_BYTES_NO_BITS (0x0 << 10) +#define QSPI_SETUP0_NUM_D_BYTES_8_BITS (0x1 << 10) +#define QSPI_SETUP0_READ_NORMAL (0x0 << 12) +#define QSPI_SETUP0_READ_QUAD (0x3 << 12) +#define QSPI_CMD_WRITE (0x2 << 16) +#define QSPI_NUM_DUMMY_BITS (0x0 << 24) + +/* ti qspi register set */ +struct ti_qspi_regs { + u32 pid; + u32 pad0[3]; + u32 sysconfig; + u32 pad1[3]; + u32 intr_status_raw_set; + u32 intr_status_enabled_clear; + u32 intr_enable_set; + u32 intr_enable_clear; + u32 intc_eoi; + u32 pad2[3]; + u32 spi_clock_cntrl; + u32 spi_dc; + u32 spi_cmd; + u32 spi_status; + u32 spi_data; + u32 spi_setup0; + u32 spi_setup1; + u32 spi_setup2; + u32 spi_setup3; + u32 spi_switch; + u32 spi_data1; + u32 spi_data2; + u32 spi_data3; +}; + +/* ti qspi slave */ +struct ti_qspi_slave { + struct spi_slave slave; + struct ti_qspi_regs *base; + unsigned int mode; + u32 cmd; + u32 dc; +}; + +static inline struct ti_qspi_slave *to_ti_qspi_slave(struct spi_slave *slave) +{ + return container_of(slave, struct ti_qspi_slave, slave); +} + +#ifdef CONFIG_TI_SPI_MMAP +static void ti_spi_setup_spi_register(struct ti_qspi_slave *qslave) +{ + struct spi_slave *slave = &qslave->slave; + u32 memval = 0; + + slave->memory_map = (void *)MMAP_START_ADDR; + + memval |= QSPI_CMD_READ | QSPI_SETUP0_NUM_A_BYTES | + QSPI_SETUP0_NUM_D_BYTES_NO_BITS | + QSPI_SETUP0_READ_NORMAL | QSPI_CMD_WRITE | + QSPI_NUM_DUMMY_BITS; + + writel(memval, &qslave->base->spi_setup0); +} +#endif + +static void ti_spi_set_speed(struct spi_slave *slave, uint hz) +{ + struct ti_qspi_slave *qslave = to_ti_qspi_slave(slave); + uint clk_div; + + debug("ti_spi_set_speed: hz: %d, clock divider %d\n", hz, clk_div); + + if (!hz) + clk_div = 0; + else + clk_div = (QSPI_FCLK / hz) - 1; + + /* disable SCLK */ + writel(readl(&qslave->base->spi_clock_cntrl) & ~QSPI_CLK_EN, + &qslave->base->spi_clock_cntrl); + + /* assign clk_div values */ + if (clk_div < 0) + clk_div = 0; + else if (clk_div > QSPI_CLK_DIV_MAX) + clk_div = QSPI_CLK_DIV_MAX; + + /* enable SCLK */ + writel(QSPI_CLK_EN | clk_div, &qslave->base->spi_clock_cntrl); +} + +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + return 1; +} + +void spi_cs_activate(struct spi_slave *slave) +{ + /* CS handled in xfer */ + return; +} + +void spi_cs_deactivate(struct spi_slave *slave) +{ + struct ti_qspi_slave *qslave = to_ti_qspi_slave(slave); + + debug("spi_cs_deactivate: 0x%08x\n", (u32)slave); + + writel(qslave->cmd | QSPI_INVAL, &qslave->base->spi_cmd); +} + +void spi_init(void) +{ + /* nothing to do */ +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct ti_qspi_slave *qslave; + + qslave = spi_alloc_slave(struct ti_qspi_slave, bus, cs); + if (!qslave) { + printf("SPI_error: Fail to allocate ti_qspi_slave\n"); + return NULL; + } + + qslave->base = (struct ti_qspi_regs *)QSPI_BASE; + qslave->mode = mode; + + ti_spi_set_speed(&qslave->slave, max_hz); + +#ifdef CONFIG_TI_SPI_MMAP + ti_spi_setup_spi_register(qslave); +#endif + + return &qslave->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + struct ti_qspi_slave *qslave = to_ti_qspi_slave(slave); + free(qslave); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + struct ti_qspi_slave *qslave = to_ti_qspi_slave(slave); + + debug("spi_claim_bus: bus:%i cs:%i\n", slave->bus, slave->cs); + + qslave->dc = 0; + if (qslave->mode & SPI_CPHA) + qslave->dc |= QSPI_CKPHA(slave->cs); + if (qslave->mode & SPI_CPOL) + qslave->dc |= QSPI_CKPOL(slave->cs); + if (qslave->mode & SPI_CS_HIGH) + qslave->dc |= QSPI_CSPOL(slave->cs); + + writel(qslave->dc, &qslave->base->spi_dc); + writel(0, &qslave->base->spi_cmd); + writel(0, &qslave->base->spi_data); + + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + struct ti_qspi_slave *qslave = to_ti_qspi_slave(slave); + + debug("spi_release_bus: bus:%i cs:%i\n", slave->bus, slave->cs); + + writel(0, &qslave->base->spi_dc); + writel(0, &qslave->base->spi_cmd); + writel(0, &qslave->base->spi_data); +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, + void *din, unsigned long flags) +{ + struct ti_qspi_slave *qslave = to_ti_qspi_slave(slave); + uint words = bitlen >> 3; /* fixed 8-bit word length */ + const uchar *txp = dout; + uchar *rxp = din; + uint status; + int timeout, val; + + debug("spi_xfer: bus:%i cs:%i bitlen:%i words:%i flags:%lx\n", + slave->bus, slave->cs, bitlen, words, flags); + + /* Setup mmap flags */ + if (flags & SPI_XFER_MMAP) { + writel(MM_SWITCH, &qslave->base->spi_switch); + val = readl(CORE_CTRL_IO); + val |= MEM_CS; + writel(val, CORE_CTRL_IO); + return 0; + } else if (flags & SPI_XFER_MMAP_END) { + writel(~MM_SWITCH, &qslave->base->spi_switch); + val = readl(CORE_CTRL_IO); + val &= MEM_CS_UNSELECT; + writel(val, CORE_CTRL_IO); + return 0; + } + + if (bitlen == 0) + goto out; + + if (bitlen % 8) { + debug("spi_xfer: Non byte aligned SPI transfer\n"); + return -1; + } + + /* Setup command reg */ + qslave->cmd = 0; + qslave->cmd |= QSPI_WLEN(8); + qslave->cmd |= QSPI_EN_CS(slave->cs); + if (flags & SPI_3WIRE) + qslave->cmd |= QSPI_3_PIN; + qslave->cmd |= 0xfff; + + while (words--) { + if (txp) { + debug("tx cmd %08x dc %08x data %02x\n", + qslave->cmd | QSPI_WR_SNGL, qslave->dc, *txp); + writel(*txp++, &qslave->base->spi_data); + writel(qslave->cmd | QSPI_WR_SNGL, + &qslave->base->spi_cmd); + status = readl(&qslave->base->spi_status); + timeout = QSPI_TIMEOUT; + while ((status & QSPI_WC_BUSY) != QSPI_XFER_DONE) { + if (--timeout < 0) { + printf("spi_xfer: TX timeout!\n"); + return -1; + } + status = readl(&qslave->base->spi_status); + } + debug("tx done, status %08x\n", status); + } + if (rxp) { + qslave->cmd |= QSPI_RD_SNGL; + debug("rx cmd %08x dc %08x\n", + qslave->cmd, qslave->dc); + writel(qslave->cmd, &qslave->base->spi_cmd); + status = readl(&qslave->base->spi_status); + timeout = QSPI_TIMEOUT; + while ((status & QSPI_WC_BUSY) != QSPI_XFER_DONE) { + if (--timeout < 0) { + printf("spi_xfer: RX timeout!\n"); + return -1; + } + status = readl(&qslave->base->spi_status); + } + *rxp++ = readl(&qslave->base->spi_data); + debug("rx done, status %08x, read %02x\n", + status, *(rxp-1)); + } + } + + /* Terminate frame */ + if (flags & SPI_XFER_END) + spi_cs_deactivate(); + + return 0; +}

On Monday 07 October 2013 12:33 PM, Jagannadha Sutradharudu Teki wrote:
From: Matt Portermatt.porter@linaro.org
Adds a SPI master driver for the TI QSPI peripheral.
- Added quad read support.
- Added memory mapped support.
Signed-off-by: Matt Portermatt.porter@linaro.org Signed-off-by: Sourav Poddarsourav.poddar@ti.com Signed-off-by: Jagannadha Sutradharudu Tekijaganna@xilinx.com
Changes for v6:
- Added ti related comments
- Created ti spec func for ti code
- Fixed few checkpatch.pl errors
- Rearranged the code.
v4->v5:
- use tabs wherever required.
- remove stray character in license line
- remove "get_spi_bus" api
- move device control stuff to spi_claim_bus
- Put prints according to the reference driver from jagan
- Move macros below header.files.
drivers/spi/Makefile | 1 + drivers/spi/ti_qspi.c | 313 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 314 insertions(+) create mode 100644 drivers/spi/ti_qspi.c
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 91d24ce..e5941b0 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -38,6 +38,7 @@ COBJS-$(CONFIG_FDT_SPI) += fdt_spi.o COBJS-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o COBJS-$(CONFIG_TEGRA20_SLINK) += tegra20_slink.o COBJS-$(CONFIG_TEGRA114_SPI) += tegra114_spi.o +COBJS-$(CONFIG_TI_QSPI) += ti_qspi.o COBJS-$(CONFIG_XILINX_SPI) += xilinx_spi.o COBJS-$(CONFIG_ZYNQ_SPI) += zynq_spi.o
diff --git a/drivers/spi/ti_qspi.c b/drivers/spi/ti_qspi.c new file mode 100644 index 0000000..91a37aa --- /dev/null +++ b/drivers/spi/ti_qspi.c @@ -0,0 +1,313 @@ +/*
- TI QSPI driver
- Copyright (C) 2013, Texas Instruments, Incorporated
- SPDX-License-Identifier: GPL-2.0+
- */
+#include<common.h> +#include<asm/io.h> +#include<asm/arch/omap.h> +#include<malloc.h> +#include<spi.h>
+/* ti qpsi register bit masks */ +#define QSPI_TIMEOUT 2000000 +#define QSPI_FCLK 192000000 +/* clock control */ +#define QSPI_CLK_EN (1<< 31) +#define QSPI_CLK_DIV_MAX 0xffff +/* command */ +#define QSPI_EN_CS(n) (n<< 28) +#define QSPI_WLEN(n) ((n-1)<< 19) +#define QSPI_3_PIN (1<< 18) +#define QSPI_RD_SNGL (1<< 16) +#define QSPI_WR_SNGL (2<< 16) +#define QSPI_INVAL (4<< 16) +#define QSPI_RD_QUAD (7<< 16) +/* device control */ +#define QSPI_DD(m, n) (m<< (3 + n*8)) +#define QSPI_CKPHA(n) (1<< (2 + n*8)) +#define QSPI_CSPOL(n) (1<< (1 + n*8)) +#define QSPI_CKPOL(n) (1<< (n*8)) +/* status */ +#define QSPI_WC (1<< 1) +#define QSPI_BUSY (1<< 0) +#define QSPI_WC_BUSY (QSPI_WC | QSPI_BUSY) +#define QSPI_XFER_DONE QSPI_WC +#define MM_SWITCH 0x01 +#define MEM_CS 0x100 +#define MEM_CS_UNSELECT 0xfffff0ff +#define MMAP_START_ADDR 0x5c000000 +#define CORE_CTRL_IO 0x4a002558
+#define QSPI_CMD_READ (0x3<< 0) +#define QSPI_CMD_READ_QUAD (0x6b<< 0) +#define QSPI_CMD_READ_FAST (0x0b<< 0) +#define QSPI_SETUP0_NUM_A_BYTES (0x2<< 8) +#define QSPI_SETUP0_NUM_D_BYTES_NO_BITS (0x0<< 10) +#define QSPI_SETUP0_NUM_D_BYTES_8_BITS (0x1<< 10) +#define QSPI_SETUP0_READ_NORMAL (0x0<< 12) +#define QSPI_SETUP0_READ_QUAD (0x3<< 12) +#define QSPI_CMD_WRITE (0x2<< 16) +#define QSPI_NUM_DUMMY_BITS (0x0<< 24)
+/* ti qspi register set */ +struct ti_qspi_regs {
- u32 pid;
- u32 pad0[3];
- u32 sysconfig;
- u32 pad1[3];
- u32 intr_status_raw_set;
- u32 intr_status_enabled_clear;
- u32 intr_enable_set;
- u32 intr_enable_clear;
- u32 intc_eoi;
- u32 pad2[3];
- u32 spi_clock_cntrl;
- u32 spi_dc;
- u32 spi_cmd;
- u32 spi_status;
- u32 spi_data;
- u32 spi_setup0;
- u32 spi_setup1;
- u32 spi_setup2;
- u32 spi_setup3;
- u32 spi_switch;
- u32 spi_data1;
- u32 spi_data2;
- u32 spi_data3;
+};
+/* ti qspi slave */ +struct ti_qspi_slave {
- struct spi_slave slave;
- struct ti_qspi_regs *base;
- unsigned int mode;
- u32 cmd;
- u32 dc;
+};
+static inline struct ti_qspi_slave *to_ti_qspi_slave(struct spi_slave *slave) +{
- return container_of(slave, struct ti_qspi_slave, slave);
+}
+#ifdef CONFIG_TI_SPI_MMAP +static void ti_spi_setup_spi_register(struct ti_qspi_slave *qslave) +{
- struct spi_slave *slave =&qslave->slave;
- u32 memval = 0;
- slave->memory_map = (void *)MMAP_START_ADDR;
- memval |= QSPI_CMD_READ | QSPI_SETUP0_NUM_A_BYTES |
QSPI_SETUP0_NUM_D_BYTES_NO_BITS |
QSPI_SETUP0_READ_NORMAL | QSPI_CMD_WRITE |
QSPI_NUM_DUMMY_BITS;
- writel(memval,&qslave->base->spi_setup0);
+} +#endif
why we need this ifdef? we are calling this only if CONFIG_TI_SPI_MMAP is set from set up slave. Apart from this, this is fine.
+static void ti_spi_set_speed(struct spi_slave *slave, uint hz) +{
- struct ti_qspi_slave *qslave = to_ti_qspi_slave(slave);
- uint clk_div;
- debug("ti_spi_set_speed: hz: %d, clock divider %d\n", hz, clk_div);
- if (!hz)
clk_div = 0;
- else
clk_div = (QSPI_FCLK / hz) - 1;
- /* disable SCLK */
- writel(readl(&qslave->base->spi_clock_cntrl)& ~QSPI_CLK_EN,
- &qslave->base->spi_clock_cntrl);
- /* assign clk_div values */
- if (clk_div< 0)
clk_div = 0;
- else if (clk_div> QSPI_CLK_DIV_MAX)
clk_div = QSPI_CLK_DIV_MAX;
- /* enable SCLK */
- writel(QSPI_CLK_EN | clk_div,&qslave->base->spi_clock_cntrl);
+}
+int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{
- return 1;
+}
+void spi_cs_activate(struct spi_slave *slave) +{
- /* CS handled in xfer */
- return;
+}
+void spi_cs_deactivate(struct spi_slave *slave) +{
- struct ti_qspi_slave *qslave = to_ti_qspi_slave(slave);
- debug("spi_cs_deactivate: 0x%08x\n", (u32)slave);
- writel(qslave->cmd | QSPI_INVAL,&qslave->base->spi_cmd);
+}
+void spi_init(void) +{
- /* nothing to do */
+}
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int mode)
+{
- struct ti_qspi_slave *qslave;
- qslave = spi_alloc_slave(struct ti_qspi_slave, bus, cs);
- if (!qslave) {
printf("SPI_error: Fail to allocate ti_qspi_slave\n");
return NULL;
- }
- qslave->base = (struct ti_qspi_regs *)QSPI_BASE;
- qslave->mode = mode;
- ti_spi_set_speed(&qslave->slave, max_hz);
+#ifdef CONFIG_TI_SPI_MMAP
- ti_spi_setup_spi_register(qslave);
+#endif
- return&qslave->slave;
+}
+void spi_free_slave(struct spi_slave *slave) +{
- struct ti_qspi_slave *qslave = to_ti_qspi_slave(slave);
- free(qslave);
+}
+int spi_claim_bus(struct spi_slave *slave) +{
- struct ti_qspi_slave *qslave = to_ti_qspi_slave(slave);
- debug("spi_claim_bus: bus:%i cs:%i\n", slave->bus, slave->cs);
- qslave->dc = 0;
- if (qslave->mode& SPI_CPHA)
qslave->dc |= QSPI_CKPHA(slave->cs);
- if (qslave->mode& SPI_CPOL)
qslave->dc |= QSPI_CKPOL(slave->cs);
- if (qslave->mode& SPI_CS_HIGH)
qslave->dc |= QSPI_CSPOL(slave->cs);
- writel(qslave->dc,&qslave->base->spi_dc);
- writel(0,&qslave->base->spi_cmd);
- writel(0,&qslave->base->spi_data);
- return 0;
+}
+void spi_release_bus(struct spi_slave *slave) +{
- struct ti_qspi_slave *qslave = to_ti_qspi_slave(slave);
- debug("spi_release_bus: bus:%i cs:%i\n", slave->bus, slave->cs);
- writel(0,&qslave->base->spi_dc);
- writel(0,&qslave->base->spi_cmd);
- writel(0,&qslave->base->spi_data);
+}
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
void *din, unsigned long flags)
+{
- struct ti_qspi_slave *qslave = to_ti_qspi_slave(slave);
- uint words = bitlen>> 3; /* fixed 8-bit word length */
- const uchar *txp = dout;
- uchar *rxp = din;
- uint status;
- int timeout, val;
- debug("spi_xfer: bus:%i cs:%i bitlen:%i words:%i flags:%lx\n",
slave->bus, slave->cs, bitlen, words, flags);
- /* Setup mmap flags */
- if (flags& SPI_XFER_MMAP) {
writel(MM_SWITCH,&qslave->base->spi_switch);
val = readl(CORE_CTRL_IO);
val |= MEM_CS;
writel(val, CORE_CTRL_IO);
return 0;
- } else if (flags& SPI_XFER_MMAP_END) {
writel(~MM_SWITCH,&qslave->base->spi_switch);
val = readl(CORE_CTRL_IO);
val&= MEM_CS_UNSELECT;
writel(val, CORE_CTRL_IO);
return 0;
- }
- if (bitlen == 0)
goto out;
- if (bitlen % 8) {
debug("spi_xfer: Non byte aligned SPI transfer\n");
return -1;
- }
- /* Setup command reg */
- qslave->cmd = 0;
- qslave->cmd |= QSPI_WLEN(8);
- qslave->cmd |= QSPI_EN_CS(slave->cs);
- if (flags& SPI_3WIRE)
qslave->cmd |= QSPI_3_PIN;
- qslave->cmd |= 0xfff;
- while (words--) {
if (txp) {
debug("tx cmd %08x dc %08x data %02x\n",
qslave->cmd | QSPI_WR_SNGL, qslave->dc, *txp);
writel(*txp++,&qslave->base->spi_data);
writel(qslave->cmd | QSPI_WR_SNGL,
&qslave->base->spi_cmd);
status = readl(&qslave->base->spi_status);
timeout = QSPI_TIMEOUT;
while ((status& QSPI_WC_BUSY) != QSPI_XFER_DONE) {
if (--timeout< 0) {
printf("spi_xfer: TX timeout!\n");
return -1;
}
status = readl(&qslave->base->spi_status);
}
debug("tx done, status %08x\n", status);
}
if (rxp) {
qslave->cmd |= QSPI_RD_SNGL;
debug("rx cmd %08x dc %08x\n",
qslave->cmd, qslave->dc);
writel(qslave->cmd,&qslave->base->spi_cmd);
status = readl(&qslave->base->spi_status);
timeout = QSPI_TIMEOUT;
while ((status& QSPI_WC_BUSY) != QSPI_XFER_DONE) {
if (--timeout< 0) {
printf("spi_xfer: RX timeout!\n");
return -1;
}
status = readl(&qslave->base->spi_status);
}
*rxp++ = readl(&qslave->base->spi_data);
debug("rx done, status %08x, read %02x\n",
status, *(rxp-1));
}
- }
- /* Terminate frame */
- if (flags& SPI_XFER_END)
spi_cs_deactivate();
- return 0;
+}
participants (2)
-
Jagannadha Sutradharudu Teki
-
Sourav Poddar