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

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

DEFINITIONS

This source file includes following definitions.
  1. gpt_calc_rate
  2. clk_gpt_round_rate
  3. clk_gpt_recalc_rate
  4. clk_gpt_set_rate
  5. clk_register_gpt

   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  * General Purpose Timer Synthesizer clock implementation
  10  */
  11 
  12 #define pr_fmt(fmt) "clk-gpt-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 GPT_MSCALE_MASK         0xFFF
  21 #define GPT_NSCALE_SHIFT        12
  22 #define GPT_NSCALE_MASK         0xF
  23 
  24 /*
  25  * DOC: General Purpose Timer Synthesizer clock
  26  *
  27  * Calculates gpt synth clk rate for different values of mscale and nscale
  28  *
  29  * Fout= Fin/((2 ^ (N+1)) * (M+1))
  30  */
  31 
  32 #define to_clk_gpt(_hw) container_of(_hw, struct clk_gpt, hw)
  33 
  34 static unsigned long gpt_calc_rate(struct clk_hw *hw, unsigned long prate,
  35                 int index)
  36 {
  37         struct clk_gpt *gpt = to_clk_gpt(hw);
  38         struct gpt_rate_tbl *rtbl = gpt->rtbl;
  39 
  40         prate /= ((1 << (rtbl[index].nscale + 1)) * (rtbl[index].mscale + 1));
  41 
  42         return prate;
  43 }
  44 
  45 static long clk_gpt_round_rate(struct clk_hw *hw, unsigned long drate,
  46                 unsigned long *prate)
  47 {
  48         struct clk_gpt *gpt = to_clk_gpt(hw);
  49         int unused;
  50 
  51         return clk_round_rate_index(hw, drate, *prate, gpt_calc_rate,
  52                         gpt->rtbl_cnt, &unused);
  53 }
  54 
  55 static unsigned long clk_gpt_recalc_rate(struct clk_hw *hw,
  56                 unsigned long parent_rate)
  57 {
  58         struct clk_gpt *gpt = to_clk_gpt(hw);
  59         unsigned long flags = 0;
  60         unsigned int div = 1, val;
  61 
  62         if (gpt->lock)
  63                 spin_lock_irqsave(gpt->lock, flags);
  64 
  65         val = readl_relaxed(gpt->reg);
  66 
  67         if (gpt->lock)
  68                 spin_unlock_irqrestore(gpt->lock, flags);
  69 
  70         div += val & GPT_MSCALE_MASK;
  71         div *= 1 << (((val >> GPT_NSCALE_SHIFT) & GPT_NSCALE_MASK) + 1);
  72 
  73         if (!div)
  74                 return 0;
  75 
  76         return parent_rate / div;
  77 }
  78 
  79 /* Configures new clock rate of gpt */
  80 static int clk_gpt_set_rate(struct clk_hw *hw, unsigned long drate,
  81                                 unsigned long prate)
  82 {
  83         struct clk_gpt *gpt = to_clk_gpt(hw);
  84         struct gpt_rate_tbl *rtbl = gpt->rtbl;
  85         unsigned long flags = 0, val;
  86         int i;
  87 
  88         clk_round_rate_index(hw, drate, prate, gpt_calc_rate, gpt->rtbl_cnt,
  89                         &i);
  90 
  91         if (gpt->lock)
  92                 spin_lock_irqsave(gpt->lock, flags);
  93 
  94         val = readl(gpt->reg) & ~GPT_MSCALE_MASK;
  95         val &= ~(GPT_NSCALE_MASK << GPT_NSCALE_SHIFT);
  96 
  97         val |= rtbl[i].mscale & GPT_MSCALE_MASK;
  98         val |= (rtbl[i].nscale & GPT_NSCALE_MASK) << GPT_NSCALE_SHIFT;
  99 
 100         writel_relaxed(val, gpt->reg);
 101 
 102         if (gpt->lock)
 103                 spin_unlock_irqrestore(gpt->lock, flags);
 104 
 105         return 0;
 106 }
 107 
 108 static const struct clk_ops clk_gpt_ops = {
 109         .recalc_rate = clk_gpt_recalc_rate,
 110         .round_rate = clk_gpt_round_rate,
 111         .set_rate = clk_gpt_set_rate,
 112 };
 113 
 114 struct clk *clk_register_gpt(const char *name, const char *parent_name, unsigned
 115                 long flags, void __iomem *reg, struct gpt_rate_tbl *rtbl, u8
 116                 rtbl_cnt, spinlock_t *lock)
 117 {
 118         struct clk_init_data init;
 119         struct clk_gpt *gpt;
 120         struct clk *clk;
 121 
 122         if (!name || !parent_name || !reg || !rtbl || !rtbl_cnt) {
 123                 pr_err("Invalid arguments passed\n");
 124                 return ERR_PTR(-EINVAL);
 125         }
 126 
 127         gpt = kzalloc(sizeof(*gpt), GFP_KERNEL);
 128         if (!gpt)
 129                 return ERR_PTR(-ENOMEM);
 130 
 131         /* struct clk_gpt assignments */
 132         gpt->reg = reg;
 133         gpt->rtbl = rtbl;
 134         gpt->rtbl_cnt = rtbl_cnt;
 135         gpt->lock = lock;
 136         gpt->hw.init = &init;
 137 
 138         init.name = name;
 139         init.ops = &clk_gpt_ops;
 140         init.flags = flags;
 141         init.parent_names = &parent_name;
 142         init.num_parents = 1;
 143 
 144         clk = clk_register(NULL, &gpt->hw);
 145         if (!IS_ERR_OR_NULL(clk))
 146                 return clk;
 147 
 148         pr_err("clk register failed\n");
 149         kfree(gpt);
 150 
 151         return NULL;
 152 }

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