Message ID | 574D5C2B.1000400@gtsys.com.hk (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
[Adding Sascha and Anton in Cc] On Tue, May 31, 2016 at 6:40 AM, Chris Ruehl <chris.ruehl@gtsys.com.hk> 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@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tue, May 31, 2016 at 07:43:37AM -0300, Fabio Estevam wrote: > [Adding Sascha and Anton in Cc] > > On Tue, May 31, 2016 at 6:40 AM, Chris Ruehl <chris.ruehl@gtsys.com.hk> 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. I generally recommend to use GPIO Chip selects. The SPI controller has its own ideas when to assert the chipselects which is hard to match (if possible at all) with what Linux SPI expects. See the cs-gpios device tree property. Sascha
On 31.05.2016 12:40, Chris Ruehl 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 - Do you use PIO or DMA transfer mode? The problem description resembles a known issue within SDMA firmware (referenced as TKT238285 or ERR008517) and you should not be able to face it, if SPI controller operates in PIO mode. -- With best wishes, Vladimir -- To unsubscribe from this list: send the line "unsubscribe linux-spi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tue, May 31, 2016 at 05:40:59PM +0800, Chris Ruehl 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. Please submit patches in the format covered in SubmittingPatches, I can't take anything without a Signed-off-by.
On Tuesday, May 31, 2016 07:20 PM, Vladimir Zapolskiy wrote: > On 31.05.2016 12:40, Chris Ruehl 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 - > > Do you use PIO or DMA transfer mode? The problem description resembles > a known issue within SDMA firmware (referenced as TKT238285 or ERR008517) > and you should not be able to face it, if SPI controller operates in PIO > mode. Board is a imx6d and its runs in DMA mode. I have the MPL115A working properly when I keep an eye on even numbers of bytes in a transfer (which is always the case in a half duplex mode <cmd><00>..) But any how thanks for this interesting info! Chris -- To unsubscribe from this list: send the line "unsubscribe linux-spi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tuesday, May 31, 2016 07:06 PM, Sascha Hauer wrote: > On Tue, May 31, 2016 at 07:43:37AM -0300, Fabio Estevam wrote: >> [Adding Sascha and Anton in Cc] >> >> On Tue, May 31, 2016 at 6:40 AM, Chris Ruehl <chris.ruehl@gtsys.com.hk> 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. > > I generally recommend to use GPIO Chip selects. The SPI controller has > its own ideas when to assert the chipselects which is hard to match (if > possible at all) with what Linux SPI expects. See the cs-gpios device > tree property. > > Sascha Sascha that's a good approach to fight this problem, if you have the choice. Sadly my hardware design is finished and I can only switch to a gpio by run wires on the finished PCB.. and that's not what I want. With the single burst mode patch, the logic analyser shows a very nice and and clean and accurate chipselect clock MOSI and MISO. Chris -- To unsubscribe from this list: send the line "unsubscribe linux-spi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Mark, On Tuesday, May 31, 2016 09:08 PM, Mark Brown wrote: > On Tue, May 31, 2016 at 05:40:59PM +0800, Chris Ruehl 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. > > Please submit patches in the format covered in SubmittingPatches, I > can't take anything without a Signed-off-by. > Thanks, I will do submit an 'offical" patch with the input's from the ongoing discussion. I'm on a change enable the single-burst-mode let the cs_change alone. I set a mask in the bit_per_word to enable it, which keeps changes in the spi-imx.c only. Chris -- To unsubscribe from this list: send the line "unsubscribe linux-spi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Wed, Jun 01, 2016 at 09:54:39AM +0800, Chris Ruehl wrote: > On Tuesday, May 31, 2016 07:06 PM, Sascha Hauer wrote: > >On Tue, May 31, 2016 at 07:43:37AM -0300, Fabio Estevam wrote: > >>[Adding Sascha and Anton in Cc] > >> > >>On Tue, May 31, 2016 at 6:40 AM, Chris Ruehl <chris.ruehl@gtsys.com.hk> 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. > > > >I generally recommend to use GPIO Chip selects. The SPI controller has > >its own ideas when to assert the chipselects which is hard to match (if > >possible at all) with what Linux SPI expects. See the cs-gpios device > >tree property. > > > >Sascha > > Sascha that's a good approach to fight this problem, if you have the > choice. Sadly my hardware design is finished and I can only switch to > a gpio by run wires on the finished PCB.. and that's not what I want. I'm not suggesting to change your hardware. Every chipselect pin can be configured as GPIO aswell, i.e. exchange MX6QDL_PAD_DISP0_DAT3__ECSPI3_SS0 with MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 and be done with it. Sascha
On Wednesday, June 01, 2016 02:30 PM, Sascha Hauer wrote: > On Wed, Jun 01, 2016 at 09:54:39AM +0800, Chris Ruehl wrote: >> On Tuesday, May 31, 2016 07:06 PM, Sascha Hauer wrote: >>> On Tue, May 31, 2016 at 07:43:37AM -0300, Fabio Estevam wrote: >>>> [Adding Sascha and Anton in Cc] >>>> >>>> On Tue, May 31, 2016 at 6:40 AM, Chris Ruehl <chris.ruehl@gtsys.com.hk> 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. >>> >>> I generally recommend to use GPIO Chip selects. The SPI controller has >>> its own ideas when to assert the chipselects which is hard to match (if >>> possible at all) with what Linux SPI expects. See the cs-gpios device >>> tree property. >>> >>> Sascha >> >> Sascha that's a good approach to fight this problem, if you have the >> choice. Sadly my hardware design is finished and I can only switch to >> a gpio by run wires on the finished PCB.. and that's not what I want. > > I'm not suggesting to change your hardware. Every chipselect pin can be > configured as GPIO aswell, i.e. exchange > MX6QDL_PAD_DISP0_DAT3__ECSPI3_SS0 with MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 > and be done with it. > > Sascha > Hi Sascha, yes, :) agree. But my native chip select with single burst is doing the job flawless now. Chris -- To unsubscribe from this list: send the line "unsubscribe linux-spi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
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)