An269 – Cirrus Logic AN269 User Manual
Page 3

AN269
AN269REV1
3
/* Desired SPCLK frequency is passed in as "freq" */
int ep93xx_set_video_div(unsigned long freq)
{
/* pdiv, div, psel and esel are the final values of the appropriate bit settings in the
VidClkDiv register. The current "guess" for pdiv and div are j-3 and k, respectively. */
unsigned long pdiv = 0, div = 0, psel = 0, esel = 0, err, f, i, j, k;
/* Algorithm may return -1 if no valid setting can be found */
err = -1;
/* Try the External Clock, PLL1 an d PLL2 */
for (i = 0; i < 3; i++) {
if (i == 0)
/* The External Clock, multiplied by 2 */
f = 14745600 * 2;
else if (i == 1)
/* PLL1 output frequency, multiplied by 2 */
f = ep93xx_get_pll_frequency(1) * 2;
else
/* PLL2 output frequency, multiplied by 2 */
f = ep93xx_get_pll_frequency(2) * 2;
/* Try each setting of PDIV, the pre-divider, and look for a VDIV
setting that would give us the desired frequency. Note that we are
using PDIV*2, since we multiplied the frequency by 2 above. */
for (j = 4; j <= 6; j++) {
k = f / (freq * j);
if (k < 2) {
/* VDIV must be at least 2 */
continue;
}
/* Calculate how far off of the desired frequency this setting is,
and then set the values of PDIV and VDIV from j and k.
At this point, the clock source is set, also. */
if (abs(((f / (j * k))) - freq) < err) {
pdiv = j - 3;
div = k;
psel = (i == 2) ? 1 : 0;
esel = (i == 0) ? 0 : 1;
err = (f / (j * k)) - freq;
}
}
}
if (err == -1) {
/* We were unable to determine a setting that is appropriate */
return -1;
}
/* Unlock the registers */
outl(0xaa, SYSCON_SWLOCK);
/* Write the values to the registers */
outl(SYSCON_VIDDIV_VENA | (esel ? SYSCON_VIDDIV_ESEL : 0) |
(psel ? SYSCON_VIDDIV_PSEL : 0) |
(pdiv << SYSCON_VIDDIV_PDIV_SHIFT) |
(div << SYSCON_VIDDIV_VDIV_SHIFT), SYSCON_VIDDIV);
/* Return the actual value of what frequency we set */
return freq + err;
}