xref: /openbmc/linux/drivers/rtc/rtc-sc27xx.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
1*07869941SNobuhiro Iwamatsu // SPDX-License-Identifier: GPL-2.0
2495bbde5SBaolin Wang /*
3495bbde5SBaolin Wang  * Copyright (C) 2017 Spreadtrum Communications Inc.
4495bbde5SBaolin Wang  *
5495bbde5SBaolin Wang  */
6495bbde5SBaolin Wang 
7495bbde5SBaolin Wang #include <linux/bitops.h>
8495bbde5SBaolin Wang #include <linux/delay.h>
9495bbde5SBaolin Wang #include <linux/err.h>
10495bbde5SBaolin Wang #include <linux/module.h>
11495bbde5SBaolin Wang #include <linux/of.h>
12495bbde5SBaolin Wang #include <linux/platform_device.h>
13495bbde5SBaolin Wang #include <linux/regmap.h>
14495bbde5SBaolin Wang #include <linux/rtc.h>
15495bbde5SBaolin Wang 
16495bbde5SBaolin Wang #define SPRD_RTC_SEC_CNT_VALUE		0x0
17495bbde5SBaolin Wang #define SPRD_RTC_MIN_CNT_VALUE		0x4
18495bbde5SBaolin Wang #define SPRD_RTC_HOUR_CNT_VALUE		0x8
19495bbde5SBaolin Wang #define SPRD_RTC_DAY_CNT_VALUE		0xc
20495bbde5SBaolin Wang #define SPRD_RTC_SEC_CNT_UPD		0x10
21495bbde5SBaolin Wang #define SPRD_RTC_MIN_CNT_UPD		0x14
22495bbde5SBaolin Wang #define SPRD_RTC_HOUR_CNT_UPD		0x18
23495bbde5SBaolin Wang #define SPRD_RTC_DAY_CNT_UPD		0x1c
24495bbde5SBaolin Wang #define SPRD_RTC_SEC_ALM_UPD		0x20
25495bbde5SBaolin Wang #define SPRD_RTC_MIN_ALM_UPD		0x24
26495bbde5SBaolin Wang #define SPRD_RTC_HOUR_ALM_UPD		0x28
27495bbde5SBaolin Wang #define SPRD_RTC_DAY_ALM_UPD		0x2c
28495bbde5SBaolin Wang #define SPRD_RTC_INT_EN			0x30
29495bbde5SBaolin Wang #define SPRD_RTC_INT_RAW_STS		0x34
30495bbde5SBaolin Wang #define SPRD_RTC_INT_CLR		0x38
31495bbde5SBaolin Wang #define SPRD_RTC_INT_MASK_STS		0x3C
32495bbde5SBaolin Wang #define SPRD_RTC_SEC_ALM_VALUE		0x40
33495bbde5SBaolin Wang #define SPRD_RTC_MIN_ALM_VALUE		0x44
34495bbde5SBaolin Wang #define SPRD_RTC_HOUR_ALM_VALUE		0x48
35495bbde5SBaolin Wang #define SPRD_RTC_DAY_ALM_VALUE		0x4c
36495bbde5SBaolin Wang #define SPRD_RTC_SPG_VALUE		0x50
37495bbde5SBaolin Wang #define SPRD_RTC_SPG_UPD		0x54
38a0defd7cSBaolin Wang #define SPRD_RTC_PWR_CTRL		0x58
39a0defd7cSBaolin Wang #define SPRD_RTC_PWR_STS		0x5c
40495bbde5SBaolin Wang #define SPRD_RTC_SEC_AUXALM_UPD		0x60
41495bbde5SBaolin Wang #define SPRD_RTC_MIN_AUXALM_UPD		0x64
42495bbde5SBaolin Wang #define SPRD_RTC_HOUR_AUXALM_UPD	0x68
43495bbde5SBaolin Wang #define SPRD_RTC_DAY_AUXALM_UPD		0x6c
44495bbde5SBaolin Wang 
45495bbde5SBaolin Wang /* BIT & MASK definition for SPRD_RTC_INT_* registers */
46495bbde5SBaolin Wang #define SPRD_RTC_SEC_EN			BIT(0)
47495bbde5SBaolin Wang #define SPRD_RTC_MIN_EN			BIT(1)
48495bbde5SBaolin Wang #define SPRD_RTC_HOUR_EN		BIT(2)
49495bbde5SBaolin Wang #define SPRD_RTC_DAY_EN			BIT(3)
50495bbde5SBaolin Wang #define SPRD_RTC_ALARM_EN		BIT(4)
51495bbde5SBaolin Wang #define SPRD_RTC_HRS_FORMAT_EN		BIT(5)
52495bbde5SBaolin Wang #define SPRD_RTC_AUXALM_EN		BIT(6)
53495bbde5SBaolin Wang #define SPRD_RTC_SPG_UPD_EN		BIT(7)
54495bbde5SBaolin Wang #define SPRD_RTC_SEC_UPD_EN		BIT(8)
55495bbde5SBaolin Wang #define SPRD_RTC_MIN_UPD_EN		BIT(9)
56495bbde5SBaolin Wang #define SPRD_RTC_HOUR_UPD_EN		BIT(10)
57495bbde5SBaolin Wang #define SPRD_RTC_DAY_UPD_EN		BIT(11)
58495bbde5SBaolin Wang #define SPRD_RTC_ALMSEC_UPD_EN		BIT(12)
59495bbde5SBaolin Wang #define SPRD_RTC_ALMMIN_UPD_EN		BIT(13)
60495bbde5SBaolin Wang #define SPRD_RTC_ALMHOUR_UPD_EN		BIT(14)
61495bbde5SBaolin Wang #define SPRD_RTC_ALMDAY_UPD_EN		BIT(15)
62495bbde5SBaolin Wang #define SPRD_RTC_INT_MASK		GENMASK(15, 0)
63495bbde5SBaolin Wang 
64495bbde5SBaolin Wang #define SPRD_RTC_TIME_INT_MASK				\
65495bbde5SBaolin Wang 	(SPRD_RTC_SEC_UPD_EN | SPRD_RTC_MIN_UPD_EN |	\
66495bbde5SBaolin Wang 	 SPRD_RTC_HOUR_UPD_EN | SPRD_RTC_DAY_UPD_EN)
67495bbde5SBaolin Wang 
68495bbde5SBaolin Wang #define SPRD_RTC_ALMTIME_INT_MASK				\
69495bbde5SBaolin Wang 	(SPRD_RTC_ALMSEC_UPD_EN | SPRD_RTC_ALMMIN_UPD_EN |	\
70495bbde5SBaolin Wang 	 SPRD_RTC_ALMHOUR_UPD_EN | SPRD_RTC_ALMDAY_UPD_EN)
71495bbde5SBaolin Wang 
72495bbde5SBaolin Wang #define SPRD_RTC_ALM_INT_MASK			\
73495bbde5SBaolin Wang 	(SPRD_RTC_SEC_EN | SPRD_RTC_MIN_EN |	\
74495bbde5SBaolin Wang 	 SPRD_RTC_HOUR_EN | SPRD_RTC_DAY_EN |	\
75495bbde5SBaolin Wang 	 SPRD_RTC_ALARM_EN | SPRD_RTC_AUXALM_EN)
76495bbde5SBaolin Wang 
77495bbde5SBaolin Wang /* second/minute/hour/day values mask definition */
78495bbde5SBaolin Wang #define SPRD_RTC_SEC_MASK		GENMASK(5, 0)
79495bbde5SBaolin Wang #define SPRD_RTC_MIN_MASK		GENMASK(5, 0)
80495bbde5SBaolin Wang #define SPRD_RTC_HOUR_MASK		GENMASK(4, 0)
81495bbde5SBaolin Wang #define SPRD_RTC_DAY_MASK		GENMASK(15, 0)
82495bbde5SBaolin Wang 
83495bbde5SBaolin Wang /* alarm lock definition for SPRD_RTC_SPG_UPD register */
84495bbde5SBaolin Wang #define SPRD_RTC_ALMLOCK_MASK		GENMASK(7, 0)
85495bbde5SBaolin Wang #define SPRD_RTC_ALM_UNLOCK		0xa5
86495bbde5SBaolin Wang #define SPRD_RTC_ALM_LOCK		(~SPRD_RTC_ALM_UNLOCK &	\
87495bbde5SBaolin Wang 					 SPRD_RTC_ALMLOCK_MASK)
88495bbde5SBaolin Wang 
89495bbde5SBaolin Wang /* SPG values definition for SPRD_RTC_SPG_UPD register */
90495bbde5SBaolin Wang #define SPRD_RTC_POWEROFF_ALM_FLAG	BIT(8)
91a0defd7cSBaolin Wang 
92a0defd7cSBaolin Wang /* power control/status definition */
93a0defd7cSBaolin Wang #define SPRD_RTC_POWER_RESET_VALUE	0x96
94a0defd7cSBaolin Wang #define SPRD_RTC_POWER_STS_CLEAR	GENMASK(7, 0)
95a0defd7cSBaolin Wang #define SPRD_RTC_POWER_STS_SHIFT	8
96a0defd7cSBaolin Wang #define SPRD_RTC_POWER_STS_VALID	\
97a0defd7cSBaolin Wang 	(~SPRD_RTC_POWER_RESET_VALUE << SPRD_RTC_POWER_STS_SHIFT)
98495bbde5SBaolin Wang 
99495bbde5SBaolin Wang /* timeout of synchronizing time and alarm registers (us) */
100495bbde5SBaolin Wang #define SPRD_RTC_POLL_TIMEOUT		200000
101495bbde5SBaolin Wang #define SPRD_RTC_POLL_DELAY_US		20000
102495bbde5SBaolin Wang 
103495bbde5SBaolin Wang struct sprd_rtc {
104495bbde5SBaolin Wang 	struct rtc_device	*rtc;
105495bbde5SBaolin Wang 	struct regmap		*regmap;
106495bbde5SBaolin Wang 	struct device		*dev;
107495bbde5SBaolin Wang 	u32			base;
108495bbde5SBaolin Wang 	int			irq;
109495bbde5SBaolin Wang 	bool			valid;
110495bbde5SBaolin Wang };
111495bbde5SBaolin Wang 
112495bbde5SBaolin Wang /*
113495bbde5SBaolin Wang  * The Spreadtrum RTC controller has 3 groups registers, including time, normal
114495bbde5SBaolin Wang  * alarm and auxiliary alarm. The time group registers are used to set RTC time,
115495bbde5SBaolin Wang  * the normal alarm registers are used to set normal alarm, and the auxiliary
116495bbde5SBaolin Wang  * alarm registers are used to set auxiliary alarm. Both alarm event and
117495bbde5SBaolin Wang  * auxiliary alarm event can wake up system from deep sleep, but only alarm
118495bbde5SBaolin Wang  * event can power up system from power down status.
119495bbde5SBaolin Wang  */
120495bbde5SBaolin Wang enum sprd_rtc_reg_types {
121495bbde5SBaolin Wang 	SPRD_RTC_TIME,
122495bbde5SBaolin Wang 	SPRD_RTC_ALARM,
123495bbde5SBaolin Wang 	SPRD_RTC_AUX_ALARM,
124495bbde5SBaolin Wang };
125495bbde5SBaolin Wang 
sprd_rtc_clear_alarm_ints(struct sprd_rtc * rtc)126495bbde5SBaolin Wang static int sprd_rtc_clear_alarm_ints(struct sprd_rtc *rtc)
127495bbde5SBaolin Wang {
128495bbde5SBaolin Wang 	return regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
129495bbde5SBaolin Wang 			    SPRD_RTC_ALM_INT_MASK);
130495bbde5SBaolin Wang }
131495bbde5SBaolin Wang 
sprd_rtc_lock_alarm(struct sprd_rtc * rtc,bool lock)132495bbde5SBaolin Wang static int sprd_rtc_lock_alarm(struct sprd_rtc *rtc, bool lock)
133495bbde5SBaolin Wang {
134495bbde5SBaolin Wang 	int ret;
135495bbde5SBaolin Wang 	u32 val;
136495bbde5SBaolin Wang 
137495bbde5SBaolin Wang 	ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_SPG_VALUE, &val);
138495bbde5SBaolin Wang 	if (ret)
139495bbde5SBaolin Wang 		return ret;
140495bbde5SBaolin Wang 
141e02e3ddaSBaolin Wang 	val &= ~SPRD_RTC_ALMLOCK_MASK;
142495bbde5SBaolin Wang 	if (lock)
143495bbde5SBaolin Wang 		val |= SPRD_RTC_ALM_LOCK;
144495bbde5SBaolin Wang 	else
145495bbde5SBaolin Wang 		val |= SPRD_RTC_ALM_UNLOCK | SPRD_RTC_POWEROFF_ALM_FLAG;
146495bbde5SBaolin Wang 
147495bbde5SBaolin Wang 	ret = regmap_write(rtc->regmap, rtc->base + SPRD_RTC_SPG_UPD, val);
148495bbde5SBaolin Wang 	if (ret)
149495bbde5SBaolin Wang 		return ret;
150495bbde5SBaolin Wang 
151495bbde5SBaolin Wang 	/* wait until the SPG value is updated successfully */
152495bbde5SBaolin Wang 	ret = regmap_read_poll_timeout(rtc->regmap,
153495bbde5SBaolin Wang 				       rtc->base + SPRD_RTC_INT_RAW_STS, val,
154495bbde5SBaolin Wang 				       (val & SPRD_RTC_SPG_UPD_EN),
155495bbde5SBaolin Wang 				       SPRD_RTC_POLL_DELAY_US,
156495bbde5SBaolin Wang 				       SPRD_RTC_POLL_TIMEOUT);
157495bbde5SBaolin Wang 	if (ret) {
158495bbde5SBaolin Wang 		dev_err(rtc->dev, "failed to update SPG value:%d\n", ret);
159495bbde5SBaolin Wang 		return ret;
160495bbde5SBaolin Wang 	}
161495bbde5SBaolin Wang 
1627db5adfaSBaolin Wang 	return regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
1637db5adfaSBaolin Wang 			    SPRD_RTC_SPG_UPD_EN);
164495bbde5SBaolin Wang }
165495bbde5SBaolin Wang 
sprd_rtc_get_secs(struct sprd_rtc * rtc,enum sprd_rtc_reg_types type,time64_t * secs)166495bbde5SBaolin Wang static int sprd_rtc_get_secs(struct sprd_rtc *rtc, enum sprd_rtc_reg_types type,
167495bbde5SBaolin Wang 			     time64_t *secs)
168495bbde5SBaolin Wang {
169495bbde5SBaolin Wang 	u32 sec_reg, min_reg, hour_reg, day_reg;
170495bbde5SBaolin Wang 	u32 val, sec, min, hour, day;
171495bbde5SBaolin Wang 	int ret;
172495bbde5SBaolin Wang 
173495bbde5SBaolin Wang 	switch (type) {
174495bbde5SBaolin Wang 	case SPRD_RTC_TIME:
175495bbde5SBaolin Wang 		sec_reg = SPRD_RTC_SEC_CNT_VALUE;
176495bbde5SBaolin Wang 		min_reg = SPRD_RTC_MIN_CNT_VALUE;
177495bbde5SBaolin Wang 		hour_reg = SPRD_RTC_HOUR_CNT_VALUE;
178495bbde5SBaolin Wang 		day_reg = SPRD_RTC_DAY_CNT_VALUE;
179495bbde5SBaolin Wang 		break;
180495bbde5SBaolin Wang 	case SPRD_RTC_ALARM:
181495bbde5SBaolin Wang 		sec_reg = SPRD_RTC_SEC_ALM_VALUE;
182495bbde5SBaolin Wang 		min_reg = SPRD_RTC_MIN_ALM_VALUE;
183495bbde5SBaolin Wang 		hour_reg = SPRD_RTC_HOUR_ALM_VALUE;
184495bbde5SBaolin Wang 		day_reg = SPRD_RTC_DAY_ALM_VALUE;
185495bbde5SBaolin Wang 		break;
186495bbde5SBaolin Wang 	case SPRD_RTC_AUX_ALARM:
187495bbde5SBaolin Wang 		sec_reg = SPRD_RTC_SEC_AUXALM_UPD;
188495bbde5SBaolin Wang 		min_reg = SPRD_RTC_MIN_AUXALM_UPD;
189495bbde5SBaolin Wang 		hour_reg = SPRD_RTC_HOUR_AUXALM_UPD;
190495bbde5SBaolin Wang 		day_reg = SPRD_RTC_DAY_AUXALM_UPD;
191495bbde5SBaolin Wang 		break;
192495bbde5SBaolin Wang 	default:
193495bbde5SBaolin Wang 		return -EINVAL;
194495bbde5SBaolin Wang 	}
195495bbde5SBaolin Wang 
196495bbde5SBaolin Wang 	ret = regmap_read(rtc->regmap, rtc->base + sec_reg, &val);
197495bbde5SBaolin Wang 	if (ret)
198495bbde5SBaolin Wang 		return ret;
199495bbde5SBaolin Wang 
200495bbde5SBaolin Wang 	sec = val & SPRD_RTC_SEC_MASK;
201495bbde5SBaolin Wang 
202495bbde5SBaolin Wang 	ret = regmap_read(rtc->regmap, rtc->base + min_reg, &val);
203495bbde5SBaolin Wang 	if (ret)
204495bbde5SBaolin Wang 		return ret;
205495bbde5SBaolin Wang 
206495bbde5SBaolin Wang 	min = val & SPRD_RTC_MIN_MASK;
207495bbde5SBaolin Wang 
208495bbde5SBaolin Wang 	ret = regmap_read(rtc->regmap, rtc->base + hour_reg, &val);
209495bbde5SBaolin Wang 	if (ret)
210495bbde5SBaolin Wang 		return ret;
211495bbde5SBaolin Wang 
212495bbde5SBaolin Wang 	hour = val & SPRD_RTC_HOUR_MASK;
213495bbde5SBaolin Wang 
214495bbde5SBaolin Wang 	ret = regmap_read(rtc->regmap, rtc->base + day_reg, &val);
215495bbde5SBaolin Wang 	if (ret)
216495bbde5SBaolin Wang 		return ret;
217495bbde5SBaolin Wang 
218495bbde5SBaolin Wang 	day = val & SPRD_RTC_DAY_MASK;
219495bbde5SBaolin Wang 	*secs = (((time64_t)(day * 24) + hour) * 60 + min) * 60 + sec;
220495bbde5SBaolin Wang 	return 0;
221495bbde5SBaolin Wang }
222495bbde5SBaolin Wang 
sprd_rtc_set_secs(struct sprd_rtc * rtc,enum sprd_rtc_reg_types type,time64_t secs)223495bbde5SBaolin Wang static int sprd_rtc_set_secs(struct sprd_rtc *rtc, enum sprd_rtc_reg_types type,
224495bbde5SBaolin Wang 			     time64_t secs)
225495bbde5SBaolin Wang {
226495bbde5SBaolin Wang 	u32 sec_reg, min_reg, hour_reg, day_reg, sts_mask;
227495bbde5SBaolin Wang 	u32 sec, min, hour, day, val;
228495bbde5SBaolin Wang 	int ret, rem;
229495bbde5SBaolin Wang 
230495bbde5SBaolin Wang 	/* convert seconds to RTC time format */
231495bbde5SBaolin Wang 	day = div_s64_rem(secs, 86400, &rem);
232495bbde5SBaolin Wang 	hour = rem / 3600;
233495bbde5SBaolin Wang 	rem -= hour * 3600;
234495bbde5SBaolin Wang 	min = rem / 60;
235495bbde5SBaolin Wang 	sec = rem - min * 60;
236495bbde5SBaolin Wang 
237495bbde5SBaolin Wang 	switch (type) {
238495bbde5SBaolin Wang 	case SPRD_RTC_TIME:
239495bbde5SBaolin Wang 		sec_reg = SPRD_RTC_SEC_CNT_UPD;
240495bbde5SBaolin Wang 		min_reg = SPRD_RTC_MIN_CNT_UPD;
241495bbde5SBaolin Wang 		hour_reg = SPRD_RTC_HOUR_CNT_UPD;
242495bbde5SBaolin Wang 		day_reg = SPRD_RTC_DAY_CNT_UPD;
243495bbde5SBaolin Wang 		sts_mask = SPRD_RTC_TIME_INT_MASK;
244495bbde5SBaolin Wang 		break;
245495bbde5SBaolin Wang 	case SPRD_RTC_ALARM:
246495bbde5SBaolin Wang 		sec_reg = SPRD_RTC_SEC_ALM_UPD;
247495bbde5SBaolin Wang 		min_reg = SPRD_RTC_MIN_ALM_UPD;
248495bbde5SBaolin Wang 		hour_reg = SPRD_RTC_HOUR_ALM_UPD;
249495bbde5SBaolin Wang 		day_reg = SPRD_RTC_DAY_ALM_UPD;
250495bbde5SBaolin Wang 		sts_mask = SPRD_RTC_ALMTIME_INT_MASK;
251495bbde5SBaolin Wang 		break;
252495bbde5SBaolin Wang 	case SPRD_RTC_AUX_ALARM:
253495bbde5SBaolin Wang 		sec_reg = SPRD_RTC_SEC_AUXALM_UPD;
254495bbde5SBaolin Wang 		min_reg = SPRD_RTC_MIN_AUXALM_UPD;
255495bbde5SBaolin Wang 		hour_reg = SPRD_RTC_HOUR_AUXALM_UPD;
256495bbde5SBaolin Wang 		day_reg = SPRD_RTC_DAY_AUXALM_UPD;
257495bbde5SBaolin Wang 		sts_mask = 0;
258495bbde5SBaolin Wang 		break;
259495bbde5SBaolin Wang 	default:
260495bbde5SBaolin Wang 		return -EINVAL;
261495bbde5SBaolin Wang 	}
262495bbde5SBaolin Wang 
263495bbde5SBaolin Wang 	ret = regmap_write(rtc->regmap, rtc->base + sec_reg, sec);
264495bbde5SBaolin Wang 	if (ret)
265495bbde5SBaolin Wang 		return ret;
266495bbde5SBaolin Wang 
267495bbde5SBaolin Wang 	ret = regmap_write(rtc->regmap, rtc->base + min_reg, min);
268495bbde5SBaolin Wang 	if (ret)
269495bbde5SBaolin Wang 		return ret;
270495bbde5SBaolin Wang 
271495bbde5SBaolin Wang 	ret = regmap_write(rtc->regmap, rtc->base + hour_reg, hour);
272495bbde5SBaolin Wang 	if (ret)
273495bbde5SBaolin Wang 		return ret;
274495bbde5SBaolin Wang 
275495bbde5SBaolin Wang 	ret = regmap_write(rtc->regmap, rtc->base + day_reg, day);
276495bbde5SBaolin Wang 	if (ret)
277495bbde5SBaolin Wang 		return ret;
278495bbde5SBaolin Wang 
279495bbde5SBaolin Wang 	if (type == SPRD_RTC_AUX_ALARM)
280495bbde5SBaolin Wang 		return 0;
281495bbde5SBaolin Wang 
282495bbde5SBaolin Wang 	/*
283495bbde5SBaolin Wang 	 * Since the time and normal alarm registers are put in always-power-on
284495bbde5SBaolin Wang 	 * region supplied by VDDRTC, then these registers changing time will
285495bbde5SBaolin Wang 	 * be very long, about 125ms. Thus here we should wait until all
286495bbde5SBaolin Wang 	 * values are updated successfully.
287495bbde5SBaolin Wang 	 */
288495bbde5SBaolin Wang 	ret = regmap_read_poll_timeout(rtc->regmap,
289495bbde5SBaolin Wang 				       rtc->base + SPRD_RTC_INT_RAW_STS, val,
290495bbde5SBaolin Wang 				       ((val & sts_mask) == sts_mask),
291495bbde5SBaolin Wang 				       SPRD_RTC_POLL_DELAY_US,
292495bbde5SBaolin Wang 				       SPRD_RTC_POLL_TIMEOUT);
293495bbde5SBaolin Wang 	if (ret < 0) {
294495bbde5SBaolin Wang 		dev_err(rtc->dev, "set time/alarm values timeout\n");
295495bbde5SBaolin Wang 		return ret;
296495bbde5SBaolin Wang 	}
297495bbde5SBaolin Wang 
298495bbde5SBaolin Wang 	return regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
299495bbde5SBaolin Wang 			    sts_mask);
300495bbde5SBaolin Wang }
301495bbde5SBaolin Wang 
sprd_rtc_set_aux_alarm(struct device * dev,struct rtc_wkalrm * alrm)302495bbde5SBaolin Wang static int sprd_rtc_set_aux_alarm(struct device *dev, struct rtc_wkalrm *alrm)
303495bbde5SBaolin Wang {
304495bbde5SBaolin Wang 	struct sprd_rtc *rtc = dev_get_drvdata(dev);
305495bbde5SBaolin Wang 	time64_t secs = rtc_tm_to_time64(&alrm->time);
306495bbde5SBaolin Wang 	int ret;
307495bbde5SBaolin Wang 
308495bbde5SBaolin Wang 	/* clear the auxiliary alarm interrupt status */
309495bbde5SBaolin Wang 	ret = regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
310495bbde5SBaolin Wang 			   SPRD_RTC_AUXALM_EN);
311495bbde5SBaolin Wang 	if (ret)
312495bbde5SBaolin Wang 		return ret;
313495bbde5SBaolin Wang 
314495bbde5SBaolin Wang 	ret = sprd_rtc_set_secs(rtc, SPRD_RTC_AUX_ALARM, secs);
315495bbde5SBaolin Wang 	if (ret)
316495bbde5SBaolin Wang 		return ret;
317495bbde5SBaolin Wang 
318495bbde5SBaolin Wang 	if (alrm->enabled) {
319495bbde5SBaolin Wang 		ret = regmap_update_bits(rtc->regmap,
320495bbde5SBaolin Wang 					 rtc->base + SPRD_RTC_INT_EN,
321495bbde5SBaolin Wang 					 SPRD_RTC_AUXALM_EN,
322495bbde5SBaolin Wang 					 SPRD_RTC_AUXALM_EN);
323495bbde5SBaolin Wang 	} else {
324495bbde5SBaolin Wang 		ret = regmap_update_bits(rtc->regmap,
325495bbde5SBaolin Wang 					 rtc->base + SPRD_RTC_INT_EN,
326495bbde5SBaolin Wang 					 SPRD_RTC_AUXALM_EN, 0);
327495bbde5SBaolin Wang 	}
328495bbde5SBaolin Wang 
329495bbde5SBaolin Wang 	return ret;
330495bbde5SBaolin Wang }
331495bbde5SBaolin Wang 
sprd_rtc_read_time(struct device * dev,struct rtc_time * tm)332495bbde5SBaolin Wang static int sprd_rtc_read_time(struct device *dev, struct rtc_time *tm)
333495bbde5SBaolin Wang {
334495bbde5SBaolin Wang 	struct sprd_rtc *rtc = dev_get_drvdata(dev);
335495bbde5SBaolin Wang 	time64_t secs;
336495bbde5SBaolin Wang 	int ret;
337495bbde5SBaolin Wang 
338495bbde5SBaolin Wang 	if (!rtc->valid) {
339495bbde5SBaolin Wang 		dev_warn(dev, "RTC values are invalid\n");
340495bbde5SBaolin Wang 		return -EINVAL;
341495bbde5SBaolin Wang 	}
342495bbde5SBaolin Wang 
343495bbde5SBaolin Wang 	ret = sprd_rtc_get_secs(rtc, SPRD_RTC_TIME, &secs);
344495bbde5SBaolin Wang 	if (ret)
345495bbde5SBaolin Wang 		return ret;
346495bbde5SBaolin Wang 
347495bbde5SBaolin Wang 	rtc_time64_to_tm(secs, tm);
34866b32fc5SAlexandre Belloni 	return 0;
349495bbde5SBaolin Wang }
350495bbde5SBaolin Wang 
sprd_rtc_set_time(struct device * dev,struct rtc_time * tm)351495bbde5SBaolin Wang static int sprd_rtc_set_time(struct device *dev, struct rtc_time *tm)
352495bbde5SBaolin Wang {
353495bbde5SBaolin Wang 	struct sprd_rtc *rtc = dev_get_drvdata(dev);
354495bbde5SBaolin Wang 	time64_t secs = rtc_tm_to_time64(tm);
355495bbde5SBaolin Wang 	int ret;
356495bbde5SBaolin Wang 
357495bbde5SBaolin Wang 	ret = sprd_rtc_set_secs(rtc, SPRD_RTC_TIME, secs);
358495bbde5SBaolin Wang 	if (ret)
359495bbde5SBaolin Wang 		return ret;
360495bbde5SBaolin Wang 
361495bbde5SBaolin Wang 	if (!rtc->valid) {
362a0defd7cSBaolin Wang 		/* Clear RTC power status firstly */
363a0defd7cSBaolin Wang 		ret = regmap_write(rtc->regmap, rtc->base + SPRD_RTC_PWR_CTRL,
364a0defd7cSBaolin Wang 				   SPRD_RTC_POWER_STS_CLEAR);
365495bbde5SBaolin Wang 		if (ret)
366495bbde5SBaolin Wang 			return ret;
367495bbde5SBaolin Wang 
368a0defd7cSBaolin Wang 		/*
369a0defd7cSBaolin Wang 		 * Set RTC power status to indicate now RTC has valid time
370a0defd7cSBaolin Wang 		 * values.
371a0defd7cSBaolin Wang 		 */
372a0defd7cSBaolin Wang 		ret = regmap_write(rtc->regmap, rtc->base + SPRD_RTC_PWR_CTRL,
373a0defd7cSBaolin Wang 				   SPRD_RTC_POWER_STS_VALID);
374a0defd7cSBaolin Wang 		if (ret)
375495bbde5SBaolin Wang 			return ret;
376495bbde5SBaolin Wang 
377495bbde5SBaolin Wang 		rtc->valid = true;
378495bbde5SBaolin Wang 	}
379495bbde5SBaolin Wang 
380495bbde5SBaolin Wang 	return 0;
381495bbde5SBaolin Wang }
382495bbde5SBaolin Wang 
sprd_rtc_read_alarm(struct device * dev,struct rtc_wkalrm * alrm)383495bbde5SBaolin Wang static int sprd_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
384495bbde5SBaolin Wang {
385495bbde5SBaolin Wang 	struct sprd_rtc *rtc = dev_get_drvdata(dev);
386495bbde5SBaolin Wang 	time64_t secs;
387495bbde5SBaolin Wang 	int ret;
388495bbde5SBaolin Wang 	u32 val;
389495bbde5SBaolin Wang 
390495bbde5SBaolin Wang 	/*
3917d9d4868SAlexandre Belloni 	 * The RTC core checks to see if there is an alarm already set in RTC
3927d9d4868SAlexandre Belloni 	 * hardware, and we always read the normal alarm at this time.
393495bbde5SBaolin Wang 	 */
394495bbde5SBaolin Wang 	ret = sprd_rtc_get_secs(rtc, SPRD_RTC_ALARM, &secs);
395495bbde5SBaolin Wang 	if (ret)
396495bbde5SBaolin Wang 		return ret;
397495bbde5SBaolin Wang 
398495bbde5SBaolin Wang 	rtc_time64_to_tm(secs, &alrm->time);
399495bbde5SBaolin Wang 
400495bbde5SBaolin Wang 	ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_INT_EN, &val);
401495bbde5SBaolin Wang 	if (ret)
402495bbde5SBaolin Wang 		return ret;
403495bbde5SBaolin Wang 
404495bbde5SBaolin Wang 	alrm->enabled = !!(val & SPRD_RTC_ALARM_EN);
405495bbde5SBaolin Wang 
406495bbde5SBaolin Wang 	ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_INT_RAW_STS, &val);
407495bbde5SBaolin Wang 	if (ret)
408495bbde5SBaolin Wang 		return ret;
409495bbde5SBaolin Wang 
410495bbde5SBaolin Wang 	alrm->pending = !!(val & SPRD_RTC_ALARM_EN);
411495bbde5SBaolin Wang 	return 0;
412495bbde5SBaolin Wang }
413495bbde5SBaolin Wang 
sprd_rtc_set_alarm(struct device * dev,struct rtc_wkalrm * alrm)414495bbde5SBaolin Wang static int sprd_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
415495bbde5SBaolin Wang {
416495bbde5SBaolin Wang 	struct sprd_rtc *rtc = dev_get_drvdata(dev);
417495bbde5SBaolin Wang 	time64_t secs = rtc_tm_to_time64(&alrm->time);
418495bbde5SBaolin Wang 	struct rtc_time aie_time =
419495bbde5SBaolin Wang 		rtc_ktime_to_tm(rtc->rtc->aie_timer.node.expires);
420495bbde5SBaolin Wang 	int ret;
421495bbde5SBaolin Wang 
422495bbde5SBaolin Wang 	/*
423495bbde5SBaolin Wang 	 * We have 2 groups alarms: normal alarm and auxiliary alarm. Since
424495bbde5SBaolin Wang 	 * both normal alarm event and auxiliary alarm event can wake up system
425495bbde5SBaolin Wang 	 * from deep sleep, but only alarm event can power up system from power
426495bbde5SBaolin Wang 	 * down status. Moreover we do not need to poll about 125ms when
427495bbde5SBaolin Wang 	 * updating auxiliary alarm registers. Thus we usually set auxiliary
428495bbde5SBaolin Wang 	 * alarm when wake up system from deep sleep, and for other scenarios,
429495bbde5SBaolin Wang 	 * we should set normal alarm with polling status.
430495bbde5SBaolin Wang 	 *
431495bbde5SBaolin Wang 	 * So here we check if the alarm time is set by aie_timer, if yes, we
432495bbde5SBaolin Wang 	 * should set normal alarm, if not, we should set auxiliary alarm which
433495bbde5SBaolin Wang 	 * means it is just a wake event.
434495bbde5SBaolin Wang 	 */
435495bbde5SBaolin Wang 	if (!rtc->rtc->aie_timer.enabled || rtc_tm_sub(&aie_time, &alrm->time))
436495bbde5SBaolin Wang 		return sprd_rtc_set_aux_alarm(dev, alrm);
437495bbde5SBaolin Wang 
438495bbde5SBaolin Wang 	/* clear the alarm interrupt status firstly */
439495bbde5SBaolin Wang 	ret = regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
440495bbde5SBaolin Wang 			   SPRD_RTC_ALARM_EN);
441495bbde5SBaolin Wang 	if (ret)
442495bbde5SBaolin Wang 		return ret;
443495bbde5SBaolin Wang 
444495bbde5SBaolin Wang 	ret = sprd_rtc_set_secs(rtc, SPRD_RTC_ALARM, secs);
445495bbde5SBaolin Wang 	if (ret)
446495bbde5SBaolin Wang 		return ret;
447495bbde5SBaolin Wang 
448495bbde5SBaolin Wang 	if (alrm->enabled) {
449495bbde5SBaolin Wang 		ret = regmap_update_bits(rtc->regmap,
450495bbde5SBaolin Wang 					 rtc->base + SPRD_RTC_INT_EN,
451495bbde5SBaolin Wang 					 SPRD_RTC_ALARM_EN,
452495bbde5SBaolin Wang 					 SPRD_RTC_ALARM_EN);
453495bbde5SBaolin Wang 		if (ret)
454495bbde5SBaolin Wang 			return ret;
455495bbde5SBaolin Wang 
456495bbde5SBaolin Wang 		/* unlock the alarm to enable the alarm function. */
457495bbde5SBaolin Wang 		ret = sprd_rtc_lock_alarm(rtc, false);
458495bbde5SBaolin Wang 	} else {
459495bbde5SBaolin Wang 		regmap_update_bits(rtc->regmap,
460495bbde5SBaolin Wang 				   rtc->base + SPRD_RTC_INT_EN,
461495bbde5SBaolin Wang 				   SPRD_RTC_ALARM_EN, 0);
462495bbde5SBaolin Wang 
463495bbde5SBaolin Wang 		/*
464495bbde5SBaolin Wang 		 * Lock the alarm function in case fake alarm event will power
465495bbde5SBaolin Wang 		 * up systems.
466495bbde5SBaolin Wang 		 */
467495bbde5SBaolin Wang 		ret = sprd_rtc_lock_alarm(rtc, true);
468495bbde5SBaolin Wang 	}
469495bbde5SBaolin Wang 
470495bbde5SBaolin Wang 	return ret;
471495bbde5SBaolin Wang }
472495bbde5SBaolin Wang 
sprd_rtc_alarm_irq_enable(struct device * dev,unsigned int enabled)473495bbde5SBaolin Wang static int sprd_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
474495bbde5SBaolin Wang {
475495bbde5SBaolin Wang 	struct sprd_rtc *rtc = dev_get_drvdata(dev);
476495bbde5SBaolin Wang 	int ret;
477495bbde5SBaolin Wang 
478495bbde5SBaolin Wang 	if (enabled) {
479495bbde5SBaolin Wang 		ret = regmap_update_bits(rtc->regmap,
480495bbde5SBaolin Wang 					 rtc->base + SPRD_RTC_INT_EN,
481495bbde5SBaolin Wang 					 SPRD_RTC_ALARM_EN | SPRD_RTC_AUXALM_EN,
482495bbde5SBaolin Wang 					 SPRD_RTC_ALARM_EN | SPRD_RTC_AUXALM_EN);
483495bbde5SBaolin Wang 		if (ret)
484495bbde5SBaolin Wang 			return ret;
485495bbde5SBaolin Wang 
486495bbde5SBaolin Wang 		ret = sprd_rtc_lock_alarm(rtc, false);
487495bbde5SBaolin Wang 	} else {
488495bbde5SBaolin Wang 		regmap_update_bits(rtc->regmap, rtc->base + SPRD_RTC_INT_EN,
489495bbde5SBaolin Wang 				   SPRD_RTC_ALARM_EN | SPRD_RTC_AUXALM_EN, 0);
490495bbde5SBaolin Wang 
491495bbde5SBaolin Wang 		ret = sprd_rtc_lock_alarm(rtc, true);
492495bbde5SBaolin Wang 	}
493495bbde5SBaolin Wang 
494495bbde5SBaolin Wang 	return ret;
495495bbde5SBaolin Wang }
496495bbde5SBaolin Wang 
497495bbde5SBaolin Wang static const struct rtc_class_ops sprd_rtc_ops = {
498495bbde5SBaolin Wang 	.read_time = sprd_rtc_read_time,
499495bbde5SBaolin Wang 	.set_time = sprd_rtc_set_time,
500495bbde5SBaolin Wang 	.read_alarm = sprd_rtc_read_alarm,
501495bbde5SBaolin Wang 	.set_alarm = sprd_rtc_set_alarm,
502495bbde5SBaolin Wang 	.alarm_irq_enable = sprd_rtc_alarm_irq_enable,
503495bbde5SBaolin Wang };
504495bbde5SBaolin Wang 
sprd_rtc_handler(int irq,void * dev_id)505495bbde5SBaolin Wang static irqreturn_t sprd_rtc_handler(int irq, void *dev_id)
506495bbde5SBaolin Wang {
507495bbde5SBaolin Wang 	struct sprd_rtc *rtc = dev_id;
508495bbde5SBaolin Wang 	int ret;
509495bbde5SBaolin Wang 
510495bbde5SBaolin Wang 	ret = sprd_rtc_clear_alarm_ints(rtc);
511495bbde5SBaolin Wang 	if (ret)
512495bbde5SBaolin Wang 		return IRQ_RETVAL(ret);
513495bbde5SBaolin Wang 
514495bbde5SBaolin Wang 	rtc_update_irq(rtc->rtc, 1, RTC_AF | RTC_IRQF);
515495bbde5SBaolin Wang 	return IRQ_HANDLED;
516495bbde5SBaolin Wang }
517495bbde5SBaolin Wang 
sprd_rtc_check_power_down(struct sprd_rtc * rtc)518495bbde5SBaolin Wang static int sprd_rtc_check_power_down(struct sprd_rtc *rtc)
519495bbde5SBaolin Wang {
520495bbde5SBaolin Wang 	u32 val;
521495bbde5SBaolin Wang 	int ret;
522495bbde5SBaolin Wang 
523a0defd7cSBaolin Wang 	ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_PWR_STS, &val);
524495bbde5SBaolin Wang 	if (ret)
525495bbde5SBaolin Wang 		return ret;
526495bbde5SBaolin Wang 
527495bbde5SBaolin Wang 	/*
528a0defd7cSBaolin Wang 	 * If the RTC power status value is SPRD_RTC_POWER_RESET_VALUE, which
529a0defd7cSBaolin Wang 	 * means the RTC has been powered down, so the RTC time values are
530a0defd7cSBaolin Wang 	 * invalid.
531495bbde5SBaolin Wang 	 */
532825156a5SKaixu Xia 	rtc->valid = val != SPRD_RTC_POWER_RESET_VALUE;
533495bbde5SBaolin Wang 	return 0;
534495bbde5SBaolin Wang }
535495bbde5SBaolin Wang 
sprd_rtc_check_alarm_int(struct sprd_rtc * rtc)536bf2c532bSBaolin Wang static int sprd_rtc_check_alarm_int(struct sprd_rtc *rtc)
537bf2c532bSBaolin Wang {
538bf2c532bSBaolin Wang 	u32 val;
539bf2c532bSBaolin Wang 	int ret;
540bf2c532bSBaolin Wang 
541bf2c532bSBaolin Wang 	ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_SPG_VALUE, &val);
542bf2c532bSBaolin Wang 	if (ret)
543bf2c532bSBaolin Wang 		return ret;
544bf2c532bSBaolin Wang 
545bf2c532bSBaolin Wang 	/*
546bf2c532bSBaolin Wang 	 * The SPRD_RTC_INT_EN register is not put in always-power-on region
547bf2c532bSBaolin Wang 	 * supplied by VDDRTC, so we should check if we need enable the alarm
548bf2c532bSBaolin Wang 	 * interrupt when system booting.
549bf2c532bSBaolin Wang 	 *
550bf2c532bSBaolin Wang 	 * If we have set SPRD_RTC_POWEROFF_ALM_FLAG which is saved in
551bf2c532bSBaolin Wang 	 * always-power-on region, that means we have set one alarm last time,
552bf2c532bSBaolin Wang 	 * so we should enable the alarm interrupt to help RTC core to see if
553bf2c532bSBaolin Wang 	 * there is an alarm already set in RTC hardware.
554bf2c532bSBaolin Wang 	 */
555bf2c532bSBaolin Wang 	if (!(val & SPRD_RTC_POWEROFF_ALM_FLAG))
556bf2c532bSBaolin Wang 		return 0;
557bf2c532bSBaolin Wang 
558bf2c532bSBaolin Wang 	return regmap_update_bits(rtc->regmap, rtc->base + SPRD_RTC_INT_EN,
559bf2c532bSBaolin Wang 				  SPRD_RTC_ALARM_EN, SPRD_RTC_ALARM_EN);
560bf2c532bSBaolin Wang }
561bf2c532bSBaolin Wang 
sprd_rtc_probe(struct platform_device * pdev)562495bbde5SBaolin Wang static int sprd_rtc_probe(struct platform_device *pdev)
563495bbde5SBaolin Wang {
564495bbde5SBaolin Wang 	struct device_node *node = pdev->dev.of_node;
565495bbde5SBaolin Wang 	struct sprd_rtc *rtc;
566495bbde5SBaolin Wang 	int ret;
567495bbde5SBaolin Wang 
568495bbde5SBaolin Wang 	rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
569495bbde5SBaolin Wang 	if (!rtc)
570495bbde5SBaolin Wang 		return -ENOMEM;
571495bbde5SBaolin Wang 
572495bbde5SBaolin Wang 	rtc->regmap = dev_get_regmap(pdev->dev.parent, NULL);
573495bbde5SBaolin Wang 	if (!rtc->regmap)
574495bbde5SBaolin Wang 		return -ENODEV;
575495bbde5SBaolin Wang 
576495bbde5SBaolin Wang 	ret = of_property_read_u32(node, "reg", &rtc->base);
577495bbde5SBaolin Wang 	if (ret) {
578495bbde5SBaolin Wang 		dev_err(&pdev->dev, "failed to get RTC base address\n");
579495bbde5SBaolin Wang 		return ret;
580495bbde5SBaolin Wang 	}
581495bbde5SBaolin Wang 
582495bbde5SBaolin Wang 	rtc->irq = platform_get_irq(pdev, 0);
583faac9102SStephen Boyd 	if (rtc->irq < 0)
584495bbde5SBaolin Wang 		return rtc->irq;
585495bbde5SBaolin Wang 
586369a30a5SBaolin Wang 	rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
587369a30a5SBaolin Wang 	if (IS_ERR(rtc->rtc))
588369a30a5SBaolin Wang 		return PTR_ERR(rtc->rtc);
589369a30a5SBaolin Wang 
590495bbde5SBaolin Wang 	rtc->dev = &pdev->dev;
591495bbde5SBaolin Wang 	platform_set_drvdata(pdev, rtc);
592495bbde5SBaolin Wang 
593bf2c532bSBaolin Wang 	/* check if we need set the alarm interrupt */
594bf2c532bSBaolin Wang 	ret = sprd_rtc_check_alarm_int(rtc);
595bf2c532bSBaolin Wang 	if (ret) {
596bf2c532bSBaolin Wang 		dev_err(&pdev->dev, "failed to check RTC alarm interrupt\n");
597bf2c532bSBaolin Wang 		return ret;
598bf2c532bSBaolin Wang 	}
599bf2c532bSBaolin Wang 
600495bbde5SBaolin Wang 	/* check if RTC time values are valid */
601495bbde5SBaolin Wang 	ret = sprd_rtc_check_power_down(rtc);
602495bbde5SBaolin Wang 	if (ret) {
603495bbde5SBaolin Wang 		dev_err(&pdev->dev, "failed to check RTC time values\n");
604495bbde5SBaolin Wang 		return ret;
605495bbde5SBaolin Wang 	}
606495bbde5SBaolin Wang 
607495bbde5SBaolin Wang 	ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
608495bbde5SBaolin Wang 					sprd_rtc_handler,
609495bbde5SBaolin Wang 					IRQF_ONESHOT | IRQF_EARLY_RESUME,
610495bbde5SBaolin Wang 					pdev->name, rtc);
611495bbde5SBaolin Wang 	if (ret < 0) {
612495bbde5SBaolin Wang 		dev_err(&pdev->dev, "failed to request RTC irq\n");
613495bbde5SBaolin Wang 		return ret;
614495bbde5SBaolin Wang 	}
615495bbde5SBaolin Wang 
616a86d6b23SBaolin Wang 	device_init_wakeup(&pdev->dev, 1);
617a86d6b23SBaolin Wang 
618369a30a5SBaolin Wang 	rtc->rtc->ops = &sprd_rtc_ops;
619149aa91cSBaolin Wang 	rtc->rtc->range_min = 0;
620149aa91cSBaolin Wang 	rtc->rtc->range_max = 5662310399LL;
621fdcfd854SBartosz Golaszewski 	ret = devm_rtc_register_device(rtc->rtc);
622369a30a5SBaolin Wang 	if (ret) {
623a86d6b23SBaolin Wang 		device_init_wakeup(&pdev->dev, 0);
624369a30a5SBaolin Wang 		return ret;
625369a30a5SBaolin Wang 	}
626495bbde5SBaolin Wang 
627495bbde5SBaolin Wang 	return 0;
628495bbde5SBaolin Wang }
629495bbde5SBaolin Wang 
630495bbde5SBaolin Wang static const struct of_device_id sprd_rtc_of_match[] = {
631495bbde5SBaolin Wang 	{ .compatible = "sprd,sc2731-rtc", },
632495bbde5SBaolin Wang 	{ },
633495bbde5SBaolin Wang };
634495bbde5SBaolin Wang MODULE_DEVICE_TABLE(of, sprd_rtc_of_match);
635495bbde5SBaolin Wang 
636495bbde5SBaolin Wang static struct platform_driver sprd_rtc_driver = {
637495bbde5SBaolin Wang 	.driver = {
638495bbde5SBaolin Wang 		.name = "sprd-rtc",
639495bbde5SBaolin Wang 		.of_match_table = sprd_rtc_of_match,
640495bbde5SBaolin Wang 	},
641495bbde5SBaolin Wang 	.probe	= sprd_rtc_probe,
642495bbde5SBaolin Wang };
643495bbde5SBaolin Wang module_platform_driver(sprd_rtc_driver);
644495bbde5SBaolin Wang 
645495bbde5SBaolin Wang MODULE_LICENSE("GPL v2");
646495bbde5SBaolin Wang MODULE_DESCRIPTION("Spreadtrum RTC Device Driver");
647495bbde5SBaolin Wang MODULE_AUTHOR("Baolin Wang <baolin.wang@spreadtrum.com>");
648