1*6b63f023SChao Xie /* 2*6b63f023SChao Xie * mmp factor clock operation source file 3*6b63f023SChao Xie * 4*6b63f023SChao Xie * Copyright (C) 2012 Marvell 5*6b63f023SChao Xie * Chao Xie <xiechao.mail@gmail.com> 6*6b63f023SChao Xie * 7*6b63f023SChao Xie * This file is licensed under the terms of the GNU General Public 8*6b63f023SChao Xie * License version 2. This program is licensed "as is" without any 9*6b63f023SChao Xie * warranty of any kind, whether express or implied. 10*6b63f023SChao Xie */ 11*6b63f023SChao Xie 12*6b63f023SChao Xie #include <linux/clk-provider.h> 13*6b63f023SChao Xie #include <linux/slab.h> 14*6b63f023SChao Xie #include <linux/io.h> 15*6b63f023SChao Xie #include <linux/err.h> 16*6b63f023SChao Xie 17*6b63f023SChao Xie #include "clk.h" 18*6b63f023SChao Xie /* 19*6b63f023SChao Xie * It is M/N clock 20*6b63f023SChao Xie * 21*6b63f023SChao Xie * Fout from synthesizer can be given from two equations: 22*6b63f023SChao Xie * numerator/denominator = Fin / (Fout * factor) 23*6b63f023SChao Xie */ 24*6b63f023SChao Xie 25*6b63f023SChao Xie #define to_clk_factor(hw) container_of(hw, struct clk_factor, hw) 26*6b63f023SChao Xie struct clk_factor { 27*6b63f023SChao Xie struct clk_hw hw; 28*6b63f023SChao Xie void __iomem *base; 29*6b63f023SChao Xie struct clk_factor_masks *masks; 30*6b63f023SChao Xie struct clk_factor_tbl *ftbl; 31*6b63f023SChao Xie unsigned int ftbl_cnt; 32*6b63f023SChao Xie }; 33*6b63f023SChao Xie 34*6b63f023SChao Xie static long clk_factor_round_rate(struct clk_hw *hw, unsigned long drate, 35*6b63f023SChao Xie unsigned long *prate) 36*6b63f023SChao Xie { 37*6b63f023SChao Xie struct clk_factor *factor = to_clk_factor(hw); 38*6b63f023SChao Xie unsigned long rate = 0, prev_rate; 39*6b63f023SChao Xie int i; 40*6b63f023SChao Xie 41*6b63f023SChao Xie for (i = 0; i < factor->ftbl_cnt; i++) { 42*6b63f023SChao Xie prev_rate = rate; 43*6b63f023SChao Xie rate = (((*prate / 10000) * factor->ftbl[i].num) / 44*6b63f023SChao Xie (factor->ftbl[i].den * factor->masks->factor)) * 10000; 45*6b63f023SChao Xie if (rate > drate) 46*6b63f023SChao Xie break; 47*6b63f023SChao Xie } 48*6b63f023SChao Xie if (i == 0) 49*6b63f023SChao Xie return rate; 50*6b63f023SChao Xie else 51*6b63f023SChao Xie return prev_rate; 52*6b63f023SChao Xie } 53*6b63f023SChao Xie 54*6b63f023SChao Xie static unsigned long clk_factor_recalc_rate(struct clk_hw *hw, 55*6b63f023SChao Xie unsigned long parent_rate) 56*6b63f023SChao Xie { 57*6b63f023SChao Xie struct clk_factor *factor = to_clk_factor(hw); 58*6b63f023SChao Xie struct clk_factor_masks *masks = factor->masks; 59*6b63f023SChao Xie unsigned int val, num, den; 60*6b63f023SChao Xie 61*6b63f023SChao Xie val = readl_relaxed(factor->base); 62*6b63f023SChao Xie 63*6b63f023SChao Xie /* calculate numerator */ 64*6b63f023SChao Xie num = (val >> masks->num_shift) & masks->num_mask; 65*6b63f023SChao Xie 66*6b63f023SChao Xie /* calculate denominator */ 67*6b63f023SChao Xie den = (val >> masks->den_shift) & masks->num_mask; 68*6b63f023SChao Xie 69*6b63f023SChao Xie if (!den) 70*6b63f023SChao Xie return 0; 71*6b63f023SChao Xie 72*6b63f023SChao Xie return (((parent_rate / 10000) * den) / 73*6b63f023SChao Xie (num * factor->masks->factor)) * 10000; 74*6b63f023SChao Xie } 75*6b63f023SChao Xie 76*6b63f023SChao Xie /* Configures new clock rate*/ 77*6b63f023SChao Xie static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate, 78*6b63f023SChao Xie unsigned long prate) 79*6b63f023SChao Xie { 80*6b63f023SChao Xie struct clk_factor *factor = to_clk_factor(hw); 81*6b63f023SChao Xie struct clk_factor_masks *masks = factor->masks; 82*6b63f023SChao Xie int i; 83*6b63f023SChao Xie unsigned long val; 84*6b63f023SChao Xie unsigned long prev_rate, rate = 0; 85*6b63f023SChao Xie 86*6b63f023SChao Xie for (i = 0; i < factor->ftbl_cnt; i++) { 87*6b63f023SChao Xie prev_rate = rate; 88*6b63f023SChao Xie rate = (((prate / 10000) * factor->ftbl[i].num) / 89*6b63f023SChao Xie (factor->ftbl[i].den * factor->masks->factor)) * 10000; 90*6b63f023SChao Xie if (rate > drate) 91*6b63f023SChao Xie break; 92*6b63f023SChao Xie } 93*6b63f023SChao Xie if (i > 0) 94*6b63f023SChao Xie i--; 95*6b63f023SChao Xie 96*6b63f023SChao Xie val = readl_relaxed(factor->base); 97*6b63f023SChao Xie 98*6b63f023SChao Xie val &= ~(masks->num_mask << masks->num_shift); 99*6b63f023SChao Xie val |= (factor->ftbl[i].num & masks->num_mask) << masks->num_shift; 100*6b63f023SChao Xie 101*6b63f023SChao Xie val &= ~(masks->den_mask << masks->den_shift); 102*6b63f023SChao Xie val |= (factor->ftbl[i].den & masks->den_mask) << masks->den_shift; 103*6b63f023SChao Xie 104*6b63f023SChao Xie writel_relaxed(val, factor->base); 105*6b63f023SChao Xie 106*6b63f023SChao Xie return 0; 107*6b63f023SChao Xie } 108*6b63f023SChao Xie 109*6b63f023SChao Xie static struct clk_ops clk_factor_ops = { 110*6b63f023SChao Xie .recalc_rate = clk_factor_recalc_rate, 111*6b63f023SChao Xie .round_rate = clk_factor_round_rate, 112*6b63f023SChao Xie .set_rate = clk_factor_set_rate, 113*6b63f023SChao Xie }; 114*6b63f023SChao Xie 115*6b63f023SChao Xie struct clk *mmp_clk_register_factor(const char *name, const char *parent_name, 116*6b63f023SChao Xie unsigned long flags, void __iomem *base, 117*6b63f023SChao Xie struct clk_factor_masks *masks, struct clk_factor_tbl *ftbl, 118*6b63f023SChao Xie unsigned int ftbl_cnt) 119*6b63f023SChao Xie { 120*6b63f023SChao Xie struct clk_factor *factor; 121*6b63f023SChao Xie struct clk_init_data init; 122*6b63f023SChao Xie struct clk *clk; 123*6b63f023SChao Xie 124*6b63f023SChao Xie if (!masks) { 125*6b63f023SChao Xie pr_err("%s: must pass a clk_factor_mask\n", __func__); 126*6b63f023SChao Xie return ERR_PTR(-EINVAL); 127*6b63f023SChao Xie } 128*6b63f023SChao Xie 129*6b63f023SChao Xie factor = kzalloc(sizeof(*factor), GFP_KERNEL); 130*6b63f023SChao Xie if (!factor) { 131*6b63f023SChao Xie pr_err("%s: could not allocate factor clk\n", __func__); 132*6b63f023SChao Xie return ERR_PTR(-ENOMEM); 133*6b63f023SChao Xie } 134*6b63f023SChao Xie 135*6b63f023SChao Xie /* struct clk_aux assignments */ 136*6b63f023SChao Xie factor->base = base; 137*6b63f023SChao Xie factor->masks = masks; 138*6b63f023SChao Xie factor->ftbl = ftbl; 139*6b63f023SChao Xie factor->ftbl_cnt = ftbl_cnt; 140*6b63f023SChao Xie factor->hw.init = &init; 141*6b63f023SChao Xie 142*6b63f023SChao Xie init.name = name; 143*6b63f023SChao Xie init.ops = &clk_factor_ops; 144*6b63f023SChao Xie init.flags = flags; 145*6b63f023SChao Xie init.parent_names = &parent_name; 146*6b63f023SChao Xie init.num_parents = 1; 147*6b63f023SChao Xie 148*6b63f023SChao Xie clk = clk_register(NULL, &factor->hw); 149*6b63f023SChao Xie if (IS_ERR_OR_NULL(clk)) 150*6b63f023SChao Xie kfree(factor); 151*6b63f023SChao Xie 152*6b63f023SChao Xie return clk; 153*6b63f023SChao Xie } 154