1*3bb16560SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2270b9f42SViresh Kumar /*
3270b9f42SViresh Kumar * Copyright (C) 2012 ST Microelectronics
4da89947bSViresh Kumar * Viresh Kumar <vireshk@kernel.org>
5270b9f42SViresh Kumar *
6270b9f42SViresh Kumar * Fractional Synthesizer clock implementation
7270b9f42SViresh Kumar */
8270b9f42SViresh Kumar
9270b9f42SViresh Kumar #define pr_fmt(fmt) "clk-frac-synth: " fmt
10270b9f42SViresh Kumar
11270b9f42SViresh Kumar #include <linux/clk-provider.h>
12270b9f42SViresh Kumar #include <linux/slab.h>
13270b9f42SViresh Kumar #include <linux/io.h>
14270b9f42SViresh Kumar #include <linux/err.h>
15270b9f42SViresh Kumar #include "clk.h"
16270b9f42SViresh Kumar
17270b9f42SViresh Kumar #define DIV_FACTOR_MASK 0x1FFFF
18270b9f42SViresh Kumar
19270b9f42SViresh Kumar /*
20270b9f42SViresh Kumar * DOC: Fractional Synthesizer clock
21270b9f42SViresh Kumar *
22270b9f42SViresh Kumar * Fout from synthesizer can be given from below equation:
23270b9f42SViresh Kumar *
24270b9f42SViresh Kumar * Fout= Fin/2*div (division factor)
25270b9f42SViresh Kumar * div is 17 bits:-
26270b9f42SViresh Kumar * 0-13 (fractional part)
27270b9f42SViresh Kumar * 14-16 (integer part)
28270b9f42SViresh Kumar * div is (16-14 bits).(13-0 bits) (in binary)
29270b9f42SViresh Kumar *
30270b9f42SViresh Kumar * Fout = Fin/(2 * div)
31270b9f42SViresh Kumar * Fout = ((Fin / 10000)/(2 * div)) * 10000
32270b9f42SViresh Kumar * Fout = (2^14 * (Fin / 10000)/(2^14 * (2 * div))) * 10000
33270b9f42SViresh Kumar * Fout = (((Fin / 10000) << 14)/(2 * (div << 14))) * 10000
34270b9f42SViresh Kumar *
35270b9f42SViresh Kumar * div << 14 simply 17 bit value written at register.
36270b9f42SViresh Kumar * Max error due to scaling down by 10000 is 10 KHz
37270b9f42SViresh Kumar */
38270b9f42SViresh Kumar
39270b9f42SViresh Kumar #define to_clk_frac(_hw) container_of(_hw, struct clk_frac, hw)
40270b9f42SViresh Kumar
frac_calc_rate(struct clk_hw * hw,unsigned long prate,int index)41270b9f42SViresh Kumar static unsigned long frac_calc_rate(struct clk_hw *hw, unsigned long prate,
42270b9f42SViresh Kumar int index)
43270b9f42SViresh Kumar {
44270b9f42SViresh Kumar struct clk_frac *frac = to_clk_frac(hw);
45270b9f42SViresh Kumar struct frac_rate_tbl *rtbl = frac->rtbl;
46270b9f42SViresh Kumar
47270b9f42SViresh Kumar prate /= 10000;
48270b9f42SViresh Kumar prate <<= 14;
49270b9f42SViresh Kumar prate /= (2 * rtbl[index].div);
50270b9f42SViresh Kumar prate *= 10000;
51270b9f42SViresh Kumar
52270b9f42SViresh Kumar return prate;
53270b9f42SViresh Kumar }
54270b9f42SViresh Kumar
clk_frac_round_rate(struct clk_hw * hw,unsigned long drate,unsigned long * prate)55270b9f42SViresh Kumar static long clk_frac_round_rate(struct clk_hw *hw, unsigned long drate,
56270b9f42SViresh Kumar unsigned long *prate)
57270b9f42SViresh Kumar {
58270b9f42SViresh Kumar struct clk_frac *frac = to_clk_frac(hw);
59270b9f42SViresh Kumar int unused;
60270b9f42SViresh Kumar
61270b9f42SViresh Kumar return clk_round_rate_index(hw, drate, *prate, frac_calc_rate,
62270b9f42SViresh Kumar frac->rtbl_cnt, &unused);
63270b9f42SViresh Kumar }
64270b9f42SViresh Kumar
clk_frac_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)65270b9f42SViresh Kumar static unsigned long clk_frac_recalc_rate(struct clk_hw *hw,
66270b9f42SViresh Kumar unsigned long parent_rate)
67270b9f42SViresh Kumar {
68270b9f42SViresh Kumar struct clk_frac *frac = to_clk_frac(hw);
69270b9f42SViresh Kumar unsigned long flags = 0;
70270b9f42SViresh Kumar unsigned int div = 1, val;
71270b9f42SViresh Kumar
72270b9f42SViresh Kumar if (frac->lock)
73270b9f42SViresh Kumar spin_lock_irqsave(frac->lock, flags);
74270b9f42SViresh Kumar
75270b9f42SViresh Kumar val = readl_relaxed(frac->reg);
76270b9f42SViresh Kumar
77270b9f42SViresh Kumar if (frac->lock)
78270b9f42SViresh Kumar spin_unlock_irqrestore(frac->lock, flags);
79270b9f42SViresh Kumar
80270b9f42SViresh Kumar div = val & DIV_FACTOR_MASK;
81270b9f42SViresh Kumar
82270b9f42SViresh Kumar if (!div)
83270b9f42SViresh Kumar return 0;
84270b9f42SViresh Kumar
85270b9f42SViresh Kumar parent_rate = parent_rate / 10000;
86270b9f42SViresh Kumar
87270b9f42SViresh Kumar parent_rate = (parent_rate << 14) / (2 * div);
88270b9f42SViresh Kumar return parent_rate * 10000;
89270b9f42SViresh Kumar }
90270b9f42SViresh Kumar
91270b9f42SViresh Kumar /* Configures new clock rate of frac */
clk_frac_set_rate(struct clk_hw * hw,unsigned long drate,unsigned long prate)92270b9f42SViresh Kumar static int clk_frac_set_rate(struct clk_hw *hw, unsigned long drate,
93270b9f42SViresh Kumar unsigned long prate)
94270b9f42SViresh Kumar {
95270b9f42SViresh Kumar struct clk_frac *frac = to_clk_frac(hw);
96270b9f42SViresh Kumar struct frac_rate_tbl *rtbl = frac->rtbl;
97270b9f42SViresh Kumar unsigned long flags = 0, val;
98270b9f42SViresh Kumar int i;
99270b9f42SViresh Kumar
100270b9f42SViresh Kumar clk_round_rate_index(hw, drate, prate, frac_calc_rate, frac->rtbl_cnt,
101270b9f42SViresh Kumar &i);
102270b9f42SViresh Kumar
103270b9f42SViresh Kumar if (frac->lock)
104270b9f42SViresh Kumar spin_lock_irqsave(frac->lock, flags);
105270b9f42SViresh Kumar
106270b9f42SViresh Kumar val = readl_relaxed(frac->reg) & ~DIV_FACTOR_MASK;
107270b9f42SViresh Kumar val |= rtbl[i].div & DIV_FACTOR_MASK;
108270b9f42SViresh Kumar writel_relaxed(val, frac->reg);
109270b9f42SViresh Kumar
110270b9f42SViresh Kumar if (frac->lock)
111270b9f42SViresh Kumar spin_unlock_irqrestore(frac->lock, flags);
112270b9f42SViresh Kumar
113270b9f42SViresh Kumar return 0;
114270b9f42SViresh Kumar }
115270b9f42SViresh Kumar
116ba3892dfSBhumika Goyal static const struct clk_ops clk_frac_ops = {
117270b9f42SViresh Kumar .recalc_rate = clk_frac_recalc_rate,
118270b9f42SViresh Kumar .round_rate = clk_frac_round_rate,
119270b9f42SViresh Kumar .set_rate = clk_frac_set_rate,
120270b9f42SViresh Kumar };
121270b9f42SViresh Kumar
clk_register_frac(const char * name,const char * parent_name,unsigned long flags,void __iomem * reg,struct frac_rate_tbl * rtbl,u8 rtbl_cnt,spinlock_t * lock)122270b9f42SViresh Kumar struct clk *clk_register_frac(const char *name, const char *parent_name,
123270b9f42SViresh Kumar unsigned long flags, void __iomem *reg,
124270b9f42SViresh Kumar struct frac_rate_tbl *rtbl, u8 rtbl_cnt, spinlock_t *lock)
125270b9f42SViresh Kumar {
126270b9f42SViresh Kumar struct clk_init_data init;
127270b9f42SViresh Kumar struct clk_frac *frac;
128270b9f42SViresh Kumar struct clk *clk;
129270b9f42SViresh Kumar
130270b9f42SViresh Kumar if (!name || !parent_name || !reg || !rtbl || !rtbl_cnt) {
131811284b0SArvind Yadav pr_err("Invalid arguments passed\n");
132270b9f42SViresh Kumar return ERR_PTR(-EINVAL);
133270b9f42SViresh Kumar }
134270b9f42SViresh Kumar
135270b9f42SViresh Kumar frac = kzalloc(sizeof(*frac), GFP_KERNEL);
13663b1a5d7SMarkus Elfring if (!frac)
137270b9f42SViresh Kumar return ERR_PTR(-ENOMEM);
138270b9f42SViresh Kumar
139270b9f42SViresh Kumar /* struct clk_frac assignments */
140270b9f42SViresh Kumar frac->reg = reg;
141270b9f42SViresh Kumar frac->rtbl = rtbl;
142270b9f42SViresh Kumar frac->rtbl_cnt = rtbl_cnt;
143270b9f42SViresh Kumar frac->lock = lock;
144270b9f42SViresh Kumar frac->hw.init = &init;
145270b9f42SViresh Kumar
146270b9f42SViresh Kumar init.name = name;
147270b9f42SViresh Kumar init.ops = &clk_frac_ops;
148270b9f42SViresh Kumar init.flags = flags;
149270b9f42SViresh Kumar init.parent_names = &parent_name;
150270b9f42SViresh Kumar init.num_parents = 1;
151270b9f42SViresh Kumar
152270b9f42SViresh Kumar clk = clk_register(NULL, &frac->hw);
153270b9f42SViresh Kumar if (!IS_ERR_OR_NULL(clk))
154270b9f42SViresh Kumar return clk;
155270b9f42SViresh Kumar
156270b9f42SViresh Kumar pr_err("clk register failed\n");
157270b9f42SViresh Kumar kfree(frac);
158270b9f42SViresh Kumar
159270b9f42SViresh Kumar return NULL;
160270b9f42SViresh Kumar }
161