[U-Boot] [PATCH v1 2/3] spi: sh_spi: DM conversion
Jagan Teki
jagannadh.teki at gmail.com
Fri Apr 27 06:22:38 UTC 2018
+ add relevant board mainatiners
On Thu, Apr 26, 2018 at 10:18 PM, Akash Gajjar <gajjar04akash at gmail.com> wrote:
> This patch adds support for DM to the sh_spi driver. legacy driver support is
> removed.
>
> Some TODOs are left over for later, These would be enhancements to the
> original functionality, and can come later. The legacy functionality is
> removed in this version.
>
> This patch is not tested on board as well compile tested yet.
>
> Signed-off-by: Akash Gajjar <akash at openedev.com>
> ---
> drivers/spi/Kconfig | 12 +--
> drivers/spi/sh_spi.c | 214 +++++++++++++++++++++-----------------
> drivers/spi/sh_spi.h | 3 +-
> include/dm/platform_data/spi_sh.h | 20 ++++
> 4 files changed, 147 insertions(+), 102 deletions(-)
> create mode 100644 include/dm/platform_data/spi_sh.h
>
> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> index ec92b84..be6ad22 100644
> --- a/drivers/spi/Kconfig
> +++ b/drivers/spi/Kconfig
> @@ -155,6 +155,12 @@ config SANDBOX_SPI
> };
> };
>
> +config SH_SPI
> + bool "SuperH SPI driver"
> + help
> + Enable the SuperH SPI controller driver. This driver can be used
> + on various SuperH SoCs, such as SH7757.
> +
> config STM32_QSPI
> bool "STM32F7 QSPI driver"
> depends on STM32F7
> @@ -253,12 +259,6 @@ config DAVINCI_SPI
> help
> Enable the Davinci SPI driver
>
> -config SH_SPI
> - bool "SuperH SPI driver"
> - help
> - Enable the SuperH SPI controller driver. This driver can be used
> - on various SuperH SoCs, such as SH7757.
> -
> config SH_QSPI
> bool "Renesas Quad SPI driver"
> help
> diff --git a/drivers/spi/sh_spi.c b/drivers/spi/sh_spi.c
> index fe394e3..b308ec8 100644
> --- a/drivers/spi/sh_spi.c
> +++ b/drivers/spi/sh_spi.c
> @@ -1,6 +1,10 @@
> /*
> * SH SPI driver
> *
> + * Support for device model:
> + * Copyright (C) 2018 Akash Gajjar <akash at openedev.com>
> + * Harshit Shah <shahharshitr at gmail.com>
> + *
> * Copyright (C) 2011-2012 Renesas Solutions Corp.
> *
> * SPDX-License-Identifier: GPL-2.0
> @@ -11,6 +15,8 @@
> #include <malloc.h>
> #include <spi.h>
> #include <asm/io.h>
> +#include <dm.h>
> +#include <dm/platform_data/spi_sh.h>
> #include "sh_spi.h"
>
> static void sh_spi_write(unsigned long data, unsigned long *reg)
> @@ -41,15 +47,15 @@ static void sh_spi_clear_bit(unsigned long val, unsigned long *reg)
> sh_spi_write(tmp, reg);
> }
>
> -static void clear_fifo(struct sh_spi *ss)
> +static void clear_fifo(struct sh_spi_regs *regs)
> {
> - sh_spi_set_bit(SH_SPI_RSTF, &ss->regs->cr2);
> - sh_spi_clear_bit(SH_SPI_RSTF, &ss->regs->cr2);
> + sh_spi_set_bit(SH_SPI_RSTF, ®s->cr2);
> + sh_spi_clear_bit(SH_SPI_RSTF, ®s->cr2);
> }
>
> -static int recvbuf_wait(struct sh_spi *ss)
> +static int recvbuf_wait(struct sh_spi_regs *regs)
> {
> - while (sh_spi_read(&ss->regs->cr1) & SH_SPI_RBE) {
> + while (sh_spi_read(®s->cr1) & SH_SPI_RBE) {
> if (ctrlc())
> return 1;
> udelay(10);
> @@ -57,9 +63,9 @@ static int recvbuf_wait(struct sh_spi *ss)
> return 0;
> }
>
> -static int write_fifo_empty_wait(struct sh_spi *ss)
> +static int write_fifo_empty_wait(struct sh_spi_regs *regs)
> {
> - while (!(sh_spi_read(&ss->regs->cr1) & SH_SPI_TBE)) {
> + while (!(sh_spi_read(®s->cr1) & SH_SPI_TBE)) {
> if (ctrlc())
> return 1;
> udelay(10);
> @@ -67,11 +73,7 @@ static int write_fifo_empty_wait(struct sh_spi *ss)
> return 0;
> }
>
> -void spi_init(void)
> -{
> -}
> -
> -static void sh_spi_set_cs(struct sh_spi *ss, unsigned int cs)
> +static void sh_spi_set_cs(struct sh_spi_regs *regs, unsigned int cs)
> {
> unsigned long val = 0;
>
> @@ -80,85 +82,53 @@ static void sh_spi_set_cs(struct sh_spi *ss, unsigned int cs)
> if (cs & 0x02)
> val |= SH_SPI_SSS1;
>
> - sh_spi_clear_bit(SH_SPI_SSS0 | SH_SPI_SSS1, &ss->regs->cr4);
> - sh_spi_set_bit(val, &ss->regs->cr4);
> + sh_spi_clear_bit(SH_SPI_SSS0 | SH_SPI_SSS1, ®s->cr4);
> + sh_spi_set_bit(val, ®s->cr4);
> }
>
> -struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
> - unsigned int max_hz, unsigned int mode)
> +static void __spi_setup(struct sh_spi_regs *regs, uint cs)
> {
> - struct sh_spi *ss;
> -
> - if (!spi_cs_is_valid(bus, cs))
> - return NULL;
> -
> - ss = spi_alloc_slave(struct sh_spi, bus, cs);
> - if (!ss)
> - return NULL;
> -
> - ss->regs = (struct sh_spi_regs *)CONFIG_SH_SPI_BASE;
> -
> + /* initialize spi */
> + regs = (struct sh_spi_regs *)CONFIG_SH_SPI_BASE;
wrong, we have plat->regs
> /* SPI sycle stop */
> - sh_spi_write(0xfe, &ss->regs->cr1);
> + sh_spi_write(0xfe, ®s->cr1);
> /* CR1 init */
> - sh_spi_write(0x00, &ss->regs->cr1);
> + sh_spi_write(0x00, ®s->cr1);
> /* CR3 init */
> - sh_spi_write(0x00, &ss->regs->cr3);
> - sh_spi_set_cs(ss, cs);
> + sh_spi_write(0x00, ®s->cr3);
> + sh_spi_set_cs(regs, cs);
>
> - clear_fifo(ss);
> + clear_fifo(regs);
>
> /* 1/8 clock */
> - sh_spi_write(sh_spi_read(&ss->regs->cr2) | 0x07, &ss->regs->cr2);
> + sh_spi_write(sh_spi_read(®s->cr2) | 0x07, ®s->cr2);
> udelay(10);
> -
> - return &ss->slave;
> -}
> -
> -void spi_free_slave(struct spi_slave *slave)
> -{
> - struct sh_spi *spi = to_sh_spi(slave);
> -
> - free(spi);
> -}
> -
> -int spi_claim_bus(struct spi_slave *slave)
> -{
> - return 0;
> }
>
> -void spi_release_bus(struct spi_slave *slave)
> -{
> - struct sh_spi *ss = to_sh_spi(slave);
> -
> - sh_spi_write(sh_spi_read(&ss->regs->cr1) &
> - ~(SH_SPI_SSA | SH_SPI_SSDB | SH_SPI_SSD), &ss->regs->cr1);
> -}
> -
> -static int sh_spi_send(struct sh_spi *ss, const unsigned char *tx_data,
> +static int sh_spi_send(struct sh_spi_regs *regs, const unsigned char *tx_data,
> unsigned int len, unsigned long flags)
> {
> int i, cur_len, ret = 0;
> int remain = (int)len;
>
> if (len >= SH_SPI_FIFO_SIZE)
> - sh_spi_set_bit(SH_SPI_SSA, &ss->regs->cr1);
> + sh_spi_set_bit(SH_SPI_SSA, ®s->cr1);
>
> while (remain > 0) {
> cur_len = (remain < SH_SPI_FIFO_SIZE) ?
> remain : SH_SPI_FIFO_SIZE;
> for (i = 0; i < cur_len &&
> - !(sh_spi_read(&ss->regs->cr4) & SH_SPI_WPABRT) &&
> - !(sh_spi_read(&ss->regs->cr1) & SH_SPI_TBF);
> + !(sh_spi_read(®s->cr4) & SH_SPI_WPABRT) &&
> + !(sh_spi_read(®s->cr1) & SH_SPI_TBF);
> i++)
> - sh_spi_write(tx_data[i], &ss->regs->tbr_rbr);
> + sh_spi_write(tx_data[i], ®s->tbr_rbr);
>
> cur_len = i;
>
> - if (sh_spi_read(&ss->regs->cr4) & SH_SPI_WPABRT) {
> + if (sh_spi_read(®s->cr4) & SH_SPI_WPABRT) {
> /* Abort the transaction */
> flags |= SPI_XFER_END;
> - sh_spi_set_bit(SH_SPI_WPABRT, &ss->regs->cr4);
> + sh_spi_set_bit(SH_SPI_WPABRT, ®s->cr4);
> ret = 1;
> break;
> }
> @@ -167,88 +137,144 @@ static int sh_spi_send(struct sh_spi *ss, const unsigned char *tx_data,
> tx_data += cur_len;
>
> if (remain > 0)
> - write_fifo_empty_wait(ss);
> + write_fifo_empty_wait(regs);
> }
>
> if (flags & SPI_XFER_END) {
> - sh_spi_clear_bit(SH_SPI_SSD | SH_SPI_SSDB, &ss->regs->cr1);
> - sh_spi_set_bit(SH_SPI_SSA, &ss->regs->cr1);
> + sh_spi_clear_bit(SH_SPI_SSD | SH_SPI_SSDB, ®s->cr1);
> + sh_spi_set_bit(SH_SPI_SSA, ®s->cr1);
> udelay(100);
> - write_fifo_empty_wait(ss);
> + write_fifo_empty_wait(regs);
> }
>
> return ret;
> }
>
> -static int sh_spi_receive(struct sh_spi *ss, unsigned char *rx_data,
> - unsigned int len, unsigned long flags)
> +static int sh_spi_receive(struct sh_spi_regs *regs, unsigned char *rx_data,
> + unsigned int len, unsigned long flags)
> {
> int i;
>
> if (len > SH_SPI_MAX_BYTE)
> - sh_spi_write(SH_SPI_MAX_BYTE, &ss->regs->cr3);
> + sh_spi_write(SH_SPI_MAX_BYTE, ®s->cr3);
> else
> - sh_spi_write(len, &ss->regs->cr3);
> + sh_spi_write(len, ®s->cr3);
>
> - sh_spi_clear_bit(SH_SPI_SSD | SH_SPI_SSDB, &ss->regs->cr1);
> - sh_spi_set_bit(SH_SPI_SSA, &ss->regs->cr1);
> + sh_spi_clear_bit(SH_SPI_SSD | SH_SPI_SSDB, ®s->cr1);
> + sh_spi_set_bit(SH_SPI_SSA, ®s->cr1);
>
> for (i = 0; i < len; i++) {
> - if (recvbuf_wait(ss))
> + if (recvbuf_wait(regs))
> return 0;
>
> - rx_data[i] = (unsigned char)sh_spi_read(&ss->regs->tbr_rbr);
> + rx_data[i] = (unsigned char)sh_spi_read(®s->tbr_rbr);
> }
> - sh_spi_write(0, &ss->regs->cr3);
> + sh_spi_write(0, ®s->cr3);
>
> return 0;
> }
>
> -int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
> - void *din, unsigned long flags)
> +static int sh_spi_set_speed(struct udevice *bus, uint hz)
> {
> - struct sh_spi *ss = to_sh_spi(slave);
> + return 0;
> +}
> +
> +static int sh_spi_set_mode(struct udevice *bus, uint mode)
> +{
> + return 0;
> +}
> +
> +static int sh_spi_release_bus(struct udevice *dev)
> +{
> + struct sh_spi_priv *priv = dev_get_priv(bus);
> + struct sh_spi_regs *regs = priv->regs;
> +
> + sh_spi_write(sh_spi_read(®s->cr1) &
> + ~(SH_SPI_SSA | SH_SPI_SSDB | SH_SPI_SSD), ®s->cr1);
> +
> + return 0;
> +}
> +
> +static int sh_spi_xfer(struct udevice *dev, unsigned int bitlen,
> + const void *dout, void *din, unsigned long flags)
> +{
> + struct udevice *bus = dev_get_parent(dev);
> + struct sh_spi_priv *priv = dev_get_priv(bus);
> + struct sh_spi_regs *regs = priv->regs;
> const unsigned char *tx_data = dout;
> unsigned char *rx_data = din;
> unsigned int len = bitlen / 8;
> int ret = 0;
>
> if (flags & SPI_XFER_BEGIN)
> - sh_spi_write(sh_spi_read(&ss->regs->cr1) & ~SH_SPI_SSA,
> - &ss->regs->cr1);
> + sh_spi_write(sh_spi_read(®s->cr1) & ~SH_SPI_SSA, ®s->cr1);
>
> if (tx_data)
> - ret = sh_spi_send(ss, tx_data, len, flags);
> + ret = sh_spi_send(regs, tx_data, len, flags);
>
> if (ret == 0 && rx_data)
> - ret = sh_spi_receive(ss, rx_data, len, flags);
> + ret = sh_spi_receive(regs, rx_data, len, flags);
>
> if (flags & SPI_XFER_END) {
> - sh_spi_set_bit(SH_SPI_SSD, &ss->regs->cr1);
> + sh_spi_set_bit(SH_SPI_SSD, ®s->cr1);
> udelay(100);
>
> sh_spi_clear_bit(SH_SPI_SSA | SH_SPI_SSDB | SH_SPI_SSD,
> - &ss->regs->cr1);
> - clear_fifo(ss);
> + ®s->cr1);
> + clear_fifo(regs);
> }
>
> return ret;
> }
>
> -int spi_cs_is_valid(unsigned int bus, unsigned int cs)
> +static int sh_spi_probe(struct udevice *bus)
> {
> - if (!bus && cs < SH_SPI_NUM_CS)
> - return 1;
> - else
> - return 0;
> -}
> + struct sh_spi_priv *priv = dev_get_priv(bus);
> + struct sh_spi_regs *regs = priv->regs;
>
> -void spi_cs_activate(struct spi_slave *slave)
> -{
> + __spi_setup(regs, priv->cs);
Don't use another function, do it like old code.
>
> + return 0;
> }
>
> -void spi_cs_deactivate(struct spi_slave *slave)
> +#if CONFIG_IS_ENABLED(OF_CONTROL)
> +static int sh_spi_ofdata_to_platadata(struct udevice *bus)
> {
> + struct sh_spi_platdata *plat = bus->platdata;
> + struct sh_spi_priv *priv = dev_get_priv(bus);
> + fdt_addr_t addr;
> +
> + addr = devfdt_get_addr(bus);
> + if (addr == FDT_ADDR_T_NONE)
> + return -EINVAL;
Missing plat->regs?
> +
> + plat->cs = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus),
> + "num-cs", 4);
>
> + return 0;
> }
> +
> +static const struct dm_spi_ops mvebu_spi_ops = {
> + .release_bus = sh_spi_release_bus,
> + .xfer = sh_spi_xfer,
> + .set_speed = sh_spi_set_speed,
> + .set_mode = sh_spi_set_mode,
> +};
> +
> +static const struct udevice_id sh_spi_ids[] = {
> + { .compatible = "sh,sh_spi" },
Same like sh_qspi we need to use proper/existing binding from Linux.
> +};
> +#endif
> +
> +U_BOOT_DRIVER(sh_spi) = {
> + .name = "sh_spi",
> + .id = UCLASS_SPI,
> +#if CONFIG_IS_ENABLED(OF_CONTROL)
> + .of_match = sh_spi_ids,
> + .ofdata_to_platdata = sh_spi_ofdata_to_platadata,
> + .platdata_auto_alloc_size = sizeof(struct sh_spi_platdata),
> +#endif
> + .priv_auto_alloc_size = sizeof(struct sh_spi_priv),
> + .probe = sh_spi_probe,
> + .ops = &sh_spi_ops,
> +};
> diff --git a/drivers/spi/sh_spi.h b/drivers/spi/sh_spi.h
> index a0e949f..87a253f 100644
> --- a/drivers/spi/sh_spi.h
> +++ b/drivers/spi/sh_spi.h
> @@ -55,8 +55,7 @@ struct sh_spi_regs {
> #define SH_SPI_FIFO_SIZE 32
> #define SH_SPI_NUM_CS 4
>
> -struct sh_spi {
> - struct spi_slave slave;
> +struct sh_spi_priv {
> struct sh_spi_regs *regs;
> };
Move this header code into .c file and drop sh_spi_priv just retrive
regs using plat->regs anywhere in the code.
>
> diff --git a/include/dm/platform_data/spi_sh.h b/include/dm/platform_data/spi_sh.h
> new file mode 100644
> index 0000000..b4d63dc
> --- /dev/null
> +++ b/include/dm/platform_data/spi_sh.h
> @@ -0,0 +1,20 @@
> +/*
> + * Copyright (C) 2018 Akash Gajjar <akash at openedev.com>
> + *
> + * SPDX-License-Identifier: GPL-2.0+
> + *
no space require.
> + */
> +
> +#ifndef __spi_sh_h
> +#define __spi_sh_h
> +
> +/*
> + * struct sh_spi_platdata - information about a sh spi module
> + *
> + */
no need of these comments.
Jagan.
--
Jagan Teki
Free Software Engineer | www.openedev.com
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.
More information about the U-Boot
mailing list