diff options
author | Baolin Wang <baolin.wang@spreadtrum.com> | 2017-11-08 22:34:17 -0500 |
---|---|---|
committer | Alexandre Belloni <alexandre.belloni@free-electrons.com> | 2017-11-20 16:47:50 -0500 |
commit | 495bbde523969c596bcfb8285a6027c746a18ef4 (patch) | |
tree | e4441e3f370a7717d09c53917ac727aee78fdbdd | |
parent | 8f6596f4c94a155b93a809989314e5e8c01d0618 (diff) |
rtc: sc27xx: Add Spreadtrum SC27xx PMIC RTC driver
This patch adds the Spreadtrum RTC driver, which embedded in the
Spreadtrum SC27xx series PMICs.
Signed-off-by: Baolin Wang <baolin.wang@spreadtrum.com>
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
-rw-r--r-- | drivers/rtc/Kconfig | 11 | ||||
-rw-r--r-- | drivers/rtc/Makefile | 1 | ||||
-rw-r--r-- | drivers/rtc/rtc-sc27xx.c | 662 |
3 files changed, 674 insertions, 0 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 47663e03f9a8..b59a31b079a5 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
@@ -1187,6 +1187,17 @@ config RTC_DRV_WM8350 | |||
1187 | This driver can also be built as a module. If so, the module | 1187 | This driver can also be built as a module. If so, the module |
1188 | will be called "rtc-wm8350". | 1188 | will be called "rtc-wm8350". |
1189 | 1189 | ||
1190 | config RTC_DRV_SC27XX | ||
1191 | tristate "Spreadtrum SC27xx RTC" | ||
1192 | depends on MFD_SC27XX_PMIC || COMPILE_TEST | ||
1193 | help | ||
1194 | If you say Y here you will get support for the RTC subsystem | ||
1195 | of the Spreadtrum SC27xx series PMICs. The SC27xx series PMICs | ||
1196 | includes the SC2720, SC2721, SC2723, SC2730 and SC2731 chips. | ||
1197 | |||
1198 | This driver can also be built as a module. If so, the module | ||
1199 | will be called rtc-sc27xx. | ||
1200 | |||
1190 | config RTC_DRV_SPEAR | 1201 | config RTC_DRV_SPEAR |
1191 | tristate "SPEAR ST RTC" | 1202 | tristate "SPEAR ST RTC" |
1192 | depends on PLAT_SPEAR || COMPILE_TEST | 1203 | depends on PLAT_SPEAR || COMPILE_TEST |
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 0b5acd6b5cc3..5cf6b0a44f01 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile | |||
@@ -145,6 +145,7 @@ obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o | |||
145 | obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o | 145 | obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o |
146 | obj-$(CONFIG_RTC_DRV_S5M) += rtc-s5m.o | 146 | obj-$(CONFIG_RTC_DRV_S5M) += rtc-s5m.o |
147 | obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o | 147 | obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o |
148 | obj-$(CONFIG_RTC_DRV_SC27XX) += rtc-sc27xx.o | ||
148 | obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o | 149 | obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o |
149 | obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o | 150 | obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o |
150 | obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o | 151 | obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o |
diff --git a/drivers/rtc/rtc-sc27xx.c b/drivers/rtc/rtc-sc27xx.c new file mode 100644 index 000000000000..d544d5268757 --- /dev/null +++ b/drivers/rtc/rtc-sc27xx.c | |||
@@ -0,0 +1,662 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Spreadtrum Communications Inc. | ||
3 | * | ||
4 | * SPDX-License-Identifier: GPL-2.0 | ||
5 | */ | ||
6 | |||
7 | #include <linux/bitops.h> | ||
8 | #include <linux/delay.h> | ||
9 | #include <linux/err.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/of.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | #include <linux/regmap.h> | ||
14 | #include <linux/rtc.h> | ||
15 | |||
16 | #define SPRD_RTC_SEC_CNT_VALUE 0x0 | ||
17 | #define SPRD_RTC_MIN_CNT_VALUE 0x4 | ||
18 | #define SPRD_RTC_HOUR_CNT_VALUE 0x8 | ||
19 | #define SPRD_RTC_DAY_CNT_VALUE 0xc | ||
20 | #define SPRD_RTC_SEC_CNT_UPD 0x10 | ||
21 | #define SPRD_RTC_MIN_CNT_UPD 0x14 | ||
22 | #define SPRD_RTC_HOUR_CNT_UPD 0x18 | ||
23 | #define SPRD_RTC_DAY_CNT_UPD 0x1c | ||
24 | #define SPRD_RTC_SEC_ALM_UPD 0x20 | ||
25 | #define SPRD_RTC_MIN_ALM_UPD 0x24 | ||
26 | #define SPRD_RTC_HOUR_ALM_UPD 0x28 | ||
27 | #define SPRD_RTC_DAY_ALM_UPD 0x2c | ||
28 | #define SPRD_RTC_INT_EN 0x30 | ||
29 | #define SPRD_RTC_INT_RAW_STS 0x34 | ||
30 | #define SPRD_RTC_INT_CLR 0x38 | ||
31 | #define SPRD_RTC_INT_MASK_STS 0x3C | ||
32 | #define SPRD_RTC_SEC_ALM_VALUE 0x40 | ||
33 | #define SPRD_RTC_MIN_ALM_VALUE 0x44 | ||
34 | #define SPRD_RTC_HOUR_ALM_VALUE 0x48 | ||
35 | #define SPRD_RTC_DAY_ALM_VALUE 0x4c | ||
36 | #define SPRD_RTC_SPG_VALUE 0x50 | ||
37 | #define SPRD_RTC_SPG_UPD 0x54 | ||
38 | #define SPRD_RTC_SEC_AUXALM_UPD 0x60 | ||
39 | #define SPRD_RTC_MIN_AUXALM_UPD 0x64 | ||
40 | #define SPRD_RTC_HOUR_AUXALM_UPD 0x68 | ||
41 | #define SPRD_RTC_DAY_AUXALM_UPD 0x6c | ||
42 | |||
43 | /* BIT & MASK definition for SPRD_RTC_INT_* registers */ | ||
44 | #define SPRD_RTC_SEC_EN BIT(0) | ||
45 | #define SPRD_RTC_MIN_EN BIT(1) | ||
46 | #define SPRD_RTC_HOUR_EN BIT(2) | ||
47 | #define SPRD_RTC_DAY_EN BIT(3) | ||
48 | #define SPRD_RTC_ALARM_EN BIT(4) | ||
49 | #define SPRD_RTC_HRS_FORMAT_EN BIT(5) | ||
50 | #define SPRD_RTC_AUXALM_EN BIT(6) | ||
51 | #define SPRD_RTC_SPG_UPD_EN BIT(7) | ||
52 | #define SPRD_RTC_SEC_UPD_EN BIT(8) | ||
53 | #define SPRD_RTC_MIN_UPD_EN BIT(9) | ||
54 | #define SPRD_RTC_HOUR_UPD_EN BIT(10) | ||
55 | #define SPRD_RTC_DAY_UPD_EN BIT(11) | ||
56 | #define SPRD_RTC_ALMSEC_UPD_EN BIT(12) | ||
57 | #define SPRD_RTC_ALMMIN_UPD_EN BIT(13) | ||
58 | #define SPRD_RTC_ALMHOUR_UPD_EN BIT(14) | ||
59 | #define SPRD_RTC_ALMDAY_UPD_EN BIT(15) | ||
60 | #define SPRD_RTC_INT_MASK GENMASK(15, 0) | ||
61 | |||
62 | #define SPRD_RTC_TIME_INT_MASK \ | ||
63 | (SPRD_RTC_SEC_UPD_EN | SPRD_RTC_MIN_UPD_EN | \ | ||
64 | SPRD_RTC_HOUR_UPD_EN | SPRD_RTC_DAY_UPD_EN) | ||
65 | |||
66 | #define SPRD_RTC_ALMTIME_INT_MASK \ | ||
67 | (SPRD_RTC_ALMSEC_UPD_EN | SPRD_RTC_ALMMIN_UPD_EN | \ | ||
68 | SPRD_RTC_ALMHOUR_UPD_EN | SPRD_RTC_ALMDAY_UPD_EN) | ||
69 | |||
70 | #define SPRD_RTC_ALM_INT_MASK \ | ||
71 | (SPRD_RTC_SEC_EN | SPRD_RTC_MIN_EN | \ | ||
72 | SPRD_RTC_HOUR_EN | SPRD_RTC_DAY_EN | \ | ||
73 | SPRD_RTC_ALARM_EN | SPRD_RTC_AUXALM_EN) | ||
74 | |||
75 | /* second/minute/hour/day values mask definition */ | ||
76 | #define SPRD_RTC_SEC_MASK GENMASK(5, 0) | ||
77 | #define SPRD_RTC_MIN_MASK GENMASK(5, 0) | ||
78 | #define SPRD_RTC_HOUR_MASK GENMASK(4, 0) | ||
79 | #define SPRD_RTC_DAY_MASK GENMASK(15, 0) | ||
80 | |||
81 | /* alarm lock definition for SPRD_RTC_SPG_UPD register */ | ||
82 | #define SPRD_RTC_ALMLOCK_MASK GENMASK(7, 0) | ||
83 | #define SPRD_RTC_ALM_UNLOCK 0xa5 | ||
84 | #define SPRD_RTC_ALM_LOCK (~SPRD_RTC_ALM_UNLOCK & \ | ||
85 | SPRD_RTC_ALMLOCK_MASK) | ||
86 | |||
87 | /* SPG values definition for SPRD_RTC_SPG_UPD register */ | ||
88 | #define SPRD_RTC_POWEROFF_ALM_FLAG BIT(8) | ||
89 | #define SPRD_RTC_POWER_RESET_FLAG BIT(9) | ||
90 | |||
91 | /* timeout of synchronizing time and alarm registers (us) */ | ||
92 | #define SPRD_RTC_POLL_TIMEOUT 200000 | ||
93 | #define SPRD_RTC_POLL_DELAY_US 20000 | ||
94 | |||
95 | struct sprd_rtc { | ||
96 | struct rtc_device *rtc; | ||
97 | struct regmap *regmap; | ||
98 | struct device *dev; | ||
99 | u32 base; | ||
100 | int irq; | ||
101 | bool valid; | ||
102 | }; | ||
103 | |||
104 | /* | ||
105 | * The Spreadtrum RTC controller has 3 groups registers, including time, normal | ||
106 | * alarm and auxiliary alarm. The time group registers are used to set RTC time, | ||
107 | * the normal alarm registers are used to set normal alarm, and the auxiliary | ||
108 | * alarm registers are used to set auxiliary alarm. Both alarm event and | ||
109 | * auxiliary alarm event can wake up system from deep sleep, but only alarm | ||
110 | * event can power up system from power down status. | ||
111 | */ | ||
112 | enum sprd_rtc_reg_types { | ||
113 | SPRD_RTC_TIME, | ||
114 | SPRD_RTC_ALARM, | ||
115 | SPRD_RTC_AUX_ALARM, | ||
116 | }; | ||
117 | |||
118 | static int sprd_rtc_clear_alarm_ints(struct sprd_rtc *rtc) | ||
119 | { | ||
120 | return regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR, | ||
121 | SPRD_RTC_ALM_INT_MASK); | ||
122 | } | ||
123 | |||
124 | static int sprd_rtc_disable_ints(struct sprd_rtc *rtc) | ||
125 | { | ||
126 | int ret; | ||
127 | |||
128 | ret = regmap_update_bits(rtc->regmap, rtc->base + SPRD_RTC_INT_EN, | ||
129 | SPRD_RTC_INT_MASK, 0); | ||
130 | if (ret) | ||
131 | return ret; | ||
132 | |||
133 | return regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR, | ||
134 | SPRD_RTC_INT_MASK); | ||
135 | } | ||
136 | |||
137 | static int sprd_rtc_lock_alarm(struct sprd_rtc *rtc, bool lock) | ||
138 | { | ||
139 | int ret; | ||
140 | u32 val; | ||
141 | |||
142 | ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_SPG_VALUE, &val); | ||
143 | if (ret) | ||
144 | return ret; | ||
145 | |||
146 | val &= ~(SPRD_RTC_ALMLOCK_MASK | SPRD_RTC_POWEROFF_ALM_FLAG); | ||
147 | if (lock) | ||
148 | val |= SPRD_RTC_ALM_LOCK; | ||
149 | else | ||
150 | val |= SPRD_RTC_ALM_UNLOCK | SPRD_RTC_POWEROFF_ALM_FLAG; | ||
151 | |||
152 | ret = regmap_write(rtc->regmap, rtc->base + SPRD_RTC_SPG_UPD, val); | ||
153 | if (ret) | ||
154 | return ret; | ||
155 | |||
156 | /* wait until the SPG value is updated successfully */ | ||
157 | ret = regmap_read_poll_timeout(rtc->regmap, | ||
158 | rtc->base + SPRD_RTC_INT_RAW_STS, val, | ||
159 | (val & SPRD_RTC_SPG_UPD_EN), | ||
160 | SPRD_RTC_POLL_DELAY_US, | ||
161 | SPRD_RTC_POLL_TIMEOUT); | ||
162 | if (ret) { | ||
163 | dev_err(rtc->dev, "failed to update SPG value:%d\n", ret); | ||
164 | return ret; | ||
165 | } | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | static int sprd_rtc_get_secs(struct sprd_rtc *rtc, enum sprd_rtc_reg_types type, | ||
171 | time64_t *secs) | ||
172 | { | ||
173 | u32 sec_reg, min_reg, hour_reg, day_reg; | ||
174 | u32 val, sec, min, hour, day; | ||
175 | int ret; | ||
176 | |||
177 | switch (type) { | ||
178 | case SPRD_RTC_TIME: | ||
179 | sec_reg = SPRD_RTC_SEC_CNT_VALUE; | ||
180 | min_reg = SPRD_RTC_MIN_CNT_VALUE; | ||
181 | hour_reg = SPRD_RTC_HOUR_CNT_VALUE; | ||
182 | day_reg = SPRD_RTC_DAY_CNT_VALUE; | ||
183 | break; | ||
184 | case SPRD_RTC_ALARM: | ||
185 | sec_reg = SPRD_RTC_SEC_ALM_VALUE; | ||
186 | min_reg = SPRD_RTC_MIN_ALM_VALUE; | ||
187 | hour_reg = SPRD_RTC_HOUR_ALM_VALUE; | ||
188 | day_reg = SPRD_RTC_DAY_ALM_VALUE; | ||
189 | break; | ||
190 | case SPRD_RTC_AUX_ALARM: | ||
191 | sec_reg = SPRD_RTC_SEC_AUXALM_UPD; | ||
192 | min_reg = SPRD_RTC_MIN_AUXALM_UPD; | ||
193 | hour_reg = SPRD_RTC_HOUR_AUXALM_UPD; | ||
194 | day_reg = SPRD_RTC_DAY_AUXALM_UPD; | ||
195 | break; | ||
196 | default: | ||
197 | return -EINVAL; | ||
198 | } | ||
199 | |||
200 | ret = regmap_read(rtc->regmap, rtc->base + sec_reg, &val); | ||
201 | if (ret) | ||
202 | return ret; | ||
203 | |||
204 | sec = val & SPRD_RTC_SEC_MASK; | ||
205 | |||
206 | ret = regmap_read(rtc->regmap, rtc->base + min_reg, &val); | ||
207 | if (ret) | ||
208 | return ret; | ||
209 | |||
210 | min = val & SPRD_RTC_MIN_MASK; | ||
211 | |||
212 | ret = regmap_read(rtc->regmap, rtc->base + hour_reg, &val); | ||
213 | if (ret) | ||
214 | return ret; | ||
215 | |||
216 | hour = val & SPRD_RTC_HOUR_MASK; | ||
217 | |||
218 | ret = regmap_read(rtc->regmap, rtc->base + day_reg, &val); | ||
219 | if (ret) | ||
220 | return ret; | ||
221 | |||
222 | day = val & SPRD_RTC_DAY_MASK; | ||
223 | *secs = (((time64_t)(day * 24) + hour) * 60 + min) * 60 + sec; | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static int sprd_rtc_set_secs(struct sprd_rtc *rtc, enum sprd_rtc_reg_types type, | ||
228 | time64_t secs) | ||
229 | { | ||
230 | u32 sec_reg, min_reg, hour_reg, day_reg, sts_mask; | ||
231 | u32 sec, min, hour, day, val; | ||
232 | int ret, rem; | ||
233 | |||
234 | /* convert seconds to RTC time format */ | ||
235 | day = div_s64_rem(secs, 86400, &rem); | ||
236 | hour = rem / 3600; | ||
237 | rem -= hour * 3600; | ||
238 | min = rem / 60; | ||
239 | sec = rem - min * 60; | ||
240 | |||
241 | switch (type) { | ||
242 | case SPRD_RTC_TIME: | ||
243 | sec_reg = SPRD_RTC_SEC_CNT_UPD; | ||
244 | min_reg = SPRD_RTC_MIN_CNT_UPD; | ||
245 | hour_reg = SPRD_RTC_HOUR_CNT_UPD; | ||
246 | day_reg = SPRD_RTC_DAY_CNT_UPD; | ||
247 | sts_mask = SPRD_RTC_TIME_INT_MASK; | ||
248 | break; | ||
249 | case SPRD_RTC_ALARM: | ||
250 | sec_reg = SPRD_RTC_SEC_ALM_UPD; | ||
251 | min_reg = SPRD_RTC_MIN_ALM_UPD; | ||
252 | hour_reg = SPRD_RTC_HOUR_ALM_UPD; | ||
253 | day_reg = SPRD_RTC_DAY_ALM_UPD; | ||
254 | sts_mask = SPRD_RTC_ALMTIME_INT_MASK; | ||
255 | break; | ||
256 | case SPRD_RTC_AUX_ALARM: | ||
257 | sec_reg = SPRD_RTC_SEC_AUXALM_UPD; | ||
258 | min_reg = SPRD_RTC_MIN_AUXALM_UPD; | ||
259 | hour_reg = SPRD_RTC_HOUR_AUXALM_UPD; | ||
260 | day_reg = SPRD_RTC_DAY_AUXALM_UPD; | ||
261 | sts_mask = 0; | ||
262 | break; | ||
263 | default: | ||
264 | return -EINVAL; | ||
265 | } | ||
266 | |||
267 | ret = regmap_write(rtc->regmap, rtc->base + sec_reg, sec); | ||
268 | if (ret) | ||
269 | return ret; | ||
270 | |||
271 | ret = regmap_write(rtc->regmap, rtc->base + min_reg, min); | ||
272 | if (ret) | ||
273 | return ret; | ||
274 | |||
275 | ret = regmap_write(rtc->regmap, rtc->base + hour_reg, hour); | ||
276 | if (ret) | ||
277 | return ret; | ||
278 | |||
279 | ret = regmap_write(rtc->regmap, rtc->base + day_reg, day); | ||
280 | if (ret) | ||
281 | return ret; | ||
282 | |||
283 | if (type == SPRD_RTC_AUX_ALARM) | ||
284 | return 0; | ||
285 | |||
286 | /* | ||
287 | * Since the time and normal alarm registers are put in always-power-on | ||
288 | * region supplied by VDDRTC, then these registers changing time will | ||
289 | * be very long, about 125ms. Thus here we should wait until all | ||
290 | * values are updated successfully. | ||
291 | */ | ||
292 | ret = regmap_read_poll_timeout(rtc->regmap, | ||
293 | rtc->base + SPRD_RTC_INT_RAW_STS, val, | ||
294 | ((val & sts_mask) == sts_mask), | ||
295 | SPRD_RTC_POLL_DELAY_US, | ||
296 | SPRD_RTC_POLL_TIMEOUT); | ||
297 | if (ret < 0) { | ||
298 | dev_err(rtc->dev, "set time/alarm values timeout\n"); | ||
299 | return ret; | ||
300 | } | ||
301 | |||
302 | return regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR, | ||
303 | sts_mask); | ||
304 | } | ||
305 | |||
306 | static int sprd_rtc_read_aux_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
307 | { | ||
308 | struct sprd_rtc *rtc = dev_get_drvdata(dev); | ||
309 | time64_t secs; | ||
310 | u32 val; | ||
311 | int ret; | ||
312 | |||
313 | ret = sprd_rtc_get_secs(rtc, SPRD_RTC_AUX_ALARM, &secs); | ||
314 | if (ret) | ||
315 | return ret; | ||
316 | |||
317 | rtc_time64_to_tm(secs, &alrm->time); | ||
318 | |||
319 | ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_INT_EN, &val); | ||
320 | if (ret) | ||
321 | return ret; | ||
322 | |||
323 | alrm->enabled = !!(val & SPRD_RTC_AUXALM_EN); | ||
324 | |||
325 | ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_INT_RAW_STS, &val); | ||
326 | if (ret) | ||
327 | return ret; | ||
328 | |||
329 | alrm->pending = !!(val & SPRD_RTC_AUXALM_EN); | ||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | static int sprd_rtc_set_aux_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
334 | { | ||
335 | struct sprd_rtc *rtc = dev_get_drvdata(dev); | ||
336 | time64_t secs = rtc_tm_to_time64(&alrm->time); | ||
337 | int ret; | ||
338 | |||
339 | /* clear the auxiliary alarm interrupt status */ | ||
340 | ret = regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR, | ||
341 | SPRD_RTC_AUXALM_EN); | ||
342 | if (ret) | ||
343 | return ret; | ||
344 | |||
345 | ret = sprd_rtc_set_secs(rtc, SPRD_RTC_AUX_ALARM, secs); | ||
346 | if (ret) | ||
347 | return ret; | ||
348 | |||
349 | if (alrm->enabled) { | ||
350 | ret = regmap_update_bits(rtc->regmap, | ||
351 | rtc->base + SPRD_RTC_INT_EN, | ||
352 | SPRD_RTC_AUXALM_EN, | ||
353 | SPRD_RTC_AUXALM_EN); | ||
354 | } else { | ||
355 | ret = regmap_update_bits(rtc->regmap, | ||
356 | rtc->base + SPRD_RTC_INT_EN, | ||
357 | SPRD_RTC_AUXALM_EN, 0); | ||
358 | } | ||
359 | |||
360 | return ret; | ||
361 | } | ||
362 | |||
363 | static int sprd_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
364 | { | ||
365 | struct sprd_rtc *rtc = dev_get_drvdata(dev); | ||
366 | time64_t secs; | ||
367 | int ret; | ||
368 | |||
369 | if (!rtc->valid) { | ||
370 | dev_warn(dev, "RTC values are invalid\n"); | ||
371 | return -EINVAL; | ||
372 | } | ||
373 | |||
374 | ret = sprd_rtc_get_secs(rtc, SPRD_RTC_TIME, &secs); | ||
375 | if (ret) | ||
376 | return ret; | ||
377 | |||
378 | rtc_time64_to_tm(secs, tm); | ||
379 | return rtc_valid_tm(tm); | ||
380 | } | ||
381 | |||
382 | static int sprd_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
383 | { | ||
384 | struct sprd_rtc *rtc = dev_get_drvdata(dev); | ||
385 | time64_t secs = rtc_tm_to_time64(tm); | ||
386 | u32 val; | ||
387 | int ret; | ||
388 | |||
389 | ret = sprd_rtc_set_secs(rtc, SPRD_RTC_TIME, secs); | ||
390 | if (ret) | ||
391 | return ret; | ||
392 | |||
393 | if (!rtc->valid) { | ||
394 | /* | ||
395 | * Set SPRD_RTC_POWER_RESET_FLAG to indicate now RTC has valid | ||
396 | * time values. | ||
397 | */ | ||
398 | ret = regmap_update_bits(rtc->regmap, | ||
399 | rtc->base + SPRD_RTC_SPG_UPD, | ||
400 | SPRD_RTC_POWER_RESET_FLAG, | ||
401 | SPRD_RTC_POWER_RESET_FLAG); | ||
402 | if (ret) | ||
403 | return ret; | ||
404 | |||
405 | ret = regmap_read_poll_timeout(rtc->regmap, | ||
406 | rtc->base + SPRD_RTC_INT_RAW_STS, | ||
407 | val, (val & SPRD_RTC_SPG_UPD_EN), | ||
408 | SPRD_RTC_POLL_DELAY_US, | ||
409 | SPRD_RTC_POLL_TIMEOUT); | ||
410 | if (ret) { | ||
411 | dev_err(rtc->dev, "failed to update SPG value:%d\n", | ||
412 | ret); | ||
413 | return ret; | ||
414 | } | ||
415 | |||
416 | rtc->valid = true; | ||
417 | } | ||
418 | |||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | static int sprd_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
423 | { | ||
424 | struct sprd_rtc *rtc = dev_get_drvdata(dev); | ||
425 | time64_t secs; | ||
426 | int ret; | ||
427 | u32 val; | ||
428 | |||
429 | /* | ||
430 | * If aie_timer is enabled, we should get the normal alarm time. | ||
431 | * Otherwise we should get auxiliary alarm time. | ||
432 | */ | ||
433 | if (rtc->rtc && rtc->rtc->aie_timer.enabled == 0) | ||
434 | return sprd_rtc_read_aux_alarm(dev, alrm); | ||
435 | |||
436 | ret = sprd_rtc_get_secs(rtc, SPRD_RTC_ALARM, &secs); | ||
437 | if (ret) | ||
438 | return ret; | ||
439 | |||
440 | rtc_time64_to_tm(secs, &alrm->time); | ||
441 | |||
442 | ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_INT_EN, &val); | ||
443 | if (ret) | ||
444 | return ret; | ||
445 | |||
446 | alrm->enabled = !!(val & SPRD_RTC_ALARM_EN); | ||
447 | |||
448 | ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_INT_RAW_STS, &val); | ||
449 | if (ret) | ||
450 | return ret; | ||
451 | |||
452 | alrm->pending = !!(val & SPRD_RTC_ALARM_EN); | ||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | static int sprd_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
457 | { | ||
458 | struct sprd_rtc *rtc = dev_get_drvdata(dev); | ||
459 | time64_t secs = rtc_tm_to_time64(&alrm->time); | ||
460 | struct rtc_time aie_time = | ||
461 | rtc_ktime_to_tm(rtc->rtc->aie_timer.node.expires); | ||
462 | int ret; | ||
463 | |||
464 | /* | ||
465 | * We have 2 groups alarms: normal alarm and auxiliary alarm. Since | ||
466 | * both normal alarm event and auxiliary alarm event can wake up system | ||
467 | * from deep sleep, but only alarm event can power up system from power | ||
468 | * down status. Moreover we do not need to poll about 125ms when | ||
469 | * updating auxiliary alarm registers. Thus we usually set auxiliary | ||
470 | * alarm when wake up system from deep sleep, and for other scenarios, | ||
471 | * we should set normal alarm with polling status. | ||
472 | * | ||
473 | * So here we check if the alarm time is set by aie_timer, if yes, we | ||
474 | * should set normal alarm, if not, we should set auxiliary alarm which | ||
475 | * means it is just a wake event. | ||
476 | */ | ||
477 | if (!rtc->rtc->aie_timer.enabled || rtc_tm_sub(&aie_time, &alrm->time)) | ||
478 | return sprd_rtc_set_aux_alarm(dev, alrm); | ||
479 | |||
480 | /* clear the alarm interrupt status firstly */ | ||
481 | ret = regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR, | ||
482 | SPRD_RTC_ALARM_EN); | ||
483 | if (ret) | ||
484 | return ret; | ||
485 | |||
486 | ret = sprd_rtc_set_secs(rtc, SPRD_RTC_ALARM, secs); | ||
487 | if (ret) | ||
488 | return ret; | ||
489 | |||
490 | if (alrm->enabled) { | ||
491 | ret = regmap_update_bits(rtc->regmap, | ||
492 | rtc->base + SPRD_RTC_INT_EN, | ||
493 | SPRD_RTC_ALARM_EN, | ||
494 | SPRD_RTC_ALARM_EN); | ||
495 | if (ret) | ||
496 | return ret; | ||
497 | |||
498 | /* unlock the alarm to enable the alarm function. */ | ||
499 | ret = sprd_rtc_lock_alarm(rtc, false); | ||
500 | } else { | ||
501 | regmap_update_bits(rtc->regmap, | ||
502 | rtc->base + SPRD_RTC_INT_EN, | ||
503 | SPRD_RTC_ALARM_EN, 0); | ||
504 | |||
505 | /* | ||
506 | * Lock the alarm function in case fake alarm event will power | ||
507 | * up systems. | ||
508 | */ | ||
509 | ret = sprd_rtc_lock_alarm(rtc, true); | ||
510 | } | ||
511 | |||
512 | return ret; | ||
513 | } | ||
514 | |||
515 | static int sprd_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) | ||
516 | { | ||
517 | struct sprd_rtc *rtc = dev_get_drvdata(dev); | ||
518 | int ret; | ||
519 | |||
520 | if (enabled) { | ||
521 | ret = regmap_update_bits(rtc->regmap, | ||
522 | rtc->base + SPRD_RTC_INT_EN, | ||
523 | SPRD_RTC_ALARM_EN | SPRD_RTC_AUXALM_EN, | ||
524 | SPRD_RTC_ALARM_EN | SPRD_RTC_AUXALM_EN); | ||
525 | if (ret) | ||
526 | return ret; | ||
527 | |||
528 | ret = sprd_rtc_lock_alarm(rtc, false); | ||
529 | } else { | ||
530 | regmap_update_bits(rtc->regmap, rtc->base + SPRD_RTC_INT_EN, | ||
531 | SPRD_RTC_ALARM_EN | SPRD_RTC_AUXALM_EN, 0); | ||
532 | |||
533 | ret = sprd_rtc_lock_alarm(rtc, true); | ||
534 | } | ||
535 | |||
536 | return ret; | ||
537 | } | ||
538 | |||
539 | static const struct rtc_class_ops sprd_rtc_ops = { | ||
540 | .read_time = sprd_rtc_read_time, | ||
541 | .set_time = sprd_rtc_set_time, | ||
542 | .read_alarm = sprd_rtc_read_alarm, | ||
543 | .set_alarm = sprd_rtc_set_alarm, | ||
544 | .alarm_irq_enable = sprd_rtc_alarm_irq_enable, | ||
545 | }; | ||
546 | |||
547 | static irqreturn_t sprd_rtc_handler(int irq, void *dev_id) | ||
548 | { | ||
549 | struct sprd_rtc *rtc = dev_id; | ||
550 | int ret; | ||
551 | |||
552 | ret = sprd_rtc_clear_alarm_ints(rtc); | ||
553 | if (ret) | ||
554 | return IRQ_RETVAL(ret); | ||
555 | |||
556 | rtc_update_irq(rtc->rtc, 1, RTC_AF | RTC_IRQF); | ||
557 | return IRQ_HANDLED; | ||
558 | } | ||
559 | |||
560 | static int sprd_rtc_check_power_down(struct sprd_rtc *rtc) | ||
561 | { | ||
562 | u32 val; | ||
563 | int ret; | ||
564 | |||
565 | ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_SPG_VALUE, &val); | ||
566 | if (ret) | ||
567 | return ret; | ||
568 | |||
569 | /* | ||
570 | * If the SPRD_RTC_POWER_RESET_FLAG was not set, which means the RTC has | ||
571 | * been powered down, so the RTC time values are invalid. | ||
572 | */ | ||
573 | rtc->valid = (val & SPRD_RTC_POWER_RESET_FLAG) ? true : false; | ||
574 | return 0; | ||
575 | } | ||
576 | |||
577 | static int sprd_rtc_probe(struct platform_device *pdev) | ||
578 | { | ||
579 | struct device_node *node = pdev->dev.of_node; | ||
580 | struct sprd_rtc *rtc; | ||
581 | int ret; | ||
582 | |||
583 | rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); | ||
584 | if (!rtc) | ||
585 | return -ENOMEM; | ||
586 | |||
587 | rtc->regmap = dev_get_regmap(pdev->dev.parent, NULL); | ||
588 | if (!rtc->regmap) | ||
589 | return -ENODEV; | ||
590 | |||
591 | ret = of_property_read_u32(node, "reg", &rtc->base); | ||
592 | if (ret) { | ||
593 | dev_err(&pdev->dev, "failed to get RTC base address\n"); | ||
594 | return ret; | ||
595 | } | ||
596 | |||
597 | rtc->irq = platform_get_irq(pdev, 0); | ||
598 | if (rtc->irq < 0) { | ||
599 | dev_err(&pdev->dev, "failed to get RTC irq number\n"); | ||
600 | return rtc->irq; | ||
601 | } | ||
602 | |||
603 | rtc->dev = &pdev->dev; | ||
604 | platform_set_drvdata(pdev, rtc); | ||
605 | |||
606 | /* clear all RTC interrupts and disable all RTC interrupts */ | ||
607 | ret = sprd_rtc_disable_ints(rtc); | ||
608 | if (ret) { | ||
609 | dev_err(&pdev->dev, "failed to disable RTC interrupts\n"); | ||
610 | return ret; | ||
611 | } | ||
612 | |||
613 | /* check if RTC time values are valid */ | ||
614 | ret = sprd_rtc_check_power_down(rtc); | ||
615 | if (ret) { | ||
616 | dev_err(&pdev->dev, "failed to check RTC time values\n"); | ||
617 | return ret; | ||
618 | } | ||
619 | |||
620 | ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, | ||
621 | sprd_rtc_handler, | ||
622 | IRQF_ONESHOT | IRQF_EARLY_RESUME, | ||
623 | pdev->name, rtc); | ||
624 | if (ret < 0) { | ||
625 | dev_err(&pdev->dev, "failed to request RTC irq\n"); | ||
626 | return ret; | ||
627 | } | ||
628 | |||
629 | rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, | ||
630 | &sprd_rtc_ops, THIS_MODULE); | ||
631 | if (IS_ERR(rtc->rtc)) | ||
632 | return PTR_ERR(rtc->rtc); | ||
633 | |||
634 | device_init_wakeup(&pdev->dev, 1); | ||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | static int sprd_rtc_remove(struct platform_device *pdev) | ||
639 | { | ||
640 | device_init_wakeup(&pdev->dev, 0); | ||
641 | return 0; | ||
642 | } | ||
643 | |||
644 | static const struct of_device_id sprd_rtc_of_match[] = { | ||
645 | { .compatible = "sprd,sc2731-rtc", }, | ||
646 | { }, | ||
647 | }; | ||
648 | MODULE_DEVICE_TABLE(of, sprd_rtc_of_match); | ||
649 | |||
650 | static struct platform_driver sprd_rtc_driver = { | ||
651 | .driver = { | ||
652 | .name = "sprd-rtc", | ||
653 | .of_match_table = sprd_rtc_of_match, | ||
654 | }, | ||
655 | .probe = sprd_rtc_probe, | ||
656 | .remove = sprd_rtc_remove, | ||
657 | }; | ||
658 | module_platform_driver(sprd_rtc_driver); | ||
659 | |||
660 | MODULE_LICENSE("GPL v2"); | ||
661 | MODULE_DESCRIPTION("Spreadtrum RTC Device Driver"); | ||
662 | MODULE_AUTHOR("Baolin Wang <baolin.wang@spreadtrum.com>"); | ||