root/drivers/clk/spear/clk-frac-synth.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. frac_calc_rate
  2. clk_frac_round_rate
  3. clk_frac_recalc_rate
  4. clk_frac_set_rate
  5. clk_register_frac

   1 /*
   2  * Copyright (C) 2012 ST Microelectronics
   3  * Viresh Kumar <vireshk@kernel.org>
   4  *
   5  * This file is licensed under the terms of the GNU General Public
   6  * License version 2. This program is licensed "as is" without any
   7  * warranty of any kind, whether express or implied.
   8  *
   9  * Fractional Synthesizer clock implementation
  10  */
  11 
  12 #define pr_fmt(fmt) "clk-frac-synth: " fmt
  13 
  14 #include <linux/clk-provider.h>
  15 #include <linux/slab.h>
  16 #include <linux/io.h>
  17 #include <linux/err.h>
  18 #include "clk.h"
  19 
  20 #define DIV_FACTOR_MASK         0x1FFFF
  21 
  22 /*
  23  * DOC: Fractional Synthesizer clock
  24  *
  25  * Fout from synthesizer can be given from below equation:
  26  *
  27  * Fout= Fin/2*div (division factor)
  28  * div is 17 bits:-
  29  *      0-13 (fractional part)
  30  *      14-16 (integer part)
  31  *      div is (16-14 bits).(13-0 bits) (in binary)
  32  *
  33  *      Fout = Fin/(2 * div)
  34  *      Fout = ((Fin / 10000)/(2 * div)) * 10000
  35  *      Fout = (2^14 * (Fin / 10000)/(2^14 * (2 * div))) * 10000
  36  *      Fout = (((Fin / 10000) << 14)/(2 * (div << 14))) * 10000
  37  *
  38  * div << 14 simply 17 bit value written at register.
  39  * Max error due to scaling down by 10000 is 10 KHz
  40  */
  41 
  42 #define to_clk_frac(_hw) container_of(_hw, struct clk_frac, hw)
  43 
  44 static unsigned long frac_calc_rate(struct clk_hw *hw, unsigned long prate,
  45                 int index)
  46 {
  47         struct clk_frac *frac = to_clk_frac(hw);
  48         struct frac_rate_tbl *rtbl = frac->rtbl;
  49 
  50         prate /= 10000;
  51         prate <<= 14;
  52         prate /= (2 * rtbl[index].div);
  53         prate *= 10000;
  54 
  55         return prate;
  56 }
  57 
  58 static long clk_frac_round_rate(struct clk_hw *hw, unsigned long drate,
  59                 unsigned long *prate)
  60 {
  61         struct clk_frac *frac = to_clk_frac(hw);
  62         int unused;
  63 
  64         return clk_round_rate_index(hw, drate, *prate, frac_calc_rate,
  65                         frac->rtbl_cnt, &unused);
  66 }
  67 
  68 static unsigned long clk_frac_recalc_rate(struct clk_hw *hw,
  69                 unsigned long parent_rate)
  70 {
  71         struct clk_frac *frac = to_clk_frac(hw);
  72         unsigned long flags = 0;
  73         unsigned int div = 1, val;
  74 
  75         if (frac->lock)
  76                 spin_lock_irqsave(frac->lock, flags);
  77 
  78         val = readl_relaxed(frac->reg);
  79 
  80         if (frac->lock)
  81                 spin_unlock_irqrestore(frac->lock, flags);
  82 
  83         div = val & DIV_FACTOR_MASK;
  84 
  85         if (!div)
  86                 return 0;
  87 
  88         parent_rate = parent_rate / 10000;
  89 
  90         parent_rate = (parent_rate << 14) / (2 * div);
  91         return parent_rate * 10000;
  92 }
  93 
  94 /* Configures new clock rate of frac */
  95 static int clk_frac_set_rate(struct clk_hw *hw, unsigned long drate,
  96                                 unsigned long prate)
  97 {
  98         struct clk_frac *frac = to_clk_frac(hw);
  99         struct frac_rate_tbl *rtbl = frac->rtbl;
 100         unsigned long flags = 0, val;
 101         int i;
 102 
 103         clk_round_rate_index(hw, drate, prate, frac_calc_rate, frac->rtbl_cnt,
 104                         &i);
 105 
 106         if (frac->lock)
 107                 spin_lock_irqsave(frac->lock, flags);
 108 
 109         val = readl_relaxed(frac->reg) & ~DIV_FACTOR_MASK;
 110         val |= rtbl[i].div & DIV_FACTOR_MASK;
 111         writel_relaxed(val, frac->reg);
 112 
 113         if (frac->lock)
 114                 spin_unlock_irqrestore(frac->lock, flags);
 115 
 116         return 0;
 117 }
 118 
 119 static const struct clk_ops clk_frac_ops = {
 120         .recalc_rate = clk_frac_recalc_rate,
 121         .round_rate = clk_frac_round_rate,
 122         .set_rate = clk_frac_set_rate,
 123 };
 124 
 125 struct clk *clk_register_frac(const char *name, const char *parent_name,
 126                 unsigned long flags, void __iomem *reg,
 127                 struct frac_rate_tbl *rtbl, u8 rtbl_cnt, spinlock_t *lock)
 128 {
 129         struct clk_init_data init;
 130         struct clk_frac *frac;
 131         struct clk *clk;
 132 
 133         if (!name || !parent_name || !reg || !rtbl || !rtbl_cnt) {
 134                 pr_err("Invalid arguments passed\n");
 135                 return ERR_PTR(-EINVAL);
 136         }
 137 
 138         frac = kzalloc(sizeof(*frac), GFP_KERNEL);
 139         if (!frac)
 140                 return ERR_PTR(-ENOMEM);
 141 
 142         /* struct clk_frac assignments */
 143         frac->reg = reg;
 144         frac->rtbl = rtbl;
 145         frac->rtbl_cnt = rtbl_cnt;
 146         frac->lock = lock;
 147         frac->hw.init = &init;
 148 
 149         init.name = name;
 150         init.ops = &clk_frac_ops;
 151         init.flags = flags;
 152         init.parent_names = &parent_name;
 153         init.num_parents = 1;
 154 
 155         clk = clk_register(NULL, &frac->hw);
 156         if (!IS_ERR_OR_NULL(clk))
 157                 return clk;
 158 
 159         pr_err("clk register failed\n");
 160         kfree(frac);
 161 
 162         return NULL;
 163 }

/* [<][>][^][v][top][bottom][index][help] */