* [PATCH v4 0/7] Add versaclock3 support for RZ/V2H
@ 2026-03-02 16:54 Ovidiu Panait
2026-03-02 16:54 ` [PATCH v4 1/7] clk: versaclock3: Fix NULL pointer dereference in error path Ovidiu Panait
` (7 more replies)
0 siblings, 8 replies; 10+ messages in thread
From: Ovidiu Panait @ 2026-03-02 16:54 UTC (permalink / raw)
To: geert+renesas, magnus.damm, robh, krzk+dt, conor+dt, mturquette,
sboyd, biju.das.jz, fabrizio.castro.jz
Cc: linux-renesas-soc, devicetree, linux-kernel, linux-clk
Hi,
This series extends the versaclock3 driver to support registering multiple
devices at the same time, and adds support for the internal freerunning
32.768 kHz clock. The 32k clock is used on the Renesas RZ/V2H SoC as RTC
counter clock.
The dts nodes for the RZ/V2H EVK was updated to describe the versa3
devices found on the boards.
Best regards,
Ovidiu
v4:
- Used the I2C device name to make the clock names unique, instaed of the
dts node name.
- Dropped the RZ/V2N dts patch from this series, as the latest RZ/V2N EVK
board revision (v2) does not connect the versa3 chip to the I2C bus
anymore. The PCIe and audio cloks will be added when support for those
respective interfaces is added.
v3: https://lore.kernel.org/all/20260203135139.28151-1-ovidiu.panait.rb@renesas.com/
- Fixed a NULL pointer dereference on the error paths.
- Added support for registering multiple versa3 instances at the same time.
- Made clock names unique by prefixing them with the DT node name.
- Rebased the internal 32k clock patch to match the new logic.
- Added comments in RZ/V2H and RZ/V2N board dts to document rtxin_clk and
qextal_clk routing.
v2: https://lore.kernel.org/all/20260120150606.7356-1-ovidiu.panait.rb@renesas.com/
- Added versaclock3 dts node for RZ/V2N EVK.
v1: https://lore.kernel.org/all/20251021175311.19611-1-ovidiu.panait.rb@renesas.com/
Ovidiu Panait (7):
clk: versaclock3: Fix NULL pointer dereference in error path
clk: versaclock3: Remove unused SE2 clock select macro
clk: versaclock3: Reference parent clocks by type and index
clk: versaclock3: Add per-device clock data structure
clk: versaclock3: Prefix clock names with device name
clk: versaclock3: Add freerunning 32.768kHz clock support
arm64: dts: renesas: r9a09g057h44-rzv2h-evk: Add versa3 clock
generator node
.../dts/renesas/r9a09g057h44-rzv2h-evk.dts | 25 +
drivers/clk/clk-versaclock3.c | 618 +++++++++++++-----
2 files changed, 481 insertions(+), 162 deletions(-)
--
2.51.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 1/7] clk: versaclock3: Fix NULL pointer dereference in error path
2026-03-02 16:54 [PATCH v4 0/7] Add versaclock3 support for RZ/V2H Ovidiu Panait
@ 2026-03-02 16:54 ` Ovidiu Panait
2026-03-02 16:54 ` [PATCH v4 2/7] clk: versaclock3: Remove unused SE2 clock select macro Ovidiu Panait
` (6 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Ovidiu Panait @ 2026-03-02 16:54 UTC (permalink / raw)
To: geert+renesas, magnus.damm, robh, krzk+dt, conor+dt, mturquette,
sboyd, biju.das.jz, fabrizio.castro.jz
Cc: linux-renesas-soc, devicetree, linux-kernel, linux-clk
If devm_clk_hw_register() fails, the driver logs an error using
hw.init->name. However, the clock core sets hw->init to NULL in
__clk_register() immediately after registration, regardless of
success or failure. This leads to a NULL pointer dereference.
To fix this, save the clock name before registration and use the
saved pointer in the error message. While at it, improve the error
message to make it more clear.
Fixes: 6e9aff555db7 ("clk: Add support for versa3 clock driver")
Signed-off-by: Ovidiu Panait <ovidiu.panait.rb@renesas.com>
---
v4 changes: None.
v3 changes: New patch.
drivers/clk/clk-versaclock3.c | 36 +++++++++++++++++++++++------------
1 file changed, 24 insertions(+), 12 deletions(-)
diff --git a/drivers/clk/clk-versaclock3.c b/drivers/clk/clk-versaclock3.c
index 27b6cf70f3ae..6dcf3d94db7b 100644
--- a/drivers/clk/clk-versaclock3.c
+++ b/drivers/clk/clk-versaclock3.c
@@ -1031,19 +1031,23 @@ static int vc3_probe(struct i2c_client *client)
/* Register pfd muxes */
for (i = 0; i < ARRAY_SIZE(clk_pfd_mux); i++) {
clk_pfd_mux[i].regmap = regmap;
+ name = clk_pfd_mux[i].hw.init->name;
ret = devm_clk_hw_register(dev, &clk_pfd_mux[i].hw);
if (ret)
- return dev_err_probe(dev, ret, "%s failed\n",
- clk_pfd_mux[i].hw.init->name);
+ return dev_err_probe(dev, ret,
+ "failed to register clock %s\n",
+ name);
}
/* Register pfd's */
for (i = 0; i < ARRAY_SIZE(clk_pfd); i++) {
clk_pfd[i].regmap = regmap;
+ name = clk_pfd[i].hw.init->name;
ret = devm_clk_hw_register(dev, &clk_pfd[i].hw);
if (ret)
- return dev_err_probe(dev, ret, "%s failed\n",
- clk_pfd[i].hw.init->name);
+ return dev_err_probe(dev, ret,
+ "failed to register clock %s\n",
+ name);
}
data = i2c_get_match_data(client);
@@ -1056,28 +1060,34 @@ static int vc3_probe(struct i2c_client *client)
pll_data->vco = data->pll2_vco;
}
+ name = clk_pll[i].hw.init->name;
ret = devm_clk_hw_register(dev, &clk_pll[i].hw);
if (ret)
- return dev_err_probe(dev, ret, "%s failed\n",
- clk_pll[i].hw.init->name);
+ return dev_err_probe(dev, ret,
+ "failed to register clock %s\n",
+ name);
}
/* Register divider muxes */
for (i = 0; i < ARRAY_SIZE(clk_div_mux); i++) {
clk_div_mux[i].regmap = regmap;
+ name = clk_div_mux[i].hw.init->name;
ret = devm_clk_hw_register(dev, &clk_div_mux[i].hw);
if (ret)
- return dev_err_probe(dev, ret, "%s failed\n",
- clk_div_mux[i].hw.init->name);
+ return dev_err_probe(dev, ret,
+ "failed to register clock %s\n",
+ name);
}
/* Register dividers */
for (i = 0; i < ARRAY_SIZE(clk_div); i++) {
clk_div[i].regmap = regmap;
+ name = clk_div[i].hw.init->name;
ret = devm_clk_hw_register(dev, &clk_div[i].hw);
if (ret)
- return dev_err_probe(dev, ret, "%s failed\n",
- clk_div[i].hw.init->name);
+ return dev_err_probe(dev, ret,
+ "failed to register clock %s\n",
+ name);
}
/* Register clk muxes */
@@ -1088,10 +1098,12 @@ static int vc3_probe(struct i2c_client *client)
clk_data->bitmsk = data->se2_clk_sel_msk;
}
+ name = clk_mux[i].hw.init->name;
ret = devm_clk_hw_register(dev, &clk_mux[i].hw);
if (ret)
- return dev_err_probe(dev, ret, "%s failed\n",
- clk_mux[i].hw.init->name);
+ return dev_err_probe(dev, ret,
+ "failed to register clock %s\n",
+ name);
}
/* Register clk outputs */
--
2.51.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 2/7] clk: versaclock3: Remove unused SE2 clock select macro
2026-03-02 16:54 [PATCH v4 0/7] Add versaclock3 support for RZ/V2H Ovidiu Panait
2026-03-02 16:54 ` [PATCH v4 1/7] clk: versaclock3: Fix NULL pointer dereference in error path Ovidiu Panait
@ 2026-03-02 16:54 ` Ovidiu Panait
2026-03-02 16:54 ` [PATCH v4 3/7] clk: versaclock3: Reference parent clocks by type and index Ovidiu Panait
` (5 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Ovidiu Panait @ 2026-03-02 16:54 UTC (permalink / raw)
To: geert+renesas, magnus.damm, robh, krzk+dt, conor+dt, mturquette,
sboyd, biju.das.jz, fabrizio.castro.jz
Cc: linux-renesas-soc, devicetree, linux-kernel, linux-clk
The VC3_SE2_CTRL_REG0_SE2_CLK_SEL macro is no longer used since
commit ae6040cd7c7f8 ("clk: versaclock3: Prepare for the addition of
5L35023 device"), which switched SE2 clock select handling to use
variant-specific OF data (se2_clk_sel_msk).
Reviewed-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
Signed-off-by: Ovidiu Panait <ovidiu.panait.rb@renesas.com>
---
v4 changes: None.
v3 changes:
- Added "Reviewed-by" tag from Fabrizio.
drivers/clk/clk-versaclock3.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/clk/clk-versaclock3.c b/drivers/clk/clk-versaclock3.c
index 6dcf3d94db7b..18ef0f38c85b 100644
--- a/drivers/clk/clk-versaclock3.c
+++ b/drivers/clk/clk-versaclock3.c
@@ -61,7 +61,6 @@
#define VC3_OUTPUT_CTR_DIV4_SRC_SEL BIT(3)
#define VC3_SE2_CTRL_REG0 0x1f
-#define VC3_SE2_CTRL_REG0_SE2_CLK_SEL BIT(6)
#define VC3_SE3_DIFF1_CTRL_REG 0x21
#define VC3_SE3_DIFF1_CTRL_REG_SE3_CLK_SEL BIT(6)
--
2.51.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 3/7] clk: versaclock3: Reference parent clocks by type and index
2026-03-02 16:54 [PATCH v4 0/7] Add versaclock3 support for RZ/V2H Ovidiu Panait
2026-03-02 16:54 ` [PATCH v4 1/7] clk: versaclock3: Fix NULL pointer dereference in error path Ovidiu Panait
2026-03-02 16:54 ` [PATCH v4 2/7] clk: versaclock3: Remove unused SE2 clock select macro Ovidiu Panait
@ 2026-03-02 16:54 ` Ovidiu Panait
2026-03-02 16:54 ` [PATCH v4 4/7] clk: versaclock3: Add per-device clock data structure Ovidiu Panait
` (4 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Ovidiu Panait @ 2026-03-02 16:54 UTC (permalink / raw)
To: geert+renesas, magnus.damm, robh, krzk+dt, conor+dt, mturquette,
sboyd, biju.das.jz, fabrizio.castro.jz
Cc: linux-renesas-soc, devicetree, linux-kernel, linux-clk
The current implementation uses direct pointers to clk_hw structures
(via .parent_hws) to define parent-child relationships between clocks.
This works for a single device instance but prevents supporting multiple
devices since all instances would share the same static clk_hw pointers.
Replace direct pointers with parent references using a type and index
pair. For example, VC3_CLK_PARENT(PLL, VC3_PLL1) refers to the first
PLL clock. These references are resolved to actual clk_hw pointers at
probe time by the new vc3_register_clk() function.
This is a preparatory change for adding support for multiple versaclock3
instances, where each device will have its own set of clk_hw structures.
Signed-off-by: Ovidiu Panait <ovidiu.panait.rb@renesas.com>
---
v4 changes: None.
v3 changes: New patch.
drivers/clk/clk-versaclock3.c | 401 +++++++++++++++++++++++-----------
1 file changed, 276 insertions(+), 125 deletions(-)
diff --git a/drivers/clk/clk-versaclock3.c b/drivers/clk/clk-versaclock3.c
index 18ef0f38c85b..d3e23566a38c 100644
--- a/drivers/clk/clk-versaclock3.c
+++ b/drivers/clk/clk-versaclock3.c
@@ -83,6 +83,8 @@
#define VC3_2_POW_16 (U16_MAX + 1)
#define VC3_DIV_MASK(width) ((1 << (width)) - 1)
+#define VC3_CLK_PARENT(t, i) { .type = VC3_CLK_##t, .idx = (i) }
+
enum vc3_pfd_mux {
VC3_PFD2_MUX,
VC3_PFD3_MUX,
@@ -131,6 +133,26 @@ enum vc3_clk_mux {
VC3_DIFF2_MUX = VC3_DIFF2 - 1,
};
+enum vc3_clk_type {
+ VC3_CLK_EXT,
+ VC3_CLK_PFD_MUX,
+ VC3_CLK_PFD,
+ VC3_CLK_PLL,
+ VC3_CLK_DIV_MUX,
+ VC3_CLK_DIV,
+ VC3_CLK_CLK_MUX,
+};
+
+struct vc3_clk_parent {
+ enum vc3_clk_type type;
+ u8 idx;
+};
+
+struct vc3_parent_info {
+ const struct vc3_clk_parent *parents;
+ u8 num_parents;
+};
+
struct vc3_clk_data {
u8 offs;
u8 bitmsk;
@@ -164,6 +186,7 @@ struct vc3_div_data {
};
struct vc3_hw_data {
+ const struct vc3_parent_info *parent_info;
struct clk_hw hw;
struct regmap *regmap;
void *data;
@@ -598,11 +621,12 @@ static const struct regmap_config vc3_regmap_config = {
.max_register = 0x24,
};
-static struct vc3_hw_data clk_div[5];
-
-static const struct clk_parent_data pfd_mux_parent_data[] = {
- { .index = 0, },
- { .hw = &clk_div[VC3_DIV2].hw }
+static const struct vc3_parent_info pfd_mux_parents = {
+ .parents = (const struct vc3_clk_parent[]) {
+ VC3_CLK_PARENT(EXT, 0),
+ VC3_CLK_PARENT(DIV, VC3_DIV2),
+ },
+ .num_parents = 2,
};
static struct vc3_hw_data clk_pfd_mux[] = {
@@ -614,10 +638,9 @@ static struct vc3_hw_data clk_pfd_mux[] = {
.hw.init = &(struct clk_init_data) {
.name = "pfd2_mux",
.ops = &vc3_pfd_mux_ops,
- .parent_data = pfd_mux_parent_data,
- .num_parents = 2,
.flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT
- }
+ },
+ .parent_info = &pfd_mux_parents,
},
[VC3_PFD3_MUX] = {
.data = &(struct vc3_clk_data) {
@@ -627,13 +650,33 @@ static struct vc3_hw_data clk_pfd_mux[] = {
.hw.init = &(struct clk_init_data) {
.name = "pfd3_mux",
.ops = &vc3_pfd_mux_ops,
- .parent_data = pfd_mux_parent_data,
- .num_parents = 2,
.flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT
- }
+ },
+ .parent_info = &pfd_mux_parents,
}
};
+static const struct vc3_parent_info pfd_parents[] = {
+ [VC3_PFD1] = {
+ .parents = (const struct vc3_clk_parent[]) {
+ VC3_CLK_PARENT(EXT, 0),
+ },
+ .num_parents = 1,
+ },
+ [VC3_PFD2] = {
+ .parents = (const struct vc3_clk_parent[]) {
+ VC3_CLK_PARENT(PFD_MUX, VC3_PFD2_MUX),
+ },
+ .num_parents = 1,
+ },
+ [VC3_PFD3] = {
+ .parents = (const struct vc3_clk_parent[]) {
+ VC3_CLK_PARENT(PFD_MUX, VC3_PFD3_MUX),
+ },
+ .num_parents = 1,
+ },
+};
+
static struct vc3_hw_data clk_pfd[] = {
[VC3_PFD1] = {
.data = &(struct vc3_pfd_data) {
@@ -645,12 +688,9 @@ static struct vc3_hw_data clk_pfd[] = {
.hw.init = &(struct clk_init_data) {
.name = "pfd1",
.ops = &vc3_pfd_ops,
- .parent_data = &(const struct clk_parent_data) {
- .index = 0
- },
- .num_parents = 1,
.flags = CLK_SET_RATE_PARENT
- }
+ },
+ .parent_info = &pfd_parents[VC3_PFD1],
},
[VC3_PFD2] = {
.data = &(struct vc3_pfd_data) {
@@ -662,12 +702,9 @@ static struct vc3_hw_data clk_pfd[] = {
.hw.init = &(struct clk_init_data) {
.name = "pfd2",
.ops = &vc3_pfd_ops,
- .parent_hws = (const struct clk_hw *[]) {
- &clk_pfd_mux[VC3_PFD2_MUX].hw
- },
- .num_parents = 1,
.flags = CLK_SET_RATE_PARENT
- }
+ },
+ .parent_info = &pfd_parents[VC3_PFD2],
},
[VC3_PFD3] = {
.data = &(struct vc3_pfd_data) {
@@ -679,15 +716,33 @@ static struct vc3_hw_data clk_pfd[] = {
.hw.init = &(struct clk_init_data) {
.name = "pfd3",
.ops = &vc3_pfd_ops,
- .parent_hws = (const struct clk_hw *[]) {
- &clk_pfd_mux[VC3_PFD3_MUX].hw
- },
- .num_parents = 1,
.flags = CLK_SET_RATE_PARENT
- }
+ },
+ .parent_info = &pfd_parents[VC3_PFD3],
}
};
+static const struct vc3_parent_info pll_parents[] = {
+ [VC3_PLL1] = {
+ .parents = (const struct vc3_clk_parent[]) {
+ VC3_CLK_PARENT(PFD, VC3_PFD1),
+ },
+ .num_parents = 1,
+ },
+ [VC3_PLL2] = {
+ .parents = (const struct vc3_clk_parent[]) {
+ VC3_CLK_PARENT(PFD, VC3_PFD2),
+ },
+ .num_parents = 1,
+ },
+ [VC3_PLL3] = {
+ .parents = (const struct vc3_clk_parent[]) {
+ VC3_CLK_PARENT(PFD, VC3_PFD3),
+ },
+ .num_parents = 1,
+ },
+};
+
static struct vc3_hw_data clk_pll[] = {
[VC3_PLL1] = {
.data = &(struct vc3_pll_data) {
@@ -702,12 +757,9 @@ static struct vc3_hw_data clk_pll[] = {
.hw.init = &(struct clk_init_data) {
.name = "pll1",
.ops = &vc3_pll_ops,
- .parent_hws = (const struct clk_hw *[]) {
- &clk_pfd[VC3_PFD1].hw
- },
- .num_parents = 1,
.flags = CLK_SET_RATE_PARENT
- }
+ },
+ .parent_info = &pll_parents[VC3_PLL1],
},
[VC3_PLL2] = {
.data = &(struct vc3_pll_data) {
@@ -718,12 +770,9 @@ static struct vc3_hw_data clk_pll[] = {
.hw.init = &(struct clk_init_data) {
.name = "pll2",
.ops = &vc3_pll_ops,
- .parent_hws = (const struct clk_hw *[]) {
- &clk_pfd[VC3_PFD2].hw
- },
- .num_parents = 1,
.flags = CLK_SET_RATE_PARENT
- }
+ },
+ .parent_info = &pll_parents[VC3_PLL2],
},
[VC3_PLL3] = {
.data = &(struct vc3_pll_data) {
@@ -738,28 +787,34 @@ static struct vc3_hw_data clk_pll[] = {
.hw.init = &(struct clk_init_data) {
.name = "pll3",
.ops = &vc3_pll_ops,
- .parent_hws = (const struct clk_hw *[]) {
- &clk_pfd[VC3_PFD3].hw
- },
- .num_parents = 1,
.flags = CLK_SET_RATE_PARENT
- }
+ },
+ .parent_info = &pll_parents[VC3_PLL3],
}
};
-static const struct clk_parent_data div_mux_parent_data[][2] = {
+static const struct vc3_parent_info div_mux_parents[] = {
[VC3_DIV1_MUX] = {
- { .hw = &clk_pll[VC3_PLL1].hw },
- { .index = 0 }
+ .parents = (const struct vc3_clk_parent[]) {
+ VC3_CLK_PARENT(PLL, VC3_PLL1),
+ VC3_CLK_PARENT(EXT, 0),
+ },
+ .num_parents = 2,
},
[VC3_DIV3_MUX] = {
- { .hw = &clk_pll[VC3_PLL2].hw },
- { .hw = &clk_pll[VC3_PLL3].hw }
+ .parents = (const struct vc3_clk_parent[]) {
+ VC3_CLK_PARENT(PLL, VC3_PLL2),
+ VC3_CLK_PARENT(PLL, VC3_PLL3),
+ },
+ .num_parents = 2,
},
[VC3_DIV4_MUX] = {
- { .hw = &clk_pll[VC3_PLL2].hw },
- { .index = 0 }
- }
+ .parents = (const struct vc3_clk_parent[]) {
+ VC3_CLK_PARENT(PLL, VC3_PLL2),
+ VC3_CLK_PARENT(EXT, 0),
+ },
+ .num_parents = 2,
+ },
};
static struct vc3_hw_data clk_div_mux[] = {
@@ -771,10 +826,9 @@ static struct vc3_hw_data clk_div_mux[] = {
.hw.init = &(struct clk_init_data) {
.name = "div1_mux",
.ops = &vc3_div_mux_ops,
- .parent_data = div_mux_parent_data[VC3_DIV1_MUX],
- .num_parents = 2,
.flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT
- }
+ },
+ .parent_info = &div_mux_parents[VC3_DIV1_MUX],
},
[VC3_DIV3_MUX] = {
.data = &(struct vc3_clk_data) {
@@ -784,10 +838,9 @@ static struct vc3_hw_data clk_div_mux[] = {
.hw.init = &(struct clk_init_data) {
.name = "div3_mux",
.ops = &vc3_div_mux_ops,
- .parent_data = div_mux_parent_data[VC3_DIV3_MUX],
- .num_parents = 2,
.flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT
- }
+ },
+ .parent_info = &div_mux_parents[VC3_DIV3_MUX],
},
[VC3_DIV4_MUX] = {
.data = &(struct vc3_clk_data) {
@@ -797,13 +850,45 @@ static struct vc3_hw_data clk_div_mux[] = {
.hw.init = &(struct clk_init_data) {
.name = "div4_mux",
.ops = &vc3_div_mux_ops,
- .parent_data = div_mux_parent_data[VC3_DIV4_MUX],
- .num_parents = 2,
.flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT
- }
+ },
+ .parent_info = &div_mux_parents[VC3_DIV4_MUX],
}
};
+static const struct vc3_parent_info div_parents[] = {
+ [VC3_DIV1] = {
+ .parents = (const struct vc3_clk_parent[]) {
+ VC3_CLK_PARENT(DIV_MUX, VC3_DIV1_MUX),
+ },
+ .num_parents = 1,
+ },
+ [VC3_DIV2] = {
+ .parents = (const struct vc3_clk_parent[]) {
+ VC3_CLK_PARENT(PLL, VC3_PLL1),
+ },
+ .num_parents = 1,
+ },
+ [VC3_DIV3] = {
+ .parents = (const struct vc3_clk_parent[]) {
+ VC3_CLK_PARENT(DIV_MUX, VC3_DIV3_MUX),
+ },
+ .num_parents = 1,
+ },
+ [VC3_DIV4] = {
+ .parents = (const struct vc3_clk_parent[]) {
+ VC3_CLK_PARENT(DIV_MUX, VC3_DIV4_MUX),
+ },
+ .num_parents = 1,
+ },
+ [VC3_DIV5] = {
+ .parents = (const struct vc3_clk_parent[]) {
+ VC3_CLK_PARENT(PLL, VC3_PLL3),
+ },
+ .num_parents = 1,
+ },
+};
+
static struct vc3_hw_data clk_div[] = {
[VC3_DIV1] = {
.data = &(struct vc3_div_data) {
@@ -816,12 +901,9 @@ static struct vc3_hw_data clk_div[] = {
.hw.init = &(struct clk_init_data) {
.name = "div1",
.ops = &vc3_div_ops,
- .parent_hws = (const struct clk_hw *[]) {
- &clk_div_mux[VC3_DIV1_MUX].hw
- },
- .num_parents = 1,
.flags = CLK_SET_RATE_PARENT
- }
+ },
+ .parent_info = &div_parents[VC3_DIV1],
},
[VC3_DIV2] = {
.data = &(struct vc3_div_data) {
@@ -834,12 +916,9 @@ static struct vc3_hw_data clk_div[] = {
.hw.init = &(struct clk_init_data) {
.name = "div2",
.ops = &vc3_div_ops,
- .parent_hws = (const struct clk_hw *[]) {
- &clk_pll[VC3_PLL1].hw
- },
- .num_parents = 1,
.flags = CLK_SET_RATE_PARENT
- }
+ },
+ .parent_info = &div_parents[VC3_DIV2],
},
[VC3_DIV3] = {
.data = &(struct vc3_div_data) {
@@ -852,12 +931,9 @@ static struct vc3_hw_data clk_div[] = {
.hw.init = &(struct clk_init_data) {
.name = "div3",
.ops = &vc3_div_ops,
- .parent_hws = (const struct clk_hw *[]) {
- &clk_div_mux[VC3_DIV3_MUX].hw
- },
- .num_parents = 1,
.flags = CLK_SET_RATE_PARENT
- }
+ },
+ .parent_info = &div_parents[VC3_DIV3],
},
[VC3_DIV4] = {
.data = &(struct vc3_div_data) {
@@ -870,12 +946,9 @@ static struct vc3_hw_data clk_div[] = {
.hw.init = &(struct clk_init_data) {
.name = "div4",
.ops = &vc3_div_ops,
- .parent_hws = (const struct clk_hw *[]) {
- &clk_div_mux[VC3_DIV4_MUX].hw
- },
- .num_parents = 1,
.flags = CLK_SET_RATE_PARENT
- }
+ },
+ .parent_info = &div_parents[VC3_DIV4],
},
[VC3_DIV5] = {
.data = &(struct vc3_div_data) {
@@ -888,15 +961,50 @@ static struct vc3_hw_data clk_div[] = {
.hw.init = &(struct clk_init_data) {
.name = "div5",
.ops = &vc3_div_ops,
- .parent_hws = (const struct clk_hw *[]) {
- &clk_pll[VC3_PLL3].hw
- },
- .num_parents = 1,
.flags = CLK_SET_RATE_PARENT
- }
+ },
+ .parent_info = &div_parents[VC3_DIV5],
}
};
+static const struct vc3_parent_info clk_mux_parents[] = {
+ [VC3_SE1_MUX] = {
+ .parents = (const struct vc3_clk_parent[]) {
+ VC3_CLK_PARENT(DIV, VC3_DIV5),
+ VC3_CLK_PARENT(DIV, VC3_DIV4),
+ },
+ .num_parents = 2,
+ },
+ [VC3_SE2_MUX] = {
+ .parents = (const struct vc3_clk_parent[]) {
+ VC3_CLK_PARENT(DIV, VC3_DIV5),
+ VC3_CLK_PARENT(DIV, VC3_DIV4),
+ },
+ .num_parents = 2,
+ },
+ [VC3_SE3_MUX] = {
+ .parents = (const struct vc3_clk_parent[]) {
+ VC3_CLK_PARENT(DIV, VC3_DIV2),
+ VC3_CLK_PARENT(DIV, VC3_DIV4),
+ },
+ .num_parents = 2,
+ },
+ [VC3_DIFF1_MUX] = {
+ .parents = (const struct vc3_clk_parent[]) {
+ VC3_CLK_PARENT(DIV, VC3_DIV1),
+ VC3_CLK_PARENT(DIV, VC3_DIV3),
+ },
+ .num_parents = 2,
+ },
+ [VC3_DIFF2_MUX] = {
+ .parents = (const struct vc3_clk_parent[]) {
+ VC3_CLK_PARENT(DIV, VC3_DIV1),
+ VC3_CLK_PARENT(DIV, VC3_DIV3),
+ },
+ .num_parents = 2,
+ },
+};
+
static struct vc3_hw_data clk_mux[] = {
[VC3_SE1_MUX] = {
.data = &(struct vc3_clk_data) {
@@ -906,13 +1014,9 @@ static struct vc3_hw_data clk_mux[] = {
.hw.init = &(struct clk_init_data) {
.name = "se1_mux",
.ops = &vc3_clk_mux_ops,
- .parent_hws = (const struct clk_hw *[]) {
- &clk_div[VC3_DIV5].hw,
- &clk_div[VC3_DIV4].hw
- },
- .num_parents = 2,
.flags = CLK_SET_RATE_PARENT
- }
+ },
+ .parent_info = &clk_mux_parents[VC3_SE1_MUX],
},
[VC3_SE2_MUX] = {
.data = &(struct vc3_clk_data) {
@@ -921,13 +1025,9 @@ static struct vc3_hw_data clk_mux[] = {
.hw.init = &(struct clk_init_data) {
.name = "se2_mux",
.ops = &vc3_clk_mux_ops,
- .parent_hws = (const struct clk_hw *[]) {
- &clk_div[VC3_DIV5].hw,
- &clk_div[VC3_DIV4].hw
- },
- .num_parents = 2,
.flags = CLK_SET_RATE_PARENT
- }
+ },
+ .parent_info = &clk_mux_parents[VC3_SE2_MUX],
},
[VC3_SE3_MUX] = {
.data = &(struct vc3_clk_data) {
@@ -937,13 +1037,9 @@ static struct vc3_hw_data clk_mux[] = {
.hw.init = &(struct clk_init_data) {
.name = "se3_mux",
.ops = &vc3_clk_mux_ops,
- .parent_hws = (const struct clk_hw *[]) {
- &clk_div[VC3_DIV2].hw,
- &clk_div[VC3_DIV4].hw
- },
- .num_parents = 2,
.flags = CLK_SET_RATE_PARENT
- }
+ },
+ .parent_info = &clk_mux_parents[VC3_SE3_MUX],
},
[VC3_DIFF1_MUX] = {
.data = &(struct vc3_clk_data) {
@@ -953,13 +1049,9 @@ static struct vc3_hw_data clk_mux[] = {
.hw.init = &(struct clk_init_data) {
.name = "diff1_mux",
.ops = &vc3_clk_mux_ops,
- .parent_hws = (const struct clk_hw *[]) {
- &clk_div[VC3_DIV1].hw,
- &clk_div[VC3_DIV3].hw
- },
- .num_parents = 2,
.flags = CLK_SET_RATE_PARENT
- }
+ },
+ .parent_info = &clk_mux_parents[VC3_DIFF1_MUX],
},
[VC3_DIFF2_MUX] = {
.data = &(struct vc3_clk_data) {
@@ -969,16 +1061,81 @@ static struct vc3_hw_data clk_mux[] = {
.hw.init = &(struct clk_init_data) {
.name = "diff2_mux",
.ops = &vc3_clk_mux_ops,
- .parent_hws = (const struct clk_hw *[]) {
- &clk_div[VC3_DIV1].hw,
- &clk_div[VC3_DIV3].hw
- },
- .num_parents = 2,
.flags = CLK_SET_RATE_PARENT
- }
+ },
+ .parent_info = &clk_mux_parents[VC3_DIFF2_MUX],
}
};
+static struct clk_hw *vc3_clk_get_hw(const struct vc3_clk_parent *parent)
+{
+ switch (parent->type) {
+ case VC3_CLK_EXT:
+ return NULL;
+ case VC3_CLK_PFD_MUX:
+ return &clk_pfd_mux[parent->idx].hw;
+ case VC3_CLK_PFD:
+ return &clk_pfd[parent->idx].hw;
+ case VC3_CLK_PLL:
+ return &clk_pll[parent->idx].hw;
+ case VC3_CLK_DIV_MUX:
+ return &clk_div_mux[parent->idx].hw;
+ case VC3_CLK_DIV:
+ return &clk_div[parent->idx].hw;
+ case VC3_CLK_CLK_MUX:
+ return &clk_mux[parent->idx].hw;
+ }
+
+ return NULL;
+}
+
+static struct clk_parent_data *
+vc3_setup_parent_data(struct vc3_hw_data *hw_data)
+{
+ const struct vc3_parent_info *pinfo = hw_data->parent_info;
+ struct clk_parent_data *pd;
+
+ pd = kcalloc(pinfo->num_parents, sizeof(*pd), GFP_KERNEL);
+ if (!pd)
+ return NULL;
+
+ for (int i = 0; i < pinfo->num_parents; i++) {
+ const struct vc3_clk_parent *parent = &pinfo->parents[i];
+
+ if (parent->type == VC3_CLK_EXT)
+ pd[i].index = parent->idx;
+ else
+ pd[i].hw = vc3_clk_get_hw(parent);
+ }
+
+ return pd;
+}
+
+static int vc3_register_clk(struct device *dev, struct vc3_hw_data *hw_data,
+ struct regmap *regmap)
+{
+ struct clk_parent_data *pd;
+ struct clk_init_data init;
+ int ret;
+
+ pd = vc3_setup_parent_data(hw_data);
+ if (!pd)
+ return -ENOMEM;
+
+ init = *hw_data->hw.init;
+ init.parent_data = pd;
+ init.num_parents = hw_data->parent_info->num_parents;
+
+ hw_data->regmap = regmap;
+ hw_data->hw.init = &init;
+
+ ret = devm_clk_hw_register(dev, &hw_data->hw);
+
+ kfree(pd);
+
+ return ret;
+}
+
static struct clk_hw *vc3_of_clk_get(struct of_phandle_args *clkspec,
void *data)
{
@@ -1029,9 +1186,8 @@ static int vc3_probe(struct i2c_client *client)
/* Register pfd muxes */
for (i = 0; i < ARRAY_SIZE(clk_pfd_mux); i++) {
- clk_pfd_mux[i].regmap = regmap;
name = clk_pfd_mux[i].hw.init->name;
- ret = devm_clk_hw_register(dev, &clk_pfd_mux[i].hw);
+ ret = vc3_register_clk(dev, &clk_pfd_mux[i], regmap);
if (ret)
return dev_err_probe(dev, ret,
"failed to register clock %s\n",
@@ -1040,9 +1196,8 @@ static int vc3_probe(struct i2c_client *client)
/* Register pfd's */
for (i = 0; i < ARRAY_SIZE(clk_pfd); i++) {
- clk_pfd[i].regmap = regmap;
name = clk_pfd[i].hw.init->name;
- ret = devm_clk_hw_register(dev, &clk_pfd[i].hw);
+ ret = vc3_register_clk(dev, &clk_pfd[i], regmap);
if (ret)
return dev_err_probe(dev, ret,
"failed to register clock %s\n",
@@ -1053,14 +1208,13 @@ static int vc3_probe(struct i2c_client *client)
/* Register pll's */
for (i = 0; i < ARRAY_SIZE(clk_pll); i++) {
- clk_pll[i].regmap = regmap;
if (i == VC3_PLL2) {
struct vc3_pll_data *pll_data = clk_pll[i].data;
pll_data->vco = data->pll2_vco;
}
name = clk_pll[i].hw.init->name;
- ret = devm_clk_hw_register(dev, &clk_pll[i].hw);
+ ret = vc3_register_clk(dev, &clk_pll[i], regmap);
if (ret)
return dev_err_probe(dev, ret,
"failed to register clock %s\n",
@@ -1069,9 +1223,8 @@ static int vc3_probe(struct i2c_client *client)
/* Register divider muxes */
for (i = 0; i < ARRAY_SIZE(clk_div_mux); i++) {
- clk_div_mux[i].regmap = regmap;
name = clk_div_mux[i].hw.init->name;
- ret = devm_clk_hw_register(dev, &clk_div_mux[i].hw);
+ ret = vc3_register_clk(dev, &clk_div_mux[i], regmap);
if (ret)
return dev_err_probe(dev, ret,
"failed to register clock %s\n",
@@ -1080,9 +1233,8 @@ static int vc3_probe(struct i2c_client *client)
/* Register dividers */
for (i = 0; i < ARRAY_SIZE(clk_div); i++) {
- clk_div[i].regmap = regmap;
name = clk_div[i].hw.init->name;
- ret = devm_clk_hw_register(dev, &clk_div[i].hw);
+ ret = vc3_register_clk(dev, &clk_div[i], regmap);
if (ret)
return dev_err_probe(dev, ret,
"failed to register clock %s\n",
@@ -1091,14 +1243,13 @@ static int vc3_probe(struct i2c_client *client)
/* Register clk muxes */
for (i = 0; i < ARRAY_SIZE(clk_mux); i++) {
- clk_mux[i].regmap = regmap;
if (i == VC3_SE2_MUX) {
struct vc3_clk_data *clk_data = clk_mux[i].data;
clk_data->bitmsk = data->se2_clk_sel_msk;
}
name = clk_mux[i].hw.init->name;
- ret = devm_clk_hw_register(dev, &clk_mux[i].hw);
+ ret = vc3_register_clk(dev, &clk_mux[i], regmap);
if (ret)
return dev_err_probe(dev, ret,
"failed to register clock %s\n",
--
2.51.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 4/7] clk: versaclock3: Add per-device clock data structure
2026-03-02 16:54 [PATCH v4 0/7] Add versaclock3 support for RZ/V2H Ovidiu Panait
` (2 preceding siblings ...)
2026-03-02 16:54 ` [PATCH v4 3/7] clk: versaclock3: Reference parent clocks by type and index Ovidiu Panait
@ 2026-03-02 16:54 ` Ovidiu Panait
2026-03-02 16:54 ` [PATCH v4 5/7] clk: versaclock3: Prefix clock names with device name Ovidiu Panait
` (3 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Ovidiu Panait @ 2026-03-02 16:54 UTC (permalink / raw)
To: geert+renesas, magnus.damm, robh, krzk+dt, conor+dt, mturquette,
sboyd, biju.das.jz, fabrizio.castro.jz
Cc: linux-renesas-soc, devicetree, linux-kernel, linux-clk
Introduce struct vc3_device_data to hold per-device copies of all clock
hardware data arrays. The static clock arrays serve as templates
describing the clock topology. During probe, these templates are
referenced to initialize device-specific clock structures.
This is required to support multiple versaclock3 devices simultaneously,
as the current static arrays would be shared across all instances.
Signed-off-by: Ovidiu Panait <ovidiu.panait.rb@renesas.com>
---
v4 changes: None.
v3 changes: New patch.
drivers/clk/clk-versaclock3.c | 114 +++++++++++++++++++++++-----------
1 file changed, 77 insertions(+), 37 deletions(-)
diff --git a/drivers/clk/clk-versaclock3.c b/drivers/clk/clk-versaclock3.c
index d3e23566a38c..eb61a2c0b49b 100644
--- a/drivers/clk/clk-versaclock3.c
+++ b/drivers/clk/clk-versaclock3.c
@@ -13,6 +13,14 @@
#define NUM_CONFIG_REGISTERS 37
+#define VC3_PFD_MUX_NUM 2
+#define VC3_PFD_NUM 3
+#define VC3_PLL_NUM 3
+#define VC3_DIV_MUX_NUM 3
+#define VC3_DIV_NUM 5
+#define VC3_CLK_MUX_NUM 5
+#define VC3_CLK_OUT_NUM 6
+
#define VC3_GENERAL_CTR 0x0
#define VC3_GENERAL_CTR_DIV1_SRC_SEL BIT(3)
#define VC3_GENERAL_CTR_PLL3_REFIN_SEL BIT(2)
@@ -200,6 +208,18 @@ struct vc3_hw_cfg {
u32 se2_clk_sel_msk;
};
+struct vc3_device_data {
+ struct i2c_client *client;
+ struct regmap *regmap;
+ struct vc3_hw_data clk_pfd_mux[VC3_PFD_MUX_NUM];
+ struct vc3_hw_data clk_pfd[VC3_PFD_NUM];
+ struct vc3_hw_data clk_pll[VC3_PLL_NUM];
+ struct vc3_hw_data clk_div_mux[VC3_DIV_MUX_NUM];
+ struct vc3_hw_data clk_div[VC3_DIV_NUM];
+ struct vc3_hw_data clk_mux[VC3_CLK_MUX_NUM];
+ struct clk_hw *clk_out[VC3_CLK_OUT_NUM];
+};
+
static const struct clk_div_table div1_divs[] = {
{ .val = 0, .div = 1, }, { .val = 1, .div = 4, },
{ .val = 2, .div = 5, }, { .val = 3, .div = 6, },
@@ -236,8 +256,6 @@ static const struct clk_div_table div3_divs[] = {
{}
};
-static struct clk_hw *clk_out[6];
-
static u8 vc3_pfd_mux_get_parent(struct clk_hw *hw)
{
struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
@@ -1067,30 +1085,31 @@ static struct vc3_hw_data clk_mux[] = {
}
};
-static struct clk_hw *vc3_clk_get_hw(const struct vc3_clk_parent *parent)
+static struct clk_hw *vc3_clk_get_hw(struct vc3_device_data *vc3,
+ const struct vc3_clk_parent *parent)
{
switch (parent->type) {
case VC3_CLK_EXT:
return NULL;
case VC3_CLK_PFD_MUX:
- return &clk_pfd_mux[parent->idx].hw;
+ return &vc3->clk_pfd_mux[parent->idx].hw;
case VC3_CLK_PFD:
- return &clk_pfd[parent->idx].hw;
+ return &vc3->clk_pfd[parent->idx].hw;
case VC3_CLK_PLL:
- return &clk_pll[parent->idx].hw;
+ return &vc3->clk_pll[parent->idx].hw;
case VC3_CLK_DIV_MUX:
- return &clk_div_mux[parent->idx].hw;
+ return &vc3->clk_div_mux[parent->idx].hw;
case VC3_CLK_DIV:
- return &clk_div[parent->idx].hw;
+ return &vc3->clk_div[parent->idx].hw;
case VC3_CLK_CLK_MUX:
- return &clk_mux[parent->idx].hw;
+ return &vc3->clk_mux[parent->idx].hw;
}
return NULL;
}
static struct clk_parent_data *
-vc3_setup_parent_data(struct vc3_hw_data *hw_data)
+vc3_setup_parent_data(struct vc3_device_data *vc3, struct vc3_hw_data *hw_data)
{
const struct vc3_parent_info *pinfo = hw_data->parent_info;
struct clk_parent_data *pd;
@@ -1105,28 +1124,34 @@ vc3_setup_parent_data(struct vc3_hw_data *hw_data)
if (parent->type == VC3_CLK_EXT)
pd[i].index = parent->idx;
else
- pd[i].hw = vc3_clk_get_hw(parent);
+ pd[i].hw = vc3_clk_get_hw(vc3, parent);
}
return pd;
}
-static int vc3_register_clk(struct device *dev, struct vc3_hw_data *hw_data,
- struct regmap *regmap)
+static int vc3_register_clk(struct vc3_device_data *vc3,
+ struct vc3_hw_data *hw_data,
+ const struct vc3_hw_data *template)
{
+ struct device *dev = &vc3->client->dev;
struct clk_parent_data *pd;
struct clk_init_data init;
int ret;
- pd = vc3_setup_parent_data(hw_data);
+ if (!hw_data->data)
+ hw_data->data = template->data;
+ hw_data->parent_info = template->parent_info;
+
+ pd = vc3_setup_parent_data(vc3, hw_data);
if (!pd)
return -ENOMEM;
- init = *hw_data->hw.init;
+ init = *template->hw.init;
init.parent_data = pd;
init.num_parents = hw_data->parent_info->num_parents;
- hw_data->regmap = regmap;
+ hw_data->regmap = vc3->regmap;
hw_data->hw.init = &init;
ret = devm_clk_hw_register(dev, &hw_data->hw);
@@ -1142,7 +1167,7 @@ static struct clk_hw *vc3_of_clk_get(struct of_phandle_args *clkspec,
unsigned int idx = clkspec->args[0];
struct clk_hw **clkout_hw = data;
- if (idx >= ARRAY_SIZE(clk_out)) {
+ if (idx >= VC3_CLK_OUT_NUM) {
pr_err("invalid clk index %u for provider %pOF\n", idx, clkspec->np);
return ERR_PTR(-EINVAL);
}
@@ -1155,13 +1180,18 @@ static int vc3_probe(struct i2c_client *client)
struct device *dev = &client->dev;
u8 settings[NUM_CONFIG_REGISTERS];
const struct vc3_hw_cfg *data;
- struct regmap *regmap;
+ struct vc3_device_data *vc3;
const char *name;
int ret, i;
- regmap = devm_regmap_init_i2c(client, &vc3_regmap_config);
- if (IS_ERR(regmap))
- return dev_err_probe(dev, PTR_ERR(regmap),
+ vc3 = devm_kzalloc(dev, sizeof(*vc3), GFP_KERNEL);
+ if (!vc3)
+ return -ENOMEM;
+
+ vc3->client = client;
+ vc3->regmap = devm_regmap_init_i2c(client, &vc3_regmap_config);
+ if (IS_ERR(vc3->regmap))
+ return dev_err_probe(dev, PTR_ERR(vc3->regmap),
"failed to allocate register map\n");
ret = of_property_read_u8_array(dev->of_node, "renesas,settings",
@@ -1172,7 +1202,7 @@ static int vc3_probe(struct i2c_client *client)
* settings to the device immediately.
*/
for (i = 0; i < NUM_CONFIG_REGISTERS; i++) {
- ret = regmap_write(regmap, i, settings[i]);
+ ret = regmap_write(vc3->regmap, i, settings[i]);
if (ret) {
dev_err(dev, "error writing to chip (%i)\n", ret);
return ret;
@@ -1187,7 +1217,7 @@ static int vc3_probe(struct i2c_client *client)
/* Register pfd muxes */
for (i = 0; i < ARRAY_SIZE(clk_pfd_mux); i++) {
name = clk_pfd_mux[i].hw.init->name;
- ret = vc3_register_clk(dev, &clk_pfd_mux[i], regmap);
+ ret = vc3_register_clk(vc3, &vc3->clk_pfd_mux[i], &clk_pfd_mux[i]);
if (ret)
return dev_err_probe(dev, ret,
"failed to register clock %s\n",
@@ -1197,7 +1227,7 @@ static int vc3_probe(struct i2c_client *client)
/* Register pfd's */
for (i = 0; i < ARRAY_SIZE(clk_pfd); i++) {
name = clk_pfd[i].hw.init->name;
- ret = vc3_register_clk(dev, &clk_pfd[i], regmap);
+ ret = vc3_register_clk(vc3, &vc3->clk_pfd[i], &clk_pfd[i]);
if (ret)
return dev_err_probe(dev, ret,
"failed to register clock %s\n",
@@ -1209,12 +1239,17 @@ static int vc3_probe(struct i2c_client *client)
/* Register pll's */
for (i = 0; i < ARRAY_SIZE(clk_pll); i++) {
if (i == VC3_PLL2) {
- struct vc3_pll_data *pll_data = clk_pll[i].data;
+ struct vc3_pll_data *pll_data;
+ pll_data = devm_kmemdup(dev, clk_pll[i].data,
+ sizeof(*pll_data), GFP_KERNEL);
+ if (!pll_data)
+ return -ENOMEM;
pll_data->vco = data->pll2_vco;
+ vc3->clk_pll[i].data = pll_data;
}
name = clk_pll[i].hw.init->name;
- ret = vc3_register_clk(dev, &clk_pll[i], regmap);
+ ret = vc3_register_clk(vc3, &vc3->clk_pll[i], &clk_pll[i]);
if (ret)
return dev_err_probe(dev, ret,
"failed to register clock %s\n",
@@ -1224,7 +1259,7 @@ static int vc3_probe(struct i2c_client *client)
/* Register divider muxes */
for (i = 0; i < ARRAY_SIZE(clk_div_mux); i++) {
name = clk_div_mux[i].hw.init->name;
- ret = vc3_register_clk(dev, &clk_div_mux[i], regmap);
+ ret = vc3_register_clk(vc3, &vc3->clk_div_mux[i], &clk_div_mux[i]);
if (ret)
return dev_err_probe(dev, ret,
"failed to register clock %s\n",
@@ -1234,7 +1269,7 @@ static int vc3_probe(struct i2c_client *client)
/* Register dividers */
for (i = 0; i < ARRAY_SIZE(clk_div); i++) {
name = clk_div[i].hw.init->name;
- ret = vc3_register_clk(dev, &clk_div[i], regmap);
+ ret = vc3_register_clk(vc3, &vc3->clk_div[i], &clk_div[i]);
if (ret)
return dev_err_probe(dev, ret,
"failed to register clock %s\n",
@@ -1244,12 +1279,17 @@ static int vc3_probe(struct i2c_client *client)
/* Register clk muxes */
for (i = 0; i < ARRAY_SIZE(clk_mux); i++) {
if (i == VC3_SE2_MUX) {
- struct vc3_clk_data *clk_data = clk_mux[i].data;
+ struct vc3_clk_data *clk_data;
+ clk_data = devm_kmemdup(dev, clk_mux[i].data,
+ sizeof(*clk_data), GFP_KERNEL);
+ if (!clk_data)
+ return -ENOMEM;
clk_data->bitmsk = data->se2_clk_sel_msk;
+ vc3->clk_mux[i].data = clk_data;
}
name = clk_mux[i].hw.init->name;
- ret = vc3_register_clk(dev, &clk_mux[i], regmap);
+ ret = vc3_register_clk(vc3, &vc3->clk_mux[i], &clk_mux[i]);
if (ret)
return dev_err_probe(dev, ret,
"failed to register clock %s\n",
@@ -1257,7 +1297,7 @@ static int vc3_probe(struct i2c_client *client)
}
/* Register clk outputs */
- for (i = 0; i < ARRAY_SIZE(clk_out); i++) {
+ for (i = 0; i < ARRAY_SIZE(vc3->clk_out); i++) {
switch (i) {
case VC3_DIFF2:
name = "diff2";
@@ -1282,17 +1322,17 @@ static int vc3_probe(struct i2c_client *client)
}
if (i == VC3_REF)
- clk_out[i] = devm_clk_hw_register_fixed_factor_index(dev,
+ vc3->clk_out[i] = devm_clk_hw_register_fixed_factor_index(dev,
name, 0, CLK_SET_RATE_PARENT, 1, 1);
else
- clk_out[i] = devm_clk_hw_register_fixed_factor_parent_hw(dev,
- name, &clk_mux[i - 1].hw, CLK_SET_RATE_PARENT, 1, 1);
+ vc3->clk_out[i] = devm_clk_hw_register_fixed_factor_parent_hw(dev,
+ name, &vc3->clk_mux[i - 1].hw, CLK_SET_RATE_PARENT, 1, 1);
- if (IS_ERR(clk_out[i]))
- return PTR_ERR(clk_out[i]);
+ if (IS_ERR(vc3->clk_out[i]))
+ return PTR_ERR(vc3->clk_out[i]);
}
- ret = devm_of_clk_add_hw_provider(dev, vc3_of_clk_get, clk_out);
+ ret = devm_of_clk_add_hw_provider(dev, vc3_of_clk_get, vc3->clk_out);
if (ret)
return dev_err_probe(dev, ret, "unable to add clk provider\n");
--
2.51.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 5/7] clk: versaclock3: Prefix clock names with device name
2026-03-02 16:54 [PATCH v4 0/7] Add versaclock3 support for RZ/V2H Ovidiu Panait
` (3 preceding siblings ...)
2026-03-02 16:54 ` [PATCH v4 4/7] clk: versaclock3: Add per-device clock data structure Ovidiu Panait
@ 2026-03-02 16:54 ` Ovidiu Panait
2026-03-02 16:54 ` [PATCH v4 6/7] clk: versaclock3: Add freerunning 32.768kHz clock support Ovidiu Panait
` (2 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Ovidiu Panait @ 2026-03-02 16:54 UTC (permalink / raw)
To: geert+renesas, magnus.damm, robh, krzk+dt, conor+dt, mturquette,
sboyd, biju.das.jz, fabrizio.castro.jz
Cc: linux-renesas-soc, devicetree, linux-kernel, linux-clk
Prefix clock names with the device name to allow multiple VersaClock3
devices to be registered simultaneously.
Signed-off-by: Ovidiu Panait <ovidiu.panait.rb@renesas.com>
---
v4 changes:
- Used the I2C device name instead of device tree node name to make the
clk names globally unique.
v3 changes: New patch.
drivers/clk/clk-versaclock3.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/clk/clk-versaclock3.c b/drivers/clk/clk-versaclock3.c
index eb61a2c0b49b..eb25100bb0aa 100644
--- a/drivers/clk/clk-versaclock3.c
+++ b/drivers/clk/clk-versaclock3.c
@@ -1137,6 +1137,7 @@ static int vc3_register_clk(struct vc3_device_data *vc3,
struct device *dev = &vc3->client->dev;
struct clk_parent_data *pd;
struct clk_init_data init;
+ const char *name;
int ret;
if (!hw_data->data)
@@ -1147,7 +1148,15 @@ static int vc3_register_clk(struct vc3_device_data *vc3,
if (!pd)
return -ENOMEM;
+ name = kasprintf(GFP_KERNEL, "%s.%s", dev_name(dev),
+ template->hw.init->name);
+ if (!name) {
+ kfree(pd);
+ return -ENOMEM;
+ }
+
init = *template->hw.init;
+ init.name = name;
init.parent_data = pd;
init.num_parents = hw_data->parent_info->num_parents;
@@ -1157,6 +1166,7 @@ static int vc3_register_clk(struct vc3_device_data *vc3,
ret = devm_clk_hw_register(dev, &hw_data->hw);
kfree(pd);
+ kfree(name);
return ret;
}
@@ -1321,6 +1331,10 @@ static int vc3_probe(struct i2c_client *client)
return dev_err_probe(dev, -EINVAL, "invalid clk output %d\n", i);
}
+ name = kasprintf(GFP_KERNEL, "%s.%s", dev_name(dev), name);
+ if (!name)
+ return -ENOMEM;
+
if (i == VC3_REF)
vc3->clk_out[i] = devm_clk_hw_register_fixed_factor_index(dev,
name, 0, CLK_SET_RATE_PARENT, 1, 1);
@@ -1328,6 +1342,8 @@ static int vc3_probe(struct i2c_client *client)
vc3->clk_out[i] = devm_clk_hw_register_fixed_factor_parent_hw(dev,
name, &vc3->clk_mux[i - 1].hw, CLK_SET_RATE_PARENT, 1, 1);
+ kfree(name);
+
if (IS_ERR(vc3->clk_out[i]))
return PTR_ERR(vc3->clk_out[i]);
}
--
2.51.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 6/7] clk: versaclock3: Add freerunning 32.768kHz clock support
2026-03-02 16:54 [PATCH v4 0/7] Add versaclock3 support for RZ/V2H Ovidiu Panait
` (4 preceding siblings ...)
2026-03-02 16:54 ` [PATCH v4 5/7] clk: versaclock3: Prefix clock names with device name Ovidiu Panait
@ 2026-03-02 16:54 ` Ovidiu Panait
2026-03-02 16:54 ` [PATCH v4 7/7] arm64: dts: renesas: r9a09g057h44-rzv2h-evk: Add versa3 clock generator node Ovidiu Panait
2026-07-15 10:39 ` [PATCH v4 0/7] Add versaclock3 support for RZ/V2H Ovidiu Panait
7 siblings, 0 replies; 10+ messages in thread
From: Ovidiu Panait @ 2026-03-02 16:54 UTC (permalink / raw)
To: geert+renesas, magnus.damm, robh, krzk+dt, conor+dt, mturquette,
sboyd, biju.das.jz, fabrizio.castro.jz
Cc: linux-renesas-soc, devicetree, linux-kernel, linux-clk
The Versa 3 clock generator has an internal 32.768kHz oscillator that can
be routed to the SE1, SE2 and SE3 outputs. This patch exposes it as a
fixed-rate clock and makes it available as a parent for the SE1/SE2/SE3
muxes.
The 32.768kHz clock is only intended to be used when explicitly requested
(i.e. when a rate of exactly 32768Hz is set). Selecting it as a fallback
for other rates can cause issues, for example in audio configurations.
To enforce this, introduce a new helper function,
_vc3_clk_mux_determine_rate() which rejects configurations where the
32.768kHz parent would otherwise be chosen implicitly.
One new field is added to struct vc3_clk_data - clk_32k_bitmsk, which
is the bit mask used for selecting the 32.768kHz oscillator as output.
It is used by clk_mux callbacks to select the appropriate parent clock.
Signed-off-by: Ovidiu Panait <ovidiu.panait.rb@renesas.com>
---
v4 changes:
- Used the I2C device name instead of device tree node name to make the
32k clk name globally unique.
v3 changes:
- Rebased the patch to match the new clock registration logic and dropped
the 32k clock parent index number (clk_32k_index).
drivers/clk/clk-versaclock3.c | 96 +++++++++++++++++++++++++++++++----
1 file changed, 86 insertions(+), 10 deletions(-)
diff --git a/drivers/clk/clk-versaclock3.c b/drivers/clk/clk-versaclock3.c
index eb25100bb0aa..d8abb665e642 100644
--- a/drivers/clk/clk-versaclock3.c
+++ b/drivers/clk/clk-versaclock3.c
@@ -69,8 +69,10 @@
#define VC3_OUTPUT_CTR_DIV4_SRC_SEL BIT(3)
#define VC3_SE2_CTRL_REG0 0x1f
+#define VC3_SE2_CTRL_REG0_SE2_FREERUN_32K BIT(7)
#define VC3_SE3_DIFF1_CTRL_REG 0x21
+#define VC3_SE3_DIFF1_CTRL_REG_SE3_FREERUN_32K BIT(7)
#define VC3_SE3_DIFF1_CTRL_REG_SE3_CLK_SEL BIT(6)
#define VC3_DIFF1_CTRL_REG 0x22
@@ -80,6 +82,7 @@
#define VC3_DIFF2_CTRL_REG_DIFF2_CLK_SEL BIT(7)
#define VC3_SE1_DIV4_CTRL 0x24
+#define VC3_SE1_DIV4_CTRL_SE1_FREERUN_32K BIT(4)
#define VC3_SE1_DIV4_CTRL_SE1_CLK_SEL BIT(3)
#define VC3_PLL1_VCO_MIN 300000000UL
@@ -91,6 +94,8 @@
#define VC3_2_POW_16 (U16_MAX + 1)
#define VC3_DIV_MASK(width) ((1 << (width)) - 1)
+#define VC3_CLK_32K_FREQ 32768
+
#define VC3_CLK_PARENT(t, i) { .type = VC3_CLK_##t, .idx = (i) }
enum vc3_pfd_mux {
@@ -149,6 +154,7 @@ enum vc3_clk_type {
VC3_CLK_DIV_MUX,
VC3_CLK_DIV,
VC3_CLK_CLK_MUX,
+ VC3_CLK_32K,
};
struct vc3_clk_parent {
@@ -164,6 +170,7 @@ struct vc3_parent_info {
struct vc3_clk_data {
u8 offs;
u8 bitmsk;
+ u8 clk_32k_bitmsk;
};
struct vc3_pfd_data {
@@ -217,6 +224,7 @@ struct vc3_device_data {
struct vc3_hw_data clk_div_mux[VC3_DIV_MUX_NUM];
struct vc3_hw_data clk_div[VC3_DIV_NUM];
struct vc3_hw_data clk_mux[VC3_CLK_MUX_NUM];
+ struct clk_hw *clk_32k;
struct clk_hw *clk_out[VC3_CLK_OUT_NUM];
};
@@ -587,19 +595,52 @@ static const struct clk_ops vc3_div_ops = {
.set_rate = vc3_div_set_rate,
};
+static int vc3_get_32k_parent_index(const struct vc3_hw_data *hw_data)
+{
+ const struct vc3_parent_info *pinfo = hw_data->parent_info;
+
+ for (int i = 0; i < pinfo->num_parents; i++) {
+ if (pinfo->parents[i].type == VC3_CLK_32K)
+ return i;
+ }
+
+ return -1;
+}
+
+static int _vc3_clk_mux_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ bool is_32k_req = (req->rate == VC3_CLK_32K_FREQ);
+ struct clk_rate_request tmp_req;
+ int ret;
+
+ clk_hw_init_rate_request(hw, &tmp_req, req->rate);
+
+ ret = clk_mux_determine_rate_flags(hw, &tmp_req, CLK_SET_RATE_PARENT);
+ if (ret)
+ return ret;
+
+ /* Select the 32.768 kHz parent only when explicitly requested. */
+ if ((tmp_req.best_parent_rate == VC3_CLK_32K_FREQ) && !is_32k_req)
+ return -EINVAL;
+
+ memcpy(req, &tmp_req, sizeof(*req));
+
+ return 0;
+}
+
static int vc3_clk_mux_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
int frc;
- if (clk_mux_determine_rate_flags(hw, req, CLK_SET_RATE_PARENT)) {
+ if (_vc3_clk_mux_determine_rate(hw, req)) {
/* The below check is equivalent to (best_parent_rate/rate) */
if (req->best_parent_rate >= req->rate) {
frc = DIV_ROUND_CLOSEST_ULL(req->best_parent_rate,
req->rate);
req->rate *= frc;
- return clk_mux_determine_rate_flags(hw, req,
- CLK_SET_RATE_PARENT);
+ return _vc3_clk_mux_determine_rate(hw, req);
}
}
@@ -610,10 +651,15 @@ static u8 vc3_clk_mux_get_parent(struct clk_hw *hw)
{
struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
const struct vc3_clk_data *clk_mux = vc3->data;
+ int clk_32k_index;
u32 val;
regmap_read(vc3->regmap, clk_mux->offs, &val);
+ clk_32k_index = vc3_get_32k_parent_index(vc3);
+ if (clk_32k_index >= 0 && !(val & clk_mux->clk_32k_bitmsk))
+ return clk_32k_index;
+
return !!(val & clk_mux->bitmsk);
}
@@ -621,9 +667,17 @@ static int vc3_clk_mux_set_parent(struct clk_hw *hw, u8 index)
{
struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
const struct vc3_clk_data *clk_mux = vc3->data;
+ unsigned int bitmsk = clk_mux->clk_32k_bitmsk;
+ unsigned int val = 0;
+ int clk_32k_index;
+
+ clk_32k_index = vc3_get_32k_parent_index(vc3);
+ if (index != clk_32k_index) {
+ bitmsk |= clk_mux->bitmsk;
+ val = clk_mux->clk_32k_bitmsk | (index ? clk_mux->bitmsk : 0);
+ }
- return regmap_update_bits(vc3->regmap, clk_mux->offs, clk_mux->bitmsk,
- index ? clk_mux->bitmsk : 0);
+ return regmap_update_bits(vc3->regmap, clk_mux->offs, bitmsk, val);
}
static const struct clk_ops vc3_clk_mux_ops = {
@@ -990,22 +1044,25 @@ static const struct vc3_parent_info clk_mux_parents[] = {
.parents = (const struct vc3_clk_parent[]) {
VC3_CLK_PARENT(DIV, VC3_DIV5),
VC3_CLK_PARENT(DIV, VC3_DIV4),
+ VC3_CLK_PARENT(32K, 0),
},
- .num_parents = 2,
+ .num_parents = 3,
},
[VC3_SE2_MUX] = {
.parents = (const struct vc3_clk_parent[]) {
VC3_CLK_PARENT(DIV, VC3_DIV5),
VC3_CLK_PARENT(DIV, VC3_DIV4),
+ VC3_CLK_PARENT(32K, 0),
},
- .num_parents = 2,
+ .num_parents = 3,
},
[VC3_SE3_MUX] = {
.parents = (const struct vc3_clk_parent[]) {
VC3_CLK_PARENT(DIV, VC3_DIV2),
VC3_CLK_PARENT(DIV, VC3_DIV4),
+ VC3_CLK_PARENT(32K, 0),
},
- .num_parents = 2,
+ .num_parents = 3,
},
[VC3_DIFF1_MUX] = {
.parents = (const struct vc3_clk_parent[]) {
@@ -1027,7 +1084,8 @@ static struct vc3_hw_data clk_mux[] = {
[VC3_SE1_MUX] = {
.data = &(struct vc3_clk_data) {
.offs = VC3_SE1_DIV4_CTRL,
- .bitmsk = VC3_SE1_DIV4_CTRL_SE1_CLK_SEL
+ .bitmsk = VC3_SE1_DIV4_CTRL_SE1_CLK_SEL,
+ .clk_32k_bitmsk = VC3_SE1_DIV4_CTRL_SE1_FREERUN_32K,
},
.hw.init = &(struct clk_init_data) {
.name = "se1_mux",
@@ -1039,6 +1097,7 @@ static struct vc3_hw_data clk_mux[] = {
[VC3_SE2_MUX] = {
.data = &(struct vc3_clk_data) {
.offs = VC3_SE2_CTRL_REG0,
+ .clk_32k_bitmsk = VC3_SE2_CTRL_REG0_SE2_FREERUN_32K,
},
.hw.init = &(struct clk_init_data) {
.name = "se2_mux",
@@ -1050,7 +1109,8 @@ static struct vc3_hw_data clk_mux[] = {
[VC3_SE3_MUX] = {
.data = &(struct vc3_clk_data) {
.offs = VC3_SE3_DIFF1_CTRL_REG,
- .bitmsk = VC3_SE3_DIFF1_CTRL_REG_SE3_CLK_SEL
+ .bitmsk = VC3_SE3_DIFF1_CTRL_REG_SE3_CLK_SEL,
+ .clk_32k_bitmsk = VC3_SE3_DIFF1_CTRL_REG_SE3_FREERUN_32K,
},
.hw.init = &(struct clk_init_data) {
.name = "se3_mux",
@@ -1103,6 +1163,8 @@ static struct clk_hw *vc3_clk_get_hw(struct vc3_device_data *vc3,
return &vc3->clk_div[parent->idx].hw;
case VC3_CLK_CLK_MUX:
return &vc3->clk_mux[parent->idx].hw;
+ case VC3_CLK_32K:
+ return vc3->clk_32k;
}
return NULL;
@@ -1224,6 +1286,20 @@ static int vc3_probe(struct i2c_client *client)
return ret;
}
+ /* Register internal 32.768kHz oscillator */
+ name = kasprintf(GFP_KERNEL, "%s.clk_32k", dev_name(dev));
+ if (!name)
+ return -ENOMEM;
+
+ vc3->clk_32k = devm_clk_hw_register_fixed_rate(dev, name, NULL, 0,
+ VC3_CLK_32K_FREQ);
+ kfree(name);
+
+ if (IS_ERR(vc3->clk_32k))
+ return dev_err_probe(dev, PTR_ERR(vc3->clk_32k),
+ "Failed to register %dHz fixed clock\n",
+ VC3_CLK_32K_FREQ);
+
/* Register pfd muxes */
for (i = 0; i < ARRAY_SIZE(clk_pfd_mux); i++) {
name = clk_pfd_mux[i].hw.init->name;
--
2.51.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 7/7] arm64: dts: renesas: r9a09g057h44-rzv2h-evk: Add versa3 clock generator node
2026-03-02 16:54 [PATCH v4 0/7] Add versaclock3 support for RZ/V2H Ovidiu Panait
` (5 preceding siblings ...)
2026-03-02 16:54 ` [PATCH v4 6/7] clk: versaclock3: Add freerunning 32.768kHz clock support Ovidiu Panait
@ 2026-03-02 16:54 ` Ovidiu Panait
2026-03-26 10:06 ` Geert Uytterhoeven
2026-07-15 10:39 ` [PATCH v4 0/7] Add versaclock3 support for RZ/V2H Ovidiu Panait
7 siblings, 1 reply; 10+ messages in thread
From: Ovidiu Panait @ 2026-03-02 16:54 UTC (permalink / raw)
To: geert+renesas, magnus.damm, robh, krzk+dt, conor+dt, mturquette,
sboyd, biju.das.jz, fabrizio.castro.jz
Cc: linux-renesas-soc, devicetree, linux-kernel, linux-clk
Add versa3 clock generator node. It provides clocks for the RTC, PCIe
and audio devices.
Signed-off-by: Ovidiu Panait <ovidiu.panait.rb@renesas.com>
---
v4 changes: None.
v3 changes:
- Added comments to document rtxin_clk and qextal_clk routing.
.../dts/renesas/r9a09g057h44-rzv2h-evk.dts | 25 +++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/arch/arm64/boot/dts/renesas/r9a09g057h44-rzv2h-evk.dts b/arch/arm64/boot/dts/renesas/r9a09g057h44-rzv2h-evk.dts
index dc4577ebf2e9..4d6197301af4 100644
--- a/arch/arm64/boot/dts/renesas/r9a09g057h44-rzv2h-evk.dts
+++ b/arch/arm64/boot/dts/renesas/r9a09g057h44-rzv2h-evk.dts
@@ -108,6 +108,12 @@ vqmmc_sdhi1: regulator-vccq-sdhi1 {
states = <3300000 0>, <1800000 1>;
};
+ x1: x1-clock {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <24000000>;
+ };
+
/* 32.768kHz crystal */
x6: x6-clock {
compatible = "fixed-clock";
@@ -277,6 +283,25 @@ raa215300: pmic@12 {
clocks = <&x6>;
clock-names = "xin";
};
+
+ versa3: clock-generator@69 {
+ compatible = "renesas,5l35023";
+ reg = <0x69>;
+ clocks = <&x1>;
+ #clock-cells = <1>;
+ assigned-clocks = <&versa3 0>, /* qextal_clk */
+ <&versa3 1>,
+ <&versa3 2>, /* rtxin_clk */
+ <&versa3 3>,
+ <&versa3 4>,
+ <&versa3 5>;
+ assigned-clock-rates = <24000000>,
+ <24576000>,
+ <32768>,
+ <22579200>,
+ <100000000>,
+ <100000000>;
+ };
};
&mdio0 {
--
2.51.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 7/7] arm64: dts: renesas: r9a09g057h44-rzv2h-evk: Add versa3 clock generator node
2026-03-02 16:54 ` [PATCH v4 7/7] arm64: dts: renesas: r9a09g057h44-rzv2h-evk: Add versa3 clock generator node Ovidiu Panait
@ 2026-03-26 10:06 ` Geert Uytterhoeven
0 siblings, 0 replies; 10+ messages in thread
From: Geert Uytterhoeven @ 2026-03-26 10:06 UTC (permalink / raw)
To: Ovidiu Panait
Cc: magnus.damm, robh, krzk+dt, conor+dt, mturquette, sboyd,
biju.das.jz, fabrizio.castro.jz, linux-renesas-soc, devicetree,
linux-kernel, linux-clk
On Mon, 2 Mar 2026 at 17:55, Ovidiu Panait <ovidiu.panait.rb@renesas.com> wrote:
> Add versa3 clock generator node. It provides clocks for the RTC, PCIe
> and audio devices.
>
> Signed-off-by: Ovidiu Panait <ovidiu.panait.rb@renesas.com>
> ---
> v4 changes: None.
>
> v3 changes:
> - Added comments to document rtxin_clk and qextal_clk routing.
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
i.e. will queue in renesas-devel for v7.1.
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 0/7] Add versaclock3 support for RZ/V2H
2026-03-02 16:54 [PATCH v4 0/7] Add versaclock3 support for RZ/V2H Ovidiu Panait
` (6 preceding siblings ...)
2026-03-02 16:54 ` [PATCH v4 7/7] arm64: dts: renesas: r9a09g057h44-rzv2h-evk: Add versa3 clock generator node Ovidiu Panait
@ 2026-07-15 10:39 ` Ovidiu Panait
7 siblings, 0 replies; 10+ messages in thread
From: Ovidiu Panait @ 2026-07-15 10:39 UTC (permalink / raw)
To: Ovidiu Panait, geert+renesas, magnus.damm, robh, krzk+dt,
conor+dt, mturquette, sboyd, biju.das.jz, fabrizio.castro.jz
Cc: linux-renesas-soc, devicetree, linux-kernel, linux-clk
Hi,
On 3/2/26 6:54 PM, Ovidiu Panait wrote:
>
> Ovidiu Panait (7):
> clk: versaclock3: Fix NULL pointer dereference in error path
> clk: versaclock3: Remove unused SE2 clock select macro
> clk: versaclock3: Reference parent clocks by type and index
> clk: versaclock3: Add per-device clock data structure
> clk: versaclock3: Prefix clock names with device name
> clk: versaclock3: Add freerunning 32.768kHz clock support
> arm64: dts: renesas: r9a09g057h44-rzv2h-evk: Add versa3 clock
> generator node
>
I wanted to follow up on this series from a few months ago. The dts
patch has been applied through the Renesas tree, but the driver patches
are still pending.
Please let me know if there is anything further I need to address for
the clock patches.
Thanks!
Ovidiu
> .../dts/renesas/r9a09g057h44-rzv2h-evk.dts | 25 +
> drivers/clk/clk-versaclock3.c | 618 +++++++++++++-----
> 2 files changed, 481 insertions(+), 162 deletions(-)
>
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-07-15 10:39 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-03-02 16:54 [PATCH v4 0/7] Add versaclock3 support for RZ/V2H Ovidiu Panait
2026-03-02 16:54 ` [PATCH v4 1/7] clk: versaclock3: Fix NULL pointer dereference in error path Ovidiu Panait
2026-03-02 16:54 ` [PATCH v4 2/7] clk: versaclock3: Remove unused SE2 clock select macro Ovidiu Panait
2026-03-02 16:54 ` [PATCH v4 3/7] clk: versaclock3: Reference parent clocks by type and index Ovidiu Panait
2026-03-02 16:54 ` [PATCH v4 4/7] clk: versaclock3: Add per-device clock data structure Ovidiu Panait
2026-03-02 16:54 ` [PATCH v4 5/7] clk: versaclock3: Prefix clock names with device name Ovidiu Panait
2026-03-02 16:54 ` [PATCH v4 6/7] clk: versaclock3: Add freerunning 32.768kHz clock support Ovidiu Panait
2026-03-02 16:54 ` [PATCH v4 7/7] arm64: dts: renesas: r9a09g057h44-rzv2h-evk: Add versa3 clock generator node Ovidiu Panait
2026-03-26 10:06 ` Geert Uytterhoeven
2026-07-15 10:39 ` [PATCH v4 0/7] Add versaclock3 support for RZ/V2H Ovidiu Panait
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox