Commit a6b49ffd2d4bba53ad172b1e78ee51fe15ab195e
Committed by
Samuel Ortiz
1 parent
e8deb28ca8
Exists in
master
and in
7 other branches
rtc: Add twl6030 RTC support
This patch adds support for RTC in phoenix TWL6030. Register offset addresses have changed in TWL6030 rtc-twl.c will hence forth support all twl RTC (4030, 5030, 6030 ..) Signed-off-by: Balaji T K <balajitk@ti.com> Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com> Reviewed-by: Tony Lindgren <tony@atomide.com> Reviewed-by: Kevin Hilman <khilman@deeprootsystems.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Showing 2 changed files with 114 additions and 44 deletions Side-by-side Diff
drivers/rtc/Kconfig
... | ... | @@ -258,14 +258,14 @@ |
258 | 258 | the Menelaus driver; it's not separate module. |
259 | 259 | |
260 | 260 | config RTC_DRV_TWL4030 |
261 | - tristate "TI TWL4030/TWL5030/TPS659x0" | |
261 | + tristate "TI TWL4030/TWL5030/TWL6030/TPS659x0" | |
262 | 262 | depends on RTC_CLASS && TWL4030_CORE |
263 | 263 | help |
264 | 264 | If you say yes here you get support for the RTC on the |
265 | - TWL4030 family chips, used mostly with OMAP3 platforms. | |
265 | + TWL4030/TWL5030/TWL6030 family chips, used mostly with OMAP3 platforms. | |
266 | 266 | |
267 | 267 | This driver can also be built as a module. If so, the module |
268 | - will be called rtc-twl4030. | |
268 | + will be called rtc-twl. | |
269 | 269 | |
270 | 270 | config RTC_DRV_S35390A |
271 | 271 | tristate "Seiko Instruments S-35390A" |
drivers/rtc/rtc-twl.c
... | ... | @@ -34,28 +34,76 @@ |
34 | 34 | /* |
35 | 35 | * RTC block register offsets (use TWL_MODULE_RTC) |
36 | 36 | */ |
37 | -#define REG_SECONDS_REG 0x00 | |
38 | -#define REG_MINUTES_REG 0x01 | |
39 | -#define REG_HOURS_REG 0x02 | |
40 | -#define REG_DAYS_REG 0x03 | |
41 | -#define REG_MONTHS_REG 0x04 | |
42 | -#define REG_YEARS_REG 0x05 | |
43 | -#define REG_WEEKS_REG 0x06 | |
37 | +enum { | |
38 | + REG_SECONDS_REG = 0, | |
39 | + REG_MINUTES_REG, | |
40 | + REG_HOURS_REG, | |
41 | + REG_DAYS_REG, | |
42 | + REG_MONTHS_REG, | |
43 | + REG_YEARS_REG, | |
44 | + REG_WEEKS_REG, | |
44 | 45 | |
45 | -#define REG_ALARM_SECONDS_REG 0x07 | |
46 | -#define REG_ALARM_MINUTES_REG 0x08 | |
47 | -#define REG_ALARM_HOURS_REG 0x09 | |
48 | -#define REG_ALARM_DAYS_REG 0x0A | |
49 | -#define REG_ALARM_MONTHS_REG 0x0B | |
50 | -#define REG_ALARM_YEARS_REG 0x0C | |
46 | + REG_ALARM_SECONDS_REG, | |
47 | + REG_ALARM_MINUTES_REG, | |
48 | + REG_ALARM_HOURS_REG, | |
49 | + REG_ALARM_DAYS_REG, | |
50 | + REG_ALARM_MONTHS_REG, | |
51 | + REG_ALARM_YEARS_REG, | |
51 | 52 | |
52 | -#define REG_RTC_CTRL_REG 0x0D | |
53 | -#define REG_RTC_STATUS_REG 0x0E | |
54 | -#define REG_RTC_INTERRUPTS_REG 0x0F | |
53 | + REG_RTC_CTRL_REG, | |
54 | + REG_RTC_STATUS_REG, | |
55 | + REG_RTC_INTERRUPTS_REG, | |
55 | 56 | |
56 | -#define REG_RTC_COMP_LSB_REG 0x10 | |
57 | -#define REG_RTC_COMP_MSB_REG 0x11 | |
57 | + REG_RTC_COMP_LSB_REG, | |
58 | + REG_RTC_COMP_MSB_REG, | |
59 | +}; | |
60 | +const static u8 twl4030_rtc_reg_map[] = { | |
61 | + [REG_SECONDS_REG] = 0x00, | |
62 | + [REG_MINUTES_REG] = 0x01, | |
63 | + [REG_HOURS_REG] = 0x02, | |
64 | + [REG_DAYS_REG] = 0x03, | |
65 | + [REG_MONTHS_REG] = 0x04, | |
66 | + [REG_YEARS_REG] = 0x05, | |
67 | + [REG_WEEKS_REG] = 0x06, | |
58 | 68 | |
69 | + [REG_ALARM_SECONDS_REG] = 0x07, | |
70 | + [REG_ALARM_MINUTES_REG] = 0x08, | |
71 | + [REG_ALARM_HOURS_REG] = 0x09, | |
72 | + [REG_ALARM_DAYS_REG] = 0x0A, | |
73 | + [REG_ALARM_MONTHS_REG] = 0x0B, | |
74 | + [REG_ALARM_YEARS_REG] = 0x0C, | |
75 | + | |
76 | + [REG_RTC_CTRL_REG] = 0x0D, | |
77 | + [REG_RTC_STATUS_REG] = 0x0E, | |
78 | + [REG_RTC_INTERRUPTS_REG] = 0x0F, | |
79 | + | |
80 | + [REG_RTC_COMP_LSB_REG] = 0x10, | |
81 | + [REG_RTC_COMP_MSB_REG] = 0x11, | |
82 | +}; | |
83 | +const static u8 twl6030_rtc_reg_map[] = { | |
84 | + [REG_SECONDS_REG] = 0x00, | |
85 | + [REG_MINUTES_REG] = 0x01, | |
86 | + [REG_HOURS_REG] = 0x02, | |
87 | + [REG_DAYS_REG] = 0x03, | |
88 | + [REG_MONTHS_REG] = 0x04, | |
89 | + [REG_YEARS_REG] = 0x05, | |
90 | + [REG_WEEKS_REG] = 0x06, | |
91 | + | |
92 | + [REG_ALARM_SECONDS_REG] = 0x08, | |
93 | + [REG_ALARM_MINUTES_REG] = 0x09, | |
94 | + [REG_ALARM_HOURS_REG] = 0x0A, | |
95 | + [REG_ALARM_DAYS_REG] = 0x0B, | |
96 | + [REG_ALARM_MONTHS_REG] = 0x0C, | |
97 | + [REG_ALARM_YEARS_REG] = 0x0D, | |
98 | + | |
99 | + [REG_RTC_CTRL_REG] = 0x10, | |
100 | + [REG_RTC_STATUS_REG] = 0x11, | |
101 | + [REG_RTC_INTERRUPTS_REG] = 0x12, | |
102 | + | |
103 | + [REG_RTC_COMP_LSB_REG] = 0x13, | |
104 | + [REG_RTC_COMP_MSB_REG] = 0x14, | |
105 | +}; | |
106 | + | |
59 | 107 | /* RTC_CTRL_REG bitfields */ |
60 | 108 | #define BIT_RTC_CTRL_REG_STOP_RTC_M 0x01 |
61 | 109 | #define BIT_RTC_CTRL_REG_ROUND_30S_M 0x02 |
... | ... | @@ -84,6 +132,7 @@ |
84 | 132 | #define ALL_TIME_REGS 6 |
85 | 133 | |
86 | 134 | /*----------------------------------------------------------------------*/ |
135 | +static u8 *rtc_reg_map; | |
87 | 136 | |
88 | 137 | /* |
89 | 138 | * Supports 1 byte read from TWL RTC register. |
... | ... | @@ -92,7 +141,7 @@ |
92 | 141 | { |
93 | 142 | int ret; |
94 | 143 | |
95 | - ret = twl_i2c_read_u8(TWL_MODULE_RTC, data, reg); | |
144 | + ret = twl_i2c_read_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg])); | |
96 | 145 | if (ret < 0) |
97 | 146 | pr_err("twl_rtc: Could not read TWL" |
98 | 147 | "register %X - error %d\n", reg, ret); |
... | ... | @@ -106,7 +155,7 @@ |
106 | 155 | { |
107 | 156 | int ret; |
108 | 157 | |
109 | - ret = twl_i2c_write_u8(TWL_MODULE_RTC, data, reg); | |
158 | + ret = twl_i2c_write_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg])); | |
110 | 159 | if (ret < 0) |
111 | 160 | pr_err("twl_rtc: Could not write TWL" |
112 | 161 | "register %X - error %d\n", reg, ret); |
... | ... | @@ -202,7 +251,7 @@ |
202 | 251 | return ret; |
203 | 252 | |
204 | 253 | ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data, |
205 | - REG_SECONDS_REG, ALL_TIME_REGS); | |
254 | + (rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS); | |
206 | 255 | |
207 | 256 | if (ret < 0) { |
208 | 257 | dev_err(dev, "rtc_read_time error %d\n", ret); |
... | ... | @@ -244,7 +293,7 @@ |
244 | 293 | |
245 | 294 | /* update all the time registers in one shot */ |
246 | 295 | ret = twl_i2c_write(TWL_MODULE_RTC, rtc_data, |
247 | - REG_SECONDS_REG, ALL_TIME_REGS); | |
296 | + (rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS); | |
248 | 297 | if (ret < 0) { |
249 | 298 | dev_err(dev, "rtc_set_time error %d\n", ret); |
250 | 299 | goto out; |
... | ... | @@ -267,7 +316,7 @@ |
267 | 316 | int ret; |
268 | 317 | |
269 | 318 | ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data, |
270 | - REG_ALARM_SECONDS_REG, ALL_TIME_REGS); | |
319 | + (rtc_reg_map[REG_ALARM_SECONDS_REG]), ALL_TIME_REGS); | |
271 | 320 | if (ret < 0) { |
272 | 321 | dev_err(dev, "rtc_read_alarm error %d\n", ret); |
273 | 322 | return ret; |
... | ... | @@ -306,7 +355,7 @@ |
306 | 355 | |
307 | 356 | /* update all the alarm registers in one shot */ |
308 | 357 | ret = twl_i2c_write(TWL_MODULE_RTC, alarm_data, |
309 | - REG_ALARM_SECONDS_REG, ALL_TIME_REGS); | |
358 | + (rtc_reg_map[REG_ALARM_SECONDS_REG]), ALL_TIME_REGS); | |
310 | 359 | if (ret) { |
311 | 360 | dev_err(dev, "rtc_set_alarm error %d\n", ret); |
312 | 361 | goto out; |
313 | 362 | |
... | ... | @@ -352,21 +401,23 @@ |
352 | 401 | if (res) |
353 | 402 | goto out; |
354 | 403 | |
355 | - /* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1 | |
356 | - * needs 2 reads to clear the interrupt. One read is done in | |
357 | - * do_twl_pwrirq(). Doing the second read, to clear | |
358 | - * the bit. | |
359 | - * | |
360 | - * FIXME the reason PWR_ISR1 needs an extra read is that | |
361 | - * RTC_IF retriggered until we cleared REG_ALARM_M above. | |
362 | - * But re-reading like this is a bad hack; by doing so we | |
363 | - * risk wrongly clearing status for some other IRQ (losing | |
364 | - * the interrupt). Be smarter about handling RTC_UF ... | |
365 | - */ | |
366 | - res = twl_i2c_read_u8(TWL4030_MODULE_INT, | |
404 | + if (twl_class_is_4030()) { | |
405 | + /* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1 | |
406 | + * needs 2 reads to clear the interrupt. One read is done in | |
407 | + * do_twl_pwrirq(). Doing the second read, to clear | |
408 | + * the bit. | |
409 | + * | |
410 | + * FIXME the reason PWR_ISR1 needs an extra read is that | |
411 | + * RTC_IF retriggered until we cleared REG_ALARM_M above. | |
412 | + * But re-reading like this is a bad hack; by doing so we | |
413 | + * risk wrongly clearing status for some other IRQ (losing | |
414 | + * the interrupt). Be smarter about handling RTC_UF ... | |
415 | + */ | |
416 | + res = twl_i2c_read_u8(TWL4030_MODULE_INT, | |
367 | 417 | &rd_reg, TWL4030_INT_PWR_ISR1); |
368 | - if (res) | |
369 | - goto out; | |
418 | + if (res) | |
419 | + goto out; | |
420 | + } | |
370 | 421 | |
371 | 422 | /* Notify RTC core on event */ |
372 | 423 | rtc_update_irq(rtc, 1, events); |
... | ... | @@ -432,6 +483,13 @@ |
432 | 483 | goto out1; |
433 | 484 | } |
434 | 485 | |
486 | + if (twl_class_is_6030()) { | |
487 | + twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK, | |
488 | + REG_INT_MSK_LINE_A); | |
489 | + twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK, | |
490 | + REG_INT_MSK_STS_A); | |
491 | + } | |
492 | + | |
435 | 493 | /* Check RTC module status, Enable if it is off */ |
436 | 494 | ret = twl_rtc_read_u8(&rd_reg, REG_RTC_CTRL_REG); |
437 | 495 | if (ret < 0) |
438 | 496 | |
... | ... | @@ -472,7 +530,14 @@ |
472 | 530 | |
473 | 531 | mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); |
474 | 532 | mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); |
533 | + if (twl_class_is_6030()) { | |
534 | + twl6030_interrupt_mask(TWL6030_RTC_INT_MASK, | |
535 | + REG_INT_MSK_LINE_A); | |
536 | + twl6030_interrupt_mask(TWL6030_RTC_INT_MASK, | |
537 | + REG_INT_MSK_STS_A); | |
538 | + } | |
475 | 539 | |
540 | + | |
476 | 541 | free_irq(irq, rtc); |
477 | 542 | |
478 | 543 | rtc_device_unregister(rtc); |
... | ... | @@ -526,6 +591,11 @@ |
526 | 591 | |
527 | 592 | static int __init twl_rtc_init(void) |
528 | 593 | { |
594 | + if (twl_class_is_4030()) | |
595 | + rtc_reg_map = (u8 *) twl4030_rtc_reg_map; | |
596 | + else | |
597 | + rtc_reg_map = (u8 *) twl6030_rtc_reg_map; | |
598 | + | |
529 | 599 | return platform_driver_register(&twl4030rtc_driver); |
530 | 600 | } |
531 | 601 | module_init(twl_rtc_init); |