root/drivers/clk/mxs/clk-ref.c

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

DEFINITIONS

This source file includes following definitions.
  1. clk_ref_enable
  2. clk_ref_disable
  3. clk_ref_recalc_rate
  4. clk_ref_round_rate
  5. clk_ref_set_rate
  6. mxs_clk_ref

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright 2012 Freescale Semiconductor, Inc.
   4  */
   5 
   6 #include <linux/clk-provider.h>
   7 #include <linux/err.h>
   8 #include <linux/io.h>
   9 #include <linux/slab.h>
  10 #include "clk.h"
  11 
  12 /**
  13  * struct clk_ref - mxs reference clock
  14  * @hw: clk_hw for the reference clock
  15  * @reg: register address
  16  * @idx: the index of the reference clock within the same register
  17  *
  18  * The mxs reference clock sources from pll.  Every 4 reference clocks share
  19  * one register space, and @idx is used to identify them.  Each reference
  20  * clock has a gate control and a fractional * divider.  The rate is calculated
  21  * as pll rate  * (18 / FRAC), where FRAC = 18 ~ 35.
  22  */
  23 struct clk_ref {
  24         struct clk_hw hw;
  25         void __iomem *reg;
  26         u8 idx;
  27 };
  28 
  29 #define to_clk_ref(_hw) container_of(_hw, struct clk_ref, hw)
  30 
  31 static int clk_ref_enable(struct clk_hw *hw)
  32 {
  33         struct clk_ref *ref = to_clk_ref(hw);
  34 
  35         writel_relaxed(1 << ((ref->idx + 1) * 8 - 1), ref->reg + CLR);
  36 
  37         return 0;
  38 }
  39 
  40 static void clk_ref_disable(struct clk_hw *hw)
  41 {
  42         struct clk_ref *ref = to_clk_ref(hw);
  43 
  44         writel_relaxed(1 << ((ref->idx + 1) * 8 - 1), ref->reg + SET);
  45 }
  46 
  47 static unsigned long clk_ref_recalc_rate(struct clk_hw *hw,
  48                                          unsigned long parent_rate)
  49 {
  50         struct clk_ref *ref = to_clk_ref(hw);
  51         u64 tmp = parent_rate;
  52         u8 frac = (readl_relaxed(ref->reg) >> (ref->idx * 8)) & 0x3f;
  53 
  54         tmp *= 18;
  55         do_div(tmp, frac);
  56 
  57         return tmp;
  58 }
  59 
  60 static long clk_ref_round_rate(struct clk_hw *hw, unsigned long rate,
  61                                unsigned long *prate)
  62 {
  63         unsigned long parent_rate = *prate;
  64         u64 tmp = parent_rate;
  65         u8 frac;
  66 
  67         tmp = tmp * 18 + rate / 2;
  68         do_div(tmp, rate);
  69         frac = tmp;
  70 
  71         if (frac < 18)
  72                 frac = 18;
  73         else if (frac > 35)
  74                 frac = 35;
  75 
  76         tmp = parent_rate;
  77         tmp *= 18;
  78         do_div(tmp, frac);
  79 
  80         return tmp;
  81 }
  82 
  83 static int clk_ref_set_rate(struct clk_hw *hw, unsigned long rate,
  84                             unsigned long parent_rate)
  85 {
  86         struct clk_ref *ref = to_clk_ref(hw);
  87         unsigned long flags;
  88         u64 tmp = parent_rate;
  89         u32 val;
  90         u8 frac, shift = ref->idx * 8;
  91 
  92         tmp = tmp * 18 + rate / 2;
  93         do_div(tmp, rate);
  94         frac = tmp;
  95 
  96         if (frac < 18)
  97                 frac = 18;
  98         else if (frac > 35)
  99                 frac = 35;
 100 
 101         spin_lock_irqsave(&mxs_lock, flags);
 102 
 103         val = readl_relaxed(ref->reg);
 104         val &= ~(0x3f << shift);
 105         val |= frac << shift;
 106         writel_relaxed(val, ref->reg);
 107 
 108         spin_unlock_irqrestore(&mxs_lock, flags);
 109 
 110         return 0;
 111 }
 112 
 113 static const struct clk_ops clk_ref_ops = {
 114         .enable         = clk_ref_enable,
 115         .disable        = clk_ref_disable,
 116         .recalc_rate    = clk_ref_recalc_rate,
 117         .round_rate     = clk_ref_round_rate,
 118         .set_rate       = clk_ref_set_rate,
 119 };
 120 
 121 struct clk *mxs_clk_ref(const char *name, const char *parent_name,
 122                         void __iomem *reg, u8 idx)
 123 {
 124         struct clk_ref *ref;
 125         struct clk *clk;
 126         struct clk_init_data init;
 127 
 128         ref = kzalloc(sizeof(*ref), GFP_KERNEL);
 129         if (!ref)
 130                 return ERR_PTR(-ENOMEM);
 131 
 132         init.name = name;
 133         init.ops = &clk_ref_ops;
 134         init.flags = 0;
 135         init.parent_names = (parent_name ? &parent_name: NULL);
 136         init.num_parents = (parent_name ? 1 : 0);
 137 
 138         ref->reg = reg;
 139         ref->idx = idx;
 140         ref->hw.init = &init;
 141 
 142         clk = clk_register(NULL, &ref->hw);
 143         if (IS_ERR(clk))
 144                 kfree(ref);
 145 
 146         return clk;
 147 }

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