--- linux-original/drivers/spi/spi-imx.c    2014-03-17 17:12:35.691791218 +0100
+++ linux-stable/drivers/spi/spi-imx.c    2014-03-17 17:09:44.451795597 +0100
@@ -51,12 +51,14 @@
 /* generic defines to abstract from the different register layouts */
 #define MXC_INT_RR    (1 << 0) /* Receive data ready interrupt */
 #define MXC_INT_TE    (1 << 1) /* Transmit FIFO empty interrupt */
+#define MXC_INT_THE     (1 << 2) /* Transmit FIFO threshold interrupt */
 
 struct spi_imx_config {
     unsigned int speed_hz;
     unsigned int bpw;
     unsigned int mode;
     u8 cs;
+    unsigned long burstlen;
 };
 
 enum spi_imx_devtype {
@@ -154,6 +156,10 @@
 static int mxc_clkdivs[] = {0, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192,
     256, 384, 512, 768, 1024};
 
+// (sysfs-)tunable attributes
+static int allow_big_bursts = 0; // if set to 1 this enables 32-bit big bursts
+static int tx_fifo_thres = -1;   // if positive, use TX data request interrupt when applicable
+
 /* MX21, MX27 */
 static unsigned int spi_imx_clkdiv_1(unsigned int fin,
         unsigned int fspi, unsigned int max)
@@ -200,8 +206,13 @@
 
 #define MX51_ECSPI_INT        0x10
 #define MX51_ECSPI_INT_TEEN        (1 <<  0)
+#define MX51_ECSPI_INT_TDREN        (1 <<  1)
 #define MX51_ECSPI_INT_RREN        (1 <<  3)
 
+#define MX51_ECSPI_DMA      0x14
+#define MX51_ECSPI_DMA_TX_THRES_OFFSET  0
+#define MX51_ECSPI_DMA_TX_THRES_MASK    (0x3F)
+
 #define MX51_ECSPI_STAT        0x18
 #define MX51_ECSPI_STAT_RR        (1 <<  3)
 
@@ -250,6 +261,12 @@
     if (enable & MXC_INT_TE)
         val |= MX51_ECSPI_INT_TEEN;
 
+    // enable Tx threshold interrupt for faster reaction when transmitting long messages
+    if (enable & MXC_INT_THE) {
+        val |= MX51_ECSPI_INT_TDREN;
+        writel((unsigned int) tx_fifo_thres, spi_imx->base + MX51_ECSPI_DMA);
+    }
+
     if (enable & MXC_INT_RR)
         val |= MX51_ECSPI_INT_RREN;
 
@@ -270,6 +287,7 @@
 {
     u32 ctrl = MX51_ECSPI_CTRL_ENABLE, cfg = 0;
     u32 clk = config->speed_hz, delay;
+    unsigned long burstlen;
 
     /*
      * The hardware seems to have a race condition when changing modes. The
@@ -286,6 +304,27 @@
     /* set chip select to use */
     ctrl |= MX51_ECSPI_CTRL_CS(config->cs);
 
+    // if possible and requested, increase burstlength
+    // over whole message in 32 bit mode
+    // (which is the only mode where HW supports this)
+    // all other modes still use burstlength == bpw
+    if ((config->bpw == 32) && (allow_big_bursts == 1)) {
+        if (config->burstlen <= 4096) {
+            burstlen = config->burstlen;
+        } else {
+            // burst longer than burst register width -- need to scale appropriately
+            // so that the hardware will always terminate the burst appropriately
+            burstlen = 16;
+            do {
+                burstlen = burstlen << 1;
+            } while ((config->burstlen % (burstlen << 1)) == 0);
+        }
+    } else {
+      burstlen = config->bpw;
+    }
+
+    ctrl |= (burstlen - 1) << MX51_ECSPI_CTRL_BL_OFFSET;
+
     ctrl |= (config->bpw - 1) << MX51_ECSPI_CTRL_BL_OFFSET;
 
     cfg |= MX51_ECSPI_CONFIG_SBBCTRL(config->cs);
@@ -666,6 +705,10 @@
         spi_imx->txfifo++;
     }
 
+    // always reconfigure IRQ source (for the TX data request IRQ to work properly)
+    spi_imx->devtype_data->intctrl(spi_imx,
+        ((spi_imx->txfifo == spi_imx_get_fifosize(spi_imx)) && (tx_fifo_thres != -1)) ? MXC_INT_THE : MXC_INT_TE);
+
     spi_imx->devtype_data->trigger(spi_imx);
 }
 
@@ -708,6 +751,7 @@
     config.speed_hz  = t ? t->speed_hz : spi->max_speed_hz;
     config.mode = spi->mode;
     config.cs = spi->chip_select;
+    config.burstlen = t ? (t->len * 8) : config.bpw;
 
     if (!config.speed_hz)
         config.speed_hz = spi->max_speed_hz;
@@ -745,8 +789,6 @@
 
     spi_imx_push(spi_imx);
 
-    spi_imx->devtype_data->intctrl(spi_imx, MXC_INT_TE);
-
     wait_for_completion(&spi_imx->xfer_done);
 
     return transfer->len;
@@ -801,6 +843,63 @@
     return 0;
 }
 
+static ssize_t spidrv_setbigburst(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t size)
+{
+    unsigned long tmp;
+    tmp = simple_strtoul(buf, NULL, 10);
+    if (tmp == 1) {
+        allow_big_bursts = 1;
+        } else {
+        allow_big_bursts = 0;
+    }
+    return size;
+}
+
+static ssize_t spidrv_getbigburst(struct device *dev,
+                                  struct device_attribute *attr,
+                                  char *buf)
+{
+    sprintf (buf, "%d\n", allow_big_bursts);
+    return (ssize_t)(strlen (buf) + 1);
+}
+
+static ssize_t spidrv_settxthres(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t size)
+{
+    unsigned long tmp;
+    tmp = simple_strtoul(buf, NULL, 10);
+    if ((tmp > 0) && (tmp < 65)) {
+        tx_fifo_thres = tmp;
+    } else {
+        tx_fifo_thres = -1;
+    }
+    return size;
+}
+
+static ssize_t spidrv_gettxthres(struct device *dev,
+                                 struct device_attribute *attr,
+                                 char *buf)
+{
+    sprintf (buf, "%d\n", tx_fifo_thres);
+    return (ssize_t)(strlen (buf) + 1);
+}
+
+static DEVICE_ATTR(bigburst, 0666, spidrv_getbigburst, spidrv_setbigburst);
+static DEVICE_ATTR(txthres,  0666, spidrv_gettxthres , spidrv_settxthres);
+
+static struct attribute *spidrv_attributes[] = {
+    &dev_attr_bigburst.attr,
+    &dev_attr_txthres.attr,
+    NULL
+};
+
+static const struct attribute_group spidrv_group = {
+    .attrs = spidrv_attributes,
+};
+
 static int spi_imx_probe(struct platform_device *pdev)
 {
     struct device_node *np = pdev->dev.of_node;
@@ -840,6 +939,10 @@
     spi_imx = spi_master_get_devdata(master);
     spi_imx->bitbang.master = master;
 
+    if (sysfs_create_group(&pdev->dev.kobj, &spidrv_group)) {
+        return -ENOMEM;
+    }
+
     for (i = 0; i < master->num_chipselect; i++) {
         int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);
         if (!gpio_is_valid(cs_gpio) && mxc_platform_info)
