in ti/clkctrl.c [497:722]
static void __init _ti_omap4_clkctrl_setup(struct device_node *node)
{
struct omap_clkctrl_provider *provider;
const struct omap_clkctrl_data *data = default_clkctrl_data;
const struct omap_clkctrl_reg_data *reg_data;
struct clk_init_data init = { NULL };
struct clk_hw_omap *hw;
struct clk *clk;
struct omap_clkctrl_clk *clkctrl_clk = NULL;
const __be32 *addrp;
bool legacy_naming;
char *clkctrl_name;
u32 addr;
int ret;
char *c;
u16 soc_mask = 0;
if (!(ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT) &&
of_node_name_eq(node, "clk"))
ti_clk_features.flags |= TI_CLK_CLKCTRL_COMPAT;
addrp = of_get_address(node, 0, NULL, NULL);
addr = (u32)of_translate_address(node, addrp);
#ifdef CONFIG_ARCH_OMAP4
if (of_machine_is_compatible("ti,omap4"))
data = omap4_clkctrl_data;
#endif
#ifdef CONFIG_SOC_OMAP5
if (of_machine_is_compatible("ti,omap5"))
data = omap5_clkctrl_data;
#endif
#ifdef CONFIG_SOC_DRA7XX
if (of_machine_is_compatible("ti,dra7")) {
if (ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT)
data = dra7_clkctrl_compat_data;
else
data = dra7_clkctrl_data;
}
if (of_machine_is_compatible("ti,dra72"))
soc_mask = CLKF_SOC_DRA72;
if (of_machine_is_compatible("ti,dra74"))
soc_mask = CLKF_SOC_DRA74;
if (of_machine_is_compatible("ti,dra76"))
soc_mask = CLKF_SOC_DRA76;
#endif
#ifdef CONFIG_SOC_AM33XX
if (of_machine_is_compatible("ti,am33xx")) {
if (ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT)
data = am3_clkctrl_compat_data;
else
data = am3_clkctrl_data;
}
#endif
#ifdef CONFIG_SOC_AM43XX
if (of_machine_is_compatible("ti,am4372")) {
if (ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT)
data = am4_clkctrl_compat_data;
else
data = am4_clkctrl_data;
}
if (of_machine_is_compatible("ti,am438x")) {
if (ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT)
data = am438x_clkctrl_compat_data;
else
data = am438x_clkctrl_data;
}
#endif
#ifdef CONFIG_SOC_TI81XX
if (of_machine_is_compatible("ti,dm814"))
data = dm814_clkctrl_data;
if (of_machine_is_compatible("ti,dm816"))
data = dm816_clkctrl_data;
#endif
if (ti_clk_get_features()->flags & TI_CLK_DEVICE_TYPE_GP)
soc_mask |= CLKF_SOC_NONSEC;
while (data->addr) {
if (addr == data->addr)
break;
data++;
}
if (!data->addr) {
pr_err("%pOF not found from clkctrl data.\n", node);
return;
}
provider = kzalloc(sizeof(*provider), GFP_KERNEL);
if (!provider)
return;
provider->base = of_iomap(node, 0);
legacy_naming = ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT;
clkctrl_name = clkctrl_get_name(node);
if (clkctrl_name) {
provider->clkdm_name = kasprintf(GFP_KERNEL,
"%s_clkdm", clkctrl_name);
goto clkdm_found;
}
/*
* The code below can be removed when all clkctrl nodes use domain
* specific compatible proprerty and standard clock node naming
*/
if (legacy_naming) {
provider->clkdm_name = kasprintf(GFP_KERNEL, "%pOFnxxx", node->parent);
if (!provider->clkdm_name) {
kfree(provider);
return;
}
/*
* Create default clkdm name, replace _cm from end of parent
* node name with _clkdm
*/
provider->clkdm_name[strlen(provider->clkdm_name) - 2] = 0;
} else {
provider->clkdm_name = kasprintf(GFP_KERNEL, "%pOFn", node);
if (!provider->clkdm_name) {
kfree(provider);
return;
}
/*
* Create default clkdm name, replace _clkctrl from end of
* node name with _clkdm
*/
provider->clkdm_name[strlen(provider->clkdm_name) - 7] = 0;
}
strcat(provider->clkdm_name, "clkdm");
/* Replace any dash from the clkdm name with underscore */
c = provider->clkdm_name;
while (*c) {
if (*c == '-')
*c = '_';
c++;
}
clkdm_found:
INIT_LIST_HEAD(&provider->clocks);
/* Generate clocks */
reg_data = data->regs;
while (reg_data->parent) {
if ((reg_data->flags & CLKF_SOC_MASK) &&
(reg_data->flags & soc_mask) == 0) {
reg_data++;
continue;
}
hw = kzalloc(sizeof(*hw), GFP_KERNEL);
if (!hw)
return;
hw->enable_reg.ptr = provider->base + reg_data->offset;
_ti_clkctrl_setup_subclks(provider, node, reg_data,
hw->enable_reg.ptr, clkctrl_name);
if (reg_data->flags & CLKF_SW_SUP)
hw->enable_bit = MODULEMODE_SWCTRL;
if (reg_data->flags & CLKF_HW_SUP)
hw->enable_bit = MODULEMODE_HWCTRL;
if (reg_data->flags & CLKF_NO_IDLEST)
set_bit(NO_IDLEST, &hw->flags);
if (reg_data->clkdm_name)
hw->clkdm_name = reg_data->clkdm_name;
else
hw->clkdm_name = provider->clkdm_name;
init.parent_names = ®_data->parent;
init.num_parents = 1;
init.flags = 0;
if (reg_data->flags & CLKF_SET_RATE_PARENT)
init.flags |= CLK_SET_RATE_PARENT;
init.name = clkctrl_get_clock_name(node, clkctrl_name,
reg_data->offset, 0,
legacy_naming);
if (!init.name)
goto cleanup;
clkctrl_clk = kzalloc(sizeof(*clkctrl_clk), GFP_KERNEL);
if (!clkctrl_clk)
goto cleanup;
init.ops = &omap4_clkctrl_clk_ops;
hw->hw.init = &init;
clk = ti_clk_register_omap_hw(NULL, &hw->hw, init.name);
if (IS_ERR_OR_NULL(clk))
goto cleanup;
clkctrl_clk->reg_offset = reg_data->offset;
clkctrl_clk->clk = &hw->hw;
list_add(&clkctrl_clk->node, &provider->clocks);
reg_data++;
}
ret = of_clk_add_hw_provider(node, _ti_omap4_clkctrl_xlate, provider);
if (ret == -EPROBE_DEFER)
ti_clk_retry_init(node, provider, _clkctrl_add_provider);
kfree(clkctrl_name);
return;
cleanup:
kfree(hw);
kfree(init.name);
kfree(clkctrl_name);
kfree(clkctrl_clk);
}