/* Check if parent_rate is a valid input rate */ if (parent_rate < characteristics->input.min) return -ERANGE;
/* * Calculate minimum divider based on the minimum multiplier, the * parent_rate and the requested rate. * Should always be 2 according to the input and output characteristics * of the PLL blocks.
*/
mindiv = (parent_rate * PLL_MUL_MIN) / rate; if (!mindiv)
mindiv = 1;
if (parent_rate > characteristics->input.max) {
tmpdiv = DIV_ROUND_UP(parent_rate, characteristics->input.max); if (tmpdiv > PLL_DIV_MAX) return -ERANGE;
if (tmpdiv > mindiv)
mindiv = tmpdiv;
}
/* * Calculate the maximum divider which is limited by PLL register * layout (limited by the MUL or DIV field size).
*/
maxdiv = DIV_ROUND_UP(parent_rate * PLL_MUL_MAX(layout), rate); if (maxdiv > PLL_DIV_MAX)
maxdiv = PLL_DIV_MAX;
/* * Iterate over the acceptable divider values to find the best * divider/multiplier pair (the one that generates the closest * rate to the requested one).
*/ for (tmpdiv = mindiv; tmpdiv <= maxdiv; tmpdiv++) { unsignedlong remainder; unsignedlong tmprate; unsignedlong tmpmul;
/* * Calculate the multiplier associated with the current * divider that provide the closest rate to the requested one.
*/
tmpmul = DIV_ROUND_CLOSEST(rate, parent_rate / tmpdiv);
tmprate = (parent_rate / tmpdiv) * tmpmul; if (tmprate > rate)
remainder = tmprate - rate; else
remainder = rate - tmprate;
/* * Compare the remainder with the best remainder found until * now and elect a new best multiplier/divider pair if the * current remainder is smaller than the best one.
*/ if (remainder < bestremainder) {
bestremainder = remainder;
bestdiv = tmpdiv;
bestmul = tmpmul;
bestrate = tmprate;
}
/* * We've found a perfect match! * Stop searching now and use this multiplier/divider pair.
*/ if (!remainder) break;
}
/* We haven't found any multiplier/divider pair => return -ERANGE */ if (bestrate < 0) return bestrate;
/* Check if bestrate is a valid output rate */ for (i = 0; i < characteristics->num_output; i++) { if (bestrate >= characteristics->output[i].min &&
bestrate <= characteristics->output[i].max) break;
}
if (i >= characteristics->num_output) return -ERANGE;
if (div)
*div = bestdiv; if (mul)
*mul = bestmul - 1; if (index)
*index = i;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.