beautypg.com

An269 – Cirrus Logic AN269 User Manual

Page 3

background image

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;

}