[PATCH v2 6/9] spi: qcom-geni: Use geni_se_set_rate() for setting source clock frequency

From: Praveen Talari

Date: Thu Aug 27 2026 - 14:01:28 EST


On the SA8255P platform there is no Linux clock handler for the SE
source clock, so the driver has no way to look up the source clock
index and divider needed to fill the GSI CONFIG0 TRE for a requested
transfer frequency. To work around this, firmware instead exposes the
SE HW supported source clock frequencies as OPPs on the perf domain
device.

geni_se_domain_attach() now populates clk_perf_tbl from
the performance-domain OPP table, allowing firmware-managed
platforms to use geni_se_clk_freq_match().

Use geni_se_set_rate() instead of dev_pm_opp_set_rate()
so clock programming is handled centrally by the GENI core,
independent of the underlying clock-control mechanism.

Acked-by: Mark Brown <broonie@xxxxxxxxxx>
Signed-off-by: Praveen Talari <praveen.talari@xxxxxxxxxxxxxxxx>
---
drivers/spi/spi-geni-qcom.c | 24 +++++++++++-------------
1 file changed, 11 insertions(+), 13 deletions(-)

diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index 6566975eb24f..03ce9eff9c24 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -15,7 +15,6 @@
#include <linux/log2.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/pm_opp.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/soc/qcom/geni-se.h>
@@ -82,7 +81,6 @@

struct geni_spi_desc {
int (*resources_init)(struct geni_se *se);
- int (*set_rate)(struct geni_se *se, unsigned long clk_freq);
int (*power_on)(struct geni_se *se);
int (*power_off)(struct geni_se *se);
};
@@ -150,9 +148,9 @@ static int get_spi_clk_cfg(unsigned int speed_hz,

dev_dbg(mas->dev, "req %u=>%u sclk %lu, idx %d, div %d\n", speed_hz,
actual_hz, sclk_freq, *clk_idx, *clk_div);
- ret = dev_pm_opp_set_rate(mas->dev, sclk_freq);
+ ret = geni_se_set_rate(&mas->se, sclk_freq);
if (ret)
- dev_err(mas->dev, "dev_pm_opp_set_rate failed %d\n", ret);
+ dev_err(mas->dev, "geni_se_set_rate failed %d\n", ret);
else
mas->cur_sclk_hz = sclk_freq;

@@ -847,7 +845,7 @@ static int setup_se_xfer(struct spi_transfer *xfer,
}

/* Speed and bits per word can be overridden per transfer */
- ret = mas->dev_data->set_rate(&mas->se, xfer->speed_hz);
+ ret = geni_spi_set_clock_and_bw(&mas->se, xfer->speed_hz);
if (ret)
return ret;

@@ -1161,9 +1159,14 @@ static int __maybe_unused spi_geni_runtime_suspend(struct device *dev)
{
struct spi_controller *spi = dev_get_drvdata(dev);
struct spi_geni_master *mas = spi_controller_get_devdata(spi);
+ int ret;
+
+ ret = mas->dev_data->power_off ?
+ mas->dev_data->power_off(&mas->se) : 0;
+ if (ret)
+ return ret;

- return mas->dev_data->power_off ?
- mas->dev_data->power_off(&mas->se) : 0;
+ return geni_se_set_rate(&mas->se, 0);
}

static int __maybe_unused spi_geni_runtime_resume(struct device *dev)
@@ -1178,10 +1181,7 @@ static int __maybe_unused spi_geni_runtime_resume(struct device *dev)
return ret;
}

- if (mas->se.has_opp)
- return dev_pm_opp_set_rate(mas->dev, mas->cur_sclk_hz);
-
- return 0;
+ return geni_se_set_rate(&mas->se, mas->cur_sclk_hz);
}

static int __maybe_unused spi_geni_suspend(struct device *dev)
@@ -1224,14 +1224,12 @@ static const struct dev_pm_ops spi_geni_pm_ops = {

static const struct geni_spi_desc geni_spi = {
.resources_init = geni_se_resources_init,
- .set_rate = geni_spi_set_clock_and_bw,
.power_on = geni_se_resources_activate,
.power_off = geni_se_resources_deactivate,
};

static const struct geni_spi_desc sa8255p_geni_spi = {
.resources_init = geni_se_domain_attach,
- .set_rate = geni_se_set_perf_opp,
};

static const struct of_device_id spi_geni_dt_match[] = {

--
2.34.1