#define writel_bits_relaxed(mask, val, addr) \
        writel_relaxed((readl_relaxed(addr) & ~(mask)) | (val), addr)
 
-#define SPICC_BURST_MAX        16
-#define SPICC_FIFO_HALF 10
-
 struct meson_spicc_data {
        unsigned int                    max_speed_hz;
        unsigned int                    min_speed_hz;
+       unsigned int                    fifo_size;
        bool                            has_oen;
        bool                            has_enhance_clk_div;
 };
        unsigned long                   tx_remain;
        unsigned long                   rx_remain;
        unsigned long                   xfer_remain;
-       bool                            is_burst_end;
-       bool                            is_last_burst;
 };
 
 static void meson_spicc_oen_enable(struct meson_spicc_device *spicc)
 
 static inline bool meson_spicc_rxready(struct meson_spicc_device *spicc)
 {
-       return FIELD_GET(SPICC_RH | SPICC_RR | SPICC_RF_EN,
+       return FIELD_GET(SPICC_RH | SPICC_RR | SPICC_RF,
                         readl_relaxed(spicc->base + SPICC_STATREG));
 }
 
                               spicc->base + SPICC_TXDATA);
 }
 
-static inline u32 meson_spicc_setup_rx_irq(struct meson_spicc_device *spicc,
-                                          u32 irq_ctrl)
+static inline void meson_spicc_setup_burst(struct meson_spicc_device *spicc)
 {
-       if (spicc->rx_remain > SPICC_FIFO_HALF)
-               irq_ctrl |= SPICC_RH_EN;
-       else
-               irq_ctrl |= SPICC_RR_EN;
-
-       return irq_ctrl;
-}
 
-static inline void meson_spicc_setup_burst(struct meson_spicc_device *spicc,
-                                          unsigned int burst_len)
-{
+       unsigned int burst_len = min_t(unsigned int,
+                                      spicc->xfer_remain /
+                                      spicc->bytes_per_word,
+                                      spicc->data->fifo_size);
        /* Setup Xfer variables */
        spicc->tx_remain = burst_len;
        spicc->rx_remain = burst_len;
        spicc->xfer_remain -= burst_len * spicc->bytes_per_word;
-       spicc->is_burst_end = false;
-       if (burst_len < SPICC_BURST_MAX || !spicc->xfer_remain)
-               spicc->is_last_burst = true;
-       else
-               spicc->is_last_burst = false;
 
        /* Setup burst length */
        writel_bits_relaxed(SPICC_BURSTLENGTH_MASK,
                        FIELD_PREP(SPICC_BURSTLENGTH_MASK,
-                               burst_len),
+                               burst_len - 1),
                        spicc->base + SPICC_CONREG);
 
        /* Fill TX FIFO */
 static irqreturn_t meson_spicc_irq(int irq, void *data)
 {
        struct meson_spicc_device *spicc = (void *) data;
-       u32 ctrl = readl_relaxed(spicc->base + SPICC_INTREG);
-       u32 stat = readl_relaxed(spicc->base + SPICC_STATREG) & ctrl;
 
-       ctrl &= ~(SPICC_RH_EN | SPICC_RR_EN);
+       writel_bits_relaxed(SPICC_TC, SPICC_TC, spicc->base + SPICC_STATREG);
 
        /* Empty RX FIFO */
        meson_spicc_rx(spicc);
 
-       /* Enable TC interrupt since we transferred everything */
-       if (!spicc->tx_remain && !spicc->rx_remain) {
-               spicc->is_burst_end = true;
-
-               /* Enable TC interrupt */
-               ctrl |= SPICC_TC_EN;
-
-               /* Reload IRQ status */
-               stat = readl_relaxed(spicc->base + SPICC_STATREG) & ctrl;
-       }
-
-       /* Check transfer complete */
-       if ((stat & SPICC_TC) && spicc->is_burst_end) {
-               unsigned int burst_len;
-
-               /* Clear TC bit */
-               writel_relaxed(SPICC_TC, spicc->base + SPICC_STATREG);
-
-               /* Disable TC interrupt */
-               ctrl &= ~SPICC_TC_EN;
-
-               if (spicc->is_last_burst) {
-                       /* Disable all IRQs */
-                       writel(0, spicc->base + SPICC_INTREG);
-
-                       spi_finalize_current_transfer(spicc->master);
+       if (!spicc->xfer_remain) {
+               /* Disable all IRQs */
+               writel(0, spicc->base + SPICC_INTREG);
 
-                       return IRQ_HANDLED;
-               }
+               spi_finalize_current_transfer(spicc->master);
 
-               burst_len = min_t(unsigned int,
-                                 spicc->xfer_remain / spicc->bytes_per_word,
-                                 SPICC_BURST_MAX);
-
-               /* Setup burst */
-               meson_spicc_setup_burst(spicc, burst_len);
-
-               /* Restart burst */
-               writel_bits_relaxed(SPICC_XCH, SPICC_XCH,
-                                   spicc->base + SPICC_CONREG);
+               return IRQ_HANDLED;
        }
 
-       /* Setup RX interrupt trigger */
-       ctrl = meson_spicc_setup_rx_irq(spicc, ctrl);
+       /* Setup burst */
+       meson_spicc_setup_burst(spicc);
 
-       /* Reconfigure interrupts */
-       writel(ctrl, spicc->base + SPICC_INTREG);
+       /* Start burst */
+       writel_bits_relaxed(SPICC_XCH, SPICC_XCH, spicc->base + SPICC_CONREG);
 
        return IRQ_HANDLED;
 }
        clk_set_rate(spicc->clk, xfer->speed_hz);
 
        meson_spicc_auto_io_delay(spicc);
+
+       writel_relaxed(0, spicc->base + SPICC_DMAREG);
+}
+
+static void meson_spicc_reset_fifo(struct meson_spicc_device *spicc)
+{
+       u32 data;
+
+       if (spicc->data->has_oen)
+               writel_bits_relaxed(SPICC_ENH_MAIN_CLK_AO,
+                                   SPICC_ENH_MAIN_CLK_AO,
+                                   spicc->base + SPICC_ENH_CTL0);
+
+       writel_bits_relaxed(SPICC_FIFORST_W1_MASK, SPICC_FIFORST_W1_MASK,
+                           spicc->base + SPICC_TESTREG);
+
+       while (meson_spicc_rxready(spicc))
+               data = readl_relaxed(spicc->base + SPICC_RXDATA);
+
+       if (spicc->data->has_oen)
+               writel_bits_relaxed(SPICC_ENH_MAIN_CLK_AO, 0,
+                                   spicc->base + SPICC_ENH_CTL0);
 }
 
 static int meson_spicc_transfer_one(struct spi_master *master,
                                    struct spi_transfer *xfer)
 {
        struct meson_spicc_device *spicc = spi_master_get_devdata(master);
-       unsigned int burst_len;
-       u32 irq = 0;
 
        /* Store current transfer */
        spicc->xfer = xfer;
        spicc->bytes_per_word =
           DIV_ROUND_UP(spicc->xfer->bits_per_word, 8);
 
+       if (xfer->len % spicc->bytes_per_word)
+               return -EINVAL;
+
        /* Setup transfer parameters */
        meson_spicc_setup_xfer(spicc, xfer);
 
-       burst_len = min_t(unsigned int,
-                         spicc->xfer_remain / spicc->bytes_per_word,
-                         SPICC_BURST_MAX);
-
-       meson_spicc_setup_burst(spicc, burst_len);
+       meson_spicc_reset_fifo(spicc);
 
-       irq = meson_spicc_setup_rx_irq(spicc, irq);
+       /* Setup burst */
+       meson_spicc_setup_burst(spicc);
 
        /* Start burst */
        writel_bits_relaxed(SPICC_XCH, SPICC_XCH, spicc->base + SPICC_CONREG);
 
        /* Enable interrupts */
-       writel_relaxed(irq, spicc->base + SPICC_INTREG);
+       writel_relaxed(SPICC_TC_EN, spicc->base + SPICC_INTREG);
 
        return 1;
 }
        /* Setup no wait cycles by default */
        writel_relaxed(0, spicc->base + SPICC_PERIODREG);
 
-       writel_bits_relaxed(BIT(24), BIT(24), spicc->base + SPICC_TESTREG);
+       writel_bits_relaxed(SPICC_LBC_W1, 0, spicc->base + SPICC_TESTREG);
 
        return 0;
 }
 static const struct meson_spicc_data meson_spicc_gx_data = {
        .max_speed_hz           = 30000000,
        .min_speed_hz           = 325000,
+       .fifo_size              = 16,
 };
 
 static const struct meson_spicc_data meson_spicc_axg_data = {
        .max_speed_hz           = 80000000,
        .min_speed_hz           = 325000,
+       .fifo_size              = 16,
        .has_oen                = true,
        .has_enhance_clk_div    = true,
 };