diff options
Diffstat (limited to 'drivers/rtc/rtc-s5m.c')
| -rw-r--r-- | drivers/rtc/rtc-s5m.c | 94 |
1 files changed, 28 insertions, 66 deletions
diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 89ac1d5083c6..8c70d785ba73 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c | |||
| @@ -15,6 +15,8 @@ | |||
| 15 | * GNU General Public License for more details. | 15 | * GNU General Public License for more details. |
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 19 | |||
| 18 | #include <linux/module.h> | 20 | #include <linux/module.h> |
| 19 | #include <linux/i2c.h> | 21 | #include <linux/i2c.h> |
| 20 | #include <linux/bcd.h> | 22 | #include <linux/bcd.h> |
| @@ -48,8 +50,6 @@ struct s5m_rtc_reg_config { | |||
| 48 | unsigned int alarm0; | 50 | unsigned int alarm0; |
| 49 | /* First register for alarm 1, seconds */ | 51 | /* First register for alarm 1, seconds */ |
| 50 | unsigned int alarm1; | 52 | unsigned int alarm1; |
| 51 | /* SMPL/WTSR register */ | ||
| 52 | unsigned int smpl_wtsr; | ||
| 53 | /* | 53 | /* |
| 54 | * Register for update flag (UDR). Typically setting UDR field to 1 | 54 | * Register for update flag (UDR). Typically setting UDR field to 1 |
| 55 | * will enable update of time or alarm register. Then it will be | 55 | * will enable update of time or alarm register. Then it will be |
| @@ -67,7 +67,6 @@ static const struct s5m_rtc_reg_config s5m_rtc_regs = { | |||
| 67 | .ctrl = S5M_ALARM1_CONF, | 67 | .ctrl = S5M_ALARM1_CONF, |
| 68 | .alarm0 = S5M_ALARM0_SEC, | 68 | .alarm0 = S5M_ALARM0_SEC, |
| 69 | .alarm1 = S5M_ALARM1_SEC, | 69 | .alarm1 = S5M_ALARM1_SEC, |
| 70 | .smpl_wtsr = S5M_WTSR_SMPL_CNTL, | ||
| 71 | .rtc_udr_update = S5M_RTC_UDR_CON, | 70 | .rtc_udr_update = S5M_RTC_UDR_CON, |
| 72 | .rtc_udr_mask = S5M_RTC_UDR_MASK, | 71 | .rtc_udr_mask = S5M_RTC_UDR_MASK, |
| 73 | }; | 72 | }; |
| @@ -82,7 +81,6 @@ static const struct s5m_rtc_reg_config s2mps_rtc_regs = { | |||
| 82 | .ctrl = S2MPS_RTC_CTRL, | 81 | .ctrl = S2MPS_RTC_CTRL, |
| 83 | .alarm0 = S2MPS_ALARM0_SEC, | 82 | .alarm0 = S2MPS_ALARM0_SEC, |
| 84 | .alarm1 = S2MPS_ALARM1_SEC, | 83 | .alarm1 = S2MPS_ALARM1_SEC, |
| 85 | .smpl_wtsr = S2MPS_WTSR_SMPL_CNTL, | ||
| 86 | .rtc_udr_update = S2MPS_RTC_UDR_CON, | 84 | .rtc_udr_update = S2MPS_RTC_UDR_CON, |
| 87 | .rtc_udr_mask = S2MPS_RTC_WUDR_MASK, | 85 | .rtc_udr_mask = S2MPS_RTC_WUDR_MASK, |
| 88 | }; | 86 | }; |
| @@ -94,9 +92,8 @@ struct s5m_rtc_info { | |||
| 94 | struct regmap *regmap; | 92 | struct regmap *regmap; |
| 95 | struct rtc_device *rtc_dev; | 93 | struct rtc_device *rtc_dev; |
| 96 | int irq; | 94 | int irq; |
| 97 | int device_type; | 95 | enum sec_device_type device_type; |
| 98 | int rtc_24hr_mode; | 96 | int rtc_24hr_mode; |
| 99 | bool wtsr_smpl; | ||
| 100 | const struct s5m_rtc_reg_config *regs; | 97 | const struct s5m_rtc_reg_config *regs; |
| 101 | }; | 98 | }; |
| 102 | 99 | ||
| @@ -151,7 +148,7 @@ static int s5m8767_tm_to_data(struct rtc_time *tm, u8 *data) | |||
| 151 | data[RTC_YEAR1] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0; | 148 | data[RTC_YEAR1] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0; |
| 152 | 149 | ||
| 153 | if (tm->tm_year < 100) { | 150 | if (tm->tm_year < 100) { |
| 154 | pr_err("s5m8767 RTC cannot handle the year %d.\n", | 151 | pr_err("RTC cannot handle the year %d\n", |
| 155 | 1900 + tm->tm_year); | 152 | 1900 + tm->tm_year); |
| 156 | return -EINVAL; | 153 | return -EINVAL; |
| 157 | } else { | 154 | } else { |
| @@ -192,6 +189,7 @@ static inline int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info, | |||
| 192 | val &= S5M_ALARM0_STATUS; | 189 | val &= S5M_ALARM0_STATUS; |
| 193 | break; | 190 | break; |
| 194 | case S2MPS14X: | 191 | case S2MPS14X: |
| 192 | case S2MPS13X: | ||
| 195 | ret = regmap_read(info->s5m87xx->regmap_pmic, S2MPS14_REG_ST2, | 193 | ret = regmap_read(info->s5m87xx->regmap_pmic, S2MPS14_REG_ST2, |
| 196 | &val); | 194 | &val); |
| 197 | val &= S2MPS_ALARM0_STATUS; | 195 | val &= S2MPS_ALARM0_STATUS; |
| @@ -257,6 +255,9 @@ static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) | |||
| 257 | case S2MPS14X: | 255 | case S2MPS14X: |
| 258 | data |= S2MPS_RTC_RUDR_MASK; | 256 | data |= S2MPS_RTC_RUDR_MASK; |
| 259 | break; | 257 | break; |
| 258 | case S2MPS13X: | ||
| 259 | data |= S2MPS13_RTC_AUDR_MASK; | ||
| 260 | break; | ||
| 260 | default: | 261 | default: |
| 261 | return -EINVAL; | 262 | return -EINVAL; |
| 262 | } | 263 | } |
| @@ -270,6 +271,11 @@ static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) | |||
| 270 | 271 | ||
| 271 | ret = s5m8767_wait_for_udr_update(info); | 272 | ret = s5m8767_wait_for_udr_update(info); |
| 272 | 273 | ||
| 274 | /* On S2MPS13 the AUDR is not auto-cleared */ | ||
| 275 | if (info->device_type == S2MPS13X) | ||
| 276 | regmap_update_bits(info->regmap, info->regs->rtc_udr_update, | ||
| 277 | S2MPS13_RTC_AUDR_MASK, 0); | ||
| 278 | |||
| 273 | return ret; | 279 | return ret; |
| 274 | } | 280 | } |
| 275 | 281 | ||
| @@ -311,7 +317,7 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) | |||
| 311 | u8 data[info->regs->regs_count]; | 317 | u8 data[info->regs->regs_count]; |
| 312 | int ret; | 318 | int ret; |
| 313 | 319 | ||
| 314 | if (info->device_type == S2MPS14X) { | 320 | if (info->device_type == S2MPS14X || info->device_type == S2MPS13X) { |
| 315 | ret = regmap_update_bits(info->regmap, | 321 | ret = regmap_update_bits(info->regmap, |
| 316 | info->regs->rtc_udr_update, | 322 | info->regs->rtc_udr_update, |
| 317 | S2MPS_RTC_RUDR_MASK, S2MPS_RTC_RUDR_MASK); | 323 | S2MPS_RTC_RUDR_MASK, S2MPS_RTC_RUDR_MASK); |
| @@ -334,6 +340,7 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) | |||
| 334 | 340 | ||
| 335 | case S5M8767X: | 341 | case S5M8767X: |
| 336 | case S2MPS14X: | 342 | case S2MPS14X: |
| 343 | case S2MPS13X: | ||
| 337 | s5m8767_data_to_tm(data, tm, info->rtc_24hr_mode); | 344 | s5m8767_data_to_tm(data, tm, info->rtc_24hr_mode); |
| 338 | break; | 345 | break; |
| 339 | 346 | ||
| @@ -360,6 +367,7 @@ static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
| 360 | break; | 367 | break; |
| 361 | case S5M8767X: | 368 | case S5M8767X: |
| 362 | case S2MPS14X: | 369 | case S2MPS14X: |
| 370 | case S2MPS13X: | ||
| 363 | ret = s5m8767_tm_to_data(tm, data); | 371 | ret = s5m8767_tm_to_data(tm, data); |
| 364 | break; | 372 | break; |
| 365 | default: | 373 | default: |
| @@ -407,6 +415,7 @@ static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
| 407 | 415 | ||
| 408 | case S5M8767X: | 416 | case S5M8767X: |
| 409 | case S2MPS14X: | 417 | case S2MPS14X: |
| 418 | case S2MPS13X: | ||
| 410 | s5m8767_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); | 419 | s5m8767_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); |
| 411 | alrm->enabled = 0; | 420 | alrm->enabled = 0; |
| 412 | for (i = 0; i < info->regs->regs_count; i++) { | 421 | for (i = 0; i < info->regs->regs_count; i++) { |
| @@ -455,6 +464,7 @@ static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info) | |||
| 455 | 464 | ||
| 456 | case S5M8767X: | 465 | case S5M8767X: |
| 457 | case S2MPS14X: | 466 | case S2MPS14X: |
| 467 | case S2MPS13X: | ||
| 458 | for (i = 0; i < info->regs->regs_count; i++) | 468 | for (i = 0; i < info->regs->regs_count; i++) |
| 459 | data[i] &= ~ALARM_ENABLE_MASK; | 469 | data[i] &= ~ALARM_ENABLE_MASK; |
| 460 | 470 | ||
| @@ -499,6 +509,7 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info) | |||
| 499 | 509 | ||
| 500 | case S5M8767X: | 510 | case S5M8767X: |
| 501 | case S2MPS14X: | 511 | case S2MPS14X: |
| 512 | case S2MPS13X: | ||
| 502 | data[RTC_SEC] |= ALARM_ENABLE_MASK; | 513 | data[RTC_SEC] |= ALARM_ENABLE_MASK; |
| 503 | data[RTC_MIN] |= ALARM_ENABLE_MASK; | 514 | data[RTC_MIN] |= ALARM_ENABLE_MASK; |
| 504 | data[RTC_HOUR] |= ALARM_ENABLE_MASK; | 515 | data[RTC_HOUR] |= ALARM_ENABLE_MASK; |
| @@ -538,6 +549,7 @@ static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
| 538 | 549 | ||
| 539 | case S5M8767X: | 550 | case S5M8767X: |
| 540 | case S2MPS14X: | 551 | case S2MPS14X: |
| 552 | case S2MPS13X: | ||
| 541 | s5m8767_tm_to_data(&alrm->time, data); | 553 | s5m8767_tm_to_data(&alrm->time, data); |
| 542 | break; | 554 | break; |
| 543 | 555 | ||
| @@ -597,28 +609,6 @@ static const struct rtc_class_ops s5m_rtc_ops = { | |||
| 597 | .alarm_irq_enable = s5m_rtc_alarm_irq_enable, | 609 | .alarm_irq_enable = s5m_rtc_alarm_irq_enable, |
| 598 | }; | 610 | }; |
| 599 | 611 | ||
| 600 | static void s5m_rtc_enable_wtsr(struct s5m_rtc_info *info, bool enable) | ||
| 601 | { | ||
| 602 | int ret; | ||
| 603 | ret = regmap_update_bits(info->regmap, info->regs->smpl_wtsr, | ||
| 604 | WTSR_ENABLE_MASK, | ||
| 605 | enable ? WTSR_ENABLE_MASK : 0); | ||
| 606 | if (ret < 0) | ||
| 607 | dev_err(info->dev, "%s: fail to update WTSR reg(%d)\n", | ||
| 608 | __func__, ret); | ||
| 609 | } | ||
| 610 | |||
| 611 | static void s5m_rtc_enable_smpl(struct s5m_rtc_info *info, bool enable) | ||
| 612 | { | ||
| 613 | int ret; | ||
| 614 | ret = regmap_update_bits(info->regmap, info->regs->smpl_wtsr, | ||
| 615 | SMPL_ENABLE_MASK, | ||
| 616 | enable ? SMPL_ENABLE_MASK : 0); | ||
| 617 | if (ret < 0) | ||
| 618 | dev_err(info->dev, "%s: fail to update SMPL reg(%d)\n", | ||
| 619 | __func__, ret); | ||
| 620 | } | ||
| 621 | |||
| 622 | static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info) | 612 | static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info) |
| 623 | { | 613 | { |
| 624 | u8 data[2]; | 614 | u8 data[2]; |
| @@ -642,6 +632,7 @@ static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info) | |||
| 642 | break; | 632 | break; |
| 643 | 633 | ||
| 644 | case S2MPS14X: | 634 | case S2MPS14X: |
| 635 | case S2MPS13X: | ||
| 645 | data[0] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); | 636 | data[0] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); |
| 646 | ret = regmap_write(info->regmap, info->regs->ctrl, data[0]); | 637 | ret = regmap_write(info->regmap, info->regs->ctrl, data[0]); |
| 647 | break; | 638 | break; |
| @@ -677,8 +668,9 @@ static int s5m_rtc_probe(struct platform_device *pdev) | |||
| 677 | if (!info) | 668 | if (!info) |
| 678 | return -ENOMEM; | 669 | return -ENOMEM; |
| 679 | 670 | ||
| 680 | switch (pdata->device_type) { | 671 | switch (platform_get_device_id(pdev)->driver_data) { |
| 681 | case S2MPS14X: | 672 | case S2MPS14X: |
| 673 | case S2MPS13X: | ||
| 682 | regmap_cfg = &s2mps14_rtc_regmap_config; | 674 | regmap_cfg = &s2mps14_rtc_regmap_config; |
| 683 | info->regs = &s2mps_rtc_regs; | 675 | info->regs = &s2mps_rtc_regs; |
| 684 | alarm_irq = S2MPS14_IRQ_RTCA0; | 676 | alarm_irq = S2MPS14_IRQ_RTCA0; |
| @@ -694,7 +686,9 @@ static int s5m_rtc_probe(struct platform_device *pdev) | |||
| 694 | alarm_irq = S5M8767_IRQ_RTCA1; | 686 | alarm_irq = S5M8767_IRQ_RTCA1; |
| 695 | break; | 687 | break; |
| 696 | default: | 688 | default: |
| 697 | dev_err(&pdev->dev, "Device type is not supported by RTC driver\n"); | 689 | dev_err(&pdev->dev, |
| 690 | "Device type %lu is not supported by RTC driver\n", | ||
| 691 | platform_get_device_id(pdev)->driver_data); | ||
| 698 | return -ENODEV; | 692 | return -ENODEV; |
| 699 | } | 693 | } |
| 700 | 694 | ||
| @@ -714,8 +708,7 @@ static int s5m_rtc_probe(struct platform_device *pdev) | |||
| 714 | 708 | ||
| 715 | info->dev = &pdev->dev; | 709 | info->dev = &pdev->dev; |
| 716 | info->s5m87xx = s5m87xx; | 710 | info->s5m87xx = s5m87xx; |
| 717 | info->device_type = s5m87xx->device_type; | 711 | info->device_type = platform_get_device_id(pdev)->driver_data; |
| 718 | info->wtsr_smpl = s5m87xx->wtsr_smpl; | ||
| 719 | 712 | ||
| 720 | if (s5m87xx->irq_data) { | 713 | if (s5m87xx->irq_data) { |
| 721 | info->irq = regmap_irq_get_virq(s5m87xx->irq_data, alarm_irq); | 714 | info->irq = regmap_irq_get_virq(s5m87xx->irq_data, alarm_irq); |
| @@ -731,11 +724,6 @@ static int s5m_rtc_probe(struct platform_device *pdev) | |||
| 731 | 724 | ||
| 732 | ret = s5m8767_rtc_init_reg(info); | 725 | ret = s5m8767_rtc_init_reg(info); |
| 733 | 726 | ||
| 734 | if (info->wtsr_smpl) { | ||
| 735 | s5m_rtc_enable_wtsr(info, true); | ||
| 736 | s5m_rtc_enable_smpl(info, true); | ||
| 737 | } | ||
| 738 | |||
| 739 | device_init_wakeup(&pdev->dev, 1); | 727 | device_init_wakeup(&pdev->dev, 1); |
| 740 | 728 | ||
| 741 | info->rtc_dev = devm_rtc_device_register(&pdev->dev, "s5m-rtc", | 729 | info->rtc_dev = devm_rtc_device_register(&pdev->dev, "s5m-rtc", |
| @@ -768,36 +756,10 @@ err: | |||
| 768 | return ret; | 756 | return ret; |
| 769 | } | 757 | } |
| 770 | 758 | ||
| 771 | static void s5m_rtc_shutdown(struct platform_device *pdev) | ||
| 772 | { | ||
| 773 | struct s5m_rtc_info *info = platform_get_drvdata(pdev); | ||
| 774 | int i; | ||
| 775 | unsigned int val = 0; | ||
| 776 | if (info->wtsr_smpl) { | ||
| 777 | for (i = 0; i < 3; i++) { | ||
| 778 | s5m_rtc_enable_wtsr(info, false); | ||
| 779 | regmap_read(info->regmap, info->regs->smpl_wtsr, &val); | ||
| 780 | pr_debug("%s: WTSR_SMPL reg(0x%02x)\n", __func__, val); | ||
| 781 | if (val & WTSR_ENABLE_MASK) | ||
| 782 | pr_emerg("%s: fail to disable WTSR\n", | ||
| 783 | __func__); | ||
| 784 | else { | ||
| 785 | pr_info("%s: success to disable WTSR\n", | ||
| 786 | __func__); | ||
| 787 | break; | ||
| 788 | } | ||
| 789 | } | ||
| 790 | } | ||
| 791 | /* Disable SMPL when power off */ | ||
| 792 | s5m_rtc_enable_smpl(info, false); | ||
| 793 | } | ||
| 794 | |||
| 795 | static int s5m_rtc_remove(struct platform_device *pdev) | 759 | static int s5m_rtc_remove(struct platform_device *pdev) |
| 796 | { | 760 | { |
| 797 | struct s5m_rtc_info *info = platform_get_drvdata(pdev); | 761 | struct s5m_rtc_info *info = platform_get_drvdata(pdev); |
| 798 | 762 | ||
| 799 | /* Perform also all shutdown steps when removing */ | ||
| 800 | s5m_rtc_shutdown(pdev); | ||
| 801 | i2c_unregister_device(info->i2c); | 763 | i2c_unregister_device(info->i2c); |
| 802 | 764 | ||
| 803 | return 0; | 765 | return 0; |
| @@ -831,6 +793,7 @@ static SIMPLE_DEV_PM_OPS(s5m_rtc_pm_ops, s5m_rtc_suspend, s5m_rtc_resume); | |||
| 831 | 793 | ||
| 832 | static const struct platform_device_id s5m_rtc_id[] = { | 794 | static const struct platform_device_id s5m_rtc_id[] = { |
| 833 | { "s5m-rtc", S5M8767X }, | 795 | { "s5m-rtc", S5M8767X }, |
| 796 | { "s2mps13-rtc", S2MPS13X }, | ||
| 834 | { "s2mps14-rtc", S2MPS14X }, | 797 | { "s2mps14-rtc", S2MPS14X }, |
| 835 | { }, | 798 | { }, |
| 836 | }; | 799 | }; |
| @@ -842,7 +805,6 @@ static struct platform_driver s5m_rtc_driver = { | |||
| 842 | }, | 805 | }, |
| 843 | .probe = s5m_rtc_probe, | 806 | .probe = s5m_rtc_probe, |
| 844 | .remove = s5m_rtc_remove, | 807 | .remove = s5m_rtc_remove, |
| 845 | .shutdown = s5m_rtc_shutdown, | ||
| 846 | .id_table = s5m_rtc_id, | 808 | .id_table = s5m_rtc_id, |
| 847 | }; | 809 | }; |
| 848 | 810 | ||
