1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | // |
3 | // Copyright (c) 2013-2014 Samsung Electronics Co., Ltd |
4 | // http://www.samsung.com |
5 | // |
6 | // Copyright (C) 2013 Google, Inc |
7 | |
8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
9 | |
10 | #include <linux/module.h> |
11 | #include <linux/i2c.h> |
12 | #include <linux/bcd.h> |
13 | #include <linux/regmap.h> |
14 | #include <linux/rtc.h> |
15 | #include <linux/platform_device.h> |
16 | #include <linux/mfd/samsung/core.h> |
17 | #include <linux/mfd/samsung/irq.h> |
18 | #include <linux/mfd/samsung/rtc.h> |
19 | #include <linux/mfd/samsung/s2mps14.h> |
20 | |
21 | /* |
22 | * Maximum number of retries for checking changes in UDR field |
23 | * of S5M_RTC_UDR_CON register (to limit possible endless loop). |
24 | * |
25 | * After writing to RTC registers (setting time or alarm) read the UDR field |
26 | * in S5M_RTC_UDR_CON register. UDR is auto-cleared when data have |
27 | * been transferred. |
28 | */ |
29 | #define UDR_READ_RETRY_CNT 5 |
30 | |
31 | enum { |
32 | RTC_SEC = 0, |
33 | RTC_MIN, |
34 | RTC_HOUR, |
35 | RTC_WEEKDAY, |
36 | RTC_DATE, |
37 | RTC_MONTH, |
38 | RTC_YEAR1, |
39 | RTC_YEAR2, |
40 | /* Make sure this is always the last enum name. */ |
41 | RTC_MAX_NUM_TIME_REGS |
42 | }; |
43 | |
44 | /* |
45 | * Registers used by the driver which are different between chipsets. |
46 | * |
47 | * Operations like read time and write alarm/time require updating |
48 | * specific fields in UDR register. These fields usually are auto-cleared |
49 | * (with some exceptions). |
50 | * |
51 | * Table of operations per device: |
52 | * |
53 | * Device | Write time | Read time | Write alarm |
54 | * ================================================= |
55 | * S5M8767 | UDR + TIME | | UDR |
56 | * S2MPS11/14 | WUDR | RUDR | WUDR + RUDR |
57 | * S2MPS13 | WUDR | RUDR | WUDR + AUDR |
58 | * S2MPS15 | WUDR | RUDR | AUDR |
59 | */ |
60 | struct s5m_rtc_reg_config { |
61 | /* Number of registers used for setting time/alarm0/alarm1 */ |
62 | unsigned int regs_count; |
63 | /* First register for time, seconds */ |
64 | unsigned int time; |
65 | /* RTC control register */ |
66 | unsigned int ctrl; |
67 | /* First register for alarm 0, seconds */ |
68 | unsigned int alarm0; |
69 | /* First register for alarm 1, seconds */ |
70 | unsigned int alarm1; |
71 | /* |
72 | * Register for update flag (UDR). Typically setting UDR field to 1 |
73 | * will enable update of time or alarm register. Then it will be |
74 | * auto-cleared after successful update. |
75 | */ |
76 | unsigned int udr_update; |
77 | /* Auto-cleared mask in UDR field for writing time and alarm */ |
78 | unsigned int autoclear_udr_mask; |
79 | /* |
80 | * Masks in UDR field for time and alarm operations. |
81 | * The read time mask can be 0. Rest should not. |
82 | */ |
83 | unsigned int read_time_udr_mask; |
84 | unsigned int write_time_udr_mask; |
85 | unsigned int write_alarm_udr_mask; |
86 | }; |
87 | |
88 | /* Register map for S5M8767 */ |
89 | static const struct s5m_rtc_reg_config s5m_rtc_regs = { |
90 | .regs_count = 8, |
91 | .time = S5M_RTC_SEC, |
92 | .ctrl = S5M_ALARM1_CONF, |
93 | .alarm0 = S5M_ALARM0_SEC, |
94 | .alarm1 = S5M_ALARM1_SEC, |
95 | .udr_update = S5M_RTC_UDR_CON, |
96 | .autoclear_udr_mask = S5M_RTC_UDR_MASK, |
97 | .read_time_udr_mask = 0, /* Not needed */ |
98 | .write_time_udr_mask = S5M_RTC_UDR_MASK | S5M_RTC_TIME_EN_MASK, |
99 | .write_alarm_udr_mask = S5M_RTC_UDR_MASK, |
100 | }; |
101 | |
102 | /* Register map for S2MPS13 */ |
103 | static const struct s5m_rtc_reg_config s2mps13_rtc_regs = { |
104 | .regs_count = 7, |
105 | .time = S2MPS_RTC_SEC, |
106 | .ctrl = S2MPS_RTC_CTRL, |
107 | .alarm0 = S2MPS_ALARM0_SEC, |
108 | .alarm1 = S2MPS_ALARM1_SEC, |
109 | .udr_update = S2MPS_RTC_UDR_CON, |
110 | .autoclear_udr_mask = S2MPS_RTC_WUDR_MASK, |
111 | .read_time_udr_mask = S2MPS_RTC_RUDR_MASK, |
112 | .write_time_udr_mask = S2MPS_RTC_WUDR_MASK, |
113 | .write_alarm_udr_mask = S2MPS_RTC_WUDR_MASK | S2MPS13_RTC_AUDR_MASK, |
114 | }; |
115 | |
116 | /* Register map for S2MPS11/14 */ |
117 | static const struct s5m_rtc_reg_config s2mps14_rtc_regs = { |
118 | .regs_count = 7, |
119 | .time = S2MPS_RTC_SEC, |
120 | .ctrl = S2MPS_RTC_CTRL, |
121 | .alarm0 = S2MPS_ALARM0_SEC, |
122 | .alarm1 = S2MPS_ALARM1_SEC, |
123 | .udr_update = S2MPS_RTC_UDR_CON, |
124 | .autoclear_udr_mask = S2MPS_RTC_WUDR_MASK, |
125 | .read_time_udr_mask = S2MPS_RTC_RUDR_MASK, |
126 | .write_time_udr_mask = S2MPS_RTC_WUDR_MASK, |
127 | .write_alarm_udr_mask = S2MPS_RTC_WUDR_MASK | S2MPS_RTC_RUDR_MASK, |
128 | }; |
129 | |
130 | /* |
131 | * Register map for S2MPS15 - in comparison to S2MPS14 the WUDR and AUDR bits |
132 | * are swapped. |
133 | */ |
134 | static const struct s5m_rtc_reg_config s2mps15_rtc_regs = { |
135 | .regs_count = 7, |
136 | .time = S2MPS_RTC_SEC, |
137 | .ctrl = S2MPS_RTC_CTRL, |
138 | .alarm0 = S2MPS_ALARM0_SEC, |
139 | .alarm1 = S2MPS_ALARM1_SEC, |
140 | .udr_update = S2MPS_RTC_UDR_CON, |
141 | .autoclear_udr_mask = S2MPS_RTC_WUDR_MASK, |
142 | .read_time_udr_mask = S2MPS_RTC_RUDR_MASK, |
143 | .write_time_udr_mask = S2MPS15_RTC_WUDR_MASK, |
144 | .write_alarm_udr_mask = S2MPS15_RTC_AUDR_MASK, |
145 | }; |
146 | |
147 | struct s5m_rtc_info { |
148 | struct device *dev; |
149 | struct i2c_client *i2c; |
150 | struct sec_pmic_dev *s5m87xx; |
151 | struct regmap *regmap; |
152 | struct rtc_device *rtc_dev; |
153 | int irq; |
154 | enum sec_device_type device_type; |
155 | int rtc_24hr_mode; |
156 | const struct s5m_rtc_reg_config *regs; |
157 | }; |
158 | |
159 | static const struct regmap_config s5m_rtc_regmap_config = { |
160 | .reg_bits = 8, |
161 | .val_bits = 8, |
162 | |
163 | .max_register = S5M_RTC_REG_MAX, |
164 | }; |
165 | |
166 | static const struct regmap_config s2mps14_rtc_regmap_config = { |
167 | .reg_bits = 8, |
168 | .val_bits = 8, |
169 | |
170 | .max_register = S2MPS_RTC_REG_MAX, |
171 | }; |
172 | |
173 | static void s5m8767_data_to_tm(u8 *data, struct rtc_time *tm, |
174 | int rtc_24hr_mode) |
175 | { |
176 | tm->tm_sec = data[RTC_SEC] & 0x7f; |
177 | tm->tm_min = data[RTC_MIN] & 0x7f; |
178 | if (rtc_24hr_mode) { |
179 | tm->tm_hour = data[RTC_HOUR] & 0x1f; |
180 | } else { |
181 | tm->tm_hour = data[RTC_HOUR] & 0x0f; |
182 | if (data[RTC_HOUR] & HOUR_PM_MASK) |
183 | tm->tm_hour += 12; |
184 | } |
185 | |
186 | tm->tm_wday = ffs(data[RTC_WEEKDAY] & 0x7f); |
187 | tm->tm_mday = data[RTC_DATE] & 0x1f; |
188 | tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1; |
189 | tm->tm_year = (data[RTC_YEAR1] & 0x7f) + 100; |
190 | tm->tm_yday = 0; |
191 | tm->tm_isdst = 0; |
192 | } |
193 | |
194 | static int s5m8767_tm_to_data(struct rtc_time *tm, u8 *data) |
195 | { |
196 | data[RTC_SEC] = tm->tm_sec; |
197 | data[RTC_MIN] = tm->tm_min; |
198 | |
199 | if (tm->tm_hour >= 12) |
200 | data[RTC_HOUR] = tm->tm_hour | HOUR_PM_MASK; |
201 | else |
202 | data[RTC_HOUR] = tm->tm_hour & ~HOUR_PM_MASK; |
203 | |
204 | data[RTC_WEEKDAY] = 1 << tm->tm_wday; |
205 | data[RTC_DATE] = tm->tm_mday; |
206 | data[RTC_MONTH] = tm->tm_mon + 1; |
207 | data[RTC_YEAR1] = tm->tm_year - 100; |
208 | |
209 | return 0; |
210 | } |
211 | |
212 | /* |
213 | * Read RTC_UDR_CON register and wait till UDR field is cleared. |
214 | * This indicates that time/alarm update ended. |
215 | */ |
216 | static int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info) |
217 | { |
218 | int ret, retry = UDR_READ_RETRY_CNT; |
219 | unsigned int data; |
220 | |
221 | do { |
222 | ret = regmap_read(map: info->regmap, reg: info->regs->udr_update, val: &data); |
223 | } while (--retry && (data & info->regs->autoclear_udr_mask) && !ret); |
224 | |
225 | if (!retry) |
226 | dev_err(info->dev, "waiting for UDR update, reached max number of retries\n" ); |
227 | |
228 | return ret; |
229 | } |
230 | |
231 | static int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info, |
232 | struct rtc_wkalrm *alarm) |
233 | { |
234 | int ret; |
235 | unsigned int val; |
236 | |
237 | switch (info->device_type) { |
238 | case S5M8767X: |
239 | ret = regmap_read(map: info->regmap, reg: S5M_RTC_STATUS, val: &val); |
240 | val &= S5M_ALARM0_STATUS; |
241 | break; |
242 | case S2MPS15X: |
243 | case S2MPS14X: |
244 | case S2MPS13X: |
245 | ret = regmap_read(map: info->s5m87xx->regmap_pmic, reg: S2MPS14_REG_ST2, |
246 | val: &val); |
247 | val &= S2MPS_ALARM0_STATUS; |
248 | break; |
249 | default: |
250 | return -EINVAL; |
251 | } |
252 | if (ret < 0) |
253 | return ret; |
254 | |
255 | if (val) |
256 | alarm->pending = 1; |
257 | else |
258 | alarm->pending = 0; |
259 | |
260 | return 0; |
261 | } |
262 | |
263 | static int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) |
264 | { |
265 | int ret; |
266 | unsigned int data; |
267 | |
268 | ret = regmap_read(map: info->regmap, reg: info->regs->udr_update, val: &data); |
269 | if (ret < 0) { |
270 | dev_err(info->dev, "failed to read update reg(%d)\n" , ret); |
271 | return ret; |
272 | } |
273 | |
274 | data |= info->regs->write_time_udr_mask; |
275 | |
276 | ret = regmap_write(map: info->regmap, reg: info->regs->udr_update, val: data); |
277 | if (ret < 0) { |
278 | dev_err(info->dev, "failed to write update reg(%d)\n" , ret); |
279 | return ret; |
280 | } |
281 | |
282 | ret = s5m8767_wait_for_udr_update(info); |
283 | |
284 | return ret; |
285 | } |
286 | |
287 | static int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) |
288 | { |
289 | int ret; |
290 | unsigned int data; |
291 | |
292 | ret = regmap_read(map: info->regmap, reg: info->regs->udr_update, val: &data); |
293 | if (ret < 0) { |
294 | dev_err(info->dev, "%s: fail to read update reg(%d)\n" , |
295 | __func__, ret); |
296 | return ret; |
297 | } |
298 | |
299 | data |= info->regs->write_alarm_udr_mask; |
300 | switch (info->device_type) { |
301 | case S5M8767X: |
302 | data &= ~S5M_RTC_TIME_EN_MASK; |
303 | break; |
304 | case S2MPS15X: |
305 | case S2MPS14X: |
306 | case S2MPS13X: |
307 | /* No exceptions needed */ |
308 | break; |
309 | default: |
310 | return -EINVAL; |
311 | } |
312 | |
313 | ret = regmap_write(map: info->regmap, reg: info->regs->udr_update, val: data); |
314 | if (ret < 0) { |
315 | dev_err(info->dev, "%s: fail to write update reg(%d)\n" , |
316 | __func__, ret); |
317 | return ret; |
318 | } |
319 | |
320 | ret = s5m8767_wait_for_udr_update(info); |
321 | |
322 | /* On S2MPS13 the AUDR is not auto-cleared */ |
323 | if (info->device_type == S2MPS13X) |
324 | regmap_update_bits(map: info->regmap, reg: info->regs->udr_update, |
325 | S2MPS13_RTC_AUDR_MASK, val: 0); |
326 | |
327 | return ret; |
328 | } |
329 | |
330 | static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) |
331 | { |
332 | struct s5m_rtc_info *info = dev_get_drvdata(dev); |
333 | u8 data[RTC_MAX_NUM_TIME_REGS]; |
334 | int ret; |
335 | |
336 | if (info->regs->read_time_udr_mask) { |
337 | ret = regmap_update_bits(map: info->regmap, |
338 | reg: info->regs->udr_update, |
339 | mask: info->regs->read_time_udr_mask, |
340 | val: info->regs->read_time_udr_mask); |
341 | if (ret) { |
342 | dev_err(dev, |
343 | "Failed to prepare registers for time reading: %d\n" , |
344 | ret); |
345 | return ret; |
346 | } |
347 | } |
348 | ret = regmap_bulk_read(map: info->regmap, reg: info->regs->time, val: data, |
349 | val_count: info->regs->regs_count); |
350 | if (ret < 0) |
351 | return ret; |
352 | |
353 | switch (info->device_type) { |
354 | case S5M8767X: |
355 | case S2MPS15X: |
356 | case S2MPS14X: |
357 | case S2MPS13X: |
358 | s5m8767_data_to_tm(data, tm, rtc_24hr_mode: info->rtc_24hr_mode); |
359 | break; |
360 | |
361 | default: |
362 | return -EINVAL; |
363 | } |
364 | |
365 | dev_dbg(dev, "%s: %ptR(%d)\n" , __func__, tm, tm->tm_wday); |
366 | |
367 | return 0; |
368 | } |
369 | |
370 | static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm) |
371 | { |
372 | struct s5m_rtc_info *info = dev_get_drvdata(dev); |
373 | u8 data[RTC_MAX_NUM_TIME_REGS]; |
374 | int ret = 0; |
375 | |
376 | switch (info->device_type) { |
377 | case S5M8767X: |
378 | case S2MPS15X: |
379 | case S2MPS14X: |
380 | case S2MPS13X: |
381 | ret = s5m8767_tm_to_data(tm, data); |
382 | break; |
383 | default: |
384 | return -EINVAL; |
385 | } |
386 | |
387 | if (ret < 0) |
388 | return ret; |
389 | |
390 | dev_dbg(dev, "%s: %ptR(%d)\n" , __func__, tm, tm->tm_wday); |
391 | |
392 | ret = regmap_raw_write(map: info->regmap, reg: info->regs->time, val: data, |
393 | val_len: info->regs->regs_count); |
394 | if (ret < 0) |
395 | return ret; |
396 | |
397 | ret = s5m8767_rtc_set_time_reg(info); |
398 | |
399 | return ret; |
400 | } |
401 | |
402 | static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) |
403 | { |
404 | struct s5m_rtc_info *info = dev_get_drvdata(dev); |
405 | u8 data[RTC_MAX_NUM_TIME_REGS]; |
406 | int ret, i; |
407 | |
408 | ret = regmap_bulk_read(map: info->regmap, reg: info->regs->alarm0, val: data, |
409 | val_count: info->regs->regs_count); |
410 | if (ret < 0) |
411 | return ret; |
412 | |
413 | switch (info->device_type) { |
414 | case S5M8767X: |
415 | case S2MPS15X: |
416 | case S2MPS14X: |
417 | case S2MPS13X: |
418 | s5m8767_data_to_tm(data, tm: &alrm->time, rtc_24hr_mode: info->rtc_24hr_mode); |
419 | alrm->enabled = 0; |
420 | for (i = 0; i < info->regs->regs_count; i++) { |
421 | if (data[i] & ALARM_ENABLE_MASK) { |
422 | alrm->enabled = 1; |
423 | break; |
424 | } |
425 | } |
426 | break; |
427 | |
428 | default: |
429 | return -EINVAL; |
430 | } |
431 | |
432 | dev_dbg(dev, "%s: %ptR(%d)\n" , __func__, &alrm->time, alrm->time.tm_wday); |
433 | |
434 | return s5m_check_peding_alarm_interrupt(info, alarm: alrm); |
435 | } |
436 | |
437 | static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info) |
438 | { |
439 | u8 data[RTC_MAX_NUM_TIME_REGS]; |
440 | int ret, i; |
441 | struct rtc_time tm; |
442 | |
443 | ret = regmap_bulk_read(map: info->regmap, reg: info->regs->alarm0, val: data, |
444 | val_count: info->regs->regs_count); |
445 | if (ret < 0) |
446 | return ret; |
447 | |
448 | s5m8767_data_to_tm(data, tm: &tm, rtc_24hr_mode: info->rtc_24hr_mode); |
449 | dev_dbg(info->dev, "%s: %ptR(%d)\n" , __func__, &tm, tm.tm_wday); |
450 | |
451 | switch (info->device_type) { |
452 | case S5M8767X: |
453 | case S2MPS15X: |
454 | case S2MPS14X: |
455 | case S2MPS13X: |
456 | for (i = 0; i < info->regs->regs_count; i++) |
457 | data[i] &= ~ALARM_ENABLE_MASK; |
458 | |
459 | ret = regmap_raw_write(map: info->regmap, reg: info->regs->alarm0, val: data, |
460 | val_len: info->regs->regs_count); |
461 | if (ret < 0) |
462 | return ret; |
463 | |
464 | ret = s5m8767_rtc_set_alarm_reg(info); |
465 | |
466 | break; |
467 | |
468 | default: |
469 | return -EINVAL; |
470 | } |
471 | |
472 | return ret; |
473 | } |
474 | |
475 | static int s5m_rtc_start_alarm(struct s5m_rtc_info *info) |
476 | { |
477 | int ret; |
478 | u8 data[RTC_MAX_NUM_TIME_REGS]; |
479 | struct rtc_time tm; |
480 | |
481 | ret = regmap_bulk_read(map: info->regmap, reg: info->regs->alarm0, val: data, |
482 | val_count: info->regs->regs_count); |
483 | if (ret < 0) |
484 | return ret; |
485 | |
486 | s5m8767_data_to_tm(data, tm: &tm, rtc_24hr_mode: info->rtc_24hr_mode); |
487 | dev_dbg(info->dev, "%s: %ptR(%d)\n" , __func__, &tm, tm.tm_wday); |
488 | |
489 | switch (info->device_type) { |
490 | case S5M8767X: |
491 | case S2MPS15X: |
492 | case S2MPS14X: |
493 | case S2MPS13X: |
494 | data[RTC_SEC] |= ALARM_ENABLE_MASK; |
495 | data[RTC_MIN] |= ALARM_ENABLE_MASK; |
496 | data[RTC_HOUR] |= ALARM_ENABLE_MASK; |
497 | data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK; |
498 | if (data[RTC_DATE] & 0x1f) |
499 | data[RTC_DATE] |= ALARM_ENABLE_MASK; |
500 | if (data[RTC_MONTH] & 0xf) |
501 | data[RTC_MONTH] |= ALARM_ENABLE_MASK; |
502 | if (data[RTC_YEAR1] & 0x7f) |
503 | data[RTC_YEAR1] |= ALARM_ENABLE_MASK; |
504 | |
505 | ret = regmap_raw_write(map: info->regmap, reg: info->regs->alarm0, val: data, |
506 | val_len: info->regs->regs_count); |
507 | if (ret < 0) |
508 | return ret; |
509 | ret = s5m8767_rtc_set_alarm_reg(info); |
510 | |
511 | break; |
512 | |
513 | default: |
514 | return -EINVAL; |
515 | } |
516 | |
517 | return ret; |
518 | } |
519 | |
520 | static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) |
521 | { |
522 | struct s5m_rtc_info *info = dev_get_drvdata(dev); |
523 | u8 data[RTC_MAX_NUM_TIME_REGS]; |
524 | int ret; |
525 | |
526 | switch (info->device_type) { |
527 | case S5M8767X: |
528 | case S2MPS15X: |
529 | case S2MPS14X: |
530 | case S2MPS13X: |
531 | s5m8767_tm_to_data(tm: &alrm->time, data); |
532 | break; |
533 | |
534 | default: |
535 | return -EINVAL; |
536 | } |
537 | |
538 | dev_dbg(dev, "%s: %ptR(%d)\n" , __func__, &alrm->time, alrm->time.tm_wday); |
539 | |
540 | ret = s5m_rtc_stop_alarm(info); |
541 | if (ret < 0) |
542 | return ret; |
543 | |
544 | ret = regmap_raw_write(map: info->regmap, reg: info->regs->alarm0, val: data, |
545 | val_len: info->regs->regs_count); |
546 | if (ret < 0) |
547 | return ret; |
548 | |
549 | ret = s5m8767_rtc_set_alarm_reg(info); |
550 | if (ret < 0) |
551 | return ret; |
552 | |
553 | if (alrm->enabled) |
554 | ret = s5m_rtc_start_alarm(info); |
555 | |
556 | return ret; |
557 | } |
558 | |
559 | static int s5m_rtc_alarm_irq_enable(struct device *dev, |
560 | unsigned int enabled) |
561 | { |
562 | struct s5m_rtc_info *info = dev_get_drvdata(dev); |
563 | |
564 | if (enabled) |
565 | return s5m_rtc_start_alarm(info); |
566 | else |
567 | return s5m_rtc_stop_alarm(info); |
568 | } |
569 | |
570 | static irqreturn_t s5m_rtc_alarm_irq(int irq, void *data) |
571 | { |
572 | struct s5m_rtc_info *info = data; |
573 | |
574 | rtc_update_irq(rtc: info->rtc_dev, num: 1, RTC_IRQF | RTC_AF); |
575 | |
576 | return IRQ_HANDLED; |
577 | } |
578 | |
579 | static const struct rtc_class_ops s5m_rtc_ops = { |
580 | .read_time = s5m_rtc_read_time, |
581 | .set_time = s5m_rtc_set_time, |
582 | .read_alarm = s5m_rtc_read_alarm, |
583 | .set_alarm = s5m_rtc_set_alarm, |
584 | .alarm_irq_enable = s5m_rtc_alarm_irq_enable, |
585 | }; |
586 | |
587 | static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info) |
588 | { |
589 | u8 data[2]; |
590 | int ret; |
591 | |
592 | switch (info->device_type) { |
593 | case S5M8767X: |
594 | /* UDR update time. Default of 7.32 ms is too long. */ |
595 | ret = regmap_update_bits(map: info->regmap, reg: S5M_RTC_UDR_CON, |
596 | S5M_RTC_UDR_T_MASK, S5M_RTC_UDR_T_450_US); |
597 | if (ret < 0) |
598 | dev_err(info->dev, "%s: fail to change UDR time: %d\n" , |
599 | __func__, ret); |
600 | |
601 | /* Set RTC control register : Binary mode, 24hour mode */ |
602 | data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); |
603 | data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); |
604 | |
605 | ret = regmap_raw_write(map: info->regmap, reg: S5M_ALARM0_CONF, val: data, val_len: 2); |
606 | break; |
607 | |
608 | case S2MPS15X: |
609 | case S2MPS14X: |
610 | case S2MPS13X: |
611 | data[0] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); |
612 | ret = regmap_write(map: info->regmap, reg: info->regs->ctrl, val: data[0]); |
613 | if (ret < 0) |
614 | break; |
615 | |
616 | /* |
617 | * Should set WUDR & (RUDR or AUDR) bits to high after writing |
618 | * RTC_CTRL register like writing Alarm registers. We can't find |
619 | * the description from datasheet but vendor code does that |
620 | * really. |
621 | */ |
622 | ret = s5m8767_rtc_set_alarm_reg(info); |
623 | break; |
624 | |
625 | default: |
626 | return -EINVAL; |
627 | } |
628 | |
629 | info->rtc_24hr_mode = 1; |
630 | if (ret < 0) { |
631 | dev_err(info->dev, "%s: fail to write controlm reg(%d)\n" , |
632 | __func__, ret); |
633 | return ret; |
634 | } |
635 | |
636 | return ret; |
637 | } |
638 | |
639 | static int s5m_rtc_probe(struct platform_device *pdev) |
640 | { |
641 | struct sec_pmic_dev *s5m87xx = dev_get_drvdata(dev: pdev->dev.parent); |
642 | struct s5m_rtc_info *info; |
643 | const struct regmap_config *regmap_cfg; |
644 | int ret, alarm_irq; |
645 | |
646 | info = devm_kzalloc(dev: &pdev->dev, size: sizeof(*info), GFP_KERNEL); |
647 | if (!info) |
648 | return -ENOMEM; |
649 | |
650 | switch (platform_get_device_id(pdev)->driver_data) { |
651 | case S2MPS15X: |
652 | regmap_cfg = &s2mps14_rtc_regmap_config; |
653 | info->regs = &s2mps15_rtc_regs; |
654 | alarm_irq = S2MPS14_IRQ_RTCA0; |
655 | break; |
656 | case S2MPS14X: |
657 | regmap_cfg = &s2mps14_rtc_regmap_config; |
658 | info->regs = &s2mps14_rtc_regs; |
659 | alarm_irq = S2MPS14_IRQ_RTCA0; |
660 | break; |
661 | case S2MPS13X: |
662 | regmap_cfg = &s2mps14_rtc_regmap_config; |
663 | info->regs = &s2mps13_rtc_regs; |
664 | alarm_irq = S2MPS14_IRQ_RTCA0; |
665 | break; |
666 | case S5M8767X: |
667 | regmap_cfg = &s5m_rtc_regmap_config; |
668 | info->regs = &s5m_rtc_regs; |
669 | alarm_irq = S5M8767_IRQ_RTCA1; |
670 | break; |
671 | default: |
672 | dev_err(&pdev->dev, |
673 | "Device type %lu is not supported by RTC driver\n" , |
674 | platform_get_device_id(pdev)->driver_data); |
675 | return -ENODEV; |
676 | } |
677 | |
678 | info->i2c = devm_i2c_new_dummy_device(dev: &pdev->dev, adap: s5m87xx->i2c->adapter, |
679 | RTC_I2C_ADDR); |
680 | if (IS_ERR(ptr: info->i2c)) { |
681 | dev_err(&pdev->dev, "Failed to allocate I2C for RTC\n" ); |
682 | return PTR_ERR(ptr: info->i2c); |
683 | } |
684 | |
685 | info->regmap = devm_regmap_init_i2c(info->i2c, regmap_cfg); |
686 | if (IS_ERR(ptr: info->regmap)) { |
687 | ret = PTR_ERR(ptr: info->regmap); |
688 | dev_err(&pdev->dev, "Failed to allocate RTC register map: %d\n" , |
689 | ret); |
690 | return ret; |
691 | } |
692 | |
693 | info->dev = &pdev->dev; |
694 | info->s5m87xx = s5m87xx; |
695 | info->device_type = platform_get_device_id(pdev)->driver_data; |
696 | |
697 | if (s5m87xx->irq_data) { |
698 | info->irq = regmap_irq_get_virq(data: s5m87xx->irq_data, irq: alarm_irq); |
699 | if (info->irq <= 0) { |
700 | dev_err(&pdev->dev, "Failed to get virtual IRQ %d\n" , |
701 | alarm_irq); |
702 | return -EINVAL; |
703 | } |
704 | } |
705 | |
706 | platform_set_drvdata(pdev, data: info); |
707 | |
708 | ret = s5m8767_rtc_init_reg(info); |
709 | if (ret) |
710 | return ret; |
711 | |
712 | info->rtc_dev = devm_rtc_allocate_device(dev: &pdev->dev); |
713 | if (IS_ERR(ptr: info->rtc_dev)) |
714 | return PTR_ERR(ptr: info->rtc_dev); |
715 | |
716 | info->rtc_dev->ops = &s5m_rtc_ops; |
717 | |
718 | info->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_2000; |
719 | info->rtc_dev->range_max = RTC_TIMESTAMP_END_2099; |
720 | |
721 | if (!info->irq) { |
722 | clear_bit(RTC_FEATURE_ALARM, addr: info->rtc_dev->features); |
723 | } else { |
724 | ret = devm_request_threaded_irq(dev: &pdev->dev, irq: info->irq, NULL, |
725 | thread_fn: s5m_rtc_alarm_irq, irqflags: 0, devname: "rtc-alarm0" , |
726 | dev_id: info); |
727 | if (ret < 0) { |
728 | dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n" , |
729 | info->irq, ret); |
730 | return ret; |
731 | } |
732 | device_init_wakeup(dev: &pdev->dev, enable: 1); |
733 | } |
734 | |
735 | return devm_rtc_register_device(info->rtc_dev); |
736 | } |
737 | |
738 | #ifdef CONFIG_PM_SLEEP |
739 | static int s5m_rtc_resume(struct device *dev) |
740 | { |
741 | struct s5m_rtc_info *info = dev_get_drvdata(dev); |
742 | int ret = 0; |
743 | |
744 | if (info->irq && device_may_wakeup(dev)) |
745 | ret = disable_irq_wake(irq: info->irq); |
746 | |
747 | return ret; |
748 | } |
749 | |
750 | static int s5m_rtc_suspend(struct device *dev) |
751 | { |
752 | struct s5m_rtc_info *info = dev_get_drvdata(dev); |
753 | int ret = 0; |
754 | |
755 | if (info->irq && device_may_wakeup(dev)) |
756 | ret = enable_irq_wake(irq: info->irq); |
757 | |
758 | return ret; |
759 | } |
760 | #endif /* CONFIG_PM_SLEEP */ |
761 | |
762 | static SIMPLE_DEV_PM_OPS(s5m_rtc_pm_ops, s5m_rtc_suspend, s5m_rtc_resume); |
763 | |
764 | static const struct platform_device_id s5m_rtc_id[] = { |
765 | { "s5m-rtc" , S5M8767X }, |
766 | { "s2mps13-rtc" , S2MPS13X }, |
767 | { "s2mps14-rtc" , S2MPS14X }, |
768 | { "s2mps15-rtc" , S2MPS15X }, |
769 | { }, |
770 | }; |
771 | MODULE_DEVICE_TABLE(platform, s5m_rtc_id); |
772 | |
773 | static struct platform_driver s5m_rtc_driver = { |
774 | .driver = { |
775 | .name = "s5m-rtc" , |
776 | .pm = &s5m_rtc_pm_ops, |
777 | }, |
778 | .probe = s5m_rtc_probe, |
779 | .id_table = s5m_rtc_id, |
780 | }; |
781 | |
782 | module_platform_driver(s5m_rtc_driver); |
783 | |
784 | /* Module information */ |
785 | MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>" ); |
786 | MODULE_DESCRIPTION("Samsung S5M/S2MPS14 RTC driver" ); |
787 | MODULE_LICENSE("GPL" ); |
788 | |