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 <vigne...@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 > -- Regards Vignesh _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot