1*3bb16560SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 25335a639SViresh Kumar /* 35335a639SViresh Kumar * Copyright (C) 2012 ST Microelectronics 4da89947bSViresh Kumar * Viresh Kumar <vireshk@kernel.org> 55335a639SViresh Kumar * 65335a639SViresh Kumar * Auxiliary Synthesizer clock implementation 75335a639SViresh Kumar */ 85335a639SViresh Kumar 95335a639SViresh Kumar #define pr_fmt(fmt) "clk-aux-synth: " fmt 105335a639SViresh Kumar 115335a639SViresh Kumar #include <linux/clk-provider.h> 125335a639SViresh Kumar #include <linux/slab.h> 135335a639SViresh Kumar #include <linux/io.h> 145335a639SViresh Kumar #include <linux/err.h> 155335a639SViresh Kumar #include "clk.h" 165335a639SViresh Kumar 175335a639SViresh Kumar /* 185335a639SViresh Kumar * DOC: Auxiliary Synthesizer clock 195335a639SViresh Kumar * 205335a639SViresh Kumar * Aux synth gives rate for different values of eq, x and y 215335a639SViresh Kumar * 225335a639SViresh Kumar * Fout from synthesizer can be given from two equations: 235335a639SViresh Kumar * Fout1 = (Fin * X/Y)/2 EQ1 245335a639SViresh Kumar * Fout2 = Fin * X/Y EQ2 255335a639SViresh Kumar */ 265335a639SViresh Kumar 275335a639SViresh Kumar #define to_clk_aux(_hw) container_of(_hw, struct clk_aux, hw) 285335a639SViresh Kumar 2937d2f45dSBhumika Goyal static const struct aux_clk_masks default_aux_masks = { 305335a639SViresh Kumar .eq_sel_mask = AUX_EQ_SEL_MASK, 315335a639SViresh Kumar .eq_sel_shift = AUX_EQ_SEL_SHIFT, 325335a639SViresh Kumar .eq1_mask = AUX_EQ1_SEL, 335335a639SViresh Kumar .eq2_mask = AUX_EQ2_SEL, 345335a639SViresh Kumar .xscale_sel_mask = AUX_XSCALE_MASK, 355335a639SViresh Kumar .xscale_sel_shift = AUX_XSCALE_SHIFT, 365335a639SViresh Kumar .yscale_sel_mask = AUX_YSCALE_MASK, 375335a639SViresh Kumar .yscale_sel_shift = AUX_YSCALE_SHIFT, 385335a639SViresh Kumar .enable_bit = AUX_SYNT_ENB, 395335a639SViresh Kumar }; 405335a639SViresh Kumar 415335a639SViresh Kumar static unsigned long aux_calc_rate(struct clk_hw *hw, unsigned long prate, 425335a639SViresh Kumar int index) 435335a639SViresh Kumar { 445335a639SViresh Kumar struct clk_aux *aux = to_clk_aux(hw); 455335a639SViresh Kumar struct aux_rate_tbl *rtbl = aux->rtbl; 465335a639SViresh Kumar u8 eq = rtbl[index].eq ? 1 : 2; 475335a639SViresh Kumar 485335a639SViresh Kumar return (((prate / 10000) * rtbl[index].xscale) / 495335a639SViresh Kumar (rtbl[index].yscale * eq)) * 10000; 505335a639SViresh Kumar } 515335a639SViresh Kumar 525335a639SViresh Kumar static long clk_aux_round_rate(struct clk_hw *hw, unsigned long drate, 535335a639SViresh Kumar unsigned long *prate) 545335a639SViresh Kumar { 555335a639SViresh Kumar struct clk_aux *aux = to_clk_aux(hw); 565335a639SViresh Kumar int unused; 575335a639SViresh Kumar 585335a639SViresh Kumar return clk_round_rate_index(hw, drate, *prate, aux_calc_rate, 595335a639SViresh Kumar aux->rtbl_cnt, &unused); 605335a639SViresh Kumar } 615335a639SViresh Kumar 625335a639SViresh Kumar static unsigned long clk_aux_recalc_rate(struct clk_hw *hw, 635335a639SViresh Kumar unsigned long parent_rate) 645335a639SViresh Kumar { 655335a639SViresh Kumar struct clk_aux *aux = to_clk_aux(hw); 665335a639SViresh Kumar unsigned int num = 1, den = 1, val, eqn; 675335a639SViresh Kumar unsigned long flags = 0; 685335a639SViresh Kumar 695335a639SViresh Kumar if (aux->lock) 705335a639SViresh Kumar spin_lock_irqsave(aux->lock, flags); 715335a639SViresh Kumar 725335a639SViresh Kumar val = readl_relaxed(aux->reg); 735335a639SViresh Kumar 745335a639SViresh Kumar if (aux->lock) 755335a639SViresh Kumar spin_unlock_irqrestore(aux->lock, flags); 765335a639SViresh Kumar 775335a639SViresh Kumar eqn = (val >> aux->masks->eq_sel_shift) & aux->masks->eq_sel_mask; 785335a639SViresh Kumar if (eqn == aux->masks->eq1_mask) 795335a639SViresh Kumar den = 2; 805335a639SViresh Kumar 815335a639SViresh Kumar /* calculate numerator */ 825335a639SViresh Kumar num = (val >> aux->masks->xscale_sel_shift) & 835335a639SViresh Kumar aux->masks->xscale_sel_mask; 845335a639SViresh Kumar 855335a639SViresh Kumar /* calculate denominator */ 865335a639SViresh Kumar den *= (val >> aux->masks->yscale_sel_shift) & 875335a639SViresh Kumar aux->masks->yscale_sel_mask; 885335a639SViresh Kumar 895335a639SViresh Kumar if (!den) 905335a639SViresh Kumar return 0; 915335a639SViresh Kumar 925335a639SViresh Kumar return (((parent_rate / 10000) * num) / den) * 10000; 935335a639SViresh Kumar } 945335a639SViresh Kumar 955335a639SViresh Kumar /* Configures new clock rate of aux */ 965335a639SViresh Kumar static int clk_aux_set_rate(struct clk_hw *hw, unsigned long drate, 975335a639SViresh Kumar unsigned long prate) 985335a639SViresh Kumar { 995335a639SViresh Kumar struct clk_aux *aux = to_clk_aux(hw); 1005335a639SViresh Kumar struct aux_rate_tbl *rtbl = aux->rtbl; 1015335a639SViresh Kumar unsigned long val, flags = 0; 1025335a639SViresh Kumar int i; 1035335a639SViresh Kumar 1045335a639SViresh Kumar clk_round_rate_index(hw, drate, prate, aux_calc_rate, aux->rtbl_cnt, 1055335a639SViresh Kumar &i); 1065335a639SViresh Kumar 1075335a639SViresh Kumar if (aux->lock) 1085335a639SViresh Kumar spin_lock_irqsave(aux->lock, flags); 1095335a639SViresh Kumar 1105335a639SViresh Kumar val = readl_relaxed(aux->reg) & 1115335a639SViresh Kumar ~(aux->masks->eq_sel_mask << aux->masks->eq_sel_shift); 1125335a639SViresh Kumar val |= (rtbl[i].eq & aux->masks->eq_sel_mask) << 1135335a639SViresh Kumar aux->masks->eq_sel_shift; 1145335a639SViresh Kumar val &= ~(aux->masks->xscale_sel_mask << aux->masks->xscale_sel_shift); 1155335a639SViresh Kumar val |= (rtbl[i].xscale & aux->masks->xscale_sel_mask) << 1165335a639SViresh Kumar aux->masks->xscale_sel_shift; 1175335a639SViresh Kumar val &= ~(aux->masks->yscale_sel_mask << aux->masks->yscale_sel_shift); 1185335a639SViresh Kumar val |= (rtbl[i].yscale & aux->masks->yscale_sel_mask) << 1195335a639SViresh Kumar aux->masks->yscale_sel_shift; 1205335a639SViresh Kumar writel_relaxed(val, aux->reg); 1215335a639SViresh Kumar 1225335a639SViresh Kumar if (aux->lock) 1235335a639SViresh Kumar spin_unlock_irqrestore(aux->lock, flags); 1245335a639SViresh Kumar 1255335a639SViresh Kumar return 0; 1265335a639SViresh Kumar } 1275335a639SViresh Kumar 128ba3892dfSBhumika Goyal static const struct clk_ops clk_aux_ops = { 1295335a639SViresh Kumar .recalc_rate = clk_aux_recalc_rate, 1305335a639SViresh Kumar .round_rate = clk_aux_round_rate, 1315335a639SViresh Kumar .set_rate = clk_aux_set_rate, 1325335a639SViresh Kumar }; 1335335a639SViresh Kumar 1345335a639SViresh Kumar struct clk *clk_register_aux(const char *aux_name, const char *gate_name, 1355335a639SViresh Kumar const char *parent_name, unsigned long flags, void __iomem *reg, 13671bf5ab8SBhumika Goyal const struct aux_clk_masks *masks, struct aux_rate_tbl *rtbl, 1375335a639SViresh Kumar u8 rtbl_cnt, spinlock_t *lock, struct clk **gate_clk) 1385335a639SViresh Kumar { 1395335a639SViresh Kumar struct clk_aux *aux; 1405335a639SViresh Kumar struct clk_init_data init; 1415335a639SViresh Kumar struct clk *clk; 1425335a639SViresh Kumar 1435335a639SViresh Kumar if (!aux_name || !parent_name || !reg || !rtbl || !rtbl_cnt) { 1445335a639SViresh Kumar pr_err("Invalid arguments passed"); 1455335a639SViresh Kumar return ERR_PTR(-EINVAL); 1465335a639SViresh Kumar } 1475335a639SViresh Kumar 1485335a639SViresh Kumar aux = kzalloc(sizeof(*aux), GFP_KERNEL); 14963b1a5d7SMarkus Elfring if (!aux) 1505335a639SViresh Kumar return ERR_PTR(-ENOMEM); 1515335a639SViresh Kumar 1525335a639SViresh Kumar /* struct clk_aux assignments */ 1535335a639SViresh Kumar if (!masks) 1545335a639SViresh Kumar aux->masks = &default_aux_masks; 1555335a639SViresh Kumar else 1565335a639SViresh Kumar aux->masks = masks; 1575335a639SViresh Kumar 1585335a639SViresh Kumar aux->reg = reg; 1595335a639SViresh Kumar aux->rtbl = rtbl; 1605335a639SViresh Kumar aux->rtbl_cnt = rtbl_cnt; 1615335a639SViresh Kumar aux->lock = lock; 1625335a639SViresh Kumar aux->hw.init = &init; 1635335a639SViresh Kumar 1645335a639SViresh Kumar init.name = aux_name; 1655335a639SViresh Kumar init.ops = &clk_aux_ops; 1665335a639SViresh Kumar init.flags = flags; 1675335a639SViresh Kumar init.parent_names = &parent_name; 1685335a639SViresh Kumar init.num_parents = 1; 1695335a639SViresh Kumar 1705335a639SViresh Kumar clk = clk_register(NULL, &aux->hw); 1715335a639SViresh Kumar if (IS_ERR_OR_NULL(clk)) 1725335a639SViresh Kumar goto free_aux; 1735335a639SViresh Kumar 1745335a639SViresh Kumar if (gate_name) { 1755335a639SViresh Kumar struct clk *tgate_clk; 1765335a639SViresh Kumar 17712499792SVipul Kumar Samar tgate_clk = clk_register_gate(NULL, gate_name, aux_name, 17812499792SVipul Kumar Samar CLK_SET_RATE_PARENT, reg, 1795335a639SViresh Kumar aux->masks->enable_bit, 0, lock); 1805335a639SViresh Kumar if (IS_ERR_OR_NULL(tgate_clk)) 1815335a639SViresh Kumar goto free_aux; 1825335a639SViresh Kumar 1835335a639SViresh Kumar if (gate_clk) 1845335a639SViresh Kumar *gate_clk = tgate_clk; 1855335a639SViresh Kumar } 1865335a639SViresh Kumar 1875335a639SViresh Kumar return clk; 1885335a639SViresh Kumar 1895335a639SViresh Kumar free_aux: 1905335a639SViresh Kumar kfree(aux); 1915335a639SViresh Kumar pr_err("clk register failed\n"); 1925335a639SViresh Kumar 1935335a639SViresh Kumar return NULL; 1945335a639SViresh Kumar } 195