Skip to content

Commit

Permalink
clk: si5351: Do not pass struct clk in platform_data
Browse files Browse the repository at this point in the history
When registering clk-si5351 by platform_data, we should not pass struct clk
for the reference clocks. Drop struct clk from platform_data and rework the
driver to use devm_clk_get of named clock references.

While at it, check for at least one valid input clock and properly prepare/
enable valid reference clocks.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Reported-by: Michael Welling <mwelling@ieee.org>
Reported-by: Jean-Francois Moine <moinejf@free.fr>
Reported-by: Russell King <rmk+linux@arm.linux.org.uk>
Tested-by: Michael Welling <mwelling@ieee.org>
Tested-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Michael Turquette <mturquette@linaro.org>
  • Loading branch information
shesselba authored and Michael Turquette committed May 8, 2015
1 parent f94029d commit 0cd3be6
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 22 deletions.
63 changes: 45 additions & 18 deletions drivers/clk/clk-si5351.c
Original file line number Diff line number Diff line change
Expand Up @@ -1128,13 +1128,6 @@ static int si5351_dt_parse(struct i2c_client *client,
if (!pdata)
return -ENOMEM;

pdata->clk_xtal = of_clk_get(np, 0);
if (!IS_ERR(pdata->clk_xtal))
clk_put(pdata->clk_xtal);
pdata->clk_clkin = of_clk_get(np, 1);
if (!IS_ERR(pdata->clk_clkin))
clk_put(pdata->clk_clkin);

/*
* property silabs,pll-source : <num src>, [<..>]
* allow to selectively set pll source
Expand Down Expand Up @@ -1328,8 +1321,22 @@ static int si5351_i2c_probe(struct i2c_client *client,
i2c_set_clientdata(client, drvdata);
drvdata->client = client;
drvdata->variant = variant;
drvdata->pxtal = pdata->clk_xtal;
drvdata->pclkin = pdata->clk_clkin;
drvdata->pxtal = devm_clk_get(&client->dev, "xtal");
drvdata->pclkin = devm_clk_get(&client->dev, "clkin");

if (PTR_ERR(drvdata->pxtal) == -EPROBE_DEFER ||
PTR_ERR(drvdata->pclkin) == -EPROBE_DEFER)
return -EPROBE_DEFER;

/*
* Check for valid parent clock: VARIANT_A and VARIANT_B need XTAL,
* VARIANT_C can have CLKIN instead.
*/
if (IS_ERR(drvdata->pxtal) &&
(drvdata->variant != SI5351_VARIANT_C || IS_ERR(drvdata->pclkin))) {
dev_err(&client->dev, "missing parent clock\n");
return -EINVAL;
}

drvdata->regmap = devm_regmap_init_i2c(client, &si5351_regmap_config);
if (IS_ERR(drvdata->regmap)) {
Expand Down Expand Up @@ -1393,6 +1400,11 @@ static int si5351_i2c_probe(struct i2c_client *client,
}
}

if (!IS_ERR(drvdata->pxtal))
clk_prepare_enable(drvdata->pxtal);
if (!IS_ERR(drvdata->pclkin))
clk_prepare_enable(drvdata->pclkin);

/* register xtal input clock gate */
memset(&init, 0, sizeof(init));
init.name = si5351_input_names[0];
Expand All @@ -1407,7 +1419,8 @@ static int si5351_i2c_probe(struct i2c_client *client,
clk = devm_clk_register(&client->dev, &drvdata->xtal);
if (IS_ERR(clk)) {
dev_err(&client->dev, "unable to register %s\n", init.name);
return PTR_ERR(clk);
ret = PTR_ERR(clk);
goto err_clk;
}

/* register clkin input clock gate */
Expand All @@ -1425,7 +1438,8 @@ static int si5351_i2c_probe(struct i2c_client *client,
if (IS_ERR(clk)) {
dev_err(&client->dev, "unable to register %s\n",
init.name);
return PTR_ERR(clk);
ret = PTR_ERR(clk);
goto err_clk;
}
}

Expand All @@ -1447,7 +1461,8 @@ static int si5351_i2c_probe(struct i2c_client *client,
clk = devm_clk_register(&client->dev, &drvdata->pll[0].hw);
if (IS_ERR(clk)) {
dev_err(&client->dev, "unable to register %s\n", init.name);
return -EINVAL;
ret = PTR_ERR(clk);
goto err_clk;
}

/* register PLLB or VXCO (Si5351B) */
Expand All @@ -1471,7 +1486,8 @@ static int si5351_i2c_probe(struct i2c_client *client,
clk = devm_clk_register(&client->dev, &drvdata->pll[1].hw);
if (IS_ERR(clk)) {
dev_err(&client->dev, "unable to register %s\n", init.name);
return -EINVAL;
ret = PTR_ERR(clk);
goto err_clk;
}

/* register clk multisync and clk out divider */
Expand All @@ -1492,8 +1508,10 @@ static int si5351_i2c_probe(struct i2c_client *client,
num_clocks * sizeof(*drvdata->onecell.clks), GFP_KERNEL);

if (WARN_ON(!drvdata->msynth || !drvdata->clkout ||
!drvdata->onecell.clks))
return -ENOMEM;
!drvdata->onecell.clks)) {
ret = -ENOMEM;
goto err_clk;
}

for (n = 0; n < num_clocks; n++) {
drvdata->msynth[n].num = n;
Expand All @@ -1511,7 +1529,8 @@ static int si5351_i2c_probe(struct i2c_client *client,
if (IS_ERR(clk)) {
dev_err(&client->dev, "unable to register %s\n",
init.name);
return -EINVAL;
ret = PTR_ERR(clk);
goto err_clk;
}
}

Expand All @@ -1538,7 +1557,8 @@ static int si5351_i2c_probe(struct i2c_client *client,
if (IS_ERR(clk)) {
dev_err(&client->dev, "unable to register %s\n",
init.name);
return -EINVAL;
ret = PTR_ERR(clk);
goto err_clk;
}
drvdata->onecell.clks[n] = clk;

Expand All @@ -1557,10 +1577,17 @@ static int si5351_i2c_probe(struct i2c_client *client,
&drvdata->onecell);
if (ret) {
dev_err(&client->dev, "unable to add clk provider\n");
return ret;
goto err_clk;
}

return 0;

err_clk:
if (!IS_ERR(drvdata->pxtal))
clk_disable_unprepare(drvdata->pxtal);
if (!IS_ERR(drvdata->pclkin))
clk_disable_unprepare(drvdata->pclkin);
return ret;
}

static const struct i2c_device_id si5351_i2c_ids[] = {
Expand Down
4 changes: 0 additions & 4 deletions include/linux/platform_data/si5351.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
#ifndef __LINUX_PLATFORM_DATA_SI5351_H__
#define __LINUX_PLATFORM_DATA_SI5351_H__

struct clk;

/**
* enum si5351_pll_src - Si5351 pll clock source
* @SI5351_PLL_SRC_DEFAULT: default, do not change eeprom config
Expand Down Expand Up @@ -107,8 +105,6 @@ struct si5351_clkout_config {
* @clkout: array of clkout configuration
*/
struct si5351_platform_data {
struct clk *clk_xtal;
struct clk *clk_clkin;
enum si5351_pll_src pll_src[2];
struct si5351_clkout_config clkout[8];
};
Expand Down

0 comments on commit 0cd3be6

Please sign in to comment.