1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * MMP Audio Clock Controller driver
4 *
5 * Copyright (C) 2020 Lubomir Rintel <lkundrak@v3.sk>
6 */
7
8#include <linux/clk-provider.h>
9#include <linux/io.h>
10#include <linux/module.h>
11#include <linux/platform_device.h>
12#include <linux/pm_clock.h>
13#include <linux/pm_runtime.h>
14#include <linux/slab.h>
15#include <dt-bindings/clock/marvell,mmp2-audio.h>
16
17/* Audio Controller Registers */
18#define SSPA_AUD_CTRL				0x04
19#define SSPA_AUD_PLL_CTRL0			0x08
20#define SSPA_AUD_PLL_CTRL1			0x0c
21
22/* SSPA Audio Control Register */
23#define SSPA_AUD_CTRL_SYSCLK_SHIFT		0
24#define SSPA_AUD_CTRL_SYSCLK_DIV_SHIFT		1
25#define SSPA_AUD_CTRL_SSPA0_MUX_SHIFT		7
26#define SSPA_AUD_CTRL_SSPA0_SHIFT		8
27#define SSPA_AUD_CTRL_SSPA0_DIV_SHIFT		9
28#define SSPA_AUD_CTRL_SSPA1_SHIFT		16
29#define SSPA_AUD_CTRL_SSPA1_DIV_SHIFT		17
30#define SSPA_AUD_CTRL_SSPA1_MUX_SHIFT		23
31#define SSPA_AUD_CTRL_DIV_MASK			0x7e
32
33/* SSPA Audio PLL Control 0 Register */
34#define SSPA_AUD_PLL_CTRL0_DIV_OCLK_MODULO_MASK (0x7 << 28)
35#define SSPA_AUD_PLL_CTRL0_DIV_OCLK_MODULO(x)	((x) << 28)
36#define SSPA_AUD_PLL_CTRL0_FRACT_MASK		(0xfffff << 8)
37#define SSPA_AUD_PLL_CTRL0_FRACT(x)		((x) << 8)
38#define SSPA_AUD_PLL_CTRL0_ENA_DITHER		(1 << 7)
39#define SSPA_AUD_PLL_CTRL0_ICP_2UA		(0 << 5)
40#define SSPA_AUD_PLL_CTRL0_ICP_5UA		(1 << 5)
41#define SSPA_AUD_PLL_CTRL0_ICP_7UA		(2 << 5)
42#define SSPA_AUD_PLL_CTRL0_ICP_10UA		(3 << 5)
43#define SSPA_AUD_PLL_CTRL0_DIV_FBCCLK_MASK	(0x3 << 3)
44#define SSPA_AUD_PLL_CTRL0_DIV_FBCCLK(x)	((x) << 3)
45#define SSPA_AUD_PLL_CTRL0_DIV_MCLK_MASK	(0x1 << 2)
46#define SSPA_AUD_PLL_CTRL0_DIV_MCLK(x)		((x) << 2)
47#define SSPA_AUD_PLL_CTRL0_PD_OVPROT_DIS	(1 << 1)
48#define SSPA_AUD_PLL_CTRL0_PU			(1 << 0)
49
50/* SSPA Audio PLL Control 1 Register */
51#define SSPA_AUD_PLL_CTRL1_SEL_FAST_CLK		(1 << 24)
52#define SSPA_AUD_PLL_CTRL1_CLK_SEL_MASK		(1 << 11)
53#define SSPA_AUD_PLL_CTRL1_CLK_SEL_AUDIO_PLL	(1 << 11)
54#define SSPA_AUD_PLL_CTRL1_CLK_SEL_VCXO		(0 << 11)
55#define SSPA_AUD_PLL_CTRL1_DIV_OCLK_PATTERN_MASK (0x7ff << 0)
56#define SSPA_AUD_PLL_CTRL1_DIV_OCLK_PATTERN(x)	((x) << 0)
57
58struct mmp2_audio_clk {
59	void __iomem *mmio_base;
60
61	struct clk_hw audio_pll_hw;
62	struct clk_mux sspa_mux;
63	struct clk_mux sspa1_mux;
64	struct clk_divider sysclk_div;
65	struct clk_divider sspa0_div;
66	struct clk_divider sspa1_div;
67	struct clk_gate sysclk_gate;
68	struct clk_gate sspa0_gate;
69	struct clk_gate sspa1_gate;
70
71	u32 aud_ctrl;
72	u32 aud_pll_ctrl0;
73	u32 aud_pll_ctrl1;
74
75	spinlock_t lock;
76
77	/* Must be last */
78	struct clk_hw_onecell_data clk_data;
79};
80
81static const struct {
82	unsigned long parent_rate;
83	unsigned long freq_vco;
84	unsigned char mclk;
85	unsigned char fbcclk;
86	unsigned short fract;
87} predivs[] = {
88	{ 26000000, 135475200, 0, 0, 0x8a18 },
89	{ 26000000, 147456000, 0, 1, 0x0da1 },
90	{ 38400000, 135475200, 1, 2, 0x8208 },
91	{ 38400000, 147456000, 1, 3, 0xaaaa },
92};
93
94static const struct {
95	unsigned char divisor;
96	unsigned char modulo;
97	unsigned char pattern;
98} postdivs[] = {
99	{   1,	3,  0, },
100	{   2,	5,  0, },
101	{   4,	0,  0, },
102	{   6,	1,  1, },
103	{   8,	1,  0, },
104	{   9,	1,  2, },
105	{  12,	2,  1, },
106	{  16,	2,  0, },
107	{  18,	2,  2, },
108	{  24,	4,  1, },
109	{  36,	4,  2, },
110	{  48,	6,  1, },
111	{  72,	6,  2, },
112};
113
114static unsigned long audio_pll_recalc_rate(struct clk_hw *hw,
115					   unsigned long parent_rate)
116{
117	struct mmp2_audio_clk *priv = container_of(hw, struct mmp2_audio_clk, audio_pll_hw);
118	unsigned int prediv;
119	unsigned int postdiv;
120	u32 aud_pll_ctrl0;
121	u32 aud_pll_ctrl1;
122
123	aud_pll_ctrl0 = readl(priv->mmio_base + SSPA_AUD_PLL_CTRL0);
124	aud_pll_ctrl0 &= SSPA_AUD_PLL_CTRL0_DIV_OCLK_MODULO_MASK |
125			 SSPA_AUD_PLL_CTRL0_FRACT_MASK |
126			 SSPA_AUD_PLL_CTRL0_ENA_DITHER |
127			 SSPA_AUD_PLL_CTRL0_DIV_FBCCLK_MASK |
128			 SSPA_AUD_PLL_CTRL0_DIV_MCLK_MASK |
129			 SSPA_AUD_PLL_CTRL0_PU;
130
131	aud_pll_ctrl1 = readl(priv->mmio_base + SSPA_AUD_PLL_CTRL1);
132	aud_pll_ctrl1 &= SSPA_AUD_PLL_CTRL1_CLK_SEL_MASK |
133			 SSPA_AUD_PLL_CTRL1_DIV_OCLK_PATTERN_MASK;
134
135	for (prediv = 0; prediv < ARRAY_SIZE(predivs); prediv++) {
136		if (predivs[prediv].parent_rate != parent_rate)
137			continue;
138		for (postdiv = 0; postdiv < ARRAY_SIZE(postdivs); postdiv++) {
139			unsigned long freq;
140			u32 val;
141
142			val = SSPA_AUD_PLL_CTRL0_ENA_DITHER;
143			val |= SSPA_AUD_PLL_CTRL0_PU;
144			val |= SSPA_AUD_PLL_CTRL0_DIV_OCLK_MODULO(postdivs[postdiv].modulo);
145			val |= SSPA_AUD_PLL_CTRL0_FRACT(predivs[prediv].fract);
146			val |= SSPA_AUD_PLL_CTRL0_DIV_FBCCLK(predivs[prediv].fbcclk);
147			val |= SSPA_AUD_PLL_CTRL0_DIV_MCLK(predivs[prediv].mclk);
148			if (val != aud_pll_ctrl0)
149				continue;
150
151			val = SSPA_AUD_PLL_CTRL1_CLK_SEL_AUDIO_PLL;
152			val |= SSPA_AUD_PLL_CTRL1_DIV_OCLK_PATTERN(postdivs[postdiv].pattern);
153			if (val != aud_pll_ctrl1)
154				continue;
155
156			freq = predivs[prediv].freq_vco;
157			freq /= postdivs[postdiv].divisor;
158			return freq;
159		}
160	}
161
162	return 0;
163}
164
165static long audio_pll_round_rate(struct clk_hw *hw, unsigned long rate,
166				 unsigned long *parent_rate)
167{
168	unsigned int prediv;
169	unsigned int postdiv;
170	long rounded = 0;
171
172	for (prediv = 0; prediv < ARRAY_SIZE(predivs); prediv++) {
173		if (predivs[prediv].parent_rate != *parent_rate)
174			continue;
175		for (postdiv = 0; postdiv < ARRAY_SIZE(postdivs); postdiv++) {
176			long freq = predivs[prediv].freq_vco;
177
178			freq /= postdivs[postdiv].divisor;
179			if (freq == rate)
180				return rate;
181			if (freq < rate)
182				continue;
183			if (rounded && freq > rounded)
184				continue;
185			rounded = freq;
186		}
187	}
188
189	return rounded;
190}
191
192static int audio_pll_set_rate(struct clk_hw *hw, unsigned long rate,
193			      unsigned long parent_rate)
194{
195	struct mmp2_audio_clk *priv = container_of(hw, struct mmp2_audio_clk, audio_pll_hw);
196	unsigned int prediv;
197	unsigned int postdiv;
198	unsigned long val;
199
200	for (prediv = 0; prediv < ARRAY_SIZE(predivs); prediv++) {
201		if (predivs[prediv].parent_rate != parent_rate)
202			continue;
203
204		for (postdiv = 0; postdiv < ARRAY_SIZE(postdivs); postdiv++) {
205			if (rate * postdivs[postdiv].divisor != predivs[prediv].freq_vco)
206				continue;
207
208			val = SSPA_AUD_PLL_CTRL0_ENA_DITHER;
209			val |= SSPA_AUD_PLL_CTRL0_PU;
210			val |= SSPA_AUD_PLL_CTRL0_DIV_OCLK_MODULO(postdivs[postdiv].modulo);
211			val |= SSPA_AUD_PLL_CTRL0_FRACT(predivs[prediv].fract);
212			val |= SSPA_AUD_PLL_CTRL0_DIV_FBCCLK(predivs[prediv].fbcclk);
213			val |= SSPA_AUD_PLL_CTRL0_DIV_MCLK(predivs[prediv].mclk);
214			writel(val, priv->mmio_base + SSPA_AUD_PLL_CTRL0);
215
216			val = SSPA_AUD_PLL_CTRL1_CLK_SEL_AUDIO_PLL;
217			val |= SSPA_AUD_PLL_CTRL1_DIV_OCLK_PATTERN(postdivs[postdiv].pattern);
218			writel(val, priv->mmio_base + SSPA_AUD_PLL_CTRL1);
219
220			return 0;
221		}
222	}
223
224	return -ERANGE;
225}
226
227static const struct clk_ops audio_pll_ops = {
228	.recalc_rate = audio_pll_recalc_rate,
229	.round_rate = audio_pll_round_rate,
230	.set_rate = audio_pll_set_rate,
231};
232
233static int register_clocks(struct mmp2_audio_clk *priv, struct device *dev)
234{
235	const struct clk_parent_data sspa_mux_parents[] = {
236		{ .hw = &priv->audio_pll_hw },
237		{ .fw_name = "i2s0" },
238	};
239	const struct clk_parent_data sspa1_mux_parents[] = {
240		{ .hw = &priv->audio_pll_hw },
241		{ .fw_name = "i2s1" },
242	};
243	int ret;
244
245	priv->audio_pll_hw.init = CLK_HW_INIT_FW_NAME("audio_pll",
246				"vctcxo", &audio_pll_ops,
247				CLK_SET_RATE_PARENT);
248	ret = devm_clk_hw_register(dev, &priv->audio_pll_hw);
249	if (ret)
250		return ret;
251
252	priv->sspa_mux.hw.init = CLK_HW_INIT_PARENTS_DATA("sspa_mux",
253				sspa_mux_parents, &clk_mux_ops,
254				CLK_SET_RATE_PARENT);
255	priv->sspa_mux.reg = priv->mmio_base + SSPA_AUD_CTRL;
256	priv->sspa_mux.mask = 1;
257	priv->sspa_mux.shift = SSPA_AUD_CTRL_SSPA0_MUX_SHIFT;
258	ret = devm_clk_hw_register(dev, &priv->sspa_mux.hw);
259	if (ret)
260		return ret;
261
262	priv->sysclk_div.hw.init = CLK_HW_INIT_HW("sys_div",
263				&priv->sspa_mux.hw, &clk_divider_ops,
264				CLK_SET_RATE_PARENT);
265	priv->sysclk_div.reg = priv->mmio_base + SSPA_AUD_CTRL;
266	priv->sysclk_div.shift = SSPA_AUD_CTRL_SYSCLK_DIV_SHIFT;
267	priv->sysclk_div.width = 6;
268	priv->sysclk_div.flags = CLK_DIVIDER_ONE_BASED;
269	priv->sysclk_div.flags |= CLK_DIVIDER_ROUND_CLOSEST;
270	priv->sysclk_div.flags |= CLK_DIVIDER_ALLOW_ZERO;
271	ret = devm_clk_hw_register(dev, &priv->sysclk_div.hw);
272	if (ret)
273		return ret;
274
275	priv->sysclk_gate.hw.init = CLK_HW_INIT_HW("sys_clk",
276				&priv->sysclk_div.hw, &clk_gate_ops,
277				CLK_SET_RATE_PARENT);
278	priv->sysclk_gate.reg = priv->mmio_base + SSPA_AUD_CTRL;
279	priv->sysclk_gate.bit_idx = SSPA_AUD_CTRL_SYSCLK_SHIFT;
280	ret = devm_clk_hw_register(dev, &priv->sysclk_gate.hw);
281	if (ret)
282		return ret;
283
284	priv->sspa0_div.hw.init = CLK_HW_INIT_HW("sspa0_div",
285				&priv->sspa_mux.hw, &clk_divider_ops, 0);
286	priv->sspa0_div.reg = priv->mmio_base + SSPA_AUD_CTRL;
287	priv->sspa0_div.shift = SSPA_AUD_CTRL_SSPA0_DIV_SHIFT;
288	priv->sspa0_div.width = 6;
289	priv->sspa0_div.flags = CLK_DIVIDER_ONE_BASED;
290	priv->sspa0_div.flags |= CLK_DIVIDER_ROUND_CLOSEST;
291	priv->sspa0_div.flags |= CLK_DIVIDER_ALLOW_ZERO;
292	ret = devm_clk_hw_register(dev, &priv->sspa0_div.hw);
293	if (ret)
294		return ret;
295
296	priv->sspa0_gate.hw.init = CLK_HW_INIT_HW("sspa0_clk",
297				&priv->sspa0_div.hw, &clk_gate_ops,
298				CLK_SET_RATE_PARENT);
299	priv->sspa0_gate.reg = priv->mmio_base + SSPA_AUD_CTRL;
300	priv->sspa0_gate.bit_idx = SSPA_AUD_CTRL_SSPA0_SHIFT;
301	ret = devm_clk_hw_register(dev, &priv->sspa0_gate.hw);
302	if (ret)
303		return ret;
304
305	priv->sspa1_mux.hw.init = CLK_HW_INIT_PARENTS_DATA("sspa1_mux",
306				sspa1_mux_parents, &clk_mux_ops,
307				CLK_SET_RATE_PARENT);
308	priv->sspa1_mux.reg = priv->mmio_base + SSPA_AUD_CTRL;
309	priv->sspa1_mux.mask = 1;
310	priv->sspa1_mux.shift = SSPA_AUD_CTRL_SSPA1_MUX_SHIFT;
311	ret = devm_clk_hw_register(dev, &priv->sspa1_mux.hw);
312	if (ret)
313		return ret;
314
315	priv->sspa1_div.hw.init = CLK_HW_INIT_HW("sspa1_div",
316				&priv->sspa1_mux.hw, &clk_divider_ops, 0);
317	priv->sspa1_div.reg = priv->mmio_base + SSPA_AUD_CTRL;
318	priv->sspa1_div.shift = SSPA_AUD_CTRL_SSPA1_DIV_SHIFT;
319	priv->sspa1_div.width = 6;
320	priv->sspa1_div.flags = CLK_DIVIDER_ONE_BASED;
321	priv->sspa1_div.flags |= CLK_DIVIDER_ROUND_CLOSEST;
322	priv->sspa1_div.flags |= CLK_DIVIDER_ALLOW_ZERO;
323	ret = devm_clk_hw_register(dev, &priv->sspa1_div.hw);
324	if (ret)
325		return ret;
326
327	priv->sspa1_gate.hw.init = CLK_HW_INIT_HW("sspa1_clk",
328				&priv->sspa1_div.hw, &clk_gate_ops,
329				CLK_SET_RATE_PARENT);
330	priv->sspa1_gate.reg = priv->mmio_base + SSPA_AUD_CTRL;
331	priv->sspa1_gate.bit_idx = SSPA_AUD_CTRL_SSPA1_SHIFT;
332	ret = devm_clk_hw_register(dev, &priv->sspa1_gate.hw);
333	if (ret)
334		return ret;
335
336	priv->clk_data.hws[MMP2_CLK_AUDIO_SYSCLK] = &priv->sysclk_gate.hw;
337	priv->clk_data.hws[MMP2_CLK_AUDIO_SSPA0] = &priv->sspa0_gate.hw;
338	priv->clk_data.hws[MMP2_CLK_AUDIO_SSPA1] = &priv->sspa1_gate.hw;
339	priv->clk_data.num = MMP2_CLK_AUDIO_NR_CLKS;
340
341	return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
342				      &priv->clk_data);
343}
344
345static int mmp2_audio_clk_probe(struct platform_device *pdev)
346{
347	struct mmp2_audio_clk *priv;
348	int ret;
349
350	priv = devm_kzalloc(&pdev->dev,
351			    struct_size(priv, clk_data.hws,
352					MMP2_CLK_AUDIO_NR_CLKS),
353			    GFP_KERNEL);
354	if (!priv)
355		return -ENOMEM;
356
357	spin_lock_init(&priv->lock);
358	platform_set_drvdata(pdev, priv);
359
360	priv->mmio_base = devm_platform_ioremap_resource(pdev, 0);
361	if (IS_ERR(priv->mmio_base))
362		return PTR_ERR(priv->mmio_base);
363
364	pm_runtime_enable(&pdev->dev);
365	ret = pm_clk_create(&pdev->dev);
366	if (ret)
367		goto disable_pm_runtime;
368
369	ret = pm_clk_add(&pdev->dev, "audio");
370	if (ret)
371		goto destroy_pm_clk;
372
373	ret = register_clocks(priv, &pdev->dev);
374	if (ret)
375		goto destroy_pm_clk;
376
377	return 0;
378
379destroy_pm_clk:
380	pm_clk_destroy(&pdev->dev);
381disable_pm_runtime:
382	pm_runtime_disable(&pdev->dev);
383
384	return ret;
385}
386
387static int mmp2_audio_clk_remove(struct platform_device *pdev)
388{
389	pm_clk_destroy(&pdev->dev);
390	pm_runtime_disable(&pdev->dev);
391
392	return 0;
393}
394
395#ifdef CONFIG_PM
396static int mmp2_audio_clk_suspend(struct device *dev)
397{
398	struct mmp2_audio_clk *priv = dev_get_drvdata(dev);
399
400	priv->aud_ctrl = readl(priv->mmio_base + SSPA_AUD_CTRL);
401	priv->aud_pll_ctrl0 = readl(priv->mmio_base + SSPA_AUD_PLL_CTRL0);
402	priv->aud_pll_ctrl1 = readl(priv->mmio_base + SSPA_AUD_PLL_CTRL1);
403	pm_clk_suspend(dev);
404
405	return 0;
406}
407
408static int mmp2_audio_clk_resume(struct device *dev)
409{
410	struct mmp2_audio_clk *priv = dev_get_drvdata(dev);
411
412	pm_clk_resume(dev);
413	writel(priv->aud_ctrl, priv->mmio_base + SSPA_AUD_CTRL);
414	writel(priv->aud_pll_ctrl0, priv->mmio_base + SSPA_AUD_PLL_CTRL0);
415	writel(priv->aud_pll_ctrl1, priv->mmio_base + SSPA_AUD_PLL_CTRL1);
416
417	return 0;
418}
419#endif
420
421static const struct dev_pm_ops mmp2_audio_clk_pm_ops = {
422	SET_RUNTIME_PM_OPS(mmp2_audio_clk_suspend, mmp2_audio_clk_resume, NULL)
423};
424
425static const struct of_device_id mmp2_audio_clk_of_match[] = {
426	{ .compatible = "marvell,mmp2-audio-clock" },
427	{}
428};
429
430MODULE_DEVICE_TABLE(of, mmp2_audio_clk_of_match);
431
432static struct platform_driver mmp2_audio_clk_driver = {
433	.driver = {
434		.name = "mmp2-audio-clock",
435		.of_match_table = of_match_ptr(mmp2_audio_clk_of_match),
436		.pm = &mmp2_audio_clk_pm_ops,
437	},
438	.probe = mmp2_audio_clk_probe,
439	.remove = mmp2_audio_clk_remove,
440};
441module_platform_driver(mmp2_audio_clk_driver);
442
443MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
444MODULE_DESCRIPTION("Clock driver for MMP2 Audio subsystem");
445MODULE_LICENSE("GPL");
446