/* * Converts encoded control register address into a full address * On error, *src_addr will be returned as 0. */ static u32 omap2_clksel_get_src_field(void __iomem **src_addr, struct clk *src_clk, u32 *field_mask, struct clk *clk, u32 *parent_div) { const struct clksel *clks; const struct clksel_rate *clkr; *parent_div = 0; *src_addr = 0; clks = omap2_get_clksel_by_parent(clk, src_clk); if (clks == NULL) return 0; for (clkr = clks->rates; clkr->div; clkr++) { if (clkr->flags & (cpu_mask | DEFAULT_RATE)) break; /* Found the default rate for this platform */ } if (!clkr->div) { printk(KERN_ERR "clock: Could not find default rate for " "clock %s parent %s\n", clk->name, src_clk->parent->name); return 0; } /* Should never happen. Add a clksel mask to the struct clk. */ WARN_ON(clk->clksel_mask == 0); *field_mask = clk->clksel_mask; *src_addr = clk->clksel_reg; *parent_div = clkr->div; return clkr->val; }
/** * omap2_divisor_to_clksel() - turn clksel integer divisor into a field value * @clk: OMAP struct clk to use * @div: integer divisor to search for * * Given a struct clk of a rate-selectable clksel clock, and a clock divisor, * find the corresponding register field value. The return register value is * the value before left-shifting. Returns 0xffffffff on error */ u32 omap2_divisor_to_clksel(struct clk *clk, u32 div) { const struct clksel *clks; const struct clksel_rate *clkr; /* should never happen */ WARN_ON(div == 0); clks = omap2_get_clksel_by_parent(clk, clk->parent); if (clks == NULL) return 0; for (clkr = clks->rates; clkr->div; clkr++) { if ((clkr->flags & cpu_mask) && (clkr->div == div)) break; } if (!clkr->div) { printk(KERN_ERR "clock: Could not find divisor %d for " "clock %s parent %s\n", div, clk->name, clk->parent->name); return 0; } return clkr->val; }
/* * Converts encoded control register address into a full address * On error, the return value (parent_div) will be 0. */ static u32 _omap2_clksel_get_src_field(struct clk *src_clk, struct clk *clk, u32 *field_val) { const struct clksel *clks; const struct clksel_rate *clkr; clks = omap2_get_clksel_by_parent(clk, src_clk); if (!clks) return 0; for (clkr = clks->rates; clkr->div; clkr++) { if (clkr->flags & cpu_mask && clkr->flags & DEFAULT_RATE) break; /* Found the default rate for this platform */ } if (!clkr->div) { printk(KERN_ERR "clock: Could not find default rate for " "clock %s parent %s\n", clk->name, src_clk->parent->name); return 0; } /* Should never happen. Add a clksel mask to the struct clk. */ WARN_ON(clk->clksel_mask == 0); *field_val = clkr->val; return clkr->div; }
/** * omap2_clksel_round_rate_div - find divisor for the given clock and rate * @clk: OMAP struct clk to use * @target_rate: desired clock rate * @new_div: ptr to where we should store the divisor * * Finds 'best' divider value in an array based on the source and target * rates. The divider array must be sorted with smallest divider first. * Note that this will not work for clocks which are part of CONFIG_PARTICIPANT, * they are only settable as part of virtual_prcm set. * * Returns the rounded clock rate or returns 0xffffffff on error. */ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate, u32 *new_div) { unsigned long test_rate; const struct clksel *clks; const struct clksel_rate *clkr; u32 last_div = 0; printk(KERN_INFO "clock: clksel_round_rate_div: %s target_rate %ld\n", clk->name, target_rate); *new_div = 1; clks = omap2_get_clksel_by_parent(clk, clk->parent); if (clks == NULL) return ~0; for (clkr = clks->rates; clkr->div; clkr++) { if (!(clkr->flags & cpu_mask)) continue; /* Sanity check */ if (clkr->div <= last_div) printk(KERN_ERR "clock: clksel_rate table not sorted " "for clock %s", clk->name); last_div = clkr->div; test_rate = clk->parent->rate / clkr->div; if (test_rate <= target_rate) break; /* found it */ } if (!clkr->div) { printk(KERN_ERR "clock: Could not find divisor for target " "rate %ld for clock %s parent %s\n", target_rate, clk->name, clk->parent->name); return ~0; } *new_div = clkr->div; printk(KERN_INFO "clock: new_div = %d, new_rate = %ld\n", *new_div, (clk->parent->rate / clkr->div)); return (clk->parent->rate / clkr->div); }
/** * omap2_clksel_to_divisor() - turn clksel field value into integer divider * @clk: OMAP struct clk to use * @field_val: register field value to find * * Given a struct clk of a rate-selectable clksel clock, and a register field * value to search for, find the corresponding clock divisor. The register * field value should be pre-masked and shifted down so the LSB is at bit 0 * before calling. Returns 0 on error */ u32 omap2_clksel_to_divisor(struct clk *clk, u32 field_val) { const struct clksel *clks; const struct clksel_rate *clkr; clks = omap2_get_clksel_by_parent(clk, clk->parent); if (clks == NULL) return 0; for (clkr = clks->rates; clkr->div; clkr++) { if ((clkr->flags & cpu_mask) && (clkr->val == field_val)) break; } if (!clkr->div) { printk(KERN_ERR "clock: Could not find fieldval %d for " "clock %s parent %s\n", field_val, clk->name, clk->parent->name); return 0; } return clkr->div; }