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