in at91/sama7g5.c [882:1132]
static void __init sama7g5_pmc_setup(struct device_node *np)
{
const char *td_slck_name, *md_slck_name, *mainxtal_name;
struct pmc_data *sama7g5_pmc;
const char *parent_names[10];
void **alloc_mem = NULL;
int alloc_mem_size = 0;
struct regmap *regmap;
struct clk_hw *hw;
bool bypass;
int i, j;
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;
sama7g5_pmc = pmc_data_allocate(PMC_CPU + 1,
nck(sama7g5_systemck),
nck(sama7g5_periphck),
nck(sama7g5_gck), 8);
if (!sama7g5_pmc)
return;
alloc_mem = kmalloc(sizeof(void *) *
(ARRAY_SIZE(sama7g5_mckx) + ARRAY_SIZE(sama7g5_gck)),
GFP_KERNEL);
if (!alloc_mem)
goto err_free;
hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000000,
50000000);
if (IS_ERR(hw))
goto err_free;
bypass = of_property_read_bool(np, "atmel,osc-bypass");
hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name,
bypass);
if (IS_ERR(hw))
goto err_free;
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;
sama7g5_pmc->chws[PMC_MAIN] = hw;
for (i = 0; i < PLL_ID_MAX; i++) {
for (j = 0; j < 3; j++) {
struct clk_hw *parent_hw;
if (!sama7g5_plls[i][j].n)
continue;
switch (sama7g5_plls[i][j].t) {
case PLL_TYPE_FRAC:
if (!strcmp(sama7g5_plls[i][j].p, "mainck"))
parent_hw = sama7g5_pmc->chws[PMC_MAIN];
else
parent_hw = __clk_get_hw(of_clk_get_by_name(np,
sama7g5_plls[i][j].p));
hw = sam9x60_clk_register_frac_pll(regmap,
&pmc_pll_lock, sama7g5_plls[i][j].n,
sama7g5_plls[i][j].p, parent_hw, i,
sama7g5_plls[i][j].c,
sama7g5_plls[i][j].l,
sama7g5_plls[i][j].f);
break;
case PLL_TYPE_DIV:
hw = sam9x60_clk_register_div_pll(regmap,
&pmc_pll_lock, sama7g5_plls[i][j].n,
sama7g5_plls[i][j].p, i,
sama7g5_plls[i][j].c,
sama7g5_plls[i][j].l,
sama7g5_plls[i][j].f,
sama7g5_plls[i][j].safe_div);
break;
default:
continue;
}
if (IS_ERR(hw))
goto err_free;
if (sama7g5_plls[i][j].eid)
sama7g5_pmc->chws[sama7g5_plls[i][j].eid] = hw;
}
}
parent_names[0] = "cpupll_divpmcck";
hw = at91_clk_register_master_div(regmap, "mck0", "cpupll_divpmcck",
&mck0_layout, &mck0_characteristics,
&pmc_mck0_lock, CLK_GET_RATE_NOCACHE, 5);
if (IS_ERR(hw))
goto err_free;
sama7g5_pmc->chws[PMC_MCK] = hw;
parent_names[0] = md_slck_name;
parent_names[1] = td_slck_name;
parent_names[2] = "mainck";
for (i = 0; i < ARRAY_SIZE(sama7g5_mckx); i++) {
u8 num_parents = 3 + sama7g5_mckx[i].ep_count;
u32 *mux_table;
mux_table = kmalloc_array(num_parents, sizeof(*mux_table),
GFP_KERNEL);
if (!mux_table)
goto err_free;
SAMA7G5_INIT_TABLE(mux_table, 3);
SAMA7G5_FILL_TABLE(&mux_table[3], sama7g5_mckx[i].ep_mux_table,
sama7g5_mckx[i].ep_count);
SAMA7G5_FILL_TABLE(&parent_names[3], sama7g5_mckx[i].ep,
sama7g5_mckx[i].ep_count);
hw = at91_clk_sama7g5_register_master(regmap, sama7g5_mckx[i].n,
num_parents, parent_names, mux_table,
&pmc_mckX_lock, sama7g5_mckx[i].id,
sama7g5_mckx[i].c,
sama7g5_mckx[i].ep_chg_id);
if (IS_ERR(hw))
goto err_free;
alloc_mem[alloc_mem_size++] = mux_table;
}
hw = at91_clk_sama7g5_register_utmi(regmap, "utmick", "main_xtal");
if (IS_ERR(hw))
goto err_free;
sama7g5_pmc->chws[PMC_UTMI] = hw;
parent_names[0] = md_slck_name;
parent_names[1] = td_slck_name;
parent_names[2] = "mainck";
parent_names[3] = "syspll_divpmcck";
parent_names[4] = "ddrpll_divpmcck";
parent_names[5] = "imgpll_divpmcck";
parent_names[6] = "baudpll_divpmcck";
parent_names[7] = "audiopll_divpmcck";
parent_names[8] = "ethpll_divpmcck";
for (i = 0; i < 8; i++) {
char name[6];
snprintf(name, sizeof(name), "prog%d", i);
hw = at91_clk_register_programmable(regmap, name, parent_names,
9, i,
&programmable_layout,
sama7g5_prog_mux_table);
if (IS_ERR(hw))
goto err_free;
sama7g5_pmc->pchws[i] = hw;
}
for (i = 0; i < ARRAY_SIZE(sama7g5_systemck); i++) {
hw = at91_clk_register_system(regmap, sama7g5_systemck[i].n,
sama7g5_systemck[i].p,
sama7g5_systemck[i].id);
if (IS_ERR(hw))
goto err_free;
sama7g5_pmc->shws[sama7g5_systemck[i].id] = hw;
}
for (i = 0; i < ARRAY_SIZE(sama7g5_periphck); i++) {
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
&sama7g5_pcr_layout,
sama7g5_periphck[i].n,
sama7g5_periphck[i].p,
sama7g5_periphck[i].id,
&sama7g5_periphck[i].r,
sama7g5_periphck[i].chgp ? 0 :
INT_MIN);
if (IS_ERR(hw))
goto err_free;
sama7g5_pmc->phws[sama7g5_periphck[i].id] = hw;
}
parent_names[0] = md_slck_name;
parent_names[1] = td_slck_name;
parent_names[2] = "mainck";
for (i = 0; i < ARRAY_SIZE(sama7g5_gck); i++) {
u8 num_parents = 3 + sama7g5_gck[i].pp_count;
u32 *mux_table;
mux_table = kmalloc_array(num_parents, sizeof(*mux_table),
GFP_KERNEL);
if (!mux_table)
goto err_free;
SAMA7G5_INIT_TABLE(mux_table, 3);
SAMA7G5_FILL_TABLE(&mux_table[3], sama7g5_gck[i].pp_mux_table,
sama7g5_gck[i].pp_count);
SAMA7G5_FILL_TABLE(&parent_names[3], sama7g5_gck[i].pp,
sama7g5_gck[i].pp_count);
hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
&sama7g5_pcr_layout,
sama7g5_gck[i].n,
parent_names, mux_table,
num_parents,
sama7g5_gck[i].id,
&sama7g5_gck[i].r,
sama7g5_gck[i].pp_chg_id);
if (IS_ERR(hw))
goto err_free;
sama7g5_pmc->ghws[sama7g5_gck[i].id] = hw;
alloc_mem[alloc_mem_size++] = mux_table;
}
of_clk_add_hw_provider(np, of_clk_hw_pmc_get, sama7g5_pmc);
return;
err_free:
if (alloc_mem) {
for (i = 0; i < alloc_mem_size; i++)
kfree(alloc_mem[i]);
kfree(alloc_mem);
}
kfree(sama7g5_pmc);
}