Beispiel #1
0
static void __init of_dra7_apll_setup(struct device_node *node)
{
	struct dpll_data *ad = NULL;
	struct clk_hw_omap *clk_hw = NULL;
	struct clk_init_data *init = NULL;
	const char **parent_names = NULL;
	int i;

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

	clk_hw->dpll_data = ad;
	clk_hw->hw.init = init;
	clk_hw->flags = MEMMAP_ADDRESSING;

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

	init->num_parents = of_clk_get_parent_count(node);
	if (init->num_parents < 1) {
		pr_err("dra7 apll %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;

	ad->control_reg = ti_clk_get_reg_addr(node, 0);
	ad->idlest_reg = ti_clk_get_reg_addr(node, 1);

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

	ad->idlest_mask = 0x1;
	ad->enable_mask = 0x3;

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

cleanup:
	kfree(parent_names);
	kfree(ad);
	kfree(clk_hw);
	kfree(init);
}
static void __init
_of_ti_composite_gate_clk_setup(struct device_node *node,
				const struct clk_hw_omap_ops *hw_ops)
{
	struct clk_hw_omap *gate;
	u32 val = 0;

	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
	if (!gate)
		return;

	gate->enable_reg = ti_clk_get_reg_addr(node, 0);
	if (IS_ERR(gate->enable_reg))
		goto cleanup;

	of_property_read_u32(node, "ti,bit-shift", &val);

	gate->enable_bit = val;
	gate->ops = hw_ops;
	gate->flags = MEMMAP_ADDRESSING;

	if (!ti_clk_add_component(node, &gate->hw, CLK_COMPONENT_TYPE_GATE))
		return;

cleanup:
	kfree(gate);
}
Beispiel #3
0
/**
 * of_ti_clk_autoidle_setup - sets up hardware autoidle for a clock
 * @node: pointer to the clock device node
 *
 * Checks if a clock has hardware autoidle support or not (check
 * for presence of 'ti,autoidle-shift' property in the device tree
 * node) and sets up the hardware autoidle feature for the clock
 * if available. If autoidle is available, the clock is also added
 * to the autoidle list for later processing. Returns 0 on success,
 * negative error value on failure.
 */
int __init of_ti_clk_autoidle_setup(struct device_node *node)
{
	u32 shift;
	struct clk_ti_autoidle *clk;
	int ret;

	/* Check if this clock has autoidle support or not */
	if (of_property_read_u32(node, "ti,autoidle-shift", &shift))
		return 0;

	clk = kzalloc(sizeof(*clk), GFP_KERNEL);

	if (!clk)
		return -ENOMEM;

	clk->shift = shift;
	clk->name = node->name;
	ret = ti_clk_get_reg_addr(node, 0, &clk->reg);
	if (ret) {
		kfree(clk);
		return ret;
	}

	if (of_property_read_bool(node, "ti,invert-autoidle-bit"))
		clk->flags |= AUTOIDLE_LOW;

	list_add(&clk->node, &autoidle_clks);

	return 0;
}
static void __init _of_ti_interface_clk_setup(struct device_node *node,
					      const struct clk_hw_omap_ops *ops)
{
	struct clk *clk;
	const char *parent_name;
	void __iomem *reg;
	u8 enable_bit = 0;
	u32 val;

	reg = ti_clk_get_reg_addr(node, 0);
	if (IS_ERR(reg))
		return;

	if (!of_property_read_u32(node, "ti,bit-shift", &val))
		enable_bit = val;

	parent_name = of_clk_get_parent_name(node, 0);
	if (!parent_name) {
		pr_err("%s must have a parent\n", node->name);
		return;
	}

	clk = _register_interface(NULL, node->name, parent_name, reg,
				  enable_bit, ops);

	if (!IS_ERR(clk))
		of_clk_add_provider(node, of_clk_src_simple_get, clk);
}
static void __init _of_ti_gate_clk_setup(struct device_node *node,
					 const struct clk_ops *ops,
					 const struct clk_hw_omap_ops *hw_ops)
{
	struct clk *clk;
	const char *parent_name;
	void __iomem *reg = NULL;
	u8 enable_bit = 0;
	u32 val;
	u32 flags = 0;
	u8 clk_gate_flags = 0;

	if (ops != &omap_gate_clkdm_clk_ops) {
		reg = ti_clk_get_reg_addr(node, 0);
		if (IS_ERR(reg))
			return;

		if (!of_property_read_u32(node, "ti,bit-shift", &val))
			enable_bit = val;
	}

	if (of_clk_get_parent_count(node) != 1) {
		pr_err("%s must have 1 parent\n", node->name);
		return;
	}

	parent_name = of_clk_get_parent_name(node, 0);

	if (of_property_read_bool(node, "ti,set-rate-parent"))
		flags |= CLK_SET_RATE_PARENT;

	if (of_property_read_bool(node, "ti,set-bit-to-disable"))
		clk_gate_flags |= INVERT_ENABLE;

	clk = _register_gate(NULL, node->name, parent_name, flags, reg,
			     enable_bit, clk_gate_flags, ops, hw_ops);

	if (!IS_ERR(clk))
		of_clk_add_provider(node, of_clk_src_simple_get, clk);
}
Beispiel #6
0
static void __init of_omap2_apll_setup(struct device_node *node)
{
	struct dpll_data *ad = NULL;
	struct clk_hw_omap *clk_hw = NULL;
	struct clk_init_data *init = NULL;
	struct clk *clk;
	const char *parent_name;
	u32 val;

	ad = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
	clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
	init = kzalloc(sizeof(*init), GFP_KERNEL);

	if (!ad || !clk_hw || !init)
		goto cleanup;

	clk_hw->dpll_data = ad;
	clk_hw->hw.init = init;
	init->ops = &omap2_apll_ops;
	init->name = node->name;
	clk_hw->ops = &omap2_apll_hwops;

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

	parent_name = of_clk_get_parent_name(node, 0);
	init->parent_names = &parent_name;

	if (of_property_read_u32(node, "ti,clock-frequency", &val)) {
		pr_err("%s missing clock-frequency\n", node->name);
		goto cleanup;
	}
	clk_hw->fixed_rate = val;

	if (of_property_read_u32(node, "ti,bit-shift", &val)) {
		pr_err("%s missing bit-shift\n", node->name);
		goto cleanup;
	}

	clk_hw->enable_bit = val;
	ad->enable_mask = 0x3 << val;
	ad->autoidle_mask = 0x3 << val;

	if (of_property_read_u32(node, "ti,idlest-shift", &val)) {
		pr_err("%s missing idlest-shift\n", node->name);
		goto cleanup;
	}

	ad->idlest_mask = 1 << val;

	ad->control_reg = ti_clk_get_reg_addr(node, 0);
	ad->autoidle_reg = ti_clk_get_reg_addr(node, 1);
	ad->idlest_reg = ti_clk_get_reg_addr(node, 2);

	if (!ad->control_reg || !ad->autoidle_reg || !ad->idlest_reg)
		goto cleanup;

	clk = clk_register(NULL, &clk_hw->hw);
	if (!IS_ERR(clk)) {
		of_clk_add_provider(node, of_clk_src_simple_get, clk);
		kfree(init);
		return;
	}
cleanup:
	kfree(ad);
	kfree(clk_hw);
	kfree(init);
}
Beispiel #7
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 (IS_ERR(dd->idlest_reg))
			goto cleanup;

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

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

	if (dd->autoidle_mask) {
		dd->autoidle_reg = ti_clk_get_reg_addr(node, 3);
		if (IS_ERR(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;

	omap2_init_dpll_clkdm(dd, node);

	if (dpll_mode)
		dd->modes = dpll_mode;

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

cleanup:
	kfree(dd);
	kfree(parent_names);
	kfree(init);
	kfree(clk_hw);
}
Beispiel #8
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);
}