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>
---
drivers/clk/Kconfig | 2 +-
drivers/clk/clk-twl.c | 54 +++++++++++++++++++++++++++++++++----------
2 files changed, 43 insertions(+), 13 deletions(-)
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 299bc678ed1b..82ec12f9b82c 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -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
diff --git a/drivers/clk/clk-twl.c b/drivers/clk/clk-twl.c
index 1d684b358401..f3a52f568887 100644
--- a/drivers/clk/clk-twl.c
+++ b/drivers/clk/clk-twl.c
@@ -11,13 +11,26 @@
#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)
+
+#define DRIVER_DATA_TWL6030 0
+#define DRIVER_DATA_TWL6032 1
struct twl_clock_info {
- struct device *dev;
+ struct platform_device *pdev;
u8 base;
struct clk_hw hw;
};
@@ -56,14 +69,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 (platform_get_device_id(cinfo->pdev)->driver_data == DRIVER_DATA_TWL6030) {
+ int grp;
- return ret;
+ grp = twlclk_read(cinfo, TWL_MODULE_PM_RECEIVER, VREG_GRP);
+ if (grp < 0)
+ return grp;
+
+ 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,10 +91,16 @@ 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 (platform_get_device_id(cinfo->pdev)->driver_data == DRIVER_DATA_TWL6030)
+ 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");
+ dev_err(&cinfo->pdev->dev, "clk unprepare failed\n");
}
static const struct clk_ops twl6032_clks_ops = {
@@ -137,7 +163,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].pdev = pdev;
cinfo[i].hw.init = &hw_data[i].init;
ret = devm_clk_hw_register(&pdev->dev, &cinfo[i].hw);
if (ret) {
@@ -159,7 +185,11 @@ static int twl_clks_probe(struct platform_device *pdev)
static const struct platform_device_id twl_clks_id[] = {
{
+ .name = "twl6030-clk",
+ .driver_data = DRIVER_DATA_TWL6030,
+ }, {
.name = "twl6032-clk",
+ .driver_data = DRIVER_DATA_TWL6032,
}, {
/* sentinel */
}
--
2.39.5
On 02/10/2024 14:07, Andreas Kemnade wrote: > 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> > --- > drivers/clk/Kconfig | 2 +- > drivers/clk/clk-twl.c | 54 +++++++++++++++++++++++++++++++++---------- > 2 files changed, 43 insertions(+), 13 deletions(-) > > diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig > index 299bc678ed1b..82ec12f9b82c 100644 > --- a/drivers/clk/Kconfig > +++ b/drivers/clk/Kconfig > @@ -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 > diff --git a/drivers/clk/clk-twl.c b/drivers/clk/clk-twl.c > index 1d684b358401..f3a52f568887 100644 > --- a/drivers/clk/clk-twl.c > +++ b/drivers/clk/clk-twl.c > @@ -11,13 +11,26 @@ > #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) > + > +#define DRIVER_DATA_TWL6030 0 > +#define DRIVER_DATA_TWL6032 1 how about using enum here? enum twl_type { TWL_TYPE_6030, TWL_TYPE_6032, }; > > struct twl_clock_info { > - struct device *dev; > + struct platform_device *pdev; I wouldn't change this. Instead, you can add twl_type member here and initialize it in probe. enum twl_type type; > u8 base; > struct clk_hw hw; > }; > @@ -56,14 +69,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 (platform_get_device_id(cinfo->pdev)->driver_data == DRIVER_DATA_TWL6030) { this changes to if (cinfo->type == TWL_TYPE_6030) > + int grp; > > - return ret; > + grp = twlclk_read(cinfo, TWL_MODULE_PM_RECEIVER, VREG_GRP); > + if (grp < 0) > + return grp; > + > + 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,10 +91,16 @@ 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 (platform_get_device_id(cinfo->pdev)->driver_data == DRIVER_DATA_TWL6030) here too. > + 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"); > + dev_err(&cinfo->pdev->dev, "clk unprepare failed\n"); > } > > static const struct clk_ops twl6032_clks_ops = { > @@ -137,7 +163,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].pdev = pdev; here we can initialize twl type like so. 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 +185,11 @@ static int twl_clks_probe(struct platform_device *pdev) > > static const struct platform_device_id twl_clks_id[] = { > { > + .name = "twl6030-clk", > + .driver_data = DRIVER_DATA_TWL6030, TWL_TYPE_6030 > + }, { > .name = "twl6032-clk", > + .driver_data = DRIVER_DATA_TWL6032, TWL_TYPE_6032 > }, { > /* sentinel */ > } -- cheers, -roger
© 2016 - 2024 Red Hat, Inc.