lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260203135139.28151-5-ovidiu.panait.rb@renesas.com>
Date: Tue,  3 Feb 2026 13:51:35 +0000
From: Ovidiu Panait <ovidiu.panait.rb@...esas.com>
To: geert+renesas@...der.be,
	magnus.damm@...il.com,
	robh@...nel.org,
	krzk+dt@...nel.org,
	conor+dt@...nel.org,
	mturquette@...libre.com,
	sboyd@...nel.org,
	biju.das.jz@...renesas.com,
	fabrizio.castro.jz@...esas.com
Cc: linux-renesas-soc@...r.kernel.org,
	devicetree@...r.kernel.org,
	linux-kernel@...r.kernel.org,
	linux-clk@...r.kernel.org
Subject: [PATCH v3 4/8] clk: versaclock3: Add per-device clock data structure

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@...esas.com>
---
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


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ