diff options
Diffstat (limited to 'drivers/rtc/rtc-s5m.c')
| -rw-r--r-- | drivers/rtc/rtc-s5m.c | 131 |
1 files changed, 101 insertions, 30 deletions
diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index f2504b4eef34..7407d7394bb4 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c | |||
| @@ -38,7 +38,22 @@ | |||
| 38 | */ | 38 | */ |
| 39 | #define UDR_READ_RETRY_CNT 5 | 39 | #define UDR_READ_RETRY_CNT 5 |
| 40 | 40 | ||
| 41 | /* Registers used by the driver which are different between chipsets. */ | 41 | /* |
| 42 | * Registers used by the driver which are different between chipsets. | ||
| 43 | * | ||
| 44 | * Operations like read time and write alarm/time require updating | ||
| 45 | * specific fields in UDR register. These fields usually are auto-cleared | ||
| 46 | * (with some exceptions). | ||
| 47 | * | ||
| 48 | * Table of operations per device: | ||
| 49 | * | ||
| 50 | * Device | Write time | Read time | Write alarm | ||
| 51 | * ================================================= | ||
| 52 | * S5M8767 | UDR + TIME | | UDR | ||
| 53 | * S2MPS11/14 | WUDR | RUDR | WUDR + RUDR | ||
| 54 | * S2MPS13 | WUDR | RUDR | WUDR + AUDR | ||
| 55 | * S2MPS15 | WUDR | RUDR | AUDR | ||
| 56 | */ | ||
| 42 | struct s5m_rtc_reg_config { | 57 | struct s5m_rtc_reg_config { |
| 43 | /* Number of registers used for setting time/alarm0/alarm1 */ | 58 | /* Number of registers used for setting time/alarm0/alarm1 */ |
| 44 | unsigned int regs_count; | 59 | unsigned int regs_count; |
| @@ -55,9 +70,16 @@ struct s5m_rtc_reg_config { | |||
| 55 | * will enable update of time or alarm register. Then it will be | 70 | * will enable update of time or alarm register. Then it will be |
| 56 | * auto-cleared after successful update. | 71 | * auto-cleared after successful update. |
| 57 | */ | 72 | */ |
| 58 | unsigned int rtc_udr_update; | 73 | unsigned int udr_update; |
| 59 | /* Mask for UDR field in 'rtc_udr_update' register */ | 74 | /* Auto-cleared mask in UDR field for writing time and alarm */ |
| 60 | unsigned int rtc_udr_mask; | 75 | unsigned int autoclear_udr_mask; |
| 76 | /* | ||
| 77 | * Masks in UDR field for time and alarm operations. | ||
| 78 | * The read time mask can be 0. Rest should not. | ||
| 79 | */ | ||
| 80 | unsigned int read_time_udr_mask; | ||
| 81 | unsigned int write_time_udr_mask; | ||
| 82 | unsigned int write_alarm_udr_mask; | ||
| 61 | }; | 83 | }; |
| 62 | 84 | ||
| 63 | /* Register map for S5M8763 and S5M8767 */ | 85 | /* Register map for S5M8763 and S5M8767 */ |
| @@ -67,22 +89,56 @@ static const struct s5m_rtc_reg_config s5m_rtc_regs = { | |||
| 67 | .ctrl = S5M_ALARM1_CONF, | 89 | .ctrl = S5M_ALARM1_CONF, |
| 68 | .alarm0 = S5M_ALARM0_SEC, | 90 | .alarm0 = S5M_ALARM0_SEC, |
| 69 | .alarm1 = S5M_ALARM1_SEC, | 91 | .alarm1 = S5M_ALARM1_SEC, |
| 70 | .rtc_udr_update = S5M_RTC_UDR_CON, | 92 | .udr_update = S5M_RTC_UDR_CON, |
| 71 | .rtc_udr_mask = S5M_RTC_UDR_MASK, | 93 | .autoclear_udr_mask = S5M_RTC_UDR_MASK, |
| 94 | .read_time_udr_mask = 0, /* Not needed */ | ||
| 95 | .write_time_udr_mask = S5M_RTC_UDR_MASK | S5M_RTC_TIME_EN_MASK, | ||
| 96 | .write_alarm_udr_mask = S5M_RTC_UDR_MASK, | ||
| 97 | }; | ||
| 98 | |||
| 99 | /* Register map for S2MPS13 */ | ||
| 100 | static const struct s5m_rtc_reg_config s2mps13_rtc_regs = { | ||
| 101 | .regs_count = 7, | ||
| 102 | .time = S2MPS_RTC_SEC, | ||
| 103 | .ctrl = S2MPS_RTC_CTRL, | ||
| 104 | .alarm0 = S2MPS_ALARM0_SEC, | ||
| 105 | .alarm1 = S2MPS_ALARM1_SEC, | ||
| 106 | .udr_update = S2MPS_RTC_UDR_CON, | ||
| 107 | .autoclear_udr_mask = S2MPS_RTC_WUDR_MASK, | ||
| 108 | .read_time_udr_mask = S2MPS_RTC_RUDR_MASK, | ||
| 109 | .write_time_udr_mask = S2MPS_RTC_WUDR_MASK, | ||
| 110 | .write_alarm_udr_mask = S2MPS_RTC_WUDR_MASK | S2MPS13_RTC_AUDR_MASK, | ||
| 111 | }; | ||
| 112 | |||
| 113 | /* Register map for S2MPS11/14 */ | ||
| 114 | static const struct s5m_rtc_reg_config s2mps14_rtc_regs = { | ||
| 115 | .regs_count = 7, | ||
| 116 | .time = S2MPS_RTC_SEC, | ||
| 117 | .ctrl = S2MPS_RTC_CTRL, | ||
| 118 | .alarm0 = S2MPS_ALARM0_SEC, | ||
| 119 | .alarm1 = S2MPS_ALARM1_SEC, | ||
| 120 | .udr_update = S2MPS_RTC_UDR_CON, | ||
| 121 | .autoclear_udr_mask = S2MPS_RTC_WUDR_MASK, | ||
| 122 | .read_time_udr_mask = S2MPS_RTC_RUDR_MASK, | ||
| 123 | .write_time_udr_mask = S2MPS_RTC_WUDR_MASK, | ||
| 124 | .write_alarm_udr_mask = S2MPS_RTC_WUDR_MASK | S2MPS_RTC_RUDR_MASK, | ||
| 72 | }; | 125 | }; |
| 73 | 126 | ||
| 74 | /* | 127 | /* |
| 75 | * Register map for S2MPS14. | 128 | * Register map for S2MPS15 - in comparison to S2MPS14 the WUDR and AUDR bits |
| 76 | * It may be also suitable for S2MPS11 but this was not tested. | 129 | * are swapped. |
| 77 | */ | 130 | */ |
| 78 | static const struct s5m_rtc_reg_config s2mps_rtc_regs = { | 131 | static const struct s5m_rtc_reg_config s2mps15_rtc_regs = { |
| 79 | .regs_count = 7, | 132 | .regs_count = 7, |
| 80 | .time = S2MPS_RTC_SEC, | 133 | .time = S2MPS_RTC_SEC, |
| 81 | .ctrl = S2MPS_RTC_CTRL, | 134 | .ctrl = S2MPS_RTC_CTRL, |
| 82 | .alarm0 = S2MPS_ALARM0_SEC, | 135 | .alarm0 = S2MPS_ALARM0_SEC, |
| 83 | .alarm1 = S2MPS_ALARM1_SEC, | 136 | .alarm1 = S2MPS_ALARM1_SEC, |
| 84 | .rtc_udr_update = S2MPS_RTC_UDR_CON, | 137 | .udr_update = S2MPS_RTC_UDR_CON, |
| 85 | .rtc_udr_mask = S2MPS_RTC_WUDR_MASK, | 138 | .autoclear_udr_mask = S2MPS_RTC_WUDR_MASK, |
| 139 | .read_time_udr_mask = S2MPS_RTC_RUDR_MASK, | ||
| 140 | .write_time_udr_mask = S2MPS15_RTC_WUDR_MASK, | ||
| 141 | .write_alarm_udr_mask = S2MPS15_RTC_AUDR_MASK, | ||
| 86 | }; | 142 | }; |
| 87 | 143 | ||
| 88 | struct s5m_rtc_info { | 144 | struct s5m_rtc_info { |
| @@ -166,9 +222,8 @@ static inline int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info) | |||
| 166 | unsigned int data; | 222 | unsigned int data; |
| 167 | 223 | ||
| 168 | do { | 224 | do { |
| 169 | ret = regmap_read(info->regmap, info->regs->rtc_udr_update, | 225 | ret = regmap_read(info->regmap, info->regs->udr_update, &data); |
| 170 | &data); | 226 | } while (--retry && (data & info->regs->autoclear_udr_mask) && !ret); |
| 171 | } while (--retry && (data & info->regs->rtc_udr_mask) && !ret); | ||
| 172 | 227 | ||
| 173 | if (!retry) | 228 | if (!retry) |
| 174 | dev_err(info->dev, "waiting for UDR update, reached max number of retries\n"); | 229 | dev_err(info->dev, "waiting for UDR update, reached max number of retries\n"); |
| @@ -188,6 +243,7 @@ static inline int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info, | |||
| 188 | ret = regmap_read(info->regmap, S5M_RTC_STATUS, &val); | 243 | ret = regmap_read(info->regmap, S5M_RTC_STATUS, &val); |
| 189 | val &= S5M_ALARM0_STATUS; | 244 | val &= S5M_ALARM0_STATUS; |
| 190 | break; | 245 | break; |
| 246 | case S2MPS15X: | ||
| 191 | case S2MPS14X: | 247 | case S2MPS14X: |
| 192 | case S2MPS13X: | 248 | case S2MPS13X: |
| 193 | ret = regmap_read(info->s5m87xx->regmap_pmic, S2MPS14_REG_ST2, | 249 | ret = regmap_read(info->s5m87xx->regmap_pmic, S2MPS14_REG_ST2, |
| @@ -213,17 +269,15 @@ static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) | |||
| 213 | int ret; | 269 | int ret; |
| 214 | unsigned int data; | 270 | unsigned int data; |
| 215 | 271 | ||
| 216 | ret = regmap_read(info->regmap, info->regs->rtc_udr_update, &data); | 272 | ret = regmap_read(info->regmap, info->regs->udr_update, &data); |
| 217 | if (ret < 0) { | 273 | if (ret < 0) { |
| 218 | dev_err(info->dev, "failed to read update reg(%d)\n", ret); | 274 | dev_err(info->dev, "failed to read update reg(%d)\n", ret); |
| 219 | return ret; | 275 | return ret; |
| 220 | } | 276 | } |
| 221 | 277 | ||
| 222 | data |= info->regs->rtc_udr_mask; | 278 | data |= info->regs->write_time_udr_mask; |
| 223 | if (info->device_type == S5M8763X || info->device_type == S5M8767X) | ||
| 224 | data |= S5M_RTC_TIME_EN_MASK; | ||
| 225 | 279 | ||
| 226 | ret = regmap_write(info->regmap, info->regs->rtc_udr_update, data); | 280 | ret = regmap_write(info->regmap, info->regs->udr_update, data); |
| 227 | if (ret < 0) { | 281 | if (ret < 0) { |
| 228 | dev_err(info->dev, "failed to write update reg(%d)\n", ret); | 282 | dev_err(info->dev, "failed to write update reg(%d)\n", ret); |
| 229 | return ret; | 283 | return ret; |
| @@ -239,30 +293,29 @@ static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) | |||
| 239 | int ret; | 293 | int ret; |
| 240 | unsigned int data; | 294 | unsigned int data; |
| 241 | 295 | ||
| 242 | ret = regmap_read(info->regmap, info->regs->rtc_udr_update, &data); | 296 | ret = regmap_read(info->regmap, info->regs->udr_update, &data); |
| 243 | if (ret < 0) { | 297 | if (ret < 0) { |
| 244 | dev_err(info->dev, "%s: fail to read update reg(%d)\n", | 298 | dev_err(info->dev, "%s: fail to read update reg(%d)\n", |
| 245 | __func__, ret); | 299 | __func__, ret); |
| 246 | return ret; | 300 | return ret; |
| 247 | } | 301 | } |
| 248 | 302 | ||
| 249 | data |= info->regs->rtc_udr_mask; | 303 | data |= info->regs->write_alarm_udr_mask; |
| 250 | switch (info->device_type) { | 304 | switch (info->device_type) { |
| 251 | case S5M8763X: | 305 | case S5M8763X: |
| 252 | case S5M8767X: | 306 | case S5M8767X: |
| 253 | data &= ~S5M_RTC_TIME_EN_MASK; | 307 | data &= ~S5M_RTC_TIME_EN_MASK; |
| 254 | break; | 308 | break; |
| 309 | case S2MPS15X: | ||
| 255 | case S2MPS14X: | 310 | case S2MPS14X: |
| 256 | data |= S2MPS_RTC_RUDR_MASK; | ||
| 257 | break; | ||
| 258 | case S2MPS13X: | 311 | case S2MPS13X: |
| 259 | data |= S2MPS13_RTC_AUDR_MASK; | 312 | /* No exceptions needed */ |
| 260 | break; | 313 | break; |
| 261 | default: | 314 | default: |
| 262 | return -EINVAL; | 315 | return -EINVAL; |
| 263 | } | 316 | } |
| 264 | 317 | ||
| 265 | ret = regmap_write(info->regmap, info->regs->rtc_udr_update, data); | 318 | ret = regmap_write(info->regmap, info->regs->udr_update, data); |
| 266 | if (ret < 0) { | 319 | if (ret < 0) { |
| 267 | dev_err(info->dev, "%s: fail to write update reg(%d)\n", | 320 | dev_err(info->dev, "%s: fail to write update reg(%d)\n", |
| 268 | __func__, ret); | 321 | __func__, ret); |
| @@ -273,7 +326,7 @@ static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) | |||
| 273 | 326 | ||
| 274 | /* On S2MPS13 the AUDR is not auto-cleared */ | 327 | /* On S2MPS13 the AUDR is not auto-cleared */ |
| 275 | if (info->device_type == S2MPS13X) | 328 | if (info->device_type == S2MPS13X) |
| 276 | regmap_update_bits(info->regmap, info->regs->rtc_udr_update, | 329 | regmap_update_bits(info->regmap, info->regs->udr_update, |
| 277 | S2MPS13_RTC_AUDR_MASK, 0); | 330 | S2MPS13_RTC_AUDR_MASK, 0); |
| 278 | 331 | ||
| 279 | return ret; | 332 | return ret; |
| @@ -317,10 +370,11 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) | |||
| 317 | u8 data[info->regs->regs_count]; | 370 | u8 data[info->regs->regs_count]; |
| 318 | int ret; | 371 | int ret; |
| 319 | 372 | ||
| 320 | if (info->device_type == S2MPS14X || info->device_type == S2MPS13X) { | 373 | if (info->regs->read_time_udr_mask) { |
| 321 | ret = regmap_update_bits(info->regmap, | 374 | ret = regmap_update_bits(info->regmap, |
| 322 | info->regs->rtc_udr_update, | 375 | info->regs->udr_update, |
| 323 | S2MPS_RTC_RUDR_MASK, S2MPS_RTC_RUDR_MASK); | 376 | info->regs->read_time_udr_mask, |
| 377 | info->regs->read_time_udr_mask); | ||
| 324 | if (ret) { | 378 | if (ret) { |
| 325 | dev_err(dev, | 379 | dev_err(dev, |
| 326 | "Failed to prepare registers for time reading: %d\n", | 380 | "Failed to prepare registers for time reading: %d\n", |
| @@ -339,6 +393,7 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) | |||
| 339 | break; | 393 | break; |
| 340 | 394 | ||
| 341 | case S5M8767X: | 395 | case S5M8767X: |
| 396 | case S2MPS15X: | ||
| 342 | case S2MPS14X: | 397 | case S2MPS14X: |
| 343 | case S2MPS13X: | 398 | case S2MPS13X: |
| 344 | s5m8767_data_to_tm(data, tm, info->rtc_24hr_mode); | 399 | s5m8767_data_to_tm(data, tm, info->rtc_24hr_mode); |
| @@ -366,6 +421,7 @@ static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
| 366 | s5m8763_tm_to_data(tm, data); | 421 | s5m8763_tm_to_data(tm, data); |
| 367 | break; | 422 | break; |
| 368 | case S5M8767X: | 423 | case S5M8767X: |
| 424 | case S2MPS15X: | ||
| 369 | case S2MPS14X: | 425 | case S2MPS14X: |
| 370 | case S2MPS13X: | 426 | case S2MPS13X: |
| 371 | ret = s5m8767_tm_to_data(tm, data); | 427 | ret = s5m8767_tm_to_data(tm, data); |
| @@ -414,6 +470,7 @@ static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
| 414 | break; | 470 | break; |
| 415 | 471 | ||
| 416 | case S5M8767X: | 472 | case S5M8767X: |
| 473 | case S2MPS15X: | ||
| 417 | case S2MPS14X: | 474 | case S2MPS14X: |
| 418 | case S2MPS13X: | 475 | case S2MPS13X: |
| 419 | s5m8767_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); | 476 | s5m8767_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); |
| @@ -463,6 +520,7 @@ static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info) | |||
| 463 | break; | 520 | break; |
| 464 | 521 | ||
| 465 | case S5M8767X: | 522 | case S5M8767X: |
| 523 | case S2MPS15X: | ||
| 466 | case S2MPS14X: | 524 | case S2MPS14X: |
| 467 | case S2MPS13X: | 525 | case S2MPS13X: |
| 468 | for (i = 0; i < info->regs->regs_count; i++) | 526 | for (i = 0; i < info->regs->regs_count; i++) |
| @@ -508,6 +566,7 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info) | |||
| 508 | break; | 566 | break; |
| 509 | 567 | ||
| 510 | case S5M8767X: | 568 | case S5M8767X: |
| 569 | case S2MPS15X: | ||
| 511 | case S2MPS14X: | 570 | case S2MPS14X: |
| 512 | case S2MPS13X: | 571 | case S2MPS13X: |
| 513 | data[RTC_SEC] |= ALARM_ENABLE_MASK; | 572 | data[RTC_SEC] |= ALARM_ENABLE_MASK; |
| @@ -548,6 +607,7 @@ static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
| 548 | break; | 607 | break; |
| 549 | 608 | ||
| 550 | case S5M8767X: | 609 | case S5M8767X: |
| 610 | case S2MPS15X: | ||
| 551 | case S2MPS14X: | 611 | case S2MPS14X: |
| 552 | case S2MPS13X: | 612 | case S2MPS13X: |
| 553 | s5m8767_tm_to_data(&alrm->time, data); | 613 | s5m8767_tm_to_data(&alrm->time, data); |
| @@ -631,6 +691,7 @@ static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info) | |||
| 631 | ret = regmap_raw_write(info->regmap, S5M_ALARM0_CONF, data, 2); | 691 | ret = regmap_raw_write(info->regmap, S5M_ALARM0_CONF, data, 2); |
| 632 | break; | 692 | break; |
| 633 | 693 | ||
| 694 | case S2MPS15X: | ||
| 634 | case S2MPS14X: | 695 | case S2MPS14X: |
| 635 | case S2MPS13X: | 696 | case S2MPS13X: |
| 636 | data[0] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); | 697 | data[0] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); |
| @@ -679,10 +740,19 @@ static int s5m_rtc_probe(struct platform_device *pdev) | |||
| 679 | return -ENOMEM; | 740 | return -ENOMEM; |
| 680 | 741 | ||
| 681 | switch (platform_get_device_id(pdev)->driver_data) { | 742 | switch (platform_get_device_id(pdev)->driver_data) { |
| 743 | case S2MPS15X: | ||
| 744 | regmap_cfg = &s2mps14_rtc_regmap_config; | ||
| 745 | info->regs = &s2mps15_rtc_regs; | ||
| 746 | alarm_irq = S2MPS14_IRQ_RTCA0; | ||
| 747 | break; | ||
| 682 | case S2MPS14X: | 748 | case S2MPS14X: |
| 749 | regmap_cfg = &s2mps14_rtc_regmap_config; | ||
| 750 | info->regs = &s2mps14_rtc_regs; | ||
| 751 | alarm_irq = S2MPS14_IRQ_RTCA0; | ||
| 752 | break; | ||
| 683 | case S2MPS13X: | 753 | case S2MPS13X: |
| 684 | regmap_cfg = &s2mps14_rtc_regmap_config; | 754 | regmap_cfg = &s2mps14_rtc_regmap_config; |
| 685 | info->regs = &s2mps_rtc_regs; | 755 | info->regs = &s2mps13_rtc_regs; |
| 686 | alarm_irq = S2MPS14_IRQ_RTCA0; | 756 | alarm_irq = S2MPS14_IRQ_RTCA0; |
| 687 | break; | 757 | break; |
| 688 | case S5M8763X: | 758 | case S5M8763X: |
| @@ -805,6 +875,7 @@ static const struct platform_device_id s5m_rtc_id[] = { | |||
| 805 | { "s5m-rtc", S5M8767X }, | 875 | { "s5m-rtc", S5M8767X }, |
| 806 | { "s2mps13-rtc", S2MPS13X }, | 876 | { "s2mps13-rtc", S2MPS13X }, |
| 807 | { "s2mps14-rtc", S2MPS14X }, | 877 | { "s2mps14-rtc", S2MPS14X }, |
| 878 | { "s2mps15-rtc", S2MPS15X }, | ||
| 808 | { }, | 879 | { }, |
| 809 | }; | 880 | }; |
| 810 | MODULE_DEVICE_TABLE(platform, s5m_rtc_id); | 881 | MODULE_DEVICE_TABLE(platform, s5m_rtc_id); |
