1 /* 2 * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> 3 * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org> 4 * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org> 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 * Adjustable divider clock implementation 11 */ 12 13 #include <linux/clk-provider.h> 14 #include <linux/module.h> 15 #include <linux/slab.h> 16 #include <linux/io.h> 17 #include <linux/err.h> 18 #include <linux/string.h> 19 20 /* 21 * DOC: basic adjustable divider clock that cannot gate 22 * 23 * Traits of this clock: 24 * prepare - clk_prepare only ensures that parents are prepared 25 * enable - clk_enable only ensures that parents are enabled 26 * rate - rate is adjustable. clk->rate = parent->rate / divisor 27 * parent - fixed parent. No clk_set_parent support 28 */ 29 30 #define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) 31 32 #define div_mask(d) ((1 << (d->width)) - 1) 33 34 static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, 35 unsigned long parent_rate) 36 { 37 struct clk_divider *divider = to_clk_divider(hw); 38 unsigned int div; 39 40 div = readl(divider->reg) >> divider->shift; 41 div &= div_mask(divider); 42 43 if (!(divider->flags & CLK_DIVIDER_ONE_BASED)) 44 div++; 45 46 return parent_rate / div; 47 } 48 EXPORT_SYMBOL_GPL(clk_divider_recalc_rate); 49 50 /* 51 * The reverse of DIV_ROUND_UP: The maximum number which 52 * divided by m is r 53 */ 54 #define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1) 55 56 static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, 57 unsigned long *best_parent_rate) 58 { 59 struct clk_divider *divider = to_clk_divider(hw); 60 int i, bestdiv = 0; 61 unsigned long parent_rate, best = 0, now, maxdiv; 62 63 if (!rate) 64 rate = 1; 65 66 maxdiv = (1 << divider->width); 67 68 if (divider->flags & CLK_DIVIDER_ONE_BASED) 69 maxdiv--; 70 71 if (!best_parent_rate) { 72 parent_rate = __clk_get_rate(__clk_get_parent(hw->clk)); 73 bestdiv = DIV_ROUND_UP(parent_rate, rate); 74 bestdiv = bestdiv == 0 ? 1 : bestdiv; 75 bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; 76 return bestdiv; 77 } 78 79 /* 80 * The maximum divider we can use without overflowing 81 * unsigned long in rate * i below 82 */ 83 maxdiv = min(ULONG_MAX / rate, maxdiv); 84 85 for (i = 1; i <= maxdiv; i++) { 86 parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 87 MULT_ROUND_UP(rate, i)); 88 now = parent_rate / i; 89 if (now <= rate && now > best) { 90 bestdiv = i; 91 best = now; 92 *best_parent_rate = parent_rate; 93 } 94 } 95 96 if (!bestdiv) { 97 bestdiv = (1 << divider->width); 98 if (divider->flags & CLK_DIVIDER_ONE_BASED) 99 bestdiv--; 100 *best_parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1); 101 } 102 103 return bestdiv; 104 } 105 106 static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, 107 unsigned long *prate) 108 { 109 int div; 110 div = clk_divider_bestdiv(hw, rate, prate); 111 112 if (prate) 113 return *prate / div; 114 else { 115 unsigned long r; 116 r = __clk_get_rate(__clk_get_parent(hw->clk)); 117 return r / div; 118 } 119 } 120 EXPORT_SYMBOL_GPL(clk_divider_round_rate); 121 122 static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate) 123 { 124 struct clk_divider *divider = to_clk_divider(hw); 125 unsigned int div; 126 unsigned long flags = 0; 127 u32 val; 128 129 div = __clk_get_rate(__clk_get_parent(hw->clk)) / rate; 130 131 if (!(divider->flags & CLK_DIVIDER_ONE_BASED)) 132 div--; 133 134 if (div > div_mask(divider)) 135 div = div_mask(divider); 136 137 if (divider->lock) 138 spin_lock_irqsave(divider->lock, flags); 139 140 val = readl(divider->reg); 141 val &= ~(div_mask(divider) << divider->shift); 142 val |= div << divider->shift; 143 writel(val, divider->reg); 144 145 if (divider->lock) 146 spin_unlock_irqrestore(divider->lock, flags); 147 148 return 0; 149 } 150 EXPORT_SYMBOL_GPL(clk_divider_set_rate); 151 152 struct clk_ops clk_divider_ops = { 153 .recalc_rate = clk_divider_recalc_rate, 154 .round_rate = clk_divider_round_rate, 155 .set_rate = clk_divider_set_rate, 156 }; 157 EXPORT_SYMBOL_GPL(clk_divider_ops); 158 159 struct clk *clk_register_divider(struct device *dev, const char *name, 160 const char *parent_name, unsigned long flags, 161 void __iomem *reg, u8 shift, u8 width, 162 u8 clk_divider_flags, spinlock_t *lock) 163 { 164 struct clk_divider *div; 165 struct clk *clk; 166 167 div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL); 168 169 if (!div) { 170 pr_err("%s: could not allocate divider clk\n", __func__); 171 return NULL; 172 } 173 174 /* struct clk_divider assignments */ 175 div->reg = reg; 176 div->shift = shift; 177 div->width = width; 178 div->flags = clk_divider_flags; 179 div->lock = lock; 180 181 if (parent_name) { 182 div->parent[0] = kstrdup(parent_name, GFP_KERNEL); 183 if (!div->parent[0]) 184 goto out; 185 } 186 187 clk = clk_register(dev, name, 188 &clk_divider_ops, &div->hw, 189 div->parent, 190 (parent_name ? 1 : 0), 191 flags); 192 if (clk) 193 return clk; 194 195 out: 196 kfree(div->parent[0]); 197 kfree(div); 198 199 return NULL; 200 } 201