Patchwork [U-Boot,v3] spi: Add support SH Quad SPI driver

login
register
mail settings
Submitter Nobuhiro Iwamatsu
Date Aug. 22, 2013, 1:54 a.m.
Message ID <1377136481-27785-1-git-send-email-nobuhiro.iwamatsu.yj@renesas.com>
Download mbox | patch
Permalink /patch/268920/
State Changes Requested, archived
Delegated to: Jagannadha Sutradharudu Teki
Headers show

Comments

Nobuhiro Iwamatsu - Aug. 22, 2013, 1:54 a.m.
This patch adds a driver for Renesas SoC's Quad SPI bus.
This supports with 8 bits per transfer to use with SPI flash.

Signed-off-by: Kouei Abe <kouei.abe.cp@renesas.com>
Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
---
v3: Change Queued to Quad.
    Remove path of file from file header.
    Use read* and write* directly instead of sh_qspi_write* sh_qspi_read*.
    Change driver format.

v2: Change "SH QSPI" to "SH QSPI (Queued SPI)".
    Remove magic number.

 drivers/spi/Makefile  |   1 +
 drivers/spi/sh_qspi.c | 248 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 249 insertions(+)
 create mode 100644 drivers/spi/sh_qspi.c
Jagannadha Sutradharudu Teki - Oct. 3, 2013, 5:58 p.m.
Have you verified this on hw?

Sorry for the late response.
Can you RESEND the patch again- I couldn't find it on patchwork.

Thanks,
Jagan.

> -----Original Message-----
> From: Nobuhiro Iwamatsu [mailto:iwamatsu@nigauri.org] On Behalf Of
> Nobuhiro Iwamatsu
> Sent: Thursday, August 22, 2013 7:25 AM
> To: Jagannadha Sutradharudu Teki
> Cc: trini@ti.com; u-boot@lists.denx.de; jagannadh.teki@gmail.com;
> Nobuhiro Iwamatsu; Kouei Abe
> Subject: [PATCH v3] spi: Add support SH Quad SPI driver
>
> This patch adds a driver for Renesas SoC's Quad SPI bus.
> This supports with 8 bits per transfer to use with SPI flash.
>
> Signed-off-by: Kouei Abe <kouei.abe.cp@renesas.com>
> Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
> ---
> v3: Change Queued to Quad.
>     Remove path of file from file header.
>     Use read* and write* directly instead of sh_qspi_write* sh_qspi_read*.
>     Change driver format.
>
> v2: Change "SH QSPI" to "SH QSPI (Queued SPI)".
>     Remove magic number.
>
>  drivers/spi/Makefile  |   1 +
>  drivers/spi/sh_qspi.c | 248
> ++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 249 insertions(+)
>  create mode 100644 drivers/spi/sh_qspi.c
>
> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index
> 91d24ce..c44f851 100644
> --- a/drivers/spi/Makefile
> +++ b/drivers/spi/Makefile
> @@ -33,6 +33,7 @@ COBJS-$(CONFIG_OC_TINY_SPI) += oc_tiny_spi.o
>  COBJS-$(CONFIG_OMAP3_SPI) += omap3_spi.o
>  COBJS-$(CONFIG_SOFT_SPI) += soft_spi.o
>  COBJS-$(CONFIG_SH_SPI) += sh_spi.o
> +COBJS-$(CONFIG_SH_QSPI) += sh_qspi.o
>  COBJS-$(CONFIG_FSL_ESPI) += fsl_espi.o
>  COBJS-$(CONFIG_FDT_SPI) += fdt_spi.o
>  COBJS-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o diff --git
> a/drivers/spi/sh_qspi.c b/drivers/spi/sh_qspi.c new file mode 100644 index
> 0000000..2efaea8
> --- /dev/null
> +++ b/drivers/spi/sh_qspi.c
> @@ -0,0 +1,248 @@
> +/*
> + * SH QSPI (Quad SPI) driver
> + *
> + * Copyright (C) 2013 Renesas Electronics Corporation
> + * Copyright (C) 2013 Nobuhiro Iwamatsu
> +<nobuhiro.iwamatsu.yj@renesas.com>
> + *
> + * SPDX-License-Identifier:  GPL-2.0
> + */
> +
> +#include <common.h>
> +#include <malloc.h>
> +#include <spi.h>
> +#include <asm/io.h>
> +
> +/* SPCR */
> +#define SPCR_MSTR 0x08
> +#define SPCR_SPE 0x40
> +
> +/* SPSR */
> +#define SPSR_SPRFF 0x80
> +#define SPSR_SPTEF 0x20
> +
> +/* SPPCR */
> +#define SPPCR_IO3FV 0x04
> +#define SPPCR_IO2FV 0x02
> +#define SPPCR_IO1FV 0x01
> +
> +/* SPBDCR */
> +#define SPBDCR_RXBC0 (1 << 0)
> +
> +/* SPCMD */
> +#define SPCMD_SCKDEN (1 << 15)
> +#define SPCMD_SLNDEN (1 << 14)
> +#define SPCMD_SPNDEN (1 << 13)
> +#define SPCMD_SSLKP (1 << 7)
> +#define SPCMD_BRDV0 (1 << 2)
> +#define SPCMD_INIT1 \
> +
>       (SPCMD_SCKDEN|SPCMD_SLNDEN|SPCMD_SPNDEN|SPCMD_SSLKP|
> SPCMD_BRDV0)
> +#define SPCMD_INIT2 (SPCMD_SPNDEN|SPCMD_SSLKP|SPCMD_BRDV0)
> +
> +/* SPBFCR */
> +#define SPBFCR_TXRST (1 << 7)
> +#define SPBFCR_RXRST (1 << 6)
> +
> +/* SH QSPI register set */
> +struct sh_qspi_regs {
> +     unsigned char spcr;
> +     unsigned char sslp;
> +     unsigned char sppcr;
> +     unsigned char spsr;
> +     unsigned long spdr;
> +     unsigned char spscr;
> +     unsigned char spssr;
> +     unsigned char spbr;
> +     unsigned char spdcr;
> +     unsigned char spckd;
> +     unsigned char sslnd;
> +     unsigned char spnd;
> +     unsigned char dummy0;
> +     unsigned short spcmd0;
> +     unsigned short spcmd1;
> +     unsigned short spcmd2;
> +     unsigned short spcmd3;
> +     unsigned char spbfcr;
> +     unsigned char dummy1;
> +     unsigned short spbdcr;
> +     unsigned long spbmul0;
> +     unsigned long spbmul1;
> +     unsigned long spbmul2;
> +     unsigned long spbmul3;
> +};
> +
> +struct sh_qspi {
> +     struct spi_slave        slave;
> +     struct sh_qspi_regs     *regs;
> +};
> +
> +static inline struct sh_qspi *to_sh_qspi(struct spi_slave *slave) {
> +     return container_of(slave, struct sh_qspi, slave); }
> +
> +static int sh_qspi_xfer(struct sh_qspi *ss, unsigned char *tdata,
> +                     unsigned char *rdata, unsigned long flags) {
> +     while (!(readb(&ss->regs->spsr) & SPSR_SPTEF)) {
> +             if (ctrlc())
> +                     return 1;
> +             udelay(10);
> +     }
> +
> +     writeb(*tdata, (unsigned char *)(&ss->regs->spdr));
> +
> +     while ((readw(&ss->regs->spbdcr) != SPBDCR_RXBC0)) {
> +             int i = 100;
> +
> +             if (ctrlc())
> +                     return 1;
> +             while (i--)
> +                     ;
> +     }
> +
> +     while (!(readb(&ss->regs->spsr) & SPSR_SPRFF)) {
> +             if (ctrlc())
> +                     return 1;
> +             udelay(10);
> +     }
> +
> +     *rdata = readb((unsigned char *)(&ss->regs->spdr));
> +
> +     return 0;
> +}
> +
> +int spi_cs_is_valid(unsigned int bus, unsigned int cs) {
> +     return 1;
> +}
> +
> +void spi_cs_activate(struct spi_slave *slave) { }
> +
> +void spi_cs_deactivate(struct spi_slave *slave) { }
> +
> +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 sh_qspi *ss;
> +
> +     if (!spi_cs_is_valid(bus, cs))
> +             return NULL;
> +
> +     ss = spi_alloc_slave(struct sh_qspi, bus, cs);
> +     if (!ss)
> +             return NULL;
> +
> +     ss->regs = (struct sh_qspi_regs *)CONFIG_SH_QSPI_BASE;
> +
> +     /* QSPI initialize */
> +     writeb(SPCR_MSTR, &ss->regs->spcr);
> +     writeb(0x00, &ss->regs->sslp);
> +     writeb(SPPCR_IO3FV|SPPCR_IO2FV, &ss->regs->sppcr);
> +
> +     /* Set bit rate. See 58.3.8 Quad Serial Peripheral Interface */
> +     writeb(0x01, &ss->regs->spbr);
> +
> +     writeb(0x00, &ss->regs->spdcr);
> +     writeb(0x00, &ss->regs->spckd);
> +     writeb(0x00, &ss->regs->sslnd);
> +     writeb(0x00, &ss->regs->spnd);
> +     writew(SPCMD_INIT1, &ss->regs->spcmd0);
> +     writew(SPCMD_INIT2, &ss->regs->spcmd0);
> +     writeb(SPBFCR_TXRST|SPBFCR_RXRST, &ss->regs->spbfcr);
> +     writeb(0x00, &ss->regs->spbfcr);
> +     writeb(0x00, &ss->regs->spscr);
> +     writeb(SPCR_SPE|SPCR_MSTR, &ss->regs->spcr);
> +
> +     return &ss->slave;
> +}
> +
> +void spi_free_slave(struct spi_slave *slave) {
> +     struct sh_qspi *spi = to_sh_qspi(slave);
> +
> +     free(spi);
> +}
> +
> +int spi_claim_bus(struct spi_slave *slave) {
> +     return 0;
> +}
> +
> +void spi_release_bus(struct spi_slave *slave) { }
> +
> +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
> +          void *din, unsigned long flags)
> +{
> +     struct sh_qspi *ss = to_sh_qspi(slave);
> +     unsigned long nbyte;
> +     int ret = 0;
> +     unsigned char *tdata, *rdata, dtdata = 0, drdata;
> +
> +     if (dout == NULL && din == NULL) {
> +             if (flags & SPI_XFER_END)
> +                     writeb(SPCR_MSTR, &ss->regs->spcr);
> +             return 0;
> +     }
> +
> +     if (bitlen % 8) {
> +             printf("%s: bitlen is not 8bit alined %d", __func__, bitlen);
> +             return 1;
> +     }
> +
> +     nbyte = bitlen / 8;
> +
> +     if (flags & SPI_XFER_BEGIN) {
> +             unsigned long *spbmul0 = &ss->regs->spbmul0;
> +             writeb(SPCR_MSTR, &ss->regs->spcr);
> +
> +             writew(SPCMD_INIT1, &ss->regs->spcmd0);
> +
> +             if (flags & SPI_XFER_END)
> +                     writel(nbyte, spbmul0);
> +             else
> +                     /* Set 1048576 byte */
> +                     writel(0x100000, spbmul0);
> +
> +             writeb(SPBFCR_TXRST|SPBFCR_RXRST, &ss->regs->spbfcr);
> +             writeb(0x00, &ss->regs->spbfcr);
> +             writeb(0x00, &ss->regs->spscr);
> +             writeb(SPCR_SPE|SPCR_MSTR, &ss->regs->spcr);
> +     }
> +
> +     if (dout != NULL)
> +             tdata = (unsigned char *)dout;
> +     else
> +             tdata = &dtdata;
> +
> +     if (din != NULL)
> +             rdata = din;
> +     else
> +             rdata = &drdata;
> +
> +     while (nbyte > 0) {
> +             ret = sh_qspi_xfer(ss, tdata, rdata, flags);
> +             if (ret)
> +                     break;
> +             if (dout != NULL)
> +                     tdata++;
> +             if (din != NULL)
> +                     rdata++;
> +             nbyte--;
> +     }
> +
> +     if (flags & SPI_XFER_END)
> +             writeb(SPCR_MSTR, &ss->regs->spcr);
> +
> +     return ret;
> +}
> --
> 1.8.3.2
>



This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.
Jagannadha Sutradharudu Teki - Oct. 3, 2013, 7:35 p.m.
Ignore this I found.

On Thu, Oct 3, 2013 at 11:28 PM, Jagannadha Sutradharudu Teki
<jagannadha.sutradharudu-teki@xilinx.com> wrote:
> Have you verified this on hw?
>
> Sorry for the late response.
> Can you RESEND the patch again- I couldn't find it on patchwork.
>
> Thanks,
> Jagan.
>
>> -----Original Message-----
>> From: Nobuhiro Iwamatsu [mailto:iwamatsu@nigauri.org] On Behalf Of
>> Nobuhiro Iwamatsu
>> Sent: Thursday, August 22, 2013 7:25 AM
>> To: Jagannadha Sutradharudu Teki
>> Cc: trini@ti.com; u-boot@lists.denx.de; jagannadh.teki@gmail.com;
>> Nobuhiro Iwamatsu; Kouei Abe
>> Subject: [PATCH v3] spi: Add support SH Quad SPI driver
>>
>> This patch adds a driver for Renesas SoC's Quad SPI bus.
>> This supports with 8 bits per transfer to use with SPI flash.
>>
>> Signed-off-by: Kouei Abe <kouei.abe.cp@renesas.com>
>> Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
>> ---
>> v3: Change Queued to Quad.
>>     Remove path of file from file header.
>>     Use read* and write* directly instead of sh_qspi_write* sh_qspi_read*.
>>     Change driver format.
>>
>> v2: Change "SH QSPI" to "SH QSPI (Queued SPI)".
>>     Remove magic number.
>>
>>  drivers/spi/Makefile  |   1 +
>>  drivers/spi/sh_qspi.c | 248
>> ++++++++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 249 insertions(+)
>>  create mode 100644 drivers/spi/sh_qspi.c
>>
>> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index
>> 91d24ce..c44f851 100644
>> --- a/drivers/spi/Makefile
>> +++ b/drivers/spi/Makefile
>> @@ -33,6 +33,7 @@ COBJS-$(CONFIG_OC_TINY_SPI) += oc_tiny_spi.o
>>  COBJS-$(CONFIG_OMAP3_SPI) += omap3_spi.o
>>  COBJS-$(CONFIG_SOFT_SPI) += soft_spi.o
>>  COBJS-$(CONFIG_SH_SPI) += sh_spi.o
>> +COBJS-$(CONFIG_SH_QSPI) += sh_qspi.o
>>  COBJS-$(CONFIG_FSL_ESPI) += fsl_espi.o
>>  COBJS-$(CONFIG_FDT_SPI) += fdt_spi.o
>>  COBJS-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o diff --git
>> a/drivers/spi/sh_qspi.c b/drivers/spi/sh_qspi.c new file mode 100644 index
>> 0000000..2efaea8
>> --- /dev/null
>> +++ b/drivers/spi/sh_qspi.c
>> @@ -0,0 +1,248 @@
>> +/*
>> + * SH QSPI (Quad SPI) driver
>> + *
>> + * Copyright (C) 2013 Renesas Electronics Corporation
>> + * Copyright (C) 2013 Nobuhiro Iwamatsu
>> +<nobuhiro.iwamatsu.yj@renesas.com>
>> + *
>> + * SPDX-License-Identifier:  GPL-2.0
>> + */
>> +
>> +#include <common.h>
>> +#include <malloc.h>
>> +#include <spi.h>
>> +#include <asm/io.h>
>> +
>> +/* SPCR */
>> +#define SPCR_MSTR 0x08
>> +#define SPCR_SPE 0x40
>> +
>> +/* SPSR */
>> +#define SPSR_SPRFF 0x80
>> +#define SPSR_SPTEF 0x20
>> +
>> +/* SPPCR */
>> +#define SPPCR_IO3FV 0x04
>> +#define SPPCR_IO2FV 0x02
>> +#define SPPCR_IO1FV 0x01
>> +
>> +/* SPBDCR */
>> +#define SPBDCR_RXBC0 (1 << 0)
>> +
>> +/* SPCMD */
>> +#define SPCMD_SCKDEN (1 << 15)
>> +#define SPCMD_SLNDEN (1 << 14)
>> +#define SPCMD_SPNDEN (1 << 13)
>> +#define SPCMD_SSLKP (1 << 7)
>> +#define SPCMD_BRDV0 (1 << 2)
>> +#define SPCMD_INIT1 \
>> +
>>       (SPCMD_SCKDEN|SPCMD_SLNDEN|SPCMD_SPNDEN|SPCMD_SSLKP|
>> SPCMD_BRDV0)
>> +#define SPCMD_INIT2 (SPCMD_SPNDEN|SPCMD_SSLKP|SPCMD_BRDV0)
>> +
>> +/* SPBFCR */
>> +#define SPBFCR_TXRST (1 << 7)
>> +#define SPBFCR_RXRST (1 << 6)
>> +
>> +/* SH QSPI register set */
>> +struct sh_qspi_regs {
>> +     unsigned char spcr;
>> +     unsigned char sslp;
>> +     unsigned char sppcr;
>> +     unsigned char spsr;
>> +     unsigned long spdr;
>> +     unsigned char spscr;
>> +     unsigned char spssr;
>> +     unsigned char spbr;
>> +     unsigned char spdcr;
>> +     unsigned char spckd;
>> +     unsigned char sslnd;
>> +     unsigned char spnd;
>> +     unsigned char dummy0;
>> +     unsigned short spcmd0;
>> +     unsigned short spcmd1;
>> +     unsigned short spcmd2;
>> +     unsigned short spcmd3;
>> +     unsigned char spbfcr;
>> +     unsigned char dummy1;
>> +     unsigned short spbdcr;
>> +     unsigned long spbmul0;
>> +     unsigned long spbmul1;
>> +     unsigned long spbmul2;
>> +     unsigned long spbmul3;
>> +};
>> +
>> +struct sh_qspi {
>> +     struct spi_slave        slave;
>> +     struct sh_qspi_regs     *regs;
>> +};
>> +
>> +static inline struct sh_qspi *to_sh_qspi(struct spi_slave *slave) {
>> +     return container_of(slave, struct sh_qspi, slave); }
>> +
>> +static int sh_qspi_xfer(struct sh_qspi *ss, unsigned char *tdata,
>> +                     unsigned char *rdata, unsigned long flags) {
>> +     while (!(readb(&ss->regs->spsr) & SPSR_SPTEF)) {
>> +             if (ctrlc())
>> +                     return 1;
>> +             udelay(10);
>> +     }
>> +
>> +     writeb(*tdata, (unsigned char *)(&ss->regs->spdr));
>> +
>> +     while ((readw(&ss->regs->spbdcr) != SPBDCR_RXBC0)) {
>> +             int i = 100;
>> +
>> +             if (ctrlc())
>> +                     return 1;
>> +             while (i--)
>> +                     ;
>> +     }
>> +
>> +     while (!(readb(&ss->regs->spsr) & SPSR_SPRFF)) {
>> +             if (ctrlc())
>> +                     return 1;
>> +             udelay(10);
>> +     }
>> +
>> +     *rdata = readb((unsigned char *)(&ss->regs->spdr));
>> +
>> +     return 0;
>> +}
>> +
>> +int spi_cs_is_valid(unsigned int bus, unsigned int cs) {
>> +     return 1;
>> +}
>> +
>> +void spi_cs_activate(struct spi_slave *slave) { }
>> +
>> +void spi_cs_deactivate(struct spi_slave *slave) { }
>> +
>> +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 sh_qspi *ss;
>> +
>> +     if (!spi_cs_is_valid(bus, cs))
>> +             return NULL;
>> +
>> +     ss = spi_alloc_slave(struct sh_qspi, bus, cs);
>> +     if (!ss)
>> +             return NULL;
>> +
>> +     ss->regs = (struct sh_qspi_regs *)CONFIG_SH_QSPI_BASE;
>> +
>> +     /* QSPI initialize */
>> +     writeb(SPCR_MSTR, &ss->regs->spcr);
>> +     writeb(0x00, &ss->regs->sslp);
>> +     writeb(SPPCR_IO3FV|SPPCR_IO2FV, &ss->regs->sppcr);
>> +
>> +     /* Set bit rate. See 58.3.8 Quad Serial Peripheral Interface */
>> +     writeb(0x01, &ss->regs->spbr);
>> +
>> +     writeb(0x00, &ss->regs->spdcr);
>> +     writeb(0x00, &ss->regs->spckd);
>> +     writeb(0x00, &ss->regs->sslnd);
>> +     writeb(0x00, &ss->regs->spnd);
>> +     writew(SPCMD_INIT1, &ss->regs->spcmd0);
>> +     writew(SPCMD_INIT2, &ss->regs->spcmd0);
>> +     writeb(SPBFCR_TXRST|SPBFCR_RXRST, &ss->regs->spbfcr);
>> +     writeb(0x00, &ss->regs->spbfcr);
>> +     writeb(0x00, &ss->regs->spscr);
>> +     writeb(SPCR_SPE|SPCR_MSTR, &ss->regs->spcr);
>> +
>> +     return &ss->slave;
>> +}
>> +
>> +void spi_free_slave(struct spi_slave *slave) {
>> +     struct sh_qspi *spi = to_sh_qspi(slave);
>> +
>> +     free(spi);
>> +}
>> +
>> +int spi_claim_bus(struct spi_slave *slave) {
>> +     return 0;
>> +}
>> +
>> +void spi_release_bus(struct spi_slave *slave) { }
>> +
>> +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
>> +          void *din, unsigned long flags)
>> +{
>> +     struct sh_qspi *ss = to_sh_qspi(slave);
>> +     unsigned long nbyte;
>> +     int ret = 0;
>> +     unsigned char *tdata, *rdata, dtdata = 0, drdata;
>> +
>> +     if (dout == NULL && din == NULL) {
>> +             if (flags & SPI_XFER_END)
>> +                     writeb(SPCR_MSTR, &ss->regs->spcr);
>> +             return 0;
>> +     }
>> +
>> +     if (bitlen % 8) {
>> +             printf("%s: bitlen is not 8bit alined %d", __func__, bitlen);
>> +             return 1;
>> +     }
>> +
>> +     nbyte = bitlen / 8;
>> +
>> +     if (flags & SPI_XFER_BEGIN) {
>> +             unsigned long *spbmul0 = &ss->regs->spbmul0;
>> +             writeb(SPCR_MSTR, &ss->regs->spcr);
>> +
>> +             writew(SPCMD_INIT1, &ss->regs->spcmd0);
>> +
>> +             if (flags & SPI_XFER_END)
>> +                     writel(nbyte, spbmul0);
>> +             else
>> +                     /* Set 1048576 byte */
>> +                     writel(0x100000, spbmul0);
>> +
>> +             writeb(SPBFCR_TXRST|SPBFCR_RXRST, &ss->regs->spbfcr);
>> +             writeb(0x00, &ss->regs->spbfcr);
>> +             writeb(0x00, &ss->regs->spscr);
>> +             writeb(SPCR_SPE|SPCR_MSTR, &ss->regs->spcr);
>> +     }
>> +
>> +     if (dout != NULL)
>> +             tdata = (unsigned char *)dout;
>> +     else
>> +             tdata = &dtdata;
>> +
>> +     if (din != NULL)
>> +             rdata = din;
>> +     else
>> +             rdata = &drdata;
>> +
>> +     while (nbyte > 0) {
>> +             ret = sh_qspi_xfer(ss, tdata, rdata, flags);
>> +             if (ret)
>> +                     break;
>> +             if (dout != NULL)
>> +                     tdata++;
>> +             if (din != NULL)
>> +                     rdata++;
>> +             nbyte--;
>> +     }
>> +
>> +     if (flags & SPI_XFER_END)
>> +             writeb(SPCR_MSTR, &ss->regs->spcr);
>> +
>> +     return ret;
>> +}
>> --
>> 1.8.3.2
>>
>
>
>
> This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.
>
>

Patch

diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 91d24ce..c44f851 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -33,6 +33,7 @@  COBJS-$(CONFIG_OC_TINY_SPI) += oc_tiny_spi.o
 COBJS-$(CONFIG_OMAP3_SPI) += omap3_spi.o
 COBJS-$(CONFIG_SOFT_SPI) += soft_spi.o
 COBJS-$(CONFIG_SH_SPI) += sh_spi.o
+COBJS-$(CONFIG_SH_QSPI) += sh_qspi.o
 COBJS-$(CONFIG_FSL_ESPI) += fsl_espi.o
 COBJS-$(CONFIG_FDT_SPI) += fdt_spi.o
 COBJS-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o
diff --git a/drivers/spi/sh_qspi.c b/drivers/spi/sh_qspi.c
new file mode 100644
index 0000000..2efaea8
--- /dev/null
+++ b/drivers/spi/sh_qspi.c
@@ -0,0 +1,248 @@ 
+/*
+ * SH QSPI (Quad SPI) driver
+ *
+ * Copyright (C) 2013 Renesas Electronics Corporation
+ * Copyright (C) 2013 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <spi.h>
+#include <asm/io.h>
+
+/* SPCR */
+#define SPCR_MSTR 0x08
+#define SPCR_SPE 0x40
+
+/* SPSR */
+#define SPSR_SPRFF 0x80
+#define SPSR_SPTEF 0x20
+
+/* SPPCR */
+#define SPPCR_IO3FV 0x04
+#define SPPCR_IO2FV 0x02
+#define SPPCR_IO1FV 0x01
+
+/* SPBDCR */
+#define SPBDCR_RXBC0 (1 << 0)
+
+/* SPCMD */
+#define SPCMD_SCKDEN (1 << 15)
+#define SPCMD_SLNDEN (1 << 14)
+#define SPCMD_SPNDEN (1 << 13)
+#define SPCMD_SSLKP (1 << 7)
+#define SPCMD_BRDV0 (1 << 2)
+#define SPCMD_INIT1 \
+	(SPCMD_SCKDEN|SPCMD_SLNDEN|SPCMD_SPNDEN|SPCMD_SSLKP|SPCMD_BRDV0)
+#define SPCMD_INIT2 (SPCMD_SPNDEN|SPCMD_SSLKP|SPCMD_BRDV0)
+
+/* SPBFCR */
+#define SPBFCR_TXRST (1 << 7)
+#define SPBFCR_RXRST (1 << 6)
+
+/* SH QSPI register set */
+struct sh_qspi_regs {
+	unsigned char spcr;
+	unsigned char sslp;
+	unsigned char sppcr;
+	unsigned char spsr;
+	unsigned long spdr;
+	unsigned char spscr;
+	unsigned char spssr;
+	unsigned char spbr;
+	unsigned char spdcr;
+	unsigned char spckd;
+	unsigned char sslnd;
+	unsigned char spnd;
+	unsigned char dummy0;
+	unsigned short spcmd0;
+	unsigned short spcmd1;
+	unsigned short spcmd2;
+	unsigned short spcmd3;
+	unsigned char spbfcr;
+	unsigned char dummy1;
+	unsigned short spbdcr;
+	unsigned long spbmul0;
+	unsigned long spbmul1;
+	unsigned long spbmul2;
+	unsigned long spbmul3;
+};
+
+struct sh_qspi {
+	struct spi_slave	slave;
+	struct sh_qspi_regs	*regs;
+};
+
+static inline struct sh_qspi *to_sh_qspi(struct spi_slave *slave)
+{
+	return container_of(slave, struct sh_qspi, slave);
+}
+
+static int sh_qspi_xfer(struct sh_qspi *ss, unsigned char *tdata,
+			unsigned char *rdata, unsigned long flags)
+{
+	while (!(readb(&ss->regs->spsr) & SPSR_SPTEF)) {
+		if (ctrlc())
+			return 1;
+		udelay(10);
+	}
+
+	writeb(*tdata, (unsigned char *)(&ss->regs->spdr));
+
+	while ((readw(&ss->regs->spbdcr) != SPBDCR_RXBC0)) {
+		int i = 100;
+
+		if (ctrlc())
+			return 1;
+		while (i--)
+			;
+	}
+
+	while (!(readb(&ss->regs->spsr) & SPSR_SPRFF)) {
+		if (ctrlc())
+			return 1;
+		udelay(10);
+	}
+
+	*rdata = readb((unsigned char *)(&ss->regs->spdr));
+
+	return 0;
+}
+
+int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+{
+	return 1;
+}
+
+void spi_cs_activate(struct spi_slave *slave)
+{
+}
+
+void spi_cs_deactivate(struct spi_slave *slave)
+{
+}
+
+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 sh_qspi *ss;
+
+	if (!spi_cs_is_valid(bus, cs))
+		return NULL;
+
+	ss = spi_alloc_slave(struct sh_qspi, bus, cs);
+	if (!ss)
+		return NULL;
+
+	ss->regs = (struct sh_qspi_regs *)CONFIG_SH_QSPI_BASE;
+
+	/* QSPI initialize */
+	writeb(SPCR_MSTR, &ss->regs->spcr);
+	writeb(0x00, &ss->regs->sslp);
+	writeb(SPPCR_IO3FV|SPPCR_IO2FV, &ss->regs->sppcr);
+
+	/* Set bit rate. See 58.3.8 Quad Serial Peripheral Interface */
+	writeb(0x01, &ss->regs->spbr);
+
+	writeb(0x00, &ss->regs->spdcr);
+	writeb(0x00, &ss->regs->spckd);
+	writeb(0x00, &ss->regs->sslnd);
+	writeb(0x00, &ss->regs->spnd);
+	writew(SPCMD_INIT1, &ss->regs->spcmd0);
+	writew(SPCMD_INIT2, &ss->regs->spcmd0);
+	writeb(SPBFCR_TXRST|SPBFCR_RXRST, &ss->regs->spbfcr);
+	writeb(0x00, &ss->regs->spbfcr);
+	writeb(0x00, &ss->regs->spscr);
+	writeb(SPCR_SPE|SPCR_MSTR, &ss->regs->spcr);
+
+	return &ss->slave;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+	struct sh_qspi *spi = to_sh_qspi(slave);
+
+	free(spi);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+	return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
+	     void *din, unsigned long flags)
+{
+	struct sh_qspi *ss = to_sh_qspi(slave);
+	unsigned long nbyte;
+	int ret = 0;
+	unsigned char *tdata, *rdata, dtdata = 0, drdata;
+
+	if (dout == NULL && din == NULL) {
+		if (flags & SPI_XFER_END)
+			writeb(SPCR_MSTR, &ss->regs->spcr);
+		return 0;
+	}
+
+	if (bitlen % 8) {
+		printf("%s: bitlen is not 8bit alined %d", __func__, bitlen);
+		return 1;
+	}
+
+	nbyte = bitlen / 8;
+
+	if (flags & SPI_XFER_BEGIN) {
+		unsigned long *spbmul0 = &ss->regs->spbmul0;
+		writeb(SPCR_MSTR, &ss->regs->spcr);
+
+		writew(SPCMD_INIT1, &ss->regs->spcmd0);
+
+		if (flags & SPI_XFER_END)
+			writel(nbyte, spbmul0);
+		else
+			/* Set 1048576 byte */
+			writel(0x100000, spbmul0);
+
+		writeb(SPBFCR_TXRST|SPBFCR_RXRST, &ss->regs->spbfcr);
+		writeb(0x00, &ss->regs->spbfcr);
+		writeb(0x00, &ss->regs->spscr);
+		writeb(SPCR_SPE|SPCR_MSTR, &ss->regs->spcr);
+	}
+
+	if (dout != NULL)
+		tdata = (unsigned char *)dout;
+	else
+		tdata = &dtdata;
+
+	if (din != NULL)
+		rdata = din;
+	else
+		rdata = &drdata;
+
+	while (nbyte > 0) {
+		ret = sh_qspi_xfer(ss, tdata, rdata, flags);
+		if (ret)
+			break;
+		if (dout != NULL)
+			tdata++;
+		if (din != NULL)
+			rdata++;
+		nbyte--;
+	}
+
+	if (flags & SPI_XFER_END)
+		writeb(SPCR_MSTR, &ss->regs->spcr);
+
+	return ret;
+}