1 From f044ffe2d612dcaa2de36c918aaab79c8db1482e Mon Sep 17 00:00:00 2001
2 From: Stephen Boyd <sboyd@codeaurora.org>
3 Date: Fri, 20 Mar 2015 23:45:24 -0700
4 Subject: [PATCH 38/69] clk: qcom: Add support for High-Frequency PLLs (HFPLLs)
6 HFPLLs are the main frequency source for Krait CPU clocks. Add
7 support for changing the rate of these PLLs.
9 Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
11 drivers/clk/qcom/Makefile | 1 +
12 drivers/clk/qcom/clk-hfpll.c | 253 +++++++++++++++++++++++++++++++++++++++++++
13 drivers/clk/qcom/clk-hfpll.h | 54 +++++++++
14 3 files changed, 308 insertions(+)
15 create mode 100644 drivers/clk/qcom/clk-hfpll.c
16 create mode 100644 drivers/clk/qcom/clk-hfpll.h
18 --- a/drivers/clk/qcom/Makefile
19 +++ b/drivers/clk/qcom/Makefile
20 @@ -9,6 +9,7 @@ clk-qcom-y += clk-rcg2.o
21 clk-qcom-y += clk-branch.o
22 clk-qcom-y += clk-regmap-divider.o
23 clk-qcom-y += clk-regmap-mux.o
24 +clk-qcom-y += clk-hfpll.o
26 clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
29 +++ b/drivers/clk/qcom/clk-hfpll.c
32 + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
34 + * This program is free software; you can redistribute it and/or modify
35 + * it under the terms of the GNU General Public License version 2 and
36 + * only version 2 as published by the Free Software Foundation.
38 + * This program is distributed in the hope that it will be useful,
39 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
40 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
41 + * GNU General Public License for more details.
43 +#include <linux/kernel.h>
44 +#include <linux/export.h>
45 +#include <linux/regmap.h>
46 +#include <linux/delay.h>
47 +#include <linux/err.h>
48 +#include <linux/clk-provider.h>
49 +#include <linux/spinlock.h>
51 +#include "clk-regmap.h"
52 +#include "clk-hfpll.h"
54 +#define PLL_OUTCTRL BIT(0)
55 +#define PLL_BYPASSNL BIT(1)
56 +#define PLL_RESET_N BIT(2)
58 +/* Initialize a HFPLL at a given rate and enable it. */
59 +static void __clk_hfpll_init_once(struct clk_hw *hw)
61 + struct clk_hfpll *h = to_clk_hfpll(hw);
62 + struct hfpll_data const *hd = h->d;
63 + struct regmap *regmap = h->clkr.regmap;
65 + if (likely(h->init_done))
68 + /* Configure PLL parameters for integer mode. */
70 + regmap_write(regmap, hd->config_reg, hd->config_val);
71 + regmap_write(regmap, hd->m_reg, 0);
72 + regmap_write(regmap, hd->n_reg, 1);
75 + u32 regval = hd->user_val;
78 + rate = clk_hw_get_rate(hw);
80 + /* Pick the right VCO. */
81 + if (hd->user_vco_mask && rate > hd->low_vco_max_rate)
82 + regval |= hd->user_vco_mask;
83 + regmap_write(regmap, hd->user_reg, regval);
87 + regmap_write(regmap, hd->droop_reg, hd->droop_val);
89 + h->init_done = true;
92 +static void __clk_hfpll_enable(struct clk_hw *hw)
94 + struct clk_hfpll *h = to_clk_hfpll(hw);
95 + struct hfpll_data const *hd = h->d;
96 + struct regmap *regmap = h->clkr.regmap;
99 + __clk_hfpll_init_once(hw);
101 + /* Disable PLL bypass mode. */
102 + regmap_update_bits(regmap, hd->mode_reg, PLL_BYPASSNL, PLL_BYPASSNL);
105 + * H/W requires a 5us delay between disabling the bypass and
106 + * de-asserting the reset. Delay 10us just to be safe.
110 + /* De-assert active-low PLL reset. */
111 + regmap_update_bits(regmap, hd->mode_reg, PLL_RESET_N, PLL_RESET_N);
113 + /* Wait for PLL to lock. */
114 + if (hd->status_reg) {
116 + regmap_read(regmap, hd->status_reg, &val);
117 + } while (!(val & BIT(hd->lock_bit)));
122 + /* Enable PLL output. */
123 + regmap_update_bits(regmap, hd->mode_reg, PLL_OUTCTRL, PLL_OUTCTRL);
126 +/* Enable an already-configured HFPLL. */
127 +static int clk_hfpll_enable(struct clk_hw *hw)
129 + unsigned long flags;
130 + struct clk_hfpll *h = to_clk_hfpll(hw);
131 + struct hfpll_data const *hd = h->d;
132 + struct regmap *regmap = h->clkr.regmap;
135 + spin_lock_irqsave(&h->lock, flags);
136 + regmap_read(regmap, hd->mode_reg, &mode);
137 + if (!(mode & (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL)))
138 + __clk_hfpll_enable(hw);
139 + spin_unlock_irqrestore(&h->lock, flags);
144 +static void __clk_hfpll_disable(struct clk_hfpll *h)
146 + struct hfpll_data const *hd = h->d;
147 + struct regmap *regmap = h->clkr.regmap;
150 + * Disable the PLL output, disable test mode, enable the bypass mode,
151 + * and assert the reset.
153 + regmap_update_bits(regmap, hd->mode_reg,
154 + PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL, 0);
157 +static void clk_hfpll_disable(struct clk_hw *hw)
159 + struct clk_hfpll *h = to_clk_hfpll(hw);
160 + unsigned long flags;
162 + spin_lock_irqsave(&h->lock, flags);
163 + __clk_hfpll_disable(h);
164 + spin_unlock_irqrestore(&h->lock, flags);
167 +static long clk_hfpll_round_rate(struct clk_hw *hw, unsigned long rate,
168 + unsigned long *parent_rate)
170 + struct clk_hfpll *h = to_clk_hfpll(hw);
171 + struct hfpll_data const *hd = h->d;
172 + unsigned long rrate;
174 + rate = clamp(rate, hd->min_rate, hd->max_rate);
176 + rrate = DIV_ROUND_UP(rate, *parent_rate) * *parent_rate;
177 + if (rrate > hd->max_rate)
178 + rrate -= *parent_rate;
184 + * For optimization reasons, assumes no downstream clocks are actively using
187 +static int clk_hfpll_set_rate(struct clk_hw *hw, unsigned long rate,
188 + unsigned long parent_rate)
190 + struct clk_hfpll *h = to_clk_hfpll(hw);
191 + struct hfpll_data const *hd = h->d;
192 + struct regmap *regmap = h->clkr.regmap;
193 + unsigned long flags;
197 + l_val = rate / parent_rate;
199 + spin_lock_irqsave(&h->lock, flags);
201 + enabled = __clk_is_enabled(hw->clk);
203 + __clk_hfpll_disable(h);
205 + /* Pick the right VCO. */
206 + if (hd->user_reg && hd->user_vco_mask) {
207 + regmap_read(regmap, hd->user_reg, &val);
208 + if (rate <= hd->low_vco_max_rate)
209 + val &= ~hd->user_vco_mask;
211 + val |= hd->user_vco_mask;
212 + regmap_write(regmap, hd->user_reg, val);
215 + regmap_write(regmap, hd->l_reg, l_val);
218 + __clk_hfpll_enable(hw);
220 + spin_unlock_irqrestore(&h->lock, flags);
225 +static unsigned long clk_hfpll_recalc_rate(struct clk_hw *hw,
226 + unsigned long parent_rate)
228 + struct clk_hfpll *h = to_clk_hfpll(hw);
229 + struct hfpll_data const *hd = h->d;
230 + struct regmap *regmap = h->clkr.regmap;
233 + regmap_read(regmap, hd->l_reg, &l_val);
235 + return l_val * parent_rate;
238 +static void clk_hfpll_init(struct clk_hw *hw)
240 + struct clk_hfpll *h = to_clk_hfpll(hw);
241 + struct hfpll_data const *hd = h->d;
242 + struct regmap *regmap = h->clkr.regmap;
245 + regmap_read(regmap, hd->mode_reg, &mode);
246 + if (mode != (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL)) {
247 + __clk_hfpll_init_once(hw);
251 + if (hd->status_reg) {
252 + regmap_read(regmap, hd->status_reg, &status);
253 + if (!(status & BIT(hd->lock_bit))) {
254 + WARN(1, "HFPLL %s is ON, but not locked!\n",
255 + __clk_get_name(hw->clk));
256 + clk_hfpll_disable(hw);
257 + __clk_hfpll_init_once(hw);
262 +static int hfpll_is_enabled(struct clk_hw *hw)
264 + struct clk_hfpll *h = to_clk_hfpll(hw);
265 + struct hfpll_data const *hd = h->d;
266 + struct regmap *regmap = h->clkr.regmap;
269 + regmap_read(regmap, hd->mode_reg, &mode);
271 + return mode == (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL);
274 +const struct clk_ops clk_ops_hfpll = {
275 + .enable = clk_hfpll_enable,
276 + .disable = clk_hfpll_disable,
277 + .is_enabled = hfpll_is_enabled,
278 + .round_rate = clk_hfpll_round_rate,
279 + .set_rate = clk_hfpll_set_rate,
280 + .recalc_rate = clk_hfpll_recalc_rate,
281 + .init = clk_hfpll_init,
283 +EXPORT_SYMBOL_GPL(clk_ops_hfpll);
285 +++ b/drivers/clk/qcom/clk-hfpll.h
288 + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
290 + * This program is free software; you can redistribute it and/or modify
291 + * it under the terms of the GNU General Public License version 2 and
292 + * only version 2 as published by the Free Software Foundation.
294 + * This program is distributed in the hope that it will be useful,
295 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
296 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
297 + * GNU General Public License for more details.
299 +#ifndef __QCOM_CLK_HFPLL_H__
300 +#define __QCOM_CLK_HFPLL_H__
302 +#include <linux/clk-provider.h>
303 +#include <linux/spinlock.h>
304 +#include "clk-regmap.h"
321 + unsigned long low_vco_max_rate;
323 + unsigned long min_rate;
324 + unsigned long max_rate;
328 + struct hfpll_data const *d;
331 + struct clk_regmap clkr;
335 +#define to_clk_hfpll(_hw) \
336 + container_of(to_clk_regmap(_hw), struct clk_hfpll, clkr)
338 +extern const struct clk_ops clk_ops_hfpll;