/** * _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 or returns the actual integer divisor * upon success. */ static u32 _clksel_to_divisor(struct clk *clk, u32 field_val) { const struct clksel *clks; const struct clksel_rate *clkr; struct clk *parent; parent = __clk_get_parent(clk); clks = _get_clksel_by_parent(clk, parent); if (!clks) return 0; for (clkr = clks->rates; clkr->div; clkr++) { if (!(clkr->flags & cpu_mask)) continue; if (clkr->val == field_val) break; } if (!clkr->div) { /* This indicates a data error */ WARN(1, "clock: %s: could not find fieldval %d for parent %s\n", __clk_get_name(clk), field_val, __clk_get_name(parent)); return 0; } return clkr->div; }
/** * _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. Returns the * register field value _before_ left-shifting (i.e., LSB is at bit * 0); or returns 0xFFFFFFFF (~0) upon error. */ static u32 _divisor_to_clksel(struct clk *clk, u32 div) { const struct clksel *clks; const struct clksel_rate *clkr; struct clk *parent; /* should never happen */ WARN_ON(div == 0); parent = __clk_get_parent(clk); clks = _get_clksel_by_parent(clk, parent); if (!clks) return ~0; for (clkr = clks->rates; clkr->div; clkr++) { if (!(clkr->flags & cpu_mask)) continue; if (clkr->div == div) break; } if (!clkr->div) { pr_err("clock: %s: could not find divisor %d for parent %s\n", __clk_get_name(clk), div, __clk_get_name(parent)); return ~0; } return clkr->val; }
static u32 _divisor_to_clksel(struct clk *clk, u32 div) { const struct clksel *clks; const struct clksel_rate *clkr; WARN_ON(div == 0); clks = _get_clksel_by_parent(clk, clk->parent); if (!clks) return ~0; for (clkr = clks->rates; clkr->div; clkr++) { if (!(clkr->flags & cpu_mask)) continue; if (clkr->div == div) break; } if (!clkr->div) { pr_err("clock: Could not find divisor %d for clock %s parent " "%s\n", div, clk->name, clk->parent->name); return ~0; } return clkr->val; }
static u8 _get_div_and_fieldval(struct clk *src_clk, struct clk *clk, u32 *field_val) { const struct clksel *clks; const struct clksel_rate *clkr, *max_clkr = NULL; u8 max_div = 0; clks = _get_clksel_by_parent(clk, src_clk); if (!clks) return 0; for (clkr = clks->rates; clkr->div; clkr++) { if (!(clkr->flags & cpu_mask)) continue; if (clkr->div > max_div) { max_div = clkr->div; max_clkr = clkr; } } if (max_div == 0) { WARN(1, "clock: Could not find divisor for clock %s parent %s" "\n", clk->name, src_clk->parent->name); return 0; } *field_val = max_clkr->val; return max_div; }
/** * _divisor_to_clksel() - turn clksel integer divisor into a field value * @clk: OMAP struct clk to use * @div: integer divisor to search for * @mul: integer multiplier to search for * * Given a struct clk of a rate-selectable clksel clock, and a clock * divisor, find the corresponding register field value. Returns the * register field value _before_ left-shifting (i.e., LSB is at bit * 0); or returns 0xFFFFFFFF (~0) upon error. */ static u32 _divisor_to_clksel(struct clk *clk, u32 div, u32 mul) { const struct clksel *clks; const struct clksel_rate *clkr; /* should never happen */ WARN_ON(div == 0); clks = _get_clksel_by_parent(clk, clk->parent); if (!clks) return ~0; for (clkr = clks->rates; clkr->div; clkr++) { if (!(clkr->flags & cpu_mask)) continue; /* if multiplier is valid, it means we handle a specific * fraction divider */ if (mul) { if ((clkr->mul == mul) && (clkr->div == div)) break; /* usual path, multiplier is 0 */ } else if (clkr->div == div) break; } if (!clkr->div) { pr_err("clock: Could not find divisor %d for clock %s parent " "%s\n", div, clk->name, clk->parent->name); return ~0; } return clkr->val; }
static u32 _clksel_to_divisor(struct clk *clk, u32 field_val) { const struct clksel *clks; const struct clksel_rate *clkr; clks = _get_clksel_by_parent(clk, clk->parent); if (!clks) return 0; for (clkr = clks->rates; clkr->div; clkr++) { if (!(clkr->flags & cpu_mask)) continue; if (clkr->val == field_val) break; } if (!clkr->div) { WARN(1, "clock: Could not find fieldval %d for clock %s parent " "%s\n", field_val, clk->name, clk->parent->name); return 0; } return clkr->div; }
/** * _clksel_to_divisor() - turn clksel field value into integer divider * @clk: OMAP struct clk to use * @field_val: register field value to find * @mul: Output parameter. Multiplier for current rate. Typically 0. * * 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 or returns the actual integer divisor * upon success. */ static u32 _clksel_to_divisor(struct clk *clk, u32 field_val, u32 *mul) { const struct clksel *clks; const struct clksel_rate *clkr; clks = _get_clksel_by_parent(clk, clk->parent); if (!clks) return 0; *mul = 0; for (clkr = clks->rates; clkr->div; clkr++) { if (!(clkr->flags & cpu_mask)) continue; if (clkr->val == field_val) break; } #ifndef CONFIG_MACH_OMAP_5430ZEBU if (!clkr->div) { /* This indicates a data error */ WARN(1, "clock: Could not find fieldval %d for clock %s parent " "%s\n", field_val, clk->name, clk->parent->name); return 0; } #endif *mul = clkr->mul; return clkr->div; }
/** * _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 or returns the actual integer divisor * upon success. */ static u32 _clksel_to_divisor(struct clk *clk, u32 field_val) { const struct clksel *clks; const struct clksel_rate *clkr; clks = _get_clksel_by_parent(clk, clk->parent); if (!clks) return 0; for (clkr = clks->rates; clkr->div; clkr++) { if (!(clkr->flags & cpu_mask)) continue; if (clkr->val == field_val) break; } if (!clkr->div) { #ifdef CONFIG_OMAP4_DPLL_CASCADING pr_debug("clock: Could not find fieldval %d for clock %s parent " "%s\n", field_val, clk->name, clk->parent->name); #else /* This indicates a data error */ WARN(1, "clock: Could not find fieldval %d for clock %s parent " "%s\n", field_val, clk->name, clk->parent->name); #endif return 0; } return clkr->div; }
/** * _get_div_and_fieldval() - find the new clksel divisor and field value to use * @src_clk: planned new parent struct clk * * @clk: struct clk * that is being reparented * @field_val: pointer to a u32 to contain the register data for the divisor * @mul: Output parameter. Multiplier for current rate. Typically 0. * * Given an intended new parent struct clk * @src_clk, and the struct * clk * @clk to the clock that is being reparented, find the * appropriate rate divisor for the new clock (returned as the return * value), and the corresponding register bitfield data to program to * reach that divisor (returned in the u32 pointed to by @field_val). * Returns 0 on error, or returns the newly-selected divisor upon * success (in this latter case, the corresponding register bitfield * value is passed back in the variable pointed to by @field_val) */ static u8 _get_div_and_fieldval(struct clk *src_clk, struct clk *clk, u32 *field_val, u32 *mul) { const struct clksel *clks; const struct clksel_rate *clkr, *max_clkr = NULL; u8 max_div = 0, test_div = 0; clks = _get_clksel_by_parent(clk, src_clk); if (!clks) return 0; /* * Find the highest divisor (e.g., the one resulting in the * lowest rate) to use as the default. This should avoid * clock rates that are too high for the device. XXX A better * solution here would be to try to determine if there is a * divisor matching the original clock rate before the parent * switch, and if it cannot be found, to fall back to the * highest divisor. */ for (clkr = clks->rates; clkr->div; clkr++) { if (!(clkr->flags & cpu_mask)) continue; /* * Handle special case when multiplier is set, * it means we are handling fraction divider here, * and we should do the following comparing: * (mul / div) > max_div * So, integer truncation is not enough in this case, * we need DIV_ROUND_UP macros. * For example, if we compare 2.5 divider with * 2 divider we have the following: * integer truncation -> ((5 / 2) > 2) -> (2 > 2) -> false * DIV_ROUND_UP -> ((5 / 2) > 2) -> (3 > 2) -> true */ if (!clkr->mul) test_div = clkr->div; else test_div = DIV_ROUND_UP(clkr->mul, clkr->div); if (test_div > max_div) { max_div = clkr->div; max_clkr = clkr; } } if (max_div == 0) { /* This indicates an error in the clksel data */ WARN(1, "clock: Could not find divisor for clock %s parent %s" "\n", clk->name, src_clk->parent->name); return 0; } *field_val = max_clkr->val; *mul = max_clkr->mul; return max_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. * This function is also used by the DPLL3 M2 divider code. * * 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; struct clk *parent; unsigned long parent_rate; const char *clk_name; parent = __clk_get_parent(clk); parent_rate = __clk_get_rate(parent); clk_name = __clk_get_name(clk); if (!clk->clksel || !clk->clksel_mask) return ~0; pr_debug("clock: clksel_round_rate_div: %s target_rate %ld\n", clk_name, target_rate); *new_div = 1; clks = _get_clksel_by_parent(clk, parent); if (!clks) return ~0; for (clkr = clks->rates; clkr->div; clkr++) { if (!(clkr->flags & cpu_mask)) continue; /* Sanity check */ if (clkr->div <= last_div) pr_err("clock: %s: clksel_rate table not sorted\n", clk_name); last_div = clkr->div; test_rate = parent_rate / clkr->div; if (test_rate <= target_rate) break; /* found it */ } if (!clkr->div) { pr_err("clock: %s: could not find divisor for target rate %ld for parent %s\n", clk_name, target_rate, __clk_get_name(parent)); return ~0; } *new_div = clkr->div; pr_debug("clock: new_div = %d, new_rate = %ld\n", *new_div, (parent_rate / clkr->div)); return parent_rate / 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. * This function is also used by the DPLL3 M2 divider code. * * 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; if (!clk->clksel || !clk->clksel_mask) return ~0; pr_debug("clock: clksel_round_rate_div: %s target_rate %ld\n", clk->name, target_rate); *new_div = 1; clks = _get_clksel_by_parent(clk, clk->parent); if (!clks) return ~0; for (clkr = clks->rates; clkr->div; clkr++) { if (!(clkr->flags & cpu_mask)) continue; /* Sanity check */ if (clkr->div <= last_div) pr_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) { if (!cpu_is_ti816x() && !cpu_is_ti814x()) pr_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; pr_debug("clock: new_div = %d, new_rate = %ld\n", *new_div, (clk->parent->rate / clkr->div)); return clk->parent->rate / clkr->div; }
/** * _get_div_and_fieldval() - find the new clksel divisor and field value to use * @src_clk: planned new parent struct clk * * @clk: struct clk * that is being reparented * @field_val: pointer to a u32 to contain the register data for the divisor * * Given an intended new parent struct clk * @src_clk, and the struct * clk * @clk to the clock that is being reparented, find the * appropriate rate divisor for the new clock (returned as the return * value), and the corresponding register bitfield data to program to * reach that divisor (returned in the u32 pointed to by @field_val). * Returns 0 on error, or returns the newly-selected divisor upon * success (in this latter case, the corresponding register bitfield * value is passed back in the variable pointed to by @field_val) */ static u8 _get_div_and_fieldval(struct clk *src_clk, struct clk *clk, u32 *field_val) { const struct clksel *clks; const struct clksel_rate *clkr, *max_clkr = NULL; u8 max_div = 0; clks = _get_clksel_by_parent(clk, src_clk); if (!clks) return 0; /* * Find the highest divisor (e.g., the one resulting in the * lowest rate) to use as the default. This should avoid * clock rates that are too high for the device. XXX A better * solution here would be to try to determine if there is a * divisor matching the original clock rate before the parent * switch, and if it cannot be found, to fall back to the * highest divisor. */ for (clkr = clks->rates; clkr->div; clkr++) { if (!(clkr->flags & cpu_mask)) continue; if (clkr->div > max_div) { max_div = clkr->div; max_clkr = clkr; } } if (max_div == 0) { /* This indicates an error in the clksel data */ WARN(1, "clock: %s: could not find divisor for parent %s\n", __clk_get_name(clk), __clk_get_name(__clk_get_parent(src_clk))); return 0; } *field_val = max_clkr->val; return max_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 * @new_div: ptr to where we should store the multiplier * * Finds 'best' divider value in an array based on the source and target * rates. The divider array must be sorted with smallest divider first. * This function is also used by the DPLL3 M2 divider code. * * 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, u32 *new_mul) { unsigned long test_rate; const struct clksel *clks; const struct clksel_rate *clkr; u32 last_div = 0; long last_diff; if (!clk->clksel || !clk->clksel_mask) return ~0; pr_debug("clock: clksel_round_rate_div: %s target_rate %ld\n", clk->name, target_rate); *new_div = 1; *new_mul = 0; clks = _get_clksel_by_parent(clk, clk->parent); if (!clks) return ~0; last_diff = clk->parent->rate; for (clkr = clks->rates; clkr->div; clkr++) { long diff; if (!(clkr->flags & cpu_mask)) continue; /* Sanity check */ if ((clkr->div <= last_div) && (0 == clkr->mul)) pr_err("clock: clksel_rate table not sorted " "for clock %s", clk->name); last_div = clkr->div; test_rate = _calculate_rate(clk->parent->rate, clkr->div, clkr->mul); diff = abs(test_rate - target_rate); if (test_rate <= target_rate) { if (diff > last_diff) clkr--; break; /* found it */ } last_diff = diff; } if (!clkr->div) { pr_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; /* recalculate rate */ test_rate = _calculate_rate(clk->parent->rate, clkr->div, clkr->mul); if (clkr->mul) *new_mul = clkr->mul; pr_debug("clock: new_div = %d, new_mul = %d, new_rate = %ld\n", *new_div, *new_mul, test_rate); return test_rate; }