On Fri Jul 31 10:54:34 2026 +0200, Loic Poulain wrote:
> Add optional PM clock support to the CAMSS driver using the PM clock
> framework. This allows CAMSS clocks to be registered once and
> automatically managed during runtime suspend and resume.
> 
> This is especially useful for global CAMSS clocks that are shared across
> multiple CAMSS subblocks.
> 
> This avoids the need for each subblock to reference and manage the
> shared clocks individually. A typical example is the set of clocks in
> the top_group, which may be used by CSID, PHY, CCI, and other CAMSS
> blocks.
> 
> Introduce a small PM clock descriptor table in the CAMSS resources
> structure to describe clocks and their optional rates. Initialize
> these clocks at probe time and delegate clock ownership to the PM
> core.
> 
> Hook PM clock handling into the runtime PM callbacks to ensure clocks
> are properly suspended and resumed alongside power domains and ICC
> paths.
> 
> Reviewed-by: Bryan O'Donoghue <[email protected]>
> Reviewed-by: Frank Li <[email protected]>
> Signed-off-by: Loic Poulain <[email protected]>
> Signed-off-by: Bryan O'Donoghue <[email protected]>

Patch committed.

Thanks,
Bryan O'Donoghue

 drivers/media/platform/qcom/camss/camss.c | 49 +++++++++++++++++++++++++++++++
 drivers/media/platform/qcom/camss/camss.h |  1 +
 2 files changed, 50 insertions(+)

---

diff --git a/drivers/media/platform/qcom/camss/camss.c 
b/drivers/media/platform/qcom/camss/camss.c
index e4d0128a3d19..d1969a7fda13 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -18,6 +18,7 @@
 #include <linux/of_graph.h>
 #include <linux/pm_runtime.h>
 #include <linux/pm_domain.h>
+#include <linux/pm_clock.h>
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 
@@ -5344,6 +5345,40 @@ static void camss_genpd_cleanup(struct camss *camss)
        dev_pm_domain_detach(camss->genpd, true);
 }
 
+/*
+ * camss_init_pm_clks - set up shared CAMSS clocks
+ *
+ * Clocks listed in res->pm_clks are shared across all CAMSS sub-devices
+ * (e.g. top_ahb, axi).
+ */
+static int camss_init_pm_clks(struct camss *camss)
+{
+       struct device *dev = camss->dev;
+       unsigned int i;
+       int ret;
+
+       if (!camss->res->pm_clks[0])
+               return 0;
+
+       if (IS_ENABLED(CONFIG_PM_CLK)) {
+               ret = devm_pm_clk_create(dev);
+               if (ret)
+                       return ret;
+       }
+
+       for (i = 0; i < CAMSS_RES_MAX && camss->res->pm_clks[i]; i++) {
+               if (IS_ENABLED(CONFIG_PM_CLK))
+                       ret = pm_clk_add(dev, camss->res->pm_clks[i]);
+               else
+                       ret = PTR_ERR_OR_ZERO(devm_clk_get_enabled(dev, 
camss->res->pm_clks[i]));
+               if (ret)
+                       return dev_err_probe(dev, ret, "failed to set up pm 
clock %s\n",
+                                            camss->res->pm_clks[i]);
+       }
+
+       return 0;
+}
+
 /*
  * camss_probe - Probe CAMSS platform device
  * @pdev: Pointer to CAMSS platform device
@@ -5432,6 +5467,10 @@ static int camss_probe(struct platform_device *pdev)
 
        pm_runtime_enable(dev);
 
+       ret = camss_init_pm_clks(camss);
+       if (ret)
+               goto err_v4l2_device_unregister;
+
        ret = camss_parse_ports(camss);
        if (ret < 0)
                goto err_v4l2_device_unregister;
@@ -5773,7 +5812,11 @@ static int __maybe_unused camss_runtime_suspend(struct 
device *dev)
                        return ret;
        }
 
+#if IS_ENABLED(CONFIG_PM_CLK)
+       return pm_clk_suspend(dev);
+#else
        return 0;
+#endif
 }
 
 static int __maybe_unused camss_runtime_resume(struct device *dev)
@@ -5783,6 +5826,12 @@ static int __maybe_unused camss_runtime_resume(struct 
device *dev)
        int i;
        int ret;
 
+#if IS_ENABLED(CONFIG_PM_CLK)
+       ret = pm_clk_resume(dev);
+       if (ret)
+               return ret;
+#endif
+
        for (i = 0; i < camss->res->icc_path_num; i++) {
                ret = icc_set_bw(camss->icc_path[i],
                                 icc_res[i].icc_bw_tbl.avg,
diff --git a/drivers/media/platform/qcom/camss/camss.h 
b/drivers/media/platform/qcom/camss/camss.h
index 93d691c8ac63..fe5fe25d5f18 100644
--- a/drivers/media/platform/qcom/camss/camss.h
+++ b/drivers/media/platform/qcom/camss/camss.h
@@ -107,6 +107,7 @@ enum icc_count {
 struct camss_resources {
        enum camss_version version;
        const char *pd_name;
+       const char *pm_clks[CAMSS_RES_MAX];
        const struct camss_subdev_resources *csiphy_res;
        const struct camss_subdev_resources *tpg_res;
        const struct camss_subdev_resources *csid_res;
_______________________________________________
linuxtv-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to