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