linux/arch/arm/common/icst307.c
<<
>>
Prefs
   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);
 162
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.