xref: /openbmc/linux/drivers/clk/zynq/pll.c (revision 4419617e)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Zynq PLL driver
4  *
5  *  Copyright (C) 2013 Xilinx
6  *
7  *  Sören Brinkmann <soren.brinkmann@xilinx.com>
8  */
9 #include <linux/clk/zynq.h>
10 #include <linux/clk-provider.h>
11 #include <linux/slab.h>
12 #include <linux/io.h>
13 
14 /**
15  * struct zynq_pll
16  * @hw:		Handle between common and hardware-specific interfaces
17  * @pll_ctrl:	PLL control register
18  * @pll_status:	PLL status register
19  * @lock:	Register lock
20  * @lockbit:	Indicates the associated PLL_LOCKED bit in the PLL status
21  *		register.
22  */
23 struct zynq_pll {
24 	struct clk_hw	hw;
25 	void __iomem	*pll_ctrl;
26 	void __iomem	*pll_status;
27 	spinlock_t	*lock;
28 	u8		lockbit;
29 };
30 #define to_zynq_pll(_hw)	container_of(_hw, struct zynq_pll, hw)
31 
32 /* Register bitfield defines */
33 #define PLLCTRL_FBDIV_MASK	0x7f000
34 #define PLLCTRL_FBDIV_SHIFT	12
35 #define PLLCTRL_BPQUAL_MASK	(1 << 3)
36 #define PLLCTRL_PWRDWN_MASK	2
37 #define PLLCTRL_PWRDWN_SHIFT	1
38 #define PLLCTRL_RESET_MASK	1
39 #define PLLCTRL_RESET_SHIFT	0
40 
41 #define PLL_FBDIV_MIN	13
42 #define PLL_FBDIV_MAX	66
43 
44 /**
45  * zynq_pll_round_rate() - Round a clock frequency
46  * @hw:		Handle between common and hardware-specific interfaces
47  * @rate:	Desired clock frequency
48  * @prate:	Clock frequency of parent clock
49  * Returns frequency closest to @rate the hardware can generate.
50  */
51 static long zynq_pll_round_rate(struct clk_hw *hw, unsigned long rate,
52 		unsigned long *prate)
53 {
54 	u32 fbdiv;
55 
56 	fbdiv = DIV_ROUND_CLOSEST(rate, *prate);
57 	if (fbdiv < PLL_FBDIV_MIN)
58 		fbdiv = PLL_FBDIV_MIN;
59 	else if (fbdiv > PLL_FBDIV_MAX)
60 		fbdiv = PLL_FBDIV_MAX;
61 
62 	return *prate * fbdiv;
63 }
64 
65 /**
66  * zynq_pll_recalc_rate() - Recalculate clock frequency
67  * @hw:			Handle between common and hardware-specific interfaces
68  * @parent_rate:	Clock frequency of parent clock
69  * Returns current clock frequency.
70  */
71 static unsigned long zynq_pll_recalc_rate(struct clk_hw *hw,
72 		unsigned long parent_rate)
73 {
74 	struct zynq_pll *clk = to_zynq_pll(hw);
75 	u32 fbdiv;
76 
77 	/*
78 	 * makes probably sense to redundantly save fbdiv in the struct
79 	 * zynq_pll to save the IO access.
80 	 */
81 	fbdiv = (readl(clk->pll_ctrl) & PLLCTRL_FBDIV_MASK) >>
82 			PLLCTRL_FBDIV_SHIFT;
83 
84 	return parent_rate * fbdiv;
85 }
86 
87 /**
88  * zynq_pll_is_enabled - Check if a clock is enabled
89  * @hw:		Handle between common and hardware-specific interfaces
90  * Returns 1 if the clock is enabled, 0 otherwise.
91  *
92  * Not sure this is a good idea, but since disabled means bypassed for
93  * this clock implementation we say we are always enabled.
94  */
95 static int zynq_pll_is_enabled(struct clk_hw *hw)
96 {
97 	unsigned long flags = 0;
98 	u32 reg;
99 	struct zynq_pll *clk = to_zynq_pll(hw);
100 
101 	spin_lock_irqsave(clk->lock, flags);
102 
103 	reg = readl(clk->pll_ctrl);
104 
105 	spin_unlock_irqrestore(clk->lock, flags);
106 
107 	return !(reg & (PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK));
108 }
109 
110 /**
111  * zynq_pll_enable - Enable clock
112  * @hw:		Handle between common and hardware-specific interfaces
113  * Returns 0 on success
114  */
115 static int zynq_pll_enable(struct clk_hw *hw)
116 {
117 	unsigned long flags = 0;
118 	u32 reg;
119 	struct zynq_pll *clk = to_zynq_pll(hw);
120 
121 	if (zynq_pll_is_enabled(hw))
122 		return 0;
123 
124 	pr_info("PLL: enable\n");
125 
126 	/* Power up PLL and wait for lock */
127 	spin_lock_irqsave(clk->lock, flags);
128 
129 	reg = readl(clk->pll_ctrl);
130 	reg &= ~(PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK);
131 	writel(reg, clk->pll_ctrl);
132 	while (!(readl(clk->pll_status) & (1 << clk->lockbit)))
133 		;
134 
135 	spin_unlock_irqrestore(clk->lock, flags);
136 
137 	return 0;
138 }
139 
140 /**
141  * zynq_pll_disable - Disable clock
142  * @hw:		Handle between common and hardware-specific interfaces
143  * Returns 0 on success
144  */
145 static void zynq_pll_disable(struct clk_hw *hw)
146 {
147 	unsigned long flags = 0;
148 	u32 reg;
149 	struct zynq_pll *clk = to_zynq_pll(hw);
150 
151 	if (!zynq_pll_is_enabled(hw))
152 		return;
153 
154 	pr_info("PLL: shutdown\n");
155 
156 	/* shut down PLL */
157 	spin_lock_irqsave(clk->lock, flags);
158 
159 	reg = readl(clk->pll_ctrl);
160 	reg |= PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK;
161 	writel(reg, clk->pll_ctrl);
162 
163 	spin_unlock_irqrestore(clk->lock, flags);
164 }
165 
166 static const struct clk_ops zynq_pll_ops = {
167 	.enable = zynq_pll_enable,
168 	.disable = zynq_pll_disable,
169 	.is_enabled = zynq_pll_is_enabled,
170 	.round_rate = zynq_pll_round_rate,
171 	.recalc_rate = zynq_pll_recalc_rate
172 };
173 
174 /**
175  * clk_register_zynq_pll() - Register PLL with the clock framework
176  * @name	PLL name
177  * @parent	Parent clock name
178  * @pll_ctrl	Pointer to PLL control register
179  * @pll_status	Pointer to PLL status register
180  * @lock_index	Bit index to this PLL's lock status bit in @pll_status
181  * @lock	Register lock
182  * Returns handle to the registered clock.
183  */
184 struct clk *clk_register_zynq_pll(const char *name, const char *parent,
185 		void __iomem *pll_ctrl, void __iomem *pll_status, u8 lock_index,
186 		spinlock_t *lock)
187 {
188 	struct zynq_pll *pll;
189 	struct clk *clk;
190 	u32 reg;
191 	const char *parent_arr[1] = {parent};
192 	unsigned long flags = 0;
193 	struct clk_init_data initd = {
194 		.name = name,
195 		.parent_names = parent_arr,
196 		.ops = &zynq_pll_ops,
197 		.num_parents = 1,
198 		.flags = 0
199 	};
200 
201 	pll = kmalloc(sizeof(*pll), GFP_KERNEL);
202 	if (!pll)
203 		return ERR_PTR(-ENOMEM);
204 
205 	/* Populate the struct */
206 	pll->hw.init = &initd;
207 	pll->pll_ctrl = pll_ctrl;
208 	pll->pll_status = pll_status;
209 	pll->lockbit = lock_index;
210 	pll->lock = lock;
211 
212 	spin_lock_irqsave(pll->lock, flags);
213 
214 	reg = readl(pll->pll_ctrl);
215 	reg &= ~PLLCTRL_BPQUAL_MASK;
216 	writel(reg, pll->pll_ctrl);
217 
218 	spin_unlock_irqrestore(pll->lock, flags);
219 
220 	clk = clk_register(NULL, &pll->hw);
221 	if (WARN_ON(IS_ERR(clk)))
222 		goto free_pll;
223 
224 	return clk;
225 
226 free_pll:
227 	kfree(pll);
228 
229 	return clk;
230 }
231