1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Xilinx 'Clocking Wizard' driver
4  *
5  *  Copyright (C) 2013 - 2014 Xilinx
6  *
7  *  Sören Brinkmann <soren.brinkmann@xilinx.com>
8  */
9 
10 #include <linux/platform_device.h>
11 #include <linux/clk.h>
12 #include <linux/clk-provider.h>
13 #include <linux/slab.h>
14 #include <linux/io.h>
15 #include <linux/of.h>
16 #include <linux/module.h>
17 #include <linux/err.h>
18 
19 #define WZRD_NUM_OUTPUTS	7
20 #define WZRD_ACLK_MAX_FREQ	250000000UL
21 
22 #define WZRD_CLK_CFG_REG(n)	(0x200 + 4 * (n))
23 
24 #define WZRD_CLKOUT0_FRAC_EN	BIT(18)
25 #define WZRD_CLKFBOUT_FRAC_EN	BIT(26)
26 
27 #define WZRD_CLKFBOUT_MULT_SHIFT	8
28 #define WZRD_CLKFBOUT_MULT_MASK		(0xff << WZRD_CLKFBOUT_MULT_SHIFT)
29 #define WZRD_DIVCLK_DIVIDE_SHIFT	0
30 #define WZRD_DIVCLK_DIVIDE_MASK		(0xff << WZRD_DIVCLK_DIVIDE_SHIFT)
31 #define WZRD_CLKOUT_DIVIDE_SHIFT	0
32 #define WZRD_CLKOUT_DIVIDE_MASK		(0xff << WZRD_DIVCLK_DIVIDE_SHIFT)
33 
34 enum clk_wzrd_int_clks {
35 	wzrd_clk_mul,
36 	wzrd_clk_mul_div,
37 	wzrd_clk_int_max
38 };
39 
40 /**
41  * struct clk_wzrd:
42  * @clk_data:		Clock data
43  * @nb:			Notifier block
44  * @base:		Memory base
45  * @clk_in1:		Handle to input clock 'clk_in1'
46  * @axi_clk:		Handle to input clock 's_axi_aclk'
47  * @clks_internal:	Internal clocks
48  * @clkout:		Output clocks
49  * @speed_grade:	Speed grade of the device
50  * @suspended:		Flag indicating power state of the device
51  */
52 struct clk_wzrd {
53 	struct clk_onecell_data clk_data;
54 	struct notifier_block nb;
55 	void __iomem *base;
56 	struct clk *clk_in1;
57 	struct clk *axi_clk;
58 	struct clk *clks_internal[wzrd_clk_int_max];
59 	struct clk *clkout[WZRD_NUM_OUTPUTS];
60 	unsigned int speed_grade;
61 	bool suspended;
62 };
63 
64 #define to_clk_wzrd(_nb) container_of(_nb, struct clk_wzrd, nb)
65 
66 /* maximum frequencies for input/output clocks per speed grade */
67 static const unsigned long clk_wzrd_max_freq[] = {
68 	800000000UL,
69 	933000000UL,
70 	1066000000UL
71 };
72 
clk_wzrd_clk_notifier(struct notifier_block * nb,unsigned long event,void * data)73 static int clk_wzrd_clk_notifier(struct notifier_block *nb, unsigned long event,
74 				 void *data)
75 {
76 	unsigned long max;
77 	struct clk_notifier_data *ndata = data;
78 	struct clk_wzrd *clk_wzrd = to_clk_wzrd(nb);
79 
80 	if (clk_wzrd->suspended)
81 		return NOTIFY_OK;
82 
83 	if (ndata->clk == clk_wzrd->clk_in1)
84 		max = clk_wzrd_max_freq[clk_wzrd->speed_grade - 1];
85 	else if (ndata->clk == clk_wzrd->axi_clk)
86 		max = WZRD_ACLK_MAX_FREQ;
87 	else
88 		return NOTIFY_DONE;	/* should never happen */
89 
90 	switch (event) {
91 	case PRE_RATE_CHANGE:
92 		if (ndata->new_rate > max)
93 			return NOTIFY_BAD;
94 		return NOTIFY_OK;
95 	case POST_RATE_CHANGE:
96 	case ABORT_RATE_CHANGE:
97 	default:
98 		return NOTIFY_DONE;
99 	}
100 }
101 
clk_wzrd_suspend(struct device * dev)102 static int __maybe_unused clk_wzrd_suspend(struct device *dev)
103 {
104 	struct clk_wzrd *clk_wzrd = dev_get_drvdata(dev);
105 
106 	clk_disable_unprepare(clk_wzrd->axi_clk);
107 	clk_wzrd->suspended = true;
108 
109 	return 0;
110 }
111 
clk_wzrd_resume(struct device * dev)112 static int __maybe_unused clk_wzrd_resume(struct device *dev)
113 {
114 	int ret;
115 	struct clk_wzrd *clk_wzrd = dev_get_drvdata(dev);
116 
117 	ret = clk_prepare_enable(clk_wzrd->axi_clk);
118 	if (ret) {
119 		dev_err(dev, "unable to enable s_axi_aclk\n");
120 		return ret;
121 	}
122 
123 	clk_wzrd->suspended = false;
124 
125 	return 0;
126 }
127 
128 static SIMPLE_DEV_PM_OPS(clk_wzrd_dev_pm_ops, clk_wzrd_suspend,
129 			 clk_wzrd_resume);
130 
clk_wzrd_probe(struct platform_device * pdev)131 static int clk_wzrd_probe(struct platform_device *pdev)
132 {
133 	int i, ret;
134 	u32 reg;
135 	unsigned long rate;
136 	const char *clk_name;
137 	struct clk_wzrd *clk_wzrd;
138 	struct device_node *np = pdev->dev.of_node;
139 
140 	clk_wzrd = devm_kzalloc(&pdev->dev, sizeof(*clk_wzrd), GFP_KERNEL);
141 	if (!clk_wzrd)
142 		return -ENOMEM;
143 	platform_set_drvdata(pdev, clk_wzrd);
144 
145 	clk_wzrd->base = devm_platform_ioremap_resource(pdev, 0);
146 	if (IS_ERR(clk_wzrd->base))
147 		return PTR_ERR(clk_wzrd->base);
148 
149 	ret = of_property_read_u32(np, "speed-grade", &clk_wzrd->speed_grade);
150 	if (!ret) {
151 		if (clk_wzrd->speed_grade < 1 || clk_wzrd->speed_grade > 3) {
152 			dev_warn(&pdev->dev, "invalid speed grade '%d'\n",
153 				 clk_wzrd->speed_grade);
154 			clk_wzrd->speed_grade = 0;
155 		}
156 	}
157 
158 	clk_wzrd->clk_in1 = devm_clk_get(&pdev->dev, "clk_in1");
159 	if (IS_ERR(clk_wzrd->clk_in1)) {
160 		if (clk_wzrd->clk_in1 != ERR_PTR(-EPROBE_DEFER))
161 			dev_err(&pdev->dev, "clk_in1 not found\n");
162 		return PTR_ERR(clk_wzrd->clk_in1);
163 	}
164 
165 	clk_wzrd->axi_clk = devm_clk_get(&pdev->dev, "s_axi_aclk");
166 	if (IS_ERR(clk_wzrd->axi_clk)) {
167 		if (clk_wzrd->axi_clk != ERR_PTR(-EPROBE_DEFER))
168 			dev_err(&pdev->dev, "s_axi_aclk not found\n");
169 		return PTR_ERR(clk_wzrd->axi_clk);
170 	}
171 	ret = clk_prepare_enable(clk_wzrd->axi_clk);
172 	if (ret) {
173 		dev_err(&pdev->dev, "enabling s_axi_aclk failed\n");
174 		return ret;
175 	}
176 	rate = clk_get_rate(clk_wzrd->axi_clk);
177 	if (rate > WZRD_ACLK_MAX_FREQ) {
178 		dev_err(&pdev->dev, "s_axi_aclk frequency (%lu) too high\n",
179 			rate);
180 		ret = -EINVAL;
181 		goto err_disable_clk;
182 	}
183 
184 	/* we don't support fractional div/mul yet */
185 	reg = readl(clk_wzrd->base + WZRD_CLK_CFG_REG(0)) &
186 		    WZRD_CLKFBOUT_FRAC_EN;
187 	reg |= readl(clk_wzrd->base + WZRD_CLK_CFG_REG(2)) &
188 		     WZRD_CLKOUT0_FRAC_EN;
189 	if (reg)
190 		dev_warn(&pdev->dev, "fractional div/mul not supported\n");
191 
192 	/* register multiplier */
193 	reg = (readl(clk_wzrd->base + WZRD_CLK_CFG_REG(0)) &
194 		     WZRD_CLKFBOUT_MULT_MASK) >> WZRD_CLKFBOUT_MULT_SHIFT;
195 	clk_name = kasprintf(GFP_KERNEL, "%s_mul", dev_name(&pdev->dev));
196 	if (!clk_name) {
197 		ret = -ENOMEM;
198 		goto err_disable_clk;
199 	}
200 	clk_wzrd->clks_internal[wzrd_clk_mul] = clk_register_fixed_factor
201 			(&pdev->dev, clk_name,
202 			 __clk_get_name(clk_wzrd->clk_in1),
203 			 0, reg, 1);
204 	kfree(clk_name);
205 	if (IS_ERR(clk_wzrd->clks_internal[wzrd_clk_mul])) {
206 		dev_err(&pdev->dev, "unable to register fixed-factor clock\n");
207 		ret = PTR_ERR(clk_wzrd->clks_internal[wzrd_clk_mul]);
208 		goto err_disable_clk;
209 	}
210 
211 	/* register div */
212 	reg = (readl(clk_wzrd->base + WZRD_CLK_CFG_REG(0)) &
213 			WZRD_DIVCLK_DIVIDE_MASK) >> WZRD_DIVCLK_DIVIDE_SHIFT;
214 	clk_name = kasprintf(GFP_KERNEL, "%s_mul_div", dev_name(&pdev->dev));
215 	if (!clk_name) {
216 		ret = -ENOMEM;
217 		goto err_rm_int_clk;
218 	}
219 
220 	clk_wzrd->clks_internal[wzrd_clk_mul_div] = clk_register_fixed_factor
221 			(&pdev->dev, clk_name,
222 			 __clk_get_name(clk_wzrd->clks_internal[wzrd_clk_mul]),
223 			 0, 1, reg);
224 	if (IS_ERR(clk_wzrd->clks_internal[wzrd_clk_mul_div])) {
225 		dev_err(&pdev->dev, "unable to register divider clock\n");
226 		ret = PTR_ERR(clk_wzrd->clks_internal[wzrd_clk_mul_div]);
227 		goto err_rm_int_clk;
228 	}
229 
230 	/* register div per output */
231 	for (i = WZRD_NUM_OUTPUTS - 1; i >= 0 ; i--) {
232 		const char *clkout_name;
233 
234 		if (of_property_read_string_index(np, "clock-output-names", i,
235 						  &clkout_name)) {
236 			dev_err(&pdev->dev,
237 				"clock output name not specified\n");
238 			ret = -EINVAL;
239 			goto err_rm_int_clks;
240 		}
241 		reg = readl(clk_wzrd->base + WZRD_CLK_CFG_REG(2) + i * 12);
242 		reg &= WZRD_CLKOUT_DIVIDE_MASK;
243 		reg >>= WZRD_CLKOUT_DIVIDE_SHIFT;
244 		clk_wzrd->clkout[i] = clk_register_fixed_factor
245 			(&pdev->dev, clkout_name, clk_name, 0, 1, reg);
246 		if (IS_ERR(clk_wzrd->clkout[i])) {
247 			int j;
248 
249 			for (j = i + 1; j < WZRD_NUM_OUTPUTS; j++)
250 				clk_unregister(clk_wzrd->clkout[j]);
251 			dev_err(&pdev->dev,
252 				"unable to register divider clock\n");
253 			ret = PTR_ERR(clk_wzrd->clkout[i]);
254 			goto err_rm_int_clks;
255 		}
256 	}
257 
258 	kfree(clk_name);
259 
260 	clk_wzrd->clk_data.clks = clk_wzrd->clkout;
261 	clk_wzrd->clk_data.clk_num = ARRAY_SIZE(clk_wzrd->clkout);
262 	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_wzrd->clk_data);
263 
264 	if (clk_wzrd->speed_grade) {
265 		clk_wzrd->nb.notifier_call = clk_wzrd_clk_notifier;
266 
267 		ret = clk_notifier_register(clk_wzrd->clk_in1,
268 					    &clk_wzrd->nb);
269 		if (ret)
270 			dev_warn(&pdev->dev,
271 				 "unable to register clock notifier\n");
272 
273 		ret = clk_notifier_register(clk_wzrd->axi_clk, &clk_wzrd->nb);
274 		if (ret)
275 			dev_warn(&pdev->dev,
276 				 "unable to register clock notifier\n");
277 	}
278 
279 	return 0;
280 
281 err_rm_int_clks:
282 	clk_unregister(clk_wzrd->clks_internal[1]);
283 err_rm_int_clk:
284 	kfree(clk_name);
285 	clk_unregister(clk_wzrd->clks_internal[0]);
286 err_disable_clk:
287 	clk_disable_unprepare(clk_wzrd->axi_clk);
288 
289 	return ret;
290 }
291 
clk_wzrd_remove(struct platform_device * pdev)292 static int clk_wzrd_remove(struct platform_device *pdev)
293 {
294 	int i;
295 	struct clk_wzrd *clk_wzrd = platform_get_drvdata(pdev);
296 
297 	of_clk_del_provider(pdev->dev.of_node);
298 
299 	for (i = 0; i < WZRD_NUM_OUTPUTS; i++)
300 		clk_unregister(clk_wzrd->clkout[i]);
301 	for (i = 0; i < wzrd_clk_int_max; i++)
302 		clk_unregister(clk_wzrd->clks_internal[i]);
303 
304 	if (clk_wzrd->speed_grade) {
305 		clk_notifier_unregister(clk_wzrd->axi_clk, &clk_wzrd->nb);
306 		clk_notifier_unregister(clk_wzrd->clk_in1, &clk_wzrd->nb);
307 	}
308 
309 	clk_disable_unprepare(clk_wzrd->axi_clk);
310 
311 	return 0;
312 }
313 
314 static const struct of_device_id clk_wzrd_ids[] = {
315 	{ .compatible = "xlnx,clocking-wizard" },
316 	{ },
317 };
318 MODULE_DEVICE_TABLE(of, clk_wzrd_ids);
319 
320 static struct platform_driver clk_wzrd_driver = {
321 	.driver = {
322 		.name = "clk-wizard",
323 		.of_match_table = clk_wzrd_ids,
324 		.pm = &clk_wzrd_dev_pm_ops,
325 	},
326 	.probe = clk_wzrd_probe,
327 	.remove = clk_wzrd_remove,
328 };
329 module_platform_driver(clk_wzrd_driver);
330 
331 MODULE_LICENSE("GPL");
332 MODULE_AUTHOR("Soeren Brinkmann <soren.brinkmann@xilinx.com");
333 MODULE_DESCRIPTION("Driver for the Xilinx Clocking Wizard IP core");
334