Just sent this to linux-arm-kernel. I saw the web archive screwed up on my signature, so I include it here to eventually get to Google.
Hi folks -There appears to be a subtle problem with the otherwise neat PLL setting api for AT91 found in./arch/arm/mach-at91rm9200/clock.c The nice code in at91_pll_calc() does a search at runtime for the best match for the requested PLL output frequency given the base clock rate. So if you tell it you have a 18.432MHz crystal, and want 96MHz, it will find a good PLL multiplier and divide pair. This is commendable and cool. The problem comes from the code not having the free hand that it thinks it does to choose the PLL ratios. This is because the physical external PLL filter components must be matched to the details of the PLL settings, and of course these are chosen at design-time.
So for example, the cool code in there at the moment determines that 18.432MHz /24 * 125 --> 96MHz exactly, and (leaving aside the problem that the PLL is specified only to work with inputs > 1MHz after the divide action), this is correct.However, you must have downloaded this (hideous password-protected source VB) spreadsheet http://atmel.com/dyn/resources/prod_documents/ATMEL_PLL_LFT_Filter_CALCULATOR_AT91_2v1.zip and plug the ratios into it (except that it's cunningly password-protected code will not allow the <1MHz violation...) and compute the three passive components that will provide the correct PLL loop filter for this action. And then you must solder these uncomputable passives to your PCB in order to use the /24 * 125 ratio that the clock.c code has initialized PLLB to on boot. And the code does choose that ratio on the basis it is the closest available match. If your loop filter is cribbed from the DK or EK, it will not work properly with the /24 * 125 ratio the kernel now chooses and sets and give flaky USB communication. In the case of my USB memory stick, for example, it will work for 30 seconds or so and then the stick is disabled by the kernel and the IO errors spew. I don't know what a good solution is for this irritating situation, but I do know what an ugly hack is for it, which I attach, not at all recommending it for anyone except people with the same problem needing a quick fix. This forces clock.c to set PLLB to a ratio that, while it provides a slightly off 48.05MHz, does so with PLL ratios that are computable by the Spreadsheet Of Doom (/14 * 73). To go with this specific ratio, I have tried and recommend for stability these loop filter components calculated by the spreadsheet and rounded to real values: R1 = 200R C1 = 470nF C2 = 47nF PLLRC -----+-------- | | | < | < R1 | < = C2 | | | | = C1 | | GNDPLL ----+-------- With the ugly hack patch and these components, my USB memory stick is stable and happy. -Andy

--- arch/arm/mach-at91rm9200/clock.c~ 2006-07-12 18:26:58.000000000 +0100 +++ arch/arm/mach-at91rm9200/clock.c 2006-07-12 21:11:31.000000000 +0100 @@ -599,6 +599,11 @@ unsigned i, div = 0, mul = 0, diff = 1 << 30; unsigned ret = (out_freq > 155000000) ? 0xbe00 : 0x3e00; + if((out_freq==96000000) && (main_freq==18432000)) { // match the PLLB filter! + return ret | ((73 - 1) << 16) | 0x0e; + } + + /* PLL output max 240 MHz (or 180 MHz per errata) */ if (out_freq > 240000000) goto fail;
That was a pretty hard day of "wandering around in the desert" before I realized that a 0.5Hz frequency modulation that is appearing on the USB clock was not actually the problem. I guess it is slow enough that the loop filters inside the USB device PLLs (if they have one) can track it. The spreadsheet was pretty evil, it would not run in Open Office, I guess OO scripting and Borg scripting are not compatible. Well never mind, hopefully that was the first and last time I will ever care.