From: Biju Das <[email protected]>

The register for controlling power to the DSI region is in the SYSC
(System Controller) block. Add support for controlling the DSI PWRRDY
signal so the driver can efficiently manage power to the DSI region.

Signed-off-by: Biju Das <[email protected]>
---
 .../gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c    | 56 +++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c 
b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
index 180384c10264..8bd664aa69ac 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
@@ -13,11 +13,13 @@
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/math.h>
+#include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_graph.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/regmap.h>
 #include <linux/reset.h>
 #include <linux/slab.h>
 #include <linux/units.h>
@@ -54,6 +56,7 @@ struct rzg2l_mipi_dsi_hw_info {
                const u8 *table;
                const u8 table_size;
        } cpg_plldsi;
+       const struct reg_field *syscon_field;
        const struct rzg2l_mipi_dsi_timings *dsi_global_timings;
        unsigned int num_dsi_global_timings;
        u32 phy_reg_offset;
@@ -87,6 +90,8 @@ struct rzg2l_mipi_dsi {
        struct clk *vclk;
        struct clk *lpclk;
 
+       struct regmap_field *pwrrdy;
+
        enum mipi_dsi_pixel_format format;
        unsigned int num_data_lanes;
        unsigned int lanes;
@@ -1396,6 +1401,53 @@ static const struct dev_pm_ops rzg2l_mipi_pm_ops = {
  * Probe & Remove
  */
 
+static int rzg2l_mipi_dsi_set_pwrrdy(struct rzg2l_mipi_dsi *dsi, bool power_on)
+{
+       u32 val, mask;
+
+       mask = BIT(dsi->info->syscon_field->msb);
+       val = power_on ? 0 : mask;
+
+       return regmap_field_update_bits(dsi->pwrrdy, mask, val);
+}
+
+static void rzg2l_mipi_dsi_pwrrdy_off(void *data)
+{
+       rzg2l_mipi_dsi_set_pwrrdy(data, false);
+}
+
+static int rzg2l_mipi_dsi_pwrrdy_init(struct rzg2l_mipi_dsi *dsi)
+{
+       struct regmap *regmap;
+       u32 args[2];
+       int ret;
+
+       if (!dsi->info->syscon_field)
+               return 0;
+
+       regmap = syscon_regmap_lookup_by_phandle_args(dsi->dev->of_node,
+                                                     "renesas,sysc-pwrrdy",
+                                                    ARRAY_SIZE(args), args);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       if (args[0] != dsi->info->syscon_field->reg)
+               return -EINVAL;
+
+       if (args[1] != BIT(dsi->info->syscon_field->msb))
+               return -EINVAL;
+
+       dsi->pwrrdy = devm_regmap_field_alloc(dsi->dev, regmap, 
*dsi->info->syscon_field);
+       if (IS_ERR(dsi->pwrrdy))
+               return PTR_ERR(dsi->pwrrdy);
+
+       ret = rzg2l_mipi_dsi_set_pwrrdy(dsi, true);
+       if (ret)
+               return ret;
+
+       return devm_add_action_or_reset(dsi->dev, rzg2l_mipi_dsi_pwrrdy_off, 
dsi);
+}
+
 static int rzg2l_mipi_dsi_probe(struct platform_device *pdev)
 {
        unsigned int num_data_lanes;
@@ -1424,6 +1476,10 @@ static int rzg2l_mipi_dsi_probe(struct platform_device 
*pdev)
        if (IS_ERR(dsi->mmio))
                return PTR_ERR(dsi->mmio);
 
+       ret = rzg2l_mipi_dsi_pwrrdy_init(dsi);
+       if (ret)
+               return ret;
+
        dsi->vclk = devm_clk_get(dsi->dev, "vclk");
        if (IS_ERR(dsi->vclk))
                return PTR_ERR(dsi->vclk);
-- 
2.43.0

Reply via email to