diff options
author | Alexandre Torgue <alexandre.torgue@st.com> | 2013-07-03 18:07:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-03 19:07:59 -0400 |
commit | 25d053cf1040e6430fff679854b3710edb0b7fee (patch) | |
tree | 634f4687c40095081c1bef141085d2c7e1f30732 /drivers/rtc/rtc-ab8500.c | |
parent | 65ee88c9c68ad533463d1030d2abd859d7a4d9f9 (diff) |
drivers/rtc/rtc-ab8500.c: add second resolution to rtc driver
Android expects the RTC to have second resolution. On ab8540 cut2 RTC
block has a new register which allows setting seconds for wakeup alarms.
Existing registers (minutes hi, mid and low) have seen their offsets
changed. Here is the new mapping:
* AlarmSec (A) 0x22
* AlarmMinLow (M) from 0x8 to 0x23
* AlarmMinMid (M) from 0x9 to 0x24
* AlarmMinHigh (M) from 0xA to 0x25
Signed-off-by: Julien Delacou <julien.delacou@stericsson.com>
Signed-off-by: Alexandre Torgue <alexandre.torgue@st.com>
Acked-by: Lee Jones <lee.jones@linaro.org>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Cc: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rtc/rtc-ab8500.c')
-rw-r--r-- | drivers/rtc/rtc-ab8500.c | 63 |
1 files changed, 62 insertions, 1 deletions
diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c index c5b62d4389ee..727e2f5d14d9 100644 --- a/drivers/rtc/rtc-ab8500.c +++ b/drivers/rtc/rtc-ab8500.c | |||
@@ -35,6 +35,10 @@ | |||
35 | #define AB8500_RTC_FORCE_BKUP_REG 0x0D | 35 | #define AB8500_RTC_FORCE_BKUP_REG 0x0D |
36 | #define AB8500_RTC_CALIB_REG 0x0E | 36 | #define AB8500_RTC_CALIB_REG 0x0E |
37 | #define AB8500_RTC_SWITCH_STAT_REG 0x0F | 37 | #define AB8500_RTC_SWITCH_STAT_REG 0x0F |
38 | #define AB8540_RTC_ALRM_SEC 0x22 | ||
39 | #define AB8540_RTC_ALRM_MIN_LOW_REG 0x23 | ||
40 | #define AB8540_RTC_ALRM_MIN_MID_REG 0x24 | ||
41 | #define AB8540_RTC_ALRM_MIN_HI_REG 0x25 | ||
38 | 42 | ||
39 | /* RtcReadRequest bits */ | 43 | /* RtcReadRequest bits */ |
40 | #define RTC_READ_REQUEST 0x01 | 44 | #define RTC_READ_REQUEST 0x01 |
@@ -58,6 +62,11 @@ static const u8 ab8500_rtc_alarm_regs[] = { | |||
58 | AB8500_RTC_ALRM_MIN_LOW_REG | 62 | AB8500_RTC_ALRM_MIN_LOW_REG |
59 | }; | 63 | }; |
60 | 64 | ||
65 | static const u8 ab8540_rtc_alarm_regs[] = { | ||
66 | AB8540_RTC_ALRM_MIN_HI_REG, AB8540_RTC_ALRM_MIN_MID_REG, | ||
67 | AB8540_RTC_ALRM_MIN_LOW_REG, AB8540_RTC_ALRM_SEC | ||
68 | }; | ||
69 | |||
61 | /* Calculate the seconds from 1970 to 01-01-2000 00:00:00 */ | 70 | /* Calculate the seconds from 1970 to 01-01-2000 00:00:00 */ |
62 | static unsigned long get_elapsed_seconds(int year) | 71 | static unsigned long get_elapsed_seconds(int year) |
63 | { | 72 | { |
@@ -267,6 +276,42 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) | |||
267 | return ab8500_rtc_irq_enable(dev, alarm->enabled); | 276 | return ab8500_rtc_irq_enable(dev, alarm->enabled); |
268 | } | 277 | } |
269 | 278 | ||
279 | static int ab8540_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) | ||
280 | { | ||
281 | int retval, i; | ||
282 | unsigned char buf[ARRAY_SIZE(ab8540_rtc_alarm_regs)]; | ||
283 | unsigned long mins, secs = 0; | ||
284 | |||
285 | if (alarm->time.tm_year < (AB8500_RTC_EPOCH - 1900)) { | ||
286 | dev_dbg(dev, "year should be equal to or greater than %d\n", | ||
287 | AB8500_RTC_EPOCH); | ||
288 | return -EINVAL; | ||
289 | } | ||
290 | |||
291 | /* Get the number of seconds since 1970 */ | ||
292 | rtc_tm_to_time(&alarm->time, &secs); | ||
293 | |||
294 | /* | ||
295 | * Convert it to the number of seconds since 01-01-2000 00:00:00 | ||
296 | */ | ||
297 | secs -= get_elapsed_seconds(AB8500_RTC_EPOCH); | ||
298 | mins = secs / 60; | ||
299 | |||
300 | buf[3] = secs % 60; | ||
301 | buf[2] = mins & 0xFF; | ||
302 | buf[1] = (mins >> 8) & 0xFF; | ||
303 | buf[0] = (mins >> 16) & 0xFF; | ||
304 | |||
305 | /* Set the alarm time */ | ||
306 | for (i = 0; i < ARRAY_SIZE(ab8540_rtc_alarm_regs); i++) { | ||
307 | retval = abx500_set_register_interruptible(dev, AB8500_RTC, | ||
308 | ab8540_rtc_alarm_regs[i], buf[i]); | ||
309 | if (retval < 0) | ||
310 | return retval; | ||
311 | } | ||
312 | |||
313 | return ab8500_rtc_irq_enable(dev, alarm->enabled); | ||
314 | } | ||
270 | 315 | ||
271 | static int ab8500_rtc_set_calibration(struct device *dev, int calibration) | 316 | static int ab8500_rtc_set_calibration(struct device *dev, int calibration) |
272 | { | 317 | { |
@@ -389,8 +434,22 @@ static const struct rtc_class_ops ab8500_rtc_ops = { | |||
389 | .alarm_irq_enable = ab8500_rtc_irq_enable, | 434 | .alarm_irq_enable = ab8500_rtc_irq_enable, |
390 | }; | 435 | }; |
391 | 436 | ||
437 | static const struct rtc_class_ops ab8540_rtc_ops = { | ||
438 | .read_time = ab8500_rtc_read_time, | ||
439 | .set_time = ab8500_rtc_set_time, | ||
440 | .read_alarm = ab8500_rtc_read_alarm, | ||
441 | .set_alarm = ab8540_rtc_set_alarm, | ||
442 | .alarm_irq_enable = ab8500_rtc_irq_enable, | ||
443 | }; | ||
444 | |||
445 | static struct platform_device_id ab85xx_rtc_ids[] = { | ||
446 | { "ab8500-rtc", (kernel_ulong_t)&ab8500_rtc_ops, }, | ||
447 | { "ab8540-rtc", (kernel_ulong_t)&ab8540_rtc_ops, }, | ||
448 | }; | ||
449 | |||
392 | static int ab8500_rtc_probe(struct platform_device *pdev) | 450 | static int ab8500_rtc_probe(struct platform_device *pdev) |
393 | { | 451 | { |
452 | const struct platform_device_id *platid = platform_get_device_id(pdev); | ||
394 | int err; | 453 | int err; |
395 | struct rtc_device *rtc; | 454 | struct rtc_device *rtc; |
396 | u8 rtc_ctrl; | 455 | u8 rtc_ctrl; |
@@ -423,7 +482,8 @@ static int ab8500_rtc_probe(struct platform_device *pdev) | |||
423 | device_init_wakeup(&pdev->dev, true); | 482 | device_init_wakeup(&pdev->dev, true); |
424 | 483 | ||
425 | rtc = devm_rtc_device_register(&pdev->dev, "ab8500-rtc", | 484 | rtc = devm_rtc_device_register(&pdev->dev, "ab8500-rtc", |
426 | &ab8500_rtc_ops, THIS_MODULE); | 485 | (struct rtc_class_ops *)platid->driver_data, |
486 | THIS_MODULE); | ||
427 | if (IS_ERR(rtc)) { | 487 | if (IS_ERR(rtc)) { |
428 | dev_err(&pdev->dev, "Registration failed\n"); | 488 | dev_err(&pdev->dev, "Registration failed\n"); |
429 | err = PTR_ERR(rtc); | 489 | err = PTR_ERR(rtc); |
@@ -461,6 +521,7 @@ static struct platform_driver ab8500_rtc_driver = { | |||
461 | }, | 521 | }, |
462 | .probe = ab8500_rtc_probe, | 522 | .probe = ab8500_rtc_probe, |
463 | .remove = ab8500_rtc_remove, | 523 | .remove = ab8500_rtc_remove, |
524 | .id_table = ab85xx_rtc_ids, | ||
464 | }; | 525 | }; |
465 | 526 | ||
466 | module_platform_driver(ab8500_rtc_driver); | 527 | module_platform_driver(ab8500_rtc_driver); |