xref: /linux/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
1d91612d7SSamuel Holland // SPDX-License-Identifier: GPL-2.0-only
2d91612d7SSamuel Holland //
3d91612d7SSamuel Holland // Copyright (c) 2021 Samuel Holland <samuel@sholland.org>
4d91612d7SSamuel Holland //
5d91612d7SSamuel Holland 
6d91612d7SSamuel Holland #include <linux/clk.h>
7d91612d7SSamuel Holland #include <linux/clk-provider.h>
8a96cbb14SRob Herring #include <linux/device.h>
9d91612d7SSamuel Holland #include <linux/io.h>
10d91612d7SSamuel Holland #include <linux/module.h>
11a96cbb14SRob Herring #include <linux/of.h>
12d91612d7SSamuel Holland #include <linux/of_device.h>
13d91612d7SSamuel Holland 
141521ca5bSAlexandre Belloni #include <linux/clk/sunxi-ng.h>
151521ca5bSAlexandre Belloni 
16d91612d7SSamuel Holland #include "ccu_common.h"
17d91612d7SSamuel Holland 
18d91612d7SSamuel Holland #include "ccu_div.h"
19d91612d7SSamuel Holland #include "ccu_gate.h"
20d91612d7SSamuel Holland #include "ccu_mux.h"
21d91612d7SSamuel Holland 
22d91612d7SSamuel Holland #include "ccu-sun6i-rtc.h"
23d91612d7SSamuel Holland 
24d91612d7SSamuel Holland #define IOSC_ACCURACY			300000000 /* 30% */
25d91612d7SSamuel Holland #define IOSC_RATE			16000000
26d91612d7SSamuel Holland 
27d91612d7SSamuel Holland #define LOSC_RATE			32768
28d91612d7SSamuel Holland #define LOSC_RATE_SHIFT			15
29d91612d7SSamuel Holland 
30d91612d7SSamuel Holland #define LOSC_CTRL_REG			0x0
31d91612d7SSamuel Holland #define LOSC_CTRL_KEY			0x16aa0000
32d91612d7SSamuel Holland 
33d91612d7SSamuel Holland #define IOSC_32K_CLK_DIV_REG		0x8
34d91612d7SSamuel Holland #define IOSC_32K_CLK_DIV		GENMASK(4, 0)
35d91612d7SSamuel Holland #define IOSC_32K_PRE_DIV		32
36d91612d7SSamuel Holland 
37d91612d7SSamuel Holland #define IOSC_CLK_CALI_REG		0xc
38d91612d7SSamuel Holland #define IOSC_CLK_CALI_DIV_ONES		22
39d91612d7SSamuel Holland #define IOSC_CLK_CALI_EN		BIT(1)
40d91612d7SSamuel Holland #define IOSC_CLK_CALI_SRC_SEL		BIT(0)
41d91612d7SSamuel Holland 
42d91612d7SSamuel Holland #define LOSC_OUT_GATING_REG		0x60
43d91612d7SSamuel Holland 
44d91612d7SSamuel Holland #define DCXO_CTRL_REG			0x160
45d91612d7SSamuel Holland #define DCXO_CTRL_CLK16M_RC_EN		BIT(0)
46d91612d7SSamuel Holland 
47d91612d7SSamuel Holland struct sun6i_rtc_match_data {
48d91612d7SSamuel Holland 	bool				have_ext_osc32k		: 1;
49d91612d7SSamuel Holland 	bool				have_iosc_calibration	: 1;
50d91612d7SSamuel Holland 	bool				rtc_32k_single_parent	: 1;
51d91612d7SSamuel Holland 	const struct clk_parent_data	*osc32k_fanout_parents;
52d91612d7SSamuel Holland 	u8				osc32k_fanout_nparents;
53d91612d7SSamuel Holland };
54d91612d7SSamuel Holland 
55d91612d7SSamuel Holland static bool have_iosc_calibration;
56d91612d7SSamuel Holland 
ccu_iosc_enable(struct clk_hw * hw)57d91612d7SSamuel Holland static int ccu_iosc_enable(struct clk_hw *hw)
58d91612d7SSamuel Holland {
59d91612d7SSamuel Holland 	struct ccu_common *cm = hw_to_ccu_common(hw);
60d91612d7SSamuel Holland 
61d91612d7SSamuel Holland 	return ccu_gate_helper_enable(cm, DCXO_CTRL_CLK16M_RC_EN);
62d91612d7SSamuel Holland }
63d91612d7SSamuel Holland 
ccu_iosc_disable(struct clk_hw * hw)64d91612d7SSamuel Holland static void ccu_iosc_disable(struct clk_hw *hw)
65d91612d7SSamuel Holland {
66d91612d7SSamuel Holland 	struct ccu_common *cm = hw_to_ccu_common(hw);
67d91612d7SSamuel Holland 
68d91612d7SSamuel Holland 	return ccu_gate_helper_disable(cm, DCXO_CTRL_CLK16M_RC_EN);
69d91612d7SSamuel Holland }
70d91612d7SSamuel Holland 
ccu_iosc_is_enabled(struct clk_hw * hw)71d91612d7SSamuel Holland static int ccu_iosc_is_enabled(struct clk_hw *hw)
72d91612d7SSamuel Holland {
73d91612d7SSamuel Holland 	struct ccu_common *cm = hw_to_ccu_common(hw);
74d91612d7SSamuel Holland 
75d91612d7SSamuel Holland 	return ccu_gate_helper_is_enabled(cm, DCXO_CTRL_CLK16M_RC_EN);
76d91612d7SSamuel Holland }
77d91612d7SSamuel Holland 
ccu_iosc_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)78d91612d7SSamuel Holland static unsigned long ccu_iosc_recalc_rate(struct clk_hw *hw,
79d91612d7SSamuel Holland 					  unsigned long parent_rate)
80d91612d7SSamuel Holland {
81d91612d7SSamuel Holland 	struct ccu_common *cm = hw_to_ccu_common(hw);
82d91612d7SSamuel Holland 
83d91612d7SSamuel Holland 	if (have_iosc_calibration) {
84d91612d7SSamuel Holland 		u32 reg = readl(cm->base + IOSC_CLK_CALI_REG);
85d91612d7SSamuel Holland 
86d91612d7SSamuel Holland 		/*
87d91612d7SSamuel Holland 		 * Recover the IOSC frequency by shifting the ones place of
88d91612d7SSamuel Holland 		 * (fixed-point divider * 32768) into bit zero.
89d91612d7SSamuel Holland 		 */
90d91612d7SSamuel Holland 		if (reg & IOSC_CLK_CALI_EN)
91d91612d7SSamuel Holland 			return reg >> (IOSC_CLK_CALI_DIV_ONES - LOSC_RATE_SHIFT);
92d91612d7SSamuel Holland 	}
93d91612d7SSamuel Holland 
94d91612d7SSamuel Holland 	return IOSC_RATE;
95d91612d7SSamuel Holland }
96d91612d7SSamuel Holland 
ccu_iosc_recalc_accuracy(struct clk_hw * hw,unsigned long parent_accuracy)97d91612d7SSamuel Holland static unsigned long ccu_iosc_recalc_accuracy(struct clk_hw *hw,
98d91612d7SSamuel Holland 					      unsigned long parent_accuracy)
99d91612d7SSamuel Holland {
100d91612d7SSamuel Holland 	return IOSC_ACCURACY;
101d91612d7SSamuel Holland }
102d91612d7SSamuel Holland 
103d91612d7SSamuel Holland static const struct clk_ops ccu_iosc_ops = {
104d91612d7SSamuel Holland 	.enable			= ccu_iosc_enable,
105d91612d7SSamuel Holland 	.disable		= ccu_iosc_disable,
106d91612d7SSamuel Holland 	.is_enabled		= ccu_iosc_is_enabled,
107d91612d7SSamuel Holland 	.recalc_rate		= ccu_iosc_recalc_rate,
108d91612d7SSamuel Holland 	.recalc_accuracy	= ccu_iosc_recalc_accuracy,
109d91612d7SSamuel Holland };
110d91612d7SSamuel Holland 
111d91612d7SSamuel Holland static struct ccu_common iosc_clk = {
112d91612d7SSamuel Holland 	.reg		= DCXO_CTRL_REG,
113d91612d7SSamuel Holland 	.hw.init	= CLK_HW_INIT_NO_PARENT("iosc", &ccu_iosc_ops,
114d91612d7SSamuel Holland 						CLK_GET_RATE_NOCACHE),
115d91612d7SSamuel Holland };
116d91612d7SSamuel Holland 
ccu_iosc_32k_prepare(struct clk_hw * hw)117d91612d7SSamuel Holland static int ccu_iosc_32k_prepare(struct clk_hw *hw)
118d91612d7SSamuel Holland {
119d91612d7SSamuel Holland 	struct ccu_common *cm = hw_to_ccu_common(hw);
120d91612d7SSamuel Holland 	u32 val;
121d91612d7SSamuel Holland 
122d91612d7SSamuel Holland 	if (!have_iosc_calibration)
123d91612d7SSamuel Holland 		return 0;
124d91612d7SSamuel Holland 
125d91612d7SSamuel Holland 	val = readl(cm->base + IOSC_CLK_CALI_REG);
126d91612d7SSamuel Holland 	writel(val | IOSC_CLK_CALI_EN | IOSC_CLK_CALI_SRC_SEL,
127d91612d7SSamuel Holland 	       cm->base + IOSC_CLK_CALI_REG);
128d91612d7SSamuel Holland 
129d91612d7SSamuel Holland 	return 0;
130d91612d7SSamuel Holland }
131d91612d7SSamuel Holland 
ccu_iosc_32k_unprepare(struct clk_hw * hw)132d91612d7SSamuel Holland static void ccu_iosc_32k_unprepare(struct clk_hw *hw)
133d91612d7SSamuel Holland {
134d91612d7SSamuel Holland 	struct ccu_common *cm = hw_to_ccu_common(hw);
135d91612d7SSamuel Holland 	u32 val;
136d91612d7SSamuel Holland 
137d91612d7SSamuel Holland 	if (!have_iosc_calibration)
138d91612d7SSamuel Holland 		return;
139d91612d7SSamuel Holland 
140d91612d7SSamuel Holland 	val = readl(cm->base + IOSC_CLK_CALI_REG);
141d91612d7SSamuel Holland 	writel(val & ~(IOSC_CLK_CALI_EN | IOSC_CLK_CALI_SRC_SEL),
142d91612d7SSamuel Holland 	       cm->base + IOSC_CLK_CALI_REG);
143d91612d7SSamuel Holland }
144d91612d7SSamuel Holland 
ccu_iosc_32k_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)145d91612d7SSamuel Holland static unsigned long ccu_iosc_32k_recalc_rate(struct clk_hw *hw,
146d91612d7SSamuel Holland 					      unsigned long parent_rate)
147d91612d7SSamuel Holland {
148d91612d7SSamuel Holland 	struct ccu_common *cm = hw_to_ccu_common(hw);
149d91612d7SSamuel Holland 	u32 val;
150d91612d7SSamuel Holland 
151d91612d7SSamuel Holland 	if (have_iosc_calibration) {
152d91612d7SSamuel Holland 		val = readl(cm->base + IOSC_CLK_CALI_REG);
153d91612d7SSamuel Holland 
154d91612d7SSamuel Holland 		/* Assume the calibrated 32k clock is accurate. */
155d91612d7SSamuel Holland 		if (val & IOSC_CLK_CALI_SRC_SEL)
156d91612d7SSamuel Holland 			return LOSC_RATE;
157d91612d7SSamuel Holland 	}
158d91612d7SSamuel Holland 
159d91612d7SSamuel Holland 	val = readl(cm->base + IOSC_32K_CLK_DIV_REG) & IOSC_32K_CLK_DIV;
160d91612d7SSamuel Holland 
161d91612d7SSamuel Holland 	return parent_rate / IOSC_32K_PRE_DIV / (val + 1);
162d91612d7SSamuel Holland }
163d91612d7SSamuel Holland 
ccu_iosc_32k_recalc_accuracy(struct clk_hw * hw,unsigned long parent_accuracy)164d91612d7SSamuel Holland static unsigned long ccu_iosc_32k_recalc_accuracy(struct clk_hw *hw,
165d91612d7SSamuel Holland 						  unsigned long parent_accuracy)
166d91612d7SSamuel Holland {
167d91612d7SSamuel Holland 	struct ccu_common *cm = hw_to_ccu_common(hw);
168d91612d7SSamuel Holland 	u32 val;
169d91612d7SSamuel Holland 
170d91612d7SSamuel Holland 	if (have_iosc_calibration) {
171d91612d7SSamuel Holland 		val = readl(cm->base + IOSC_CLK_CALI_REG);
172d91612d7SSamuel Holland 
173d91612d7SSamuel Holland 		/* Assume the calibrated 32k clock is accurate. */
174d91612d7SSamuel Holland 		if (val & IOSC_CLK_CALI_SRC_SEL)
175d91612d7SSamuel Holland 			return 0;
176d91612d7SSamuel Holland 	}
177d91612d7SSamuel Holland 
178d91612d7SSamuel Holland 	return parent_accuracy;
179d91612d7SSamuel Holland }
180d91612d7SSamuel Holland 
181d91612d7SSamuel Holland static const struct clk_ops ccu_iosc_32k_ops = {
182d91612d7SSamuel Holland 	.prepare		= ccu_iosc_32k_prepare,
183d91612d7SSamuel Holland 	.unprepare		= ccu_iosc_32k_unprepare,
184d91612d7SSamuel Holland 	.recalc_rate		= ccu_iosc_32k_recalc_rate,
185d91612d7SSamuel Holland 	.recalc_accuracy	= ccu_iosc_32k_recalc_accuracy,
186d91612d7SSamuel Holland };
187d91612d7SSamuel Holland 
188d91612d7SSamuel Holland static struct ccu_common iosc_32k_clk = {
189d91612d7SSamuel Holland 	.hw.init	= CLK_HW_INIT_HW("iosc-32k", &iosc_clk.hw,
190d91612d7SSamuel Holland 					 &ccu_iosc_32k_ops,
191d91612d7SSamuel Holland 					 CLK_GET_RATE_NOCACHE),
192d91612d7SSamuel Holland };
193d91612d7SSamuel Holland 
194d91612d7SSamuel Holland static const struct clk_hw *ext_osc32k[] = { NULL }; /* updated during probe */
195d91612d7SSamuel Holland 
196d91612d7SSamuel Holland static SUNXI_CCU_GATE_HWS(ext_osc32k_gate_clk, "ext-osc32k-gate",
197d91612d7SSamuel Holland 			  ext_osc32k, 0x0, BIT(4), 0);
198d91612d7SSamuel Holland 
199d91612d7SSamuel Holland static const struct clk_hw *osc32k_parents[] = {
200d91612d7SSamuel Holland 	&iosc_32k_clk.hw,
201d91612d7SSamuel Holland 	&ext_osc32k_gate_clk.common.hw
202d91612d7SSamuel Holland };
203d91612d7SSamuel Holland 
204d91612d7SSamuel Holland static struct clk_init_data osc32k_init_data = {
205d91612d7SSamuel Holland 	.name		= "osc32k",
206d91612d7SSamuel Holland 	.ops		= &ccu_mux_ops,
207d91612d7SSamuel Holland 	.parent_hws	= osc32k_parents,
208d91612d7SSamuel Holland 	.num_parents	= ARRAY_SIZE(osc32k_parents), /* updated during probe */
209d91612d7SSamuel Holland };
210d91612d7SSamuel Holland 
211d91612d7SSamuel Holland static struct ccu_mux osc32k_clk = {
212d91612d7SSamuel Holland 	.mux	= _SUNXI_CCU_MUX(0, 1),
213d91612d7SSamuel Holland 	.common	= {
214d91612d7SSamuel Holland 		.reg		= LOSC_CTRL_REG,
215d91612d7SSamuel Holland 		.features	= CCU_FEATURE_KEY_FIELD,
216d91612d7SSamuel Holland 		.hw.init	= &osc32k_init_data,
217d91612d7SSamuel Holland 	},
218d91612d7SSamuel Holland };
219d91612d7SSamuel Holland 
220d91612d7SSamuel Holland /* This falls back to the global name for fwnodes without a named reference. */
221d91612d7SSamuel Holland static const struct clk_parent_data osc24M[] = {
222d91612d7SSamuel Holland 	{ .fw_name = "hosc", .name = "osc24M" }
223d91612d7SSamuel Holland };
224d91612d7SSamuel Holland 
225d91612d7SSamuel Holland static struct ccu_gate osc24M_32k_clk = {
226d91612d7SSamuel Holland 	.enable	= BIT(16),
227d91612d7SSamuel Holland 	.common	= {
228d91612d7SSamuel Holland 		.reg		= LOSC_OUT_GATING_REG,
229d91612d7SSamuel Holland 		.prediv		= 750,
230d91612d7SSamuel Holland 		.features	= CCU_FEATURE_ALL_PREDIV,
231d91612d7SSamuel Holland 		.hw.init	= CLK_HW_INIT_PARENTS_DATA("osc24M-32k", osc24M,
232d91612d7SSamuel Holland 							   &ccu_gate_ops, 0),
233d91612d7SSamuel Holland 	},
234d91612d7SSamuel Holland };
235d91612d7SSamuel Holland 
236d91612d7SSamuel Holland static const struct clk_hw *rtc_32k_parents[] = {
237d91612d7SSamuel Holland 	&osc32k_clk.common.hw,
238d91612d7SSamuel Holland 	&osc24M_32k_clk.common.hw
239d91612d7SSamuel Holland };
240d91612d7SSamuel Holland 
241d91612d7SSamuel Holland static struct clk_init_data rtc_32k_init_data = {
242d91612d7SSamuel Holland 	.name		= "rtc-32k",
243d91612d7SSamuel Holland 	.ops		= &ccu_mux_ops,
244d91612d7SSamuel Holland 	.parent_hws	= rtc_32k_parents,
245d91612d7SSamuel Holland 	.num_parents	= ARRAY_SIZE(rtc_32k_parents), /* updated during probe */
246b4f3d5f0SSamuel Holland 	.flags		= CLK_IS_CRITICAL,
247d91612d7SSamuel Holland };
248d91612d7SSamuel Holland 
249d91612d7SSamuel Holland static struct ccu_mux rtc_32k_clk = {
250d91612d7SSamuel Holland 	.mux	= _SUNXI_CCU_MUX(1, 1),
251d91612d7SSamuel Holland 	.common	= {
252d91612d7SSamuel Holland 		.reg		= LOSC_CTRL_REG,
253d91612d7SSamuel Holland 		.features	= CCU_FEATURE_KEY_FIELD,
254d91612d7SSamuel Holland 		.hw.init	= &rtc_32k_init_data,
255d91612d7SSamuel Holland 	},
256d91612d7SSamuel Holland };
257d91612d7SSamuel Holland 
258d91612d7SSamuel Holland static struct clk_init_data osc32k_fanout_init_data = {
259d91612d7SSamuel Holland 	.name		= "osc32k-fanout",
260d91612d7SSamuel Holland 	.ops		= &ccu_mux_ops,
261d91612d7SSamuel Holland 	/* parents are set during probe */
262d91612d7SSamuel Holland };
263d91612d7SSamuel Holland 
264d91612d7SSamuel Holland static struct ccu_mux osc32k_fanout_clk = {
265d91612d7SSamuel Holland 	.enable	= BIT(0),
266d91612d7SSamuel Holland 	.mux	= _SUNXI_CCU_MUX(1, 2),
267d91612d7SSamuel Holland 	.common	= {
268d91612d7SSamuel Holland 		.reg		= LOSC_OUT_GATING_REG,
269d91612d7SSamuel Holland 		.hw.init	= &osc32k_fanout_init_data,
270d91612d7SSamuel Holland 	},
271d91612d7SSamuel Holland };
272d91612d7SSamuel Holland 
273d91612d7SSamuel Holland static struct ccu_common *sun6i_rtc_ccu_clks[] = {
274d91612d7SSamuel Holland 	&iosc_clk,
275d91612d7SSamuel Holland 	&iosc_32k_clk,
276d91612d7SSamuel Holland 	&ext_osc32k_gate_clk.common,
277d91612d7SSamuel Holland 	&osc32k_clk.common,
278d91612d7SSamuel Holland 	&osc24M_32k_clk.common,
279d91612d7SSamuel Holland 	&rtc_32k_clk.common,
280d91612d7SSamuel Holland 	&osc32k_fanout_clk.common,
281d91612d7SSamuel Holland };
282d91612d7SSamuel Holland 
283d91612d7SSamuel Holland static struct clk_hw_onecell_data sun6i_rtc_ccu_hw_clks = {
284d91612d7SSamuel Holland 	.num = CLK_NUMBER,
285d91612d7SSamuel Holland 	.hws = {
286d91612d7SSamuel Holland 		[CLK_OSC32K]		= &osc32k_clk.common.hw,
287d91612d7SSamuel Holland 		[CLK_OSC32K_FANOUT]	= &osc32k_fanout_clk.common.hw,
288d91612d7SSamuel Holland 		[CLK_IOSC]		= &iosc_clk.hw,
289d91612d7SSamuel Holland 		[CLK_IOSC_32K]		= &iosc_32k_clk.hw,
290d91612d7SSamuel Holland 		[CLK_EXT_OSC32K_GATE]	= &ext_osc32k_gate_clk.common.hw,
291d91612d7SSamuel Holland 		[CLK_OSC24M_32K]	= &osc24M_32k_clk.common.hw,
292d91612d7SSamuel Holland 		[CLK_RTC_32K]		= &rtc_32k_clk.common.hw,
293d91612d7SSamuel Holland 	},
294d91612d7SSamuel Holland };
295d91612d7SSamuel Holland 
296d91612d7SSamuel Holland static const struct sunxi_ccu_desc sun6i_rtc_ccu_desc = {
297d91612d7SSamuel Holland 	.ccu_clks	= sun6i_rtc_ccu_clks,
298d91612d7SSamuel Holland 	.num_ccu_clks	= ARRAY_SIZE(sun6i_rtc_ccu_clks),
299d91612d7SSamuel Holland 
300d91612d7SSamuel Holland 	.hw_clks	= &sun6i_rtc_ccu_hw_clks,
301d91612d7SSamuel Holland };
302d91612d7SSamuel Holland 
303d91612d7SSamuel Holland static const struct clk_parent_data sun50i_h616_osc32k_fanout_parents[] = {
304d91612d7SSamuel Holland 	{ .hw = &osc32k_clk.common.hw },
305d91612d7SSamuel Holland 	{ .fw_name = "pll-32k" },
306d91612d7SSamuel Holland 	{ .hw = &osc24M_32k_clk.common.hw }
307d91612d7SSamuel Holland };
308d91612d7SSamuel Holland 
309d91612d7SSamuel Holland static const struct clk_parent_data sun50i_r329_osc32k_fanout_parents[] = {
310d91612d7SSamuel Holland 	{ .hw = &osc32k_clk.common.hw },
311d91612d7SSamuel Holland 	{ .hw = &ext_osc32k_gate_clk.common.hw },
312d91612d7SSamuel Holland 	{ .hw = &osc24M_32k_clk.common.hw }
313d91612d7SSamuel Holland };
314d91612d7SSamuel Holland 
315d91612d7SSamuel Holland static const struct sun6i_rtc_match_data sun50i_h616_rtc_ccu_data = {
316d91612d7SSamuel Holland 	.have_iosc_calibration	= true,
317d91612d7SSamuel Holland 	.rtc_32k_single_parent	= true,
318d91612d7SSamuel Holland 	.osc32k_fanout_parents	= sun50i_h616_osc32k_fanout_parents,
319d91612d7SSamuel Holland 	.osc32k_fanout_nparents	= ARRAY_SIZE(sun50i_h616_osc32k_fanout_parents),
320d91612d7SSamuel Holland };
321d91612d7SSamuel Holland 
322d91612d7SSamuel Holland static const struct sun6i_rtc_match_data sun50i_r329_rtc_ccu_data = {
323d91612d7SSamuel Holland 	.have_ext_osc32k	= true,
324d91612d7SSamuel Holland 	.osc32k_fanout_parents	= sun50i_r329_osc32k_fanout_parents,
325d91612d7SSamuel Holland 	.osc32k_fanout_nparents	= ARRAY_SIZE(sun50i_r329_osc32k_fanout_parents),
326d91612d7SSamuel Holland };
327d91612d7SSamuel Holland 
328d91612d7SSamuel Holland static const struct of_device_id sun6i_rtc_ccu_match[] = {
329d91612d7SSamuel Holland 	{
330d91612d7SSamuel Holland 		.compatible	= "allwinner,sun50i-h616-rtc",
331d91612d7SSamuel Holland 		.data		= &sun50i_h616_rtc_ccu_data,
332d91612d7SSamuel Holland 	},
333d91612d7SSamuel Holland 	{
334d91612d7SSamuel Holland 		.compatible	= "allwinner,sun50i-r329-rtc",
335d91612d7SSamuel Holland 		.data		= &sun50i_r329_rtc_ccu_data,
336d91612d7SSamuel Holland 	},
337c887bdc4SWan Jiabing 	{},
338d91612d7SSamuel Holland };
339c60f6804SKrzysztof Kozlowski MODULE_DEVICE_TABLE(of, sun6i_rtc_ccu_match);
340d91612d7SSamuel Holland 
sun6i_rtc_ccu_probe(struct device * dev,void __iomem * reg)341d91612d7SSamuel Holland int sun6i_rtc_ccu_probe(struct device *dev, void __iomem *reg)
342d91612d7SSamuel Holland {
343d91612d7SSamuel Holland 	const struct sun6i_rtc_match_data *data;
344d91612d7SSamuel Holland 	struct clk *ext_osc32k_clk = NULL;
345d91612d7SSamuel Holland 	const struct of_device_id *match;
346d91612d7SSamuel Holland 
347d91612d7SSamuel Holland 	/* This driver is only used for newer variants of the hardware. */
348d91612d7SSamuel Holland 	match = of_match_device(sun6i_rtc_ccu_match, dev);
349d91612d7SSamuel Holland 	if (!match)
350d91612d7SSamuel Holland 		return 0;
351d91612d7SSamuel Holland 
352d91612d7SSamuel Holland 	data = match->data;
353d91612d7SSamuel Holland 	have_iosc_calibration = data->have_iosc_calibration;
354d91612d7SSamuel Holland 
355d91612d7SSamuel Holland 	if (data->have_ext_osc32k) {
356d91612d7SSamuel Holland 		const char *fw_name;
357d91612d7SSamuel Holland 
358d91612d7SSamuel Holland 		/* ext-osc32k was the only input clock in the old binding. */
359d91612d7SSamuel Holland 		fw_name = of_property_read_bool(dev->of_node, "clock-names")
360d91612d7SSamuel Holland 			? "ext-osc32k" : NULL;
361d91612d7SSamuel Holland 		ext_osc32k_clk = devm_clk_get_optional(dev, fw_name);
362d91612d7SSamuel Holland 		if (IS_ERR(ext_osc32k_clk))
363d91612d7SSamuel Holland 			return PTR_ERR(ext_osc32k_clk);
364d91612d7SSamuel Holland 	}
365d91612d7SSamuel Holland 
366d91612d7SSamuel Holland 	if (ext_osc32k_clk) {
367d91612d7SSamuel Holland 		/* Link ext-osc32k-gate to its parent. */
368d91612d7SSamuel Holland 		*ext_osc32k = __clk_get_hw(ext_osc32k_clk);
369d91612d7SSamuel Holland 	} else {
370d91612d7SSamuel Holland 		/* ext-osc32k-gate is an orphan, so do not register it. */
371d91612d7SSamuel Holland 		sun6i_rtc_ccu_hw_clks.hws[CLK_EXT_OSC32K_GATE] = NULL;
372d91612d7SSamuel Holland 		osc32k_init_data.num_parents = 1;
373d91612d7SSamuel Holland 	}
374d91612d7SSamuel Holland 
375d91612d7SSamuel Holland 	if (data->rtc_32k_single_parent)
376d91612d7SSamuel Holland 		rtc_32k_init_data.num_parents = 1;
377d91612d7SSamuel Holland 
378d91612d7SSamuel Holland 	osc32k_fanout_init_data.parent_data = data->osc32k_fanout_parents;
379d91612d7SSamuel Holland 	osc32k_fanout_init_data.num_parents = data->osc32k_fanout_nparents;
380d91612d7SSamuel Holland 
381d91612d7SSamuel Holland 	return devm_sunxi_ccu_probe(dev, reg, &sun6i_rtc_ccu_desc);
382d91612d7SSamuel Holland }
383d91612d7SSamuel Holland 
384d91612d7SSamuel Holland MODULE_IMPORT_NS(SUNXI_CCU);
385*4e7134faSJeff Johnson MODULE_DESCRIPTION("Support for the Allwinner H616/R329 RTC CCU");
386d91612d7SSamuel Holland MODULE_LICENSE("GPL");
387