diff options
author | Mylène Josserand <mylene.josserand@free-electrons.com> | 2016-05-03 05:54:38 -0400 |
---|---|---|
committer | Alexandre Belloni <alexandre.belloni@free-electrons.com> | 2016-05-21 11:07:00 -0400 |
commit | 0ddc5b89cd12938e251c691563f45409b4d15d98 (patch) | |
tree | 14498555704c54d71fddbd0be95e74336b60a08f /drivers/rtc | |
parent | 38201ca3c58d27ac95ee08995558c7176b4feb13 (diff) |
rtc: rv3029: add alarm IRQ
Add the alarm IRQ functionality.
Signed-off-by: Mylène Josserand <mylene.josserand@free-electrons.com>
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/rtc-rv3029c2.c | 114 |
1 files changed, 93 insertions, 21 deletions
diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c index 916bbc2f57de..c2ef64fb4757 100644 --- a/drivers/rtc/rtc-rv3029c2.c +++ b/drivers/rtc/rtc-rv3029c2.c | |||
@@ -329,6 +329,47 @@ static int rv3029_eeprom_update_bits(struct device *dev, | |||
329 | return 0; | 329 | return 0; |
330 | } | 330 | } |
331 | 331 | ||
332 | static irqreturn_t rv3029_handle_irq(int irq, void *dev_id) | ||
333 | { | ||
334 | struct device *dev = dev_id; | ||
335 | struct rv3029_data *rv3029 = dev_get_drvdata(dev); | ||
336 | struct mutex *lock = &rv3029->rtc->ops_lock; | ||
337 | unsigned long events = 0; | ||
338 | u8 flags, controls; | ||
339 | int ret; | ||
340 | |||
341 | mutex_lock(lock); | ||
342 | |||
343 | ret = rv3029_read_regs(dev, RV3029_IRQ_CTRL, &controls, 1); | ||
344 | if (ret) { | ||
345 | dev_warn(dev, "Read IRQ Control Register error %d\n", ret); | ||
346 | mutex_unlock(lock); | ||
347 | return IRQ_NONE; | ||
348 | } | ||
349 | |||
350 | ret = rv3029_read_regs(dev, RV3029_IRQ_FLAGS, &flags, 1); | ||
351 | if (ret) { | ||
352 | dev_warn(dev, "Read IRQ Flags Register error %d\n", ret); | ||
353 | mutex_unlock(lock); | ||
354 | return IRQ_NONE; | ||
355 | } | ||
356 | |||
357 | if (flags & RV3029_IRQ_FLAGS_AF) { | ||
358 | flags &= ~RV3029_IRQ_FLAGS_AF; | ||
359 | controls &= ~RV3029_IRQ_CTRL_AIE; | ||
360 | events |= RTC_AF; | ||
361 | } | ||
362 | |||
363 | if (events) { | ||
364 | rtc_update_irq(rv3029->rtc, 1, events); | ||
365 | rv3029_write_regs(dev, RV3029_IRQ_FLAGS, &flags, 1); | ||
366 | rv3029_write_regs(dev, RV3029_IRQ_CTRL, &controls, 1); | ||
367 | } | ||
368 | mutex_unlock(lock); | ||
369 | |||
370 | return IRQ_HANDLED; | ||
371 | } | ||
372 | |||
332 | static int rv3029_read_time(struct device *dev, struct rtc_time *tm) | 373 | static int rv3029_read_time(struct device *dev, struct rtc_time *tm) |
333 | { | 374 | { |
334 | u8 buf[1]; | 375 | u8 buf[1]; |
@@ -376,7 +417,7 @@ static int rv3029_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) | |||
376 | { | 417 | { |
377 | struct rtc_time *const tm = &alarm->time; | 418 | struct rtc_time *const tm = &alarm->time; |
378 | int ret; | 419 | int ret; |
379 | u8 regs[8]; | 420 | u8 regs[8], controls, flags; |
380 | 421 | ||
381 | ret = rv3029_get_sr(dev, regs); | 422 | ret = rv3029_get_sr(dev, regs); |
382 | if (ret < 0) { | 423 | if (ret < 0) { |
@@ -392,6 +433,17 @@ static int rv3029_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) | |||
392 | return ret; | 433 | return ret; |
393 | } | 434 | } |
394 | 435 | ||
436 | ret = rv3029_read_regs(dev, RV3029_IRQ_CTRL, &controls, 1); | ||
437 | if (ret) { | ||
438 | dev_err(dev, "Read IRQ Control Register error %d\n", ret); | ||
439 | return ret; | ||
440 | } | ||
441 | ret = rv3029_read_regs(dev, RV3029_IRQ_FLAGS, &flags, 1); | ||
442 | if (ret < 0) { | ||
443 | dev_err(dev, "Read IRQ Flags Register error %d\n", ret); | ||
444 | return ret; | ||
445 | } | ||
446 | |||
395 | tm->tm_sec = bcd2bin(regs[RV3029_A_SC - RV3029_A_SC] & 0x7f); | 447 | tm->tm_sec = bcd2bin(regs[RV3029_A_SC - RV3029_A_SC] & 0x7f); |
396 | tm->tm_min = bcd2bin(regs[RV3029_A_MN - RV3029_A_SC] & 0x7f); | 448 | tm->tm_min = bcd2bin(regs[RV3029_A_MN - RV3029_A_SC] & 0x7f); |
397 | tm->tm_hour = bcd2bin(regs[RV3029_A_HR - RV3029_A_SC] & 0x3f); | 449 | tm->tm_hour = bcd2bin(regs[RV3029_A_HR - RV3029_A_SC] & 0x3f); |
@@ -400,16 +452,30 @@ static int rv3029_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) | |||
400 | tm->tm_year = bcd2bin(regs[RV3029_A_YR - RV3029_A_SC] & 0x7f) + 100; | 452 | tm->tm_year = bcd2bin(regs[RV3029_A_YR - RV3029_A_SC] & 0x7f) + 100; |
401 | tm->tm_wday = bcd2bin(regs[RV3029_A_DW - RV3029_A_SC] & 0x07) - 1; | 453 | tm->tm_wday = bcd2bin(regs[RV3029_A_DW - RV3029_A_SC] & 0x07) - 1; |
402 | 454 | ||
455 | alarm->enabled = !!(controls & RV3029_IRQ_CTRL_AIE); | ||
456 | alarm->pending = (flags & RV3029_IRQ_FLAGS_AF) && alarm->enabled; | ||
457 | |||
403 | return 0; | 458 | return 0; |
404 | } | 459 | } |
405 | 460 | ||
406 | static int rv3029_rtc_alarm_set_irq(struct device *dev, int enable) | 461 | static int rv3029_alarm_irq_enable(struct device *dev, unsigned int enable) |
407 | { | 462 | { |
408 | int ret; | 463 | int ret; |
464 | u8 controls; | ||
465 | |||
466 | ret = rv3029_read_regs(dev, RV3029_IRQ_CTRL, &controls, 1); | ||
467 | if (ret < 0) { | ||
468 | dev_warn(dev, "Read IRQ Control Register error %d\n", ret); | ||
469 | return ret; | ||
470 | } | ||
409 | 471 | ||
410 | /* enable/disable AIE irq */ | 472 | /* enable/disable AIE irq */ |
411 | ret = rv3029_update_bits(dev, RV3029_IRQ_CTRL, RV3029_IRQ_CTRL_AIE, | 473 | if (enable) |
412 | (enable ? RV3029_IRQ_CTRL_AIE : 0)); | 474 | controls |= RV3029_IRQ_CTRL_AIE; |
475 | else | ||
476 | controls &= ~RV3029_IRQ_CTRL_AIE; | ||
477 | |||
478 | ret = rv3029_write_regs(dev, RV3029_IRQ_CTRL, &controls, 1); | ||
413 | if (ret < 0) { | 479 | if (ret < 0) { |
414 | dev_err(dev, "can't update INT reg\n"); | 480 | dev_err(dev, "can't update INT reg\n"); |
415 | return ret; | 481 | return ret; |
@@ -459,26 +525,15 @@ static int rv3029_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) | |||
459 | return ret; | 525 | return ret; |
460 | 526 | ||
461 | if (alarm->enabled) { | 527 | if (alarm->enabled) { |
462 | /* clear AF flag */ | ||
463 | ret = rv3029_update_bits(dev, RV3029_IRQ_FLAGS, | ||
464 | RV3029_IRQ_FLAGS_AF, 0); | ||
465 | if (ret < 0) { | ||
466 | dev_err(dev, "can't clear alarm flag\n"); | ||
467 | return ret; | ||
468 | } | ||
469 | /* enable AIE irq */ | 528 | /* enable AIE irq */ |
470 | ret = rv3029_rtc_alarm_set_irq(dev, 1); | 529 | ret = rv3029_alarm_irq_enable(dev, 1); |
471 | if (ret) | 530 | if (ret) |
472 | return ret; | 531 | return ret; |
473 | |||
474 | dev_dbg(dev, "alarm IRQ armed\n"); | ||
475 | } else { | 532 | } else { |
476 | /* disable AIE irq */ | 533 | /* disable AIE irq */ |
477 | ret = rv3029_rtc_alarm_set_irq(dev, 0); | 534 | ret = rv3029_alarm_irq_enable(dev, 0); |
478 | if (ret) | 535 | if (ret) |
479 | return ret; | 536 | return ret; |
480 | |||
481 | dev_dbg(dev, "alarm IRQ disabled\n"); | ||
482 | } | 537 | } |
483 | 538 | ||
484 | return 0; | 539 | return 0; |
@@ -731,11 +786,9 @@ static void rv3029_hwmon_register(struct device *dev, const char *name) | |||
731 | 786 | ||
732 | #endif /* CONFIG_RTC_DRV_RV3029_HWMON */ | 787 | #endif /* CONFIG_RTC_DRV_RV3029_HWMON */ |
733 | 788 | ||
734 | static const struct rtc_class_ops rv3029_rtc_ops = { | 789 | static struct rtc_class_ops rv3029_rtc_ops = { |
735 | .read_time = rv3029_read_time, | 790 | .read_time = rv3029_read_time, |
736 | .set_time = rv3029_set_time, | 791 | .set_time = rv3029_set_time, |
737 | .read_alarm = rv3029_read_alarm, | ||
738 | .set_alarm = rv3029_set_alarm, | ||
739 | }; | 792 | }; |
740 | 793 | ||
741 | static struct i2c_device_id rv3029_id[] = { | 794 | static struct i2c_device_id rv3029_id[] = { |
@@ -772,8 +825,27 @@ static int rv3029_probe(struct device *dev, struct regmap *regmap, int irq, | |||
772 | 825 | ||
773 | rv3029->rtc = devm_rtc_device_register(dev, name, &rv3029_rtc_ops, | 826 | rv3029->rtc = devm_rtc_device_register(dev, name, &rv3029_rtc_ops, |
774 | THIS_MODULE); | 827 | THIS_MODULE); |
828 | if (IS_ERR(rv3029->rtc)) { | ||
829 | dev_err(dev, "unable to register the class device\n"); | ||
830 | return PTR_ERR(rv3029->rtc); | ||
831 | } | ||
775 | 832 | ||
776 | return PTR_ERR_OR_ZERO(rv3029->rtc); | 833 | if (rv3029->irq > 0) { |
834 | rc = devm_request_threaded_irq(dev, rv3029->irq, | ||
835 | NULL, rv3029_handle_irq, | ||
836 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | ||
837 | "rv3029", dev); | ||
838 | if (rc) { | ||
839 | dev_warn(dev, "unable to request IRQ, alarms disabled\n"); | ||
840 | rv3029->irq = 0; | ||
841 | } else { | ||
842 | rv3029_rtc_ops.read_alarm = rv3029_read_alarm; | ||
843 | rv3029_rtc_ops.set_alarm = rv3029_set_alarm; | ||
844 | rv3029_rtc_ops.alarm_irq_enable = rv3029_alarm_irq_enable; | ||
845 | } | ||
846 | } | ||
847 | |||
848 | return 0; | ||
777 | } | 849 | } |
778 | 850 | ||
779 | #if IS_ENABLED(CONFIG_I2C) | 851 | #if IS_ENABLED(CONFIG_I2C) |