1bcd61c0fSStephen Boyd /* 2bcd61c0fSStephen Boyd * Copyright (c) 2013, The Linux Foundation. All rights reserved. 3bcd61c0fSStephen Boyd * 4bcd61c0fSStephen Boyd * This software is licensed under the terms of the GNU General Public 5bcd61c0fSStephen Boyd * License version 2, as published by the Free Software Foundation, and 6bcd61c0fSStephen Boyd * may be copied, distributed, and modified under those terms. 7bcd61c0fSStephen Boyd * 8bcd61c0fSStephen Boyd * This program is distributed in the hope that it will be useful, 9bcd61c0fSStephen Boyd * but WITHOUT ANY WARRANTY; without even the implied warranty of 10bcd61c0fSStephen Boyd * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11bcd61c0fSStephen Boyd * GNU General Public License for more details. 12bcd61c0fSStephen Boyd */ 13bcd61c0fSStephen Boyd 14bcd61c0fSStephen Boyd #include <linux/kernel.h> 15bcd61c0fSStephen Boyd #include <linux/bitops.h> 16bcd61c0fSStephen Boyd #include <linux/err.h> 17bcd61c0fSStephen Boyd #include <linux/export.h> 18bcd61c0fSStephen Boyd #include <linux/clk-provider.h> 19bcd61c0fSStephen Boyd #include <linux/regmap.h> 20bcd61c0fSStephen Boyd 21bcd61c0fSStephen Boyd #include <asm/div64.h> 22bcd61c0fSStephen Boyd 23bcd61c0fSStephen Boyd #include "clk-rcg.h" 2450c6a503SStephen Boyd #include "common.h" 25bcd61c0fSStephen Boyd 26bcd61c0fSStephen Boyd static u32 ns_to_src(struct src_sel *s, u32 ns) 27bcd61c0fSStephen Boyd { 28bcd61c0fSStephen Boyd ns >>= s->src_sel_shift; 29bcd61c0fSStephen Boyd ns &= SRC_SEL_MASK; 30bcd61c0fSStephen Boyd return ns; 31bcd61c0fSStephen Boyd } 32bcd61c0fSStephen Boyd 33bcd61c0fSStephen Boyd static u32 src_to_ns(struct src_sel *s, u8 src, u32 ns) 34bcd61c0fSStephen Boyd { 35bcd61c0fSStephen Boyd u32 mask; 36bcd61c0fSStephen Boyd 37bcd61c0fSStephen Boyd mask = SRC_SEL_MASK; 38bcd61c0fSStephen Boyd mask <<= s->src_sel_shift; 39bcd61c0fSStephen Boyd ns &= ~mask; 40bcd61c0fSStephen Boyd 41bcd61c0fSStephen Boyd ns |= src << s->src_sel_shift; 42bcd61c0fSStephen Boyd return ns; 43bcd61c0fSStephen Boyd } 44bcd61c0fSStephen Boyd 45bcd61c0fSStephen Boyd static u8 clk_rcg_get_parent(struct clk_hw *hw) 46bcd61c0fSStephen Boyd { 47bcd61c0fSStephen Boyd struct clk_rcg *rcg = to_clk_rcg(hw); 48bcd61c0fSStephen Boyd int num_parents = __clk_get_num_parents(hw->clk); 49bcd61c0fSStephen Boyd u32 ns; 50bcd61c0fSStephen Boyd int i; 51bcd61c0fSStephen Boyd 52bcd61c0fSStephen Boyd regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); 53bcd61c0fSStephen Boyd ns = ns_to_src(&rcg->s, ns); 54bcd61c0fSStephen Boyd for (i = 0; i < num_parents; i++) 55bcd61c0fSStephen Boyd if (ns == rcg->s.parent_map[i]) 56bcd61c0fSStephen Boyd return i; 57bcd61c0fSStephen Boyd 58bcd61c0fSStephen Boyd return -EINVAL; 59bcd61c0fSStephen Boyd } 60bcd61c0fSStephen Boyd 61bcd61c0fSStephen Boyd static int reg_to_bank(struct clk_dyn_rcg *rcg, u32 bank) 62bcd61c0fSStephen Boyd { 63bcd61c0fSStephen Boyd bank &= BIT(rcg->mux_sel_bit); 64bcd61c0fSStephen Boyd return !!bank; 65bcd61c0fSStephen Boyd } 66bcd61c0fSStephen Boyd 67bcd61c0fSStephen Boyd static u8 clk_dyn_rcg_get_parent(struct clk_hw *hw) 68bcd61c0fSStephen Boyd { 69bcd61c0fSStephen Boyd struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); 70bcd61c0fSStephen Boyd int num_parents = __clk_get_num_parents(hw->clk); 71*229fd4a5SStephen Boyd u32 ns, reg; 72bcd61c0fSStephen Boyd int bank; 73bcd61c0fSStephen Boyd int i; 74bcd61c0fSStephen Boyd struct src_sel *s; 75bcd61c0fSStephen Boyd 76*229fd4a5SStephen Boyd regmap_read(rcg->clkr.regmap, rcg->bank_reg, ®); 77*229fd4a5SStephen Boyd bank = reg_to_bank(rcg, reg); 78bcd61c0fSStephen Boyd s = &rcg->s[bank]; 79bcd61c0fSStephen Boyd 80*229fd4a5SStephen Boyd regmap_read(rcg->clkr.regmap, rcg->ns_reg[bank], &ns); 81bcd61c0fSStephen Boyd ns = ns_to_src(s, ns); 82bcd61c0fSStephen Boyd 83bcd61c0fSStephen Boyd for (i = 0; i < num_parents; i++) 84bcd61c0fSStephen Boyd if (ns == s->parent_map[i]) 85bcd61c0fSStephen Boyd return i; 86bcd61c0fSStephen Boyd 87bcd61c0fSStephen Boyd return -EINVAL; 88bcd61c0fSStephen Boyd } 89bcd61c0fSStephen Boyd 90bcd61c0fSStephen Boyd static int clk_rcg_set_parent(struct clk_hw *hw, u8 index) 91bcd61c0fSStephen Boyd { 92bcd61c0fSStephen Boyd struct clk_rcg *rcg = to_clk_rcg(hw); 93bcd61c0fSStephen Boyd u32 ns; 94bcd61c0fSStephen Boyd 95bcd61c0fSStephen Boyd regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); 96bcd61c0fSStephen Boyd ns = src_to_ns(&rcg->s, rcg->s.parent_map[index], ns); 97bcd61c0fSStephen Boyd regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns); 98bcd61c0fSStephen Boyd 99bcd61c0fSStephen Boyd return 0; 100bcd61c0fSStephen Boyd } 101bcd61c0fSStephen Boyd 102bcd61c0fSStephen Boyd static u32 md_to_m(struct mn *mn, u32 md) 103bcd61c0fSStephen Boyd { 104bcd61c0fSStephen Boyd md >>= mn->m_val_shift; 105bcd61c0fSStephen Boyd md &= BIT(mn->width) - 1; 106bcd61c0fSStephen Boyd return md; 107bcd61c0fSStephen Boyd } 108bcd61c0fSStephen Boyd 109bcd61c0fSStephen Boyd static u32 ns_to_pre_div(struct pre_div *p, u32 ns) 110bcd61c0fSStephen Boyd { 111bcd61c0fSStephen Boyd ns >>= p->pre_div_shift; 112bcd61c0fSStephen Boyd ns &= BIT(p->pre_div_width) - 1; 113bcd61c0fSStephen Boyd return ns; 114bcd61c0fSStephen Boyd } 115bcd61c0fSStephen Boyd 116bcd61c0fSStephen Boyd static u32 pre_div_to_ns(struct pre_div *p, u8 pre_div, u32 ns) 117bcd61c0fSStephen Boyd { 118bcd61c0fSStephen Boyd u32 mask; 119bcd61c0fSStephen Boyd 120bcd61c0fSStephen Boyd mask = BIT(p->pre_div_width) - 1; 121bcd61c0fSStephen Boyd mask <<= p->pre_div_shift; 122bcd61c0fSStephen Boyd ns &= ~mask; 123bcd61c0fSStephen Boyd 124bcd61c0fSStephen Boyd ns |= pre_div << p->pre_div_shift; 125bcd61c0fSStephen Boyd return ns; 126bcd61c0fSStephen Boyd } 127bcd61c0fSStephen Boyd 128bcd61c0fSStephen Boyd static u32 mn_to_md(struct mn *mn, u32 m, u32 n, u32 md) 129bcd61c0fSStephen Boyd { 130bcd61c0fSStephen Boyd u32 mask, mask_w; 131bcd61c0fSStephen Boyd 132bcd61c0fSStephen Boyd mask_w = BIT(mn->width) - 1; 133bcd61c0fSStephen Boyd mask = (mask_w << mn->m_val_shift) | mask_w; 134bcd61c0fSStephen Boyd md &= ~mask; 135bcd61c0fSStephen Boyd 136bcd61c0fSStephen Boyd if (n) { 137bcd61c0fSStephen Boyd m <<= mn->m_val_shift; 138bcd61c0fSStephen Boyd md |= m; 139bcd61c0fSStephen Boyd md |= ~n & mask_w; 140bcd61c0fSStephen Boyd } 141bcd61c0fSStephen Boyd 142bcd61c0fSStephen Boyd return md; 143bcd61c0fSStephen Boyd } 144bcd61c0fSStephen Boyd 145bcd61c0fSStephen Boyd static u32 ns_m_to_n(struct mn *mn, u32 ns, u32 m) 146bcd61c0fSStephen Boyd { 147bcd61c0fSStephen Boyd ns = ~ns >> mn->n_val_shift; 148bcd61c0fSStephen Boyd ns &= BIT(mn->width) - 1; 149bcd61c0fSStephen Boyd return ns + m; 150bcd61c0fSStephen Boyd } 151bcd61c0fSStephen Boyd 152bcd61c0fSStephen Boyd static u32 reg_to_mnctr_mode(struct mn *mn, u32 val) 153bcd61c0fSStephen Boyd { 154bcd61c0fSStephen Boyd val >>= mn->mnctr_mode_shift; 155bcd61c0fSStephen Boyd val &= MNCTR_MODE_MASK; 156bcd61c0fSStephen Boyd return val; 157bcd61c0fSStephen Boyd } 158bcd61c0fSStephen Boyd 159bcd61c0fSStephen Boyd static u32 mn_to_ns(struct mn *mn, u32 m, u32 n, u32 ns) 160bcd61c0fSStephen Boyd { 161bcd61c0fSStephen Boyd u32 mask; 162bcd61c0fSStephen Boyd 163bcd61c0fSStephen Boyd mask = BIT(mn->width) - 1; 164bcd61c0fSStephen Boyd mask <<= mn->n_val_shift; 165bcd61c0fSStephen Boyd ns &= ~mask; 166bcd61c0fSStephen Boyd 167bcd61c0fSStephen Boyd if (n) { 168bcd61c0fSStephen Boyd n = n - m; 169bcd61c0fSStephen Boyd n = ~n; 170bcd61c0fSStephen Boyd n &= BIT(mn->width) - 1; 171bcd61c0fSStephen Boyd n <<= mn->n_val_shift; 172bcd61c0fSStephen Boyd ns |= n; 173bcd61c0fSStephen Boyd } 174bcd61c0fSStephen Boyd 175bcd61c0fSStephen Boyd return ns; 176bcd61c0fSStephen Boyd } 177bcd61c0fSStephen Boyd 178bcd61c0fSStephen Boyd static u32 mn_to_reg(struct mn *mn, u32 m, u32 n, u32 val) 179bcd61c0fSStephen Boyd { 180bcd61c0fSStephen Boyd u32 mask; 181bcd61c0fSStephen Boyd 182bcd61c0fSStephen Boyd mask = MNCTR_MODE_MASK << mn->mnctr_mode_shift; 183bcd61c0fSStephen Boyd mask |= BIT(mn->mnctr_en_bit); 184bcd61c0fSStephen Boyd val &= ~mask; 185bcd61c0fSStephen Boyd 186bcd61c0fSStephen Boyd if (n) { 187bcd61c0fSStephen Boyd val |= BIT(mn->mnctr_en_bit); 188bcd61c0fSStephen Boyd val |= MNCTR_MODE_DUAL << mn->mnctr_mode_shift; 189bcd61c0fSStephen Boyd } 190bcd61c0fSStephen Boyd 191bcd61c0fSStephen Boyd return val; 192bcd61c0fSStephen Boyd } 193bcd61c0fSStephen Boyd 194bcd61c0fSStephen Boyd static void configure_bank(struct clk_dyn_rcg *rcg, const struct freq_tbl *f) 195bcd61c0fSStephen Boyd { 196*229fd4a5SStephen Boyd u32 ns, md, reg; 197bcd61c0fSStephen Boyd int bank, new_bank; 198bcd61c0fSStephen Boyd struct mn *mn; 199bcd61c0fSStephen Boyd struct pre_div *p; 200bcd61c0fSStephen Boyd struct src_sel *s; 201bcd61c0fSStephen Boyd bool enabled; 202*229fd4a5SStephen Boyd u32 md_reg, ns_reg; 203bcd61c0fSStephen Boyd bool banked_mn = !!rcg->mn[1].width; 204*229fd4a5SStephen Boyd bool banked_p = !!rcg->p[1].pre_div_width; 205bcd61c0fSStephen Boyd struct clk_hw *hw = &rcg->clkr.hw; 206bcd61c0fSStephen Boyd 207bcd61c0fSStephen Boyd enabled = __clk_is_enabled(hw->clk); 208bcd61c0fSStephen Boyd 209*229fd4a5SStephen Boyd regmap_read(rcg->clkr.regmap, rcg->bank_reg, ®); 210*229fd4a5SStephen Boyd bank = reg_to_bank(rcg, reg); 211bcd61c0fSStephen Boyd new_bank = enabled ? !bank : bank; 212bcd61c0fSStephen Boyd 213*229fd4a5SStephen Boyd ns_reg = rcg->ns_reg[new_bank]; 214*229fd4a5SStephen Boyd regmap_read(rcg->clkr.regmap, ns_reg, &ns); 215*229fd4a5SStephen Boyd 216bcd61c0fSStephen Boyd if (banked_mn) { 217bcd61c0fSStephen Boyd mn = &rcg->mn[new_bank]; 218bcd61c0fSStephen Boyd md_reg = rcg->md_reg[new_bank]; 219bcd61c0fSStephen Boyd 220bcd61c0fSStephen Boyd ns |= BIT(mn->mnctr_reset_bit); 221*229fd4a5SStephen Boyd regmap_write(rcg->clkr.regmap, ns_reg, ns); 222bcd61c0fSStephen Boyd 223bcd61c0fSStephen Boyd regmap_read(rcg->clkr.regmap, md_reg, &md); 224bcd61c0fSStephen Boyd md = mn_to_md(mn, f->m, f->n, md); 225bcd61c0fSStephen Boyd regmap_write(rcg->clkr.regmap, md_reg, md); 226bcd61c0fSStephen Boyd 227bcd61c0fSStephen Boyd ns = mn_to_ns(mn, f->m, f->n, ns); 228*229fd4a5SStephen Boyd regmap_write(rcg->clkr.regmap, ns_reg, ns); 229bcd61c0fSStephen Boyd 230*229fd4a5SStephen Boyd /* Two NS registers means mode control is in NS register */ 231*229fd4a5SStephen Boyd if (rcg->ns_reg[0] != rcg->ns_reg[1]) { 232*229fd4a5SStephen Boyd ns = mn_to_reg(mn, f->m, f->n, ns); 233*229fd4a5SStephen Boyd regmap_write(rcg->clkr.regmap, ns_reg, ns); 234*229fd4a5SStephen Boyd } else { 235*229fd4a5SStephen Boyd reg = mn_to_reg(mn, f->m, f->n, reg); 236*229fd4a5SStephen Boyd regmap_write(rcg->clkr.regmap, rcg->bank_reg, reg); 237*229fd4a5SStephen Boyd } 238bcd61c0fSStephen Boyd 239bcd61c0fSStephen Boyd ns &= ~BIT(mn->mnctr_reset_bit); 240*229fd4a5SStephen Boyd regmap_write(rcg->clkr.regmap, ns_reg, ns); 241*229fd4a5SStephen Boyd } 242*229fd4a5SStephen Boyd 243*229fd4a5SStephen Boyd if (banked_p) { 244bcd61c0fSStephen Boyd p = &rcg->p[new_bank]; 245bcd61c0fSStephen Boyd ns = pre_div_to_ns(p, f->pre_div - 1, ns); 246bcd61c0fSStephen Boyd } 247bcd61c0fSStephen Boyd 248bcd61c0fSStephen Boyd s = &rcg->s[new_bank]; 249bcd61c0fSStephen Boyd ns = src_to_ns(s, s->parent_map[f->src], ns); 250*229fd4a5SStephen Boyd regmap_write(rcg->clkr.regmap, ns_reg, ns); 251bcd61c0fSStephen Boyd 252bcd61c0fSStephen Boyd if (enabled) { 253*229fd4a5SStephen Boyd regmap_read(rcg->clkr.regmap, rcg->bank_reg, ®); 254*229fd4a5SStephen Boyd reg ^= BIT(rcg->mux_sel_bit); 255*229fd4a5SStephen Boyd regmap_write(rcg->clkr.regmap, rcg->bank_reg, reg); 256bcd61c0fSStephen Boyd } 257bcd61c0fSStephen Boyd } 258bcd61c0fSStephen Boyd 259bcd61c0fSStephen Boyd static int clk_dyn_rcg_set_parent(struct clk_hw *hw, u8 index) 260bcd61c0fSStephen Boyd { 261bcd61c0fSStephen Boyd struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); 262*229fd4a5SStephen Boyd u32 ns, md, reg; 263bcd61c0fSStephen Boyd int bank; 264bcd61c0fSStephen Boyd struct freq_tbl f = { 0 }; 265bcd61c0fSStephen Boyd bool banked_mn = !!rcg->mn[1].width; 266*229fd4a5SStephen Boyd bool banked_p = !!rcg->p[1].pre_div_width; 267bcd61c0fSStephen Boyd 268*229fd4a5SStephen Boyd regmap_read(rcg->clkr.regmap, rcg->bank_reg, ®); 269bcd61c0fSStephen Boyd bank = reg_to_bank(rcg, reg); 270bcd61c0fSStephen Boyd 271*229fd4a5SStephen Boyd regmap_read(rcg->clkr.regmap, rcg->ns_reg[bank], &ns); 272*229fd4a5SStephen Boyd 273bcd61c0fSStephen Boyd if (banked_mn) { 274bcd61c0fSStephen Boyd regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md); 275bcd61c0fSStephen Boyd f.m = md_to_m(&rcg->mn[bank], md); 276bcd61c0fSStephen Boyd f.n = ns_m_to_n(&rcg->mn[bank], ns, f.m); 277bcd61c0fSStephen Boyd } 278bcd61c0fSStephen Boyd 279*229fd4a5SStephen Boyd if (banked_p) 280*229fd4a5SStephen Boyd f.pre_div = ns_to_pre_div(&rcg->p[bank], ns) + 1; 281*229fd4a5SStephen Boyd 282*229fd4a5SStephen Boyd f.src = index; 283bcd61c0fSStephen Boyd configure_bank(rcg, &f); 284bcd61c0fSStephen Boyd 285bcd61c0fSStephen Boyd return 0; 286bcd61c0fSStephen Boyd } 287bcd61c0fSStephen Boyd 288bcd61c0fSStephen Boyd /* 289bcd61c0fSStephen Boyd * Calculate m/n:d rate 290bcd61c0fSStephen Boyd * 291bcd61c0fSStephen Boyd * parent_rate m 292bcd61c0fSStephen Boyd * rate = ----------- x --- 293bcd61c0fSStephen Boyd * pre_div n 294bcd61c0fSStephen Boyd */ 295bcd61c0fSStephen Boyd static unsigned long 296bcd61c0fSStephen Boyd calc_rate(unsigned long rate, u32 m, u32 n, u32 mode, u32 pre_div) 297bcd61c0fSStephen Boyd { 298bcd61c0fSStephen Boyd if (pre_div) 299bcd61c0fSStephen Boyd rate /= pre_div + 1; 300bcd61c0fSStephen Boyd 301bcd61c0fSStephen Boyd if (mode) { 302bcd61c0fSStephen Boyd u64 tmp = rate; 303bcd61c0fSStephen Boyd tmp *= m; 304bcd61c0fSStephen Boyd do_div(tmp, n); 305bcd61c0fSStephen Boyd rate = tmp; 306bcd61c0fSStephen Boyd } 307bcd61c0fSStephen Boyd 308bcd61c0fSStephen Boyd return rate; 309bcd61c0fSStephen Boyd } 310bcd61c0fSStephen Boyd 311bcd61c0fSStephen Boyd static unsigned long 312bcd61c0fSStephen Boyd clk_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) 313bcd61c0fSStephen Boyd { 314bcd61c0fSStephen Boyd struct clk_rcg *rcg = to_clk_rcg(hw); 315bcd61c0fSStephen Boyd u32 pre_div, m = 0, n = 0, ns, md, mode = 0; 316bcd61c0fSStephen Boyd struct mn *mn = &rcg->mn; 317bcd61c0fSStephen Boyd 318bcd61c0fSStephen Boyd regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); 319bcd61c0fSStephen Boyd pre_div = ns_to_pre_div(&rcg->p, ns); 320bcd61c0fSStephen Boyd 321bcd61c0fSStephen Boyd if (rcg->mn.width) { 322bcd61c0fSStephen Boyd regmap_read(rcg->clkr.regmap, rcg->md_reg, &md); 323bcd61c0fSStephen Boyd m = md_to_m(mn, md); 324bcd61c0fSStephen Boyd n = ns_m_to_n(mn, ns, m); 325bcd61c0fSStephen Boyd /* MN counter mode is in hw.enable_reg sometimes */ 326bcd61c0fSStephen Boyd if (rcg->clkr.enable_reg != rcg->ns_reg) 327bcd61c0fSStephen Boyd regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, &mode); 328bcd61c0fSStephen Boyd else 329bcd61c0fSStephen Boyd mode = ns; 330bcd61c0fSStephen Boyd mode = reg_to_mnctr_mode(mn, mode); 331bcd61c0fSStephen Boyd } 332bcd61c0fSStephen Boyd 333bcd61c0fSStephen Boyd return calc_rate(parent_rate, m, n, mode, pre_div); 334bcd61c0fSStephen Boyd } 335bcd61c0fSStephen Boyd 336bcd61c0fSStephen Boyd static unsigned long 337bcd61c0fSStephen Boyd clk_dyn_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) 338bcd61c0fSStephen Boyd { 339bcd61c0fSStephen Boyd struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); 340bcd61c0fSStephen Boyd u32 m, n, pre_div, ns, md, mode, reg; 341bcd61c0fSStephen Boyd int bank; 342bcd61c0fSStephen Boyd struct mn *mn; 343*229fd4a5SStephen Boyd bool banked_p = !!rcg->p[1].pre_div_width; 344bcd61c0fSStephen Boyd bool banked_mn = !!rcg->mn[1].width; 345bcd61c0fSStephen Boyd 346*229fd4a5SStephen Boyd regmap_read(rcg->clkr.regmap, rcg->bank_reg, ®); 347bcd61c0fSStephen Boyd bank = reg_to_bank(rcg, reg); 348bcd61c0fSStephen Boyd 349*229fd4a5SStephen Boyd regmap_read(rcg->clkr.regmap, rcg->ns_reg[bank], &ns); 350*229fd4a5SStephen Boyd m = n = pre_div = mode = 0; 351*229fd4a5SStephen Boyd 352bcd61c0fSStephen Boyd if (banked_mn) { 353bcd61c0fSStephen Boyd mn = &rcg->mn[bank]; 354bcd61c0fSStephen Boyd regmap_read(rcg->clkr.regmap, rcg->md_reg[bank], &md); 355bcd61c0fSStephen Boyd m = md_to_m(mn, md); 356bcd61c0fSStephen Boyd n = ns_m_to_n(mn, ns, m); 357*229fd4a5SStephen Boyd /* Two NS registers means mode control is in NS register */ 358*229fd4a5SStephen Boyd if (rcg->ns_reg[0] != rcg->ns_reg[1]) 359*229fd4a5SStephen Boyd reg = ns; 360bcd61c0fSStephen Boyd mode = reg_to_mnctr_mode(mn, reg); 361bcd61c0fSStephen Boyd } 362*229fd4a5SStephen Boyd 363*229fd4a5SStephen Boyd if (banked_p) 364*229fd4a5SStephen Boyd pre_div = ns_to_pre_div(&rcg->p[bank], ns); 365*229fd4a5SStephen Boyd 366*229fd4a5SStephen Boyd return calc_rate(parent_rate, m, n, mode, pre_div); 367bcd61c0fSStephen Boyd } 368bcd61c0fSStephen Boyd 369bcd61c0fSStephen Boyd static long _freq_tbl_determine_rate(struct clk_hw *hw, 370bcd61c0fSStephen Boyd const struct freq_tbl *f, unsigned long rate, 371bcd61c0fSStephen Boyd unsigned long *p_rate, struct clk **p) 372bcd61c0fSStephen Boyd { 373bcd61c0fSStephen Boyd unsigned long clk_flags; 374bcd61c0fSStephen Boyd 37550c6a503SStephen Boyd f = qcom_find_freq(f, rate); 376bcd61c0fSStephen Boyd if (!f) 377bcd61c0fSStephen Boyd return -EINVAL; 378bcd61c0fSStephen Boyd 379bcd61c0fSStephen Boyd clk_flags = __clk_get_flags(hw->clk); 380bcd61c0fSStephen Boyd *p = clk_get_parent_by_index(hw->clk, f->src); 381bcd61c0fSStephen Boyd if (clk_flags & CLK_SET_RATE_PARENT) { 382bcd61c0fSStephen Boyd rate = rate * f->pre_div; 383bcd61c0fSStephen Boyd if (f->n) { 384bcd61c0fSStephen Boyd u64 tmp = rate; 385bcd61c0fSStephen Boyd tmp = tmp * f->n; 386bcd61c0fSStephen Boyd do_div(tmp, f->m); 387bcd61c0fSStephen Boyd rate = tmp; 388bcd61c0fSStephen Boyd } 389bcd61c0fSStephen Boyd } else { 390bcd61c0fSStephen Boyd rate = __clk_get_rate(*p); 391bcd61c0fSStephen Boyd } 392bcd61c0fSStephen Boyd *p_rate = rate; 393bcd61c0fSStephen Boyd 394bcd61c0fSStephen Boyd return f->freq; 395bcd61c0fSStephen Boyd } 396bcd61c0fSStephen Boyd 397bcd61c0fSStephen Boyd static long clk_rcg_determine_rate(struct clk_hw *hw, unsigned long rate, 398bcd61c0fSStephen Boyd unsigned long *p_rate, struct clk **p) 399bcd61c0fSStephen Boyd { 400bcd61c0fSStephen Boyd struct clk_rcg *rcg = to_clk_rcg(hw); 401bcd61c0fSStephen Boyd 402bcd61c0fSStephen Boyd return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p); 403bcd61c0fSStephen Boyd } 404bcd61c0fSStephen Boyd 405bcd61c0fSStephen Boyd static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate, 406bcd61c0fSStephen Boyd unsigned long *p_rate, struct clk **p) 407bcd61c0fSStephen Boyd { 408bcd61c0fSStephen Boyd struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); 409bcd61c0fSStephen Boyd 410bcd61c0fSStephen Boyd return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p); 411bcd61c0fSStephen Boyd } 412bcd61c0fSStephen Boyd 413404c1ff6SStephen Boyd static long clk_rcg_bypass_determine_rate(struct clk_hw *hw, unsigned long rate, 414404c1ff6SStephen Boyd unsigned long *p_rate, struct clk **p) 415bcd61c0fSStephen Boyd { 416bcd61c0fSStephen Boyd struct clk_rcg *rcg = to_clk_rcg(hw); 417404c1ff6SStephen Boyd const struct freq_tbl *f = rcg->freq_tbl; 418404c1ff6SStephen Boyd 419404c1ff6SStephen Boyd *p = clk_get_parent_by_index(hw->clk, f->src); 420404c1ff6SStephen Boyd *p_rate = __clk_round_rate(*p, rate); 421404c1ff6SStephen Boyd 422404c1ff6SStephen Boyd return *p_rate; 423404c1ff6SStephen Boyd } 424404c1ff6SStephen Boyd 425404c1ff6SStephen Boyd static int __clk_rcg_set_rate(struct clk_rcg *rcg, const struct freq_tbl *f) 426404c1ff6SStephen Boyd { 427bcd61c0fSStephen Boyd u32 ns, md, ctl; 428bcd61c0fSStephen Boyd struct mn *mn = &rcg->mn; 429bcd61c0fSStephen Boyd u32 mask = 0; 430bcd61c0fSStephen Boyd unsigned int reset_reg; 431bcd61c0fSStephen Boyd 432bcd61c0fSStephen Boyd if (rcg->mn.reset_in_cc) 433bcd61c0fSStephen Boyd reset_reg = rcg->clkr.enable_reg; 434bcd61c0fSStephen Boyd else 435bcd61c0fSStephen Boyd reset_reg = rcg->ns_reg; 436bcd61c0fSStephen Boyd 437bcd61c0fSStephen Boyd if (rcg->mn.width) { 438bcd61c0fSStephen Boyd mask = BIT(mn->mnctr_reset_bit); 439bcd61c0fSStephen Boyd regmap_update_bits(rcg->clkr.regmap, reset_reg, mask, mask); 440bcd61c0fSStephen Boyd 441bcd61c0fSStephen Boyd regmap_read(rcg->clkr.regmap, rcg->md_reg, &md); 442bcd61c0fSStephen Boyd md = mn_to_md(mn, f->m, f->n, md); 443bcd61c0fSStephen Boyd regmap_write(rcg->clkr.regmap, rcg->md_reg, md); 444bcd61c0fSStephen Boyd 445bcd61c0fSStephen Boyd regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); 446bcd61c0fSStephen Boyd /* MN counter mode is in hw.enable_reg sometimes */ 447bcd61c0fSStephen Boyd if (rcg->clkr.enable_reg != rcg->ns_reg) { 448bcd61c0fSStephen Boyd regmap_read(rcg->clkr.regmap, rcg->clkr.enable_reg, &ctl); 449bcd61c0fSStephen Boyd ctl = mn_to_reg(mn, f->m, f->n, ctl); 450bcd61c0fSStephen Boyd regmap_write(rcg->clkr.regmap, rcg->clkr.enable_reg, ctl); 451bcd61c0fSStephen Boyd } else { 452bcd61c0fSStephen Boyd ns = mn_to_reg(mn, f->m, f->n, ns); 453bcd61c0fSStephen Boyd } 454bcd61c0fSStephen Boyd ns = mn_to_ns(mn, f->m, f->n, ns); 455bcd61c0fSStephen Boyd } else { 456bcd61c0fSStephen Boyd regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); 457bcd61c0fSStephen Boyd } 458bcd61c0fSStephen Boyd 459bcd61c0fSStephen Boyd ns = pre_div_to_ns(&rcg->p, f->pre_div - 1, ns); 460bcd61c0fSStephen Boyd regmap_write(rcg->clkr.regmap, rcg->ns_reg, ns); 461bcd61c0fSStephen Boyd 462bcd61c0fSStephen Boyd regmap_update_bits(rcg->clkr.regmap, reset_reg, mask, 0); 463bcd61c0fSStephen Boyd 464bcd61c0fSStephen Boyd return 0; 465bcd61c0fSStephen Boyd } 466bcd61c0fSStephen Boyd 467404c1ff6SStephen Boyd static int clk_rcg_set_rate(struct clk_hw *hw, unsigned long rate, 468404c1ff6SStephen Boyd unsigned long parent_rate) 469404c1ff6SStephen Boyd { 470404c1ff6SStephen Boyd struct clk_rcg *rcg = to_clk_rcg(hw); 471404c1ff6SStephen Boyd const struct freq_tbl *f; 472404c1ff6SStephen Boyd 47350c6a503SStephen Boyd f = qcom_find_freq(rcg->freq_tbl, rate); 474404c1ff6SStephen Boyd if (!f) 475404c1ff6SStephen Boyd return -EINVAL; 476404c1ff6SStephen Boyd 477404c1ff6SStephen Boyd return __clk_rcg_set_rate(rcg, f); 478404c1ff6SStephen Boyd } 479404c1ff6SStephen Boyd 480404c1ff6SStephen Boyd static int clk_rcg_bypass_set_rate(struct clk_hw *hw, unsigned long rate, 481404c1ff6SStephen Boyd unsigned long parent_rate) 482404c1ff6SStephen Boyd { 483404c1ff6SStephen Boyd struct clk_rcg *rcg = to_clk_rcg(hw); 484404c1ff6SStephen Boyd 485404c1ff6SStephen Boyd return __clk_rcg_set_rate(rcg, rcg->freq_tbl); 486404c1ff6SStephen Boyd } 487404c1ff6SStephen Boyd 488bcd61c0fSStephen Boyd static int __clk_dyn_rcg_set_rate(struct clk_hw *hw, unsigned long rate) 489bcd61c0fSStephen Boyd { 490bcd61c0fSStephen Boyd struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); 491bcd61c0fSStephen Boyd const struct freq_tbl *f; 492bcd61c0fSStephen Boyd 49350c6a503SStephen Boyd f = qcom_find_freq(rcg->freq_tbl, rate); 494bcd61c0fSStephen Boyd if (!f) 495bcd61c0fSStephen Boyd return -EINVAL; 496bcd61c0fSStephen Boyd 497bcd61c0fSStephen Boyd configure_bank(rcg, f); 498bcd61c0fSStephen Boyd 499bcd61c0fSStephen Boyd return 0; 500bcd61c0fSStephen Boyd } 501bcd61c0fSStephen Boyd 502bcd61c0fSStephen Boyd static int clk_dyn_rcg_set_rate(struct clk_hw *hw, unsigned long rate, 503bcd61c0fSStephen Boyd unsigned long parent_rate) 504bcd61c0fSStephen Boyd { 505bcd61c0fSStephen Boyd return __clk_dyn_rcg_set_rate(hw, rate); 506bcd61c0fSStephen Boyd } 507bcd61c0fSStephen Boyd 508bcd61c0fSStephen Boyd static int clk_dyn_rcg_set_rate_and_parent(struct clk_hw *hw, 509bcd61c0fSStephen Boyd unsigned long rate, unsigned long parent_rate, u8 index) 510bcd61c0fSStephen Boyd { 511bcd61c0fSStephen Boyd return __clk_dyn_rcg_set_rate(hw, rate); 512bcd61c0fSStephen Boyd } 513bcd61c0fSStephen Boyd 514bcd61c0fSStephen Boyd const struct clk_ops clk_rcg_ops = { 515bcd61c0fSStephen Boyd .enable = clk_enable_regmap, 516bcd61c0fSStephen Boyd .disable = clk_disable_regmap, 517bcd61c0fSStephen Boyd .get_parent = clk_rcg_get_parent, 518bcd61c0fSStephen Boyd .set_parent = clk_rcg_set_parent, 519bcd61c0fSStephen Boyd .recalc_rate = clk_rcg_recalc_rate, 520bcd61c0fSStephen Boyd .determine_rate = clk_rcg_determine_rate, 521bcd61c0fSStephen Boyd .set_rate = clk_rcg_set_rate, 522bcd61c0fSStephen Boyd }; 523bcd61c0fSStephen Boyd EXPORT_SYMBOL_GPL(clk_rcg_ops); 524bcd61c0fSStephen Boyd 525404c1ff6SStephen Boyd const struct clk_ops clk_rcg_bypass_ops = { 526404c1ff6SStephen Boyd .enable = clk_enable_regmap, 527404c1ff6SStephen Boyd .disable = clk_disable_regmap, 528404c1ff6SStephen Boyd .get_parent = clk_rcg_get_parent, 529404c1ff6SStephen Boyd .set_parent = clk_rcg_set_parent, 530404c1ff6SStephen Boyd .recalc_rate = clk_rcg_recalc_rate, 531404c1ff6SStephen Boyd .determine_rate = clk_rcg_bypass_determine_rate, 532404c1ff6SStephen Boyd .set_rate = clk_rcg_bypass_set_rate, 533404c1ff6SStephen Boyd }; 534404c1ff6SStephen Boyd EXPORT_SYMBOL_GPL(clk_rcg_bypass_ops); 535404c1ff6SStephen Boyd 536bcd61c0fSStephen Boyd const struct clk_ops clk_dyn_rcg_ops = { 537bcd61c0fSStephen Boyd .enable = clk_enable_regmap, 538bcd61c0fSStephen Boyd .is_enabled = clk_is_enabled_regmap, 539bcd61c0fSStephen Boyd .disable = clk_disable_regmap, 540bcd61c0fSStephen Boyd .get_parent = clk_dyn_rcg_get_parent, 541bcd61c0fSStephen Boyd .set_parent = clk_dyn_rcg_set_parent, 542bcd61c0fSStephen Boyd .recalc_rate = clk_dyn_rcg_recalc_rate, 543bcd61c0fSStephen Boyd .determine_rate = clk_dyn_rcg_determine_rate, 544bcd61c0fSStephen Boyd .set_rate = clk_dyn_rcg_set_rate, 545bcd61c0fSStephen Boyd .set_rate_and_parent = clk_dyn_rcg_set_rate_and_parent, 546bcd61c0fSStephen Boyd }; 547bcd61c0fSStephen Boyd EXPORT_SYMBOL_GPL(clk_dyn_rcg_ops); 548