in clk-si5341.c [1548:1796]
static int si5341_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct clk_si5341 *data;
struct clk_init_data init;
struct clk *input;
const char *root_clock_name;
const char *synth_clock_names[SI5341_NUM_SYNTH];
int err;
unsigned int i;
struct clk_si5341_output_config config[SI5341_MAX_NUM_OUTPUTS];
bool initialization_required;
u32 status;
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->i2c_client = client;
/* Must be done before otherwise touching hardware */
err = si5341_wait_device_ready(client);
if (err)
return err;
for (i = 0; i < SI5341_NUM_INPUTS; ++i) {
input = devm_clk_get(&client->dev, si5341_input_clock_names[i]);
if (IS_ERR(input)) {
if (PTR_ERR(input) == -EPROBE_DEFER)
return -EPROBE_DEFER;
data->input_clk_name[i] = si5341_input_clock_names[i];
} else {
data->input_clk[i] = input;
data->input_clk_name[i] = __clk_get_name(input);
}
}
for (i = 0; i < SI5341_MAX_NUM_OUTPUTS; ++i) {
char reg_name[10];
snprintf(reg_name, sizeof(reg_name), "vddo%d", i);
data->clk[i].vddo_reg = devm_regulator_get_optional(
&client->dev, reg_name);
if (IS_ERR(data->clk[i].vddo_reg)) {
err = PTR_ERR(data->clk[i].vddo_reg);
data->clk[i].vddo_reg = NULL;
if (err == -ENODEV)
continue;
goto cleanup;
} else {
err = regulator_enable(data->clk[i].vddo_reg);
if (err) {
dev_err(&client->dev,
"failed to enable %s regulator: %d\n",
reg_name, err);
data->clk[i].vddo_reg = NULL;
goto cleanup;
}
}
}
err = si5341_dt_parse_dt(data, config);
if (err)
goto cleanup;
if (of_property_read_string(client->dev.of_node, "clock-output-names",
&init.name))
init.name = client->dev.of_node->name;
root_clock_name = init.name;
data->regmap = devm_regmap_init_i2c(client, &si5341_regmap_config);
if (IS_ERR(data->regmap)) {
err = PTR_ERR(data->regmap);
goto cleanup;
}
i2c_set_clientdata(client, data);
err = si5341_probe_chip_id(data);
if (err < 0)
goto cleanup;
if (of_property_read_bool(client->dev.of_node, "silabs,reprogram")) {
initialization_required = true;
} else {
err = si5341_is_programmed_already(data);
if (err < 0)
goto cleanup;
initialization_required = !err;
}
data->xaxb_ext_clk = of_property_read_bool(client->dev.of_node,
"silabs,xaxb-ext-clk");
data->iovdd_33 = of_property_read_bool(client->dev.of_node,
"silabs,iovdd-33");
if (initialization_required) {
/* Populate the regmap cache in preparation for "cache only" */
err = si5341_read_settings(data);
if (err < 0)
goto cleanup;
err = si5341_send_preamble(data);
if (err < 0)
goto cleanup;
/*
* We intend to send all 'final' register values in a single
* transaction. So cache all register writes until we're done
* configuring.
*/
regcache_cache_only(data->regmap, true);
/* Write the configuration pairs from the firmware blob */
err = si5341_write_multiple(data, si5341_reg_defaults,
ARRAY_SIZE(si5341_reg_defaults));
if (err < 0)
goto cleanup;
}
/* Input must be up and running at this point */
err = si5341_clk_select_active_input(data);
if (err < 0)
goto cleanup;
if (initialization_required) {
/* PLL configuration is required */
err = si5341_initialize_pll(data);
if (err < 0)
goto cleanup;
}
/* Register the PLL */
init.parent_names = data->input_clk_name;
init.num_parents = SI5341_NUM_INPUTS;
init.ops = &si5341_clk_ops;
init.flags = 0;
data->hw.init = &init;
err = devm_clk_hw_register(&client->dev, &data->hw);
if (err) {
dev_err(&client->dev, "clock registration failed\n");
goto cleanup;
}
init.num_parents = 1;
init.parent_names = &root_clock_name;
init.ops = &si5341_synth_clk_ops;
for (i = 0; i < data->num_synth; ++i) {
synth_clock_names[i] = devm_kasprintf(&client->dev, GFP_KERNEL,
"%s.N%u", client->dev.of_node->name, i);
init.name = synth_clock_names[i];
data->synth[i].index = i;
data->synth[i].data = data;
data->synth[i].hw.init = &init;
err = devm_clk_hw_register(&client->dev, &data->synth[i].hw);
if (err) {
dev_err(&client->dev,
"synth N%u registration failed\n", i);
}
}
init.num_parents = data->num_synth;
init.parent_names = synth_clock_names;
init.ops = &si5341_output_clk_ops;
for (i = 0; i < data->num_outputs; ++i) {
init.name = kasprintf(GFP_KERNEL, "%s.%d",
client->dev.of_node->name, i);
init.flags = config[i].synth_master ? CLK_SET_RATE_PARENT : 0;
data->clk[i].index = i;
data->clk[i].data = data;
data->clk[i].hw.init = &init;
if (config[i].out_format_drv_bits & 0x07) {
regmap_write(data->regmap,
SI5341_OUT_FORMAT(&data->clk[i]),
config[i].out_format_drv_bits);
regmap_write(data->regmap,
SI5341_OUT_CM(&data->clk[i]),
config[i].out_cm_ampl_bits);
regmap_update_bits(data->regmap,
SI5341_OUT_MUX_SEL(&data->clk[i]),
SI5341_OUT_MUX_VDD_SEL_MASK,
config[i].vdd_sel_bits);
}
err = devm_clk_hw_register(&client->dev, &data->clk[i].hw);
kfree(init.name); /* clock framework made a copy of the name */
if (err) {
dev_err(&client->dev,
"output %u registration failed\n", i);
goto cleanup;
}
if (config[i].always_on)
clk_prepare(data->clk[i].hw.clk);
}
err = of_clk_add_hw_provider(client->dev.of_node, of_clk_si5341_get,
data);
if (err) {
dev_err(&client->dev, "unable to add clk provider\n");
goto cleanup;
}
if (initialization_required) {
/* Synchronize */
regcache_cache_only(data->regmap, false);
err = regcache_sync(data->regmap);
if (err < 0)
goto cleanup;
err = si5341_finalize_defaults(data);
if (err < 0)
goto cleanup;
}
/* wait for device to report input clock present and PLL lock */
err = regmap_read_poll_timeout(data->regmap, SI5341_STATUS, status,
!(status & (SI5341_STATUS_LOSREF | SI5341_STATUS_LOL)),
10000, 250000);
if (err) {
dev_err(&client->dev, "Error waiting for input clock or PLL lock\n");
goto cleanup;
}
/* clear sticky alarm bits from initialization */
err = regmap_write(data->regmap, SI5341_STATUS_STICKY, 0);
if (err) {
dev_err(&client->dev, "unable to clear sticky status\n");
goto cleanup;
}
err = sysfs_create_files(&client->dev.kobj, si5341_attributes);
if (err) {
dev_err(&client->dev, "unable to create sysfs files\n");
goto cleanup;
}
/* Free the names, clk framework makes copies */
for (i = 0; i < data->num_synth; ++i)
devm_kfree(&client->dev, (void *)synth_clock_names[i]);
return 0;
cleanup:
for (i = 0; i < SI5341_MAX_NUM_OUTPUTS; ++i) {
if (data->clk[i].vddo_reg)
regulator_disable(data->clk[i].vddo_reg);
}
return err;
}