#define SUN6I_TFR_CTL_CS_MANUAL                        BIT(6)
 #define SUN6I_TFR_CTL_CS_LEVEL                 BIT(7)
 #define SUN6I_TFR_CTL_DHB                      BIT(8)
+#define SUN6I_TFR_CTL_SDC                      BIT(11)
 #define SUN6I_TFR_CTL_FBS                      BIT(12)
+#define SUN6I_TFR_CTL_SDM                      BIT(13)
 #define SUN6I_TFR_CTL_XCH                      BIT(31)
 
 #define SUN6I_INT_CTL_REG              0x10
 
 struct sun6i_spi_cfg {
        unsigned long           fifo_depth;
+       bool                    has_clk_ctl;
 };
 
 struct sun6i_spi {
                                  struct spi_transfer *tfr)
 {
        struct sun6i_spi *sspi = spi_master_get_devdata(master);
-       unsigned int mclk_rate, div, div_cdr1, div_cdr2, timeout;
+       unsigned int div, div_cdr1, div_cdr2, timeout;
        unsigned int start, end, tx_time;
        unsigned int trig_level;
        unsigned int tx_len = 0, rx_len = 0;
 
        sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
 
-       /* Ensure that we have a parent clock fast enough */
-       mclk_rate = clk_get_rate(sspi->mclk);
-       if (mclk_rate < (2 * tfr->speed_hz)) {
-               clk_set_rate(sspi->mclk, 2 * tfr->speed_hz);
-               mclk_rate = clk_get_rate(sspi->mclk);
-       }
+       if (sspi->cfg->has_clk_ctl) {
+               unsigned int mclk_rate = clk_get_rate(sspi->mclk);
 
-       /*
-        * Setup clock divider.
-        *
-        * We have two choices there. Either we can use the clock
-        * divide rate 1, which is calculated thanks to this formula:
-        * SPI_CLK = MOD_CLK / (2 ^ cdr)
-        * Or we can use CDR2, which is calculated with the formula:
-        * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
-        * Wether we use the former or the latter is set through the
-        * DRS bit.
-        *
-        * First try CDR2, and if we can't reach the expected
-        * frequency, fall back to CDR1.
-        */
-       div_cdr1 = DIV_ROUND_UP(mclk_rate, tfr->speed_hz);
-       div_cdr2 = DIV_ROUND_UP(div_cdr1, 2);
-       if (div_cdr2 <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
-               reg = SUN6I_CLK_CTL_CDR2(div_cdr2 - 1) | SUN6I_CLK_CTL_DRS;
-               tfr->effective_speed_hz = mclk_rate / (2 * div_cdr2);
+               /* Ensure that we have a parent clock fast enough */
+               if (mclk_rate < (2 * tfr->speed_hz)) {
+                       clk_set_rate(sspi->mclk, 2 * tfr->speed_hz);
+                       mclk_rate = clk_get_rate(sspi->mclk);
+               }
+
+               /*
+                * Setup clock divider.
+                *
+                * We have two choices there. Either we can use the clock
+                * divide rate 1, which is calculated thanks to this formula:
+                * SPI_CLK = MOD_CLK / (2 ^ cdr)
+                * Or we can use CDR2, which is calculated with the formula:
+                * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
+                * Wether we use the former or the latter is set through the
+                * DRS bit.
+                *
+                * First try CDR2, and if we can't reach the expected
+                * frequency, fall back to CDR1.
+                */
+               div_cdr1 = DIV_ROUND_UP(mclk_rate, tfr->speed_hz);
+               div_cdr2 = DIV_ROUND_UP(div_cdr1, 2);
+               if (div_cdr2 <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
+                       reg = SUN6I_CLK_CTL_CDR2(div_cdr2 - 1) | SUN6I_CLK_CTL_DRS;
+                       tfr->effective_speed_hz = mclk_rate / (2 * div_cdr2);
+               } else {
+                       div = min(SUN6I_CLK_CTL_CDR1_MASK, order_base_2(div_cdr1));
+                       reg = SUN6I_CLK_CTL_CDR1(div);
+                       tfr->effective_speed_hz = mclk_rate / (1 << div);
+               }
+
+               sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
        } else {
-               div = min(SUN6I_CLK_CTL_CDR1_MASK, order_base_2(div_cdr1));
-               reg = SUN6I_CLK_CTL_CDR1(div);
-               tfr->effective_speed_hz = mclk_rate / (1 << div);
+               clk_set_rate(sspi->mclk, tfr->speed_hz);
+               tfr->effective_speed_hz = clk_get_rate(sspi->mclk);
+
+               /*
+                * Configure work mode.
+                *
+                * There are three work modes depending on the controller clock
+                * frequency:
+                * - normal sample mode           : CLK <= 24MHz SDM=1 SDC=0
+                * - delay half-cycle sample mode : CLK <= 40MHz SDM=0 SDC=0
+                * - delay one-cycle sample mode  : CLK >= 80MHz SDM=0 SDC=1
+                */
+               reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
+               reg &= ~(SUN6I_TFR_CTL_SDM | SUN6I_TFR_CTL_SDC);
+
+               if (tfr->effective_speed_hz <= 24000000)
+                       reg |= SUN6I_TFR_CTL_SDM;
+               else if (tfr->effective_speed_hz >= 80000000)
+                       reg |= SUN6I_TFR_CTL_SDC;
+
+               sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
        }
 
-       sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
        /* Finally enable the bus - doing so before might raise SCK to HIGH */
        reg = sun6i_spi_read(sspi, SUN6I_GBL_CTL_REG);
        reg |= SUN6I_GBL_CTL_BUS_ENABLE;
 
 static const struct sun6i_spi_cfg sun6i_a31_spi_cfg = {
        .fifo_depth     = SUN6I_FIFO_DEPTH,
+       .has_clk_ctl    = true,
 };
 
 static const struct sun6i_spi_cfg sun8i_h3_spi_cfg = {
        .fifo_depth     = SUN8I_FIFO_DEPTH,
+       .has_clk_ctl    = true,
 };
 
 static const struct of_device_id sun6i_spi_match[] = {