static int si5351_dt_parse()

in clk-si5351.c [1163:1342]


static int si5351_dt_parse(struct i2c_client *client,
			   enum si5351_variant variant)
{
	struct device_node *child, *np = client->dev.of_node;
	struct si5351_platform_data *pdata;
	struct property *prop;
	const __be32 *p;
	int num = 0;
	u32 val;

	if (np == NULL)
		return 0;

	pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
	if (!pdata)
		return -ENOMEM;

	/*
	 * property silabs,pll-source : <num src>, [<..>]
	 * allow to selectively set pll source
	 */
	of_property_for_each_u32(np, "silabs,pll-source", prop, p, num) {
		if (num >= 2) {
			dev_err(&client->dev,
				"invalid pll %d on pll-source prop\n", num);
			return -EINVAL;
		}

		p = of_prop_next_u32(prop, p, &val);
		if (!p) {
			dev_err(&client->dev,
				"missing pll-source for pll %d\n", num);
			return -EINVAL;
		}

		switch (val) {
		case 0:
			pdata->pll_src[num] = SI5351_PLL_SRC_XTAL;
			break;
		case 1:
			if (variant != SI5351_VARIANT_C) {
				dev_err(&client->dev,
					"invalid parent %d for pll %d\n",
					val, num);
				return -EINVAL;
			}
			pdata->pll_src[num] = SI5351_PLL_SRC_CLKIN;
			break;
		default:
			dev_err(&client->dev,
				 "invalid parent %d for pll %d\n", val, num);
			return -EINVAL;
		}
	}

	/* per clkout properties */
	for_each_child_of_node(np, child) {
		if (of_property_read_u32(child, "reg", &num)) {
			dev_err(&client->dev, "missing reg property of %pOFn\n",
				child);
			goto put_child;
		}

		if (num >= 8 ||
		    (variant == SI5351_VARIANT_A3 && num >= 3)) {
			dev_err(&client->dev, "invalid clkout %d\n", num);
			goto put_child;
		}

		if (!of_property_read_u32(child, "silabs,multisynth-source",
					  &val)) {
			switch (val) {
			case 0:
				pdata->clkout[num].multisynth_src =
					SI5351_MULTISYNTH_SRC_VCO0;
				break;
			case 1:
				pdata->clkout[num].multisynth_src =
					SI5351_MULTISYNTH_SRC_VCO1;
				break;
			default:
				dev_err(&client->dev,
					"invalid parent %d for multisynth %d\n",
					val, num);
				goto put_child;
			}
		}

		if (!of_property_read_u32(child, "silabs,clock-source", &val)) {
			switch (val) {
			case 0:
				pdata->clkout[num].clkout_src =
					SI5351_CLKOUT_SRC_MSYNTH_N;
				break;
			case 1:
				pdata->clkout[num].clkout_src =
					SI5351_CLKOUT_SRC_MSYNTH_0_4;
				break;
			case 2:
				pdata->clkout[num].clkout_src =
					SI5351_CLKOUT_SRC_XTAL;
				break;
			case 3:
				if (variant != SI5351_VARIANT_C) {
					dev_err(&client->dev,
						"invalid parent %d for clkout %d\n",
						val, num);
					goto put_child;
				}
				pdata->clkout[num].clkout_src =
					SI5351_CLKOUT_SRC_CLKIN;
				break;
			default:
				dev_err(&client->dev,
					"invalid parent %d for clkout %d\n",
					val, num);
				goto put_child;
			}
		}

		if (!of_property_read_u32(child, "silabs,drive-strength",
					  &val)) {
			switch (val) {
			case SI5351_DRIVE_2MA:
			case SI5351_DRIVE_4MA:
			case SI5351_DRIVE_6MA:
			case SI5351_DRIVE_8MA:
				pdata->clkout[num].drive = val;
				break;
			default:
				dev_err(&client->dev,
					"invalid drive strength %d for clkout %d\n",
					val, num);
				goto put_child;
			}
		}

		if (!of_property_read_u32(child, "silabs,disable-state",
					  &val)) {
			switch (val) {
			case 0:
				pdata->clkout[num].disable_state =
					SI5351_DISABLE_LOW;
				break;
			case 1:
				pdata->clkout[num].disable_state =
					SI5351_DISABLE_HIGH;
				break;
			case 2:
				pdata->clkout[num].disable_state =
					SI5351_DISABLE_FLOATING;
				break;
			case 3:
				pdata->clkout[num].disable_state =
					SI5351_DISABLE_NEVER;
				break;
			default:
				dev_err(&client->dev,
					"invalid disable state %d for clkout %d\n",
					val, num);
				goto put_child;
			}
		}

		if (!of_property_read_u32(child, "clock-frequency", &val))
			pdata->clkout[num].rate = val;

		pdata->clkout[num].pll_master =
			of_property_read_bool(child, "silabs,pll-master");

		pdata->clkout[num].pll_reset =
			of_property_read_bool(child, "silabs,pll-reset");
	}
	client->dev.platform_data = pdata;

	return 0;
put_child:
	of_node_put(child);
	return -EINVAL;
}