1*5335a639SViresh Kumar /* 2*5335a639SViresh Kumar * Copyright (C) 2012 ST Microelectronics 3*5335a639SViresh Kumar * Viresh Kumar <viresh.kumar@st.com> 4*5335a639SViresh Kumar * 5*5335a639SViresh Kumar * This file is licensed under the terms of the GNU General Public 6*5335a639SViresh Kumar * License version 2. This program is licensed "as is" without any 7*5335a639SViresh Kumar * warranty of any kind, whether express or implied. 8*5335a639SViresh Kumar * 9*5335a639SViresh Kumar * Auxiliary Synthesizer clock implementation 10*5335a639SViresh Kumar */ 11*5335a639SViresh Kumar 12*5335a639SViresh Kumar #define pr_fmt(fmt) "clk-aux-synth: " fmt 13*5335a639SViresh Kumar 14*5335a639SViresh Kumar #include <linux/clk-provider.h> 15*5335a639SViresh Kumar #include <linux/slab.h> 16*5335a639SViresh Kumar #include <linux/io.h> 17*5335a639SViresh Kumar #include <linux/err.h> 18*5335a639SViresh Kumar #include "clk.h" 19*5335a639SViresh Kumar 20*5335a639SViresh Kumar /* 21*5335a639SViresh Kumar * DOC: Auxiliary Synthesizer clock 22*5335a639SViresh Kumar * 23*5335a639SViresh Kumar * Aux synth gives rate for different values of eq, x and y 24*5335a639SViresh Kumar * 25*5335a639SViresh Kumar * Fout from synthesizer can be given from two equations: 26*5335a639SViresh Kumar * Fout1 = (Fin * X/Y)/2 EQ1 27*5335a639SViresh Kumar * Fout2 = Fin * X/Y EQ2 28*5335a639SViresh Kumar */ 29*5335a639SViresh Kumar 30*5335a639SViresh Kumar #define to_clk_aux(_hw) container_of(_hw, struct clk_aux, hw) 31*5335a639SViresh Kumar 32*5335a639SViresh Kumar static struct aux_clk_masks default_aux_masks = { 33*5335a639SViresh Kumar .eq_sel_mask = AUX_EQ_SEL_MASK, 34*5335a639SViresh Kumar .eq_sel_shift = AUX_EQ_SEL_SHIFT, 35*5335a639SViresh Kumar .eq1_mask = AUX_EQ1_SEL, 36*5335a639SViresh Kumar .eq2_mask = AUX_EQ2_SEL, 37*5335a639SViresh Kumar .xscale_sel_mask = AUX_XSCALE_MASK, 38*5335a639SViresh Kumar .xscale_sel_shift = AUX_XSCALE_SHIFT, 39*5335a639SViresh Kumar .yscale_sel_mask = AUX_YSCALE_MASK, 40*5335a639SViresh Kumar .yscale_sel_shift = AUX_YSCALE_SHIFT, 41*5335a639SViresh Kumar .enable_bit = AUX_SYNT_ENB, 42*5335a639SViresh Kumar }; 43*5335a639SViresh Kumar 44*5335a639SViresh Kumar static unsigned long aux_calc_rate(struct clk_hw *hw, unsigned long prate, 45*5335a639SViresh Kumar int index) 46*5335a639SViresh Kumar { 47*5335a639SViresh Kumar struct clk_aux *aux = to_clk_aux(hw); 48*5335a639SViresh Kumar struct aux_rate_tbl *rtbl = aux->rtbl; 49*5335a639SViresh Kumar u8 eq = rtbl[index].eq ? 1 : 2; 50*5335a639SViresh Kumar 51*5335a639SViresh Kumar return (((prate / 10000) * rtbl[index].xscale) / 52*5335a639SViresh Kumar (rtbl[index].yscale * eq)) * 10000; 53*5335a639SViresh Kumar } 54*5335a639SViresh Kumar 55*5335a639SViresh Kumar static long clk_aux_round_rate(struct clk_hw *hw, unsigned long drate, 56*5335a639SViresh Kumar unsigned long *prate) 57*5335a639SViresh Kumar { 58*5335a639SViresh Kumar struct clk_aux *aux = to_clk_aux(hw); 59*5335a639SViresh Kumar int unused; 60*5335a639SViresh Kumar 61*5335a639SViresh Kumar return clk_round_rate_index(hw, drate, *prate, aux_calc_rate, 62*5335a639SViresh Kumar aux->rtbl_cnt, &unused); 63*5335a639SViresh Kumar } 64*5335a639SViresh Kumar 65*5335a639SViresh Kumar static unsigned long clk_aux_recalc_rate(struct clk_hw *hw, 66*5335a639SViresh Kumar unsigned long parent_rate) 67*5335a639SViresh Kumar { 68*5335a639SViresh Kumar struct clk_aux *aux = to_clk_aux(hw); 69*5335a639SViresh Kumar unsigned int num = 1, den = 1, val, eqn; 70*5335a639SViresh Kumar unsigned long flags = 0; 71*5335a639SViresh Kumar 72*5335a639SViresh Kumar if (aux->lock) 73*5335a639SViresh Kumar spin_lock_irqsave(aux->lock, flags); 74*5335a639SViresh Kumar 75*5335a639SViresh Kumar val = readl_relaxed(aux->reg); 76*5335a639SViresh Kumar 77*5335a639SViresh Kumar if (aux->lock) 78*5335a639SViresh Kumar spin_unlock_irqrestore(aux->lock, flags); 79*5335a639SViresh Kumar 80*5335a639SViresh Kumar eqn = (val >> aux->masks->eq_sel_shift) & aux->masks->eq_sel_mask; 81*5335a639SViresh Kumar if (eqn == aux->masks->eq1_mask) 82*5335a639SViresh Kumar den = 2; 83*5335a639SViresh Kumar 84*5335a639SViresh Kumar /* calculate numerator */ 85*5335a639SViresh Kumar num = (val >> aux->masks->xscale_sel_shift) & 86*5335a639SViresh Kumar aux->masks->xscale_sel_mask; 87*5335a639SViresh Kumar 88*5335a639SViresh Kumar /* calculate denominator */ 89*5335a639SViresh Kumar den *= (val >> aux->masks->yscale_sel_shift) & 90*5335a639SViresh Kumar aux->masks->yscale_sel_mask; 91*5335a639SViresh Kumar 92*5335a639SViresh Kumar if (!den) 93*5335a639SViresh Kumar return 0; 94*5335a639SViresh Kumar 95*5335a639SViresh Kumar return (((parent_rate / 10000) * num) / den) * 10000; 96*5335a639SViresh Kumar } 97*5335a639SViresh Kumar 98*5335a639SViresh Kumar /* Configures new clock rate of aux */ 99*5335a639SViresh Kumar static int clk_aux_set_rate(struct clk_hw *hw, unsigned long drate, 100*5335a639SViresh Kumar unsigned long prate) 101*5335a639SViresh Kumar { 102*5335a639SViresh Kumar struct clk_aux *aux = to_clk_aux(hw); 103*5335a639SViresh Kumar struct aux_rate_tbl *rtbl = aux->rtbl; 104*5335a639SViresh Kumar unsigned long val, flags = 0; 105*5335a639SViresh Kumar int i; 106*5335a639SViresh Kumar 107*5335a639SViresh Kumar clk_round_rate_index(hw, drate, prate, aux_calc_rate, aux->rtbl_cnt, 108*5335a639SViresh Kumar &i); 109*5335a639SViresh Kumar 110*5335a639SViresh Kumar if (aux->lock) 111*5335a639SViresh Kumar spin_lock_irqsave(aux->lock, flags); 112*5335a639SViresh Kumar 113*5335a639SViresh Kumar val = readl_relaxed(aux->reg) & 114*5335a639SViresh Kumar ~(aux->masks->eq_sel_mask << aux->masks->eq_sel_shift); 115*5335a639SViresh Kumar val |= (rtbl[i].eq & aux->masks->eq_sel_mask) << 116*5335a639SViresh Kumar aux->masks->eq_sel_shift; 117*5335a639SViresh Kumar val &= ~(aux->masks->xscale_sel_mask << aux->masks->xscale_sel_shift); 118*5335a639SViresh Kumar val |= (rtbl[i].xscale & aux->masks->xscale_sel_mask) << 119*5335a639SViresh Kumar aux->masks->xscale_sel_shift; 120*5335a639SViresh Kumar val &= ~(aux->masks->yscale_sel_mask << aux->masks->yscale_sel_shift); 121*5335a639SViresh Kumar val |= (rtbl[i].yscale & aux->masks->yscale_sel_mask) << 122*5335a639SViresh Kumar aux->masks->yscale_sel_shift; 123*5335a639SViresh Kumar writel_relaxed(val, aux->reg); 124*5335a639SViresh Kumar 125*5335a639SViresh Kumar if (aux->lock) 126*5335a639SViresh Kumar spin_unlock_irqrestore(aux->lock, flags); 127*5335a639SViresh Kumar 128*5335a639SViresh Kumar return 0; 129*5335a639SViresh Kumar } 130*5335a639SViresh Kumar 131*5335a639SViresh Kumar static struct clk_ops clk_aux_ops = { 132*5335a639SViresh Kumar .recalc_rate = clk_aux_recalc_rate, 133*5335a639SViresh Kumar .round_rate = clk_aux_round_rate, 134*5335a639SViresh Kumar .set_rate = clk_aux_set_rate, 135*5335a639SViresh Kumar }; 136*5335a639SViresh Kumar 137*5335a639SViresh Kumar struct clk *clk_register_aux(const char *aux_name, const char *gate_name, 138*5335a639SViresh Kumar const char *parent_name, unsigned long flags, void __iomem *reg, 139*5335a639SViresh Kumar struct aux_clk_masks *masks, struct aux_rate_tbl *rtbl, 140*5335a639SViresh Kumar u8 rtbl_cnt, spinlock_t *lock, struct clk **gate_clk) 141*5335a639SViresh Kumar { 142*5335a639SViresh Kumar struct clk_aux *aux; 143*5335a639SViresh Kumar struct clk_init_data init; 144*5335a639SViresh Kumar struct clk *clk; 145*5335a639SViresh Kumar 146*5335a639SViresh Kumar if (!aux_name || !parent_name || !reg || !rtbl || !rtbl_cnt) { 147*5335a639SViresh Kumar pr_err("Invalid arguments passed"); 148*5335a639SViresh Kumar return ERR_PTR(-EINVAL); 149*5335a639SViresh Kumar } 150*5335a639SViresh Kumar 151*5335a639SViresh Kumar aux = kzalloc(sizeof(*aux), GFP_KERNEL); 152*5335a639SViresh Kumar if (!aux) { 153*5335a639SViresh Kumar pr_err("could not allocate aux clk\n"); 154*5335a639SViresh Kumar return ERR_PTR(-ENOMEM); 155*5335a639SViresh Kumar } 156*5335a639SViresh Kumar 157*5335a639SViresh Kumar /* struct clk_aux assignments */ 158*5335a639SViresh Kumar if (!masks) 159*5335a639SViresh Kumar aux->masks = &default_aux_masks; 160*5335a639SViresh Kumar else 161*5335a639SViresh Kumar aux->masks = masks; 162*5335a639SViresh Kumar 163*5335a639SViresh Kumar aux->reg = reg; 164*5335a639SViresh Kumar aux->rtbl = rtbl; 165*5335a639SViresh Kumar aux->rtbl_cnt = rtbl_cnt; 166*5335a639SViresh Kumar aux->lock = lock; 167*5335a639SViresh Kumar aux->hw.init = &init; 168*5335a639SViresh Kumar 169*5335a639SViresh Kumar init.name = aux_name; 170*5335a639SViresh Kumar init.ops = &clk_aux_ops; 171*5335a639SViresh Kumar init.flags = flags; 172*5335a639SViresh Kumar init.parent_names = &parent_name; 173*5335a639SViresh Kumar init.num_parents = 1; 174*5335a639SViresh Kumar 175*5335a639SViresh Kumar clk = clk_register(NULL, &aux->hw); 176*5335a639SViresh Kumar if (IS_ERR_OR_NULL(clk)) 177*5335a639SViresh Kumar goto free_aux; 178*5335a639SViresh Kumar 179*5335a639SViresh Kumar if (gate_name) { 180*5335a639SViresh Kumar struct clk *tgate_clk; 181*5335a639SViresh Kumar 182*5335a639SViresh Kumar tgate_clk = clk_register_gate(NULL, gate_name, aux_name, 0, reg, 183*5335a639SViresh Kumar aux->masks->enable_bit, 0, lock); 184*5335a639SViresh Kumar if (IS_ERR_OR_NULL(tgate_clk)) 185*5335a639SViresh Kumar goto free_aux; 186*5335a639SViresh Kumar 187*5335a639SViresh Kumar if (gate_clk) 188*5335a639SViresh Kumar *gate_clk = tgate_clk; 189*5335a639SViresh Kumar } 190*5335a639SViresh Kumar 191*5335a639SViresh Kumar return clk; 192*5335a639SViresh Kumar 193*5335a639SViresh Kumar free_aux: 194*5335a639SViresh Kumar kfree(aux); 195*5335a639SViresh Kumar pr_err("clk register failed\n"); 196*5335a639SViresh Kumar 197*5335a639SViresh Kumar return NULL; 198*5335a639SViresh Kumar } 199