aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKrzysztof Kozlowski <k.kozlowski@samsung.com>2014-06-10 18:18:44 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-06-10 18:34:47 -0400
commitf8b23bbdad5dfb50af101a56c58ad4e83510a9a6 (patch)
treea82f4e1d56794b98e882aa0cff641284a70c3444
parent0c5f5d9af311013aabc519b68df19533d0d51cda (diff)
rtc: s5m: support different register layout
Prepare for adding support for S2MPS14 RTC device to the rtc-s5m driver: 1. Add a map of registers used by the driver which differ between the chipsets (S5M876X and S2MPS14). 2. Move code of checking for alarm pending to separate function. 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>
-rw-r--r--drivers/rtc/rtc-s5m.c157
1 files changed, 109 insertions, 48 deletions
diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c
index 3751ef90f93c..59860128a221 100644
--- a/drivers/rtc/rtc-s5m.c
+++ b/drivers/rtc/rtc-s5m.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2013 Samsung Electronics Co., Ltd 2 * Copyright (c) 2013-2014 Samsung Electronics Co., Ltd
3 * http://www.samsung.com 3 * http://www.samsung.com
4 * 4 *
5 * Copyright (C) 2013 Google, Inc 5 * Copyright (C) 2013 Google, Inc
@@ -38,6 +38,42 @@
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. */
42struct s5m_rtc_reg_config {
43 /* Number of registers used for setting time/alarm0/alarm1 */
44 unsigned int regs_count;
45 /* First register for time, seconds */
46 unsigned int time;
47 /* RTC control register */
48 unsigned int ctrl;
49 /* First register for alarm 0, seconds */
50 unsigned int alarm0;
51 /* First register for alarm 1, seconds */
52 unsigned int alarm1;
53 /* SMPL/WTSR register */
54 unsigned int smpl_wtsr;
55 /*
56 * Register for update flag (UDR). Typically setting UDR field to 1
57 * will enable update of time or alarm register. Then it will be
58 * auto-cleared after successful update.
59 */
60 unsigned int rtc_udr_update;
61 /* Mask for UDR field in 'rtc_udr_update' register */
62 unsigned int rtc_udr_mask;
63};
64
65/* Register map for S5M8763 and S5M8767 */
66static const struct s5m_rtc_reg_config s5m_rtc_regs = {
67 .regs_count = 8,
68 .time = S5M_RTC_SEC,
69 .ctrl = S5M_ALARM1_CONF,
70 .alarm0 = S5M_ALARM0_SEC,
71 .alarm1 = S5M_ALARM1_SEC,
72 .smpl_wtsr = S5M_WTSR_SMPL_CNTL,
73 .rtc_udr_update = S5M_RTC_UDR_CON,
74 .rtc_udr_mask = S5M_RTC_UDR_MASK,
75};
76
41struct s5m_rtc_info { 77struct s5m_rtc_info {
42 struct device *dev; 78 struct device *dev;
43 struct i2c_client *i2c; 79 struct i2c_client *i2c;
@@ -48,6 +84,7 @@ struct s5m_rtc_info {
48 int device_type; 84 int device_type;
49 int rtc_24hr_mode; 85 int rtc_24hr_mode;
50 bool wtsr_smpl; 86 bool wtsr_smpl;
87 const struct s5m_rtc_reg_config *regs;
51}; 88};
52 89
53static const struct regmap_config s5m_rtc_regmap_config = { 90static const struct regmap_config s5m_rtc_regmap_config = {
@@ -119,8 +156,9 @@ static inline int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info)
119 unsigned int data; 156 unsigned int data;
120 157
121 do { 158 do {
122 ret = regmap_read(info->regmap, S5M_RTC_UDR_CON, &data); 159 ret = regmap_read(info->regmap, info->regs->rtc_udr_update,
123 } while (--retry && (data & S5M_RTC_UDR_MASK) && !ret); 160 &data);
161 } while (--retry && (data & info->regs->rtc_udr_mask) && !ret);
124 162
125 if (!retry) 163 if (!retry)
126 dev_err(info->dev, "waiting for UDR update, reached max number of retries\n"); 164 dev_err(info->dev, "waiting for UDR update, reached max number of retries\n");
@@ -128,21 +166,47 @@ static inline int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info)
128 return ret; 166 return ret;
129} 167}
130 168
169static inline int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info,
170 struct rtc_wkalrm *alarm)
171{
172 int ret;
173 unsigned int val;
174
175 switch (info->device_type) {
176 case S5M8767X:
177 case S5M8763X:
178 ret = regmap_read(info->regmap, S5M_RTC_STATUS, &val);
179 val &= S5M_ALARM0_STATUS;
180 break;
181 default:
182 return -EINVAL;
183 }
184 if (ret < 0)
185 return ret;
186
187 if (val)
188 alarm->pending = 1;
189 else
190 alarm->pending = 0;
191
192 return 0;
193}
194
131static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) 195static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info)
132{ 196{
133 int ret; 197 int ret;
134 unsigned int data; 198 unsigned int data;
135 199
136 ret = regmap_read(info->regmap, S5M_RTC_UDR_CON, &data); 200 ret = regmap_read(info->regmap, info->regs->rtc_udr_update, &data);
137 if (ret < 0) { 201 if (ret < 0) {
138 dev_err(info->dev, "failed to read update reg(%d)\n", ret); 202 dev_err(info->dev, "failed to read update reg(%d)\n", ret);
139 return ret; 203 return ret;
140 } 204 }
141 205
142 data |= S5M_RTC_TIME_EN_MASK; 206 data |= S5M_RTC_TIME_EN_MASK;
143 data |= S5M_RTC_UDR_MASK; 207 data |= info->regs->rtc_udr_mask;
144 208
145 ret = regmap_write(info->regmap, S5M_RTC_UDR_CON, data); 209 ret = regmap_write(info->regmap, info->regs->rtc_udr_update, data);
146 if (ret < 0) { 210 if (ret < 0) {
147 dev_err(info->dev, "failed to write update reg(%d)\n", ret); 211 dev_err(info->dev, "failed to write update reg(%d)\n", ret);
148 return ret; 212 return ret;
@@ -158,7 +222,7 @@ static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info)
158 int ret; 222 int ret;
159 unsigned int data; 223 unsigned int data;
160 224
161 ret = regmap_read(info->regmap, S5M_RTC_UDR_CON, &data); 225 ret = regmap_read(info->regmap, info->regs->rtc_udr_update, &data);
162 if (ret < 0) { 226 if (ret < 0) {
163 dev_err(info->dev, "%s: fail to read update reg(%d)\n", 227 dev_err(info->dev, "%s: fail to read update reg(%d)\n",
164 __func__, ret); 228 __func__, ret);
@@ -166,9 +230,9 @@ static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info)
166 } 230 }
167 231
168 data &= ~S5M_RTC_TIME_EN_MASK; 232 data &= ~S5M_RTC_TIME_EN_MASK;
169 data |= S5M_RTC_UDR_MASK; 233 data |= info->regs->rtc_udr_mask;
170 234
171 ret = regmap_write(info->regmap, S5M_RTC_UDR_CON, data); 235 ret = regmap_write(info->regmap, info->regs->rtc_udr_update, data);
172 if (ret < 0) { 236 if (ret < 0) {
173 dev_err(info->dev, "%s: fail to write update reg(%d)\n", 237 dev_err(info->dev, "%s: fail to write update reg(%d)\n",
174 __func__, ret); 238 __func__, ret);
@@ -215,10 +279,11 @@ static void s5m8763_tm_to_data(struct rtc_time *tm, u8 *data)
215static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) 279static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm)
216{ 280{
217 struct s5m_rtc_info *info = dev_get_drvdata(dev); 281 struct s5m_rtc_info *info = dev_get_drvdata(dev);
218 u8 data[8]; 282 u8 data[info->regs->regs_count];
219 int ret; 283 int ret;
220 284
221 ret = regmap_bulk_read(info->regmap, S5M_RTC_SEC, data, 8); 285 ret = regmap_bulk_read(info->regmap, info->regs->time, data,
286 info->regs->regs_count);
222 if (ret < 0) 287 if (ret < 0)
223 return ret; 288 return ret;
224 289
@@ -245,7 +310,7 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm)
245static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm) 310static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm)
246{ 311{
247 struct s5m_rtc_info *info = dev_get_drvdata(dev); 312 struct s5m_rtc_info *info = dev_get_drvdata(dev);
248 u8 data[8]; 313 u8 data[info->regs->regs_count];
249 int ret = 0; 314 int ret = 0;
250 315
251 switch (info->device_type) { 316 switch (info->device_type) {
@@ -266,7 +331,8 @@ static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm)
266 1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, 331 1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday,
267 tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday); 332 tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday);
268 333
269 ret = regmap_raw_write(info->regmap, S5M_RTC_SEC, data, 8); 334 ret = regmap_raw_write(info->regmap, info->regs->time, data,
335 info->regs->regs_count);
270 if (ret < 0) 336 if (ret < 0)
271 return ret; 337 return ret;
272 338
@@ -278,11 +344,12 @@ static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm)
278static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) 344static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
279{ 345{
280 struct s5m_rtc_info *info = dev_get_drvdata(dev); 346 struct s5m_rtc_info *info = dev_get_drvdata(dev);
281 u8 data[8]; 347 u8 data[info->regs->regs_count];
282 unsigned int val; 348 unsigned int val;
283 int ret, i; 349 int ret, i;
284 350
285 ret = regmap_bulk_read(info->regmap, S5M_ALARM0_SEC, data, 8); 351 ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data,
352 info->regs->regs_count);
286 if (ret < 0) 353 if (ret < 0)
287 return ret; 354 return ret;
288 355
@@ -294,54 +361,42 @@ static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
294 return ret; 361 return ret;
295 362
296 alrm->enabled = !!val; 363 alrm->enabled = !!val;
297
298 ret = regmap_read(info->regmap, S5M_RTC_STATUS, &val);
299 if (ret < 0)
300 return ret;
301
302 break; 364 break;
303 365
304 case S5M8767X: 366 case S5M8767X:
305 s5m8767_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); 367 s5m8767_data_to_tm(data, &alrm->time, info->rtc_24hr_mode);
306 dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__,
307 1900 + alrm->time.tm_year, 1 + alrm->time.tm_mon,
308 alrm->time.tm_mday, alrm->time.tm_hour,
309 alrm->time.tm_min, alrm->time.tm_sec,
310 alrm->time.tm_wday);
311
312 alrm->enabled = 0; 368 alrm->enabled = 0;
313 for (i = 0; i < 7; i++) { 369 for (i = 0; i < info->regs->regs_count; i++) {
314 if (data[i] & ALARM_ENABLE_MASK) { 370 if (data[i] & ALARM_ENABLE_MASK) {
315 alrm->enabled = 1; 371 alrm->enabled = 1;
316 break; 372 break;
317 } 373 }
318 } 374 }
319
320 alrm->pending = 0;
321 ret = regmap_read(info->regmap, S5M_RTC_STATUS, &val);
322 if (ret < 0)
323 return ret;
324 break; 375 break;
325 376
326 default: 377 default:
327 return -EINVAL; 378 return -EINVAL;
328 } 379 }
329 380
330 if (val & S5M_ALARM0_STATUS) 381 dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__,
331 alrm->pending = 1; 382 1900 + alrm->time.tm_year, 1 + alrm->time.tm_mon,
332 else 383 alrm->time.tm_mday, alrm->time.tm_hour,
333 alrm->pending = 0; 384 alrm->time.tm_min, alrm->time.tm_sec,
385 alrm->time.tm_wday);
386
387 ret = s5m_check_peding_alarm_interrupt(info, alrm);
334 388
335 return 0; 389 return 0;
336} 390}
337 391
338static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info) 392static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info)
339{ 393{
340 u8 data[8]; 394 u8 data[info->regs->regs_count];
341 int ret, i; 395 int ret, i;
342 struct rtc_time tm; 396 struct rtc_time tm;
343 397
344 ret = regmap_bulk_read(info->regmap, S5M_ALARM0_SEC, data, 8); 398 ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data,
399 info->regs->regs_count);
345 if (ret < 0) 400 if (ret < 0)
346 return ret; 401 return ret;
347 402
@@ -356,10 +411,11 @@ static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info)
356 break; 411 break;
357 412
358 case S5M8767X: 413 case S5M8767X:
359 for (i = 0; i < 7; i++) 414 for (i = 0; i < info->regs->regs_count; i++)
360 data[i] &= ~ALARM_ENABLE_MASK; 415 data[i] &= ~ALARM_ENABLE_MASK;
361 416
362 ret = regmap_raw_write(info->regmap, S5M_ALARM0_SEC, data, 8); 417 ret = regmap_raw_write(info->regmap, info->regs->alarm0, data,
418 info->regs->regs_count);
363 if (ret < 0) 419 if (ret < 0)
364 return ret; 420 return ret;
365 421
@@ -377,11 +433,12 @@ static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info)
377static int s5m_rtc_start_alarm(struct s5m_rtc_info *info) 433static int s5m_rtc_start_alarm(struct s5m_rtc_info *info)
378{ 434{
379 int ret; 435 int ret;
380 u8 data[8]; 436 u8 data[info->regs->regs_count];
381 u8 alarm0_conf; 437 u8 alarm0_conf;
382 struct rtc_time tm; 438 struct rtc_time tm;
383 439
384 ret = regmap_bulk_read(info->regmap, S5M_ALARM0_SEC, data, 8); 440 ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data,
441 info->regs->regs_count);
385 if (ret < 0) 442 if (ret < 0)
386 return ret; 443 return ret;
387 444
@@ -408,7 +465,8 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info)
408 if (data[RTC_YEAR1] & 0x7f) 465 if (data[RTC_YEAR1] & 0x7f)
409 data[RTC_YEAR1] |= ALARM_ENABLE_MASK; 466 data[RTC_YEAR1] |= ALARM_ENABLE_MASK;
410 467
411 ret = regmap_raw_write(info->regmap, S5M_ALARM0_SEC, data, 8); 468 ret = regmap_raw_write(info->regmap, info->regs->alarm0, data,
469 info->regs->regs_count);
412 if (ret < 0) 470 if (ret < 0)
413 return ret; 471 return ret;
414 ret = s5m8767_rtc_set_alarm_reg(info); 472 ret = s5m8767_rtc_set_alarm_reg(info);
@@ -425,7 +483,7 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info)
425static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) 483static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
426{ 484{
427 struct s5m_rtc_info *info = dev_get_drvdata(dev); 485 struct s5m_rtc_info *info = dev_get_drvdata(dev);
428 u8 data[8]; 486 u8 data[info->regs->regs_count];
429 int ret; 487 int ret;
430 488
431 switch (info->device_type) { 489 switch (info->device_type) {
@@ -450,7 +508,8 @@ static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
450 if (ret < 0) 508 if (ret < 0)
451 return ret; 509 return ret;
452 510
453 ret = regmap_raw_write(info->regmap, S5M_ALARM0_SEC, data, 8); 511 ret = regmap_raw_write(info->regmap, info->regs->alarm0, data,
512 info->regs->regs_count);
454 if (ret < 0) 513 if (ret < 0)
455 return ret; 514 return ret;
456 515
@@ -495,7 +554,7 @@ static const struct rtc_class_ops s5m_rtc_ops = {
495static void s5m_rtc_enable_wtsr(struct s5m_rtc_info *info, bool enable) 554static void s5m_rtc_enable_wtsr(struct s5m_rtc_info *info, bool enable)
496{ 555{
497 int ret; 556 int ret;
498 ret = regmap_update_bits(info->regmap, S5M_WTSR_SMPL_CNTL, 557 ret = regmap_update_bits(info->regmap, info->regs->smpl_wtsr,
499 WTSR_ENABLE_MASK, 558 WTSR_ENABLE_MASK,
500 enable ? WTSR_ENABLE_MASK : 0); 559 enable ? WTSR_ENABLE_MASK : 0);
501 if (ret < 0) 560 if (ret < 0)
@@ -506,7 +565,7 @@ static void s5m_rtc_enable_wtsr(struct s5m_rtc_info *info, bool enable)
506static void s5m_rtc_enable_smpl(struct s5m_rtc_info *info, bool enable) 565static void s5m_rtc_enable_smpl(struct s5m_rtc_info *info, bool enable)
507{ 566{
508 int ret; 567 int ret;
509 ret = regmap_update_bits(info->regmap, S5M_WTSR_SMPL_CNTL, 568 ret = regmap_update_bits(info->regmap, info->regs->smpl_wtsr,
510 SMPL_ENABLE_MASK, 569 SMPL_ENABLE_MASK,
511 enable ? SMPL_ENABLE_MASK : 0); 570 enable ? SMPL_ENABLE_MASK : 0);
512 if (ret < 0) 571 if (ret < 0)
@@ -564,9 +623,11 @@ static int s5m_rtc_probe(struct platform_device *pdev)
564 break; 623 break;
565 case S5M8763X: 624 case S5M8763X:
566 regmap_cfg = &s5m_rtc_regmap_config; 625 regmap_cfg = &s5m_rtc_regmap_config;
626 info->regs = &s5m_rtc_regs;
567 break; 627 break;
568 case S5M8767X: 628 case S5M8767X:
569 regmap_cfg = &s5m_rtc_regmap_config; 629 regmap_cfg = &s5m_rtc_regmap_config;
630 info->regs = &s5m_rtc_regs;
570 break; 631 break;
571 default: 632 default:
572 dev_err(&pdev->dev, "Device type is not supported by RTC driver\n"); 633 dev_err(&pdev->dev, "Device type is not supported by RTC driver\n");
@@ -653,7 +714,7 @@ static void s5m_rtc_shutdown(struct platform_device *pdev)
653 if (info->wtsr_smpl) { 714 if (info->wtsr_smpl) {
654 for (i = 0; i < 3; i++) { 715 for (i = 0; i < 3; i++) {
655 s5m_rtc_enable_wtsr(info, false); 716 s5m_rtc_enable_wtsr(info, false);
656 regmap_read(info->regmap, S5M_WTSR_SMPL_CNTL, &val); 717 regmap_read(info->regmap, info->regs->smpl_wtsr, &val);
657 pr_debug("%s: WTSR_SMPL reg(0x%02x)\n", __func__, val); 718 pr_debug("%s: WTSR_SMPL reg(0x%02x)\n", __func__, val);
658 if (val & WTSR_ENABLE_MASK) 719 if (val & WTSR_ENABLE_MASK)
659 pr_emerg("%s: fail to disable WTSR\n", 720 pr_emerg("%s: fail to disable WTSR\n",