in clk-si5351.c [1370:1643]
static int si5351_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
enum si5351_variant variant = (enum si5351_variant)id->driver_data;
struct si5351_platform_data *pdata;
struct si5351_driver_data *drvdata;
struct clk_init_data init;
const char *parent_names[4];
u8 num_parents, num_clocks;
int ret, n;
ret = si5351_dt_parse(client, variant);
if (ret)
return ret;
pdata = client->dev.platform_data;
if (!pdata)
return -EINVAL;
drvdata = devm_kzalloc(&client->dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
i2c_set_clientdata(client, drvdata);
drvdata->client = client;
drvdata->variant = variant;
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)) {
dev_err(&client->dev, "failed to allocate register map\n");
return PTR_ERR(drvdata->regmap);
}
/* Disable interrupts */
si5351_reg_write(drvdata, SI5351_INTERRUPT_MASK, 0xf0);
/* Ensure pll select is on XTAL for Si5351A/B */
if (drvdata->variant != SI5351_VARIANT_C)
si5351_set_bits(drvdata, SI5351_PLL_INPUT_SOURCE,
SI5351_PLLA_SOURCE | SI5351_PLLB_SOURCE, 0);
/* setup clock configuration */
for (n = 0; n < 2; n++) {
ret = _si5351_pll_reparent(drvdata, n, pdata->pll_src[n]);
if (ret) {
dev_err(&client->dev,
"failed to reparent pll %d to %d\n",
n, pdata->pll_src[n]);
return ret;
}
}
for (n = 0; n < 8; n++) {
ret = _si5351_msynth_reparent(drvdata, n,
pdata->clkout[n].multisynth_src);
if (ret) {
dev_err(&client->dev,
"failed to reparent multisynth %d to %d\n",
n, pdata->clkout[n].multisynth_src);
return ret;
}
ret = _si5351_clkout_reparent(drvdata, n,
pdata->clkout[n].clkout_src);
if (ret) {
dev_err(&client->dev,
"failed to reparent clkout %d to %d\n",
n, pdata->clkout[n].clkout_src);
return ret;
}
ret = _si5351_clkout_set_drive_strength(drvdata, n,
pdata->clkout[n].drive);
if (ret) {
dev_err(&client->dev,
"failed set drive strength of clkout%d to %d\n",
n, pdata->clkout[n].drive);
return ret;
}
ret = _si5351_clkout_set_disable_state(drvdata, n,
pdata->clkout[n].disable_state);
if (ret) {
dev_err(&client->dev,
"failed set disable state of clkout%d to %d\n",
n, pdata->clkout[n].disable_state);
return ret;
}
}
/* register xtal input clock gate */
memset(&init, 0, sizeof(init));
init.name = si5351_input_names[0];
init.ops = &si5351_xtal_ops;
init.flags = 0;
if (!IS_ERR(drvdata->pxtal)) {
drvdata->pxtal_name = __clk_get_name(drvdata->pxtal);
init.parent_names = &drvdata->pxtal_name;
init.num_parents = 1;
}
drvdata->xtal.init = &init;
ret = devm_clk_hw_register(&client->dev, &drvdata->xtal);
if (ret) {
dev_err(&client->dev, "unable to register %s\n", init.name);
return ret;
}
/* register clkin input clock gate */
if (drvdata->variant == SI5351_VARIANT_C) {
memset(&init, 0, sizeof(init));
init.name = si5351_input_names[1];
init.ops = &si5351_clkin_ops;
if (!IS_ERR(drvdata->pclkin)) {
drvdata->pclkin_name = __clk_get_name(drvdata->pclkin);
init.parent_names = &drvdata->pclkin_name;
init.num_parents = 1;
}
drvdata->clkin.init = &init;
ret = devm_clk_hw_register(&client->dev, &drvdata->clkin);
if (ret) {
dev_err(&client->dev, "unable to register %s\n",
init.name);
return ret;
}
}
/* Si5351C allows to mux either xtal or clkin to PLL input */
num_parents = (drvdata->variant == SI5351_VARIANT_C) ? 2 : 1;
parent_names[0] = si5351_input_names[0];
parent_names[1] = si5351_input_names[1];
/* register PLLA */
drvdata->pll[0].num = 0;
drvdata->pll[0].drvdata = drvdata;
drvdata->pll[0].hw.init = &init;
memset(&init, 0, sizeof(init));
init.name = si5351_pll_names[0];
init.ops = &si5351_pll_ops;
init.flags = 0;
init.parent_names = parent_names;
init.num_parents = num_parents;
ret = devm_clk_hw_register(&client->dev, &drvdata->pll[0].hw);
if (ret) {
dev_err(&client->dev, "unable to register %s\n", init.name);
return ret;
}
/* register PLLB or VXCO (Si5351B) */
drvdata->pll[1].num = 1;
drvdata->pll[1].drvdata = drvdata;
drvdata->pll[1].hw.init = &init;
memset(&init, 0, sizeof(init));
if (drvdata->variant == SI5351_VARIANT_B) {
init.name = si5351_pll_names[2];
init.ops = &si5351_vxco_ops;
init.flags = 0;
init.parent_names = NULL;
init.num_parents = 0;
} else {
init.name = si5351_pll_names[1];
init.ops = &si5351_pll_ops;
init.flags = 0;
init.parent_names = parent_names;
init.num_parents = num_parents;
}
ret = devm_clk_hw_register(&client->dev, &drvdata->pll[1].hw);
if (ret) {
dev_err(&client->dev, "unable to register %s\n", init.name);
return ret;
}
/* register clk multisync and clk out divider */
num_clocks = (drvdata->variant == SI5351_VARIANT_A3) ? 3 : 8;
parent_names[0] = si5351_pll_names[0];
if (drvdata->variant == SI5351_VARIANT_B)
parent_names[1] = si5351_pll_names[2];
else
parent_names[1] = si5351_pll_names[1];
drvdata->msynth = devm_kcalloc(&client->dev, num_clocks,
sizeof(*drvdata->msynth), GFP_KERNEL);
drvdata->clkout = devm_kcalloc(&client->dev, num_clocks,
sizeof(*drvdata->clkout), GFP_KERNEL);
drvdata->num_clkout = num_clocks;
if (WARN_ON(!drvdata->msynth || !drvdata->clkout)) {
ret = -ENOMEM;
return ret;
}
for (n = 0; n < num_clocks; n++) {
drvdata->msynth[n].num = n;
drvdata->msynth[n].drvdata = drvdata;
drvdata->msynth[n].hw.init = &init;
memset(&init, 0, sizeof(init));
init.name = si5351_msynth_names[n];
init.ops = &si5351_msynth_ops;
init.flags = 0;
if (pdata->clkout[n].pll_master)
init.flags |= CLK_SET_RATE_PARENT;
init.parent_names = parent_names;
init.num_parents = 2;
ret = devm_clk_hw_register(&client->dev,
&drvdata->msynth[n].hw);
if (ret) {
dev_err(&client->dev, "unable to register %s\n",
init.name);
return ret;
}
}
num_parents = (drvdata->variant == SI5351_VARIANT_C) ? 4 : 3;
parent_names[2] = si5351_input_names[0];
parent_names[3] = si5351_input_names[1];
for (n = 0; n < num_clocks; n++) {
parent_names[0] = si5351_msynth_names[n];
parent_names[1] = (n < 4) ? si5351_msynth_names[0] :
si5351_msynth_names[4];
drvdata->clkout[n].num = n;
drvdata->clkout[n].drvdata = drvdata;
drvdata->clkout[n].hw.init = &init;
memset(&init, 0, sizeof(init));
init.name = si5351_clkout_names[n];
init.ops = &si5351_clkout_ops;
init.flags = 0;
if (pdata->clkout[n].clkout_src == SI5351_CLKOUT_SRC_MSYNTH_N)
init.flags |= CLK_SET_RATE_PARENT;
init.parent_names = parent_names;
init.num_parents = num_parents;
ret = devm_clk_hw_register(&client->dev,
&drvdata->clkout[n].hw);
if (ret) {
dev_err(&client->dev, "unable to register %s\n",
init.name);
return ret;
}
/* set initial clkout rate */
if (pdata->clkout[n].rate != 0) {
int ret;
ret = clk_set_rate(drvdata->clkout[n].hw.clk,
pdata->clkout[n].rate);
if (ret != 0) {
dev_err(&client->dev, "Cannot set rate : %d\n",
ret);
}
}
}
ret = of_clk_add_hw_provider(client->dev.of_node, si53351_of_clk_get,
drvdata);
if (ret) {
dev_err(&client->dev, "unable to add clk provider\n");
return ret;
}
return 0;
}