[Adding Sascha and Anton in Cc] On Tue, May 31, 2016 at 6:40 AM, Chris Ruehl <chris.ruehl@xxxxxxxxxxxx> wrote: > Hi, > > as imx6 using multiple burst to send data to spi slaves and drop the > chipselect between the words by default my sensor NXP MPL115A1 wasn't > working. > The hint comes from a discussion in the Freescale forum from 2013 where Jeff > Coffman posted his solution for a 3.x kernel. > I'd pick-up the idea behind and develop something which works "so far" with > 4.6 and linux-next > > Up front - I'm not happy using the xfer->cs_change to get set the single > burst > I more likely want add a new xfer bit which allow to dedicated set a single > burst. > To replace todays: > xfer[0].cs_change = 0; > with a > xfer[0].singleburst = 1; > > An other issue with is not yet solved; when I have a odd number of bytes (8 > bpw) in a transfer, its result in 3 bytes eaten on the start and 0x00 added > on the tail - > > Single file patch - something to view. > > Patch v0: add support for imx6 single burst mode. > > diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c > index 50769078..3440d0e 100644 > --- a/drivers/spi/spi-imx.c > +++ b/drivers/spi/spi-imx.c > @@ -60,6 +60,8 @@ struct spi_imx_config { > unsigned int speed_hz; > unsigned int bpw; > unsigned int mode; > + unsigned int len; > + unsigned int single_burst_mode:1; > u8 cs; > }; > > @@ -99,11 +101,13 @@ struct spi_imx_data { > unsigned int bytes_per_word; > > unsigned int count; > + unsigned int rxcount; > void (*tx)(struct spi_imx_data *); > void (*rx)(struct spi_imx_data *); > void *rx_buf; > const void *tx_buf; > unsigned int txfifo; /* number of words pushed in tx FIFO */ > + u8 bits_per_word; > > /* DMA */ > bool usedma; > @@ -168,6 +172,191 @@ MXC_SPI_BUF_TX(u16) > MXC_SPI_BUF_RX(u32) > MXC_SPI_BUF_TX(u32) > > +static void spi_imx_buf_rx_sb(struct spi_imx_data *spi_imx) > +{ > + unsigned int val = readl(spi_imx->base + MXC_CSPIRXDATA); > + dev_dbg(spi_imx->dev, "%s: rxcount: %u val:0x%08x\n", > + __func__, spi_imx->rxcount , val); > + if (spi_imx->rxcount>=4) { > + if (spi_imx->rx_buf) { > + if (spi_imx->bits_per_word==32) { > + spi_imx_buf_rx_u32(spi_imx); > + } else if (spi_imx->bits_per_word==16) { > + *(u16 *)spi_imx->rx_buf = (val>>16); > + spi_imx->rx_buf += sizeof(u16); > + *(u16 *)spi_imx->rx_buf = val; > + spi_imx->rx_buf += sizeof(u16); > + } else { > + *(u8 *)spi_imx->rx_buf = (val>>24); > + spi_imx->rx_buf += sizeof(u8); > + *(u8 *)spi_imx->rx_buf = (val>>16); > + spi_imx->rx_buf += sizeof(u8); > + *(u8 *)spi_imx->rx_buf = (val>>8); > + spi_imx->rx_buf += sizeof(u8); > + *(u8 *)spi_imx->rx_buf = val; > + spi_imx->rx_buf += sizeof(u8); > + } > + } > + spi_imx->rxcount-=4; > + } > + else if (spi_imx->rxcount==3) { > + if (spi_imx->rx_buf) { > + if (spi_imx->bits_per_word==32) { > + *(u8 *)spi_imx->rx_buf = val>>24; > + spi_imx->rx_buf += sizeof(u8); > + *(u8 *)spi_imx->rx_buf = val>>16; > + spi_imx->rx_buf += sizeof(u8); > + *(u8 *)spi_imx->rx_buf = val>>8; > + spi_imx->rx_buf += sizeof(u8); > + } else if (spi_imx->bits_per_word==16) { > + *(u16 *)spi_imx->rx_buf = (val>>16); > + spi_imx->rx_buf += sizeof(u16); > + *(u8 *)spi_imx->rx_buf = val>>8; > + spi_imx->rx_buf += sizeof(u8); > + } else { > + *(u8 *)spi_imx->rx_buf = (val>>16); > + spi_imx->rx_buf += sizeof(u8); > + *(u8 *)spi_imx->rx_buf = (val>>8); > + spi_imx->rx_buf += sizeof(u8); > + *(u8 *)spi_imx->rx_buf = val; > + spi_imx->rx_buf += sizeof(u8); > + } > + } > + spi_imx->rxcount-=3; > + } > + else if (spi_imx->rxcount==2) { > + if (spi_imx->rx_buf) { > + if (spi_imx->bits_per_word==32) { > + *(u8 *)spi_imx->rx_buf = val>>24; > + spi_imx->rx_buf += sizeof(u8); > + *(u8 *)spi_imx->rx_buf = val>>16; > + spi_imx->rx_buf += sizeof(u8); > + } else if (spi_imx->bits_per_word==16) { > + spi_imx_buf_rx_u16(spi_imx); > + } else { > + *(u8 *)spi_imx->rx_buf = (val>>8); > + spi_imx->rx_buf += sizeof(u8); > + *(u8 *)spi_imx->rx_buf = val; > + spi_imx->rx_buf += sizeof(u8); > + } > + } > + spi_imx->rxcount-=2; > + } > + else if (spi_imx->rxcount==1) { > + if (spi_imx->rx_buf) { > + if (spi_imx->bits_per_word==32) { > + *(u8 *)spi_imx->rx_buf = val>>24; > + } else if (spi_imx->bits_per_word==16) { > + *(u8 *)spi_imx->rx_buf = val>>8; > + } else { > + spi_imx_buf_rx_u8(spi_imx); > + } > + } > + spi_imx->rxcount-=1; > + } > +} > + > +static void spi_imx_buf_tx_sb(struct spi_imx_data *spi_imx) > +{ > + unsigned int val = 0; > + dev_dbg(spi_imx->dev, "%s: txcount: %u ptr:0x%08x\n", > + __func__, spi_imx->count ,*(u32 *)spi_imx->tx_buf); > + if (spi_imx->count>=4) { > + if (spi_imx->bits_per_word==32) { > + spi_imx_buf_tx_u32(spi_imx); > + } else { > + if (spi_imx->tx_buf) { > + if (spi_imx->bits_per_word==16) { > + val = *(u16 *)spi_imx->tx_buf<<16; > + spi_imx->tx_buf += sizeof(u16); > + val |= *(u16 *)spi_imx->tx_buf; > + spi_imx->tx_buf += sizeof(u16); > + } else { > + val = *(u8 *)spi_imx->tx_buf<<24; > + spi_imx->tx_buf += sizeof(u8); > + val |= *(u8 *)spi_imx->tx_buf<<16; > + spi_imx->tx_buf += sizeof(u8); > + val |= *(u8 *)spi_imx->tx_buf<<8; > + spi_imx->tx_buf += sizeof(u8); > + val |= *(u8 *)spi_imx->tx_buf; > + spi_imx->tx_buf += sizeof(u8); > + } > + writel(val, spi_imx->base + MXC_CSPITXDATA); > + } > + spi_imx->count -= 4; > + } > + } > + else if (spi_imx->count==3) { > + if (spi_imx->tx_buf) { > + if (spi_imx->bits_per_word==32) { > + val = *(u8 *)spi_imx->tx_buf<<24; > + spi_imx->tx_buf += sizeof(u8); > + val |= *(u8 *)spi_imx->tx_buf<<16; > + spi_imx->tx_buf += sizeof(u8); > + val |= *(u8 *)spi_imx->tx_buf<<8; > + spi_imx->tx_buf += sizeof(u8); > + > + } else if (spi_imx->bits_per_word==16) { > + val = *(u8 *)spi_imx->tx_buf<<24; > + spi_imx->tx_buf += sizeof(u8); > + val |= *(u8 *)spi_imx->tx_buf<<16; > + spi_imx->tx_buf += sizeof(u8); > + val |= *(u8 *)spi_imx->tx_buf; > + spi_imx->tx_buf += sizeof(u8); > + > + } else { > + val = *(u8 *)spi_imx->tx_buf<<16; > + spi_imx->tx_buf += sizeof(u8); > + val |= *(u8 *)spi_imx->tx_buf<<8; > + spi_imx->tx_buf += sizeof(u8); > + val |= *(u8 *)spi_imx->tx_buf; > + spi_imx->tx_buf += sizeof(u8); > + } > + writel(val, spi_imx->base + MXC_CSPITXDATA); > + } > + spi_imx->count -= 3; > + } > + else if (spi_imx->count==2) { > + if (spi_imx->bits_per_word==16) { > + spi_imx_buf_tx_u16(spi_imx); > + } else { > + if (spi_imx->tx_buf) { > + if (spi_imx->bits_per_word==32) { > + val = *(u8 *)spi_imx->tx_buf<<24; > + spi_imx->tx_buf += sizeof(u8); > + val |= *(u8 *)spi_imx->tx_buf<<16; > + spi_imx->tx_buf += sizeof(u8); > + } else { > + val = *(u8 *)spi_imx->tx_buf<<8; > + spi_imx->tx_buf += sizeof(u8); > + val |= *(u8 *)spi_imx->tx_buf; > + spi_imx->tx_buf += sizeof(u8); > + } > + writel(val, spi_imx->base + MXC_CSPITXDATA); > + } > + spi_imx->count -= 2; > + } > + } > + else if (spi_imx->count==1) { > + if (spi_imx->bits_per_word==8){ > + spi_imx_buf_tx_u8(spi_imx); > + } else { > + if (spi_imx->tx_buf) { > + if (spi_imx->bits_per_word==32) { > + val = *(u8 *)spi_imx->tx_buf<<24; > + spi_imx->tx_buf += sizeof(u8); > + } else if (spi_imx->bits_per_word==16) { > + val = *(u8 *)spi_imx->tx_buf<<8; > + spi_imx->tx_buf += sizeof(u8); > + } > + writel(val, spi_imx->base + MXC_CSPITXDATA); > + } > + spi_imx->count -= 1; > + } > + } > +} > + > + > /* First entry is reserved, second entry is valid only if SDHC_SPIEN is set > * (which is currently not the case in this driver) > */ > @@ -357,9 +546,49 @@ static int __maybe_unused mx51_ecspi_config(struct > spi_imx_data *spi_imx, > /* set chip select to use */ > ctrl |= MX51_ECSPI_CTRL_CS(config->cs); > > - ctrl |= (config->bpw - 1) << MX51_ECSPI_CTRL_BL_OFFSET; > + /* set single/multible burst parameters */ > + if (config->single_burst_mode>0) { > + reg = 0; > + spi_imx->rx = spi_imx_buf_rx_sb; > + spi_imx->tx = spi_imx_buf_tx_sb; > + spi_imx->rxcount = config->len; > + spi_imx->bits_per_word = config->bpw; > + > + /* calculate the Burst Length, > + refer to 21.7.3 Control Register (ECSPIx_CONREG) > + for details. > + */ > + switch (config->len%4) > + { > + case 1: > + ctrl |= 7 << MX51_ECSPI_CTRL_BL_OFFSET; > + reg = (config->len-1) / 4; > + break; > + case 2: > + ctrl |= 15 << MX51_ECSPI_CTRL_BL_OFFSET; > + reg = (config->len-2) / 4; > + break; > + case 3: > + ctrl |= 23 << MX51_ECSPI_CTRL_BL_OFFSET; > + reg = (config->len-3) / 4; > + break; > + case 0: > + ctrl |= 31 << MX51_ECSPI_CTRL_BL_OFFSET; > + reg = (config->len-4) / 4; > + break; > + } > + > + if (reg>0) > + ctrl |= reg << (MX51_ECSPI_CTRL_BL_OFFSET + 5); > > - cfg |= MX51_ECSPI_CONFIG_SBBCTRL(config->cs); > + cfg &= ~(MX51_ECSPI_CONFIG_SBBCTRL(config->cs)); > + > + dev_dbg(spi_imx->dev, "Single Burst reg:0x%08x cfg:0x%08x > ctrl:0x%08x\n" > + , reg, cfg, ctrl); > + } else { > + ctrl |= (config->bpw - 1) << MX51_ECSPI_CTRL_BL_OFFSET; > + cfg |= MX51_ECSPI_CONFIG_SBBCTRL(config->cs); > + } > > if (config->mode & SPI_CPHA) > cfg |= MX51_ECSPI_CONFIG_SCLKPHA(config->cs); > @@ -861,6 +1090,8 @@ static int spi_imx_setupxfer(struct spi_device *spi, > config.speed_hz = t ? t->speed_hz : spi->max_speed_hz; > config.mode = spi->mode; > config.cs = spi->chip_select; > + config.len = t->len; > + config.single_burst_mode = ~(t->cs_change); > > if (!config.speed_hz) > config.speed_hz = spi->max_speed_hz; > > > > > > Regards > Chris > > -- > GTSYS Limited RFID Technology > 9/F, Unit E, R07, Kwai Shing Industrial Building Phase 2, > 42-46 Tai Lin Pai Road, Kwai Chung, N.T., Hong Kong > Tel (852) 9079 9521 > > Disclaimer: http://www.gtsys.com.hk/email/classified.html -- To unsubscribe from this list: send the line "unsubscribe linux-spi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html