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