spi: rzv2h-rspi: make transfer clock rate finding chip-specific

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>
This commit is contained in:
Cosmin Tanislav 2025-11-19 18:14:27 +02:00 committed by Mark Brown
parent 8878249320
commit 77d931584d
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0

View File

@ -67,7 +67,18 @@
#define RSPI_RESET_NUM 2 #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 { 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; const char *tclk_name;
unsigned int fifo_size; unsigned int fifo_size;
unsigned int num_clks; 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))); 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; int spr;
u8 brdv; 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 = SPR - is RSPI_SPBR.SPR (from 0 to 255)
* * N = BRDV - is RSPI_SPCMD.BRDV (from 0 to 3) * * 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++) { 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--; spr--;
if (spr >= RSPI_SPBR_SPR_MIN && spr <= RSPI_SPBR_SPR_MAX) if (spr >= spr_min && spr <= spr_max)
goto clock_found; goto clock_found;
} }
return 0; return;
clock_found: clock_found:
rspi->spr = spr; actual_hz = rzv2h_rspi_calc_bitrate(clk_rate, spr, brdv);
rspi->brdv = brdv; error = abs((long)hz - (long)actual_hz);
return rzv2h_rspi_calc_bitrate(tclk_rate, spr, brdv); 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 best_clock.actual_hz;
} }
static int rzv2h_rspi_prepare_message(struct spi_controller *ctlr, 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 = { static const struct rzv2h_rspi_info rzv2h_info = {
.find_tclk_rate = rzv2h_rspi_find_rate_fixed,
.tclk_name = "tclk", .tclk_name = "tclk",
.fifo_size = 16, .fifo_size = 16,
.num_clks = 3, .num_clks = 3,