static void __init sam9x60_pmc_setup()

in at91/sam9x60.c [168:358]


static void __init sam9x60_pmc_setup(struct device_node *np)
{
	struct clk_range range = CLK_RANGE(0, 0);
	const char *td_slck_name, *md_slck_name, *mainxtal_name;
	struct pmc_data *sam9x60_pmc;
	const char *parent_names[6];
	struct clk_hw *main_osc_hw;
	struct regmap *regmap;
	struct clk_hw *hw;
	int i;

	i = of_property_match_string(np, "clock-names", "td_slck");
	if (i < 0)
		return;

	td_slck_name = of_clk_get_parent_name(np, i);

	i = of_property_match_string(np, "clock-names", "md_slck");
	if (i < 0)
		return;

	md_slck_name = of_clk_get_parent_name(np, i);

	i = of_property_match_string(np, "clock-names", "main_xtal");
	if (i < 0)
		return;
	mainxtal_name = of_clk_get_parent_name(np, i);

	regmap = device_node_to_regmap(np);
	if (IS_ERR(regmap))
		return;

	sam9x60_pmc = pmc_data_allocate(PMC_PLLACK + 1,
					nck(sam9x60_systemck),
					nck(sam9x60_periphck),
					nck(sam9x60_gck), 8);
	if (!sam9x60_pmc)
		return;

	hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000000,
					   50000000);
	if (IS_ERR(hw))
		goto err_free;

	hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name, 0);
	if (IS_ERR(hw))
		goto err_free;
	main_osc_hw = hw;

	parent_names[0] = "main_rc_osc";
	parent_names[1] = "main_osc";
	hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, 2);
	if (IS_ERR(hw))
		goto err_free;

	sam9x60_pmc->chws[PMC_MAIN] = hw;

	hw = sam9x60_clk_register_frac_pll(regmap, &pmc_pll_lock, "pllack_fracck",
					   "mainck", sam9x60_pmc->chws[PMC_MAIN],
					   0, &plla_characteristics,
					   &pll_frac_layout,
					   /*
					    * This feeds pllack_divck which
					    * feeds CPU. It should not be
					    * disabled.
					    */
					   CLK_IS_CRITICAL | CLK_SET_RATE_GATE);
	if (IS_ERR(hw))
		goto err_free;

	hw = sam9x60_clk_register_div_pll(regmap, &pmc_pll_lock, "pllack_divck",
					  "pllack_fracck", 0, &plla_characteristics,
					  &pll_div_layout,
					   /*
					    * This feeds CPU. It should not
					    * be disabled.
					    */
					  CLK_IS_CRITICAL | CLK_SET_RATE_GATE, 0);
	if (IS_ERR(hw))
		goto err_free;

	sam9x60_pmc->chws[PMC_PLLACK] = hw;

	hw = sam9x60_clk_register_frac_pll(regmap, &pmc_pll_lock, "upllck_fracck",
					   "main_osc", main_osc_hw, 1,
					   &upll_characteristics,
					   &pll_frac_layout, CLK_SET_RATE_GATE);
	if (IS_ERR(hw))
		goto err_free;

	hw = sam9x60_clk_register_div_pll(regmap, &pmc_pll_lock, "upllck_divck",
					  "upllck_fracck", 1, &upll_characteristics,
					  &pll_div_layout,
					  CLK_SET_RATE_GATE |
					  CLK_SET_PARENT_GATE |
					  CLK_SET_RATE_PARENT, 0);
	if (IS_ERR(hw))
		goto err_free;

	sam9x60_pmc->chws[PMC_UTMI] = hw;

	parent_names[0] = md_slck_name;
	parent_names[1] = "mainck";
	parent_names[2] = "pllack_divck";
	hw = at91_clk_register_master_pres(regmap, "masterck_pres", 3,
					   parent_names, &sam9x60_master_layout,
					   &mck_characteristics, &mck_lock,
					   CLK_SET_RATE_GATE, INT_MIN);
	if (IS_ERR(hw))
		goto err_free;

	hw = at91_clk_register_master_div(regmap, "masterck_div",
					  "masterck_pres", &sam9x60_master_layout,
					  &mck_characteristics, &mck_lock,
					  CLK_SET_RATE_GATE, 0);
	if (IS_ERR(hw))
		goto err_free;

	sam9x60_pmc->chws[PMC_MCK] = hw;

	parent_names[0] = "pllack_divck";
	parent_names[1] = "upllck_divck";
	parent_names[2] = "main_osc";
	hw = sam9x60_clk_register_usb(regmap, "usbck", parent_names, 3);
	if (IS_ERR(hw))
		goto err_free;

	parent_names[0] = md_slck_name;
	parent_names[1] = td_slck_name;
	parent_names[2] = "mainck";
	parent_names[3] = "masterck_div";
	parent_names[4] = "pllack_divck";
	parent_names[5] = "upllck_divck";
	for (i = 0; i < 2; i++) {
		char name[6];

		snprintf(name, sizeof(name), "prog%d", i);

		hw = at91_clk_register_programmable(regmap, name,
						    parent_names, 6, i,
						    &sam9x60_programmable_layout,
						    NULL);
		if (IS_ERR(hw))
			goto err_free;

		sam9x60_pmc->pchws[i] = hw;
	}

	for (i = 0; i < ARRAY_SIZE(sam9x60_systemck); i++) {
		hw = at91_clk_register_system(regmap, sam9x60_systemck[i].n,
					      sam9x60_systemck[i].p,
					      sam9x60_systemck[i].id);
		if (IS_ERR(hw))
			goto err_free;

		sam9x60_pmc->shws[sam9x60_systemck[i].id] = hw;
	}

	for (i = 0; i < ARRAY_SIZE(sam9x60_periphck); i++) {
		hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
							 &sam9x60_pcr_layout,
							 sam9x60_periphck[i].n,
							 "masterck_div",
							 sam9x60_periphck[i].id,
							 &range, INT_MIN);
		if (IS_ERR(hw))
			goto err_free;

		sam9x60_pmc->phws[sam9x60_periphck[i].id] = hw;
	}

	for (i = 0; i < ARRAY_SIZE(sam9x60_gck); i++) {
		hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
						 &sam9x60_pcr_layout,
						 sam9x60_gck[i].n,
						 parent_names, NULL, 6,
						 sam9x60_gck[i].id,
						 &sam9x60_gck[i].r, INT_MIN);
		if (IS_ERR(hw))
			goto err_free;

		sam9x60_pmc->ghws[sam9x60_gck[i].id] = hw;
	}

	of_clk_add_hw_provider(np, of_clk_hw_pmc_get, sam9x60_pmc);

	return;

err_free:
	kfree(sam9x60_pmc);
}