]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
spi: rzv2h-rspi: make transfer clock rate finding chip-specific
authorCosmin Tanislav <cosmin-gabriel.tanislav.xa@renesas.com>
Wed, 19 Nov 2025 16:14:27 +0000 (18:14 +0200)
committerMark Brown <broonie@kernel.org>
Mon, 24 Nov 2025 14:10:43 +0000 (14:10 +0000)
The Renesas RZ/T2H (R9A09G077) and RZ/N2H (R9A09G087) SoCs have a more
complicated clocking setup for the SPI transfer clock than RZ/V2H, as
the clock from which it is generated supports multiple dividers.

To prepare for adding support for these SoCs, split out the logic for
finding the SPR and BRDV for a fixed clock into
rzv2h_rspi_find_rate_fixed(), and add and use a .find_tclk_rate()
callback into the chip-specific structure.

Signed-off-by: Cosmin Tanislav <cosmin-gabriel.tanislav.xa@renesas.com>
Link: https://patch.msgid.link/20251119161434.595677-7-cosmin-gabriel.tanislav.xa@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/spi/spi-rzv2h-rspi.c

index d7719f3c7b13457e0edb4c6cdbd5ba119dcf6ca9..f59bcadf5e38280679954a33852f56b55d215fcc 100644 (file)
 
 #define RSPI_RESET_NUM         2
 
+struct rzv2h_rspi_best_clock {
+       struct clk *clk;
+       unsigned long clk_rate;
+       unsigned long error;
+       u32 actual_hz;
+       u8 brdv;
+       u8 spr;
+};
+
 struct rzv2h_rspi_info {
+       void (*find_tclk_rate)(struct clk *clk, u32 hz, u8 spr_min, u8 spr_max,
+                              struct rzv2h_rspi_best_clock *best_clk);
        const char *tclk_name;
        unsigned int fifo_size;
        unsigned int num_clks;
@@ -240,9 +251,13 @@ static inline u32 rzv2h_rspi_calc_bitrate(unsigned long tclk_rate, u8 spr,
        return DIV_ROUND_UP(tclk_rate, (2 * (spr + 1) * (1 << brdv)));
 }
 
-static u32 rzv2h_rspi_setup_clock(struct rzv2h_rspi_priv *rspi, u32 hz)
+static void rzv2h_rspi_find_rate_fixed(struct clk *clk, u32 hz,
+                                      u8 spr_min, u8 spr_max,
+                                      struct rzv2h_rspi_best_clock *best)
 {
-       unsigned long tclk_rate;
+       unsigned long clk_rate;
+       unsigned long error;
+       u32 actual_hz;
        int spr;
        u8 brdv;
 
@@ -255,21 +270,49 @@ static u32 rzv2h_rspi_setup_clock(struct rzv2h_rspi_priv *rspi, u32 hz)
         * * n = SPR - is RSPI_SPBR.SPR (from 0 to 255)
         * * N = BRDV - is RSPI_SPCMD.BRDV (from 0 to 3)
         */
-       tclk_rate = clk_get_rate(rspi->tclk);
+       clk_rate = clk_get_rate(clk);
        for (brdv = RSPI_SPCMD_BRDV_MIN; brdv <= RSPI_SPCMD_BRDV_MAX; brdv++) {
-               spr = DIV_ROUND_UP(tclk_rate, hz * (1 << (brdv + 1)));
+               spr = DIV_ROUND_UP(clk_rate, hz * (1 << (brdv + 1)));
                spr--;
-               if (spr >= RSPI_SPBR_SPR_MIN && spr <= RSPI_SPBR_SPR_MAX)
+               if (spr >= spr_min && spr <= spr_max)
                        goto clock_found;
        }
 
-       return 0;
+       return;
 
 clock_found:
-       rspi->spr = spr;
-       rspi->brdv = brdv;
+       actual_hz = rzv2h_rspi_calc_bitrate(clk_rate, spr, brdv);
+       error = abs((long)hz - (long)actual_hz);
+
+       if (error >= best->error)
+               return;
+
+       *best = (struct rzv2h_rspi_best_clock) {
+               .clk = clk,
+               .clk_rate = clk_rate,
+               .error = error,
+               .actual_hz = actual_hz,
+               .brdv = brdv,
+               .spr = spr,
+       };
+}
+
+static u32 rzv2h_rspi_setup_clock(struct rzv2h_rspi_priv *rspi, u32 hz)
+{
+       struct rzv2h_rspi_best_clock best_clock = {
+               .error = ULONG_MAX,
+       };
+
+       rspi->info->find_tclk_rate(rspi->tclk, hz, RSPI_SPBR_SPR_MIN,
+                                  RSPI_SPBR_SPR_MAX, &best_clock);
+
+       if (!best_clock.clk_rate)
+               return -EINVAL;
+
+       rspi->spr = best_clock.spr;
+       rspi->brdv = best_clock.brdv;
 
-       return rzv2h_rspi_calc_bitrate(tclk_rate, spr, brdv);
+       return best_clock.actual_hz;
 }
 
 static int rzv2h_rspi_prepare_message(struct spi_controller *ctlr,
@@ -463,6 +506,7 @@ static void rzv2h_rspi_remove(struct platform_device *pdev)
 }
 
 static const struct rzv2h_rspi_info rzv2h_info = {
+       .find_tclk_rate = rzv2h_rspi_find_rate_fixed,
        .tclk_name = "tclk",
        .fifo_size = 16,
        .num_clks = 3,