static int si5351_i2c_probe()

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