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