diff options
Diffstat (limited to 'drivers/rtc/rtc-s5m.c')
-rw-r--r-- | drivers/rtc/rtc-s5m.c | 118 |
1 files changed, 85 insertions, 33 deletions
diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index b7fd02bc0a14..ae8119dc2846 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c | |||
@@ -28,10 +28,20 @@ | |||
28 | #include <linux/mfd/samsung/irq.h> | 28 | #include <linux/mfd/samsung/irq.h> |
29 | #include <linux/mfd/samsung/rtc.h> | 29 | #include <linux/mfd/samsung/rtc.h> |
30 | 30 | ||
31 | /* | ||
32 | * Maximum number of retries for checking changes in UDR field | ||
33 | * of SEC_RTC_UDR_CON register (to limit possible endless loop). | ||
34 | * | ||
35 | * After writing to RTC registers (setting time or alarm) read the UDR field | ||
36 | * in SEC_RTC_UDR_CON register. UDR is auto-cleared when data have | ||
37 | * been transferred. | ||
38 | */ | ||
39 | #define UDR_READ_RETRY_CNT 5 | ||
40 | |||
31 | struct s5m_rtc_info { | 41 | struct s5m_rtc_info { |
32 | struct device *dev; | 42 | struct device *dev; |
33 | struct sec_pmic_dev *s5m87xx; | 43 | struct sec_pmic_dev *s5m87xx; |
34 | struct regmap *rtc; | 44 | struct regmap *regmap; |
35 | struct rtc_device *rtc_dev; | 45 | struct rtc_device *rtc_dev; |
36 | int irq; | 46 | int irq; |
37 | int device_type; | 47 | int device_type; |
@@ -84,12 +94,31 @@ static int s5m8767_tm_to_data(struct rtc_time *tm, u8 *data) | |||
84 | } | 94 | } |
85 | } | 95 | } |
86 | 96 | ||
97 | /* | ||
98 | * Read RTC_UDR_CON register and wait till UDR field is cleared. | ||
99 | * This indicates that time/alarm update ended. | ||
100 | */ | ||
101 | static inline int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info) | ||
102 | { | ||
103 | int ret, retry = UDR_READ_RETRY_CNT; | ||
104 | unsigned int data; | ||
105 | |||
106 | do { | ||
107 | ret = regmap_read(info->regmap, SEC_RTC_UDR_CON, &data); | ||
108 | } while (--retry && (data & RTC_UDR_MASK) && !ret); | ||
109 | |||
110 | if (!retry) | ||
111 | dev_err(info->dev, "waiting for UDR update, reached max number of retries\n"); | ||
112 | |||
113 | return ret; | ||
114 | } | ||
115 | |||
87 | static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) | 116 | static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) |
88 | { | 117 | { |
89 | int ret; | 118 | int ret; |
90 | unsigned int data; | 119 | unsigned int data; |
91 | 120 | ||
92 | ret = regmap_read(info->rtc, SEC_RTC_UDR_CON, &data); | 121 | ret = regmap_read(info->regmap, SEC_RTC_UDR_CON, &data); |
93 | if (ret < 0) { | 122 | if (ret < 0) { |
94 | dev_err(info->dev, "failed to read update reg(%d)\n", ret); | 123 | dev_err(info->dev, "failed to read update reg(%d)\n", ret); |
95 | return ret; | 124 | return ret; |
@@ -98,15 +127,13 @@ static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) | |||
98 | data |= RTC_TIME_EN_MASK; | 127 | data |= RTC_TIME_EN_MASK; |
99 | data |= RTC_UDR_MASK; | 128 | data |= RTC_UDR_MASK; |
100 | 129 | ||
101 | ret = regmap_write(info->rtc, SEC_RTC_UDR_CON, data); | 130 | ret = regmap_write(info->regmap, SEC_RTC_UDR_CON, data); |
102 | if (ret < 0) { | 131 | if (ret < 0) { |
103 | dev_err(info->dev, "failed to write update reg(%d)\n", ret); | 132 | dev_err(info->dev, "failed to write update reg(%d)\n", ret); |
104 | return ret; | 133 | return ret; |
105 | } | 134 | } |
106 | 135 | ||
107 | do { | 136 | ret = s5m8767_wait_for_udr_update(info); |
108 | ret = regmap_read(info->rtc, SEC_RTC_UDR_CON, &data); | ||
109 | } while ((data & RTC_UDR_MASK) && !ret); | ||
110 | 137 | ||
111 | return ret; | 138 | return ret; |
112 | } | 139 | } |
@@ -116,7 +143,7 @@ static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) | |||
116 | int ret; | 143 | int ret; |
117 | unsigned int data; | 144 | unsigned int data; |
118 | 145 | ||
119 | ret = regmap_read(info->rtc, SEC_RTC_UDR_CON, &data); | 146 | ret = regmap_read(info->regmap, SEC_RTC_UDR_CON, &data); |
120 | if (ret < 0) { | 147 | if (ret < 0) { |
121 | dev_err(info->dev, "%s: fail to read update reg(%d)\n", | 148 | dev_err(info->dev, "%s: fail to read update reg(%d)\n", |
122 | __func__, ret); | 149 | __func__, ret); |
@@ -126,16 +153,14 @@ static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) | |||
126 | data &= ~RTC_TIME_EN_MASK; | 153 | data &= ~RTC_TIME_EN_MASK; |
127 | data |= RTC_UDR_MASK; | 154 | data |= RTC_UDR_MASK; |
128 | 155 | ||
129 | ret = regmap_write(info->rtc, SEC_RTC_UDR_CON, data); | 156 | ret = regmap_write(info->regmap, SEC_RTC_UDR_CON, data); |
130 | if (ret < 0) { | 157 | if (ret < 0) { |
131 | dev_err(info->dev, "%s: fail to write update reg(%d)\n", | 158 | dev_err(info->dev, "%s: fail to write update reg(%d)\n", |
132 | __func__, ret); | 159 | __func__, ret); |
133 | return ret; | 160 | return ret; |
134 | } | 161 | } |
135 | 162 | ||
136 | do { | 163 | ret = s5m8767_wait_for_udr_update(info); |
137 | ret = regmap_read(info->rtc, SEC_RTC_UDR_CON, &data); | ||
138 | } while ((data & RTC_UDR_MASK) && !ret); | ||
139 | 164 | ||
140 | return ret; | 165 | return ret; |
141 | } | 166 | } |
@@ -178,7 +203,7 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) | |||
178 | u8 data[8]; | 203 | u8 data[8]; |
179 | int ret; | 204 | int ret; |
180 | 205 | ||
181 | ret = regmap_bulk_read(info->rtc, SEC_RTC_SEC, data, 8); | 206 | ret = regmap_bulk_read(info->regmap, SEC_RTC_SEC, data, 8); |
182 | if (ret < 0) | 207 | if (ret < 0) |
183 | return ret; | 208 | return ret; |
184 | 209 | ||
@@ -226,7 +251,7 @@ static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
226 | 1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, | 251 | 1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, |
227 | tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday); | 252 | tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday); |
228 | 253 | ||
229 | ret = regmap_raw_write(info->rtc, SEC_RTC_SEC, data, 8); | 254 | ret = regmap_raw_write(info->regmap, SEC_RTC_SEC, data, 8); |
230 | if (ret < 0) | 255 | if (ret < 0) |
231 | return ret; | 256 | return ret; |
232 | 257 | ||
@@ -242,20 +267,20 @@ static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
242 | unsigned int val; | 267 | unsigned int val; |
243 | int ret, i; | 268 | int ret, i; |
244 | 269 | ||
245 | ret = regmap_bulk_read(info->rtc, SEC_ALARM0_SEC, data, 8); | 270 | ret = regmap_bulk_read(info->regmap, SEC_ALARM0_SEC, data, 8); |
246 | if (ret < 0) | 271 | if (ret < 0) |
247 | return ret; | 272 | return ret; |
248 | 273 | ||
249 | switch (info->device_type) { | 274 | switch (info->device_type) { |
250 | case S5M8763X: | 275 | case S5M8763X: |
251 | s5m8763_data_to_tm(data, &alrm->time); | 276 | s5m8763_data_to_tm(data, &alrm->time); |
252 | ret = regmap_read(info->rtc, SEC_ALARM0_CONF, &val); | 277 | ret = regmap_read(info->regmap, SEC_ALARM0_CONF, &val); |
253 | if (ret < 0) | 278 | if (ret < 0) |
254 | return ret; | 279 | return ret; |
255 | 280 | ||
256 | alrm->enabled = !!val; | 281 | alrm->enabled = !!val; |
257 | 282 | ||
258 | ret = regmap_read(info->rtc, SEC_RTC_STATUS, &val); | 283 | ret = regmap_read(info->regmap, SEC_RTC_STATUS, &val); |
259 | if (ret < 0) | 284 | if (ret < 0) |
260 | return ret; | 285 | return ret; |
261 | 286 | ||
@@ -278,7 +303,7 @@ static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
278 | } | 303 | } |
279 | 304 | ||
280 | alrm->pending = 0; | 305 | alrm->pending = 0; |
281 | ret = regmap_read(info->rtc, SEC_RTC_STATUS, &val); | 306 | ret = regmap_read(info->regmap, SEC_RTC_STATUS, &val); |
282 | if (ret < 0) | 307 | if (ret < 0) |
283 | return ret; | 308 | return ret; |
284 | break; | 309 | break; |
@@ -301,7 +326,7 @@ static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info) | |||
301 | int ret, i; | 326 | int ret, i; |
302 | struct rtc_time tm; | 327 | struct rtc_time tm; |
303 | 328 | ||
304 | ret = regmap_bulk_read(info->rtc, SEC_ALARM0_SEC, data, 8); | 329 | ret = regmap_bulk_read(info->regmap, SEC_ALARM0_SEC, data, 8); |
305 | if (ret < 0) | 330 | if (ret < 0) |
306 | return ret; | 331 | return ret; |
307 | 332 | ||
@@ -312,14 +337,14 @@ static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info) | |||
312 | 337 | ||
313 | switch (info->device_type) { | 338 | switch (info->device_type) { |
314 | case S5M8763X: | 339 | case S5M8763X: |
315 | ret = regmap_write(info->rtc, SEC_ALARM0_CONF, 0); | 340 | ret = regmap_write(info->regmap, SEC_ALARM0_CONF, 0); |
316 | break; | 341 | break; |
317 | 342 | ||
318 | case S5M8767X: | 343 | case S5M8767X: |
319 | for (i = 0; i < 7; i++) | 344 | for (i = 0; i < 7; i++) |
320 | data[i] &= ~ALARM_ENABLE_MASK; | 345 | data[i] &= ~ALARM_ENABLE_MASK; |
321 | 346 | ||
322 | ret = regmap_raw_write(info->rtc, SEC_ALARM0_SEC, data, 8); | 347 | ret = regmap_raw_write(info->regmap, SEC_ALARM0_SEC, data, 8); |
323 | if (ret < 0) | 348 | if (ret < 0) |
324 | return ret; | 349 | return ret; |
325 | 350 | ||
@@ -341,7 +366,7 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info) | |||
341 | u8 alarm0_conf; | 366 | u8 alarm0_conf; |
342 | struct rtc_time tm; | 367 | struct rtc_time tm; |
343 | 368 | ||
344 | ret = regmap_bulk_read(info->rtc, SEC_ALARM0_SEC, data, 8); | 369 | ret = regmap_bulk_read(info->regmap, SEC_ALARM0_SEC, data, 8); |
345 | if (ret < 0) | 370 | if (ret < 0) |
346 | return ret; | 371 | return ret; |
347 | 372 | ||
@@ -353,7 +378,7 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info) | |||
353 | switch (info->device_type) { | 378 | switch (info->device_type) { |
354 | case S5M8763X: | 379 | case S5M8763X: |
355 | alarm0_conf = 0x77; | 380 | alarm0_conf = 0x77; |
356 | ret = regmap_write(info->rtc, SEC_ALARM0_CONF, alarm0_conf); | 381 | ret = regmap_write(info->regmap, SEC_ALARM0_CONF, alarm0_conf); |
357 | break; | 382 | break; |
358 | 383 | ||
359 | case S5M8767X: | 384 | case S5M8767X: |
@@ -368,7 +393,7 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info) | |||
368 | if (data[RTC_YEAR1] & 0x7f) | 393 | if (data[RTC_YEAR1] & 0x7f) |
369 | data[RTC_YEAR1] |= ALARM_ENABLE_MASK; | 394 | data[RTC_YEAR1] |= ALARM_ENABLE_MASK; |
370 | 395 | ||
371 | ret = regmap_raw_write(info->rtc, SEC_ALARM0_SEC, data, 8); | 396 | ret = regmap_raw_write(info->regmap, SEC_ALARM0_SEC, data, 8); |
372 | if (ret < 0) | 397 | if (ret < 0) |
373 | return ret; | 398 | return ret; |
374 | ret = s5m8767_rtc_set_alarm_reg(info); | 399 | ret = s5m8767_rtc_set_alarm_reg(info); |
@@ -410,7 +435,7 @@ static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
410 | if (ret < 0) | 435 | if (ret < 0) |
411 | return ret; | 436 | return ret; |
412 | 437 | ||
413 | ret = regmap_raw_write(info->rtc, SEC_ALARM0_SEC, data, 8); | 438 | ret = regmap_raw_write(info->regmap, SEC_ALARM0_SEC, data, 8); |
414 | if (ret < 0) | 439 | if (ret < 0) |
415 | return ret; | 440 | return ret; |
416 | 441 | ||
@@ -455,7 +480,7 @@ static const struct rtc_class_ops s5m_rtc_ops = { | |||
455 | static void s5m_rtc_enable_wtsr(struct s5m_rtc_info *info, bool enable) | 480 | static void s5m_rtc_enable_wtsr(struct s5m_rtc_info *info, bool enable) |
456 | { | 481 | { |
457 | int ret; | 482 | int ret; |
458 | ret = regmap_update_bits(info->rtc, SEC_WTSR_SMPL_CNTL, | 483 | ret = regmap_update_bits(info->regmap, SEC_WTSR_SMPL_CNTL, |
459 | WTSR_ENABLE_MASK, | 484 | WTSR_ENABLE_MASK, |
460 | enable ? WTSR_ENABLE_MASK : 0); | 485 | enable ? WTSR_ENABLE_MASK : 0); |
461 | if (ret < 0) | 486 | if (ret < 0) |
@@ -466,7 +491,7 @@ static void s5m_rtc_enable_wtsr(struct s5m_rtc_info *info, bool enable) | |||
466 | static void s5m_rtc_enable_smpl(struct s5m_rtc_info *info, bool enable) | 491 | static void s5m_rtc_enable_smpl(struct s5m_rtc_info *info, bool enable) |
467 | { | 492 | { |
468 | int ret; | 493 | int ret; |
469 | ret = regmap_update_bits(info->rtc, SEC_WTSR_SMPL_CNTL, | 494 | ret = regmap_update_bits(info->regmap, SEC_WTSR_SMPL_CNTL, |
470 | SMPL_ENABLE_MASK, | 495 | SMPL_ENABLE_MASK, |
471 | enable ? SMPL_ENABLE_MASK : 0); | 496 | enable ? SMPL_ENABLE_MASK : 0); |
472 | if (ret < 0) | 497 | if (ret < 0) |
@@ -481,7 +506,7 @@ static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info) | |||
481 | int ret; | 506 | int ret; |
482 | struct rtc_time tm; | 507 | struct rtc_time tm; |
483 | 508 | ||
484 | ret = regmap_read(info->rtc, SEC_RTC_UDR_CON, &tp_read); | 509 | ret = regmap_read(info->regmap, SEC_RTC_UDR_CON, &tp_read); |
485 | if (ret < 0) { | 510 | if (ret < 0) { |
486 | dev_err(info->dev, "%s: fail to read control reg(%d)\n", | 511 | dev_err(info->dev, "%s: fail to read control reg(%d)\n", |
487 | __func__, ret); | 512 | __func__, ret); |
@@ -493,7 +518,7 @@ static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info) | |||
493 | data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); | 518 | data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); |
494 | 519 | ||
495 | info->rtc_24hr_mode = 1; | 520 | info->rtc_24hr_mode = 1; |
496 | ret = regmap_raw_write(info->rtc, SEC_ALARM0_CONF, data, 2); | 521 | ret = regmap_raw_write(info->regmap, SEC_ALARM0_CONF, data, 2); |
497 | if (ret < 0) { | 522 | if (ret < 0) { |
498 | dev_err(info->dev, "%s: fail to write controlm reg(%d)\n", | 523 | dev_err(info->dev, "%s: fail to write controlm reg(%d)\n", |
499 | __func__, ret); | 524 | __func__, ret); |
@@ -515,7 +540,7 @@ static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info) | |||
515 | ret = s5m_rtc_set_time(info->dev, &tm); | 540 | ret = s5m_rtc_set_time(info->dev, &tm); |
516 | } | 541 | } |
517 | 542 | ||
518 | ret = regmap_update_bits(info->rtc, SEC_RTC_UDR_CON, | 543 | ret = regmap_update_bits(info->regmap, SEC_RTC_UDR_CON, |
519 | RTC_TCON_MASK, tp_read | RTC_TCON_MASK); | 544 | RTC_TCON_MASK, tp_read | RTC_TCON_MASK); |
520 | if (ret < 0) | 545 | if (ret < 0) |
521 | dev_err(info->dev, "%s: fail to update TCON reg(%d)\n", | 546 | dev_err(info->dev, "%s: fail to update TCON reg(%d)\n", |
@@ -542,17 +567,19 @@ static int s5m_rtc_probe(struct platform_device *pdev) | |||
542 | 567 | ||
543 | info->dev = &pdev->dev; | 568 | info->dev = &pdev->dev; |
544 | info->s5m87xx = s5m87xx; | 569 | info->s5m87xx = s5m87xx; |
545 | info->rtc = s5m87xx->rtc; | 570 | info->regmap = s5m87xx->regmap_rtc; |
546 | info->device_type = s5m87xx->device_type; | 571 | info->device_type = s5m87xx->device_type; |
547 | info->wtsr_smpl = s5m87xx->wtsr_smpl; | 572 | info->wtsr_smpl = s5m87xx->wtsr_smpl; |
548 | 573 | ||
549 | switch (pdata->device_type) { | 574 | switch (pdata->device_type) { |
550 | case S5M8763X: | 575 | case S5M8763X: |
551 | info->irq = s5m87xx->irq_base + S5M8763_IRQ_ALARM0; | 576 | info->irq = regmap_irq_get_virq(s5m87xx->irq_data, |
577 | S5M8763_IRQ_ALARM0); | ||
552 | break; | 578 | break; |
553 | 579 | ||
554 | case S5M8767X: | 580 | case S5M8767X: |
555 | info->irq = s5m87xx->irq_base + S5M8767_IRQ_RTCA1; | 581 | info->irq = regmap_irq_get_virq(s5m87xx->irq_data, |
582 | S5M8767_IRQ_RTCA1); | ||
556 | break; | 583 | break; |
557 | 584 | ||
558 | default: | 585 | default: |
@@ -596,7 +623,7 @@ static void s5m_rtc_shutdown(struct platform_device *pdev) | |||
596 | if (info->wtsr_smpl) { | 623 | if (info->wtsr_smpl) { |
597 | for (i = 0; i < 3; i++) { | 624 | for (i = 0; i < 3; i++) { |
598 | s5m_rtc_enable_wtsr(info, false); | 625 | s5m_rtc_enable_wtsr(info, false); |
599 | regmap_read(info->rtc, SEC_WTSR_SMPL_CNTL, &val); | 626 | regmap_read(info->regmap, SEC_WTSR_SMPL_CNTL, &val); |
600 | pr_debug("%s: WTSR_SMPL reg(0x%02x)\n", __func__, val); | 627 | pr_debug("%s: WTSR_SMPL reg(0x%02x)\n", __func__, val); |
601 | if (val & WTSR_ENABLE_MASK) | 628 | if (val & WTSR_ENABLE_MASK) |
602 | pr_emerg("%s: fail to disable WTSR\n", | 629 | pr_emerg("%s: fail to disable WTSR\n", |
@@ -612,6 +639,30 @@ static void s5m_rtc_shutdown(struct platform_device *pdev) | |||
612 | s5m_rtc_enable_smpl(info, false); | 639 | s5m_rtc_enable_smpl(info, false); |
613 | } | 640 | } |
614 | 641 | ||
642 | static int s5m_rtc_resume(struct device *dev) | ||
643 | { | ||
644 | struct s5m_rtc_info *info = dev_get_drvdata(dev); | ||
645 | int ret = 0; | ||
646 | |||
647 | if (device_may_wakeup(dev)) | ||
648 | ret = disable_irq_wake(info->irq); | ||
649 | |||
650 | return ret; | ||
651 | } | ||
652 | |||
653 | static int s5m_rtc_suspend(struct device *dev) | ||
654 | { | ||
655 | struct s5m_rtc_info *info = dev_get_drvdata(dev); | ||
656 | int ret = 0; | ||
657 | |||
658 | if (device_may_wakeup(dev)) | ||
659 | ret = enable_irq_wake(info->irq); | ||
660 | |||
661 | return ret; | ||
662 | } | ||
663 | |||
664 | static SIMPLE_DEV_PM_OPS(s5m_rtc_pm_ops, s5m_rtc_suspend, s5m_rtc_resume); | ||
665 | |||
615 | static const struct platform_device_id s5m_rtc_id[] = { | 666 | static const struct platform_device_id s5m_rtc_id[] = { |
616 | { "s5m-rtc", 0 }, | 667 | { "s5m-rtc", 0 }, |
617 | }; | 668 | }; |
@@ -620,6 +671,7 @@ static struct platform_driver s5m_rtc_driver = { | |||
620 | .driver = { | 671 | .driver = { |
621 | .name = "s5m-rtc", | 672 | .name = "s5m-rtc", |
622 | .owner = THIS_MODULE, | 673 | .owner = THIS_MODULE, |
674 | .pm = &s5m_rtc_pm_ops, | ||
623 | }, | 675 | }, |
624 | .probe = s5m_rtc_probe, | 676 | .probe = s5m_rtc_probe, |
625 | .shutdown = s5m_rtc_shutdown, | 677 | .shutdown = s5m_rtc_shutdown, |