]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
clk: twl: add TWL6030 support
authorAndreas Kemnade <andreas@kemnade.info>
Mon, 14 Oct 2024 16:11:09 +0000 (18:11 +0200)
committerStephen Boyd <sboyd@kernel.org>
Thu, 17 Oct 2024 19:02:42 +0000 (12:02 -0700)
The TWL6030 has similar clocks, so add support for it. Take care of the
resource grouping handling needed.

Signed-off-by: Andreas Kemnade <andreas@kemnade.info>
Link: https://lore.kernel.org/r/20241014161109.2222-4-andreas@kemnade.info
Reviewed-by: Roger Quadros <rogerq@kernel.org>
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
drivers/clk/Kconfig
drivers/clk/clk-twl.c

index 299bc678ed1b9fcd9110bb8c5937a1bd1ea60e23..82ec12f9b82c73310b715c78090119f21d4e8474 100644 (file)
@@ -291,7 +291,7 @@ config CLK_TWL
        help
          Enable support for controlling the clock resources on TWL family
          PMICs. These devices have some 32K clock outputs which can be
-         controlled by software. For now, only the TWL6032 clocks are
+         controlled by software. For now, the TWL6032 and TWL6030 clocks are
          supported.
 
 config CLK_TWL6040
index 1d684b3584015378dbe396c55ca549ffad1dfcb9..20bc3bf8fd62d3f92716c09ca4fa81d181bfe4e3 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 
-#define VREG_STATE              2
+#define VREG_STATE             2
+#define VREG_GRP               0
 #define TWL6030_CFG_STATE_OFF   0x00
 #define TWL6030_CFG_STATE_ON    0x01
 #define TWL6030_CFG_STATE_MASK  0x03
+#define TWL6030_CFG_STATE_GRP_SHIFT    5
+#define TWL6030_CFG_STATE_APP_SHIFT    2
+#define TWL6030_CFG_STATE_APP_MASK     (0x03 << TWL6030_CFG_STATE_APP_SHIFT)
+#define TWL6030_CFG_STATE_APP(v)       (((v) & TWL6030_CFG_STATE_APP_MASK) >>\
+                                               TWL6030_CFG_STATE_APP_SHIFT)
+#define P1_GRP BIT(0) /* processor power group */
+#define P2_GRP BIT(1)
+#define P3_GRP BIT(2)
+#define ALL_GRP (P1_GRP | P2_GRP | P3_GRP)
+
+enum twl_type {
+       TWL_TYPE_6030,
+       TWL_TYPE_6032,
+};
 
 struct twl_clock_info {
        struct device *dev;
+       enum twl_type type;
        u8 base;
        struct clk_hw hw;
 };
@@ -56,14 +72,21 @@ static unsigned long twl_clks_recalc_rate(struct clk_hw *hw,
 static int twl6032_clks_prepare(struct clk_hw *hw)
 {
        struct twl_clock_info *cinfo = to_twl_clks_info(hw);
-       int ret;
 
-       ret = twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
-                          TWL6030_CFG_STATE_ON);
-       if (ret < 0)
-               dev_err(cinfo->dev, "clk prepare failed\n");
+       if (cinfo->type == TWL_TYPE_6030) {
+               int grp;
+
+               grp = twlclk_read(cinfo, TWL_MODULE_PM_RECEIVER, VREG_GRP);
+               if (grp < 0)
+                       return grp;
 
-       return ret;
+               return twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
+                                   grp << TWL6030_CFG_STATE_GRP_SHIFT |
+                                   TWL6030_CFG_STATE_ON);
+       }
+
+       return twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
+                           TWL6030_CFG_STATE_ON);
 }
 
 static void twl6032_clks_unprepare(struct clk_hw *hw)
@@ -71,8 +94,14 @@ static void twl6032_clks_unprepare(struct clk_hw *hw)
        struct twl_clock_info *cinfo = to_twl_clks_info(hw);
        int ret;
 
-       ret = twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
-                          TWL6030_CFG_STATE_OFF);
+       if (cinfo->type == TWL_TYPE_6030)
+               ret = twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
+                                  ALL_GRP << TWL6030_CFG_STATE_GRP_SHIFT |
+                                  TWL6030_CFG_STATE_OFF);
+       else
+               ret = twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
+                                  TWL6030_CFG_STATE_OFF);
+
        if (ret < 0)
                dev_err(cinfo->dev, "clk unprepare failed\n");
 }
@@ -138,6 +167,7 @@ static int twl_clks_probe(struct platform_device *pdev)
        for (i = 0; i < count; i++) {
                cinfo[i].base = hw_data[i].base;
                cinfo[i].dev = &pdev->dev;
+               cinfo[i].type = platform_get_device_id(pdev)->driver_data;
                cinfo[i].hw.init = &hw_data[i].init;
                ret = devm_clk_hw_register(&pdev->dev, &cinfo[i].hw);
                if (ret) {
@@ -159,7 +189,11 @@ static int twl_clks_probe(struct platform_device *pdev)
 
 static const struct platform_device_id twl_clks_id[] = {
        {
+               .name = "twl6030-clk",
+               .driver_data = TWL_TYPE_6030,
+       }, {
                .name = "twl6032-clk",
+               .driver_data = TWL_TYPE_6032,
        }, {
                /* sentinel */
        }