Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.17 161 lines 3.5 kB view raw
1/* 2 * linux/arch/arm/common/icst307.c 3 * 4 * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 * Support functions for calculating clocks/divisors for the ICST307 11 * clock generators. See http://www.icst.com/ for more information 12 * on these devices. 13 * 14 * This is an almost identical implementation to the ICST525 clock generator. 15 * The s2div and idx2s files are different 16 */ 17#include <linux/module.h> 18#include <linux/kernel.h> 19 20#include <asm/hardware/icst307.h> 21 22/* 23 * Divisors for each OD setting. 24 */ 25static unsigned char s2div[8] = { 10, 2, 8, 4, 5, 7, 3, 6 }; 26 27unsigned long icst307_khz(const struct icst307_params *p, struct icst307_vco vco) 28{ 29 return p->ref * 2 * (vco.v + 8) / ((vco.r + 2) * s2div[vco.s]); 30} 31 32EXPORT_SYMBOL(icst307_khz); 33 34/* 35 * Ascending divisor S values. 36 */ 37static unsigned char idx2s[8] = { 1, 6, 3, 4, 7, 5, 2, 0 }; 38 39struct icst307_vco 40icst307_khz_to_vco(const struct icst307_params *p, unsigned long freq) 41{ 42 struct icst307_vco vco = { .s = 1, .v = p->vd_max, .r = p->rd_max }; 43 unsigned long f; 44 unsigned int i = 0, rd, best = (unsigned int)-1; 45 46 /* 47 * First, find the PLL output divisor such 48 * that the PLL output is within spec. 49 */ 50 do { 51 f = freq * s2div[idx2s[i]]; 52 53 /* 54 * f must be between 6MHz and 200MHz (3.3 or 5V) 55 */ 56 if (f > 6000 && f <= p->vco_max) 57 break; 58 } while (i < ARRAY_SIZE(idx2s)); 59 60 if (i > ARRAY_SIZE(idx2s)) 61 return vco; 62 63 vco.s = idx2s[i]; 64 65 /* 66 * Now find the closest divisor combination 67 * which gives a PLL output of 'f'. 68 */ 69 for (rd = p->rd_min; rd <= p->rd_max; rd++) { 70 unsigned long fref_div, f_pll; 71 unsigned int vd; 72 int f_diff; 73 74 fref_div = (2 * p->ref) / rd; 75 76 vd = (f + fref_div / 2) / fref_div; 77 if (vd < p->vd_min || vd > p->vd_max) 78 continue; 79 80 f_pll = fref_div * vd; 81 f_diff = f_pll - f; 82 if (f_diff < 0) 83 f_diff = -f_diff; 84 85 if ((unsigned)f_diff < best) { 86 vco.v = vd - 8; 87 vco.r = rd - 2; 88 if (f_diff == 0) 89 break; 90 best = f_diff; 91 } 92 } 93 94 return vco; 95} 96 97EXPORT_SYMBOL(icst307_khz_to_vco); 98 99struct icst307_vco 100icst307_ps_to_vco(const struct icst307_params *p, unsigned long period) 101{ 102 struct icst307_vco vco = { .s = 1, .v = p->vd_max, .r = p->rd_max }; 103 unsigned long f, ps; 104 unsigned int i = 0, rd, best = (unsigned int)-1; 105 106 ps = 1000000000UL / p->vco_max; 107 108 /* 109 * First, find the PLL output divisor such 110 * that the PLL output is within spec. 111 */ 112 do { 113 f = period / s2div[idx2s[i]]; 114 115 /* 116 * f must be between 6MHz and 200MHz (3.3 or 5V) 117 */ 118 if (f >= ps && f < 1000000000UL / 6000 + 1) 119 break; 120 } while (i < ARRAY_SIZE(idx2s)); 121 122 if (i > ARRAY_SIZE(idx2s)) 123 return vco; 124 125 vco.s = idx2s[i]; 126 127 ps = 500000000UL / p->ref; 128 129 /* 130 * Now find the closest divisor combination 131 * which gives a PLL output of 'f'. 132 */ 133 for (rd = p->rd_min; rd <= p->rd_max; rd++) { 134 unsigned long f_in_div, f_pll; 135 unsigned int vd; 136 int f_diff; 137 138 f_in_div = ps * rd; 139 140 vd = (f_in_div + f / 2) / f; 141 if (vd < p->vd_min || vd > p->vd_max) 142 continue; 143 144 f_pll = (f_in_div + vd / 2) / vd; 145 f_diff = f_pll - f; 146 if (f_diff < 0) 147 f_diff = -f_diff; 148 149 if ((unsigned)f_diff < best) { 150 vco.v = vd - 8; 151 vco.r = rd - 2; 152 if (f_diff == 0) 153 break; 154 best = f_diff; 155 } 156 } 157 158 return vco; 159} 160 161EXPORT_SYMBOL(icst307_ps_to_vco);