xref: /openbmc/linux/drivers/clk/qcom/clk-hfpll.c (revision aa74c44b)
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2018, The Linux Foundation. All rights reserved.
3 
4 #include <linux/kernel.h>
5 #include <linux/export.h>
6 #include <linux/regmap.h>
7 #include <linux/delay.h>
8 #include <linux/err.h>
9 #include <linux/clk-provider.h>
10 #include <linux/spinlock.h>
11 
12 #include "clk-regmap.h"
13 #include "clk-hfpll.h"
14 
15 #define PLL_OUTCTRL	BIT(0)
16 #define PLL_BYPASSNL	BIT(1)
17 #define PLL_RESET_N	BIT(2)
18 
19 /* Initialize a HFPLL at a given rate and enable it. */
20 static void __clk_hfpll_init_once(struct clk_hw *hw)
21 {
22 	struct clk_hfpll *h = to_clk_hfpll(hw);
23 	struct hfpll_data const *hd = h->d;
24 	struct regmap *regmap = h->clkr.regmap;
25 
26 	if (likely(h->init_done))
27 		return;
28 
29 	/* Configure PLL parameters for integer mode. */
30 	if (hd->config_val)
31 		regmap_write(regmap, hd->config_reg, hd->config_val);
32 	regmap_write(regmap, hd->m_reg, 0);
33 	regmap_write(regmap, hd->n_reg, 1);
34 
35 	if (hd->user_reg) {
36 		u32 regval = hd->user_val;
37 		unsigned long rate;
38 
39 		rate = clk_hw_get_rate(hw);
40 
41 		/* Pick the right VCO. */
42 		if (hd->user_vco_mask && rate > hd->low_vco_max_rate)
43 			regval |= hd->user_vco_mask;
44 		regmap_write(regmap, hd->user_reg, regval);
45 	}
46 
47 	if (hd->droop_reg)
48 		regmap_write(regmap, hd->droop_reg, hd->droop_val);
49 
50 	h->init_done = true;
51 }
52 
53 static void __clk_hfpll_enable(struct clk_hw *hw)
54 {
55 	struct clk_hfpll *h = to_clk_hfpll(hw);
56 	struct hfpll_data const *hd = h->d;
57 	struct regmap *regmap = h->clkr.regmap;
58 	u32 val;
59 
60 	__clk_hfpll_init_once(hw);
61 
62 	/* Disable PLL bypass mode. */
63 	regmap_update_bits(regmap, hd->mode_reg, PLL_BYPASSNL, PLL_BYPASSNL);
64 
65 	/*
66 	 * H/W requires a 5us delay between disabling the bypass and
67 	 * de-asserting the reset. Delay 10us just to be safe.
68 	 */
69 	udelay(10);
70 
71 	/* De-assert active-low PLL reset. */
72 	regmap_update_bits(regmap, hd->mode_reg, PLL_RESET_N, PLL_RESET_N);
73 
74 	/* Wait for PLL to lock. */
75 	if (hd->status_reg) {
76 		do {
77 			regmap_read(regmap, hd->status_reg, &val);
78 		} while (!(val & BIT(hd->lock_bit)));
79 	} else {
80 		udelay(60);
81 	}
82 
83 	/* Enable PLL output. */
84 	regmap_update_bits(regmap, hd->mode_reg, PLL_OUTCTRL, PLL_OUTCTRL);
85 }
86 
87 /* Enable an already-configured HFPLL. */
88 static int clk_hfpll_enable(struct clk_hw *hw)
89 {
90 	unsigned long flags;
91 	struct clk_hfpll *h = to_clk_hfpll(hw);
92 	struct hfpll_data const *hd = h->d;
93 	struct regmap *regmap = h->clkr.regmap;
94 	u32 mode;
95 
96 	spin_lock_irqsave(&h->lock, flags);
97 	regmap_read(regmap, hd->mode_reg, &mode);
98 	if (!(mode & (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL)))
99 		__clk_hfpll_enable(hw);
100 	spin_unlock_irqrestore(&h->lock, flags);
101 
102 	return 0;
103 }
104 
105 static void __clk_hfpll_disable(struct clk_hfpll *h)
106 {
107 	struct hfpll_data const *hd = h->d;
108 	struct regmap *regmap = h->clkr.regmap;
109 
110 	/*
111 	 * Disable the PLL output, disable test mode, enable the bypass mode,
112 	 * and assert the reset.
113 	 */
114 	regmap_update_bits(regmap, hd->mode_reg,
115 			   PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL, 0);
116 }
117 
118 static void clk_hfpll_disable(struct clk_hw *hw)
119 {
120 	struct clk_hfpll *h = to_clk_hfpll(hw);
121 	unsigned long flags;
122 
123 	spin_lock_irqsave(&h->lock, flags);
124 	__clk_hfpll_disable(h);
125 	spin_unlock_irqrestore(&h->lock, flags);
126 }
127 
128 static long clk_hfpll_round_rate(struct clk_hw *hw, unsigned long rate,
129 				 unsigned long *parent_rate)
130 {
131 	struct clk_hfpll *h = to_clk_hfpll(hw);
132 	struct hfpll_data const *hd = h->d;
133 	unsigned long rrate;
134 
135 	rate = clamp(rate, hd->min_rate, hd->max_rate);
136 
137 	rrate = DIV_ROUND_UP(rate, *parent_rate) * *parent_rate;
138 	if (rrate > hd->max_rate)
139 		rrate -= *parent_rate;
140 
141 	return rrate;
142 }
143 
144 /*
145  * For optimization reasons, assumes no downstream clocks are actively using
146  * it.
147  */
148 static int clk_hfpll_set_rate(struct clk_hw *hw, unsigned long rate,
149 			      unsigned long parent_rate)
150 {
151 	struct clk_hfpll *h = to_clk_hfpll(hw);
152 	struct hfpll_data const *hd = h->d;
153 	struct regmap *regmap = h->clkr.regmap;
154 	unsigned long flags;
155 	u32 l_val, val;
156 	bool enabled;
157 
158 	l_val = rate / parent_rate;
159 
160 	spin_lock_irqsave(&h->lock, flags);
161 
162 	enabled = __clk_is_enabled(hw->clk);
163 	if (enabled)
164 		__clk_hfpll_disable(h);
165 
166 	/* Pick the right VCO. */
167 	if (hd->user_reg && hd->user_vco_mask) {
168 		regmap_read(regmap, hd->user_reg, &val);
169 		if (rate <= hd->low_vco_max_rate)
170 			val &= ~hd->user_vco_mask;
171 		else
172 			val |= hd->user_vco_mask;
173 		regmap_write(regmap, hd->user_reg, val);
174 	}
175 
176 	regmap_write(regmap, hd->l_reg, l_val);
177 
178 	if (enabled)
179 		__clk_hfpll_enable(hw);
180 
181 	spin_unlock_irqrestore(&h->lock, flags);
182 
183 	return 0;
184 }
185 
186 static unsigned long clk_hfpll_recalc_rate(struct clk_hw *hw,
187 					   unsigned long parent_rate)
188 {
189 	struct clk_hfpll *h = to_clk_hfpll(hw);
190 	struct hfpll_data const *hd = h->d;
191 	struct regmap *regmap = h->clkr.regmap;
192 	u32 l_val;
193 
194 	regmap_read(regmap, hd->l_reg, &l_val);
195 
196 	return l_val * parent_rate;
197 }
198 
199 static int clk_hfpll_init(struct clk_hw *hw)
200 {
201 	struct clk_hfpll *h = to_clk_hfpll(hw);
202 	struct hfpll_data const *hd = h->d;
203 	struct regmap *regmap = h->clkr.regmap;
204 	u32 mode, status;
205 
206 	regmap_read(regmap, hd->mode_reg, &mode);
207 	if (mode != (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL)) {
208 		__clk_hfpll_init_once(hw);
209 		return 0;
210 	}
211 
212 	if (hd->status_reg) {
213 		regmap_read(regmap, hd->status_reg, &status);
214 		if (!(status & BIT(hd->lock_bit))) {
215 			WARN(1, "HFPLL %s is ON, but not locked!\n",
216 			     __clk_get_name(hw->clk));
217 			clk_hfpll_disable(hw);
218 			__clk_hfpll_init_once(hw);
219 		}
220 	}
221 
222 	return 0;
223 }
224 
225 static int hfpll_is_enabled(struct clk_hw *hw)
226 {
227 	struct clk_hfpll *h = to_clk_hfpll(hw);
228 	struct hfpll_data const *hd = h->d;
229 	struct regmap *regmap = h->clkr.regmap;
230 	u32 mode;
231 
232 	regmap_read(regmap, hd->mode_reg, &mode);
233 	mode &= 0x7;
234 	return mode == (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL);
235 }
236 
237 const struct clk_ops clk_ops_hfpll = {
238 	.enable = clk_hfpll_enable,
239 	.disable = clk_hfpll_disable,
240 	.is_enabled = hfpll_is_enabled,
241 	.round_rate = clk_hfpll_round_rate,
242 	.set_rate = clk_hfpll_set_rate,
243 	.recalc_rate = clk_hfpll_recalc_rate,
244 	.init = clk_hfpll_init,
245 };
246 EXPORT_SYMBOL_GPL(clk_ops_hfpll);
247