Hi Jagan, I am sorry for late answer.
> -----Original Message----- > From: U-Boot [mailto:u-boot-boun...@lists.denx.de] On Behalf Of Jagan Teki > Sent: 2016年9月21日 16:24 > To: Wenyou Yang <wenyou.y...@atmel.com> > Cc: U-Boot Mailing List <u-boot@lists.denx.de>; Stephen Warren > <swar...@nvidia.com> > Subject: Re: [U-Boot] [PATCH v10] dm: at91: Add driver model support for the > spi > driver > > On Sun, Sep 18, 2016 at 12:28 PM, Wenyou Yang <wenyou.y...@atmel.com> > wrote: > > Add driver model support while retaining the existing legacy code. > > This allows the driver to support boards that have converted to driver > > model as well as those that have not. > > > > Signed-off-by: Wenyou Yang <wenyou.y...@atmel.com> > > Reviewed-by: Simon Glass <s...@chromium.org> > > Acked-by: Stephen Warren <swar...@nvidia.com> > > --- > > > > Changes in v10: > > - Add Acked-by tag. > > > > Changes in v9: > > - Due to the peripheral clock driver improvement, remove the > > unneccessary clock calling. > > > > Changes in v8: > > - Fix compile error for AVR32. > > > > Changes in v7: > > - Move gpio_request_list_by_name() to _probe(), remove > > *_ofdata_to_platdata(). > > > > Changes in v6: > > - Remove the two flash related options. > > > > Changes in v5: > > - Change clk_client.h -> clk.h to adapt to clk API conversion. > > > > Changes in v4: > > - Collect Reviewed-by tag. > > - Update the clk API based on [PATCH] clk: convert API to match > > reset/mailbox fstyle (http://patchwork.ozlabs.org/patch/625342/). > > - Remove check on dev_get_parent() return. > > - Fixed the return value, -ENODEV->-EINVAL. > > - Retain #include <asm/arch/clk.h> line. > > > > Changes in v3: > > - Remove redundant log print. > > > > Changes in v2: > > - Add clock support. > > > > drivers/spi/Kconfig | 7 ++ > > drivers/spi/atmel_spi.c | 283 > > ++++++++++++++++++++++++++++++++++++++++++++++++ > > 2 files changed, 290 insertions(+) > > > > diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index > > aca385d..16ed231 100644 > > --- a/drivers/spi/Kconfig > > +++ b/drivers/spi/Kconfig > > @@ -32,6 +32,13 @@ config ATH79_SPI > > uses driver model and requires a device tree binding to operate. > > please refer to doc/device-tree-bindings/spi/spi-ath79.txt. > > > > +config ATMEL_SPI > > + bool "Atmel SPI driver" > > + depends on ARCH_AT91 > > + help > > + Enable the Atmel SPI driver. This driver can be used to access > > + the SPI Flash, such as AT25DF321. > > + > > config CADENCE_QSPI > > bool "Cadence QSPI driver" > > help > > diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index > > ed6278b..190f58b 100644 > > --- a/drivers/spi/atmel_spi.c > > +++ b/drivers/spi/atmel_spi.c > > @@ -4,6 +4,9 @@ > > * SPDX-License-Identifier: GPL-2.0+ > > */ > > #include <common.h> > > +#include <clk.h> > > +#include <dm.h> > > +#include <fdtdec.h> > > #include <spi.h> > > #include <malloc.h> > > > > @@ -11,9 +14,19 @@ > > > > #include <asm/arch/clk.h> > > #include <asm/arch/hardware.h> > > +#ifdef CONFIG_DM_SPI > > +#include <asm/arch/at91_spi.h> > > +#endif > > +#ifdef CONFIG_DM_GPIO > > +#include <asm/gpio.h> > > +#endif > > > > #include "atmel_spi.h" > > > > +DECLARE_GLOBAL_DATA_PTR; > > + > > +#ifndef CONFIG_DM_SPI > > + > > static int spi_has_wdrbt(struct atmel_spi_slave *slave) { > > unsigned int ver; > > @@ -209,3 +222,273 @@ out: > > > > return 0; > > } > > + > > +#else > > + > > +#define MAX_CS_COUNT 4 > > + > > +struct atmel_spi_platdata { > > + struct at91_spi *regs; > > +}; > > + > > +struct atmel_spi_priv { > > + unsigned int freq; /* Default frequency */ > > + unsigned int mode; > > + ulong bus_clk_rate; > > + struct gpio_desc cs_gpios[MAX_CS_COUNT]; }; > > + > > +static int atmel_spi_claim_bus(struct udevice *dev) { > > + struct udevice *bus = dev_get_parent(dev); > > + struct atmel_spi_platdata *bus_plat = dev_get_platdata(bus); > > + struct atmel_spi_priv *priv = dev_get_priv(bus); > > + struct dm_spi_slave_platdata *slave_plat = > > dev_get_parent_platdata(dev); > > + struct at91_spi *reg_base = bus_plat->regs; > > + u32 cs = slave_plat->cs; > > + u32 freq = priv->freq; > > + u32 scbr, csrx, mode; > > + > > + scbr = (priv->bus_clk_rate + freq - 1) / freq; > > + if (scbr > ATMEL_SPI_CSRx_SCBR_MAX) > > + return -EINVAL; > > + > > + if (scbr < 1) > > + scbr = 1; > > + > > + csrx = ATMEL_SPI_CSRx_SCBR(scbr); > > + csrx |= ATMEL_SPI_CSRx_BITS(ATMEL_SPI_BITS_8); > > + > > + if (!(priv->mode & SPI_CPHA)) > > + csrx |= ATMEL_SPI_CSRx_NCPHA; > > + if (priv->mode & SPI_CPOL) > > + csrx |= ATMEL_SPI_CSRx_CPOL; > > + > > + writel(csrx, ®_base->csr[cs]); > > + > > + mode = ATMEL_SPI_MR_MSTR | > > + ATMEL_SPI_MR_MODFDIS | > > + ATMEL_SPI_MR_WDRBT | > > + ATMEL_SPI_MR_PCS(~(1 << cs)); > > + > > + writel(mode, ®_base->mr); > > Usually this mode and speed stuff should go on respetcive fops. Since we > couldn't > find the cs number on those fops you wrote these here, correct? can you tried > to > add .cs_info see we can get the cs number so-that these will move, becuase > claim bus usually enable the spi instead of doing mode and speed stuff. > I looked through the code, try to add .cs_info as your advice. But failed. Could you give me more information? Thank you. > > + > > + writel(ATMEL_SPI_CR_SPIEN, ®_base->cr); > > This is correct. > > > + > > + return 0; > > +} > > + > > +static int atmel_spi_release_bus(struct udevice *dev) { > > + struct udevice *bus = dev_get_parent(dev); > > + struct atmel_spi_platdata *bus_plat = dev_get_platdata(bus); > > + > > + writel(ATMEL_SPI_CR_SPIDIS, &bus_plat->regs->cr); > > + > > + return 0; > > +} > > + > > +static void atmel_spi_cs_activate(struct udevice *dev) { > > + struct udevice *bus = dev_get_parent(dev); > > + struct atmel_spi_priv *priv = dev_get_priv(bus); > > + struct dm_spi_slave_platdata *slave_plat = > > dev_get_parent_platdata(dev); > > + u32 cs = slave_plat->cs; > > + > > + dm_gpio_set_value(&priv->cs_gpios[cs], 0); } > > + > > +static void atmel_spi_cs_deactivate(struct udevice *dev) { > > + struct udevice *bus = dev_get_parent(dev); > > + struct atmel_spi_priv *priv = dev_get_priv(bus); > > + struct dm_spi_slave_platdata *slave_plat = > > dev_get_parent_platdata(dev); > > + u32 cs = slave_plat->cs; > > + > > + dm_gpio_set_value(&priv->cs_gpios[cs], 1); } > > + > > +static int atmel_spi_xfer(struct udevice *dev, unsigned int bitlen, > > + const void *dout, void *din, unsigned long > > +flags) { > > + struct udevice *bus = dev_get_parent(dev); > > + struct atmel_spi_platdata *bus_plat = dev_get_platdata(bus); > > + struct at91_spi *reg_base = bus_plat->regs; > > + > > + u32 len_tx, len_rx, len; > > + u32 status; > > + const u8 *txp = dout; > > + u8 *rxp = din; > > + u8 value; > > + > > + if (bitlen == 0) > > + goto out; > > + > > + /* > > + * The controller can do non-multiple-of-8 bit > > + * transfers, but this driver currently doesn't support it. > > + * > > + * It's also not clear how such transfers are supposed to be > > + * represented as a stream of bytes...this is a limitation of > > + * the current SPI interface. > > + */ > > + if (bitlen % 8) { > > + /* Errors always terminate an ongoing transfer */ > > + flags |= SPI_XFER_END; > > + goto out; > > + } > > + > > + len = bitlen / 8; > > + > > + /* > > + * The controller can do automatic CS control, but it is > > + * somewhat quirky, and it doesn't really buy us much anyway > > + * in the context of U-Boot. > > + */ > > + if (flags & SPI_XFER_BEGIN) { > > + atmel_spi_cs_activate(dev); > > + > > + /* > > + * sometimes the RDR is not empty when we get here, > > + * in theory that should not happen, but it DOES happen. > > + * Read it here to be on the safe side. > > + * That also clears the OVRES flag. Required if the > > + * following loop exits due to OVRES! > > + */ > > + readl(®_base->rdr); > > + } > > + > > + for (len_tx = 0, len_rx = 0; len_rx < len; ) { > > + status = readl(®_base->sr); > > + > > + if (status & ATMEL_SPI_SR_OVRES) > > + return -1; > > + > > + if ((len_tx < len) && (status & ATMEL_SPI_SR_TDRE)) { > > + if (txp) > > + value = *txp++; > > + else > > + value = 0; > > + writel(value, ®_base->tdr); > > + len_tx++; > > + } > > + > > + if (status & ATMEL_SPI_SR_RDRF) { > > + value = readl(®_base->rdr); > > + if (rxp) > > + *rxp++ = value; > > + len_rx++; > > + } > > + } > > + > > +out: > > + if (flags & SPI_XFER_END) { > > + /* > > + * Wait until the transfer is completely done before > > + * we deactivate CS. > > + */ > > + do { > > + status = readl(®_base->sr); > > + } while (!(status & ATMEL_SPI_SR_TXEMPTY)); > > Use wait_for_bit. Accepted. Best Regards, Wenyou Yang _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot