static void __init _ti_omap4_clkctrl_setup()

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 = &reg_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);
}