#define S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD      (1<<17)
 #define S3C64XX_SPI_MODE_BUS_TSZ_WORD          (2<<17)
 #define S3C64XX_SPI_MODE_BUS_TSZ_MASK          (3<<17)
+#define S3C64XX_SPI_MODE_RX_RDY_LVL            GENMASK(16, 11)
+#define S3C64XX_SPI_MODE_RX_RDY_LVL_SHIFT      11
 #define S3C64XX_SPI_MODE_SELF_LOOPBACK         (1<<3)
 #define S3C64XX_SPI_MODE_RXDMA_ON              (1<<2)
 #define S3C64XX_SPI_MODE_TXDMA_ON              (1<<1)
 
 #define S3C64XX_SPI_TRAILCNT           S3C64XX_SPI_MAX_TRAILCNT
 
+#define S3C64XX_SPI_POLLING_SIZE       32
+
 #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
 #define is_polling(x)  (x->cntrlr_info->polling)
 
 }
 
 static int s3c64xx_wait_for_pio(struct s3c64xx_spi_driver_data *sdd,
-                               struct spi_transfer *xfer)
+                               struct spi_transfer *xfer, bool use_irq)
 {
        void __iomem *regs = sdd->regs;
        unsigned long val;
        if (RX_FIFO_LVL(status, sdd) < xfer->len)
                usleep_range(time_us / 2, time_us);
 
+       if (use_irq) {
+               val = msecs_to_jiffies(ms);
+               if (!wait_for_completion_timeout(&sdd->xfer_completion, val))
+                       return -EIO;
+       }
+
        val = msecs_to_loops(ms);
        do {
                status = readl(regs + S3C64XX_SPI_STATUS);
        void *rx_buf = NULL;
        int target_len = 0, origin_len = 0;
        int use_dma = 0;
+       bool use_irq = false;
        int status;
        u32 speed;
        u8 bpw;
        unsigned long flags;
+       u32 rdy_lv;
+       u32 val;
 
        reinit_completion(&sdd->xfer_completion);
 
            sdd->rx_dma.ch && sdd->tx_dma.ch) {
                use_dma = 1;
 
-       } else if (xfer->len > fifo_len) {
+       } else if (xfer->len >= fifo_len) {
                tx_buf = xfer->tx_buf;
                rx_buf = xfer->rx_buf;
                origin_len = xfer->len;
-
                target_len = xfer->len;
-               if (xfer->len > fifo_len)
-                       xfer->len = fifo_len;
+               xfer->len = fifo_len - 1;
        }
 
        do {
+               /* transfer size is greater than 32, change to IRQ mode */
+               if (xfer->len > S3C64XX_SPI_POLLING_SIZE)
+                       use_irq = true;
+
+               if (use_irq) {
+                       reinit_completion(&sdd->xfer_completion);
+
+                       rdy_lv = xfer->len;
+                       /* Setup RDY_FIFO trigger Level
+                        * RDY_LVL =
+                        * fifo_lvl up to 64 byte -> N bytes
+                        *               128 byte -> RDY_LVL * 2 bytes
+                        *               256 byte -> RDY_LVL * 4 bytes
+                        */
+                       if (fifo_len == 128)
+                               rdy_lv /= 2;
+                       else if (fifo_len == 256)
+                               rdy_lv /= 4;
+
+                       val = readl(sdd->regs + S3C64XX_SPI_MODE_CFG);
+                       val &= ~S3C64XX_SPI_MODE_RX_RDY_LVL;
+                       val |= (rdy_lv << S3C64XX_SPI_MODE_RX_RDY_LVL_SHIFT);
+                       writel(val, sdd->regs + S3C64XX_SPI_MODE_CFG);
+
+                       /* Enable FIFO_RDY_EN IRQ */
+                       val = readl(sdd->regs + S3C64XX_SPI_INT_EN);
+                       writel((val | S3C64XX_SPI_INT_RX_FIFORDY_EN),
+                                       sdd->regs + S3C64XX_SPI_INT_EN);
+
+               }
+
                spin_lock_irqsave(&sdd->lock, flags);
 
                /* Pending only which is to be done */
                if (use_dma)
                        status = s3c64xx_wait_for_dma(sdd, xfer);
                else
-                       status = s3c64xx_wait_for_pio(sdd, xfer);
+                       status = s3c64xx_wait_for_pio(sdd, xfer, use_irq);
 
                if (status) {
                        dev_err(&spi->dev,
                        if (xfer->rx_buf)
                                xfer->rx_buf += xfer->len;
 
-                       if (target_len > fifo_len)
-                               xfer->len = fifo_len;
+                       if (target_len >= fifo_len)
+                               xfer->len = fifo_len - 1;
                        else
                                xfer->len = target_len;
                }
                dev_err(&spi->dev, "TX underrun\n");
        }
 
+       if (val & S3C64XX_SPI_ST_RX_FIFORDY) {
+               complete(&sdd->xfer_completion);
+               /* No pending clear irq, turn-off INT_EN_RX_FIFO_RDY */
+               val = readl(sdd->regs + S3C64XX_SPI_INT_EN);
+               writel((val & ~S3C64XX_SPI_INT_RX_FIFORDY_EN),
+                               sdd->regs + S3C64XX_SPI_INT_EN);
+       }
+
        /* Clear the pending irq by setting and then clearing it */
        writel(clr, sdd->regs + S3C64XX_SPI_PENDING_CLR);
        writel(0, sdd->regs + S3C64XX_SPI_PENDING_CLR);