diff mbox

spi-imx: imx6q add single burst transfer support

Message ID 1464756628-25463-1-git-send-email-chris.ruehl@gtsys.com.hk (mailing list archive)
State New, archived
Headers show

Commit Message

Chris Ruehl June 1, 2016, 4:50 a.m. UTC
The patch add support for single burst transfer where chipselect will
hold active until transfer completes with a limit to 2^7 words transferred.
The single-burst-mode need set the burstlength in ECSPI_CONREG.BURST_LENGTH
and clear the ecspi channel related ss_ctl flag in ECSPI_CONFIGREG.SS_CTL.

The single-burst-mode is disabled by default. The activation from spidev
is implemented by set bit0 of the xfer.speed_hz, which don't break anything
in the mx51_ecspi_clkdiv() function.

xfer[0].speed_hz = 2000000 | 0x1; /* enable single burst mode with 1hz */

There is a bug in the SDMA firmware (referenced as TKT238285 or ERR008517)
which breaks the transmission with a odd numbers of bytes.
Its turns out, that its safe to use with slaves in half duplex mode where
always an even number of bytes is required.

function added:
spi_imx_buf_tx_sb()  - singleburst transmit
spi_imx_buf_rx_sb()  - singleburst receive

stucts modified:
spi_imx_config - add len ; add single_burst_mode:1
spi_imx_data   - add rxcount; add bits_per_word

Signed-off-by: Chris Ruehl <chris.ruehl@gtsys.com.hk>
---
 drivers/spi/spi-imx.c | 233 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 231 insertions(+), 2 deletions(-)

Comments

Chris Ruehl June 1, 2016, 5:06 a.m. UTC | #1
On Wednesday, June 01, 2016 12:50 PM, Chris Ruehl wrote:
> The patch add support for single burst transfer where chipselect will
> hold active until transfer completes with a limit to 2^7 words transferred.
> The single-burst-mode need set the burstlength in ECSPI_CONREG.BURST_LENGTH
> and clear the ecspi channel related ss_ctl flag in ECSPI_CONFIGREG.SS_CTL.
>
> The single-burst-mode is disabled by default. The activation from spidev
> is implemented by set bit0 of the xfer.speed_hz, which don't break anything
> in the mx51_ecspi_clkdiv() function.
>
> xfer[0].speed_hz = 2000000 | 0x1; /* enable single burst mode with 1hz */
>
> There is a bug in the SDMA firmware (referenced as TKT238285 or ERR008517)
> which breaks the transmission with a odd numbers of bytes.
> Its turns out, that its safe to use with slaves in half duplex mode where
> always an even number of bytes is required.
>
> function added:
> spi_imx_buf_tx_sb()  - singleburst transmit
> spi_imx_buf_rx_sb()  - singleburst receive
>
> stucts modified:
> spi_imx_config - add len ; add single_burst_mode:1
> spi_imx_data   - add rxcount; add bits_per_word
>
> Signed-off-by: Chris Ruehl <chris.ruehl@gtsys.com.hk>

User Space program - sensor MPL115A1 in sb-mode
-----------------
16 	>> "88008a008c008e009000920094009600"
16 	<< "003d007100b500c300c2004100350010"
2 	>> "2400"
2 	<< "0000"
8 	>> "8000820084008600"
8 	<< "005f0040006d0040"
Pres ADC: 381
Temp ADC: 437
a0: 1966.12
b1: -2.31995
b2: -0.964783
c12: 0.000809669
Pcomp: 795.423
Pressure:  100.54 kPa


Kernel debug
------------
[ 1065.586066] spi_imx 200c000.ecspi: Single Burst reg:0x00000003 cfg:0x00000000 
ctrl:0x07f0e1f1
[ 1065.586088] spi_imx 200c000.ecspi: spi_imx_buf_tx_sb: txcount: 16 ptr:0x008a0088
[ 1065.586105] spi_imx 200c000.ecspi: spi_imx_buf_tx_sb: txcount: 12 ptr:0x008e008c
[ 1065.586119] spi_imx 200c000.ecspi: spi_imx_buf_tx_sb: txcount: 8 ptr:0x00920090
[ 1065.586133] spi_imx 200c000.ecspi: spi_imx_buf_tx_sb: txcount: 4 ptr:0x00960094
[ 1065.586209] spi_imx 200c000.ecspi: spi_imx_buf_rx_sb: rxcount: 16 val:0x003d0071
[ 1065.586227] spi_imx 200c000.ecspi: spi_imx_buf_rx_sb: rxcount: 12 val:0x00b500c3
[ 1065.586242] spi_imx 200c000.ecspi: spi_imx_buf_rx_sb: rxcount: 8 val:0x00c20041
[ 1065.586256] spi_imx 200c000.ecspi: spi_imx_buf_rx_sb: rxcount: 4 val:0x00350010

[ 1065.593173] spi_imx 200c000.ecspi: mx51_ecspi_clkdiv: fin: 60000000, fspi: 
2000001, post: 1, pre: 14
[ 1065.593195] spi_imx 200c000.ecspi: Single Burst reg:0x00000000 cfg:0x00000000 
ctrl:0x00f0e1f1
[ 1065.593216] spi_imx 200c000.ecspi: spi_imx_buf_tx_sb: txcount: 2 ptr:0x008a0024
[ 1065.593248] spi_imx 200c000.ecspi: spi_imx_buf_rx_sb: rxcount: 2 val:0x00000000

[ 1065.604517] spi_imx 200c000.ecspi: mx51_ecspi_clkdiv: fin: 60000000, fspi: 
2000001, post: 1, pre: 14
[ 1065.604539] spi_imx 200c000.ecspi: Single Burst reg:0x00000001 cfg:0x00000000 
ctrl:0x03f0e1f1
[ 1065.604559] spi_imx 200c000.ecspi: spi_imx_buf_tx_sb: txcount: 8 ptr:0x00820080
[ 1065.604575] spi_imx 200c000.ecspi: spi_imx_buf_tx_sb: txcount: 4 ptr:0x00860084
[ 1065.604618] spi_imx 200c000.ecspi: spi_imx_buf_rx_sb: rxcount: 8 val:0x005f0040
[ 1065.604633] spi_imx 200c000.ecspi: spi_imx_buf_rx_sb: rxcount: 4 val:0x006c0080
Sascha Hauer June 1, 2016, 6:54 a.m. UTC | #2
On Wed, Jun 01, 2016 at 12:50:28PM +0800, Chris Ruehl wrote:
> The patch add support for single burst transfer where chipselect will
> hold active until transfer completes with a limit to 2^7 words transferred.
> The single-burst-mode need set the burstlength in ECSPI_CONREG.BURST_LENGTH
> and clear the ecspi channel related ss_ctl flag in ECSPI_CONFIGREG.SS_CTL.
> 
> The single-burst-mode is disabled by default. The activation from spidev
> is implemented by set bit0 of the xfer.speed_hz, which don't break anything
> in the mx51_ecspi_clkdiv() function.
> 
> xfer[0].speed_hz = 2000000 | 0x1; /* enable single burst mode with 1hz */

Erm, no. This is not acceptable in many ways. First of all the SPI API
between the kernel and userspace is driver agnostic. There is simply no
place for passing driver specific quirks from userspace to the spi-imx
driver. Then there is no API change needed because the way SPI
messages should be translated to the wire is well defined, the spi-imx
driver is just doing it wrong in this case which might be worth fixing.
This could be done without passing a "do it right" flag to the driver.

As noted in my response to the previous patch, I don't think we need a
fix for this at all, because we can always use GPIO chip selects which
works reliably not only in this case, but also in other cases where the
controller driven chipselect falls apart.

IMO there is only a single reason to keep controller driven chip select
support at all: On i.MX31 there is one dedicated chip select which can't
be configured as GPIO.

Sascha
Chris Ruehl June 1, 2016, 7:09 a.m. UTC | #3
On Wednesday, June 01, 2016 02:54 PM, Sascha Hauer wrote:
> On Wed, Jun 01, 2016 at 12:50:28PM +0800, Chris Ruehl wrote:
>> The patch add support for single burst transfer where chipselect will
>> hold active until transfer completes with a limit to 2^7 words transferred.
>> The single-burst-mode need set the burstlength in ECSPI_CONREG.BURST_LENGTH
>> and clear the ecspi channel related ss_ctl flag in ECSPI_CONFIGREG.SS_CTL.
>>
>> The single-burst-mode is disabled by default. The activation from spidev
>> is implemented by set bit0 of the xfer.speed_hz, which don't break anything
>> in the mx51_ecspi_clkdiv() function.
>>
>> xfer[0].speed_hz = 2000000 | 0x1; /* enable single burst mode with 1hz */
>
> Erm, no. This is not acceptable in many ways. First of all the SPI API
> between the kernel and userspace is driver agnostic. There is simply no
> place for passing driver specific quirks from userspace to the spi-imx
> driver. Then there is no API change needed because the way SPI
> messages should be translated to the wire is well defined, the spi-imx
> driver is just doing it wrong in this case which might be worth fixing.
> This could be done without passing a "do it right" flag to the driver.

I expected AND except the "NO" on this!
But the userspace interface (xfer) does not have anything else then tx,rx-buf 
cs_change delay.. to carry infos forward to the driver.

On the other hand it's useful to have the 'native cs working' to give the
hardware manufactures a hand to fixup their stuff! And play with the
chips features. Lot of things going wrong with hardware cs, and its good
to have a fallback to GPIO chip selects when the native chip fails.

My opinion, support both ways and don't give the chip guys an excuse to
give us rubbish.

>
> As noted in my response to the previous patch, I don't think we need a
> fix for this at all, because we can always use GPIO chip selects which
> works reliably not only in this case, but also in other cases where the
> controller driven chipselect falls apart.
>
> IMO there is only a single reason to keep controller driven chip select
> support at all: On i.MX31 there is one dedicated chip select which can't
> be configured as GPIO.
>
> Sascha
>

Thank you, its worth have your opinion on this.

Chris
Mark Brown June 1, 2016, 2:32 p.m. UTC | #4
On Wed, Jun 01, 2016 at 03:09:13PM +0800, Chris Ruehl wrote:
> On Wednesday, June 01, 2016 02:54 PM, Sascha Hauer wrote:

> > > The patch add support for single burst transfer where chipselect will
> > > hold active until transfer completes with a limit to 2^7 words transferred.
> > > The single-burst-mode need set the burstlength in ECSPI_CONREG.BURST_LENGTH
> > > and clear the ecspi channel related ss_ctl flag in ECSPI_CONFIGREG.SS_CTL.

> > > The single-burst-mode is disabled by default. The activation from spidev

> > Erm, no. This is not acceptable in many ways. First of all the SPI API
> > between the kernel and userspace is driver agnostic. There is simply no
> > place for passing driver specific quirks from userspace to the spi-imx
> > driver. Then there is no API change needed because the way SPI
> > messages should be translated to the wire is well defined, the spi-imx
> > driver is just doing it wrong in this case which might be worth fixing.
> > This could be done without passing a "do it right" flag to the driver.

> I expected AND except the "NO" on this!
> But the userspace interface (xfer) does not have anything else then
> tx,rx-buf cs_change delay.. to carry infos forward to the driver.

That's absolutely fine.  The "new" behaviour which you are introducing
is the standard behaviour, the fact that the driver currently does
anything different is just a very bad bug in the driver.  Instead of
introducing a new option to provide a driver specific "make it work"
quirk that users must activate you should fix the driver to perform
correctly as standard.
Chris Ruehl June 2, 2016, 1:27 a.m. UTC | #5
On Wednesday, June 01, 2016 10:32 PM, Mark Brown wrote:
> On Wed, Jun 01, 2016 at 03:09:13PM +0800, Chris Ruehl wrote:
>> On Wednesday, June 01, 2016 02:54 PM, Sascha Hauer wrote:
>
>>>> The patch add support for single burst transfer where chipselect will
>>>> hold active until transfer completes with a limit to 2^7 words transferred.
>>>> The single-burst-mode need set the burstlength in ECSPI_CONREG.BURST_LENGTH
>>>> and clear the ecspi channel related ss_ctl flag in ECSPI_CONFIGREG.SS_CTL.
>
>>>> The single-burst-mode is disabled by default. The activation from spidev
>
>>> Erm, no. This is not acceptable in many ways. First of all the SPI API
>>> between the kernel and userspace is driver agnostic. There is simply no
>>> place for passing driver specific quirks from userspace to the spi-imx
>>> driver. Then there is no API change needed because the way SPI
>>> messages should be translated to the wire is well defined, the spi-imx
>>> driver is just doing it wrong in this case which might be worth fixing.
>>> This could be done without passing a "do it right" flag to the driver.
>
>> I expected AND except the "NO" on this!
>> But the userspace interface (xfer) does not have anything else then
>> tx,rx-buf cs_change delay.. to carry infos forward to the driver.
>
> That's absolutely fine.  The "new" behaviour which you are introducing
> is the standard behaviour, the fact that the driver currently does
> anything different is just a very bad bug in the driver.  Instead of
> introducing a new option to provide a driver specific "make it work"
> quirk that users must activate you should fix the driver to perform
> correctly as standard.
>

Mark,

thanks for that explanation. I did not feel in the position to overrule
the current behaviour of the driver.
So if you agree that the change I did is acceptable as standard I going
to update the patch in the way to do so.

Chris
diff mbox

Patch

diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 50769078..15708eb 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,188 @@  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 +543,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 else 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 +1087,9 @@  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;
+	/* using bit0 of hz to enable the single burst mode */
+	config.single_burst_mode = (config.speed_hz&0x1) > 0 ? true : false;
 
 	if (!config.speed_hz)
 		config.speed_hz = spi->max_speed_hz;