Commit f491276a authored by Adam Ford's avatar Adam Ford Committed by Stephen Boyd

clk: vc5: Allow Versaclock driver to support multiple instances

Currently, the Versaclock driver is only expecting one instance and
uses hard-coded names for the various clock names.  Unfortunately,
this is a problem when there is more than one instance of the driver,
because the subsequent instantiations of the driver use the identical
name.  Each clock after the fist fails to load, because the clock
subsystem cannot handle two clocks with identical name.

This patch removes the hard-coded name arrays and uses kasprintf to
assign clock names based on names of their respective node and parent
node which gives each clock a unique identifying name.

For a verasaclock node with a name like:
   versaclock5: versaclock_som@6a

The updated clock names would appear like:
    versaclock_som.mux
       versaclock_som.out0_sel_i2cb
       versaclock_som.pfd
          versaclock_som.pll
             versaclock_som.fod3
                versaclock_som.out4
             versaclock_som.fod2
                versaclock_som.out3
             versaclock_som.fod1
                versaclock_som.out2
             versaclock_som.fod0
                versaclock_som.out1
Signed-off-by: default avatarAdam Ford <aford173@gmail.com>
Link: https://lore.kernel.org/r/20200603154329.31579-1-aford173@gmail.comSigned-off-by: default avatarStephen Boyd <sboyd@kernel.org>
parent b3a9e3b9
...@@ -161,30 +161,6 @@ struct vc5_driver_data { ...@@ -161,30 +161,6 @@ struct vc5_driver_data {
struct vc5_hw_data clk_out[VC5_MAX_CLK_OUT_NUM]; struct vc5_hw_data clk_out[VC5_MAX_CLK_OUT_NUM];
}; };
static const char * const vc5_mux_names[] = {
"mux"
};
static const char * const vc5_dbl_names[] = {
"dbl"
};
static const char * const vc5_pfd_names[] = {
"pfd"
};
static const char * const vc5_pll_names[] = {
"pll"
};
static const char * const vc5_fod_names[] = {
"fod0", "fod1", "fod2", "fod3",
};
static const char * const vc5_clk_out_names[] = {
"out0_sel_i2cb", "out1", "out2", "out3", "out4",
};
/* /*
* VersaClock5 i2c regmap * VersaClock5 i2c regmap
*/ */
...@@ -692,8 +668,7 @@ static int vc5_map_index_to_output(const enum vc5_model model, ...@@ -692,8 +668,7 @@ static int vc5_map_index_to_output(const enum vc5_model model,
static const struct of_device_id clk_vc5_of_match[]; static const struct of_device_id clk_vc5_of_match[];
static int vc5_probe(struct i2c_client *client, static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
const struct i2c_device_id *id)
{ {
struct vc5_driver_data *vc5; struct vc5_driver_data *vc5;
struct clk_init_data init; struct clk_init_data init;
...@@ -750,12 +725,13 @@ static int vc5_probe(struct i2c_client *client, ...@@ -750,12 +725,13 @@ static int vc5_probe(struct i2c_client *client,
return -EINVAL; return -EINVAL;
} }
init.name = vc5_mux_names[0]; init.name = kasprintf(GFP_KERNEL, "%pOFn.mux", client->dev.of_node);
init.ops = &vc5_mux_ops; init.ops = &vc5_mux_ops;
init.flags = 0; init.flags = 0;
init.parent_names = parent_names; init.parent_names = parent_names;
vc5->clk_mux.init = &init; vc5->clk_mux.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_mux); ret = devm_clk_hw_register(&client->dev, &vc5->clk_mux);
kfree(init.name); /* clock framework made a copy of the name */
if (ret) { if (ret) {
dev_err(&client->dev, "unable to register %s\n", init.name); dev_err(&client->dev, "unable to register %s\n", init.name);
goto err_clk; goto err_clk;
...@@ -764,13 +740,16 @@ static int vc5_probe(struct i2c_client *client, ...@@ -764,13 +740,16 @@ static int vc5_probe(struct i2c_client *client,
if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL) { if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL) {
/* Register frequency doubler */ /* Register frequency doubler */
memset(&init, 0, sizeof(init)); memset(&init, 0, sizeof(init));
init.name = vc5_dbl_names[0]; init.name = kasprintf(GFP_KERNEL, "%pOFn.dbl",
client->dev.of_node);
init.ops = &vc5_dbl_ops; init.ops = &vc5_dbl_ops;
init.flags = CLK_SET_RATE_PARENT; init.flags = CLK_SET_RATE_PARENT;
init.parent_names = vc5_mux_names; init.parent_names = parent_names;
parent_names[0] = clk_hw_get_name(&vc5->clk_mux);
init.num_parents = 1; init.num_parents = 1;
vc5->clk_mul.init = &init; vc5->clk_mul.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_mul); ret = devm_clk_hw_register(&client->dev, &vc5->clk_mul);
kfree(init.name); /* clock framework made a copy of the name */
if (ret) { if (ret) {
dev_err(&client->dev, "unable to register %s\n", dev_err(&client->dev, "unable to register %s\n",
init.name); init.name);
...@@ -780,16 +759,18 @@ static int vc5_probe(struct i2c_client *client, ...@@ -780,16 +759,18 @@ static int vc5_probe(struct i2c_client *client,
/* Register PFD */ /* Register PFD */
memset(&init, 0, sizeof(init)); memset(&init, 0, sizeof(init));
init.name = vc5_pfd_names[0]; init.name = kasprintf(GFP_KERNEL, "%pOFn.pfd", client->dev.of_node);
init.ops = &vc5_pfd_ops; init.ops = &vc5_pfd_ops;
init.flags = CLK_SET_RATE_PARENT; init.flags = CLK_SET_RATE_PARENT;
init.parent_names = parent_names;
if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL) if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL)
init.parent_names = vc5_dbl_names; parent_names[0] = clk_hw_get_name(&vc5->clk_mul);
else else
init.parent_names = vc5_mux_names; parent_names[0] = clk_hw_get_name(&vc5->clk_mux);
init.num_parents = 1; init.num_parents = 1;
vc5->clk_pfd.init = &init; vc5->clk_pfd.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_pfd); ret = devm_clk_hw_register(&client->dev, &vc5->clk_pfd);
kfree(init.name); /* clock framework made a copy of the name */
if (ret) { if (ret) {
dev_err(&client->dev, "unable to register %s\n", init.name); dev_err(&client->dev, "unable to register %s\n", init.name);
goto err_clk; goto err_clk;
...@@ -797,15 +778,17 @@ static int vc5_probe(struct i2c_client *client, ...@@ -797,15 +778,17 @@ static int vc5_probe(struct i2c_client *client,
/* Register PLL */ /* Register PLL */
memset(&init, 0, sizeof(init)); memset(&init, 0, sizeof(init));
init.name = vc5_pll_names[0]; init.name = kasprintf(GFP_KERNEL, "%pOFn.pll", client->dev.of_node);
init.ops = &vc5_pll_ops; init.ops = &vc5_pll_ops;
init.flags = CLK_SET_RATE_PARENT; init.flags = CLK_SET_RATE_PARENT;
init.parent_names = vc5_pfd_names; init.parent_names = parent_names;
parent_names[0] = clk_hw_get_name(&vc5->clk_pfd);
init.num_parents = 1; init.num_parents = 1;
vc5->clk_pll.num = 0; vc5->clk_pll.num = 0;
vc5->clk_pll.vc5 = vc5; vc5->clk_pll.vc5 = vc5;
vc5->clk_pll.hw.init = &init; vc5->clk_pll.hw.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_pll.hw); ret = devm_clk_hw_register(&client->dev, &vc5->clk_pll.hw);
kfree(init.name); /* clock framework made a copy of the name */
if (ret) { if (ret) {
dev_err(&client->dev, "unable to register %s\n", init.name); dev_err(&client->dev, "unable to register %s\n", init.name);
goto err_clk; goto err_clk;
...@@ -815,15 +798,18 @@ static int vc5_probe(struct i2c_client *client, ...@@ -815,15 +798,18 @@ static int vc5_probe(struct i2c_client *client,
for (n = 0; n < vc5->chip_info->clk_fod_cnt; n++) { for (n = 0; n < vc5->chip_info->clk_fod_cnt; n++) {
idx = vc5_map_index_to_output(vc5->chip_info->model, n); idx = vc5_map_index_to_output(vc5->chip_info->model, n);
memset(&init, 0, sizeof(init)); memset(&init, 0, sizeof(init));
init.name = vc5_fod_names[idx]; init.name = kasprintf(GFP_KERNEL, "%pOFn.fod%d",
client->dev.of_node, idx);
init.ops = &vc5_fod_ops; init.ops = &vc5_fod_ops;
init.flags = CLK_SET_RATE_PARENT; init.flags = CLK_SET_RATE_PARENT;
init.parent_names = vc5_pll_names; init.parent_names = parent_names;
parent_names[0] = clk_hw_get_name(&vc5->clk_pll.hw);
init.num_parents = 1; init.num_parents = 1;
vc5->clk_fod[n].num = idx; vc5->clk_fod[n].num = idx;
vc5->clk_fod[n].vc5 = vc5; vc5->clk_fod[n].vc5 = vc5;
vc5->clk_fod[n].hw.init = &init; vc5->clk_fod[n].hw.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_fod[n].hw); ret = devm_clk_hw_register(&client->dev, &vc5->clk_fod[n].hw);
kfree(init.name); /* clock framework made a copy of the name */
if (ret) { if (ret) {
dev_err(&client->dev, "unable to register %s\n", dev_err(&client->dev, "unable to register %s\n",
init.name); init.name);
...@@ -833,32 +819,36 @@ static int vc5_probe(struct i2c_client *client, ...@@ -833,32 +819,36 @@ static int vc5_probe(struct i2c_client *client,
/* Register MUX-connected OUT0_I2C_SELB output */ /* Register MUX-connected OUT0_I2C_SELB output */
memset(&init, 0, sizeof(init)); memset(&init, 0, sizeof(init));
init.name = vc5_clk_out_names[0]; init.name = kasprintf(GFP_KERNEL, "%pOFn.out0_sel_i2cb",
client->dev.of_node);
init.ops = &vc5_clk_out_ops; init.ops = &vc5_clk_out_ops;
init.flags = CLK_SET_RATE_PARENT; init.flags = CLK_SET_RATE_PARENT;
init.parent_names = vc5_mux_names; init.parent_names = parent_names;
parent_names[0] = clk_hw_get_name(&vc5->clk_mux);
init.num_parents = 1; init.num_parents = 1;
vc5->clk_out[0].num = idx; vc5->clk_out[0].num = idx;
vc5->clk_out[0].vc5 = vc5; vc5->clk_out[0].vc5 = vc5;
vc5->clk_out[0].hw.init = &init; vc5->clk_out[0].hw.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_out[0].hw); ret = devm_clk_hw_register(&client->dev, &vc5->clk_out[0].hw);
kfree(init.name); /* clock framework made a copy of the name */
if (ret) { if (ret) {
dev_err(&client->dev, "unable to register %s\n", dev_err(&client->dev, "unable to register %s\n", init.name);
init.name);
goto err_clk; goto err_clk;
} }
/* Register FOD-connected OUTx outputs */ /* Register FOD-connected OUTx outputs */
for (n = 1; n < vc5->chip_info->clk_out_cnt; n++) { for (n = 1; n < vc5->chip_info->clk_out_cnt; n++) {
idx = vc5_map_index_to_output(vc5->chip_info->model, n - 1); idx = vc5_map_index_to_output(vc5->chip_info->model, n - 1);
parent_names[0] = vc5_fod_names[idx]; parent_names[0] = clk_hw_get_name(&vc5->clk_fod[idx].hw);
if (n == 1) if (n == 1)
parent_names[1] = vc5_mux_names[0]; parent_names[1] = clk_hw_get_name(&vc5->clk_mux);
else else
parent_names[1] = vc5_clk_out_names[n - 1]; parent_names[1] =
clk_hw_get_name(&vc5->clk_out[n - 1].hw);
memset(&init, 0, sizeof(init)); memset(&init, 0, sizeof(init));
init.name = vc5_clk_out_names[idx + 1]; init.name = kasprintf(GFP_KERNEL, "%pOFn.out%d",
client->dev.of_node, idx + 1);
init.ops = &vc5_clk_out_ops; init.ops = &vc5_clk_out_ops;
init.flags = CLK_SET_RATE_PARENT; init.flags = CLK_SET_RATE_PARENT;
init.parent_names = parent_names; init.parent_names = parent_names;
...@@ -866,8 +856,8 @@ static int vc5_probe(struct i2c_client *client, ...@@ -866,8 +856,8 @@ static int vc5_probe(struct i2c_client *client,
vc5->clk_out[n].num = idx; vc5->clk_out[n].num = idx;
vc5->clk_out[n].vc5 = vc5; vc5->clk_out[n].vc5 = vc5;
vc5->clk_out[n].hw.init = &init; vc5->clk_out[n].hw.init = &init;
ret = devm_clk_hw_register(&client->dev, ret = devm_clk_hw_register(&client->dev, &vc5->clk_out[n].hw);
&vc5->clk_out[n].hw); kfree(init.name); /* clock framework made a copy of the name */
if (ret) { if (ret) {
dev_err(&client->dev, "unable to register %s\n", dev_err(&client->dev, "unable to register %s\n",
init.name); init.name);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment