static int si5341_probe()

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;
}