aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc/rtc-s5m.c
diff options
context:
space:
mode:
authorKrzysztof Kozlowski <k.kozlowski@samsung.com>2014-06-10 18:18:46 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-06-10 18:34:47 -0400
commit0c5deb1ea92fefa6ee69e2da8b887723bdecf3d9 (patch)
tree1fb14a31b5a4696a2c7ae16fa9c1e2abc5c010b9 /drivers/rtc/rtc-s5m.c
parentf8b23bbdad5dfb50af101a56c58ad4e83510a9a6 (diff)
rtc: s5m: add support for S2MPS14 RTC
Add support for S2MPS14 to the rtc-s5m driver. Differences in S2MPS14 (in comparison to S5M8767): - Layout of registers - Lack of century support for time and alarms (7 registers used for storing time/alarm) - Two buffer control registers: WUDR and RUDR - No register for enabling writing time - RTC interrupts are reported in main PMIC I2C device Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Lee Jones <lee.jones@linaro.org> Cc: Alessandro Zummo <a.zummo@towertech.it> Cc: Sangbeom Kim <sbkim73@samsung.com> Cc: Samuel Ortiz <sameo@linux.intel.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Cc: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.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-s5m.c')
-rw-r--r--drivers/rtc/rtc-s5m.c101
1 files changed, 84 insertions, 17 deletions
diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c
index 59860128a221..76287ebd0e35 100644
--- a/drivers/rtc/rtc-s5m.c
+++ b/drivers/rtc/rtc-s5m.c
@@ -17,16 +17,14 @@
17 17
18#include <linux/module.h> 18#include <linux/module.h>
19#include <linux/i2c.h> 19#include <linux/i2c.h>
20#include <linux/slab.h>
21#include <linux/bcd.h> 20#include <linux/bcd.h>
22#include <linux/bitops.h>
23#include <linux/regmap.h> 21#include <linux/regmap.h>
24#include <linux/rtc.h> 22#include <linux/rtc.h>
25#include <linux/delay.h>
26#include <linux/platform_device.h> 23#include <linux/platform_device.h>
27#include <linux/mfd/samsung/core.h> 24#include <linux/mfd/samsung/core.h>
28#include <linux/mfd/samsung/irq.h> 25#include <linux/mfd/samsung/irq.h>
29#include <linux/mfd/samsung/rtc.h> 26#include <linux/mfd/samsung/rtc.h>
27#include <linux/mfd/samsung/s2mps14.h>
30 28
31/* 29/*
32 * Maximum number of retries for checking changes in UDR field 30 * Maximum number of retries for checking changes in UDR field
@@ -74,6 +72,21 @@ static const struct s5m_rtc_reg_config s5m_rtc_regs = {
74 .rtc_udr_mask = S5M_RTC_UDR_MASK, 72 .rtc_udr_mask = S5M_RTC_UDR_MASK,
75}; 73};
76 74
75/*
76 * Register map for S2MPS14.
77 * It may be also suitable for S2MPS11 but this was not tested.
78 */
79static const struct s5m_rtc_reg_config s2mps_rtc_regs = {
80 .regs_count = 7,
81 .time = S2MPS_RTC_SEC,
82 .ctrl = S2MPS_RTC_CTRL,
83 .alarm0 = S2MPS_ALARM0_SEC,
84 .alarm1 = S2MPS_ALARM1_SEC,
85 .smpl_wtsr = S2MPS_WTSR_SMPL_CNTL,
86 .rtc_udr_update = S2MPS_RTC_UDR_CON,
87 .rtc_udr_mask = S2MPS_RTC_WUDR_MASK,
88};
89
77struct s5m_rtc_info { 90struct s5m_rtc_info {
78 struct device *dev; 91 struct device *dev;
79 struct i2c_client *i2c; 92 struct i2c_client *i2c;
@@ -178,6 +191,11 @@ static inline int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info,
178 ret = regmap_read(info->regmap, S5M_RTC_STATUS, &val); 191 ret = regmap_read(info->regmap, S5M_RTC_STATUS, &val);
179 val &= S5M_ALARM0_STATUS; 192 val &= S5M_ALARM0_STATUS;
180 break; 193 break;
194 case S2MPS14X:
195 ret = regmap_read(info->s5m87xx->regmap_pmic, S2MPS14_REG_ST2,
196 &val);
197 val &= S2MPS_ALARM0_STATUS;
198 break;
181 default: 199 default:
182 return -EINVAL; 200 return -EINVAL;
183 } 201 }
@@ -203,8 +221,9 @@ static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info)
203 return ret; 221 return ret;
204 } 222 }
205 223
206 data |= S5M_RTC_TIME_EN_MASK;
207 data |= info->regs->rtc_udr_mask; 224 data |= info->regs->rtc_udr_mask;
225 if (info->device_type == S5M8763X || info->device_type == S5M8767X)
226 data |= S5M_RTC_TIME_EN_MASK;
208 227
209 ret = regmap_write(info->regmap, info->regs->rtc_udr_update, data); 228 ret = regmap_write(info->regmap, info->regs->rtc_udr_update, data);
210 if (ret < 0) { 229 if (ret < 0) {
@@ -229,8 +248,18 @@ static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info)
229 return ret; 248 return ret;
230 } 249 }
231 250
232 data &= ~S5M_RTC_TIME_EN_MASK;
233 data |= info->regs->rtc_udr_mask; 251 data |= info->regs->rtc_udr_mask;
252 switch (info->device_type) {
253 case S5M8763X:
254 case S5M8767X:
255 data &= ~S5M_RTC_TIME_EN_MASK;
256 break;
257 case S2MPS14X:
258 data |= S2MPS_RTC_RUDR_MASK;
259 break;
260 default:
261 return -EINVAL;
262 }
234 263
235 ret = regmap_write(info->regmap, info->regs->rtc_udr_update, data); 264 ret = regmap_write(info->regmap, info->regs->rtc_udr_update, data);
236 if (ret < 0) { 265 if (ret < 0) {
@@ -282,6 +311,17 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm)
282 u8 data[info->regs->regs_count]; 311 u8 data[info->regs->regs_count];
283 int ret; 312 int ret;
284 313
314 if (info->device_type == S2MPS14X) {
315 ret = regmap_update_bits(info->regmap,
316 info->regs->rtc_udr_update,
317 S2MPS_RTC_RUDR_MASK, S2MPS_RTC_RUDR_MASK);
318 if (ret) {
319 dev_err(dev,
320 "Failed to prepare registers for time reading: %d\n",
321 ret);
322 return ret;
323 }
324 }
285 ret = regmap_bulk_read(info->regmap, info->regs->time, data, 325 ret = regmap_bulk_read(info->regmap, info->regs->time, data,
286 info->regs->regs_count); 326 info->regs->regs_count);
287 if (ret < 0) 327 if (ret < 0)
@@ -293,6 +333,7 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm)
293 break; 333 break;
294 334
295 case S5M8767X: 335 case S5M8767X:
336 case S2MPS14X:
296 s5m8767_data_to_tm(data, tm, info->rtc_24hr_mode); 337 s5m8767_data_to_tm(data, tm, info->rtc_24hr_mode);
297 break; 338 break;
298 339
@@ -318,6 +359,7 @@ static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm)
318 s5m8763_tm_to_data(tm, data); 359 s5m8763_tm_to_data(tm, data);
319 break; 360 break;
320 case S5M8767X: 361 case S5M8767X:
362 case S2MPS14X:
321 ret = s5m8767_tm_to_data(tm, data); 363 ret = s5m8767_tm_to_data(tm, data);
322 break; 364 break;
323 default: 365 default:
@@ -364,6 +406,7 @@ static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
364 break; 406 break;
365 407
366 case S5M8767X: 408 case S5M8767X:
409 case S2MPS14X:
367 s5m8767_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); 410 s5m8767_data_to_tm(data, &alrm->time, info->rtc_24hr_mode);
368 alrm->enabled = 0; 411 alrm->enabled = 0;
369 for (i = 0; i < info->regs->regs_count; i++) { 412 for (i = 0; i < info->regs->regs_count; i++) {
@@ -411,6 +454,7 @@ static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info)
411 break; 454 break;
412 455
413 case S5M8767X: 456 case S5M8767X:
457 case S2MPS14X:
414 for (i = 0; i < info->regs->regs_count; i++) 458 for (i = 0; i < info->regs->regs_count; i++)
415 data[i] &= ~ALARM_ENABLE_MASK; 459 data[i] &= ~ALARM_ENABLE_MASK;
416 460
@@ -454,6 +498,7 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info)
454 break; 498 break;
455 499
456 case S5M8767X: 500 case S5M8767X:
501 case S2MPS14X:
457 data[RTC_SEC] |= ALARM_ENABLE_MASK; 502 data[RTC_SEC] |= ALARM_ENABLE_MASK;
458 data[RTC_MIN] |= ALARM_ENABLE_MASK; 503 data[RTC_MIN] |= ALARM_ENABLE_MASK;
459 data[RTC_HOUR] |= ALARM_ENABLE_MASK; 504 data[RTC_HOUR] |= ALARM_ENABLE_MASK;
@@ -492,6 +537,7 @@ static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
492 break; 537 break;
493 538
494 case S5M8767X: 539 case S5M8767X:
540 case S2MPS14X:
495 s5m8767_tm_to_data(&alrm->time, data); 541 s5m8767_tm_to_data(&alrm->time, data);
496 break; 542 break;
497 543
@@ -578,19 +624,33 @@ static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info)
578 u8 data[2]; 624 u8 data[2];
579 int ret; 625 int ret;
580 626
581 /* UDR update time. Default of 7.32 ms is too long. */ 627 switch (info->device_type) {
582 ret = regmap_update_bits(info->regmap, S5M_RTC_UDR_CON, 628 case S5M8763X:
583 S5M_RTC_UDR_T_MASK, S5M_RTC_UDR_T_450_US); 629 case S5M8767X:
584 if (ret < 0) 630 /* UDR update time. Default of 7.32 ms is too long. */
585 dev_err(info->dev, "%s: fail to change UDR time: %d\n", 631 ret = regmap_update_bits(info->regmap, S5M_RTC_UDR_CON,
586 __func__, ret); 632 S5M_RTC_UDR_T_MASK, S5M_RTC_UDR_T_450_US);
633 if (ret < 0)
634 dev_err(info->dev, "%s: fail to change UDR time: %d\n",
635 __func__, ret);
587 636
588 /* Set RTC control register : Binary mode, 24hour mode */ 637 /* Set RTC control register : Binary mode, 24hour mode */
589 data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); 638 data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
590 data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); 639 data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
640
641 ret = regmap_raw_write(info->regmap, S5M_ALARM0_CONF, data, 2);
642 break;
643
644 case S2MPS14X:
645 data[0] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
646 ret = regmap_write(info->regmap, info->regs->ctrl, data[0]);
647 break;
648
649 default:
650 return -EINVAL;
651 }
591 652
592 info->rtc_24hr_mode = 1; 653 info->rtc_24hr_mode = 1;
593 ret = regmap_raw_write(info->regmap, S5M_ALARM0_CONF, data, 2);
594 if (ret < 0) { 654 if (ret < 0) {
595 dev_err(info->dev, "%s: fail to write controlm reg(%d)\n", 655 dev_err(info->dev, "%s: fail to write controlm reg(%d)\n",
596 __func__, ret); 656 __func__, ret);
@@ -620,6 +680,7 @@ static int s5m_rtc_probe(struct platform_device *pdev)
620 switch (pdata->device_type) { 680 switch (pdata->device_type) {
621 case S2MPS14X: 681 case S2MPS14X:
622 regmap_cfg = &s2mps14_rtc_regmap_config; 682 regmap_cfg = &s2mps14_rtc_regmap_config;
683 info->regs = &s2mps_rtc_regs;
623 break; 684 break;
624 case S5M8763X: 685 case S5M8763X:
625 regmap_cfg = &s5m_rtc_regmap_config; 686 regmap_cfg = &s5m_rtc_regmap_config;
@@ -654,6 +715,11 @@ static int s5m_rtc_probe(struct platform_device *pdev)
654 info->wtsr_smpl = s5m87xx->wtsr_smpl; 715 info->wtsr_smpl = s5m87xx->wtsr_smpl;
655 716
656 switch (pdata->device_type) { 717 switch (pdata->device_type) {
718 case S2MPS14X:
719 info->irq = regmap_irq_get_virq(s5m87xx->irq_data,
720 S2MPS14_IRQ_RTCA0);
721 break;
722
657 case S5M8763X: 723 case S5M8763X:
658 info->irq = regmap_irq_get_virq(s5m87xx->irq_data, 724 info->irq = regmap_irq_get_virq(s5m87xx->irq_data,
659 S5M8763_IRQ_ALARM0); 725 S5M8763_IRQ_ALARM0);
@@ -768,7 +834,8 @@ static int s5m_rtc_suspend(struct device *dev)
768static SIMPLE_DEV_PM_OPS(s5m_rtc_pm_ops, s5m_rtc_suspend, s5m_rtc_resume); 834static SIMPLE_DEV_PM_OPS(s5m_rtc_pm_ops, s5m_rtc_suspend, s5m_rtc_resume);
769 835
770static const struct platform_device_id s5m_rtc_id[] = { 836static const struct platform_device_id s5m_rtc_id[] = {
771 { "s5m-rtc", 0 }, 837 { "s5m-rtc", S5M8767X },
838 { "s2mps14-rtc", S2MPS14X },
772}; 839};
773 840
774static struct platform_driver s5m_rtc_driver = { 841static struct platform_driver s5m_rtc_driver = {
@@ -787,6 +854,6 @@ module_platform_driver(s5m_rtc_driver);
787 854
788/* Module information */ 855/* Module information */
789MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); 856MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
790MODULE_DESCRIPTION("Samsung S5M RTC driver"); 857MODULE_DESCRIPTION("Samsung S5M/S2MPS14 RTC driver");
791MODULE_LICENSE("GPL"); 858MODULE_LICENSE("GPL");
792MODULE_ALIAS("platform:s5m-rtc"); 859MODULE_ALIAS("platform:s5m-rtc");