• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * sunxi RTC ccu driver
3  *
4  * Copyright (c) 2020, Martin <wuyan@allwinnertech.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16  */
17 #include <linux/init.h>
18 #include <linux/kernel.h>
19 #include <linux/module.h>
20 #include <linux/err.h>
21 #include <linux/of.h>
22 #include <linux/of_address.h>
23 #include <linux/of_device.h>
24 #include <linux/rtc.h>
25 #include <linux/types.h>
26 #include <linux/delay.h>
27 #include <linux/clk.h>
28 #include <linux/clk-provider.h>
29 
30 /* set the parent of osc32k-out fixed to osc32k-sys, to simplify the clock tree */
31 #define OSC32KOUT_PARENT_FIX_TO_OSC32KSYS	1
32 
33 #define LOSC_CTRL_REG			0x00
34 #define KEY_FIELD_MAGIC			0x16AA0000
35 #define LOSC_SRC_SEL			BIT(0)  /* 0: from RC16M; 1: from external OSC (ext-osc32k) */
36 #define RTC_SRC_SEL			BIT(1)  /* 0: osc32k-sys; 1: dcxo24M-div-32k */
37 #define LOSC_AUTO_SWT_32K_SEL_EN	BIT(14) /* LOSC auto switch 32k clk source sel enable. 1: enable */
38 #define LOSC_AUTO_SWT_DISABLE		BIT(15)	/* LOSC auto switch function disable. 1: disable */
39 #define EXT_LOSC_GSM			(0x2 << 2)  /* 0x8 */
40 
41 /* sun8iw20 does not have this register */
42 #define INTOSC_CLK_AUTO_CALI_REG	0x0C
43 #define RC_CLK_SRC_SEL			BIT(0)  /* 0: Normal RC; 1: Calibrated RC */
44 #define RC_CALI_EN			BIT(1)  /* 0: disable; 1: enable */
45 
46 #define LOSC_OUT_GATING_REG		0x60  /* Or: 32K_FOUT_CTRL_GATING_REG */
47 #define BIT_INDEX_LOSC_OUT_GATING	0     /* bit 0 of LOSC_OUT_GATING_REG. 0: disable output; 1: enable output */
48 #define BIT_INDEX_LOSC_OUT_SRC_SEL	1     /* bit 1~2 of LOSC_OUT_GATING_REG */
49 #define BIT_WIDTH_LOSC_OUT_SRC_SEL	2     /* 2 bits are used */
50 #define LOSC_OUT_SRC_SEL_32K_SYS	0x0   /* 0b00: osc32k-sys */
51 #define LOSC_OUT_SRC_SEL_32K_EXT	0x1   /* 0b01: ext-osc32k */
52 #define LOSC_OUT_SRC_SEL_32K_DCXO	0x2   /* 0b10: dcxo24M-div-32k */
53 #define LOSC_OUT_SRC_SEL_MASK		0x3   /* 0b11: bit mask */
54 #define HOSC_TO_32K_DIVIDER_ENABLE	BIT(16)  /* 0: disable; 1: enable */
55 
56 #define XO_CTRL_REG			0x160  /* XO Control register */
57 #define BIT_INDEX_CLK_REQ_ENB		31     /* bit 31 of XO_CTRL_REG. 0: enable; 1: disable */
58 #define DCXO_EN				BIT(1) /* 0: disable; 1: enable */
59 
60 /* sun8iw20 does not have this register */
61 #define CALI_CTRL_REG			0x164
62 #define WAKEUP_DCXO_EN			BIT(31)  /* 0: ��У׼; 1: �ػ�У׼ */
63 
64 #define CLK_PARENT_CNT_MAX		3  /* the max count of a clock's parent */
65 
66 struct sunxi_rtc_ccu;  /* Forward declaration */
67 typedef int (*clk_reg_fn)(struct sunxi_rtc_ccu *priv, int clk_index);
68 
69 struct clk_info {
70 	char *clk_name;
71 	char *parent_names[CLK_PARENT_CNT_MAX];  /* Must be NULL terminated */
72 	clk_reg_fn reg_fn;  /* The function to register this clock */
73 	clk_reg_fn unreg_fn;  /* The function to unregister this clock */
74 };
75 
76 struct sunxi_rtc_ccu_hw_data {
77 	bool support_cali;  /* Does the hardware support RC-16M calibration circuit? */
78 	bool support_rtc_src_sel;  /* Does the RTC_SRC_SEL bit exist? */
79 	struct clk_info *clk_info_table; /* Must be NULL terminated */
80 };
81 
82 /* Driver's private resource */
83 struct sunxi_rtc_ccu {
84 	struct sunxi_rtc_ccu_hw_data *hw_data;
85 	struct device *dev;
86 	void __iomem *reg_base;
87 	struct clk **clks;
88 	int clks_num;
89 };
90 
config_clock_tree(struct sunxi_rtc_ccu * priv)91 static void config_clock_tree(struct sunxi_rtc_ccu *priv)
92 {
93 	__maybe_unused struct device *dev = priv->dev;
94 	struct sunxi_rtc_ccu_hw_data *hw_data = priv->hw_data;
95 	void __iomem *reg_base = priv->reg_base;
96 	void __iomem *reg;
97 	u32 val;
98 
99 	/* Let's make it easier by simplify the clock tree: make it a fixed tree */
100 
101 	/* (1) enable DCXO */
102 	/* by default, DCXO_EN = 1. We don't have to do this... */
103 	reg = reg_base + XO_CTRL_REG;
104 	val = readl(reg);
105 	val |= DCXO_EN;
106 	writel(val, reg);
107 
108 	/* (2) enable calibrated RC-16M, and switch to it */
109 	if (hw_data->support_cali) {
110 		reg = reg_base + CALI_CTRL_REG;
111 		val = readl(reg);
112 		val &= ~WAKEUP_DCXO_EN;
113 		writel(val, reg);
114 		reg = reg_base + INTOSC_CLK_AUTO_CALI_REG;
115 		val = readl(reg);
116 		val |= RC_CALI_EN;
117 		val |= RC_CLK_SRC_SEL;
118 		writel(val, reg);
119 	}
120 
121 	/* (3) enable auto switch function */
122 	/*
123 	 * In some cases, we boot with auto switch function disabled, and try to
124 	 * enable the auto switch function by rebooting.
125 	 * But the rtc default value does not change unless vcc-rtc is loss.
126 	 * So we should not rely on the default value of reg.
127 	 */
128 	reg = reg_base + LOSC_CTRL_REG;
129 	val = readl(reg);
130 	val &= ~LOSC_AUTO_SWT_DISABLE;
131 	val |= LOSC_AUTO_SWT_32K_SEL_EN;
132 	val |= KEY_FIELD_MAGIC;
133 	writel(val, reg);
134 
135 	/* (4) set the parent of osc32k-sys to ext-osc32k */
136 	reg = reg_base + LOSC_CTRL_REG;
137 	val = readl(reg);
138 	val |= LOSC_SRC_SEL;
139 	val |= KEY_FIELD_MAGIC;
140 	writel(val, reg);
141 
142 	/* (5) set the parent of rtc-32k to osc32k-sys */
143 	if (hw_data->support_rtc_src_sel) {
144 		/* by default, RTC_SRC_SEL = 0x0. We don't have to do this... */
145 		reg = reg_base + LOSC_CTRL_REG;
146 		val = readl(reg);
147 		val &= ~RTC_SRC_SEL;
148 		val |= KEY_FIELD_MAGIC;
149 		writel(val, reg);
150 	}
151 
152 #if OSC32KOUT_PARENT_FIX_TO_OSC32KSYS
153 	/* (6) set the parent of osc32k-out to osc32k-sys */
154 	/* by default, LOSC_OUT_SRC_SEL = 0x0. We don't have to do this... */
155 	reg = reg_base + LOSC_OUT_GATING_REG;
156 	val = readl(reg);
157 	val &= ~(LOSC_OUT_SRC_SEL_MASK << BIT_INDEX_LOSC_OUT_SRC_SEL);
158 	val |= (LOSC_OUT_SRC_SEL_32K_SYS << BIT_INDEX_LOSC_OUT_SRC_SEL);
159 	writel(val, reg);
160 #else
161 	/* (6) enable dcxo24M-div-32k */
162 	reg = reg_base + LOSC_OUT_GATING_REG;
163 	val = readl(reg);
164 	val |= HOSC_TO_32K_DIVIDER_ENABLE;
165 	writel(val, reg);
166 #endif
167 
168 	/* Now we have a fixed clock tree, we can treat as many as possible clocks as fixed clock */
169 }
170 
171 /* dcxo24M-out: DCXO 24M output to WiFi */
register_dcxo24M_out_as_gate(struct sunxi_rtc_ccu * priv,int clk_index)172 static int register_dcxo24M_out_as_gate(struct sunxi_rtc_ccu *priv, int clk_index)
173 {
174 	struct sunxi_rtc_ccu_hw_data *hw_data = priv->hw_data;
175 	struct device *dev = priv->dev;
176 	void __iomem *reg_base = priv->reg_base;
177 	struct clk_info *clk_info = &(hw_data->clk_info_table[clk_index]);
178 	const char *clkname;
179 	char *parent_clkname;
180 	void __iomem *reg;
181 	int bit_idx;
182 	u8 flags;
183 
184 	clkname = clk_info->clk_name;
185 	parent_clkname = clk_info->parent_names[0];  /* There should be only one parent for gate clock */
186 	reg = reg_base + XO_CTRL_REG;
187 	bit_idx = BIT_INDEX_CLK_REQ_ENB;
188 	flags = CLK_GATE_SET_TO_DISABLE;
189 	priv->clks[clk_index] = clk_register_gate(NULL, clkname, parent_clkname, 0, reg, bit_idx, flags, NULL);
190 	if (IS_ERR(priv->clks[clk_index])) {
191 		dev_err(dev, "Couldn't register clk '%s'\n", clkname);
192 		return PTR_ERR(priv->clks[clk_index]);
193 	}
194 
195 	return 0;
196 }
unregister_dcxo24M_out_as_gate(struct sunxi_rtc_ccu * priv,int clk_index)197 static int unregister_dcxo24M_out_as_gate(struct sunxi_rtc_ccu *priv, int clk_index)
198 {
199 	clk_unregister_gate(priv->clks[clk_index]);
200 	return 0;
201 }
202 
203 /* iosc: Internal RC 16M */
register_iosc_as_fixed_rate(struct sunxi_rtc_ccu * priv,int clk_index)204 static int register_iosc_as_fixed_rate(struct sunxi_rtc_ccu *priv, int clk_index)
205 {
206 	struct sunxi_rtc_ccu_hw_data *hw_data = priv->hw_data;
207 	struct device *dev = priv->dev;
208 	struct clk_info *clk_info = &(hw_data->clk_info_table[clk_index]);
209 	const char *clkname;
210 	char *parent_clkname;
211 	unsigned long fixed_rate;
212 
213 	clkname = clk_info->clk_name;
214 	parent_clkname = clk_info->parent_names[0];  /* There should be only one parent for fixed rate clock */
215 	fixed_rate = 16000000;
216 	priv->clks[clk_index] = clk_register_fixed_rate(NULL, clkname, parent_clkname, 0, fixed_rate);
217 	if (IS_ERR(priv->clks[clk_index])) {
218 		dev_err(dev, "Couldn't register clk '%s'\n", clkname);
219 		return PTR_ERR(priv->clks[clk_index]);
220 	}
221 
222 	return 0;
223 }
unregister_iosc_as_fixed_rate(struct sunxi_rtc_ccu * priv,int clk_index)224 static int unregister_iosc_as_fixed_rate(struct sunxi_rtc_ccu *priv, int clk_index)
225 {
226 	clk_unregister_fixed_rate(priv->clks[clk_index]);
227 	return 0;
228 }
229 
230 /* osc32k (osc32k-sys): internal 32k to the system */
register_osc32k_as_fixed_rate(struct sunxi_rtc_ccu * priv,int clk_index)231 static int register_osc32k_as_fixed_rate(struct sunxi_rtc_ccu *priv, int clk_index)
232 {
233 	struct sunxi_rtc_ccu_hw_data *hw_data = priv->hw_data;
234 	struct device *dev = priv->dev;
235 	struct clk_info *clk_info = &(hw_data->clk_info_table[clk_index]);
236 	const char *clkname;
237 	char *parent_clkname;
238 	unsigned long fixed_rate;
239 
240 	clkname = clk_info->clk_name;
241 	parent_clkname = clk_info->parent_names[0];  /* There should be only one parent for fixed rate clock */
242 	fixed_rate = 32768;
243 	priv->clks[clk_index] = clk_register_fixed_rate(NULL, clkname, parent_clkname, 0, fixed_rate);
244 	if (IS_ERR(priv->clks[clk_index])) {
245 		dev_err(dev, "Couldn't register clk '%s'\n", clkname);
246 		return PTR_ERR(priv->clks[clk_index]);
247 	}
248 
249 	return 0;
250 }
unregister_osc32k_as_fixed_rate(struct sunxi_rtc_ccu * priv,int clk_index)251 static int unregister_osc32k_as_fixed_rate(struct sunxi_rtc_ccu *priv, int clk_index)
252 {
253 	clk_unregister_fixed_rate(priv->clks[clk_index]);
254 	return 0;
255 }
256 
257 /* osc32k-out: 32k output on pin */
register_osc32k_out_as_gate(struct sunxi_rtc_ccu * priv,int clk_index)258 static int register_osc32k_out_as_gate(struct sunxi_rtc_ccu *priv, int clk_index)
259 {
260 	struct sunxi_rtc_ccu_hw_data *hw_data = priv->hw_data;
261 	struct device *dev = priv->dev;
262 	void __iomem *reg_base = priv->reg_base;
263 	struct clk_info *clk_info = &(hw_data->clk_info_table[clk_index]);
264 	const char *clkname;
265 	char *parent_clkname;
266 	void __iomem *reg;
267 	int bit_idx;
268 	u8 flags;
269 
270 	clkname = clk_info->clk_name;
271 	parent_clkname = clk_info->parent_names[0];  /* There should be only one parent for gate clock */
272 	reg = reg_base + LOSC_OUT_GATING_REG;
273 	bit_idx = BIT_INDEX_LOSC_OUT_GATING;
274 	flags = 0;
275 	priv->clks[clk_index] = clk_register_gate(NULL, clkname, parent_clkname, 0, reg, bit_idx, flags, NULL);
276 	if (IS_ERR(priv->clks[clk_index])) {
277 		dev_err(dev, "Couldn't register clk '%s'\n", clkname);
278 		return PTR_ERR(priv->clks[clk_index]);
279 	}
280 
281 	return 0;
282 }
unregister_osc32k_out_as_gate(struct sunxi_rtc_ccu * priv,int clk_index)283 static int unregister_osc32k_out_as_gate(struct sunxi_rtc_ccu *priv, int clk_index)
284 {
285 	clk_unregister_gate(priv->clks[clk_index]);
286 	return 0;
287 }
288 
289 /* rtc-1k = osc32k / 32 */
register_rtc_1k_as_fixed_factor(struct sunxi_rtc_ccu * priv,int clk_index)290 static int register_rtc_1k_as_fixed_factor(struct sunxi_rtc_ccu *priv, int clk_index)
291 {
292 	struct sunxi_rtc_ccu_hw_data *hw_data = priv->hw_data;
293 	struct device *dev = priv->dev;
294 	struct clk_info *clk_info = &(hw_data->clk_info_table[clk_index]);
295 	const char *clkname;
296 	char *parent_clkname;
297 	u8 flags;
298 	unsigned int mult;
299 	unsigned int div;
300 
301 	clkname = clk_info->clk_name;
302 	parent_clkname = clk_info->parent_names[0];  /* There should be only one parent for fixed factor clock */
303 	flags = 0;
304 	mult = 1;
305 	div = 32;
306 	priv->clks[clk_index] = clk_register_fixed_factor(NULL, clkname, parent_clkname, flags, mult, div);
307 	if (IS_ERR(priv->clks[clk_index])) {
308 		dev_err(dev, "Couldn't register clk '%s'\n", clkname);
309 		return PTR_ERR(priv->clks[clk_index]);
310 	}
311 
312 	return 0;
313 }
unregister_rtc_1k_as_fixed_factor(struct sunxi_rtc_ccu * priv,int clk_index)314 static int unregister_rtc_1k_as_fixed_factor(struct sunxi_rtc_ccu *priv, int clk_index)
315 {
316 	clk_unregister_fixed_factor(priv->clks[clk_index]);
317 	return 0;
318 }
319 
sunxi_rtc_clk_provider_register(struct sunxi_rtc_ccu * priv)320 static int sunxi_rtc_clk_provider_register(struct sunxi_rtc_ccu *priv)
321 {
322 	struct sunxi_rtc_ccu_hw_data *hw_data = priv->hw_data;
323 	struct clk_info *clk_info_table = hw_data->clk_info_table;
324 	struct device *dev = priv->dev;
325 	struct clk_hw_onecell_data *clk_data;
326 	int err;
327 	int i;
328 
329 	config_clock_tree(priv);
330 
331 	for (i = 0; clk_info_table[i].clk_name; i++)  /* get the clks_num */
332 		priv->clks_num++;
333 	priv->clks = devm_kzalloc(dev, priv->clks_num * sizeof(priv->clks), GFP_KERNEL);
334 	if (!priv->clks) {
335 		dev_err(dev, "Fail to alloc memory for priv->clks\n");
336 		return -ENOMEM;
337 	}
338 
339 	for (i = 0; i < priv->clks_num; i++) {
340 		dev_info(dev, "Registering clk '%s'\n", clk_info_table[i].clk_name);
341 		err = clk_info_table[i].reg_fn(priv, i);
342 		if (err) {
343 			while (i--)
344 				clk_info_table[i].unreg_fn(priv, i);
345 			return err;
346 		}
347 	}
348 
349 	clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, priv->clks_num), GFP_KERNEL);
350 	if (!clk_data) {
351 		dev_err(dev, "Fail to alloc memory for clk_data\n");
352 		return -ENOMEM;
353 	}
354 
355 	clk_data->num = priv->clks_num;
356 	for (i = 0; i < clk_data->num; i++)
357 		clk_data->hws[i] = __clk_get_hw(priv->clks[i]);
358 	err = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data);
359 	if (err) {
360 		dev_err(dev, "Fail to add clk provider\n");
361 		return err;
362 	}
363 
364 	return 0;
365 }
366 
sunxi_rtc_clk_provider_unregister(struct sunxi_rtc_ccu * priv)367 static void sunxi_rtc_clk_provider_unregister(struct sunxi_rtc_ccu *priv)
368 {
369 }
370 
371 static struct clk_info sun50iw10_clk_info_table[] = {
372 	/* Keep it in the same order with the DT-BINDINGS in include/dt-bindings/clock/sun50iw10-rtc.h */
373 	{
374 		.clk_name = "dcxo24M-out",
375 		.parent_names = { "dcxo24M", NULL },
376 		.reg_fn = register_dcxo24M_out_as_gate,
377 		.unreg_fn = unregister_dcxo24M_out_as_gate,
378 	},
379 	{
380 		.clk_name = "iosc",
381 		.parent_names = { NULL },
382 		.reg_fn = register_iosc_as_fixed_rate,
383 		.unreg_fn = unregister_iosc_as_fixed_rate,
384 	},
385 	{
386 		.clk_name = "osc32k",
387 		.parent_names = { NULL },
388 		.reg_fn = register_osc32k_as_fixed_rate,
389 		.unreg_fn = unregister_osc32k_as_fixed_rate,
390 	},
391 #if OSC32KOUT_PARENT_FIX_TO_OSC32KSYS
392 	{
393 		.clk_name = "osc32k-out",
394 		.parent_names = { "osc32k", NULL },
395 		.reg_fn = register_osc32k_out_as_gate,
396 		.unreg_fn = unregister_osc32k_out_as_gate,
397 	},
398 #else
399 	/* @TODO */
400 #endif
401 	{
402 		.clk_name = "rtc-1k",
403 		.parent_names = { "osc32k", NULL },
404 		.reg_fn = register_rtc_1k_as_fixed_factor,
405 		.unreg_fn = unregister_rtc_1k_as_fixed_factor,
406 	},
407 	{
408 		/* sentinel */
409 	},
410 };
411 
412 static struct clk_info sun50iw12_clk_info_table[] = {
413 	/* Keep it in the same order with the DT-BINDINGS in include/dt-bindings/clock/sun50iw12-rtc.h */
414 	{
415 		.clk_name = "dcxo24M-out",
416 		.parent_names = { "dcxo24M", NULL },
417 		.reg_fn = register_dcxo24M_out_as_gate,
418 		.unreg_fn = unregister_dcxo24M_out_as_gate,
419 	},
420 #if OSC32KOUT_PARENT_FIX_TO_OSC32KSYS
421 	{
422 		.clk_name = "osc32k-out",
423 		.parent_names = { "osc32k", NULL },
424 		.reg_fn = register_osc32k_out_as_gate,
425 		.unreg_fn = unregister_osc32k_out_as_gate,
426 	},
427 #else
428 	/* @TODO */
429 #endif
430 	{
431 		.clk_name = "rtc-1k",
432 		.parent_names = { "osc32k", NULL },
433 		.reg_fn = register_rtc_1k_as_fixed_factor,
434 		.unreg_fn = unregister_rtc_1k_as_fixed_factor,
435 	},
436 	{
437 		/* sentinel */
438 	},
439 };
440 
441 static struct sunxi_rtc_ccu_hw_data sun50iw10_hw_data = {
442 	.support_cali = true,
443 	.support_rtc_src_sel = false,
444 	.clk_info_table = sun50iw10_clk_info_table,
445 };
446 
447 static struct sunxi_rtc_ccu_hw_data sun50iw12_hw_data = {
448 	.support_cali = true,
449 	.support_rtc_src_sel = false,
450 	.clk_info_table = sun50iw12_clk_info_table,
451 };
452 
453 static const struct of_device_id sunxi_rtc_ccu_dt_ids[] = {
454 	{ .compatible = "allwinner,sun50iw10p1-rtc-ccu", .data = &sun50iw10_hw_data },
455 	{ .compatible = "allwinner,sun50iw12p1-rtc-ccu", .data = &sun50iw12_hw_data },
456 	{ /* sentinel */ },
457 };
458 MODULE_DEVICE_TABLE(of, sunxi_rtc_ccu_dt_ids);
459 
sunxi_rtc_ccu_probe(struct platform_device * pdev)460 static int sunxi_rtc_ccu_probe(struct platform_device *pdev)
461 {
462 	struct sunxi_rtc_ccu *priv;
463 	struct device *dev = &pdev->dev;
464 	const struct of_device_id *of_id;
465 	struct resource *res;
466 	int err;
467 
468 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
469 	if (!priv)
470 		return -ENOMEM;
471 
472 	of_id = of_match_device(sunxi_rtc_ccu_dt_ids, dev);
473 	if (!of_id) {
474 		dev_err(dev, "of_match_device() failed\n");
475 		return -EINVAL;
476 	}
477 	priv->hw_data = (struct sunxi_rtc_ccu_hw_data *)(of_id->data);
478 
479 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
480 	if (!res) {
481 		dev_err(dev, "Fail to get IORESOURCE_MEM\n");
482 		return -EINVAL;
483 	}
484 
485 	/*
486 	 * Don't use devm_ioremap_resource() here! Or else the RTC driver will
487 	 * not able to get the same resource later in rtc-sunxi.c.
488 	 */
489 	//priv->reg_base = devm_ioremap_resource(dev, res);
490 	priv->reg_base = devm_ioremap(dev, res->start, resource_size(res));
491 	if (IS_ERR(priv->reg_base)) {
492 		dev_err(dev, "Fail to map IO resource\n");
493 		return PTR_ERR(priv->reg_base);
494 	}
495 
496 	platform_set_drvdata(pdev, priv);
497 	priv->dev = dev;
498 
499 	/* Register clk providers */
500 	err = sunxi_rtc_clk_provider_register(priv);
501 	if (err) {
502 		dev_err(dev, "sunxi_rtc_clk_provider_register() failed\n");
503 		return err;
504 	}
505 
506 	dev_info(dev, "sunxi rtc-ccu probed\n");
507 	return 0;
508 }
509 
sunxi_rtc_ccu_remove(struct platform_device * pdev)510 static int sunxi_rtc_ccu_remove(struct platform_device *pdev)
511 {
512 	struct sunxi_rtc_ccu *priv = platform_get_drvdata(pdev);
513 
514 	sunxi_rtc_clk_provider_unregister(priv);
515 
516 	return 0;
517 }
518 
519 static struct platform_driver sunxi_rtc_ccu = {
520 	.probe    = sunxi_rtc_ccu_probe,
521 	.remove   = sunxi_rtc_ccu_remove,
522 	.driver   = {
523 		.name  = "sunxi-rtc-ccu",
524 		.owner = THIS_MODULE,
525 		.of_match_table = sunxi_rtc_ccu_dt_ids,
526 	},
527 };
528 
sunxi_rtc_ccu_init(void)529 static int __init sunxi_rtc_ccu_init(void)
530 {
531 	int err;
532 
533 	err = platform_driver_register(&sunxi_rtc_ccu);
534 	if (err)
535 		pr_err("Fail to register sunxi_rtc_ccu as platform device\n");
536 
537 	return err;
538 }
539 core_initcall(sunxi_rtc_ccu_init);
540 
sunxi_rtc_ccu_exit(void)541 static void __exit sunxi_rtc_ccu_exit(void)
542 {
543 	platform_driver_unregister(&sunxi_rtc_ccu);
544 }
545 module_exit(sunxi_rtc_ccu_exit);
546 
547 MODULE_DESCRIPTION("sunxi RTC CCU driver");
548 MODULE_AUTHOR("Martin <wuyan@allwinnertech.com>");
549 MODULE_LICENSE("GPL v2");
550 MODULE_VERSION("1.1.0");
551