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 long clk_aux_round_rate(struct clk_hw *hw, unsigned long drate, 53 unsigned long *prate) 54 { 55 struct clk_aux *aux = to_clk_aux(hw); 56 int unused; 57 58 return clk_round_rate_index(hw, drate, *prate, aux_calc_rate, 59 aux->rtbl_cnt, &unused); 60 } 61 62 static unsigned long clk_aux_recalc_rate(struct clk_hw *hw, 63 unsigned long parent_rate) 64 { 65 struct clk_aux *aux = to_clk_aux(hw); 66 unsigned int num = 1, den = 1, val, eqn; 67 unsigned long flags = 0; 68 69 if (aux->lock) 70 spin_lock_irqsave(aux->lock, flags); 71 72 val = readl_relaxed(aux->reg); 73 74 if (aux->lock) 75 spin_unlock_irqrestore(aux->lock, flags); 76 77 eqn = (val >> aux->masks->eq_sel_shift) & aux->masks->eq_sel_mask; 78 if (eqn == aux->masks->eq1_mask) 79 den = 2; 80 81 /* calculate numerator */ 82 num = (val >> aux->masks->xscale_sel_shift) & 83 aux->masks->xscale_sel_mask; 84 85 /* calculate denominator */ 86 den *= (val >> aux->masks->yscale_sel_shift) & 87 aux->masks->yscale_sel_mask; 88 89 if (!den) 90 return 0; 91 92 return (((parent_rate / 10000) * num) / den) * 10000; 93 } 94 95 /* Configures new clock rate of aux */ 96 static int clk_aux_set_rate(struct clk_hw *hw, unsigned long drate, 97 unsigned long prate) 98 { 99 struct clk_aux *aux = to_clk_aux(hw); 100 struct aux_rate_tbl *rtbl = aux->rtbl; 101 unsigned long val, flags = 0; 102 int i; 103 104 clk_round_rate_index(hw, drate, prate, aux_calc_rate, aux->rtbl_cnt, 105 &i); 106 107 if (aux->lock) 108 spin_lock_irqsave(aux->lock, flags); 109 110 val = readl_relaxed(aux->reg) & 111 ~(aux->masks->eq_sel_mask << aux->masks->eq_sel_shift); 112 val |= (rtbl[i].eq & aux->masks->eq_sel_mask) << 113 aux->masks->eq_sel_shift; 114 val &= ~(aux->masks->xscale_sel_mask << aux->masks->xscale_sel_shift); 115 val |= (rtbl[i].xscale & aux->masks->xscale_sel_mask) << 116 aux->masks->xscale_sel_shift; 117 val &= ~(aux->masks->yscale_sel_mask << aux->masks->yscale_sel_shift); 118 val |= (rtbl[i].yscale & aux->masks->yscale_sel_mask) << 119 aux->masks->yscale_sel_shift; 120 writel_relaxed(val, aux->reg); 121 122 if (aux->lock) 123 spin_unlock_irqrestore(aux->lock, flags); 124 125 return 0; 126 } 127 128 static const struct clk_ops clk_aux_ops = { 129 .recalc_rate = clk_aux_recalc_rate, 130 .round_rate = clk_aux_round_rate, 131 .set_rate = clk_aux_set_rate, 132 }; 133 134 struct clk *clk_register_aux(const char *aux_name, const char *gate_name, 135 const char *parent_name, unsigned long flags, void __iomem *reg, 136 const struct aux_clk_masks *masks, struct aux_rate_tbl *rtbl, 137 u8 rtbl_cnt, spinlock_t *lock, struct clk **gate_clk) 138 { 139 struct clk_aux *aux; 140 struct clk_init_data init; 141 struct clk *clk; 142 143 if (!aux_name || !parent_name || !reg || !rtbl || !rtbl_cnt) { 144 pr_err("Invalid arguments passed"); 145 return ERR_PTR(-EINVAL); 146 } 147 148 aux = kzalloc(sizeof(*aux), GFP_KERNEL); 149 if (!aux) 150 return ERR_PTR(-ENOMEM); 151 152 /* struct clk_aux assignments */ 153 if (!masks) 154 aux->masks = &default_aux_masks; 155 else 156 aux->masks = masks; 157 158 aux->reg = reg; 159 aux->rtbl = rtbl; 160 aux->rtbl_cnt = rtbl_cnt; 161 aux->lock = lock; 162 aux->hw.init = &init; 163 164 init.name = aux_name; 165 init.ops = &clk_aux_ops; 166 init.flags = flags; 167 init.parent_names = &parent_name; 168 init.num_parents = 1; 169 170 clk = clk_register(NULL, &aux->hw); 171 if (IS_ERR_OR_NULL(clk)) 172 goto free_aux; 173 174 if (gate_name) { 175 struct clk *tgate_clk; 176 177 tgate_clk = clk_register_gate(NULL, gate_name, aux_name, 178 CLK_SET_RATE_PARENT, reg, 179 aux->masks->enable_bit, 0, lock); 180 if (IS_ERR_OR_NULL(tgate_clk)) 181 goto free_aux; 182 183 if (gate_clk) 184 *gate_clk = tgate_clk; 185 } 186 187 return clk; 188 189 free_aux: 190 kfree(aux); 191 pr_err("clk register failed\n"); 192 193 return NULL; 194 } 195