diff options
| author | Ingo Molnar <mingo@elte.hu> | 2008-08-14 06:19:59 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2008-08-14 06:19:59 -0400 |
| commit | 8d7ccaa545490cdffdfaff0842436a8dd85cf47b (patch) | |
| tree | 8129b5907161bc6ae26deb3645ce1e280c5e1f51 /drivers/rtc/rtc-bfin.c | |
| parent | b2139aa0eec330c711c5a279db361e5ef1178e78 (diff) | |
| parent | 30a2f3c60a84092c8084dfe788b710f8d0768cd4 (diff) | |
Merge commit 'v2.6.27-rc3' into x86/prototypes
Conflicts:
include/asm-x86/dma-mapping.h
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'drivers/rtc/rtc-bfin.c')
| -rw-r--r-- | drivers/rtc/rtc-bfin.c | 105 |
1 files changed, 55 insertions, 50 deletions
diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index 8624f55d0560..a1af4c27939b 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * Blackfin On-Chip Real Time Clock Driver | 2 | * Blackfin On-Chip Real Time Clock Driver |
| 3 | * Supports BF52[257]/BF53[123]/BF53[467]/BF54[24789] | 3 | * Supports BF52[257]/BF53[123]/BF53[467]/BF54[24789] |
| 4 | * | 4 | * |
| 5 | * Copyright 2004-2007 Analog Devices Inc. | 5 | * Copyright 2004-2008 Analog Devices Inc. |
| 6 | * | 6 | * |
| 7 | * Enter bugs at http://blackfin.uclinux.org/ | 7 | * Enter bugs at http://blackfin.uclinux.org/ |
| 8 | * | 8 | * |
| @@ -32,6 +32,15 @@ | |||
| 32 | * writes to clear status registers complete immediately. | 32 | * writes to clear status registers complete immediately. |
| 33 | */ | 33 | */ |
| 34 | 34 | ||
| 35 | /* It may seem odd that there is no SWCNT code in here (which would be exposed | ||
| 36 | * via the periodic interrupt event, or PIE). Since the Blackfin RTC peripheral | ||
| 37 | * runs in units of seconds (N/HZ) but the Linux framework runs in units of HZ | ||
| 38 | * (2^N HZ), there is no point in keeping code that only provides 1 HZ PIEs. | ||
| 39 | * The same exact behavior can be accomplished by using the update interrupt | ||
| 40 | * event (UIE). Maybe down the line the RTC peripheral will suck less in which | ||
| 41 | * case we can re-introduce PIE support. | ||
| 42 | */ | ||
| 43 | |||
| 35 | #include <linux/bcd.h> | 44 | #include <linux/bcd.h> |
| 36 | #include <linux/completion.h> | 45 | #include <linux/completion.h> |
| 37 | #include <linux/delay.h> | 46 | #include <linux/delay.h> |
| @@ -144,14 +153,13 @@ static void bfin_rtc_sync_pending(struct device *dev) | |||
| 144 | * Initialize the RTC. Enable pre-scaler to scale RTC clock | 153 | * Initialize the RTC. Enable pre-scaler to scale RTC clock |
| 145 | * to 1Hz and clear interrupt/status registers. | 154 | * to 1Hz and clear interrupt/status registers. |
| 146 | */ | 155 | */ |
| 147 | static void bfin_rtc_reset(struct device *dev) | 156 | static void bfin_rtc_reset(struct device *dev, u16 rtc_ictl) |
| 148 | { | 157 | { |
| 149 | struct bfin_rtc *rtc = dev_get_drvdata(dev); | 158 | struct bfin_rtc *rtc = dev_get_drvdata(dev); |
| 150 | dev_dbg_stamp(dev); | 159 | dev_dbg_stamp(dev); |
| 151 | bfin_rtc_sync_pending(dev); | 160 | bfin_rtc_sync_pending(dev); |
| 152 | bfin_write_RTC_PREN(0x1); | 161 | bfin_write_RTC_PREN(0x1); |
| 153 | bfin_write_RTC_ICTL(RTC_ISTAT_WRITE_COMPLETE); | 162 | bfin_write_RTC_ICTL(rtc_ictl); |
| 154 | bfin_write_RTC_SWCNT(0); | ||
| 155 | bfin_write_RTC_ALARM(0); | 163 | bfin_write_RTC_ALARM(0); |
| 156 | bfin_write_RTC_ISTAT(0xFFFF); | 164 | bfin_write_RTC_ISTAT(0xFFFF); |
| 157 | rtc->rtc_wrote_regs = 0; | 165 | rtc->rtc_wrote_regs = 0; |
| @@ -194,14 +202,6 @@ static irqreturn_t bfin_rtc_interrupt(int irq, void *dev_id) | |||
| 194 | } | 202 | } |
| 195 | } | 203 | } |
| 196 | 204 | ||
| 197 | if (rtc_ictl & RTC_ISTAT_STOPWATCH) { | ||
| 198 | if (rtc_istat & RTC_ISTAT_STOPWATCH) { | ||
| 199 | bfin_write_RTC_ISTAT(RTC_ISTAT_STOPWATCH); | ||
| 200 | events |= RTC_PF | RTC_IRQF; | ||
| 201 | bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq); | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | if (rtc_ictl & RTC_ISTAT_SEC) { | 205 | if (rtc_ictl & RTC_ISTAT_SEC) { |
| 206 | if (rtc_istat & RTC_ISTAT_SEC) { | 206 | if (rtc_istat & RTC_ISTAT_SEC) { |
| 207 | bfin_write_RTC_ISTAT(RTC_ISTAT_SEC); | 207 | bfin_write_RTC_ISTAT(RTC_ISTAT_SEC); |
| @@ -226,7 +226,7 @@ static int bfin_rtc_open(struct device *dev) | |||
| 226 | 226 | ||
| 227 | ret = request_irq(IRQ_RTC, bfin_rtc_interrupt, IRQF_SHARED, to_platform_device(dev)->name, dev); | 227 | ret = request_irq(IRQ_RTC, bfin_rtc_interrupt, IRQF_SHARED, to_platform_device(dev)->name, dev); |
| 228 | if (!ret) | 228 | if (!ret) |
| 229 | bfin_rtc_reset(dev); | 229 | bfin_rtc_reset(dev, RTC_ISTAT_WRITE_COMPLETE); |
| 230 | 230 | ||
| 231 | return ret; | 231 | return ret; |
| 232 | } | 232 | } |
| @@ -234,16 +234,16 @@ static int bfin_rtc_open(struct device *dev) | |||
| 234 | static void bfin_rtc_release(struct device *dev) | 234 | static void bfin_rtc_release(struct device *dev) |
| 235 | { | 235 | { |
| 236 | dev_dbg_stamp(dev); | 236 | dev_dbg_stamp(dev); |
| 237 | bfin_rtc_reset(dev); | 237 | bfin_rtc_reset(dev, 0); |
| 238 | free_irq(IRQ_RTC, dev); | 238 | free_irq(IRQ_RTC, dev); |
| 239 | } | 239 | } |
| 240 | 240 | ||
| 241 | static void bfin_rtc_int_set(struct bfin_rtc *rtc, u16 rtc_int) | 241 | static void bfin_rtc_int_set(u16 rtc_int) |
| 242 | { | 242 | { |
| 243 | bfin_write_RTC_ISTAT(rtc_int); | 243 | bfin_write_RTC_ISTAT(rtc_int); |
| 244 | bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | rtc_int); | 244 | bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | rtc_int); |
| 245 | } | 245 | } |
| 246 | static void bfin_rtc_int_clear(struct bfin_rtc *rtc, u16 rtc_int) | 246 | static void bfin_rtc_int_clear(u16 rtc_int) |
| 247 | { | 247 | { |
| 248 | bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & rtc_int); | 248 | bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & rtc_int); |
| 249 | } | 249 | } |
| @@ -252,7 +252,7 @@ static void bfin_rtc_int_set_alarm(struct bfin_rtc *rtc) | |||
| 252 | /* Blackfin has different bits for whether the alarm is | 252 | /* Blackfin has different bits for whether the alarm is |
| 253 | * more than 24 hours away. | 253 | * more than 24 hours away. |
| 254 | */ | 254 | */ |
| 255 | bfin_rtc_int_set(rtc, (rtc->rtc_alarm.tm_yday == -1 ? RTC_ISTAT_ALARM : RTC_ISTAT_ALARM_DAY)); | 255 | bfin_rtc_int_set(rtc->rtc_alarm.tm_yday == -1 ? RTC_ISTAT_ALARM : RTC_ISTAT_ALARM_DAY); |
| 256 | } | 256 | } |
| 257 | static int bfin_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) | 257 | static int bfin_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) |
| 258 | { | 258 | { |
| @@ -264,23 +264,13 @@ static int bfin_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long ar | |||
| 264 | bfin_rtc_sync_pending(dev); | 264 | bfin_rtc_sync_pending(dev); |
| 265 | 265 | ||
| 266 | switch (cmd) { | 266 | switch (cmd) { |
| 267 | case RTC_PIE_ON: | ||
| 268 | dev_dbg_stamp(dev); | ||
| 269 | bfin_rtc_int_set(rtc, RTC_ISTAT_STOPWATCH); | ||
| 270 | bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq); | ||
| 271 | break; | ||
| 272 | case RTC_PIE_OFF: | ||
| 273 | dev_dbg_stamp(dev); | ||
| 274 | bfin_rtc_int_clear(rtc, ~RTC_ISTAT_STOPWATCH); | ||
| 275 | break; | ||
| 276 | |||
| 277 | case RTC_UIE_ON: | 267 | case RTC_UIE_ON: |
| 278 | dev_dbg_stamp(dev); | 268 | dev_dbg_stamp(dev); |
| 279 | bfin_rtc_int_set(rtc, RTC_ISTAT_SEC); | 269 | bfin_rtc_int_set(RTC_ISTAT_SEC); |
| 280 | break; | 270 | break; |
| 281 | case RTC_UIE_OFF: | 271 | case RTC_UIE_OFF: |
| 282 | dev_dbg_stamp(dev); | 272 | dev_dbg_stamp(dev); |
| 283 | bfin_rtc_int_clear(rtc, ~RTC_ISTAT_SEC); | 273 | bfin_rtc_int_clear(~RTC_ISTAT_SEC); |
| 284 | break; | 274 | break; |
| 285 | 275 | ||
| 286 | case RTC_AIE_ON: | 276 | case RTC_AIE_ON: |
| @@ -289,7 +279,7 @@ static int bfin_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long ar | |||
| 289 | break; | 279 | break; |
| 290 | case RTC_AIE_OFF: | 280 | case RTC_AIE_OFF: |
| 291 | dev_dbg_stamp(dev); | 281 | dev_dbg_stamp(dev); |
| 292 | bfin_rtc_int_clear(rtc, ~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)); | 282 | bfin_rtc_int_clear(~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)); |
| 293 | break; | 283 | break; |
| 294 | 284 | ||
| 295 | default: | 285 | default: |
| @@ -371,30 +361,14 @@ static int bfin_rtc_proc(struct device *dev, struct seq_file *seq) | |||
| 371 | seq_printf(seq, | 361 | seq_printf(seq, |
| 372 | "alarm_IRQ\t: %s\n" | 362 | "alarm_IRQ\t: %s\n" |
| 373 | "wkalarm_IRQ\t: %s\n" | 363 | "wkalarm_IRQ\t: %s\n" |
| 374 | "seconds_IRQ\t: %s\n" | 364 | "seconds_IRQ\t: %s\n", |
| 375 | "periodic_IRQ\t: %s\n", | ||
| 376 | yesno(ictl & RTC_ISTAT_ALARM), | 365 | yesno(ictl & RTC_ISTAT_ALARM), |
| 377 | yesno(ictl & RTC_ISTAT_ALARM_DAY), | 366 | yesno(ictl & RTC_ISTAT_ALARM_DAY), |
| 378 | yesno(ictl & RTC_ISTAT_SEC), | 367 | yesno(ictl & RTC_ISTAT_SEC)); |
| 379 | yesno(ictl & RTC_ISTAT_STOPWATCH)); | ||
| 380 | return 0; | 368 | return 0; |
| 381 | #undef yesno | 369 | #undef yesno |
| 382 | } | 370 | } |
| 383 | 371 | ||
| 384 | /** | ||
| 385 | * bfin_irq_set_freq - make sure hardware supports requested freq | ||
| 386 | * @dev: pointer to RTC device structure | ||
| 387 | * @freq: requested frequency rate | ||
| 388 | * | ||
| 389 | * The Blackfin RTC can only generate periodic events at 1 per | ||
| 390 | * second (1 Hz), so reject any attempt at changing it. | ||
| 391 | */ | ||
| 392 | static int bfin_irq_set_freq(struct device *dev, int freq) | ||
| 393 | { | ||
| 394 | dev_dbg_stamp(dev); | ||
| 395 | return -ENOTTY; | ||
| 396 | } | ||
| 397 | |||
| 398 | static struct rtc_class_ops bfin_rtc_ops = { | 372 | static struct rtc_class_ops bfin_rtc_ops = { |
| 399 | .open = bfin_rtc_open, | 373 | .open = bfin_rtc_open, |
| 400 | .release = bfin_rtc_release, | 374 | .release = bfin_rtc_release, |
| @@ -404,7 +378,6 @@ static struct rtc_class_ops bfin_rtc_ops = { | |||
| 404 | .read_alarm = bfin_rtc_read_alarm, | 378 | .read_alarm = bfin_rtc_read_alarm, |
| 405 | .set_alarm = bfin_rtc_set_alarm, | 379 | .set_alarm = bfin_rtc_set_alarm, |
| 406 | .proc = bfin_rtc_proc, | 380 | .proc = bfin_rtc_proc, |
| 407 | .irq_set_freq = bfin_irq_set_freq, | ||
| 408 | }; | 381 | }; |
| 409 | 382 | ||
| 410 | static int __devinit bfin_rtc_probe(struct platform_device *pdev) | 383 | static int __devinit bfin_rtc_probe(struct platform_device *pdev) |
| @@ -423,10 +396,14 @@ static int __devinit bfin_rtc_probe(struct platform_device *pdev) | |||
| 423 | ret = PTR_ERR(rtc->rtc_dev); | 396 | ret = PTR_ERR(rtc->rtc_dev); |
| 424 | goto err; | 397 | goto err; |
| 425 | } | 398 | } |
| 426 | rtc->rtc_dev->irq_freq = 1; | 399 | |
| 400 | /* see comment at top of file about stopwatch/PIE */ | ||
| 401 | bfin_write_RTC_SWCNT(0); | ||
| 427 | 402 | ||
| 428 | platform_set_drvdata(pdev, rtc); | 403 | platform_set_drvdata(pdev, rtc); |
| 429 | 404 | ||
| 405 | device_init_wakeup(&pdev->dev, 1); | ||
| 406 | |||
| 430 | return 0; | 407 | return 0; |
| 431 | 408 | ||
| 432 | err: | 409 | err: |
| @@ -445,6 +422,32 @@ static int __devexit bfin_rtc_remove(struct platform_device *pdev) | |||
| 445 | return 0; | 422 | return 0; |
| 446 | } | 423 | } |
| 447 | 424 | ||
| 425 | #ifdef CONFIG_PM | ||
| 426 | static int bfin_rtc_suspend(struct platform_device *pdev, pm_message_t state) | ||
| 427 | { | ||
| 428 | if (device_may_wakeup(&pdev->dev)) { | ||
| 429 | enable_irq_wake(IRQ_RTC); | ||
| 430 | bfin_rtc_sync_pending(&pdev->dev); | ||
| 431 | } else | ||
| 432 | bfin_rtc_int_clear(-1); | ||
| 433 | |||
| 434 | return 0; | ||
| 435 | } | ||
| 436 | |||
| 437 | static int bfin_rtc_resume(struct platform_device *pdev) | ||
| 438 | { | ||
| 439 | if (device_may_wakeup(&pdev->dev)) | ||
| 440 | disable_irq_wake(IRQ_RTC); | ||
| 441 | else | ||
| 442 | bfin_write_RTC_ISTAT(-1); | ||
| 443 | |||
| 444 | return 0; | ||
| 445 | } | ||
| 446 | #else | ||
| 447 | # define bfin_rtc_suspend NULL | ||
| 448 | # define bfin_rtc_resume NULL | ||
| 449 | #endif | ||
| 450 | |||
| 448 | static struct platform_driver bfin_rtc_driver = { | 451 | static struct platform_driver bfin_rtc_driver = { |
| 449 | .driver = { | 452 | .driver = { |
| 450 | .name = "rtc-bfin", | 453 | .name = "rtc-bfin", |
| @@ -452,6 +455,8 @@ static struct platform_driver bfin_rtc_driver = { | |||
| 452 | }, | 455 | }, |
| 453 | .probe = bfin_rtc_probe, | 456 | .probe = bfin_rtc_probe, |
| 454 | .remove = __devexit_p(bfin_rtc_remove), | 457 | .remove = __devexit_p(bfin_rtc_remove), |
| 458 | .suspend = bfin_rtc_suspend, | ||
| 459 | .resume = bfin_rtc_resume, | ||
| 455 | }; | 460 | }; |
| 456 | 461 | ||
| 457 | static int __init bfin_rtc_init(void) | 462 | static int __init bfin_rtc_init(void) |
