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