/** * 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); }
/** * 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); }