Ejemplo n.º 1
0
/**
 * of_ti_dpll_setup - Setup function for OMAP DPLL clocks
 * @node: device node containing the DPLL info
 * @ops: ops for the DPLL
 * @ddt: DPLL data template to use
 *
 * Initializes a DPLL clock from device tree data.
 */
static void __init of_ti_dpll_setup(struct device_node *node,
				    const struct clk_ops *ops,
				    const struct dpll_data *ddt)
{
	struct clk_hw_omap *clk_hw = NULL;
	struct clk_init_data *init = NULL;
	const char **parent_names = NULL;
	struct dpll_data *dd = NULL;
	int i;
	u8 dpll_mode = 0;

	dd = kzalloc(sizeof(*dd), GFP_KERNEL);
	clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
	init = kzalloc(sizeof(*init), GFP_KERNEL);
	if (!dd || !clk_hw || !init)
		goto cleanup;

	memcpy(dd, ddt, sizeof(*dd));

	clk_hw->dpll_data = dd;
	clk_hw->ops = &clkhwops_omap3_dpll;
	clk_hw->hw.init = init;
	clk_hw->flags = MEMMAP_ADDRESSING;

	init->name = node->name;
	init->ops = ops;

	init->num_parents = of_clk_get_parent_count(node);
	if (init->num_parents < 1) {
		pr_err("%s must have parent(s)\n", node->name);
		goto cleanup;
	}

	parent_names = kzalloc(sizeof(char *) * init->num_parents, GFP_KERNEL);
	if (!parent_names)
		goto cleanup;

	for (i = 0; i < init->num_parents; i++)
		parent_names[i] = of_clk_get_parent_name(node, i);

	init->parent_names = parent_names;

	dd->control_reg = ti_clk_get_reg_addr(node, 0);

	/*
	 * Special case for OMAP2 DPLL, register order is different due to
	 * missing idlest_reg, also clkhwops is different. Detected from
	 * missing idlest_mask.
	 */
	if (!dd->idlest_mask) {
		dd->mult_div1_reg = ti_clk_get_reg_addr(node, 1);
#ifdef CONFIG_ARCH_OMAP2
		clk_hw->ops = &clkhwops_omap2xxx_dpll;
		omap2xxx_clkt_dpllcore_init(&clk_hw->hw);
#endif
	} else {
		dd->idlest_reg = ti_clk_get_reg_addr(node, 1);
		if (!dd->idlest_reg)
			goto cleanup;

		dd->mult_div1_reg = ti_clk_get_reg_addr(node, 2);
	}

	if (!dd->control_reg || !dd->mult_div1_reg)
		goto cleanup;

	if (dd->autoidle_mask) {
		dd->autoidle_reg = ti_clk_get_reg_addr(node, 3);
		if (!dd->autoidle_reg)
			goto cleanup;
	}

	if (of_property_read_bool(node, "ti,low-power-stop"))
		dpll_mode |= 1 << DPLL_LOW_POWER_STOP;

	if (of_property_read_bool(node, "ti,low-power-bypass"))
		dpll_mode |= 1 << DPLL_LOW_POWER_BYPASS;

	if (of_property_read_bool(node, "ti,lock"))
		dpll_mode |= 1 << DPLL_LOCKED;

	if (dpll_mode)
		dd->modes = dpll_mode;

	ti_clk_register_dpll(&clk_hw->hw, node);
	return;

cleanup:
	kfree(dd);
	kfree(parent_names);
	kfree(init);
	kfree(clk_hw);
}
Ejemplo n.º 2
0
/**
 * of_ti_dpll_setup - Setup function for OMAP DPLL clocks
 * @node: device node containing the DPLL info
 * @ops: ops for the DPLL
 * @ddt: DPLL data template to use
 * @init_flags: flags for controlling init types
 *
 * Initializes a DPLL clock from device tree data.
 */
static void __init of_ti_dpll_setup(struct device_node *node,
                                    const struct clk_ops *ops,
                                    const struct dpll_data *ddt,
                                    u8 init_flags)
{
    struct clk_hw_omap *clk_hw = NULL;
    struct clk_init_data *init = NULL;
    const char **parent_names = NULL;
    struct dpll_data *dd = NULL;
    int i;
    u8 dpll_mode = 0;

    dd = kzalloc(sizeof(*dd), GFP_KERNEL);
    clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
    init = kzalloc(sizeof(*init), GFP_KERNEL);
    if (!dd || !clk_hw || !init)
        goto cleanup;

    memcpy(dd, ddt, sizeof(*dd));

    clk_hw->dpll_data = dd;
    clk_hw->ops = &clkhwops_omap3_dpll;
    clk_hw->hw.init = init;
    clk_hw->flags = MEMMAP_ADDRESSING;

    init->name = node->name;
    init->ops = ops;

    init->num_parents = of_clk_get_parent_count(node);
    if (init->num_parents < 1) {
        pr_err("%s must have parent(s)\n", node->name);
        goto cleanup;
    }

    parent_names = kzalloc(sizeof(char *) * init->num_parents, GFP_KERNEL);
    if (!parent_names)
        goto cleanup;

    for (i = 0; i < init->num_parents; i++)
        parent_names[i] = of_clk_get_parent_name(node, i);

    init->parent_names = parent_names;

    dd->control_reg = ti_clk_get_reg_addr(node, 0);
    dd->idlest_reg = ti_clk_get_reg_addr(node, 1);
    dd->mult_div1_reg = ti_clk_get_reg_addr(node, 2);

    if (!dd->control_reg || !dd->idlest_reg || !dd->mult_div1_reg)
        goto cleanup;

    if (init_flags & DPLL_HAS_AUTOIDLE) {
        dd->autoidle_reg = ti_clk_get_reg_addr(node, 3);
        if (!dd->autoidle_reg)
            goto cleanup;
    }

    if (of_property_read_bool(node, "ti,low-power-stop"))
        dpll_mode |= 1 << DPLL_LOW_POWER_STOP;

    if (of_property_read_bool(node, "ti,low-power-bypass"))
        dpll_mode |= 1 << DPLL_LOW_POWER_BYPASS;

    if (of_property_read_bool(node, "ti,lock"))
        dpll_mode |= 1 << DPLL_LOCKED;

    if (dpll_mode)
        dd->modes = dpll_mode;

    ti_clk_register_dpll(&clk_hw->hw, node);
    return;

cleanup:
    kfree(dd);
    kfree(parent_names);
    kfree(init);
    kfree(clk_hw);
}