diff options
Diffstat (limited to 'drivers/rtc/rtc-max77686.c')
| -rw-r--r-- | drivers/rtc/rtc-max77686.c | 167 |
1 files changed, 39 insertions, 128 deletions
diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index 9efe118a28ba..cf73e969c8cc 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c | |||
| @@ -32,15 +32,6 @@ | |||
| 32 | #define RTC_UDR_MASK (1 << RTC_UDR_SHIFT) | 32 | #define RTC_UDR_MASK (1 << RTC_UDR_SHIFT) |
| 33 | #define RTC_RBUDR_SHIFT 4 | 33 | #define RTC_RBUDR_SHIFT 4 |
| 34 | #define RTC_RBUDR_MASK (1 << RTC_RBUDR_SHIFT) | 34 | #define RTC_RBUDR_MASK (1 << RTC_RBUDR_SHIFT) |
| 35 | /* WTSR and SMPL Register */ | ||
| 36 | #define WTSRT_SHIFT 0 | ||
| 37 | #define SMPLT_SHIFT 2 | ||
| 38 | #define WTSR_EN_SHIFT 6 | ||
| 39 | #define SMPL_EN_SHIFT 7 | ||
| 40 | #define WTSRT_MASK (3 << WTSRT_SHIFT) | ||
| 41 | #define SMPLT_MASK (3 << SMPLT_SHIFT) | ||
| 42 | #define WTSR_EN_MASK (1 << WTSR_EN_SHIFT) | ||
| 43 | #define SMPL_EN_MASK (1 << SMPL_EN_SHIFT) | ||
| 44 | /* RTC Hour register */ | 35 | /* RTC Hour register */ |
| 45 | #define HOUR_PM_SHIFT 6 | 36 | #define HOUR_PM_SHIFT 6 |
| 46 | #define HOUR_PM_MASK (1 << HOUR_PM_SHIFT) | 37 | #define HOUR_PM_MASK (1 << HOUR_PM_SHIFT) |
| @@ -49,7 +40,6 @@ | |||
| 49 | #define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT) | 40 | #define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT) |
| 50 | 41 | ||
| 51 | #define MAX77686_RTC_UPDATE_DELAY 16 | 42 | #define MAX77686_RTC_UPDATE_DELAY 16 |
| 52 | #undef MAX77686_RTC_WTSR_SMPL | ||
| 53 | 43 | ||
| 54 | enum { | 44 | enum { |
| 55 | RTC_SEC = 0, | 45 | RTC_SEC = 0, |
| @@ -80,16 +70,6 @@ enum MAX77686_RTC_OP { | |||
| 80 | MAX77686_RTC_READ, | 70 | MAX77686_RTC_READ, |
| 81 | }; | 71 | }; |
| 82 | 72 | ||
| 83 | static inline int max77686_rtc_calculate_wday(u8 shifted) | ||
| 84 | { | ||
| 85 | int counter = -1; | ||
| 86 | while (shifted) { | ||
| 87 | shifted >>= 1; | ||
| 88 | counter++; | ||
| 89 | } | ||
| 90 | return counter; | ||
| 91 | } | ||
| 92 | |||
| 93 | static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm, | 73 | static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm, |
| 94 | int rtc_24hr_mode) | 74 | int rtc_24hr_mode) |
| 95 | { | 75 | { |
| @@ -103,7 +83,8 @@ static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm, | |||
| 103 | tm->tm_hour += 12; | 83 | tm->tm_hour += 12; |
| 104 | } | 84 | } |
| 105 | 85 | ||
| 106 | tm->tm_wday = max77686_rtc_calculate_wday(data[RTC_WEEKDAY] & 0x7f); | 86 | /* Only a single bit is set in data[], so fls() would be equivalent */ |
| 87 | tm->tm_wday = ffs(data[RTC_WEEKDAY] & 0x7f) - 1; | ||
| 107 | tm->tm_mday = data[RTC_DATE] & 0x1f; | 88 | tm->tm_mday = data[RTC_DATE] & 0x1f; |
| 108 | tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1; | 89 | tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1; |
| 109 | tm->tm_year = (data[RTC_YEAR] & 0x7f) + 100; | 90 | tm->tm_year = (data[RTC_YEAR] & 0x7f) + 100; |
| @@ -412,64 +393,6 @@ static const struct rtc_class_ops max77686_rtc_ops = { | |||
| 412 | .alarm_irq_enable = max77686_rtc_alarm_irq_enable, | 393 | .alarm_irq_enable = max77686_rtc_alarm_irq_enable, |
| 413 | }; | 394 | }; |
| 414 | 395 | ||
| 415 | #ifdef MAX77686_RTC_WTSR_SMPL | ||
| 416 | static void max77686_rtc_enable_wtsr(struct max77686_rtc_info *info, bool enable) | ||
| 417 | { | ||
| 418 | int ret; | ||
| 419 | unsigned int val, mask; | ||
| 420 | |||
| 421 | if (enable) | ||
| 422 | val = (1 << WTSR_EN_SHIFT) | (3 << WTSRT_SHIFT); | ||
| 423 | else | ||
| 424 | val = 0; | ||
| 425 | |||
| 426 | mask = WTSR_EN_MASK | WTSRT_MASK; | ||
| 427 | |||
| 428 | dev_info(info->dev, "%s: %s WTSR\n", __func__, | ||
| 429 | enable ? "enable" : "disable"); | ||
| 430 | |||
| 431 | ret = regmap_update_bits(info->max77686->rtc_regmap, | ||
| 432 | MAX77686_WTSR_SMPL_CNTL, mask, val); | ||
| 433 | if (ret < 0) { | ||
| 434 | dev_err(info->dev, "%s: fail to update WTSR reg(%d)\n", | ||
| 435 | __func__, ret); | ||
| 436 | return; | ||
| 437 | } | ||
| 438 | |||
| 439 | max77686_rtc_update(info, MAX77686_RTC_WRITE); | ||
| 440 | } | ||
| 441 | |||
| 442 | static void max77686_rtc_enable_smpl(struct max77686_rtc_info *info, bool enable) | ||
| 443 | { | ||
| 444 | int ret; | ||
| 445 | unsigned int val, mask; | ||
| 446 | |||
| 447 | if (enable) | ||
| 448 | val = (1 << SMPL_EN_SHIFT) | (0 << SMPLT_SHIFT); | ||
| 449 | else | ||
| 450 | val = 0; | ||
| 451 | |||
| 452 | mask = SMPL_EN_MASK | SMPLT_MASK; | ||
| 453 | |||
| 454 | dev_info(info->dev, "%s: %s SMPL\n", __func__, | ||
| 455 | enable ? "enable" : "disable"); | ||
| 456 | |||
| 457 | ret = regmap_update_bits(info->max77686->rtc_regmap, | ||
| 458 | MAX77686_WTSR_SMPL_CNTL, mask, val); | ||
| 459 | if (ret < 0) { | ||
| 460 | dev_err(info->dev, "%s: fail to update SMPL reg(%d)\n", | ||
| 461 | __func__, ret); | ||
| 462 | return; | ||
| 463 | } | ||
| 464 | |||
| 465 | max77686_rtc_update(info, MAX77686_RTC_WRITE); | ||
| 466 | |||
| 467 | val = 0; | ||
| 468 | regmap_read(info->max77686->rtc_regmap, MAX77686_WTSR_SMPL_CNTL, &val); | ||
| 469 | dev_info(info->dev, "%s: WTSR_SMPL(0x%02x)\n", __func__, val); | ||
| 470 | } | ||
| 471 | #endif /* MAX77686_RTC_WTSR_SMPL */ | ||
| 472 | |||
| 473 | static int max77686_rtc_init_reg(struct max77686_rtc_info *info) | 396 | static int max77686_rtc_init_reg(struct max77686_rtc_info *info) |
| 474 | { | 397 | { |
| 475 | u8 data[2]; | 398 | u8 data[2]; |
| @@ -492,16 +415,11 @@ static int max77686_rtc_init_reg(struct max77686_rtc_info *info) | |||
| 492 | return ret; | 415 | return ret; |
| 493 | } | 416 | } |
| 494 | 417 | ||
| 495 | static struct regmap_config max77686_rtc_regmap_config = { | ||
| 496 | .reg_bits = 8, | ||
| 497 | .val_bits = 8, | ||
| 498 | }; | ||
| 499 | |||
| 500 | static int max77686_rtc_probe(struct platform_device *pdev) | 418 | static int max77686_rtc_probe(struct platform_device *pdev) |
| 501 | { | 419 | { |
| 502 | struct max77686_dev *max77686 = dev_get_drvdata(pdev->dev.parent); | 420 | struct max77686_dev *max77686 = dev_get_drvdata(pdev->dev.parent); |
| 503 | struct max77686_rtc_info *info; | 421 | struct max77686_rtc_info *info; |
| 504 | int ret, virq; | 422 | int ret; |
| 505 | 423 | ||
| 506 | dev_info(&pdev->dev, "%s\n", __func__); | 424 | dev_info(&pdev->dev, "%s\n", __func__); |
| 507 | 425 | ||
| @@ -514,14 +432,7 @@ static int max77686_rtc_probe(struct platform_device *pdev) | |||
| 514 | info->dev = &pdev->dev; | 432 | info->dev = &pdev->dev; |
| 515 | info->max77686 = max77686; | 433 | info->max77686 = max77686; |
| 516 | info->rtc = max77686->rtc; | 434 | info->rtc = max77686->rtc; |
| 517 | info->max77686->rtc_regmap = devm_regmap_init_i2c(info->max77686->rtc, | 435 | |
| 518 | &max77686_rtc_regmap_config); | ||
| 519 | if (IS_ERR(info->max77686->rtc_regmap)) { | ||
| 520 | ret = PTR_ERR(info->max77686->rtc_regmap); | ||
| 521 | dev_err(info->max77686->dev, "Failed to allocate register map: %d\n", | ||
| 522 | ret); | ||
| 523 | return ret; | ||
| 524 | } | ||
| 525 | platform_set_drvdata(pdev, info); | 436 | platform_set_drvdata(pdev, info); |
| 526 | 437 | ||
| 527 | ret = max77686_rtc_init_reg(info); | 438 | ret = max77686_rtc_init_reg(info); |
| @@ -531,34 +442,34 @@ static int max77686_rtc_probe(struct platform_device *pdev) | |||
| 531 | goto err_rtc; | 442 | goto err_rtc; |
| 532 | } | 443 | } |
| 533 | 444 | ||
| 534 | #ifdef MAX77686_RTC_WTSR_SMPL | ||
| 535 | max77686_rtc_enable_wtsr(info, true); | ||
| 536 | max77686_rtc_enable_smpl(info, true); | ||
| 537 | #endif | ||
| 538 | |||
| 539 | device_init_wakeup(&pdev->dev, 1); | 445 | device_init_wakeup(&pdev->dev, 1); |
| 540 | 446 | ||
| 541 | info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max77686-rtc", | 447 | info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max77686-rtc", |
| 542 | &max77686_rtc_ops, THIS_MODULE); | 448 | &max77686_rtc_ops, THIS_MODULE); |
| 543 | 449 | ||
| 544 | if (IS_ERR(info->rtc_dev)) { | 450 | if (IS_ERR(info->rtc_dev)) { |
| 545 | dev_info(&pdev->dev, "%s: fail\n", __func__); | ||
| 546 | |||
| 547 | ret = PTR_ERR(info->rtc_dev); | 451 | ret = PTR_ERR(info->rtc_dev); |
| 548 | dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); | 452 | dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); |
| 549 | if (ret == 0) | 453 | if (ret == 0) |
| 550 | ret = -EINVAL; | 454 | ret = -EINVAL; |
| 551 | goto err_rtc; | 455 | goto err_rtc; |
| 552 | } | 456 | } |
| 553 | virq = irq_create_mapping(max77686->irq_domain, MAX77686_RTCIRQ_RTCA1); | 457 | |
| 554 | if (!virq) { | 458 | if (!max77686->rtc_irq_data) { |
| 459 | ret = -EINVAL; | ||
| 460 | dev_err(&pdev->dev, "%s: no RTC regmap IRQ chip\n", __func__); | ||
| 461 | goto err_rtc; | ||
| 462 | } | ||
| 463 | |||
| 464 | info->virq = regmap_irq_get_virq(max77686->rtc_irq_data, | ||
| 465 | MAX77686_RTCIRQ_RTCA1); | ||
| 466 | if (!info->virq) { | ||
| 555 | ret = -ENXIO; | 467 | ret = -ENXIO; |
| 556 | goto err_rtc; | 468 | goto err_rtc; |
| 557 | } | 469 | } |
| 558 | info->virq = virq; | ||
| 559 | 470 | ||
| 560 | ret = devm_request_threaded_irq(&pdev->dev, virq, NULL, | 471 | ret = devm_request_threaded_irq(&pdev->dev, info->virq, NULL, |
| 561 | max77686_rtc_alarm_irq, 0, "rtc-alarm0", info); | 472 | max77686_rtc_alarm_irq, 0, "rtc-alarm1", info); |
| 562 | if (ret < 0) | 473 | if (ret < 0) |
| 563 | dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", | 474 | dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", |
| 564 | info->virq, ret); | 475 | info->virq, ret); |
| @@ -567,33 +478,33 @@ err_rtc: | |||
| 567 | return ret; | 478 | return ret; |
| 568 | } | 479 | } |
| 569 | 480 | ||
| 570 | static void max77686_rtc_shutdown(struct platform_device *pdev) | 481 | #ifdef CONFIG_PM_SLEEP |
| 482 | static int max77686_rtc_suspend(struct device *dev) | ||
| 571 | { | 483 | { |
| 572 | #ifdef MAX77686_RTC_WTSR_SMPL | 484 | if (device_may_wakeup(dev)) { |
| 573 | struct max77686_rtc_info *info = platform_get_drvdata(pdev); | 485 | struct max77686_rtc_info *info = dev_get_drvdata(dev); |
| 574 | int i; | 486 | |
| 575 | u8 val = 0; | 487 | return enable_irq_wake(info->virq); |
| 576 | |||
| 577 | for (i = 0; i < 3; i++) { | ||
| 578 | max77686_rtc_enable_wtsr(info, false); | ||
| 579 | regmap_read(info->max77686->rtc_regmap, MAX77686_WTSR_SMPL_CNTL, &val); | ||
| 580 | dev_info(info->dev, "%s: WTSR_SMPL reg(0x%02x)\n", __func__, | ||
| 581 | val); | ||
| 582 | if (val & WTSR_EN_MASK) { | ||
| 583 | dev_emerg(info->dev, "%s: fail to disable WTSR\n", | ||
| 584 | __func__); | ||
| 585 | } else { | ||
| 586 | dev_info(info->dev, "%s: success to disable WTSR\n", | ||
| 587 | __func__); | ||
| 588 | break; | ||
| 589 | } | ||
| 590 | } | 488 | } |
| 591 | 489 | ||
| 592 | /* Disable SMPL when power off */ | 490 | return 0; |
| 593 | max77686_rtc_enable_smpl(info, false); | ||
| 594 | #endif /* MAX77686_RTC_WTSR_SMPL */ | ||
| 595 | } | 491 | } |
| 596 | 492 | ||
| 493 | static int max77686_rtc_resume(struct device *dev) | ||
| 494 | { | ||
| 495 | if (device_may_wakeup(dev)) { | ||
| 496 | struct max77686_rtc_info *info = dev_get_drvdata(dev); | ||
| 497 | |||
| 498 | return disable_irq_wake(info->virq); | ||
| 499 | } | ||
| 500 | |||
| 501 | return 0; | ||
| 502 | } | ||
| 503 | #endif | ||
| 504 | |||
| 505 | static SIMPLE_DEV_PM_OPS(max77686_rtc_pm_ops, | ||
| 506 | max77686_rtc_suspend, max77686_rtc_resume); | ||
| 507 | |||
| 597 | static const struct platform_device_id rtc_id[] = { | 508 | static const struct platform_device_id rtc_id[] = { |
| 598 | { "max77686-rtc", 0 }, | 509 | { "max77686-rtc", 0 }, |
| 599 | {}, | 510 | {}, |
| @@ -603,9 +514,9 @@ static struct platform_driver max77686_rtc_driver = { | |||
| 603 | .driver = { | 514 | .driver = { |
| 604 | .name = "max77686-rtc", | 515 | .name = "max77686-rtc", |
| 605 | .owner = THIS_MODULE, | 516 | .owner = THIS_MODULE, |
| 517 | .pm = &max77686_rtc_pm_ops, | ||
| 606 | }, | 518 | }, |
| 607 | .probe = max77686_rtc_probe, | 519 | .probe = max77686_rtc_probe, |
| 608 | .shutdown = max77686_rtc_shutdown, | ||
| 609 | .id_table = rtc_id, | 520 | .id_table = rtc_id, |
| 610 | }; | 521 | }; |
| 611 | 522 | ||
