diff options
author | Balaji T K <balajitk@ti.com> | 2009-12-13 16:16:31 -0500 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2009-12-13 18:26:08 -0500 |
commit | a6b49ffd2d4bba53ad172b1e78ee51fe15ab195e (patch) | |
tree | 1fc03d75e700644c3846c0eaa8b560cd5993d4ec /drivers/rtc | |
parent | e8deb28ca8e221de0239eafb3c3d431d8854278e (diff) |
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>
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/Kconfig | 6 | ||||
-rw-r--r-- | drivers/rtc/rtc-twl.c | 152 |
2 files changed, 114 insertions, 44 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index f2e1004d12c..71fbd6e8edf 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
@@ -258,14 +258,14 @@ config RTC_DRV_TWL92330 | |||
258 | the Menelaus driver; it's not separate module. | 258 | the Menelaus driver; it's not separate module. |
259 | 259 | ||
260 | config RTC_DRV_TWL4030 | 260 | config RTC_DRV_TWL4030 |
261 | tristate "TI TWL4030/TWL5030/TPS659x0" | 261 | tristate "TI TWL4030/TWL5030/TWL6030/TPS659x0" |
262 | depends on RTC_CLASS && TWL4030_CORE | 262 | depends on RTC_CLASS && TWL4030_CORE |
263 | help | 263 | help |
264 | If you say yes here you get support for the RTC on the | 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 | This driver can also be built as a module. If so, the module | 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 | config RTC_DRV_S35390A | 270 | config RTC_DRV_S35390A |
271 | tristate "Seiko Instruments S-35390A" | 271 | tristate "Seiko Instruments S-35390A" |
diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index 7cea920ff6a..c6a83a2a722 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c | |||
@@ -34,27 +34,75 @@ | |||
34 | /* | 34 | /* |
35 | * RTC block register offsets (use TWL_MODULE_RTC) | 35 | * RTC block register offsets (use TWL_MODULE_RTC) |
36 | */ | 36 | */ |
37 | #define REG_SECONDS_REG 0x00 | 37 | enum { |
38 | #define REG_MINUTES_REG 0x01 | 38 | REG_SECONDS_REG = 0, |
39 | #define REG_HOURS_REG 0x02 | 39 | REG_MINUTES_REG, |
40 | #define REG_DAYS_REG 0x03 | 40 | REG_HOURS_REG, |
41 | #define REG_MONTHS_REG 0x04 | 41 | REG_DAYS_REG, |
42 | #define REG_YEARS_REG 0x05 | 42 | REG_MONTHS_REG, |
43 | #define REG_WEEKS_REG 0x06 | 43 | REG_YEARS_REG, |
44 | 44 | REG_WEEKS_REG, | |
45 | #define REG_ALARM_SECONDS_REG 0x07 | 45 | |
46 | #define REG_ALARM_MINUTES_REG 0x08 | 46 | REG_ALARM_SECONDS_REG, |
47 | #define REG_ALARM_HOURS_REG 0x09 | 47 | REG_ALARM_MINUTES_REG, |
48 | #define REG_ALARM_DAYS_REG 0x0A | 48 | REG_ALARM_HOURS_REG, |
49 | #define REG_ALARM_MONTHS_REG 0x0B | 49 | REG_ALARM_DAYS_REG, |
50 | #define REG_ALARM_YEARS_REG 0x0C | 50 | REG_ALARM_MONTHS_REG, |
51 | 51 | REG_ALARM_YEARS_REG, | |
52 | #define REG_RTC_CTRL_REG 0x0D | 52 | |
53 | #define REG_RTC_STATUS_REG 0x0E | 53 | REG_RTC_CTRL_REG, |
54 | #define REG_RTC_INTERRUPTS_REG 0x0F | 54 | REG_RTC_STATUS_REG, |
55 | 55 | REG_RTC_INTERRUPTS_REG, | |
56 | #define REG_RTC_COMP_LSB_REG 0x10 | 56 | |
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, | ||
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 | }; | ||
58 | 106 | ||
59 | /* RTC_CTRL_REG bitfields */ | 107 | /* RTC_CTRL_REG bitfields */ |
60 | #define BIT_RTC_CTRL_REG_STOP_RTC_M 0x01 | 108 | #define BIT_RTC_CTRL_REG_STOP_RTC_M 0x01 |
@@ -84,6 +132,7 @@ | |||
84 | #define ALL_TIME_REGS 6 | 132 | #define ALL_TIME_REGS 6 |
85 | 133 | ||
86 | /*----------------------------------------------------------------------*/ | 134 | /*----------------------------------------------------------------------*/ |
135 | static u8 *rtc_reg_map; | ||
87 | 136 | ||
88 | /* | 137 | /* |
89 | * Supports 1 byte read from TWL RTC register. | 138 | * Supports 1 byte read from TWL RTC register. |
@@ -92,7 +141,7 @@ static int twl_rtc_read_u8(u8 *data, u8 reg) | |||
92 | { | 141 | { |
93 | int ret; | 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 | if (ret < 0) | 145 | if (ret < 0) |
97 | pr_err("twl_rtc: Could not read TWL" | 146 | pr_err("twl_rtc: Could not read TWL" |
98 | "register %X - error %d\n", reg, ret); | 147 | "register %X - error %d\n", reg, ret); |
@@ -106,7 +155,7 @@ static int twl_rtc_write_u8(u8 data, u8 reg) | |||
106 | { | 155 | { |
107 | int ret; | 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 | if (ret < 0) | 159 | if (ret < 0) |
111 | pr_err("twl_rtc: Could not write TWL" | 160 | pr_err("twl_rtc: Could not write TWL" |
112 | "register %X - error %d\n", reg, ret); | 161 | "register %X - error %d\n", reg, ret); |
@@ -202,7 +251,7 @@ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm) | |||
202 | return ret; | 251 | return ret; |
203 | 252 | ||
204 | ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data, | 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 | if (ret < 0) { | 256 | if (ret < 0) { |
208 | dev_err(dev, "rtc_read_time error %d\n", ret); | 257 | dev_err(dev, "rtc_read_time error %d\n", ret); |
@@ -244,7 +293,7 @@ static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
244 | 293 | ||
245 | /* update all the time registers in one shot */ | 294 | /* update all the time registers in one shot */ |
246 | ret = twl_i2c_write(TWL_MODULE_RTC, rtc_data, | 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 | if (ret < 0) { | 297 | if (ret < 0) { |
249 | dev_err(dev, "rtc_set_time error %d\n", ret); | 298 | dev_err(dev, "rtc_set_time error %d\n", ret); |
250 | goto out; | 299 | goto out; |
@@ -267,7 +316,7 @@ static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) | |||
267 | int ret; | 316 | int ret; |
268 | 317 | ||
269 | ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data, | 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 | if (ret < 0) { | 320 | if (ret < 0) { |
272 | dev_err(dev, "rtc_read_alarm error %d\n", ret); | 321 | dev_err(dev, "rtc_read_alarm error %d\n", ret); |
273 | return ret; | 322 | return ret; |
@@ -306,7 +355,7 @@ static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) | |||
306 | 355 | ||
307 | /* update all the alarm registers in one shot */ | 356 | /* update all the alarm registers in one shot */ |
308 | ret = twl_i2c_write(TWL_MODULE_RTC, alarm_data, | 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 | if (ret) { | 359 | if (ret) { |
311 | dev_err(dev, "rtc_set_alarm error %d\n", ret); | 360 | dev_err(dev, "rtc_set_alarm error %d\n", ret); |
312 | goto out; | 361 | goto out; |
@@ -352,21 +401,23 @@ static irqreturn_t twl_rtc_interrupt(int irq, void *rtc) | |||
352 | if (res) | 401 | if (res) |
353 | goto out; | 402 | goto out; |
354 | 403 | ||
355 | /* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1 | 404 | if (twl_class_is_4030()) { |
356 | * needs 2 reads to clear the interrupt. One read is done in | 405 | /* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1 |
357 | * do_twl_pwrirq(). Doing the second read, to clear | 406 | * needs 2 reads to clear the interrupt. One read is done in |
358 | * the bit. | 407 | * do_twl_pwrirq(). Doing the second read, to clear |
359 | * | 408 | * the bit. |
360 | * FIXME the reason PWR_ISR1 needs an extra read is that | 409 | * |
361 | * RTC_IF retriggered until we cleared REG_ALARM_M above. | 410 | * FIXME the reason PWR_ISR1 needs an extra read is that |
362 | * But re-reading like this is a bad hack; by doing so we | 411 | * RTC_IF retriggered until we cleared REG_ALARM_M above. |
363 | * risk wrongly clearing status for some other IRQ (losing | 412 | * But re-reading like this is a bad hack; by doing so we |
364 | * the interrupt). Be smarter about handling RTC_UF ... | 413 | * risk wrongly clearing status for some other IRQ (losing |
365 | */ | 414 | * the interrupt). Be smarter about handling RTC_UF ... |
366 | res = twl_i2c_read_u8(TWL4030_MODULE_INT, | 415 | */ |
416 | res = twl_i2c_read_u8(TWL4030_MODULE_INT, | ||
367 | &rd_reg, TWL4030_INT_PWR_ISR1); | 417 | &rd_reg, TWL4030_INT_PWR_ISR1); |
368 | if (res) | 418 | if (res) |
369 | goto out; | 419 | goto out; |
420 | } | ||
370 | 421 | ||
371 | /* Notify RTC core on event */ | 422 | /* Notify RTC core on event */ |
372 | rtc_update_irq(rtc, 1, events); | 423 | rtc_update_irq(rtc, 1, events); |
@@ -432,6 +483,13 @@ static int __devinit twl_rtc_probe(struct platform_device *pdev) | |||
432 | goto out1; | 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 | /* Check RTC module status, Enable if it is off */ | 493 | /* Check RTC module status, Enable if it is off */ |
436 | ret = twl_rtc_read_u8(&rd_reg, REG_RTC_CTRL_REG); | 494 | ret = twl_rtc_read_u8(&rd_reg, REG_RTC_CTRL_REG); |
437 | if (ret < 0) | 495 | if (ret < 0) |
@@ -472,6 +530,13 @@ static int __devexit twl_rtc_remove(struct platform_device *pdev) | |||
472 | 530 | ||
473 | mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); | 531 | mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); |
474 | mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); | 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 | } | ||
539 | |||
475 | 540 | ||
476 | free_irq(irq, rtc); | 541 | free_irq(irq, rtc); |
477 | 542 | ||
@@ -526,6 +591,11 @@ static struct platform_driver twl4030rtc_driver = { | |||
526 | 591 | ||
527 | static int __init twl_rtc_init(void) | 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 | return platform_driver_register(&twl4030rtc_driver); | 599 | return platform_driver_register(&twl4030rtc_driver); |
530 | } | 600 | } |
531 | module_init(twl_rtc_init); | 601 | module_init(twl_rtc_init); |