diff options
Diffstat (limited to 'drivers/rtc')
28 files changed, 2496 insertions, 83 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index e1878877399c..f822e13dc04b 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
| @@ -3,10 +3,10 @@ | |||
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | config RTC_LIB | 5 | config RTC_LIB |
| 6 | tristate | 6 | bool |
| 7 | 7 | ||
| 8 | menuconfig RTC_CLASS | 8 | menuconfig RTC_CLASS |
| 9 | tristate "Real Time Clock" | 9 | bool "Real Time Clock" |
| 10 | default n | 10 | default n |
| 11 | depends on !S390 | 11 | depends on !S390 |
| 12 | select RTC_LIB | 12 | select RTC_LIB |
| @@ -15,9 +15,6 @@ menuconfig RTC_CLASS | |||
| 15 | be allowed to plug one or more RTCs to your system. You will | 15 | be allowed to plug one or more RTCs to your system. You will |
| 16 | probably want to enable one or more of the interfaces below. | 16 | probably want to enable one or more of the interfaces below. |
| 17 | 17 | ||
| 18 | This driver can also be built as a module. If so, the module | ||
| 19 | will be called rtc-core. | ||
| 20 | |||
| 21 | if RTC_CLASS | 18 | if RTC_CLASS |
| 22 | 19 | ||
| 23 | config RTC_HCTOSYS | 20 | config RTC_HCTOSYS |
| @@ -128,6 +125,16 @@ comment "I2C RTC drivers" | |||
| 128 | 125 | ||
| 129 | if I2C | 126 | if I2C |
| 130 | 127 | ||
| 128 | config RTC_DRV_88PM860X | ||
| 129 | tristate "Marvell 88PM860x" | ||
| 130 | depends on RTC_CLASS && I2C && MFD_88PM860X | ||
| 131 | help | ||
| 132 | If you say yes here you get support for RTC function in Marvell | ||
| 133 | 88PM860x chips. | ||
| 134 | |||
| 135 | This driver can also be built as a module. If so, the module | ||
| 136 | will be called rtc-88pm860x. | ||
| 137 | |||
| 131 | config RTC_DRV_DS1307 | 138 | config RTC_DRV_DS1307 |
| 132 | tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025" | 139 | tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025" |
| 133 | help | 140 | help |
| @@ -354,12 +361,39 @@ config RTC_DRV_RX8025 | |||
| 354 | This driver can also be built as a module. If so, the module | 361 | This driver can also be built as a module. If so, the module |
| 355 | will be called rtc-rx8025. | 362 | will be called rtc-rx8025. |
| 356 | 363 | ||
| 364 | config RTC_DRV_EM3027 | ||
| 365 | tristate "EM Microelectronic EM3027" | ||
| 366 | help | ||
| 367 | If you say yes here you get support for the EM | ||
| 368 | Microelectronic EM3027 RTC chips. | ||
| 369 | |||
| 370 | This driver can also be built as a module. If so, the module | ||
| 371 | will be called rtc-em3027. | ||
| 372 | |||
| 373 | config RTC_DRV_RV3029C2 | ||
| 374 | tristate "Micro Crystal RTC" | ||
| 375 | help | ||
| 376 | If you say yes here you get support for the Micro Crystal | ||
| 377 | RV3029-C2 RTC chips. | ||
| 378 | |||
| 379 | This driver can also be built as a module. If so, the module | ||
| 380 | will be called rtc-rv3029c2. | ||
| 381 | |||
| 357 | endif # I2C | 382 | endif # I2C |
| 358 | 383 | ||
| 359 | comment "SPI RTC drivers" | 384 | comment "SPI RTC drivers" |
| 360 | 385 | ||
| 361 | if SPI_MASTER | 386 | if SPI_MASTER |
| 362 | 387 | ||
| 388 | config RTC_DRV_M41T93 | ||
| 389 | tristate "ST M41T93" | ||
| 390 | help | ||
| 391 | If you say yes here you will get support for the | ||
| 392 | ST M41T93 SPI RTC chip. | ||
| 393 | |||
| 394 | This driver can also be built as a module. If so, the module | ||
| 395 | will be called rtc-m41t93. | ||
| 396 | |||
| 363 | config RTC_DRV_M41T94 | 397 | config RTC_DRV_M41T94 |
| 364 | tristate "ST M41T94" | 398 | tristate "ST M41T94" |
| 365 | help | 399 | help |
| @@ -648,6 +682,14 @@ config RTC_DRV_WM8350 | |||
| 648 | This driver can also be built as a module. If so, the module | 682 | This driver can also be built as a module. If so, the module |
| 649 | will be called "rtc-wm8350". | 683 | will be called "rtc-wm8350". |
| 650 | 684 | ||
| 685 | config RTC_DRV_SPEAR | ||
| 686 | tristate "SPEAR ST RTC" | ||
| 687 | depends on PLAT_SPEAR | ||
| 688 | default y | ||
| 689 | help | ||
| 690 | If you say Y here you will get support for the RTC found on | ||
| 691 | spear | ||
| 692 | |||
| 651 | config RTC_DRV_PCF50633 | 693 | config RTC_DRV_PCF50633 |
| 652 | depends on MFD_PCF50633 | 694 | depends on MFD_PCF50633 |
| 653 | tristate "NXP PCF50633 RTC" | 695 | tristate "NXP PCF50633 RTC" |
| @@ -877,6 +919,13 @@ config RTC_DRV_PXA | |||
| 877 | This RTC driver uses PXA RTC registers available since pxa27x | 919 | This RTC driver uses PXA RTC registers available since pxa27x |
| 878 | series (RDxR, RYxR) instead of legacy RCNR, RTAR. | 920 | series (RDxR, RYxR) instead of legacy RCNR, RTAR. |
| 879 | 921 | ||
| 922 | config RTC_DRV_VT8500 | ||
| 923 | tristate "VIA/WonderMedia 85xx SoC RTC" | ||
| 924 | depends on ARCH_VT8500 | ||
| 925 | help | ||
| 926 | If you say Y here you will get access to the real time clock | ||
| 927 | built into your VIA VT8500 SoC or its relatives. | ||
| 928 | |||
| 880 | 929 | ||
| 881 | config RTC_DRV_SUN4V | 930 | config RTC_DRV_SUN4V |
| 882 | bool "SUN4V Hypervisor RTC" | 931 | bool "SUN4V Hypervisor RTC" |
| @@ -995,4 +1044,11 @@ config RTC_DRV_TEGRA | |||
| 995 | This drive can also be built as a module. If so, the module | 1044 | This drive can also be built as a module. If so, the module |
| 996 | will be called rtc-tegra. | 1045 | will be called rtc-tegra. |
| 997 | 1046 | ||
| 1047 | config RTC_DRV_TILE | ||
| 1048 | tristate "Tilera hypervisor RTC support" | ||
| 1049 | depends on TILE | ||
| 1050 | help | ||
| 1051 | Enable support for the Linux driver side of the Tilera | ||
| 1052 | hypervisor's real-time clock interface. | ||
| 1053 | |||
| 998 | endif # RTC_CLASS | 1054 | endif # RTC_CLASS |
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index ca91c3c42e98..213d725f16d4 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile | |||
| @@ -15,6 +15,7 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o | |||
| 15 | 15 | ||
| 16 | # Keep the list ordered. | 16 | # Keep the list ordered. |
| 17 | 17 | ||
| 18 | obj-$(CONFIG_RTC_DRV_88PM860X) += rtc-88pm860x.o | ||
| 18 | obj-$(CONFIG_RTC_DRV_AB3100) += rtc-ab3100.o | 19 | obj-$(CONFIG_RTC_DRV_AB3100) += rtc-ab3100.o |
| 19 | obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o | 20 | obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o |
| 20 | obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o | 21 | obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o |
| @@ -43,6 +44,7 @@ obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o | |||
| 43 | obj-$(CONFIG_RTC_DRV_DS3232) += rtc-ds3232.o | 44 | obj-$(CONFIG_RTC_DRV_DS3232) += rtc-ds3232.o |
| 44 | obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o | 45 | obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o |
| 45 | obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o | 46 | obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o |
| 47 | obj-$(CONFIG_RTC_DRV_EM3027) += rtc-em3027.o | ||
| 46 | obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o | 48 | obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o |
| 47 | obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o | 49 | obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o |
| 48 | obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o | 50 | obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o |
| @@ -52,6 +54,7 @@ obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o | |||
| 52 | obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o | 54 | obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o |
| 53 | obj-$(CONFIG_RTC_DRV_LPC32XX) += rtc-lpc32xx.o | 55 | obj-$(CONFIG_RTC_DRV_LPC32XX) += rtc-lpc32xx.o |
| 54 | obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o | 56 | obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o |
| 57 | obj-$(CONFIG_RTC_DRV_M41T93) += rtc-m41t93.o | ||
| 55 | obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o | 58 | obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o |
| 56 | obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o | 59 | obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o |
| 57 | obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o | 60 | obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o |
| @@ -81,22 +84,26 @@ obj-$(CONFIG_RTC_DRV_RP5C01) += rtc-rp5c01.o | |||
| 81 | obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o | 84 | obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o |
| 82 | obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o | 85 | obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o |
| 83 | obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o | 86 | obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o |
| 87 | obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o | ||
| 84 | obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o | 88 | obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o |
| 85 | obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o | 89 | obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o |
| 86 | obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o | 90 | obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o |
| 87 | obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o | 91 | obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o |
| 88 | obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o | 92 | obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o |
| 89 | obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o | 93 | obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o |
| 94 | obj-$(CONFIG_RTC_DRV_SPEAR) += rtc-spear.o | ||
| 90 | obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o | 95 | obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o |
| 91 | obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o | 96 | obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o |
| 92 | obj-$(CONFIG_RTC_DRV_STMP) += rtc-stmp3xxx.o | 97 | obj-$(CONFIG_RTC_DRV_STMP) += rtc-stmp3xxx.o |
| 93 | obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o | 98 | obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o |
| 94 | obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o | 99 | obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o |
| 95 | obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o | 100 | obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o |
| 101 | obj-$(CONFIG_RTC_DRV_TILE) += rtc-tile.o | ||
| 96 | obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o | 102 | obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o |
| 97 | obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o | 103 | obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o |
| 98 | obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o | 104 | obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o |
| 99 | obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o | 105 | obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o |
| 106 | obj-$(CONFIG_RTC_DRV_VT8500) += rtc-vt8500.o | ||
| 100 | obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o | 107 | obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o |
| 101 | obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o | 108 | obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o |
| 102 | obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o | 109 | obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o |
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 09b4437b3e61..4194e59e14cd 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c | |||
| @@ -41,26 +41,21 @@ static void rtc_device_release(struct device *dev) | |||
| 41 | * system's wall clock; restore it on resume(). | 41 | * system's wall clock; restore it on resume(). |
| 42 | */ | 42 | */ |
| 43 | 43 | ||
| 44 | static struct timespec delta; | ||
| 45 | static time_t oldtime; | 44 | static time_t oldtime; |
| 45 | static struct timespec oldts; | ||
| 46 | 46 | ||
| 47 | static int rtc_suspend(struct device *dev, pm_message_t mesg) | 47 | static int rtc_suspend(struct device *dev, pm_message_t mesg) |
| 48 | { | 48 | { |
| 49 | struct rtc_device *rtc = to_rtc_device(dev); | 49 | struct rtc_device *rtc = to_rtc_device(dev); |
| 50 | struct rtc_time tm; | 50 | struct rtc_time tm; |
| 51 | struct timespec ts = current_kernel_time(); | ||
| 52 | 51 | ||
| 53 | if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) | 52 | if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) |
| 54 | return 0; | 53 | return 0; |
| 55 | 54 | ||
| 56 | rtc_read_time(rtc, &tm); | 55 | rtc_read_time(rtc, &tm); |
| 56 | ktime_get_ts(&oldts); | ||
| 57 | rtc_tm_to_time(&tm, &oldtime); | 57 | rtc_tm_to_time(&tm, &oldtime); |
| 58 | 58 | ||
| 59 | /* RTC precision is 1 second; adjust delta for avg 1/2 sec err */ | ||
| 60 | set_normalized_timespec(&delta, | ||
| 61 | ts.tv_sec - oldtime, | ||
| 62 | ts.tv_nsec - (NSEC_PER_SEC >> 1)); | ||
| 63 | |||
| 64 | return 0; | 59 | return 0; |
| 65 | } | 60 | } |
| 66 | 61 | ||
| @@ -70,10 +65,12 @@ static int rtc_resume(struct device *dev) | |||
| 70 | struct rtc_time tm; | 65 | struct rtc_time tm; |
| 71 | time_t newtime; | 66 | time_t newtime; |
| 72 | struct timespec time; | 67 | struct timespec time; |
| 68 | struct timespec newts; | ||
| 73 | 69 | ||
| 74 | if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) | 70 | if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) |
| 75 | return 0; | 71 | return 0; |
| 76 | 72 | ||
| 73 | ktime_get_ts(&newts); | ||
| 77 | rtc_read_time(rtc, &tm); | 74 | rtc_read_time(rtc, &tm); |
| 78 | if (rtc_valid_tm(&tm) != 0) { | 75 | if (rtc_valid_tm(&tm) != 0) { |
| 79 | pr_debug("%s: bogus resume time\n", dev_name(&rtc->dev)); | 76 | pr_debug("%s: bogus resume time\n", dev_name(&rtc->dev)); |
| @@ -85,15 +82,13 @@ static int rtc_resume(struct device *dev) | |||
| 85 | pr_debug("%s: time travel!\n", dev_name(&rtc->dev)); | 82 | pr_debug("%s: time travel!\n", dev_name(&rtc->dev)); |
| 86 | return 0; | 83 | return 0; |
| 87 | } | 84 | } |
| 85 | /* calculate the RTC time delta */ | ||
| 86 | set_normalized_timespec(&time, newtime - oldtime, 0); | ||
| 88 | 87 | ||
| 89 | /* restore wall clock using delta against this RTC; | 88 | /* subtract kernel time between rtc_suspend to rtc_resume */ |
| 90 | * adjust again for avg 1/2 second RTC sampling error | 89 | time = timespec_sub(time, timespec_sub(newts, oldts)); |
| 91 | */ | ||
| 92 | set_normalized_timespec(&time, | ||
| 93 | newtime + delta.tv_sec, | ||
| 94 | (NSEC_PER_SEC >> 1) + delta.tv_nsec); | ||
| 95 | do_settimeofday(&time); | ||
| 96 | 90 | ||
| 91 | timekeeping_inject_sleeptime(&time); | ||
| 97 | return 0; | 92 | return 0; |
| 98 | } | 93 | } |
| 99 | 94 | ||
| @@ -171,7 +166,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, | |||
| 171 | err = __rtc_read_alarm(rtc, &alrm); | 166 | err = __rtc_read_alarm(rtc, &alrm); |
| 172 | 167 | ||
| 173 | if (!err && !rtc_valid_tm(&alrm.time)) | 168 | if (!err && !rtc_valid_tm(&alrm.time)) |
| 174 | rtc_set_alarm(rtc, &alrm); | 169 | rtc_initialize_alarm(rtc, &alrm); |
| 175 | 170 | ||
| 176 | strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE); | 171 | strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE); |
| 177 | dev_set_name(&rtc->dev, "rtc%d", id); | 172 | dev_set_name(&rtc->dev, "rtc%d", id); |
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 23719f0acbf6..ef6316acec43 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c | |||
| @@ -375,6 +375,32 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) | |||
| 375 | } | 375 | } |
| 376 | EXPORT_SYMBOL_GPL(rtc_set_alarm); | 376 | EXPORT_SYMBOL_GPL(rtc_set_alarm); |
| 377 | 377 | ||
| 378 | /* Called once per device from rtc_device_register */ | ||
| 379 | int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) | ||
| 380 | { | ||
| 381 | int err; | ||
| 382 | |||
| 383 | err = rtc_valid_tm(&alarm->time); | ||
| 384 | if (err != 0) | ||
| 385 | return err; | ||
| 386 | |||
| 387 | err = mutex_lock_interruptible(&rtc->ops_lock); | ||
| 388 | if (err) | ||
| 389 | return err; | ||
| 390 | |||
| 391 | rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time); | ||
| 392 | rtc->aie_timer.period = ktime_set(0, 0); | ||
| 393 | if (alarm->enabled) { | ||
| 394 | rtc->aie_timer.enabled = 1; | ||
| 395 | timerqueue_add(&rtc->timerqueue, &rtc->aie_timer.node); | ||
| 396 | } | ||
| 397 | mutex_unlock(&rtc->ops_lock); | ||
| 398 | return err; | ||
| 399 | } | ||
| 400 | EXPORT_SYMBOL_GPL(rtc_initialize_alarm); | ||
| 401 | |||
| 402 | |||
| 403 | |||
| 378 | int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled) | 404 | int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled) |
| 379 | { | 405 | { |
| 380 | int err = mutex_lock_interruptible(&rtc->ops_lock); | 406 | int err = mutex_lock_interruptible(&rtc->ops_lock); |
diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c new file mode 100644 index 000000000000..64b847b7f970 --- /dev/null +++ b/drivers/rtc/rtc-88pm860x.c | |||
| @@ -0,0 +1,427 @@ | |||
| 1 | /* | ||
| 2 | * Real Time Clock driver for Marvell 88PM860x PMIC | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010 Marvell International Ltd. | ||
| 5 | * Author: Haojian Zhuang <haojian.zhuang@marvell.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/platform_device.h> | ||
| 15 | #include <linux/slab.h> | ||
| 16 | #include <linux/mutex.h> | ||
| 17 | #include <linux/rtc.h> | ||
| 18 | #include <linux/delay.h> | ||
| 19 | #include <linux/mfd/core.h> | ||
| 20 | #include <linux/mfd/88pm860x.h> | ||
| 21 | |||
| 22 | #define VRTC_CALIBRATION | ||
| 23 | |||
| 24 | struct pm860x_rtc_info { | ||
| 25 | struct pm860x_chip *chip; | ||
| 26 | struct i2c_client *i2c; | ||
| 27 | struct rtc_device *rtc_dev; | ||
| 28 | struct device *dev; | ||
| 29 | struct delayed_work calib_work; | ||
| 30 | |||
| 31 | int irq; | ||
| 32 | int vrtc; | ||
| 33 | int (*sync)(unsigned int ticks); | ||
| 34 | }; | ||
| 35 | |||
| 36 | #define REG_VRTC_MEAS1 0x7D | ||
| 37 | |||
| 38 | #define REG0_ADDR 0xB0 | ||
| 39 | #define REG1_ADDR 0xB2 | ||
| 40 | #define REG2_ADDR 0xB4 | ||
| 41 | #define REG3_ADDR 0xB6 | ||
| 42 | |||
| 43 | #define REG0_DATA 0xB1 | ||
| 44 | #define REG1_DATA 0xB3 | ||
| 45 | #define REG2_DATA 0xB5 | ||
| 46 | #define REG3_DATA 0xB7 | ||
| 47 | |||
| 48 | /* bit definitions of Measurement Enable Register 2 (0x51) */ | ||
| 49 | #define MEAS2_VRTC (1 << 0) | ||
| 50 | |||
| 51 | /* bit definitions of RTC Register 1 (0xA0) */ | ||
| 52 | #define ALARM_EN (1 << 3) | ||
| 53 | #define ALARM_WAKEUP (1 << 4) | ||
| 54 | #define ALARM (1 << 5) | ||
| 55 | #define RTC1_USE_XO (1 << 7) | ||
| 56 | |||
| 57 | #define VRTC_CALIB_INTERVAL (HZ * 60 * 10) /* 10 minutes */ | ||
| 58 | |||
| 59 | static irqreturn_t rtc_update_handler(int irq, void *data) | ||
| 60 | { | ||
| 61 | struct pm860x_rtc_info *info = (struct pm860x_rtc_info *)data; | ||
| 62 | int mask; | ||
| 63 | |||
| 64 | mask = ALARM | ALARM_WAKEUP; | ||
| 65 | pm860x_set_bits(info->i2c, PM8607_RTC1, mask | ALARM_EN, mask); | ||
| 66 | rtc_update_irq(info->rtc_dev, 1, RTC_AF); | ||
| 67 | return IRQ_HANDLED; | ||
| 68 | } | ||
| 69 | |||
| 70 | static int pm860x_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) | ||
| 71 | { | ||
| 72 | struct pm860x_rtc_info *info = dev_get_drvdata(dev); | ||
| 73 | |||
| 74 | if (enabled) | ||
| 75 | pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM, ALARM); | ||
| 76 | else | ||
| 77 | pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM, 0); | ||
| 78 | return 0; | ||
| 79 | } | ||
| 80 | |||
| 81 | /* | ||
| 82 | * Calculate the next alarm time given the requested alarm time mask | ||
| 83 | * and the current time. | ||
| 84 | */ | ||
| 85 | static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, | ||
| 86 | struct rtc_time *alrm) | ||
| 87 | { | ||
| 88 | unsigned long next_time; | ||
| 89 | unsigned long now_time; | ||
| 90 | |||
| 91 | next->tm_year = now->tm_year; | ||
| 92 | next->tm_mon = now->tm_mon; | ||
| 93 | next->tm_mday = now->tm_mday; | ||
| 94 | next->tm_hour = alrm->tm_hour; | ||
| 95 | next->tm_min = alrm->tm_min; | ||
| 96 | next->tm_sec = alrm->tm_sec; | ||
| 97 | |||
| 98 | rtc_tm_to_time(now, &now_time); | ||
| 99 | rtc_tm_to_time(next, &next_time); | ||
| 100 | |||
| 101 | if (next_time < now_time) { | ||
| 102 | /* Advance one day */ | ||
| 103 | next_time += 60 * 60 * 24; | ||
| 104 | rtc_time_to_tm(next_time, next); | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | static int pm860x_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
| 109 | { | ||
| 110 | struct pm860x_rtc_info *info = dev_get_drvdata(dev); | ||
| 111 | unsigned char buf[8]; | ||
| 112 | unsigned long ticks, base, data; | ||
| 113 | |||
| 114 | pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf); | ||
| 115 | dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1], | ||
| 116 | buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); | ||
| 117 | base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7]; | ||
| 118 | |||
| 119 | /* load 32-bit read-only counter */ | ||
| 120 | pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf); | ||
| 121 | data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; | ||
| 122 | ticks = base + data; | ||
| 123 | dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", | ||
| 124 | base, data, ticks); | ||
| 125 | |||
| 126 | rtc_time_to_tm(ticks, tm); | ||
| 127 | |||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | |||
| 131 | static int pm860x_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
| 132 | { | ||
| 133 | struct pm860x_rtc_info *info = dev_get_drvdata(dev); | ||
| 134 | unsigned char buf[4]; | ||
| 135 | unsigned long ticks, base, data; | ||
| 136 | |||
| 137 | if ((tm->tm_year < 70) || (tm->tm_year > 138)) { | ||
| 138 | dev_dbg(info->dev, "Set time %d out of range. " | ||
| 139 | "Please set time between 1970 to 2038.\n", | ||
| 140 | 1900 + tm->tm_year); | ||
| 141 | return -EINVAL; | ||
| 142 | } | ||
| 143 | rtc_tm_to_time(tm, &ticks); | ||
| 144 | |||
| 145 | /* load 32-bit read-only counter */ | ||
| 146 | pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf); | ||
| 147 | data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; | ||
| 148 | base = ticks - data; | ||
| 149 | dev_dbg(info->dev, "set base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", | ||
| 150 | base, data, ticks); | ||
| 151 | |||
| 152 | pm860x_page_reg_write(info->i2c, REG0_DATA, (base >> 24) & 0xFF); | ||
| 153 | pm860x_page_reg_write(info->i2c, REG1_DATA, (base >> 16) & 0xFF); | ||
| 154 | pm860x_page_reg_write(info->i2c, REG2_DATA, (base >> 8) & 0xFF); | ||
| 155 | pm860x_page_reg_write(info->i2c, REG3_DATA, base & 0xFF); | ||
| 156 | |||
| 157 | if (info->sync) | ||
| 158 | info->sync(ticks); | ||
| 159 | return 0; | ||
| 160 | } | ||
| 161 | |||
| 162 | static int pm860x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
| 163 | { | ||
| 164 | struct pm860x_rtc_info *info = dev_get_drvdata(dev); | ||
| 165 | unsigned char buf[8]; | ||
| 166 | unsigned long ticks, base, data; | ||
| 167 | int ret; | ||
| 168 | |||
| 169 | pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf); | ||
| 170 | dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1], | ||
| 171 | buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); | ||
| 172 | base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7]; | ||
| 173 | |||
| 174 | pm860x_bulk_read(info->i2c, PM8607_RTC_EXPIRE1, 4, buf); | ||
| 175 | data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; | ||
| 176 | ticks = base + data; | ||
| 177 | dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", | ||
| 178 | base, data, ticks); | ||
| 179 | |||
| 180 | rtc_time_to_tm(ticks, &alrm->time); | ||
| 181 | ret = pm860x_reg_read(info->i2c, PM8607_RTC1); | ||
| 182 | alrm->enabled = (ret & ALARM_EN) ? 1 : 0; | ||
| 183 | alrm->pending = (ret & (ALARM | ALARM_WAKEUP)) ? 1 : 0; | ||
| 184 | return 0; | ||
| 185 | } | ||
| 186 | |||
| 187 | static int pm860x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
| 188 | { | ||
| 189 | struct pm860x_rtc_info *info = dev_get_drvdata(dev); | ||
| 190 | struct rtc_time now_tm, alarm_tm; | ||
| 191 | unsigned long ticks, base, data; | ||
| 192 | unsigned char buf[8]; | ||
| 193 | int mask; | ||
| 194 | |||
| 195 | pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM_EN, 0); | ||
| 196 | |||
| 197 | pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf); | ||
| 198 | dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1], | ||
| 199 | buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); | ||
| 200 | base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7]; | ||
| 201 | |||
| 202 | /* load 32-bit read-only counter */ | ||
| 203 | pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf); | ||
| 204 | data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; | ||
| 205 | ticks = base + data; | ||
| 206 | dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", | ||
| 207 | base, data, ticks); | ||
| 208 | |||
| 209 | rtc_time_to_tm(ticks, &now_tm); | ||
| 210 | rtc_next_alarm_time(&alarm_tm, &now_tm, &alrm->time); | ||
| 211 | /* get new ticks for alarm in 24 hours */ | ||
| 212 | rtc_tm_to_time(&alarm_tm, &ticks); | ||
| 213 | data = ticks - base; | ||
| 214 | |||
| 215 | buf[0] = data & 0xff; | ||
| 216 | buf[1] = (data >> 8) & 0xff; | ||
| 217 | buf[2] = (data >> 16) & 0xff; | ||
| 218 | buf[3] = (data >> 24) & 0xff; | ||
| 219 | pm860x_bulk_write(info->i2c, PM8607_RTC_EXPIRE1, 4, buf); | ||
| 220 | if (alrm->enabled) { | ||
| 221 | mask = ALARM | ALARM_WAKEUP | ALARM_EN; | ||
| 222 | pm860x_set_bits(info->i2c, PM8607_RTC1, mask, mask); | ||
| 223 | } else { | ||
| 224 | mask = ALARM | ALARM_WAKEUP | ALARM_EN; | ||
| 225 | pm860x_set_bits(info->i2c, PM8607_RTC1, mask, | ||
| 226 | ALARM | ALARM_WAKEUP); | ||
| 227 | } | ||
| 228 | return 0; | ||
| 229 | } | ||
| 230 | |||
| 231 | static const struct rtc_class_ops pm860x_rtc_ops = { | ||
| 232 | .read_time = pm860x_rtc_read_time, | ||
| 233 | .set_time = pm860x_rtc_set_time, | ||
| 234 | .read_alarm = pm860x_rtc_read_alarm, | ||
| 235 | .set_alarm = pm860x_rtc_set_alarm, | ||
| 236 | .alarm_irq_enable = pm860x_rtc_alarm_irq_enable, | ||
| 237 | }; | ||
| 238 | |||
| 239 | #ifdef VRTC_CALIBRATION | ||
| 240 | static void calibrate_vrtc_work(struct work_struct *work) | ||
| 241 | { | ||
| 242 | struct pm860x_rtc_info *info = container_of(work, | ||
| 243 | struct pm860x_rtc_info, calib_work.work); | ||
| 244 | unsigned char buf[2]; | ||
| 245 | unsigned int sum, data, mean, vrtc_set; | ||
| 246 | int i; | ||
| 247 | |||
| 248 | for (i = 0, sum = 0; i < 16; i++) { | ||
| 249 | msleep(100); | ||
| 250 | pm860x_bulk_read(info->i2c, REG_VRTC_MEAS1, 2, buf); | ||
| 251 | data = (buf[0] << 4) | buf[1]; | ||
| 252 | data = (data * 5400) >> 12; /* convert to mv */ | ||
| 253 | sum += data; | ||
| 254 | } | ||
| 255 | mean = sum >> 4; | ||
| 256 | vrtc_set = 2700 + (info->vrtc & 0x3) * 200; | ||
| 257 | dev_dbg(info->dev, "mean:%d, vrtc_set:%d\n", mean, vrtc_set); | ||
| 258 | |||
| 259 | sum = pm860x_reg_read(info->i2c, PM8607_RTC_MISC1); | ||
| 260 | data = sum & 0x3; | ||
| 261 | if ((mean + 200) < vrtc_set) { | ||
| 262 | /* try higher voltage */ | ||
| 263 | if (++data == 4) | ||
| 264 | goto out; | ||
| 265 | data = (sum & 0xf8) | (data & 0x3); | ||
| 266 | pm860x_reg_write(info->i2c, PM8607_RTC_MISC1, data); | ||
| 267 | } else if ((mean - 200) > vrtc_set) { | ||
| 268 | /* try lower voltage */ | ||
| 269 | if (data-- == 0) | ||
| 270 | goto out; | ||
| 271 | data = (sum & 0xf8) | (data & 0x3); | ||
| 272 | pm860x_reg_write(info->i2c, PM8607_RTC_MISC1, data); | ||
| 273 | } else | ||
| 274 | goto out; | ||
| 275 | dev_dbg(info->dev, "set 0x%x to RTC_MISC1\n", data); | ||
| 276 | /* trigger next calibration since VRTC is updated */ | ||
| 277 | schedule_delayed_work(&info->calib_work, VRTC_CALIB_INTERVAL); | ||
| 278 | return; | ||
| 279 | out: | ||
| 280 | /* disable measurement */ | ||
| 281 | pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, 0); | ||
| 282 | dev_dbg(info->dev, "finish VRTC calibration\n"); | ||
| 283 | return; | ||
| 284 | } | ||
| 285 | #endif | ||
| 286 | |||
| 287 | static int __devinit pm860x_rtc_probe(struct platform_device *pdev) | ||
| 288 | { | ||
| 289 | struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); | ||
| 290 | struct pm860x_rtc_pdata *pdata = NULL; | ||
| 291 | struct pm860x_rtc_info *info; | ||
| 292 | struct rtc_time tm; | ||
| 293 | unsigned long ticks = 0; | ||
| 294 | int ret; | ||
| 295 | |||
| 296 | pdata = pdev->dev.platform_data; | ||
| 297 | if (pdata == NULL) | ||
| 298 | dev_warn(&pdev->dev, "No platform data!\n"); | ||
| 299 | |||
| 300 | info = kzalloc(sizeof(struct pm860x_rtc_info), GFP_KERNEL); | ||
| 301 | if (!info) | ||
| 302 | return -ENOMEM; | ||
| 303 | info->irq = platform_get_irq(pdev, 0); | ||
| 304 | if (info->irq < 0) { | ||
| 305 | dev_err(&pdev->dev, "No IRQ resource!\n"); | ||
| 306 | ret = -EINVAL; | ||
| 307 | goto out; | ||
| 308 | } | ||
| 309 | |||
| 310 | info->chip = chip; | ||
| 311 | info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; | ||
| 312 | info->dev = &pdev->dev; | ||
| 313 | dev_set_drvdata(&pdev->dev, info); | ||
| 314 | |||
| 315 | ret = request_threaded_irq(info->irq, NULL, rtc_update_handler, | ||
| 316 | IRQF_ONESHOT, "rtc", info); | ||
| 317 | if (ret < 0) { | ||
| 318 | dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n", | ||
| 319 | info->irq, ret); | ||
| 320 | goto out; | ||
| 321 | } | ||
| 322 | |||
| 323 | /* set addresses of 32-bit base value for RTC time */ | ||
| 324 | pm860x_page_reg_write(info->i2c, REG0_ADDR, REG0_DATA); | ||
| 325 | pm860x_page_reg_write(info->i2c, REG1_ADDR, REG1_DATA); | ||
| 326 | pm860x_page_reg_write(info->i2c, REG2_ADDR, REG2_DATA); | ||
| 327 | pm860x_page_reg_write(info->i2c, REG3_ADDR, REG3_DATA); | ||
| 328 | |||
| 329 | ret = pm860x_rtc_read_time(&pdev->dev, &tm); | ||
| 330 | if (ret < 0) { | ||
| 331 | dev_err(&pdev->dev, "Failed to read initial time.\n"); | ||
| 332 | goto out_rtc; | ||
| 333 | } | ||
| 334 | if ((tm.tm_year < 70) || (tm.tm_year > 138)) { | ||
| 335 | tm.tm_year = 70; | ||
| 336 | tm.tm_mon = 0; | ||
| 337 | tm.tm_mday = 1; | ||
| 338 | tm.tm_hour = 0; | ||
| 339 | tm.tm_min = 0; | ||
| 340 | tm.tm_sec = 0; | ||
| 341 | ret = pm860x_rtc_set_time(&pdev->dev, &tm); | ||
| 342 | if (ret < 0) { | ||
| 343 | dev_err(&pdev->dev, "Failed to set initial time.\n"); | ||
| 344 | goto out_rtc; | ||
| 345 | } | ||
| 346 | } | ||
| 347 | rtc_tm_to_time(&tm, &ticks); | ||
| 348 | if (pdata && pdata->sync) { | ||
| 349 | pdata->sync(ticks); | ||
| 350 | info->sync = pdata->sync; | ||
| 351 | } | ||
| 352 | |||
| 353 | info->rtc_dev = rtc_device_register("88pm860x-rtc", &pdev->dev, | ||
| 354 | &pm860x_rtc_ops, THIS_MODULE); | ||
| 355 | ret = PTR_ERR(info->rtc_dev); | ||
| 356 | if (IS_ERR(info->rtc_dev)) { | ||
| 357 | dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); | ||
| 358 | goto out_rtc; | ||
| 359 | } | ||
| 360 | |||
| 361 | /* | ||
| 362 | * enable internal XO instead of internal 3.25MHz clock since it can | ||
| 363 | * free running in PMIC power-down state. | ||
| 364 | */ | ||
| 365 | pm860x_set_bits(info->i2c, PM8607_RTC1, RTC1_USE_XO, RTC1_USE_XO); | ||
| 366 | |||
| 367 | #ifdef VRTC_CALIBRATION | ||
| 368 | /* <00> -- 2.7V, <01> -- 2.9V, <10> -- 3.1V, <11> -- 3.3V */ | ||
| 369 | if (pdata && pdata->vrtc) | ||
| 370 | info->vrtc = pdata->vrtc & 0x3; | ||
| 371 | else | ||
| 372 | info->vrtc = 1; | ||
| 373 | pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, MEAS2_VRTC); | ||
| 374 | |||
| 375 | /* calibrate VRTC */ | ||
| 376 | INIT_DELAYED_WORK(&info->calib_work, calibrate_vrtc_work); | ||
| 377 | schedule_delayed_work(&info->calib_work, VRTC_CALIB_INTERVAL); | ||
| 378 | #endif /* VRTC_CALIBRATION */ | ||
| 379 | return 0; | ||
| 380 | out_rtc: | ||
| 381 | free_irq(info->irq, info); | ||
| 382 | out: | ||
| 383 | kfree(info); | ||
| 384 | return ret; | ||
| 385 | } | ||
| 386 | |||
| 387 | static int __devexit pm860x_rtc_remove(struct platform_device *pdev) | ||
| 388 | { | ||
| 389 | struct pm860x_rtc_info *info = platform_get_drvdata(pdev); | ||
| 390 | |||
| 391 | #ifdef VRTC_CALIBRATION | ||
| 392 | flush_scheduled_work(); | ||
| 393 | /* disable measurement */ | ||
| 394 | pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, 0); | ||
| 395 | #endif /* VRTC_CALIBRATION */ | ||
| 396 | |||
| 397 | platform_set_drvdata(pdev, NULL); | ||
| 398 | rtc_device_unregister(info->rtc_dev); | ||
| 399 | free_irq(info->irq, info); | ||
| 400 | kfree(info); | ||
| 401 | return 0; | ||
| 402 | } | ||
| 403 | |||
| 404 | static struct platform_driver pm860x_rtc_driver = { | ||
| 405 | .driver = { | ||
| 406 | .name = "88pm860x-rtc", | ||
| 407 | .owner = THIS_MODULE, | ||
| 408 | }, | ||
| 409 | .probe = pm860x_rtc_probe, | ||
| 410 | .remove = __devexit_p(pm860x_rtc_remove), | ||
| 411 | }; | ||
| 412 | |||
| 413 | static int __init pm860x_rtc_init(void) | ||
| 414 | { | ||
| 415 | return platform_driver_register(&pm860x_rtc_driver); | ||
| 416 | } | ||
| 417 | module_init(pm860x_rtc_init); | ||
| 418 | |||
| 419 | static void __exit pm860x_rtc_exit(void) | ||
| 420 | { | ||
| 421 | platform_driver_unregister(&pm860x_rtc_driver); | ||
| 422 | } | ||
| 423 | module_exit(pm860x_rtc_exit); | ||
| 424 | |||
| 425 | MODULE_DESCRIPTION("Marvell 88PM860x RTC driver"); | ||
| 426 | MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); | ||
| 427 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index a0fc4cf42abf..90d866272c8e 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c | |||
| @@ -250,6 +250,8 @@ static int bfin_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) | |||
| 250 | bfin_rtc_int_set_alarm(rtc); | 250 | bfin_rtc_int_set_alarm(rtc); |
| 251 | else | 251 | else |
| 252 | bfin_rtc_int_clear(~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)); | 252 | bfin_rtc_int_clear(~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)); |
| 253 | |||
| 254 | return 0; | ||
| 253 | } | 255 | } |
| 254 | 256 | ||
| 255 | static int bfin_rtc_read_time(struct device *dev, struct rtc_time *tm) | 257 | static int bfin_rtc_read_time(struct device *dev, struct rtc_time *tm) |
diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c index 316f484999b5..80f9c88214c5 100644 --- a/drivers/rtc/rtc-coh901331.c +++ b/drivers/rtc/rtc-coh901331.c | |||
| @@ -220,6 +220,7 @@ static int __init coh901331_probe(struct platform_device *pdev) | |||
| 220 | } | 220 | } |
| 221 | clk_disable(rtap->clk); | 221 | clk_disable(rtap->clk); |
| 222 | 222 | ||
| 223 | platform_set_drvdata(pdev, rtap); | ||
| 223 | rtap->rtc = rtc_device_register("coh901331", &pdev->dev, &coh901331_ops, | 224 | rtap->rtc = rtc_device_register("coh901331", &pdev->dev, &coh901331_ops, |
| 224 | THIS_MODULE); | 225 | THIS_MODULE); |
| 225 | if (IS_ERR(rtap->rtc)) { | 226 | if (IS_ERR(rtap->rtc)) { |
| @@ -227,11 +228,10 @@ static int __init coh901331_probe(struct platform_device *pdev) | |||
| 227 | goto out_no_rtc; | 228 | goto out_no_rtc; |
| 228 | } | 229 | } |
| 229 | 230 | ||
| 230 | platform_set_drvdata(pdev, rtap); | ||
| 231 | |||
| 232 | return 0; | 231 | return 0; |
| 233 | 232 | ||
| 234 | out_no_rtc: | 233 | out_no_rtc: |
| 234 | platform_set_drvdata(pdev, NULL); | ||
| 235 | out_no_clk_enable: | 235 | out_no_clk_enable: |
| 236 | clk_put(rtap->clk); | 236 | clk_put(rtap->clk); |
| 237 | out_no_clk: | 237 | out_no_clk: |
diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c index 8d46838dff8a..755e1fe914af 100644 --- a/drivers/rtc/rtc-davinci.c +++ b/drivers/rtc/rtc-davinci.c | |||
| @@ -524,6 +524,8 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) | |||
| 524 | goto fail2; | 524 | goto fail2; |
| 525 | } | 525 | } |
| 526 | 526 | ||
| 527 | platform_set_drvdata(pdev, davinci_rtc); | ||
| 528 | |||
| 527 | davinci_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, | 529 | davinci_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, |
| 528 | &davinci_rtc_ops, THIS_MODULE); | 530 | &davinci_rtc_ops, THIS_MODULE); |
| 529 | if (IS_ERR(davinci_rtc->rtc)) { | 531 | if (IS_ERR(davinci_rtc->rtc)) { |
| @@ -553,8 +555,6 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) | |||
| 553 | 555 | ||
| 554 | rtcss_write(davinci_rtc, PRTCSS_RTC_CCTRL_CAEN, PRTCSS_RTC_CCTRL); | 556 | rtcss_write(davinci_rtc, PRTCSS_RTC_CCTRL_CAEN, PRTCSS_RTC_CCTRL); |
| 555 | 557 | ||
| 556 | platform_set_drvdata(pdev, davinci_rtc); | ||
| 557 | |||
| 558 | device_init_wakeup(&pdev->dev, 0); | 558 | device_init_wakeup(&pdev->dev, 0); |
| 559 | 559 | ||
| 560 | return 0; | 560 | return 0; |
| @@ -562,6 +562,7 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) | |||
| 562 | fail4: | 562 | fail4: |
| 563 | rtc_device_unregister(davinci_rtc->rtc); | 563 | rtc_device_unregister(davinci_rtc->rtc); |
| 564 | fail3: | 564 | fail3: |
| 565 | platform_set_drvdata(pdev, NULL); | ||
| 565 | iounmap(davinci_rtc->base); | 566 | iounmap(davinci_rtc->base); |
| 566 | fail2: | 567 | fail2: |
| 567 | release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size); | 568 | release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size); |
diff --git a/drivers/rtc/rtc-ds1286.c b/drivers/rtc/rtc-ds1286.c index 60ce69600828..47e681df31e2 100644 --- a/drivers/rtc/rtc-ds1286.c +++ b/drivers/rtc/rtc-ds1286.c | |||
| @@ -355,6 +355,7 @@ static int __devinit ds1286_probe(struct platform_device *pdev) | |||
| 355 | goto out; | 355 | goto out; |
| 356 | } | 356 | } |
| 357 | spin_lock_init(&priv->lock); | 357 | spin_lock_init(&priv->lock); |
| 358 | platform_set_drvdata(pdev, priv); | ||
| 358 | rtc = rtc_device_register("ds1286", &pdev->dev, | 359 | rtc = rtc_device_register("ds1286", &pdev->dev, |
| 359 | &ds1286_ops, THIS_MODULE); | 360 | &ds1286_ops, THIS_MODULE); |
| 360 | if (IS_ERR(rtc)) { | 361 | if (IS_ERR(rtc)) { |
| @@ -362,7 +363,6 @@ static int __devinit ds1286_probe(struct platform_device *pdev) | |||
| 362 | goto out; | 363 | goto out; |
| 363 | } | 364 | } |
| 364 | priv->rtc = rtc; | 365 | priv->rtc = rtc; |
| 365 | platform_set_drvdata(pdev, priv); | ||
| 366 | return 0; | 366 | return 0; |
| 367 | 367 | ||
| 368 | out: | 368 | out: |
diff --git a/drivers/rtc/rtc-em3027.c b/drivers/rtc/rtc-em3027.c new file mode 100644 index 000000000000..d8e1c2578553 --- /dev/null +++ b/drivers/rtc/rtc-em3027.c | |||
| @@ -0,0 +1,161 @@ | |||
| 1 | /* | ||
| 2 | * An rtc/i2c driver for the EM Microelectronic EM3027 | ||
| 3 | * Copyright 2011 CompuLab, Ltd. | ||
| 4 | * | ||
| 5 | * Author: Mike Rapoport <mike@compulab.co.il> | ||
| 6 | * | ||
| 7 | * Based on rtc-ds1672.c by Alessandro Zummo <a.zummo@towertech.it> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License version 2 as | ||
| 11 | * published by the Free Software Foundation. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/i2c.h> | ||
| 15 | #include <linux/rtc.h> | ||
| 16 | #include <linux/bcd.h> | ||
| 17 | |||
| 18 | /* Registers */ | ||
| 19 | #define EM3027_REG_ON_OFF_CTRL 0x00 | ||
| 20 | #define EM3027_REG_IRQ_CTRL 0x01 | ||
| 21 | #define EM3027_REG_IRQ_FLAGS 0x02 | ||
| 22 | #define EM3027_REG_STATUS 0x03 | ||
| 23 | #define EM3027_REG_RST_CTRL 0x04 | ||
| 24 | |||
| 25 | #define EM3027_REG_WATCH_SEC 0x08 | ||
| 26 | #define EM3027_REG_WATCH_MIN 0x09 | ||
| 27 | #define EM3027_REG_WATCH_HOUR 0x0a | ||
| 28 | #define EM3027_REG_WATCH_DATE 0x0b | ||
| 29 | #define EM3027_REG_WATCH_DAY 0x0c | ||
| 30 | #define EM3027_REG_WATCH_MON 0x0d | ||
| 31 | #define EM3027_REG_WATCH_YEAR 0x0e | ||
| 32 | |||
| 33 | #define EM3027_REG_ALARM_SEC 0x10 | ||
| 34 | #define EM3027_REG_ALARM_MIN 0x11 | ||
| 35 | #define EM3027_REG_ALARM_HOUR 0x12 | ||
| 36 | #define EM3027_REG_ALARM_DATE 0x13 | ||
| 37 | #define EM3027_REG_ALARM_DAY 0x14 | ||
| 38 | #define EM3027_REG_ALARM_MON 0x15 | ||
| 39 | #define EM3027_REG_ALARM_YEAR 0x16 | ||
| 40 | |||
| 41 | static struct i2c_driver em3027_driver; | ||
| 42 | |||
| 43 | static int em3027_get_time(struct device *dev, struct rtc_time *tm) | ||
| 44 | { | ||
| 45 | struct i2c_client *client = to_i2c_client(dev); | ||
| 46 | |||
| 47 | unsigned char addr = EM3027_REG_WATCH_SEC; | ||
| 48 | unsigned char buf[7]; | ||
| 49 | |||
| 50 | struct i2c_msg msgs[] = { | ||
| 51 | {client->addr, 0, 1, &addr}, /* setup read addr */ | ||
| 52 | {client->addr, I2C_M_RD, 7, buf}, /* read time/date */ | ||
| 53 | }; | ||
| 54 | |||
| 55 | /* read time/date registers */ | ||
| 56 | if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { | ||
| 57 | dev_err(&client->dev, "%s: read error\n", __func__); | ||
| 58 | return -EIO; | ||
| 59 | } | ||
| 60 | |||
| 61 | tm->tm_sec = bcd2bin(buf[0]); | ||
| 62 | tm->tm_min = bcd2bin(buf[1]); | ||
| 63 | tm->tm_hour = bcd2bin(buf[2]); | ||
| 64 | tm->tm_mday = bcd2bin(buf[3]); | ||
| 65 | tm->tm_wday = bcd2bin(buf[4]); | ||
| 66 | tm->tm_mon = bcd2bin(buf[5]); | ||
| 67 | tm->tm_year = bcd2bin(buf[6]) + 100; | ||
| 68 | |||
| 69 | return 0; | ||
| 70 | } | ||
| 71 | |||
| 72 | static int em3027_set_time(struct device *dev, struct rtc_time *tm) | ||
| 73 | { | ||
| 74 | struct i2c_client *client = to_i2c_client(dev); | ||
| 75 | unsigned char buf[8]; | ||
| 76 | |||
| 77 | struct i2c_msg msg = { | ||
| 78 | client->addr, 0, 8, buf, /* write time/date */ | ||
| 79 | }; | ||
| 80 | |||
| 81 | buf[0] = EM3027_REG_WATCH_SEC; | ||
| 82 | buf[1] = bin2bcd(tm->tm_sec); | ||
| 83 | buf[2] = bin2bcd(tm->tm_min); | ||
| 84 | buf[3] = bin2bcd(tm->tm_hour); | ||
| 85 | buf[4] = bin2bcd(tm->tm_mday); | ||
| 86 | buf[5] = bin2bcd(tm->tm_wday); | ||
| 87 | buf[6] = bin2bcd(tm->tm_mon); | ||
| 88 | buf[7] = bin2bcd(tm->tm_year % 100); | ||
| 89 | |||
| 90 | /* write time/date registers */ | ||
| 91 | if ((i2c_transfer(client->adapter, &msg, 1)) != 1) { | ||
| 92 | dev_err(&client->dev, "%s: write error\n", __func__); | ||
| 93 | return -EIO; | ||
| 94 | } | ||
| 95 | |||
| 96 | return 0; | ||
| 97 | } | ||
| 98 | |||
| 99 | static const struct rtc_class_ops em3027_rtc_ops = { | ||
| 100 | .read_time = em3027_get_time, | ||
| 101 | .set_time = em3027_set_time, | ||
| 102 | }; | ||
| 103 | |||
| 104 | static int em3027_probe(struct i2c_client *client, | ||
| 105 | const struct i2c_device_id *id) | ||
| 106 | { | ||
| 107 | struct rtc_device *rtc; | ||
| 108 | |||
| 109 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) | ||
| 110 | return -ENODEV; | ||
| 111 | |||
| 112 | rtc = rtc_device_register(em3027_driver.driver.name, &client->dev, | ||
| 113 | &em3027_rtc_ops, THIS_MODULE); | ||
| 114 | if (IS_ERR(rtc)) | ||
| 115 | return PTR_ERR(rtc); | ||
| 116 | |||
| 117 | i2c_set_clientdata(client, rtc); | ||
| 118 | |||
| 119 | return 0; | ||
| 120 | } | ||
| 121 | |||
| 122 | static int em3027_remove(struct i2c_client *client) | ||
| 123 | { | ||
| 124 | struct rtc_device *rtc = i2c_get_clientdata(client); | ||
| 125 | |||
| 126 | if (rtc) | ||
| 127 | rtc_device_unregister(rtc); | ||
| 128 | |||
| 129 | return 0; | ||
| 130 | } | ||
| 131 | |||
| 132 | static struct i2c_device_id em3027_id[] = { | ||
| 133 | { "em3027", 0 }, | ||
| 134 | { } | ||
| 135 | }; | ||
| 136 | |||
| 137 | static struct i2c_driver em3027_driver = { | ||
| 138 | .driver = { | ||
| 139 | .name = "rtc-em3027", | ||
| 140 | }, | ||
| 141 | .probe = &em3027_probe, | ||
| 142 | .remove = &em3027_remove, | ||
| 143 | .id_table = em3027_id, | ||
| 144 | }; | ||
| 145 | |||
| 146 | static int __init em3027_init(void) | ||
| 147 | { | ||
| 148 | return i2c_add_driver(&em3027_driver); | ||
| 149 | } | ||
| 150 | |||
| 151 | static void __exit em3027_exit(void) | ||
| 152 | { | ||
| 153 | i2c_del_driver(&em3027_driver); | ||
| 154 | } | ||
| 155 | |||
| 156 | MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>"); | ||
| 157 | MODULE_DESCRIPTION("EM Microelectronic EM3027 RTC driver"); | ||
| 158 | MODULE_LICENSE("GPL"); | ||
| 159 | |||
| 160 | module_init(em3027_init); | ||
| 161 | module_exit(em3027_exit); | ||
diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c index 11ae64dcbf3c..335551d333b2 100644 --- a/drivers/rtc/rtc-ep93xx.c +++ b/drivers/rtc/rtc-ep93xx.c | |||
| @@ -151,6 +151,7 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev) | |||
| 151 | return -ENXIO; | 151 | return -ENXIO; |
| 152 | 152 | ||
| 153 | pdev->dev.platform_data = ep93xx_rtc; | 153 | pdev->dev.platform_data = ep93xx_rtc; |
| 154 | platform_set_drvdata(pdev, rtc); | ||
| 154 | 155 | ||
| 155 | rtc = rtc_device_register(pdev->name, | 156 | rtc = rtc_device_register(pdev->name, |
| 156 | &pdev->dev, &ep93xx_rtc_ops, THIS_MODULE); | 157 | &pdev->dev, &ep93xx_rtc_ops, THIS_MODULE); |
| @@ -159,8 +160,6 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev) | |||
| 159 | goto exit; | 160 | goto exit; |
| 160 | } | 161 | } |
| 161 | 162 | ||
| 162 | platform_set_drvdata(pdev, rtc); | ||
| 163 | |||
| 164 | err = sysfs_create_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files); | 163 | err = sysfs_create_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files); |
| 165 | if (err) | 164 | if (err) |
| 166 | goto fail; | 165 | goto fail; |
| @@ -168,9 +167,9 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev) | |||
| 168 | return 0; | 167 | return 0; |
| 169 | 168 | ||
| 170 | fail: | 169 | fail: |
| 171 | platform_set_drvdata(pdev, NULL); | ||
| 172 | rtc_device_unregister(rtc); | 170 | rtc_device_unregister(rtc); |
| 173 | exit: | 171 | exit: |
| 172 | platform_set_drvdata(pdev, NULL); | ||
| 174 | pdev->dev.platform_data = NULL; | 173 | pdev->dev.platform_data = NULL; |
| 175 | return err; | 174 | return err; |
| 176 | } | 175 | } |
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 69fe664a2228..eda128fc1d38 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c | |||
| @@ -783,6 +783,9 @@ static int m41t80_probe(struct i2c_client *client, | |||
| 783 | goto exit; | 783 | goto exit; |
| 784 | } | 784 | } |
| 785 | 785 | ||
| 786 | clientdata->features = id->driver_data; | ||
| 787 | i2c_set_clientdata(client, clientdata); | ||
| 788 | |||
| 786 | rtc = rtc_device_register(client->name, &client->dev, | 789 | rtc = rtc_device_register(client->name, &client->dev, |
| 787 | &m41t80_rtc_ops, THIS_MODULE); | 790 | &m41t80_rtc_ops, THIS_MODULE); |
| 788 | if (IS_ERR(rtc)) { | 791 | if (IS_ERR(rtc)) { |
| @@ -792,8 +795,6 @@ static int m41t80_probe(struct i2c_client *client, | |||
| 792 | } | 795 | } |
| 793 | 796 | ||
| 794 | clientdata->rtc = rtc; | 797 | clientdata->rtc = rtc; |
| 795 | clientdata->features = id->driver_data; | ||
| 796 | i2c_set_clientdata(client, clientdata); | ||
| 797 | 798 | ||
| 798 | /* Make sure HT (Halt Update) bit is cleared */ | 799 | /* Make sure HT (Halt Update) bit is cleared */ |
| 799 | rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_HOUR); | 800 | rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_HOUR); |
diff --git a/drivers/rtc/rtc-m41t93.c b/drivers/rtc/rtc-m41t93.c new file mode 100644 index 000000000000..1a84b3e227d1 --- /dev/null +++ b/drivers/rtc/rtc-m41t93.c | |||
| @@ -0,0 +1,225 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * Driver for ST M41T93 SPI RTC | ||
| 4 | * | ||
| 5 | * (c) 2010 Nikolaus Voss, Weinmann Medical GmbH | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/bcd.h> | ||
| 13 | #include <linux/kernel.h> | ||
| 14 | #include <linux/module.h> | ||
| 15 | #include <linux/platform_device.h> | ||
| 16 | #include <linux/rtc.h> | ||
| 17 | #include <linux/spi/spi.h> | ||
| 18 | |||
| 19 | #define M41T93_REG_SSEC 0 | ||
| 20 | #define M41T93_REG_ST_SEC 1 | ||
| 21 | #define M41T93_REG_MIN 2 | ||
| 22 | #define M41T93_REG_CENT_HOUR 3 | ||
| 23 | #define M41T93_REG_WDAY 4 | ||
| 24 | #define M41T93_REG_DAY 5 | ||
| 25 | #define M41T93_REG_MON 6 | ||
| 26 | #define M41T93_REG_YEAR 7 | ||
| 27 | |||
| 28 | |||
| 29 | #define M41T93_REG_ALM_HOUR_HT 0xc | ||
| 30 | #define M41T93_REG_FLAGS 0xf | ||
| 31 | |||
| 32 | #define M41T93_FLAG_ST (1 << 7) | ||
| 33 | #define M41T93_FLAG_OF (1 << 2) | ||
| 34 | #define M41T93_FLAG_BL (1 << 4) | ||
| 35 | #define M41T93_FLAG_HT (1 << 6) | ||
| 36 | |||
| 37 | static inline int m41t93_set_reg(struct spi_device *spi, u8 addr, u8 data) | ||
| 38 | { | ||
| 39 | u8 buf[2]; | ||
| 40 | |||
| 41 | /* MSB must be '1' to write */ | ||
| 42 | buf[0] = addr | 0x80; | ||
| 43 | buf[1] = data; | ||
| 44 | |||
| 45 | return spi_write(spi, buf, sizeof(buf)); | ||
| 46 | } | ||
| 47 | |||
| 48 | static int m41t93_set_time(struct device *dev, struct rtc_time *tm) | ||
| 49 | { | ||
| 50 | struct spi_device *spi = to_spi_device(dev); | ||
| 51 | u8 buf[9] = {0x80}; /* write cmd + 8 data bytes */ | ||
| 52 | u8 * const data = &buf[1]; /* ptr to first data byte */ | ||
| 53 | |||
| 54 | dev_dbg(dev, "%s secs=%d, mins=%d, " | ||
| 55 | "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", | ||
| 56 | "write", tm->tm_sec, tm->tm_min, | ||
| 57 | tm->tm_hour, tm->tm_mday, | ||
| 58 | tm->tm_mon, tm->tm_year, tm->tm_wday); | ||
| 59 | |||
| 60 | if (tm->tm_year < 100) { | ||
| 61 | dev_warn(&spi->dev, "unsupported date (before 2000-01-01).\n"); | ||
| 62 | return -EINVAL; | ||
| 63 | } | ||
| 64 | |||
| 65 | data[M41T93_REG_SSEC] = 0; | ||
| 66 | data[M41T93_REG_ST_SEC] = bin2bcd(tm->tm_sec); | ||
| 67 | data[M41T93_REG_MIN] = bin2bcd(tm->tm_min); | ||
| 68 | data[M41T93_REG_CENT_HOUR] = bin2bcd(tm->tm_hour) | | ||
| 69 | ((tm->tm_year/100-1) << 6); | ||
| 70 | data[M41T93_REG_DAY] = bin2bcd(tm->tm_mday); | ||
| 71 | data[M41T93_REG_WDAY] = bin2bcd(tm->tm_wday + 1); | ||
| 72 | data[M41T93_REG_MON] = bin2bcd(tm->tm_mon + 1); | ||
| 73 | data[M41T93_REG_YEAR] = bin2bcd(tm->tm_year % 100); | ||
| 74 | |||
| 75 | return spi_write(spi, buf, sizeof(buf)); | ||
| 76 | } | ||
| 77 | |||
| 78 | |||
| 79 | static int m41t93_get_time(struct device *dev, struct rtc_time *tm) | ||
| 80 | { | ||
| 81 | struct spi_device *spi = to_spi_device(dev); | ||
| 82 | const u8 start_addr = 0; | ||
| 83 | u8 buf[8]; | ||
| 84 | int century_after_1900; | ||
| 85 | int tmp; | ||
| 86 | int ret = 0; | ||
| 87 | |||
| 88 | /* Check status of clock. Two states must be considered: | ||
| 89 | 1. halt bit (HT) is set: the clock is running but update of readout | ||
| 90 | registers has been disabled due to power failure. This is normal | ||
| 91 | case after poweron. Time is valid after resetting HT bit. | ||
| 92 | 2. oscillator fail bit (OF) is set. Oscillator has be stopped and | ||
| 93 | time is invalid: | ||
| 94 | a) OF can be immeditely reset. | ||
| 95 | b) OF cannot be immediately reset: oscillator has to be restarted. | ||
| 96 | */ | ||
| 97 | tmp = spi_w8r8(spi, M41T93_REG_ALM_HOUR_HT); | ||
| 98 | if (tmp < 0) | ||
| 99 | return tmp; | ||
| 100 | |||
| 101 | if (tmp & M41T93_FLAG_HT) { | ||
| 102 | dev_dbg(&spi->dev, "HT bit is set, reenable clock update.\n"); | ||
| 103 | m41t93_set_reg(spi, M41T93_REG_ALM_HOUR_HT, | ||
| 104 | tmp & ~M41T93_FLAG_HT); | ||
| 105 | } | ||
| 106 | |||
| 107 | tmp = spi_w8r8(spi, M41T93_REG_FLAGS); | ||
| 108 | if (tmp < 0) | ||
| 109 | return tmp; | ||
| 110 | |||
| 111 | if (tmp & M41T93_FLAG_OF) { | ||
| 112 | ret = -EINVAL; | ||
| 113 | dev_warn(&spi->dev, "OF bit is set, resetting.\n"); | ||
| 114 | m41t93_set_reg(spi, M41T93_REG_FLAGS, tmp & ~M41T93_FLAG_OF); | ||
| 115 | |||
| 116 | tmp = spi_w8r8(spi, M41T93_REG_FLAGS); | ||
| 117 | if (tmp < 0) | ||
| 118 | return tmp; | ||
| 119 | else if (tmp & M41T93_FLAG_OF) { | ||
| 120 | u8 reset_osc = buf[M41T93_REG_ST_SEC] | M41T93_FLAG_ST; | ||
| 121 | |||
| 122 | dev_warn(&spi->dev, | ||
| 123 | "OF bit is still set, kickstarting clock.\n"); | ||
| 124 | m41t93_set_reg(spi, M41T93_REG_ST_SEC, reset_osc); | ||
| 125 | reset_osc &= ~M41T93_FLAG_ST; | ||
| 126 | m41t93_set_reg(spi, M41T93_REG_ST_SEC, reset_osc); | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | if (tmp & M41T93_FLAG_BL) | ||
| 131 | dev_warn(&spi->dev, "BL bit is set, replace battery.\n"); | ||
| 132 | |||
| 133 | /* read actual time/date */ | ||
| 134 | tmp = spi_write_then_read(spi, &start_addr, 1, buf, sizeof(buf)); | ||
| 135 | if (tmp < 0) | ||
| 136 | return tmp; | ||
| 137 | |||
| 138 | tm->tm_sec = bcd2bin(buf[M41T93_REG_ST_SEC]); | ||
| 139 | tm->tm_min = bcd2bin(buf[M41T93_REG_MIN]); | ||
| 140 | tm->tm_hour = bcd2bin(buf[M41T93_REG_CENT_HOUR] & 0x3f); | ||
| 141 | tm->tm_mday = bcd2bin(buf[M41T93_REG_DAY]); | ||
| 142 | tm->tm_mon = bcd2bin(buf[M41T93_REG_MON]) - 1; | ||
| 143 | tm->tm_wday = bcd2bin(buf[M41T93_REG_WDAY] & 0x0f) - 1; | ||
| 144 | |||
| 145 | century_after_1900 = (buf[M41T93_REG_CENT_HOUR] >> 6) + 1; | ||
| 146 | tm->tm_year = bcd2bin(buf[M41T93_REG_YEAR]) + century_after_1900 * 100; | ||
| 147 | |||
| 148 | dev_dbg(dev, "%s secs=%d, mins=%d, " | ||
| 149 | "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", | ||
| 150 | "read", tm->tm_sec, tm->tm_min, | ||
| 151 | tm->tm_hour, tm->tm_mday, | ||
| 152 | tm->tm_mon, tm->tm_year, tm->tm_wday); | ||
| 153 | |||
| 154 | return ret < 0 ? ret : rtc_valid_tm(tm); | ||
| 155 | } | ||
| 156 | |||
| 157 | |||
| 158 | static const struct rtc_class_ops m41t93_rtc_ops = { | ||
| 159 | .read_time = m41t93_get_time, | ||
| 160 | .set_time = m41t93_set_time, | ||
| 161 | }; | ||
| 162 | |||
| 163 | static struct spi_driver m41t93_driver; | ||
| 164 | |||
| 165 | static int __devinit m41t93_probe(struct spi_device *spi) | ||
| 166 | { | ||
| 167 | struct rtc_device *rtc; | ||
| 168 | int res; | ||
| 169 | |||
| 170 | spi->bits_per_word = 8; | ||
| 171 | spi_setup(spi); | ||
| 172 | |||
| 173 | res = spi_w8r8(spi, M41T93_REG_WDAY); | ||
| 174 | if (res < 0 || (res & 0xf8) != 0) { | ||
| 175 | dev_err(&spi->dev, "not found 0x%x.\n", res); | ||
| 176 | return -ENODEV; | ||
| 177 | } | ||
| 178 | |||
| 179 | rtc = rtc_device_register(m41t93_driver.driver.name, | ||
| 180 | &spi->dev, &m41t93_rtc_ops, THIS_MODULE); | ||
| 181 | if (IS_ERR(rtc)) | ||
| 182 | return PTR_ERR(rtc); | ||
| 183 | |||
| 184 | dev_set_drvdata(&spi->dev, rtc); | ||
| 185 | |||
| 186 | return 0; | ||
| 187 | } | ||
| 188 | |||
| 189 | |||
| 190 | static int __devexit m41t93_remove(struct spi_device *spi) | ||
| 191 | { | ||
| 192 | struct rtc_device *rtc = platform_get_drvdata(spi); | ||
| 193 | |||
| 194 | if (rtc) | ||
| 195 | rtc_device_unregister(rtc); | ||
| 196 | |||
| 197 | return 0; | ||
| 198 | } | ||
| 199 | |||
| 200 | static struct spi_driver m41t93_driver = { | ||
| 201 | .driver = { | ||
| 202 | .name = "rtc-m41t93", | ||
| 203 | .bus = &spi_bus_type, | ||
| 204 | .owner = THIS_MODULE, | ||
| 205 | }, | ||
| 206 | .probe = m41t93_probe, | ||
| 207 | .remove = __devexit_p(m41t93_remove), | ||
| 208 | }; | ||
| 209 | |||
| 210 | static __init int m41t93_init(void) | ||
| 211 | { | ||
| 212 | return spi_register_driver(&m41t93_driver); | ||
| 213 | } | ||
| 214 | module_init(m41t93_init); | ||
| 215 | |||
| 216 | static __exit void m41t93_exit(void) | ||
| 217 | { | ||
| 218 | spi_unregister_driver(&m41t93_driver); | ||
| 219 | } | ||
| 220 | module_exit(m41t93_exit); | ||
| 221 | |||
| 222 | MODULE_AUTHOR("Nikolaus Voss <n.voss@weinmann.de>"); | ||
| 223 | MODULE_DESCRIPTION("Driver for ST M41T93 SPI RTC"); | ||
| 224 | MODULE_LICENSE("GPL"); | ||
| 225 | MODULE_ALIAS("spi:rtc-m41t93"); | ||
diff --git a/drivers/rtc/rtc-max8925.c b/drivers/rtc/rtc-max8925.c index 174036dda786..3bc046f427e0 100644 --- a/drivers/rtc/rtc-max8925.c +++ b/drivers/rtc/rtc-max8925.c | |||
| @@ -257,6 +257,10 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev) | |||
| 257 | goto out_irq; | 257 | goto out_irq; |
| 258 | } | 258 | } |
| 259 | 259 | ||
| 260 | dev_set_drvdata(&pdev->dev, info); | ||
| 261 | /* XXX - isn't this redundant? */ | ||
| 262 | platform_set_drvdata(pdev, info); | ||
| 263 | |||
| 260 | info->rtc_dev = rtc_device_register("max8925-rtc", &pdev->dev, | 264 | info->rtc_dev = rtc_device_register("max8925-rtc", &pdev->dev, |
| 261 | &max8925_rtc_ops, THIS_MODULE); | 265 | &max8925_rtc_ops, THIS_MODULE); |
| 262 | ret = PTR_ERR(info->rtc_dev); | 266 | ret = PTR_ERR(info->rtc_dev); |
| @@ -265,11 +269,9 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev) | |||
| 265 | goto out_rtc; | 269 | goto out_rtc; |
| 266 | } | 270 | } |
| 267 | 271 | ||
| 268 | dev_set_drvdata(&pdev->dev, info); | ||
| 269 | platform_set_drvdata(pdev, info); | ||
| 270 | |||
| 271 | return 0; | 272 | return 0; |
| 272 | out_rtc: | 273 | out_rtc: |
| 274 | platform_set_drvdata(pdev, NULL); | ||
| 273 | free_irq(chip->irq_base + MAX8925_IRQ_RTC_ALARM0, info); | 275 | free_irq(chip->irq_base + MAX8925_IRQ_RTC_ALARM0, info); |
| 274 | out_irq: | 276 | out_irq: |
| 275 | kfree(info); | 277 | kfree(info); |
diff --git a/drivers/rtc/rtc-max8998.c b/drivers/rtc/rtc-max8998.c index 3f7bc6b9fefa..2e48aa604273 100644 --- a/drivers/rtc/rtc-max8998.c +++ b/drivers/rtc/rtc-max8998.c | |||
| @@ -265,6 +265,8 @@ static int __devinit max8998_rtc_probe(struct platform_device *pdev) | |||
| 265 | info->rtc = max8998->rtc; | 265 | info->rtc = max8998->rtc; |
| 266 | info->irq = max8998->irq_base + MAX8998_IRQ_ALARM0; | 266 | info->irq = max8998->irq_base + MAX8998_IRQ_ALARM0; |
| 267 | 267 | ||
| 268 | platform_set_drvdata(pdev, info); | ||
| 269 | |||
| 268 | info->rtc_dev = rtc_device_register("max8998-rtc", &pdev->dev, | 270 | info->rtc_dev = rtc_device_register("max8998-rtc", &pdev->dev, |
| 269 | &max8998_rtc_ops, THIS_MODULE); | 271 | &max8998_rtc_ops, THIS_MODULE); |
| 270 | 272 | ||
| @@ -274,8 +276,6 @@ static int __devinit max8998_rtc_probe(struct platform_device *pdev) | |||
| 274 | goto out_rtc; | 276 | goto out_rtc; |
| 275 | } | 277 | } |
| 276 | 278 | ||
| 277 | platform_set_drvdata(pdev, info); | ||
| 278 | |||
| 279 | ret = request_threaded_irq(info->irq, NULL, max8998_rtc_alarm_irq, 0, | 279 | ret = request_threaded_irq(info->irq, NULL, max8998_rtc_alarm_irq, 0, |
| 280 | "rtc-alarm0", info); | 280 | "rtc-alarm0", info); |
| 281 | 281 | ||
| @@ -293,6 +293,7 @@ static int __devinit max8998_rtc_probe(struct platform_device *pdev) | |||
| 293 | return 0; | 293 | return 0; |
| 294 | 294 | ||
| 295 | out_rtc: | 295 | out_rtc: |
| 296 | platform_set_drvdata(pdev, NULL); | ||
| 296 | kfree(info); | 297 | kfree(info); |
| 297 | return ret; | 298 | return ret; |
| 298 | } | 299 | } |
diff --git a/drivers/rtc/rtc-mc13xxx.c b/drivers/rtc/rtc-mc13xxx.c index c42006469559..a1a278bc340d 100644 --- a/drivers/rtc/rtc-mc13xxx.c +++ b/drivers/rtc/rtc-mc13xxx.c | |||
| @@ -349,11 +349,15 @@ static int __devinit mc13xxx_rtc_probe(struct platform_device *pdev) | |||
| 349 | if (ret) | 349 | if (ret) |
| 350 | goto err_alarm_irq_request; | 350 | goto err_alarm_irq_request; |
| 351 | 351 | ||
| 352 | mc13xxx_unlock(mc13xxx); | ||
| 353 | |||
| 352 | priv->rtc = rtc_device_register(pdev->name, | 354 | priv->rtc = rtc_device_register(pdev->name, |
| 353 | &pdev->dev, &mc13xxx_rtc_ops, THIS_MODULE); | 355 | &pdev->dev, &mc13xxx_rtc_ops, THIS_MODULE); |
| 354 | if (IS_ERR(priv->rtc)) { | 356 | if (IS_ERR(priv->rtc)) { |
| 355 | ret = PTR_ERR(priv->rtc); | 357 | ret = PTR_ERR(priv->rtc); |
| 356 | 358 | ||
| 359 | mc13xxx_lock(mc13xxx); | ||
| 360 | |||
| 357 | mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_TODA, priv); | 361 | mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_TODA, priv); |
| 358 | err_alarm_irq_request: | 362 | err_alarm_irq_request: |
| 359 | 363 | ||
| @@ -365,12 +369,12 @@ err_reset_irq_status: | |||
| 365 | mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_RTCRST, priv); | 369 | mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_RTCRST, priv); |
| 366 | err_reset_irq_request: | 370 | err_reset_irq_request: |
| 367 | 371 | ||
| 372 | mc13xxx_unlock(mc13xxx); | ||
| 373 | |||
| 368 | platform_set_drvdata(pdev, NULL); | 374 | platform_set_drvdata(pdev, NULL); |
| 369 | kfree(priv); | 375 | kfree(priv); |
| 370 | } | 376 | } |
| 371 | 377 | ||
| 372 | mc13xxx_unlock(mc13xxx); | ||
| 373 | |||
| 374 | return ret; | 378 | return ret; |
| 375 | } | 379 | } |
| 376 | 380 | ||
| @@ -401,6 +405,7 @@ const struct platform_device_id mc13xxx_rtc_idtable[] = { | |||
| 401 | }, { | 405 | }, { |
| 402 | .name = "mc13892-rtc", | 406 | .name = "mc13892-rtc", |
| 403 | }, | 407 | }, |
| 408 | { } | ||
| 404 | }; | 409 | }; |
| 405 | 410 | ||
| 406 | static struct platform_driver mc13xxx_rtc_driver = { | 411 | static struct platform_driver mc13xxx_rtc_driver = { |
diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c index b2f096871a97..0cec5650d56a 100644 --- a/drivers/rtc/rtc-mrst.c +++ b/drivers/rtc/rtc-mrst.c | |||
| @@ -380,7 +380,7 @@ cleanup1: | |||
| 380 | cleanup0: | 380 | cleanup0: |
| 381 | dev_set_drvdata(dev, NULL); | 381 | dev_set_drvdata(dev, NULL); |
| 382 | mrst_rtc.dev = NULL; | 382 | mrst_rtc.dev = NULL; |
| 383 | release_region(iomem->start, iomem->end + 1 - iomem->start); | 383 | release_mem_region(iomem->start, resource_size(iomem)); |
| 384 | dev_err(dev, "rtc-mrst: unable to initialise\n"); | 384 | dev_err(dev, "rtc-mrst: unable to initialise\n"); |
| 385 | return retval; | 385 | return retval; |
| 386 | } | 386 | } |
| @@ -406,7 +406,7 @@ static void __devexit rtc_mrst_do_remove(struct device *dev) | |||
| 406 | mrst->rtc = NULL; | 406 | mrst->rtc = NULL; |
| 407 | 407 | ||
| 408 | iomem = mrst->iomem; | 408 | iomem = mrst->iomem; |
| 409 | release_region(iomem->start, iomem->end + 1 - iomem->start); | 409 | release_mem_region(iomem->start, resource_size(iomem)); |
| 410 | mrst->iomem = NULL; | 410 | mrst->iomem = NULL; |
| 411 | 411 | ||
| 412 | mrst->dev = NULL; | 412 | mrst->dev = NULL; |
diff --git a/drivers/rtc/rtc-msm6242.c b/drivers/rtc/rtc-msm6242.c index 67820626e18f..fcb113c11122 100644 --- a/drivers/rtc/rtc-msm6242.c +++ b/drivers/rtc/rtc-msm6242.c | |||
| @@ -214,6 +214,7 @@ static int __init msm6242_rtc_probe(struct platform_device *dev) | |||
| 214 | error = -ENOMEM; | 214 | error = -ENOMEM; |
| 215 | goto out_free_priv; | 215 | goto out_free_priv; |
| 216 | } | 216 | } |
| 217 | platform_set_drvdata(dev, priv); | ||
| 217 | 218 | ||
| 218 | rtc = rtc_device_register("rtc-msm6242", &dev->dev, &msm6242_rtc_ops, | 219 | rtc = rtc_device_register("rtc-msm6242", &dev->dev, &msm6242_rtc_ops, |
| 219 | THIS_MODULE); | 220 | THIS_MODULE); |
| @@ -223,10 +224,10 @@ static int __init msm6242_rtc_probe(struct platform_device *dev) | |||
| 223 | } | 224 | } |
| 224 | 225 | ||
| 225 | priv->rtc = rtc; | 226 | priv->rtc = rtc; |
| 226 | platform_set_drvdata(dev, priv); | ||
| 227 | return 0; | 227 | return 0; |
| 228 | 228 | ||
| 229 | out_unmap: | 229 | out_unmap: |
| 230 | platform_set_drvdata(dev, NULL); | ||
| 230 | iounmap(priv->regs); | 231 | iounmap(priv->regs); |
| 231 | out_free_priv: | 232 | out_free_priv: |
| 232 | kfree(priv); | 233 | kfree(priv); |
diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index 826ab64a8fa9..39e41fbdf08b 100644 --- a/drivers/rtc/rtc-mxc.c +++ b/drivers/rtc/rtc-mxc.c | |||
| @@ -55,12 +55,6 @@ static const u32 PIE_BIT_DEF[MAX_PIE_NUM][2] = { | |||
| 55 | { MAX_PIE_FREQ, RTC_SAM7_BIT }, | 55 | { MAX_PIE_FREQ, RTC_SAM7_BIT }, |
| 56 | }; | 56 | }; |
| 57 | 57 | ||
| 58 | /* Those are the bits from a classic RTC we want to mimic */ | ||
| 59 | #define RTC_IRQF 0x80 /* any of the following 3 is active */ | ||
| 60 | #define RTC_PF 0x40 /* Periodic interrupt */ | ||
| 61 | #define RTC_AF 0x20 /* Alarm interrupt */ | ||
| 62 | #define RTC_UF 0x10 /* Update interrupt for 1Hz RTC */ | ||
| 63 | |||
| 64 | #define MXC_RTC_TIME 0 | 58 | #define MXC_RTC_TIME 0 |
| 65 | #define MXC_RTC_ALARM 1 | 59 | #define MXC_RTC_ALARM 1 |
| 66 | 60 | ||
| @@ -418,14 +412,6 @@ static int __init mxc_rtc_probe(struct platform_device *pdev) | |||
| 418 | goto exit_put_clk; | 412 | goto exit_put_clk; |
| 419 | } | 413 | } |
| 420 | 414 | ||
| 421 | rtc = rtc_device_register(pdev->name, &pdev->dev, &mxc_rtc_ops, | ||
| 422 | THIS_MODULE); | ||
| 423 | if (IS_ERR(rtc)) { | ||
| 424 | ret = PTR_ERR(rtc); | ||
| 425 | goto exit_put_clk; | ||
| 426 | } | ||
| 427 | |||
| 428 | pdata->rtc = rtc; | ||
| 429 | platform_set_drvdata(pdev, pdata); | 415 | platform_set_drvdata(pdev, pdata); |
| 430 | 416 | ||
| 431 | /* Configure and enable the RTC */ | 417 | /* Configure and enable the RTC */ |
| @@ -438,8 +424,19 @@ static int __init mxc_rtc_probe(struct platform_device *pdev) | |||
| 438 | pdata->irq = -1; | 424 | pdata->irq = -1; |
| 439 | } | 425 | } |
| 440 | 426 | ||
| 427 | rtc = rtc_device_register(pdev->name, &pdev->dev, &mxc_rtc_ops, | ||
| 428 | THIS_MODULE); | ||
| 429 | if (IS_ERR(rtc)) { | ||
| 430 | ret = PTR_ERR(rtc); | ||
| 431 | goto exit_clr_drvdata; | ||
| 432 | } | ||
| 433 | |||
| 434 | pdata->rtc = rtc; | ||
| 435 | |||
| 441 | return 0; | 436 | return 0; |
| 442 | 437 | ||
| 438 | exit_clr_drvdata: | ||
| 439 | platform_set_drvdata(pdev, NULL); | ||
| 443 | exit_put_clk: | 440 | exit_put_clk: |
| 444 | clk_disable(pdata->clk); | 441 | clk_disable(pdata->clk); |
| 445 | clk_put(pdata->clk); | 442 | clk_put(pdata->clk); |
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index de0dd7b1f146..bcae8dd41496 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c | |||
| @@ -394,7 +394,7 @@ static int __init omap_rtc_probe(struct platform_device *pdev) | |||
| 394 | return 0; | 394 | return 0; |
| 395 | 395 | ||
| 396 | fail2: | 396 | fail2: |
| 397 | free_irq(omap_rtc_timer, NULL); | 397 | free_irq(omap_rtc_timer, rtc); |
| 398 | fail1: | 398 | fail1: |
| 399 | rtc_device_unregister(rtc); | 399 | rtc_device_unregister(rtc); |
| 400 | fail0: | 400 | fail0: |
diff --git a/drivers/rtc/rtc-pcap.c b/drivers/rtc/rtc-pcap.c index a633abc42896..cd4f198cc2ef 100644 --- a/drivers/rtc/rtc-pcap.c +++ b/drivers/rtc/rtc-pcap.c | |||
| @@ -151,6 +151,8 @@ static int __devinit pcap_rtc_probe(struct platform_device *pdev) | |||
| 151 | 151 | ||
| 152 | pcap_rtc->pcap = dev_get_drvdata(pdev->dev.parent); | 152 | pcap_rtc->pcap = dev_get_drvdata(pdev->dev.parent); |
| 153 | 153 | ||
| 154 | platform_set_drvdata(pdev, pcap_rtc); | ||
| 155 | |||
| 154 | pcap_rtc->rtc = rtc_device_register("pcap", &pdev->dev, | 156 | pcap_rtc->rtc = rtc_device_register("pcap", &pdev->dev, |
| 155 | &pcap_rtc_ops, THIS_MODULE); | 157 | &pcap_rtc_ops, THIS_MODULE); |
| 156 | if (IS_ERR(pcap_rtc->rtc)) { | 158 | if (IS_ERR(pcap_rtc->rtc)) { |
| @@ -158,7 +160,6 @@ static int __devinit pcap_rtc_probe(struct platform_device *pdev) | |||
| 158 | goto fail_rtc; | 160 | goto fail_rtc; |
| 159 | } | 161 | } |
| 160 | 162 | ||
| 161 | platform_set_drvdata(pdev, pcap_rtc); | ||
| 162 | 163 | ||
| 163 | timer_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_1HZ); | 164 | timer_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_1HZ); |
| 164 | alarm_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_TODA); | 165 | alarm_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_TODA); |
| @@ -177,6 +178,7 @@ fail_alarm: | |||
| 177 | fail_timer: | 178 | fail_timer: |
| 178 | rtc_device_unregister(pcap_rtc->rtc); | 179 | rtc_device_unregister(pcap_rtc->rtc); |
| 179 | fail_rtc: | 180 | fail_rtc: |
| 181 | platform_set_drvdata(pdev, NULL); | ||
| 180 | kfree(pcap_rtc); | 182 | kfree(pcap_rtc); |
| 181 | return err; | 183 | return err; |
| 182 | } | 184 | } |
diff --git a/drivers/rtc/rtc-pcf50633.c b/drivers/rtc/rtc-pcf50633.c index f90c574f9d05..0c423892923c 100644 --- a/drivers/rtc/rtc-pcf50633.c +++ b/drivers/rtc/rtc-pcf50633.c | |||
| @@ -58,7 +58,6 @@ struct pcf50633_time { | |||
| 58 | 58 | ||
| 59 | struct pcf50633_rtc { | 59 | struct pcf50633_rtc { |
| 60 | int alarm_enabled; | 60 | int alarm_enabled; |
| 61 | int second_enabled; | ||
| 62 | int alarm_pending; | 61 | int alarm_pending; |
| 63 | 62 | ||
| 64 | struct pcf50633 *pcf; | 63 | struct pcf50633 *pcf; |
| @@ -143,7 +142,7 @@ static int pcf50633_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
| 143 | { | 142 | { |
| 144 | struct pcf50633_rtc *rtc; | 143 | struct pcf50633_rtc *rtc; |
| 145 | struct pcf50633_time pcf_tm; | 144 | struct pcf50633_time pcf_tm; |
| 146 | int second_masked, alarm_masked, ret = 0; | 145 | int alarm_masked, ret = 0; |
| 147 | 146 | ||
| 148 | rtc = dev_get_drvdata(dev); | 147 | rtc = dev_get_drvdata(dev); |
| 149 | 148 | ||
| @@ -162,11 +161,8 @@ static int pcf50633_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
| 162 | pcf_tm.time[PCF50633_TI_SEC]); | 161 | pcf_tm.time[PCF50633_TI_SEC]); |
| 163 | 162 | ||
| 164 | 163 | ||
| 165 | second_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_SECOND); | ||
| 166 | alarm_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_ALARM); | 164 | alarm_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_ALARM); |
| 167 | 165 | ||
| 168 | if (!second_masked) | ||
| 169 | pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_SECOND); | ||
| 170 | if (!alarm_masked) | 166 | if (!alarm_masked) |
| 171 | pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM); | 167 | pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM); |
| 172 | 168 | ||
| @@ -175,8 +171,6 @@ static int pcf50633_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
| 175 | PCF50633_TI_EXTENT, | 171 | PCF50633_TI_EXTENT, |
| 176 | &pcf_tm.time[0]); | 172 | &pcf_tm.time[0]); |
| 177 | 173 | ||
| 178 | if (!second_masked) | ||
| 179 | pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_SECOND); | ||
| 180 | if (!alarm_masked) | 174 | if (!alarm_masked) |
| 181 | pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM); | 175 | pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM); |
| 182 | 176 | ||
| @@ -250,15 +244,8 @@ static void pcf50633_rtc_irq(int irq, void *data) | |||
| 250 | { | 244 | { |
| 251 | struct pcf50633_rtc *rtc = data; | 245 | struct pcf50633_rtc *rtc = data; |
| 252 | 246 | ||
| 253 | switch (irq) { | 247 | rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); |
| 254 | case PCF50633_IRQ_ALARM: | 248 | rtc->alarm_pending = 1; |
| 255 | rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); | ||
| 256 | rtc->alarm_pending = 1; | ||
| 257 | break; | ||
| 258 | case PCF50633_IRQ_SECOND: | ||
| 259 | rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF); | ||
| 260 | break; | ||
| 261 | } | ||
| 262 | } | 249 | } |
| 263 | 250 | ||
| 264 | static int __devinit pcf50633_rtc_probe(struct platform_device *pdev) | 251 | static int __devinit pcf50633_rtc_probe(struct platform_device *pdev) |
| @@ -282,9 +269,6 @@ static int __devinit pcf50633_rtc_probe(struct platform_device *pdev) | |||
| 282 | 269 | ||
| 283 | pcf50633_register_irq(rtc->pcf, PCF50633_IRQ_ALARM, | 270 | pcf50633_register_irq(rtc->pcf, PCF50633_IRQ_ALARM, |
| 284 | pcf50633_rtc_irq, rtc); | 271 | pcf50633_rtc_irq, rtc); |
| 285 | pcf50633_register_irq(rtc->pcf, PCF50633_IRQ_SECOND, | ||
| 286 | pcf50633_rtc_irq, rtc); | ||
| 287 | |||
| 288 | return 0; | 272 | return 0; |
| 289 | } | 273 | } |
| 290 | 274 | ||
| @@ -295,7 +279,6 @@ static int __devexit pcf50633_rtc_remove(struct platform_device *pdev) | |||
| 295 | rtc = platform_get_drvdata(pdev); | 279 | rtc = platform_get_drvdata(pdev); |
| 296 | 280 | ||
| 297 | pcf50633_free_irq(rtc->pcf, PCF50633_IRQ_ALARM); | 281 | pcf50633_free_irq(rtc->pcf, PCF50633_IRQ_ALARM); |
| 298 | pcf50633_free_irq(rtc->pcf, PCF50633_IRQ_SECOND); | ||
| 299 | 282 | ||
| 300 | rtc_device_unregister(rtc->rtc_dev); | 283 | rtc_device_unregister(rtc->rtc_dev); |
| 301 | kfree(rtc); | 284 | kfree(rtc); |
diff --git a/drivers/rtc/rtc-rp5c01.c b/drivers/rtc/rtc-rp5c01.c index 694da39b6dd2..359da6d020b9 100644 --- a/drivers/rtc/rtc-rp5c01.c +++ b/drivers/rtc/rtc-rp5c01.c | |||
| @@ -249,15 +249,15 @@ static int __init rp5c01_rtc_probe(struct platform_device *dev) | |||
| 249 | 249 | ||
| 250 | spin_lock_init(&priv->lock); | 250 | spin_lock_init(&priv->lock); |
| 251 | 251 | ||
| 252 | platform_set_drvdata(dev, priv); | ||
| 253 | |||
| 252 | rtc = rtc_device_register("rtc-rp5c01", &dev->dev, &rp5c01_rtc_ops, | 254 | rtc = rtc_device_register("rtc-rp5c01", &dev->dev, &rp5c01_rtc_ops, |
| 253 | THIS_MODULE); | 255 | THIS_MODULE); |
| 254 | if (IS_ERR(rtc)) { | 256 | if (IS_ERR(rtc)) { |
| 255 | error = PTR_ERR(rtc); | 257 | error = PTR_ERR(rtc); |
| 256 | goto out_unmap; | 258 | goto out_unmap; |
| 257 | } | 259 | } |
| 258 | |||
| 259 | priv->rtc = rtc; | 260 | priv->rtc = rtc; |
| 260 | platform_set_drvdata(dev, priv); | ||
| 261 | 261 | ||
| 262 | error = sysfs_create_bin_file(&dev->dev.kobj, &priv->nvram_attr); | 262 | error = sysfs_create_bin_file(&dev->dev.kobj, &priv->nvram_attr); |
| 263 | if (error) | 263 | if (error) |
| @@ -268,6 +268,7 @@ static int __init rp5c01_rtc_probe(struct platform_device *dev) | |||
| 268 | out_unregister: | 268 | out_unregister: |
| 269 | rtc_device_unregister(rtc); | 269 | rtc_device_unregister(rtc); |
| 270 | out_unmap: | 270 | out_unmap: |
| 271 | platform_set_drvdata(dev, NULL); | ||
| 271 | iounmap(priv->regs); | 272 | iounmap(priv->regs); |
| 272 | out_free_priv: | 273 | out_free_priv: |
| 273 | kfree(priv); | 274 | kfree(priv); |
diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c new file mode 100644 index 000000000000..ea09ff211dc6 --- /dev/null +++ b/drivers/rtc/rtc-rv3029c2.c | |||
| @@ -0,0 +1,454 @@ | |||
| 1 | /* | ||
| 2 | * Micro Crystal RV-3029C2 rtc class driver | ||
| 3 | * | ||
| 4 | * Author: Gregory Hermant <gregory.hermant@calao-systems.com> | ||
| 5 | * | ||
| 6 | * based on previously existing rtc class drivers | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | * | ||
| 12 | * NOTE: Currently this driver only supports the bare minimum for read | ||
| 13 | * and write the RTC and alarms. The extra features provided by this chip | ||
| 14 | * (trickle charger, eeprom, T° compensation) are unavailable. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/i2c.h> | ||
| 19 | #include <linux/bcd.h> | ||
| 20 | #include <linux/rtc.h> | ||
| 21 | |||
| 22 | /* Register map */ | ||
| 23 | /* control section */ | ||
| 24 | #define RV3029C2_ONOFF_CTRL 0x00 | ||
| 25 | #define RV3029C2_IRQ_CTRL 0x01 | ||
| 26 | #define RV3029C2_IRQ_CTRL_AIE (1 << 0) | ||
| 27 | #define RV3029C2_IRQ_FLAGS 0x02 | ||
| 28 | #define RV3029C2_IRQ_FLAGS_AF (1 << 0) | ||
| 29 | #define RV3029C2_STATUS 0x03 | ||
| 30 | #define RV3029C2_STATUS_VLOW1 (1 << 2) | ||
| 31 | #define RV3029C2_STATUS_VLOW2 (1 << 3) | ||
| 32 | #define RV3029C2_STATUS_SR (1 << 4) | ||
| 33 | #define RV3029C2_STATUS_PON (1 << 5) | ||
| 34 | #define RV3029C2_STATUS_EEBUSY (1 << 7) | ||
| 35 | #define RV3029C2_RST_CTRL 0x04 | ||
| 36 | #define RV3029C2_CONTROL_SECTION_LEN 0x05 | ||
| 37 | |||
| 38 | /* watch section */ | ||
| 39 | #define RV3029C2_W_SEC 0x08 | ||
| 40 | #define RV3029C2_W_MINUTES 0x09 | ||
| 41 | #define RV3029C2_W_HOURS 0x0A | ||
| 42 | #define RV3029C2_REG_HR_12_24 (1<<6) /* 24h/12h mode */ | ||
| 43 | #define RV3029C2_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */ | ||
| 44 | #define RV3029C2_W_DATE 0x0B | ||
| 45 | #define RV3029C2_W_DAYS 0x0C | ||
| 46 | #define RV3029C2_W_MONTHS 0x0D | ||
| 47 | #define RV3029C2_W_YEARS 0x0E | ||
| 48 | #define RV3029C2_WATCH_SECTION_LEN 0x07 | ||
| 49 | |||
| 50 | /* alarm section */ | ||
| 51 | #define RV3029C2_A_SC 0x10 | ||
| 52 | #define RV3029C2_A_MN 0x11 | ||
| 53 | #define RV3029C2_A_HR 0x12 | ||
| 54 | #define RV3029C2_A_DT 0x13 | ||
| 55 | #define RV3029C2_A_DW 0x14 | ||
| 56 | #define RV3029C2_A_MO 0x15 | ||
| 57 | #define RV3029C2_A_YR 0x16 | ||
| 58 | #define RV3029C2_ALARM_SECTION_LEN 0x07 | ||
| 59 | |||
| 60 | /* timer section */ | ||
| 61 | #define RV3029C2_TIMER_LOW 0x18 | ||
| 62 | #define RV3029C2_TIMER_HIGH 0x19 | ||
| 63 | |||
| 64 | /* temperature section */ | ||
| 65 | #define RV3029C2_TEMP_PAGE 0x20 | ||
| 66 | |||
| 67 | /* eeprom data section */ | ||
| 68 | #define RV3029C2_E2P_EEDATA1 0x28 | ||
| 69 | #define RV3029C2_E2P_EEDATA2 0x29 | ||
| 70 | |||
| 71 | /* eeprom control section */ | ||
| 72 | #define RV3029C2_CONTROL_E2P_EECTRL 0x30 | ||
| 73 | #define RV3029C2_TRICKLE_1K (1<<0) /* 1K resistance */ | ||
| 74 | #define RV3029C2_TRICKLE_5K (1<<1) /* 5K resistance */ | ||
| 75 | #define RV3029C2_TRICKLE_20K (1<<2) /* 20K resistance */ | ||
| 76 | #define RV3029C2_TRICKLE_80K (1<<3) /* 80K resistance */ | ||
| 77 | #define RV3029C2_CONTROL_E2P_XTALOFFSET 0x31 | ||
| 78 | #define RV3029C2_CONTROL_E2P_QCOEF 0x32 | ||
| 79 | #define RV3029C2_CONTROL_E2P_TURNOVER 0x33 | ||
| 80 | |||
| 81 | /* user ram section */ | ||
| 82 | #define RV3029C2_USR1_RAM_PAGE 0x38 | ||
| 83 | #define RV3029C2_USR1_SECTION_LEN 0x04 | ||
| 84 | #define RV3029C2_USR2_RAM_PAGE 0x3C | ||
| 85 | #define RV3029C2_USR2_SECTION_LEN 0x04 | ||
| 86 | |||
| 87 | static int | ||
| 88 | rv3029c2_i2c_read_regs(struct i2c_client *client, u8 reg, u8 *buf, | ||
| 89 | unsigned len) | ||
| 90 | { | ||
| 91 | int ret; | ||
| 92 | |||
| 93 | if ((reg > RV3029C2_USR1_RAM_PAGE + 7) || | ||
| 94 | (reg + len > RV3029C2_USR1_RAM_PAGE + 8)) | ||
| 95 | return -EINVAL; | ||
| 96 | |||
| 97 | ret = i2c_smbus_read_i2c_block_data(client, reg, len, buf); | ||
| 98 | if (ret < 0) | ||
| 99 | return ret; | ||
| 100 | if (ret < len) | ||
| 101 | return -EIO; | ||
| 102 | return 0; | ||
| 103 | } | ||
| 104 | |||
| 105 | static int | ||
| 106 | rv3029c2_i2c_write_regs(struct i2c_client *client, u8 reg, u8 const buf[], | ||
| 107 | unsigned len) | ||
| 108 | { | ||
| 109 | if ((reg > RV3029C2_USR1_RAM_PAGE + 7) || | ||
| 110 | (reg + len > RV3029C2_USR1_RAM_PAGE + 8)) | ||
| 111 | return -EINVAL; | ||
| 112 | |||
| 113 | return i2c_smbus_write_i2c_block_data(client, reg, len, buf); | ||
| 114 | } | ||
| 115 | |||
| 116 | static int | ||
| 117 | rv3029c2_i2c_get_sr(struct i2c_client *client, u8 *buf) | ||
| 118 | { | ||
| 119 | int ret = rv3029c2_i2c_read_regs(client, RV3029C2_STATUS, buf, 1); | ||
| 120 | |||
| 121 | if (ret < 0) | ||
| 122 | return -EIO; | ||
| 123 | dev_dbg(&client->dev, "status = 0x%.2x (%d)\n", buf[0], buf[0]); | ||
| 124 | return 0; | ||
| 125 | } | ||
| 126 | |||
| 127 | static int | ||
| 128 | rv3029c2_i2c_set_sr(struct i2c_client *client, u8 val) | ||
| 129 | { | ||
| 130 | u8 buf[1]; | ||
| 131 | int sr; | ||
| 132 | |||
| 133 | buf[0] = val; | ||
| 134 | sr = rv3029c2_i2c_write_regs(client, RV3029C2_STATUS, buf, 1); | ||
| 135 | dev_dbg(&client->dev, "status = 0x%.2x (%d)\n", buf[0], buf[0]); | ||
| 136 | if (sr < 0) | ||
| 137 | return -EIO; | ||
| 138 | return 0; | ||
| 139 | } | ||
| 140 | |||
| 141 | static int | ||
| 142 | rv3029c2_i2c_read_time(struct i2c_client *client, struct rtc_time *tm) | ||
| 143 | { | ||
| 144 | u8 buf[1]; | ||
| 145 | int ret; | ||
| 146 | u8 regs[RV3029C2_WATCH_SECTION_LEN] = { 0, }; | ||
| 147 | |||
| 148 | ret = rv3029c2_i2c_get_sr(client, buf); | ||
| 149 | if (ret < 0) { | ||
| 150 | dev_err(&client->dev, "%s: reading SR failed\n", __func__); | ||
| 151 | return -EIO; | ||
| 152 | } | ||
| 153 | |||
| 154 | ret = rv3029c2_i2c_read_regs(client, RV3029C2_W_SEC , regs, | ||
| 155 | RV3029C2_WATCH_SECTION_LEN); | ||
| 156 | if (ret < 0) { | ||
| 157 | dev_err(&client->dev, "%s: reading RTC section failed\n", | ||
| 158 | __func__); | ||
| 159 | return ret; | ||
| 160 | } | ||
| 161 | |||
| 162 | tm->tm_sec = bcd2bin(regs[RV3029C2_W_SEC-RV3029C2_W_SEC]); | ||
| 163 | tm->tm_min = bcd2bin(regs[RV3029C2_W_MINUTES-RV3029C2_W_SEC]); | ||
| 164 | |||
| 165 | /* HR field has a more complex interpretation */ | ||
| 166 | { | ||
| 167 | const u8 _hr = regs[RV3029C2_W_HOURS-RV3029C2_W_SEC]; | ||
| 168 | if (_hr & RV3029C2_REG_HR_12_24) { | ||
| 169 | /* 12h format */ | ||
| 170 | tm->tm_hour = bcd2bin(_hr & 0x1f); | ||
| 171 | if (_hr & RV3029C2_REG_HR_PM) /* PM flag set */ | ||
| 172 | tm->tm_hour += 12; | ||
| 173 | } else /* 24h format */ | ||
| 174 | tm->tm_hour = bcd2bin(_hr & 0x3f); | ||
| 175 | } | ||
| 176 | |||
| 177 | tm->tm_mday = bcd2bin(regs[RV3029C2_W_DATE-RV3029C2_W_SEC]); | ||
| 178 | tm->tm_mon = bcd2bin(regs[RV3029C2_W_MONTHS-RV3029C2_W_SEC]) - 1; | ||
| 179 | tm->tm_year = bcd2bin(regs[RV3029C2_W_YEARS-RV3029C2_W_SEC]) + 100; | ||
| 180 | tm->tm_wday = bcd2bin(regs[RV3029C2_W_DAYS-RV3029C2_W_SEC]) - 1; | ||
| 181 | |||
| 182 | return 0; | ||
| 183 | } | ||
| 184 | |||
| 185 | static int rv3029c2_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
| 186 | { | ||
| 187 | return rv3029c2_i2c_read_time(to_i2c_client(dev), tm); | ||
| 188 | } | ||
| 189 | |||
| 190 | static int | ||
| 191 | rv3029c2_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm) | ||
| 192 | { | ||
| 193 | struct rtc_time *const tm = &alarm->time; | ||
| 194 | int ret; | ||
| 195 | u8 regs[8]; | ||
| 196 | |||
| 197 | ret = rv3029c2_i2c_get_sr(client, regs); | ||
| 198 | if (ret < 0) { | ||
| 199 | dev_err(&client->dev, "%s: reading SR failed\n", __func__); | ||
| 200 | return -EIO; | ||
| 201 | } | ||
| 202 | |||
| 203 | ret = rv3029c2_i2c_read_regs(client, RV3029C2_A_SC, regs, | ||
| 204 | RV3029C2_ALARM_SECTION_LEN); | ||
| 205 | |||
| 206 | if (ret < 0) { | ||
| 207 | dev_err(&client->dev, "%s: reading alarm section failed\n", | ||
| 208 | __func__); | ||
| 209 | return ret; | ||
| 210 | } | ||
| 211 | |||
| 212 | tm->tm_sec = bcd2bin(regs[RV3029C2_A_SC-RV3029C2_A_SC] & 0x7f); | ||
| 213 | tm->tm_min = bcd2bin(regs[RV3029C2_A_MN-RV3029C2_A_SC] & 0x7f); | ||
| 214 | tm->tm_hour = bcd2bin(regs[RV3029C2_A_HR-RV3029C2_A_SC] & 0x3f); | ||
| 215 | tm->tm_mday = bcd2bin(regs[RV3029C2_A_DT-RV3029C2_A_SC] & 0x3f); | ||
| 216 | tm->tm_mon = bcd2bin(regs[RV3029C2_A_MO-RV3029C2_A_SC] & 0x1f) - 1; | ||
| 217 | tm->tm_year = bcd2bin(regs[RV3029C2_A_YR-RV3029C2_A_SC] & 0x7f) + 100; | ||
| 218 | tm->tm_wday = bcd2bin(regs[RV3029C2_A_DW-RV3029C2_A_SC] & 0x07) - 1; | ||
| 219 | |||
| 220 | return 0; | ||
| 221 | } | ||
| 222 | |||
| 223 | static int | ||
| 224 | rv3029c2_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) | ||
| 225 | { | ||
| 226 | return rv3029c2_i2c_read_alarm(to_i2c_client(dev), alarm); | ||
| 227 | } | ||
| 228 | |||
| 229 | static int rv3029c2_rtc_i2c_alarm_set_irq(struct i2c_client *client, | ||
| 230 | int enable) | ||
| 231 | { | ||
| 232 | int ret; | ||
| 233 | u8 buf[1]; | ||
| 234 | |||
| 235 | /* enable AIE irq */ | ||
| 236 | ret = rv3029c2_i2c_read_regs(client, RV3029C2_IRQ_CTRL, buf, 1); | ||
| 237 | if (ret < 0) { | ||
| 238 | dev_err(&client->dev, "can't read INT reg\n"); | ||
| 239 | return ret; | ||
| 240 | } | ||
| 241 | if (enable) | ||
| 242 | buf[0] |= RV3029C2_IRQ_CTRL_AIE; | ||
| 243 | else | ||
| 244 | buf[0] &= ~RV3029C2_IRQ_CTRL_AIE; | ||
| 245 | |||
| 246 | ret = rv3029c2_i2c_write_regs(client, RV3029C2_IRQ_CTRL, buf, 1); | ||
| 247 | if (ret < 0) { | ||
| 248 | dev_err(&client->dev, "can't set INT reg\n"); | ||
| 249 | return ret; | ||
| 250 | } | ||
| 251 | |||
| 252 | return 0; | ||
| 253 | } | ||
| 254 | |||
| 255 | static int rv3029c2_rtc_i2c_set_alarm(struct i2c_client *client, | ||
| 256 | struct rtc_wkalrm *alarm) | ||
| 257 | { | ||
| 258 | struct rtc_time *const tm = &alarm->time; | ||
| 259 | int ret; | ||
| 260 | u8 regs[8]; | ||
| 261 | |||
| 262 | /* | ||
| 263 | * The clock has an 8 bit wide bcd-coded register (they never learn) | ||
| 264 | * for the year. tm_year is an offset from 1900 and we are interested | ||
| 265 | * in the 2000-2099 range, so any value less than 100 is invalid. | ||
| 266 | */ | ||
| 267 | if (tm->tm_year < 100) | ||
| 268 | return -EINVAL; | ||
| 269 | |||
| 270 | ret = rv3029c2_i2c_get_sr(client, regs); | ||
| 271 | if (ret < 0) { | ||
| 272 | dev_err(&client->dev, "%s: reading SR failed\n", __func__); | ||
| 273 | return -EIO; | ||
| 274 | } | ||
| 275 | regs[RV3029C2_A_SC-RV3029C2_A_SC] = bin2bcd(tm->tm_sec & 0x7f); | ||
| 276 | regs[RV3029C2_A_MN-RV3029C2_A_SC] = bin2bcd(tm->tm_min & 0x7f); | ||
| 277 | regs[RV3029C2_A_HR-RV3029C2_A_SC] = bin2bcd(tm->tm_hour & 0x3f); | ||
| 278 | regs[RV3029C2_A_DT-RV3029C2_A_SC] = bin2bcd(tm->tm_mday & 0x3f); | ||
| 279 | regs[RV3029C2_A_MO-RV3029C2_A_SC] = bin2bcd((tm->tm_mon & 0x1f) - 1); | ||
| 280 | regs[RV3029C2_A_DW-RV3029C2_A_SC] = bin2bcd((tm->tm_wday & 7) - 1); | ||
| 281 | regs[RV3029C2_A_YR-RV3029C2_A_SC] = bin2bcd((tm->tm_year & 0x7f) - 100); | ||
| 282 | |||
| 283 | ret = rv3029c2_i2c_write_regs(client, RV3029C2_A_SC, regs, | ||
| 284 | RV3029C2_ALARM_SECTION_LEN); | ||
| 285 | if (ret < 0) | ||
| 286 | return ret; | ||
| 287 | |||
| 288 | if (alarm->enabled) { | ||
| 289 | u8 buf[1]; | ||
| 290 | |||
| 291 | /* clear AF flag */ | ||
| 292 | ret = rv3029c2_i2c_read_regs(client, RV3029C2_IRQ_FLAGS, | ||
| 293 | buf, 1); | ||
| 294 | if (ret < 0) { | ||
| 295 | dev_err(&client->dev, "can't read alarm flag\n"); | ||
| 296 | return ret; | ||
| 297 | } | ||
| 298 | buf[0] &= ~RV3029C2_IRQ_FLAGS_AF; | ||
| 299 | ret = rv3029c2_i2c_write_regs(client, RV3029C2_IRQ_FLAGS, | ||
| 300 | buf, 1); | ||
| 301 | if (ret < 0) { | ||
| 302 | dev_err(&client->dev, "can't set alarm flag\n"); | ||
| 303 | return ret; | ||
| 304 | } | ||
| 305 | /* enable AIE irq */ | ||
| 306 | ret = rv3029c2_rtc_i2c_alarm_set_irq(client, 1); | ||
| 307 | if (ret) | ||
| 308 | return ret; | ||
| 309 | |||
| 310 | dev_dbg(&client->dev, "alarm IRQ armed\n"); | ||
| 311 | } else { | ||
| 312 | /* disable AIE irq */ | ||
| 313 | ret = rv3029c2_rtc_i2c_alarm_set_irq(client, 1); | ||
| 314 | if (ret) | ||
| 315 | return ret; | ||
| 316 | |||
| 317 | dev_dbg(&client->dev, "alarm IRQ disabled\n"); | ||
| 318 | } | ||
| 319 | |||
| 320 | return 0; | ||
| 321 | } | ||
| 322 | |||
| 323 | static int rv3029c2_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) | ||
| 324 | { | ||
| 325 | return rv3029c2_rtc_i2c_set_alarm(to_i2c_client(dev), alarm); | ||
| 326 | } | ||
| 327 | |||
| 328 | static int | ||
| 329 | rv3029c2_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm) | ||
| 330 | { | ||
| 331 | u8 regs[8]; | ||
| 332 | int ret; | ||
| 333 | |||
| 334 | /* | ||
| 335 | * The clock has an 8 bit wide bcd-coded register (they never learn) | ||
| 336 | * for the year. tm_year is an offset from 1900 and we are interested | ||
| 337 | * in the 2000-2099 range, so any value less than 100 is invalid. | ||
| 338 | */ | ||
| 339 | if (tm->tm_year < 100) | ||
| 340 | return -EINVAL; | ||
| 341 | |||
| 342 | regs[RV3029C2_W_SEC-RV3029C2_W_SEC] = bin2bcd(tm->tm_sec); | ||
| 343 | regs[RV3029C2_W_MINUTES-RV3029C2_W_SEC] = bin2bcd(tm->tm_min); | ||
| 344 | regs[RV3029C2_W_HOURS-RV3029C2_W_SEC] = bin2bcd(tm->tm_hour); | ||
| 345 | regs[RV3029C2_W_DATE-RV3029C2_W_SEC] = bin2bcd(tm->tm_mday); | ||
| 346 | regs[RV3029C2_W_MONTHS-RV3029C2_W_SEC] = bin2bcd(tm->tm_mon+1); | ||
| 347 | regs[RV3029C2_W_DAYS-RV3029C2_W_SEC] = bin2bcd((tm->tm_wday & 7)+1); | ||
| 348 | regs[RV3029C2_W_YEARS-RV3029C2_W_SEC] = bin2bcd(tm->tm_year - 100); | ||
| 349 | |||
| 350 | ret = rv3029c2_i2c_write_regs(client, RV3029C2_W_SEC, regs, | ||
| 351 | RV3029C2_WATCH_SECTION_LEN); | ||
| 352 | if (ret < 0) | ||
| 353 | return ret; | ||
| 354 | |||
| 355 | ret = rv3029c2_i2c_get_sr(client, regs); | ||
| 356 | if (ret < 0) { | ||
| 357 | dev_err(&client->dev, "%s: reading SR failed\n", __func__); | ||
| 358 | return ret; | ||
| 359 | } | ||
| 360 | /* clear PON bit */ | ||
| 361 | ret = rv3029c2_i2c_set_sr(client, (regs[0] & ~RV3029C2_STATUS_PON)); | ||
| 362 | if (ret < 0) { | ||
| 363 | dev_err(&client->dev, "%s: reading SR failed\n", __func__); | ||
| 364 | return ret; | ||
| 365 | } | ||
| 366 | |||
| 367 | return 0; | ||
| 368 | } | ||
| 369 | |||
| 370 | static int rv3029c2_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
| 371 | { | ||
| 372 | return rv3029c2_i2c_set_time(to_i2c_client(dev), tm); | ||
| 373 | } | ||
| 374 | |||
| 375 | static const struct rtc_class_ops rv3029c2_rtc_ops = { | ||
| 376 | .read_time = rv3029c2_rtc_read_time, | ||
| 377 | .set_time = rv3029c2_rtc_set_time, | ||
| 378 | .read_alarm = rv3029c2_rtc_read_alarm, | ||
| 379 | .set_alarm = rv3029c2_rtc_set_alarm, | ||
| 380 | }; | ||
| 381 | |||
| 382 | static struct i2c_device_id rv3029c2_id[] = { | ||
| 383 | { "rv3029c2", 0 }, | ||
| 384 | { } | ||
| 385 | }; | ||
| 386 | MODULE_DEVICE_TABLE(i2c, rv3029c2_id); | ||
| 387 | |||
| 388 | static int __devinit | ||
| 389 | rv3029c2_probe(struct i2c_client *client, const struct i2c_device_id *id) | ||
| 390 | { | ||
| 391 | struct rtc_device *rtc; | ||
| 392 | int rc = 0; | ||
| 393 | u8 buf[1]; | ||
| 394 | |||
| 395 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_EMUL)) | ||
| 396 | return -ENODEV; | ||
| 397 | |||
| 398 | rtc = rtc_device_register(client->name, | ||
| 399 | &client->dev, &rv3029c2_rtc_ops, | ||
| 400 | THIS_MODULE); | ||
| 401 | |||
| 402 | if (IS_ERR(rtc)) | ||
| 403 | return PTR_ERR(rtc); | ||
| 404 | |||
| 405 | i2c_set_clientdata(client, rtc); | ||
| 406 | |||
| 407 | rc = rv3029c2_i2c_get_sr(client, buf); | ||
| 408 | if (rc < 0) { | ||
| 409 | dev_err(&client->dev, "reading status failed\n"); | ||
| 410 | goto exit_unregister; | ||
| 411 | } | ||
| 412 | |||
| 413 | return 0; | ||
| 414 | |||
| 415 | exit_unregister: | ||
| 416 | rtc_device_unregister(rtc); | ||
| 417 | |||
| 418 | return rc; | ||
| 419 | } | ||
| 420 | |||
| 421 | static int __devexit rv3029c2_remove(struct i2c_client *client) | ||
| 422 | { | ||
| 423 | struct rtc_device *rtc = i2c_get_clientdata(client); | ||
| 424 | |||
| 425 | rtc_device_unregister(rtc); | ||
| 426 | |||
| 427 | return 0; | ||
| 428 | } | ||
| 429 | |||
| 430 | static struct i2c_driver rv3029c2_driver = { | ||
| 431 | .driver = { | ||
| 432 | .name = "rtc-rv3029c2", | ||
| 433 | }, | ||
| 434 | .probe = rv3029c2_probe, | ||
| 435 | .remove = __devexit_p(rv3029c2_remove), | ||
| 436 | .id_table = rv3029c2_id, | ||
| 437 | }; | ||
| 438 | |||
| 439 | static int __init rv3029c2_init(void) | ||
| 440 | { | ||
| 441 | return i2c_add_driver(&rv3029c2_driver); | ||
| 442 | } | ||
| 443 | |||
| 444 | static void __exit rv3029c2_exit(void) | ||
| 445 | { | ||
| 446 | i2c_del_driver(&rv3029c2_driver); | ||
| 447 | } | ||
| 448 | |||
| 449 | module_init(rv3029c2_init); | ||
| 450 | module_exit(rv3029c2_exit); | ||
| 451 | |||
| 452 | MODULE_AUTHOR("Gregory Hermant <gregory.hermant@calao-systems.com>"); | ||
| 453 | MODULE_DESCRIPTION("Micro Crystal RV3029C2 RTC driver"); | ||
| 454 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 714964913e5e..16512ecae31a 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c | |||
| @@ -46,6 +46,7 @@ static struct clk *rtc_clk; | |||
| 46 | static void __iomem *s3c_rtc_base; | 46 | static void __iomem *s3c_rtc_base; |
| 47 | static int s3c_rtc_alarmno = NO_IRQ; | 47 | static int s3c_rtc_alarmno = NO_IRQ; |
| 48 | static int s3c_rtc_tickno = NO_IRQ; | 48 | static int s3c_rtc_tickno = NO_IRQ; |
| 49 | static bool wake_en; | ||
| 49 | static enum s3c_cpu_type s3c_rtc_cpu_type; | 50 | static enum s3c_cpu_type s3c_rtc_cpu_type; |
| 50 | 51 | ||
| 51 | static DEFINE_SPINLOCK(s3c_rtc_pie_lock); | 52 | static DEFINE_SPINLOCK(s3c_rtc_pie_lock); |
| @@ -336,7 +337,6 @@ static void s3c_rtc_release(struct device *dev) | |||
| 336 | 337 | ||
| 337 | /* do not clear AIE here, it may be needed for wake */ | 338 | /* do not clear AIE here, it may be needed for wake */ |
| 338 | 339 | ||
| 339 | s3c_rtc_setpie(dev, 0); | ||
| 340 | free_irq(s3c_rtc_alarmno, rtc_dev); | 340 | free_irq(s3c_rtc_alarmno, rtc_dev); |
| 341 | free_irq(s3c_rtc_tickno, rtc_dev); | 341 | free_irq(s3c_rtc_tickno, rtc_dev); |
| 342 | } | 342 | } |
| @@ -408,7 +408,6 @@ static int __devexit s3c_rtc_remove(struct platform_device *dev) | |||
| 408 | platform_set_drvdata(dev, NULL); | 408 | platform_set_drvdata(dev, NULL); |
| 409 | rtc_device_unregister(rtc); | 409 | rtc_device_unregister(rtc); |
| 410 | 410 | ||
| 411 | s3c_rtc_setpie(&dev->dev, 0); | ||
| 412 | s3c_rtc_setaie(&dev->dev, 0); | 411 | s3c_rtc_setaie(&dev->dev, 0); |
| 413 | 412 | ||
| 414 | clk_disable(rtc_clk); | 413 | clk_disable(rtc_clk); |
| @@ -564,8 +563,12 @@ static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state) | |||
| 564 | } | 563 | } |
| 565 | s3c_rtc_enable(pdev, 0); | 564 | s3c_rtc_enable(pdev, 0); |
| 566 | 565 | ||
| 567 | if (device_may_wakeup(&pdev->dev)) | 566 | if (device_may_wakeup(&pdev->dev) && !wake_en) { |
| 568 | enable_irq_wake(s3c_rtc_alarmno); | 567 | if (enable_irq_wake(s3c_rtc_alarmno) == 0) |
| 568 | wake_en = true; | ||
| 569 | else | ||
| 570 | dev_err(&pdev->dev, "enable_irq_wake failed\n"); | ||
| 571 | } | ||
| 569 | 572 | ||
| 570 | return 0; | 573 | return 0; |
| 571 | } | 574 | } |
| @@ -581,8 +584,10 @@ static int s3c_rtc_resume(struct platform_device *pdev) | |||
| 581 | writew(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON); | 584 | writew(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON); |
| 582 | } | 585 | } |
| 583 | 586 | ||
| 584 | if (device_may_wakeup(&pdev->dev)) | 587 | if (device_may_wakeup(&pdev->dev) && wake_en) { |
| 585 | disable_irq_wake(s3c_rtc_alarmno); | 588 | disable_irq_wake(s3c_rtc_alarmno); |
| 589 | wake_en = false; | ||
| 590 | } | ||
| 586 | 591 | ||
| 587 | return 0; | 592 | return 0; |
| 588 | } | 593 | } |
diff --git a/drivers/rtc/rtc-spear.c b/drivers/rtc/rtc-spear.c new file mode 100644 index 000000000000..893bac2bb21b --- /dev/null +++ b/drivers/rtc/rtc-spear.c | |||
| @@ -0,0 +1,534 @@ | |||
| 1 | /* | ||
| 2 | * drivers/rtc/rtc-spear.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010 ST Microelectronics | ||
| 5 | * Rajeev Kumar<rajeev-dlh.kumar@st.com> | ||
| 6 | * | ||
| 7 | * This file is licensed under the terms of the GNU General Public | ||
| 8 | * License version 2. This program is licensed "as is" without any | ||
| 9 | * warranty of any kind, whether express or implied. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/bcd.h> | ||
| 13 | #include <linux/clk.h> | ||
| 14 | #include <linux/delay.h> | ||
| 15 | #include <linux/init.h> | ||
| 16 | #include <linux/io.h> | ||
| 17 | #include <linux/irq.h> | ||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/platform_device.h> | ||
| 20 | #include <linux/rtc.h> | ||
| 21 | #include <linux/slab.h> | ||
| 22 | #include <linux/spinlock.h> | ||
| 23 | |||
| 24 | /* RTC registers */ | ||
| 25 | #define TIME_REG 0x00 | ||
| 26 | #define DATE_REG 0x04 | ||
| 27 | #define ALARM_TIME_REG 0x08 | ||
| 28 | #define ALARM_DATE_REG 0x0C | ||
| 29 | #define CTRL_REG 0x10 | ||
| 30 | #define STATUS_REG 0x14 | ||
| 31 | |||
| 32 | /* TIME_REG & ALARM_TIME_REG */ | ||
| 33 | #define SECONDS_UNITS (0xf<<0) /* seconds units position */ | ||
| 34 | #define SECONDS_TENS (0x7<<4) /* seconds tens position */ | ||
| 35 | #define MINUTES_UNITS (0xf<<8) /* minutes units position */ | ||
| 36 | #define MINUTES_TENS (0x7<<12) /* minutes tens position */ | ||
| 37 | #define HOURS_UNITS (0xf<<16) /* hours units position */ | ||
| 38 | #define HOURS_TENS (0x3<<20) /* hours tens position */ | ||
| 39 | |||
| 40 | /* DATE_REG & ALARM_DATE_REG */ | ||
| 41 | #define DAYS_UNITS (0xf<<0) /* days units position */ | ||
| 42 | #define DAYS_TENS (0x3<<4) /* days tens position */ | ||
| 43 | #define MONTHS_UNITS (0xf<<8) /* months units position */ | ||
| 44 | #define MONTHS_TENS (0x1<<12) /* months tens position */ | ||
| 45 | #define YEARS_UNITS (0xf<<16) /* years units position */ | ||
| 46 | #define YEARS_TENS (0xf<<20) /* years tens position */ | ||
| 47 | #define YEARS_HUNDREDS (0xf<<24) /* years hundereds position */ | ||
| 48 | #define YEARS_MILLENIUMS (0xf<<28) /* years millenium position */ | ||
| 49 | |||
| 50 | /* MASK SHIFT TIME_REG & ALARM_TIME_REG*/ | ||
| 51 | #define SECOND_SHIFT 0x00 /* seconds units */ | ||
| 52 | #define MINUTE_SHIFT 0x08 /* minutes units position */ | ||
| 53 | #define HOUR_SHIFT 0x10 /* hours units position */ | ||
| 54 | #define MDAY_SHIFT 0x00 /* Month day shift */ | ||
| 55 | #define MONTH_SHIFT 0x08 /* Month shift */ | ||
| 56 | #define YEAR_SHIFT 0x10 /* Year shift */ | ||
| 57 | |||
| 58 | #define SECOND_MASK 0x7F | ||
| 59 | #define MIN_MASK 0x7F | ||
| 60 | #define HOUR_MASK 0x3F | ||
| 61 | #define DAY_MASK 0x3F | ||
| 62 | #define MONTH_MASK 0x7F | ||
| 63 | #define YEAR_MASK 0xFFFF | ||
| 64 | |||
| 65 | /* date reg equal to time reg, for debug only */ | ||
| 66 | #define TIME_BYP (1<<9) | ||
| 67 | #define INT_ENABLE (1<<31) /* interrupt enable */ | ||
| 68 | |||
| 69 | /* STATUS_REG */ | ||
| 70 | #define CLK_UNCONNECTED (1<<0) | ||
| 71 | #define PEND_WR_TIME (1<<2) | ||
| 72 | #define PEND_WR_DATE (1<<3) | ||
| 73 | #define LOST_WR_TIME (1<<4) | ||
| 74 | #define LOST_WR_DATE (1<<5) | ||
| 75 | #define RTC_INT_MASK (1<<31) | ||
| 76 | #define STATUS_BUSY (PEND_WR_TIME | PEND_WR_DATE) | ||
| 77 | #define STATUS_FAIL (LOST_WR_TIME | LOST_WR_DATE) | ||
| 78 | |||
| 79 | struct spear_rtc_config { | ||
| 80 | struct clk *clk; | ||
| 81 | spinlock_t lock; | ||
| 82 | void __iomem *ioaddr; | ||
| 83 | }; | ||
| 84 | |||
| 85 | static inline void spear_rtc_clear_interrupt(struct spear_rtc_config *config) | ||
| 86 | { | ||
| 87 | unsigned int val; | ||
| 88 | unsigned long flags; | ||
| 89 | |||
| 90 | spin_lock_irqsave(&config->lock, flags); | ||
| 91 | val = readl(config->ioaddr + STATUS_REG); | ||
| 92 | val |= RTC_INT_MASK; | ||
| 93 | writel(val, config->ioaddr + STATUS_REG); | ||
| 94 | spin_unlock_irqrestore(&config->lock, flags); | ||
| 95 | } | ||
| 96 | |||
| 97 | static inline void spear_rtc_enable_interrupt(struct spear_rtc_config *config) | ||
| 98 | { | ||
| 99 | unsigned int val; | ||
| 100 | |||
| 101 | val = readl(config->ioaddr + CTRL_REG); | ||
| 102 | if (!(val & INT_ENABLE)) { | ||
| 103 | spear_rtc_clear_interrupt(config); | ||
| 104 | val |= INT_ENABLE; | ||
| 105 | writel(val, config->ioaddr + CTRL_REG); | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | static inline void spear_rtc_disable_interrupt(struct spear_rtc_config *config) | ||
| 110 | { | ||
| 111 | unsigned int val; | ||
| 112 | |||
| 113 | val = readl(config->ioaddr + CTRL_REG); | ||
| 114 | if (val & INT_ENABLE) { | ||
| 115 | val &= ~INT_ENABLE; | ||
| 116 | writel(val, config->ioaddr + CTRL_REG); | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | static inline int is_write_complete(struct spear_rtc_config *config) | ||
| 121 | { | ||
| 122 | int ret = 0; | ||
| 123 | unsigned long flags; | ||
| 124 | |||
| 125 | spin_lock_irqsave(&config->lock, flags); | ||
| 126 | if ((readl(config->ioaddr + STATUS_REG)) & STATUS_FAIL) | ||
| 127 | ret = -EIO; | ||
| 128 | spin_unlock_irqrestore(&config->lock, flags); | ||
| 129 | |||
| 130 | return ret; | ||
| 131 | } | ||
| 132 | |||
| 133 | static void rtc_wait_not_busy(struct spear_rtc_config *config) | ||
| 134 | { | ||
| 135 | int status, count = 0; | ||
| 136 | unsigned long flags; | ||
| 137 | |||
| 138 | /* Assuming BUSY may stay active for 80 msec) */ | ||
| 139 | for (count = 0; count < 80; count++) { | ||
| 140 | spin_lock_irqsave(&config->lock, flags); | ||
| 141 | status = readl(config->ioaddr + STATUS_REG); | ||
| 142 | spin_unlock_irqrestore(&config->lock, flags); | ||
| 143 | if ((status & STATUS_BUSY) == 0) | ||
| 144 | break; | ||
| 145 | /* check status busy, after each msec */ | ||
| 146 | msleep(1); | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | static irqreturn_t spear_rtc_irq(int irq, void *dev_id) | ||
| 151 | { | ||
| 152 | struct rtc_device *rtc = (struct rtc_device *)dev_id; | ||
| 153 | struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev); | ||
| 154 | unsigned long flags, events = 0; | ||
| 155 | unsigned int irq_data; | ||
| 156 | |||
| 157 | spin_lock_irqsave(&config->lock, flags); | ||
| 158 | irq_data = readl(config->ioaddr + STATUS_REG); | ||
| 159 | spin_unlock_irqrestore(&config->lock, flags); | ||
| 160 | |||
| 161 | if ((irq_data & RTC_INT_MASK)) { | ||
| 162 | spear_rtc_clear_interrupt(config); | ||
| 163 | events = RTC_IRQF | RTC_AF; | ||
| 164 | rtc_update_irq(rtc, 1, events); | ||
| 165 | return IRQ_HANDLED; | ||
| 166 | } else | ||
| 167 | return IRQ_NONE; | ||
| 168 | |||
| 169 | } | ||
| 170 | |||
| 171 | static int tm2bcd(struct rtc_time *tm) | ||
| 172 | { | ||
| 173 | if (rtc_valid_tm(tm) != 0) | ||
| 174 | return -EINVAL; | ||
| 175 | tm->tm_sec = bin2bcd(tm->tm_sec); | ||
| 176 | tm->tm_min = bin2bcd(tm->tm_min); | ||
| 177 | tm->tm_hour = bin2bcd(tm->tm_hour); | ||
| 178 | tm->tm_mday = bin2bcd(tm->tm_mday); | ||
| 179 | tm->tm_mon = bin2bcd(tm->tm_mon + 1); | ||
| 180 | tm->tm_year = bin2bcd(tm->tm_year); | ||
| 181 | |||
| 182 | return 0; | ||
| 183 | } | ||
| 184 | |||
| 185 | static void bcd2tm(struct rtc_time *tm) | ||
| 186 | { | ||
| 187 | tm->tm_sec = bcd2bin(tm->tm_sec); | ||
| 188 | tm->tm_min = bcd2bin(tm->tm_min); | ||
| 189 | tm->tm_hour = bcd2bin(tm->tm_hour); | ||
| 190 | tm->tm_mday = bcd2bin(tm->tm_mday); | ||
| 191 | tm->tm_mon = bcd2bin(tm->tm_mon) - 1; | ||
| 192 | /* epoch == 1900 */ | ||
| 193 | tm->tm_year = bcd2bin(tm->tm_year); | ||
| 194 | } | ||
| 195 | |||
| 196 | /* | ||
| 197 | * spear_rtc_read_time - set the time | ||
| 198 | * @dev: rtc device in use | ||
| 199 | * @tm: holds date and time | ||
| 200 | * | ||
| 201 | * This function read time and date. On success it will return 0 | ||
| 202 | * otherwise -ve error is returned. | ||
| 203 | */ | ||
| 204 | static int spear_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
| 205 | { | ||
| 206 | struct platform_device *pdev = to_platform_device(dev); | ||
| 207 | struct rtc_device *rtc = platform_get_drvdata(pdev); | ||
| 208 | struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev); | ||
| 209 | unsigned int time, date; | ||
| 210 | |||
| 211 | /* we don't report wday/yday/isdst ... */ | ||
| 212 | rtc_wait_not_busy(config); | ||
| 213 | |||
| 214 | time = readl(config->ioaddr + TIME_REG); | ||
| 215 | date = readl(config->ioaddr + DATE_REG); | ||
| 216 | tm->tm_sec = (time >> SECOND_SHIFT) & SECOND_MASK; | ||
| 217 | tm->tm_min = (time >> MINUTE_SHIFT) & MIN_MASK; | ||
| 218 | tm->tm_hour = (time >> HOUR_SHIFT) & HOUR_MASK; | ||
| 219 | tm->tm_mday = (date >> MDAY_SHIFT) & DAY_MASK; | ||
| 220 | tm->tm_mon = (date >> MONTH_SHIFT) & MONTH_MASK; | ||
| 221 | tm->tm_year = (date >> YEAR_SHIFT) & YEAR_MASK; | ||
| 222 | |||
| 223 | bcd2tm(tm); | ||
| 224 | return 0; | ||
| 225 | } | ||
| 226 | |||
| 227 | /* | ||
| 228 | * spear_rtc_set_time - set the time | ||
| 229 | * @dev: rtc device in use | ||
| 230 | * @tm: holds date and time | ||
| 231 | * | ||
| 232 | * This function set time and date. On success it will return 0 | ||
| 233 | * otherwise -ve error is returned. | ||
| 234 | */ | ||
| 235 | static int spear_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
| 236 | { | ||
| 237 | struct platform_device *pdev = to_platform_device(dev); | ||
| 238 | struct rtc_device *rtc = platform_get_drvdata(pdev); | ||
| 239 | struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev); | ||
| 240 | unsigned int time, date, err = 0; | ||
| 241 | |||
| 242 | if (tm2bcd(tm) < 0) | ||
| 243 | return -EINVAL; | ||
| 244 | |||
| 245 | rtc_wait_not_busy(config); | ||
| 246 | time = (tm->tm_sec << SECOND_SHIFT) | (tm->tm_min << MINUTE_SHIFT) | | ||
| 247 | (tm->tm_hour << HOUR_SHIFT); | ||
| 248 | date = (tm->tm_mday << MDAY_SHIFT) | (tm->tm_mon << MONTH_SHIFT) | | ||
| 249 | (tm->tm_year << YEAR_SHIFT); | ||
| 250 | writel(time, config->ioaddr + TIME_REG); | ||
| 251 | writel(date, config->ioaddr + DATE_REG); | ||
| 252 | err = is_write_complete(config); | ||
| 253 | if (err < 0) | ||
| 254 | return err; | ||
| 255 | |||
| 256 | return 0; | ||
| 257 | } | ||
| 258 | |||
| 259 | /* | ||
| 260 | * spear_rtc_read_alarm - read the alarm time | ||
| 261 | * @dev: rtc device in use | ||
| 262 | * @alm: holds alarm date and time | ||
| 263 | * | ||
| 264 | * This function read alarm time and date. On success it will return 0 | ||
| 265 | * otherwise -ve error is returned. | ||
| 266 | */ | ||
| 267 | static int spear_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) | ||
| 268 | { | ||
| 269 | struct platform_device *pdev = to_platform_device(dev); | ||
| 270 | struct rtc_device *rtc = platform_get_drvdata(pdev); | ||
| 271 | struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev); | ||
| 272 | unsigned int time, date; | ||
| 273 | |||
| 274 | rtc_wait_not_busy(config); | ||
| 275 | |||
| 276 | time = readl(config->ioaddr + ALARM_TIME_REG); | ||
| 277 | date = readl(config->ioaddr + ALARM_DATE_REG); | ||
| 278 | alm->time.tm_sec = (time >> SECOND_SHIFT) & SECOND_MASK; | ||
| 279 | alm->time.tm_min = (time >> MINUTE_SHIFT) & MIN_MASK; | ||
| 280 | alm->time.tm_hour = (time >> HOUR_SHIFT) & HOUR_MASK; | ||
| 281 | alm->time.tm_mday = (date >> MDAY_SHIFT) & DAY_MASK; | ||
| 282 | alm->time.tm_mon = (date >> MONTH_SHIFT) & MONTH_MASK; | ||
| 283 | alm->time.tm_year = (date >> YEAR_SHIFT) & YEAR_MASK; | ||
| 284 | |||
| 285 | bcd2tm(&alm->time); | ||
| 286 | alm->enabled = readl(config->ioaddr + CTRL_REG) & INT_ENABLE; | ||
| 287 | |||
| 288 | return 0; | ||
| 289 | } | ||
| 290 | |||
| 291 | /* | ||
| 292 | * spear_rtc_set_alarm - set the alarm time | ||
| 293 | * @dev: rtc device in use | ||
| 294 | * @alm: holds alarm date and time | ||
| 295 | * | ||
| 296 | * This function set alarm time and date. On success it will return 0 | ||
| 297 | * otherwise -ve error is returned. | ||
| 298 | */ | ||
| 299 | static int spear_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) | ||
| 300 | { | ||
| 301 | struct platform_device *pdev = to_platform_device(dev); | ||
| 302 | struct rtc_device *rtc = platform_get_drvdata(pdev); | ||
| 303 | struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev); | ||
| 304 | unsigned int time, date, err = 0; | ||
| 305 | |||
| 306 | if (tm2bcd(&alm->time) < 0) | ||
| 307 | return -EINVAL; | ||
| 308 | |||
| 309 | rtc_wait_not_busy(config); | ||
| 310 | |||
| 311 | time = (alm->time.tm_sec << SECOND_SHIFT) | (alm->time.tm_min << | ||
| 312 | MINUTE_SHIFT) | (alm->time.tm_hour << HOUR_SHIFT); | ||
| 313 | date = (alm->time.tm_mday << MDAY_SHIFT) | (alm->time.tm_mon << | ||
| 314 | MONTH_SHIFT) | (alm->time.tm_year << YEAR_SHIFT); | ||
| 315 | |||
| 316 | writel(time, config->ioaddr + ALARM_TIME_REG); | ||
| 317 | writel(date, config->ioaddr + ALARM_DATE_REG); | ||
| 318 | err = is_write_complete(config); | ||
| 319 | if (err < 0) | ||
| 320 | return err; | ||
| 321 | |||
| 322 | if (alm->enabled) | ||
| 323 | spear_rtc_enable_interrupt(config); | ||
| 324 | else | ||
| 325 | spear_rtc_disable_interrupt(config); | ||
| 326 | |||
| 327 | return 0; | ||
| 328 | } | ||
| 329 | static struct rtc_class_ops spear_rtc_ops = { | ||
| 330 | .read_time = spear_rtc_read_time, | ||
| 331 | .set_time = spear_rtc_set_time, | ||
| 332 | .read_alarm = spear_rtc_read_alarm, | ||
| 333 | .set_alarm = spear_rtc_set_alarm, | ||
| 334 | }; | ||
| 335 | |||
| 336 | static int __devinit spear_rtc_probe(struct platform_device *pdev) | ||
| 337 | { | ||
| 338 | struct resource *res; | ||
| 339 | struct rtc_device *rtc; | ||
| 340 | struct spear_rtc_config *config; | ||
| 341 | unsigned int status = 0; | ||
| 342 | int irq; | ||
| 343 | |||
| 344 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 345 | if (!res) { | ||
| 346 | dev_err(&pdev->dev, "no resource defined\n"); | ||
| 347 | return -EBUSY; | ||
| 348 | } | ||
| 349 | if (!request_mem_region(res->start, resource_size(res), pdev->name)) { | ||
| 350 | dev_err(&pdev->dev, "rtc region already claimed\n"); | ||
| 351 | return -EBUSY; | ||
| 352 | } | ||
| 353 | |||
| 354 | config = kzalloc(sizeof(*config), GFP_KERNEL); | ||
| 355 | if (!config) { | ||
| 356 | dev_err(&pdev->dev, "out of memory\n"); | ||
| 357 | status = -ENOMEM; | ||
| 358 | goto err_release_region; | ||
| 359 | } | ||
| 360 | |||
| 361 | config->clk = clk_get(&pdev->dev, NULL); | ||
| 362 | if (IS_ERR(config->clk)) { | ||
| 363 | status = PTR_ERR(config->clk); | ||
| 364 | goto err_kfree; | ||
| 365 | } | ||
| 366 | |||
| 367 | status = clk_enable(config->clk); | ||
| 368 | if (status < 0) | ||
| 369 | goto err_clk_put; | ||
| 370 | |||
| 371 | config->ioaddr = ioremap(res->start, resource_size(res)); | ||
| 372 | if (!config->ioaddr) { | ||
| 373 | dev_err(&pdev->dev, "ioremap fail\n"); | ||
| 374 | status = -ENOMEM; | ||
| 375 | goto err_disable_clock; | ||
| 376 | } | ||
| 377 | |||
| 378 | spin_lock_init(&config->lock); | ||
| 379 | |||
| 380 | rtc = rtc_device_register(pdev->name, &pdev->dev, &spear_rtc_ops, | ||
| 381 | THIS_MODULE); | ||
| 382 | if (IS_ERR(rtc)) { | ||
| 383 | dev_err(&pdev->dev, "can't register RTC device, err %ld\n", | ||
| 384 | PTR_ERR(rtc)); | ||
| 385 | status = PTR_ERR(rtc); | ||
| 386 | goto err_iounmap; | ||
| 387 | } | ||
| 388 | |||
| 389 | platform_set_drvdata(pdev, rtc); | ||
| 390 | dev_set_drvdata(&rtc->dev, config); | ||
| 391 | |||
| 392 | /* alarm irqs */ | ||
| 393 | irq = platform_get_irq(pdev, 0); | ||
| 394 | if (irq < 0) { | ||
| 395 | dev_err(&pdev->dev, "no update irq?\n"); | ||
| 396 | status = irq; | ||
| 397 | goto err_clear_platdata; | ||
| 398 | } | ||
| 399 | |||
| 400 | status = request_irq(irq, spear_rtc_irq, 0, pdev->name, rtc); | ||
| 401 | if (status) { | ||
| 402 | dev_err(&pdev->dev, "Alarm interrupt IRQ%d already \ | ||
| 403 | claimed\n", irq); | ||
| 404 | goto err_clear_platdata; | ||
| 405 | } | ||
| 406 | |||
| 407 | if (!device_can_wakeup(&pdev->dev)) | ||
| 408 | device_init_wakeup(&pdev->dev, 1); | ||
| 409 | |||
| 410 | return 0; | ||
| 411 | |||
| 412 | err_clear_platdata: | ||
| 413 | platform_set_drvdata(pdev, NULL); | ||
| 414 | dev_set_drvdata(&rtc->dev, NULL); | ||
| 415 | rtc_device_unregister(rtc); | ||
| 416 | err_iounmap: | ||
| 417 | iounmap(config->ioaddr); | ||
| 418 | err_disable_clock: | ||
| 419 | clk_disable(config->clk); | ||
| 420 | err_clk_put: | ||
| 421 | clk_put(config->clk); | ||
| 422 | err_kfree: | ||
| 423 | kfree(config); | ||
| 424 | err_release_region: | ||
| 425 | release_mem_region(res->start, resource_size(res)); | ||
| 426 | |||
| 427 | return status; | ||
| 428 | } | ||
| 429 | |||
| 430 | static int __devexit spear_rtc_remove(struct platform_device *pdev) | ||
| 431 | { | ||
| 432 | struct rtc_device *rtc = platform_get_drvdata(pdev); | ||
| 433 | struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev); | ||
| 434 | int irq; | ||
| 435 | struct resource *res; | ||
| 436 | |||
| 437 | /* leave rtc running, but disable irqs */ | ||
| 438 | spear_rtc_disable_interrupt(config); | ||
| 439 | device_init_wakeup(&pdev->dev, 0); | ||
| 440 | irq = platform_get_irq(pdev, 0); | ||
| 441 | if (irq) | ||
| 442 | free_irq(irq, pdev); | ||
| 443 | clk_disable(config->clk); | ||
| 444 | clk_put(config->clk); | ||
| 445 | iounmap(config->ioaddr); | ||
| 446 | kfree(config); | ||
| 447 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 448 | if (res) | ||
| 449 | release_mem_region(res->start, resource_size(res)); | ||
| 450 | platform_set_drvdata(pdev, NULL); | ||
| 451 | dev_set_drvdata(&rtc->dev, NULL); | ||
| 452 | rtc_device_unregister(rtc); | ||
| 453 | |||
| 454 | return 0; | ||
| 455 | } | ||
| 456 | |||
| 457 | #ifdef CONFIG_PM | ||
| 458 | |||
| 459 | static int spear_rtc_suspend(struct platform_device *pdev, pm_message_t state) | ||
| 460 | { | ||
| 461 | struct rtc_device *rtc = platform_get_drvdata(pdev); | ||
| 462 | struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev); | ||
| 463 | int irq; | ||
| 464 | |||
| 465 | irq = platform_get_irq(pdev, 0); | ||
| 466 | if (device_may_wakeup(&pdev->dev)) | ||
| 467 | enable_irq_wake(irq); | ||
| 468 | else { | ||
| 469 | spear_rtc_disable_interrupt(config); | ||
| 470 | clk_disable(config->clk); | ||
| 471 | } | ||
| 472 | |||
| 473 | return 0; | ||
| 474 | } | ||
| 475 | |||
| 476 | static int spear_rtc_resume(struct platform_device *pdev) | ||
| 477 | { | ||
| 478 | struct rtc_device *rtc = platform_get_drvdata(pdev); | ||
| 479 | struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev); | ||
| 480 | int irq; | ||
| 481 | |||
| 482 | irq = platform_get_irq(pdev, 0); | ||
| 483 | |||
| 484 | if (device_may_wakeup(&pdev->dev)) | ||
| 485 | disable_irq_wake(irq); | ||
| 486 | else { | ||
| 487 | clk_enable(config->clk); | ||
| 488 | spear_rtc_enable_interrupt(config); | ||
| 489 | } | ||
| 490 | |||
| 491 | return 0; | ||
| 492 | } | ||
| 493 | |||
| 494 | #else | ||
| 495 | #define spear_rtc_suspend NULL | ||
| 496 | #define spear_rtc_resume NULL | ||
| 497 | #endif | ||
| 498 | |||
| 499 | static void spear_rtc_shutdown(struct platform_device *pdev) | ||
| 500 | { | ||
| 501 | struct rtc_device *rtc = platform_get_drvdata(pdev); | ||
| 502 | struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev); | ||
| 503 | |||
| 504 | spear_rtc_disable_interrupt(config); | ||
| 505 | clk_disable(config->clk); | ||
| 506 | } | ||
| 507 | |||
| 508 | static struct platform_driver spear_rtc_driver = { | ||
| 509 | .probe = spear_rtc_probe, | ||
| 510 | .remove = __devexit_p(spear_rtc_remove), | ||
| 511 | .suspend = spear_rtc_suspend, | ||
| 512 | .resume = spear_rtc_resume, | ||
| 513 | .shutdown = spear_rtc_shutdown, | ||
| 514 | .driver = { | ||
| 515 | .name = "rtc-spear", | ||
| 516 | }, | ||
| 517 | }; | ||
| 518 | |||
| 519 | static int __init rtc_init(void) | ||
| 520 | { | ||
| 521 | return platform_driver_register(&spear_rtc_driver); | ||
| 522 | } | ||
| 523 | module_init(rtc_init); | ||
| 524 | |||
| 525 | static void __exit rtc_exit(void) | ||
| 526 | { | ||
| 527 | platform_driver_unregister(&spear_rtc_driver); | ||
| 528 | } | ||
| 529 | module_exit(rtc_exit); | ||
| 530 | |||
| 531 | MODULE_ALIAS("platform:rtc-spear"); | ||
| 532 | MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>"); | ||
| 533 | MODULE_DESCRIPTION("ST SPEAr Realtime Clock Driver (RTC)"); | ||
| 534 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-tile.c b/drivers/rtc/rtc-tile.c new file mode 100644 index 000000000000..eb65dafee66e --- /dev/null +++ b/drivers/rtc/rtc-tile.c | |||
| @@ -0,0 +1,162 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2011 Tilera Corporation. All Rights Reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation, version 2. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, but | ||
| 9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
| 11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
| 12 | * more details. | ||
| 13 | * | ||
| 14 | * Tilera-specific RTC driver. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/device.h> | ||
| 19 | #include <linux/rtc.h> | ||
| 20 | #include <linux/platform_device.h> | ||
| 21 | |||
| 22 | /* Platform device pointer. */ | ||
| 23 | static struct platform_device *tile_rtc_platform_device; | ||
| 24 | |||
| 25 | /* | ||
| 26 | * RTC read routine. Gets time info from RTC chip via hypervisor syscall. | ||
| 27 | */ | ||
| 28 | static int read_rtc_time(struct device *dev, struct rtc_time *tm) | ||
| 29 | { | ||
| 30 | HV_RTCTime hvtm = hv_get_rtc(); | ||
| 31 | |||
| 32 | tm->tm_sec = hvtm.tm_sec; | ||
| 33 | tm->tm_min = hvtm.tm_min; | ||
| 34 | tm->tm_hour = hvtm.tm_hour; | ||
| 35 | tm->tm_mday = hvtm.tm_mday; | ||
| 36 | tm->tm_mon = hvtm.tm_mon; | ||
| 37 | tm->tm_year = hvtm.tm_year; | ||
| 38 | tm->tm_wday = 0; | ||
| 39 | tm->tm_yday = 0; | ||
| 40 | tm->tm_isdst = 0; | ||
| 41 | |||
| 42 | if (rtc_valid_tm(tm) < 0) | ||
| 43 | dev_warn(dev, "Read invalid date/time from RTC\n"); | ||
| 44 | |||
| 45 | return 0; | ||
| 46 | } | ||
| 47 | |||
| 48 | /* | ||
| 49 | * RTC write routine. Sends time info to hypervisor via syscall, to be | ||
| 50 | * written to RTC chip. | ||
| 51 | */ | ||
| 52 | static int set_rtc_time(struct device *dev, struct rtc_time *tm) | ||
| 53 | { | ||
| 54 | HV_RTCTime hvtm; | ||
| 55 | |||
| 56 | hvtm.tm_sec = tm->tm_sec; | ||
| 57 | hvtm.tm_min = tm->tm_min; | ||
| 58 | hvtm.tm_hour = tm->tm_hour; | ||
| 59 | hvtm.tm_mday = tm->tm_mday; | ||
| 60 | hvtm.tm_mon = tm->tm_mon; | ||
| 61 | hvtm.tm_year = tm->tm_year; | ||
| 62 | |||
| 63 | hv_set_rtc(hvtm); | ||
| 64 | |||
| 65 | return 0; | ||
| 66 | } | ||
| 67 | |||
| 68 | /* | ||
| 69 | * RTC read/write ops. | ||
| 70 | */ | ||
| 71 | static const struct rtc_class_ops tile_rtc_ops = { | ||
| 72 | .read_time = read_rtc_time, | ||
| 73 | .set_time = set_rtc_time, | ||
| 74 | }; | ||
| 75 | |||
| 76 | /* | ||
| 77 | * Device probe routine. | ||
| 78 | */ | ||
| 79 | static int __devinit tile_rtc_probe(struct platform_device *dev) | ||
| 80 | { | ||
| 81 | struct rtc_device *rtc; | ||
| 82 | |||
| 83 | rtc = rtc_device_register("tile", | ||
| 84 | &dev->dev, &tile_rtc_ops, THIS_MODULE); | ||
| 85 | |||
| 86 | if (IS_ERR(rtc)) | ||
| 87 | return PTR_ERR(rtc); | ||
| 88 | |||
| 89 | platform_set_drvdata(dev, rtc); | ||
| 90 | |||
| 91 | return 0; | ||
| 92 | } | ||
| 93 | |||
| 94 | /* | ||
| 95 | * Device cleanup routine. | ||
| 96 | */ | ||
| 97 | static int __devexit tile_rtc_remove(struct platform_device *dev) | ||
| 98 | { | ||
| 99 | struct rtc_device *rtc = platform_get_drvdata(dev); | ||
| 100 | |||
| 101 | if (rtc) | ||
| 102 | rtc_device_unregister(rtc); | ||
| 103 | |||
| 104 | platform_set_drvdata(dev, NULL); | ||
| 105 | |||
| 106 | return 0; | ||
| 107 | } | ||
| 108 | |||
| 109 | static struct platform_driver tile_rtc_platform_driver = { | ||
| 110 | .driver = { | ||
| 111 | .name = "rtc-tile", | ||
| 112 | .owner = THIS_MODULE, | ||
| 113 | }, | ||
| 114 | .probe = tile_rtc_probe, | ||
| 115 | .remove = __devexit_p(tile_rtc_remove), | ||
| 116 | }; | ||
| 117 | |||
| 118 | /* | ||
| 119 | * Driver init routine. | ||
| 120 | */ | ||
| 121 | static int __init tile_rtc_driver_init(void) | ||
| 122 | { | ||
| 123 | int err; | ||
| 124 | |||
| 125 | err = platform_driver_register(&tile_rtc_platform_driver); | ||
| 126 | if (err) | ||
| 127 | return err; | ||
| 128 | |||
| 129 | tile_rtc_platform_device = platform_device_alloc("rtc-tile", 0); | ||
| 130 | if (tile_rtc_platform_device == NULL) { | ||
| 131 | err = -ENOMEM; | ||
| 132 | goto exit_driver_unregister; | ||
| 133 | } | ||
| 134 | |||
| 135 | err = platform_device_add(tile_rtc_platform_device); | ||
| 136 | if (err) | ||
| 137 | goto exit_device_put; | ||
| 138 | |||
| 139 | return 0; | ||
| 140 | |||
| 141 | exit_device_put: | ||
| 142 | platform_device_put(tile_rtc_platform_device); | ||
| 143 | |||
| 144 | exit_driver_unregister: | ||
| 145 | platform_driver_unregister(&tile_rtc_platform_driver); | ||
| 146 | return err; | ||
| 147 | } | ||
| 148 | |||
| 149 | /* | ||
| 150 | * Driver cleanup routine. | ||
| 151 | */ | ||
| 152 | static void __exit tile_rtc_driver_exit(void) | ||
| 153 | { | ||
| 154 | platform_driver_unregister(&tile_rtc_platform_driver); | ||
| 155 | } | ||
| 156 | |||
| 157 | module_init(tile_rtc_driver_init); | ||
| 158 | module_exit(tile_rtc_driver_exit); | ||
| 159 | |||
| 160 | MODULE_DESCRIPTION("Tilera-specific Real Time Clock Driver"); | ||
| 161 | MODULE_LICENSE("GPL"); | ||
| 162 | MODULE_ALIAS("platform:rtc-tile"); | ||
diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c new file mode 100644 index 000000000000..b8bc862903ae --- /dev/null +++ b/drivers/rtc/rtc-vt8500.c | |||
| @@ -0,0 +1,366 @@ | |||
| 1 | /* | ||
| 2 | * drivers/rtc/rtc-vt8500.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> | ||
| 5 | * | ||
| 6 | * Based on rtc-pxa.c | ||
| 7 | * | ||
| 8 | * This software is licensed under the terms of the GNU General Public | ||
| 9 | * License version 2, as published by the Free Software Foundation, and | ||
| 10 | * may be copied, distributed, and modified under those terms. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/rtc.h> | ||
| 20 | #include <linux/init.h> | ||
| 21 | #include <linux/interrupt.h> | ||
| 22 | #include <linux/io.h> | ||
| 23 | #include <linux/bcd.h> | ||
| 24 | #include <linux/platform_device.h> | ||
| 25 | #include <linux/slab.h> | ||
| 26 | |||
| 27 | /* | ||
| 28 | * Register definitions | ||
| 29 | */ | ||
| 30 | #define VT8500_RTC_TS 0x00 /* Time set */ | ||
| 31 | #define VT8500_RTC_DS 0x04 /* Date set */ | ||
| 32 | #define VT8500_RTC_AS 0x08 /* Alarm set */ | ||
| 33 | #define VT8500_RTC_CR 0x0c /* Control */ | ||
| 34 | #define VT8500_RTC_TR 0x10 /* Time read */ | ||
| 35 | #define VT8500_RTC_DR 0x14 /* Date read */ | ||
| 36 | #define VT8500_RTC_WS 0x18 /* Write status */ | ||
| 37 | #define VT8500_RTC_CL 0x20 /* Calibration */ | ||
| 38 | #define VT8500_RTC_IS 0x24 /* Interrupt status */ | ||
| 39 | #define VT8500_RTC_ST 0x28 /* Status */ | ||
| 40 | |||
| 41 | #define INVALID_TIME_BIT (1 << 31) | ||
| 42 | |||
| 43 | #define DATE_CENTURY_S 19 | ||
| 44 | #define DATE_YEAR_S 11 | ||
| 45 | #define DATE_YEAR_MASK (0xff << DATE_YEAR_S) | ||
| 46 | #define DATE_MONTH_S 6 | ||
| 47 | #define DATE_MONTH_MASK (0x1f << DATE_MONTH_S) | ||
| 48 | #define DATE_DAY_MASK 0x3f | ||
| 49 | |||
| 50 | #define TIME_DOW_S 20 | ||
| 51 | #define TIME_DOW_MASK (0x07 << TIME_DOW_S) | ||
| 52 | #define TIME_HOUR_S 14 | ||
| 53 | #define TIME_HOUR_MASK (0x3f << TIME_HOUR_S) | ||
| 54 | #define TIME_MIN_S 7 | ||
| 55 | #define TIME_MIN_MASK (0x7f << TIME_MIN_S) | ||
| 56 | #define TIME_SEC_MASK 0x7f | ||
| 57 | |||
| 58 | #define ALARM_DAY_S 20 | ||
| 59 | #define ALARM_DAY_MASK (0x3f << ALARM_DAY_S) | ||
| 60 | |||
| 61 | #define ALARM_DAY_BIT (1 << 29) | ||
| 62 | #define ALARM_HOUR_BIT (1 << 28) | ||
| 63 | #define ALARM_MIN_BIT (1 << 27) | ||
| 64 | #define ALARM_SEC_BIT (1 << 26) | ||
| 65 | |||
| 66 | #define ALARM_ENABLE_MASK (ALARM_DAY_BIT \ | ||
| 67 | | ALARM_HOUR_BIT \ | ||
| 68 | | ALARM_MIN_BIT \ | ||
| 69 | | ALARM_SEC_BIT) | ||
| 70 | |||
| 71 | #define VT8500_RTC_CR_ENABLE (1 << 0) /* Enable RTC */ | ||
| 72 | #define VT8500_RTC_CR_24H (1 << 1) /* 24h time format */ | ||
| 73 | #define VT8500_RTC_CR_SM_ENABLE (1 << 2) /* Enable periodic irqs */ | ||
| 74 | #define VT8500_RTC_CR_SM_SEC (1 << 3) /* 0: 1Hz/60, 1: 1Hz */ | ||
| 75 | #define VT8500_RTC_CR_CALIB (1 << 4) /* Enable calibration */ | ||
| 76 | |||
| 77 | struct vt8500_rtc { | ||
| 78 | void __iomem *regbase; | ||
| 79 | struct resource *res; | ||
| 80 | int irq_alarm; | ||
| 81 | int irq_hz; | ||
| 82 | struct rtc_device *rtc; | ||
| 83 | spinlock_t lock; /* Protects this structure */ | ||
| 84 | }; | ||
| 85 | |||
| 86 | static irqreturn_t vt8500_rtc_irq(int irq, void *dev_id) | ||
| 87 | { | ||
| 88 | struct vt8500_rtc *vt8500_rtc = dev_id; | ||
| 89 | u32 isr; | ||
| 90 | unsigned long events = 0; | ||
| 91 | |||
| 92 | spin_lock(&vt8500_rtc->lock); | ||
| 93 | |||
| 94 | /* clear interrupt sources */ | ||
| 95 | isr = readl(vt8500_rtc->regbase + VT8500_RTC_IS); | ||
| 96 | writel(isr, vt8500_rtc->regbase + VT8500_RTC_IS); | ||
| 97 | |||
| 98 | spin_unlock(&vt8500_rtc->lock); | ||
| 99 | |||
| 100 | if (isr & 1) | ||
| 101 | events |= RTC_AF | RTC_IRQF; | ||
| 102 | |||
| 103 | /* Only second/minute interrupts are supported */ | ||
| 104 | if (isr & 2) | ||
| 105 | events |= RTC_UF | RTC_IRQF; | ||
| 106 | |||
| 107 | rtc_update_irq(vt8500_rtc->rtc, 1, events); | ||
| 108 | |||
| 109 | return IRQ_HANDLED; | ||
| 110 | } | ||
| 111 | |||
| 112 | static int vt8500_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
| 113 | { | ||
| 114 | struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev); | ||
| 115 | u32 date, time; | ||
| 116 | |||
| 117 | date = readl(vt8500_rtc->regbase + VT8500_RTC_DR); | ||
| 118 | time = readl(vt8500_rtc->regbase + VT8500_RTC_TR); | ||
| 119 | |||
| 120 | tm->tm_sec = bcd2bin(time & TIME_SEC_MASK); | ||
| 121 | tm->tm_min = bcd2bin((time & TIME_MIN_MASK) >> TIME_MIN_S); | ||
| 122 | tm->tm_hour = bcd2bin((time & TIME_HOUR_MASK) >> TIME_HOUR_S); | ||
| 123 | tm->tm_mday = bcd2bin(date & DATE_DAY_MASK); | ||
| 124 | tm->tm_mon = bcd2bin((date & DATE_MONTH_MASK) >> DATE_MONTH_S); | ||
| 125 | tm->tm_year = bcd2bin((date & DATE_YEAR_MASK) >> DATE_YEAR_S) | ||
| 126 | + ((date >> DATE_CENTURY_S) & 1 ? 200 : 100); | ||
| 127 | tm->tm_wday = (time & TIME_DOW_MASK) >> TIME_DOW_S; | ||
| 128 | |||
| 129 | return 0; | ||
| 130 | } | ||
| 131 | |||
| 132 | static int vt8500_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
| 133 | { | ||
| 134 | struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev); | ||
| 135 | |||
| 136 | if (tm->tm_year < 100) { | ||
| 137 | dev_warn(dev, "Only years 2000-2199 are supported by the " | ||
| 138 | "hardware!\n"); | ||
| 139 | return -EINVAL; | ||
| 140 | } | ||
| 141 | |||
| 142 | writel((bin2bcd(tm->tm_year - 100) << DATE_YEAR_S) | ||
| 143 | | (bin2bcd(tm->tm_mon) << DATE_MONTH_S) | ||
| 144 | | (bin2bcd(tm->tm_mday)), | ||
| 145 | vt8500_rtc->regbase + VT8500_RTC_DS); | ||
| 146 | writel((bin2bcd(tm->tm_wday) << TIME_DOW_S) | ||
| 147 | | (bin2bcd(tm->tm_hour) << TIME_HOUR_S) | ||
| 148 | | (bin2bcd(tm->tm_min) << TIME_MIN_S) | ||
| 149 | | (bin2bcd(tm->tm_sec)), | ||
| 150 | vt8500_rtc->regbase + VT8500_RTC_TS); | ||
| 151 | |||
| 152 | return 0; | ||
| 153 | } | ||
| 154 | |||
| 155 | static int vt8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
| 156 | { | ||
| 157 | struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev); | ||
| 158 | u32 isr, alarm; | ||
| 159 | |||
| 160 | alarm = readl(vt8500_rtc->regbase + VT8500_RTC_AS); | ||
| 161 | isr = readl(vt8500_rtc->regbase + VT8500_RTC_IS); | ||
| 162 | |||
| 163 | alrm->time.tm_mday = bcd2bin((alarm & ALARM_DAY_MASK) >> ALARM_DAY_S); | ||
| 164 | alrm->time.tm_hour = bcd2bin((alarm & TIME_HOUR_MASK) >> TIME_HOUR_S); | ||
| 165 | alrm->time.tm_min = bcd2bin((alarm & TIME_MIN_MASK) >> TIME_MIN_S); | ||
| 166 | alrm->time.tm_sec = bcd2bin((alarm & TIME_SEC_MASK)); | ||
| 167 | |||
| 168 | alrm->enabled = (alarm & ALARM_ENABLE_MASK) ? 1 : 0; | ||
| 169 | |||
| 170 | alrm->pending = (isr & 1) ? 1 : 0; | ||
| 171 | return rtc_valid_tm(&alrm->time); | ||
| 172 | } | ||
| 173 | |||
| 174 | static int vt8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
| 175 | { | ||
| 176 | struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev); | ||
| 177 | |||
| 178 | writel((alrm->enabled ? ALARM_ENABLE_MASK : 0) | ||
| 179 | | (bin2bcd(alrm->time.tm_mday) << ALARM_DAY_S) | ||
| 180 | | (bin2bcd(alrm->time.tm_hour) << TIME_HOUR_S) | ||
| 181 | | (bin2bcd(alrm->time.tm_min) << TIME_MIN_S) | ||
| 182 | | (bin2bcd(alrm->time.tm_sec)), | ||
| 183 | vt8500_rtc->regbase + VT8500_RTC_AS); | ||
| 184 | |||
| 185 | return 0; | ||
| 186 | } | ||
| 187 | |||
| 188 | static int vt8500_alarm_irq_enable(struct device *dev, unsigned int enabled) | ||
| 189 | { | ||
| 190 | struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev); | ||
| 191 | unsigned long tmp = readl(vt8500_rtc->regbase + VT8500_RTC_AS); | ||
| 192 | |||
| 193 | if (enabled) | ||
| 194 | tmp |= ALARM_ENABLE_MASK; | ||
| 195 | else | ||
| 196 | tmp &= ~ALARM_ENABLE_MASK; | ||
| 197 | |||
| 198 | writel(tmp, vt8500_rtc->regbase + VT8500_RTC_AS); | ||
| 199 | return 0; | ||
| 200 | } | ||
| 201 | |||
| 202 | static int vt8500_update_irq_enable(struct device *dev, unsigned int enabled) | ||
| 203 | { | ||
| 204 | struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev); | ||
| 205 | unsigned long tmp = readl(vt8500_rtc->regbase + VT8500_RTC_CR); | ||
| 206 | |||
| 207 | if (enabled) | ||
| 208 | tmp |= VT8500_RTC_CR_SM_SEC | VT8500_RTC_CR_SM_ENABLE; | ||
| 209 | else | ||
| 210 | tmp &= ~VT8500_RTC_CR_SM_ENABLE; | ||
| 211 | |||
| 212 | writel(tmp, vt8500_rtc->regbase + VT8500_RTC_CR); | ||
| 213 | return 0; | ||
| 214 | } | ||
| 215 | |||
| 216 | static const struct rtc_class_ops vt8500_rtc_ops = { | ||
| 217 | .read_time = vt8500_rtc_read_time, | ||
| 218 | .set_time = vt8500_rtc_set_time, | ||
| 219 | .read_alarm = vt8500_rtc_read_alarm, | ||
| 220 | .set_alarm = vt8500_rtc_set_alarm, | ||
| 221 | .alarm_irq_enable = vt8500_alarm_irq_enable, | ||
| 222 | .update_irq_enable = vt8500_update_irq_enable, | ||
| 223 | }; | ||
| 224 | |||
| 225 | static int __devinit vt8500_rtc_probe(struct platform_device *pdev) | ||
| 226 | { | ||
| 227 | struct vt8500_rtc *vt8500_rtc; | ||
| 228 | int ret; | ||
| 229 | |||
| 230 | vt8500_rtc = kzalloc(sizeof(struct vt8500_rtc), GFP_KERNEL); | ||
| 231 | if (!vt8500_rtc) | ||
| 232 | return -ENOMEM; | ||
| 233 | |||
| 234 | spin_lock_init(&vt8500_rtc->lock); | ||
| 235 | platform_set_drvdata(pdev, vt8500_rtc); | ||
| 236 | |||
| 237 | vt8500_rtc->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 238 | if (!vt8500_rtc->res) { | ||
| 239 | dev_err(&pdev->dev, "No I/O memory resource defined\n"); | ||
| 240 | ret = -ENXIO; | ||
| 241 | goto err_free; | ||
| 242 | } | ||
| 243 | |||
| 244 | vt8500_rtc->irq_alarm = platform_get_irq(pdev, 0); | ||
| 245 | if (vt8500_rtc->irq_alarm < 0) { | ||
| 246 | dev_err(&pdev->dev, "No alarm IRQ resource defined\n"); | ||
| 247 | ret = -ENXIO; | ||
| 248 | goto err_free; | ||
| 249 | } | ||
| 250 | |||
| 251 | vt8500_rtc->irq_hz = platform_get_irq(pdev, 1); | ||
| 252 | if (vt8500_rtc->irq_hz < 0) { | ||
| 253 | dev_err(&pdev->dev, "No 1Hz IRQ resource defined\n"); | ||
| 254 | ret = -ENXIO; | ||
| 255 | goto err_free; | ||
| 256 | } | ||
| 257 | |||
| 258 | vt8500_rtc->res = request_mem_region(vt8500_rtc->res->start, | ||
| 259 | resource_size(vt8500_rtc->res), | ||
| 260 | "vt8500-rtc"); | ||
| 261 | if (vt8500_rtc->res == NULL) { | ||
| 262 | dev_err(&pdev->dev, "failed to request I/O memory\n"); | ||
| 263 | ret = -EBUSY; | ||
| 264 | goto err_free; | ||
| 265 | } | ||
| 266 | |||
| 267 | vt8500_rtc->regbase = ioremap(vt8500_rtc->res->start, | ||
| 268 | resource_size(vt8500_rtc->res)); | ||
| 269 | if (!vt8500_rtc->regbase) { | ||
| 270 | dev_err(&pdev->dev, "Unable to map RTC I/O memory\n"); | ||
| 271 | ret = -EBUSY; | ||
| 272 | goto err_release; | ||
| 273 | } | ||
| 274 | |||
| 275 | /* Enable the second/minute interrupt generation and enable RTC */ | ||
| 276 | writel(VT8500_RTC_CR_ENABLE | VT8500_RTC_CR_24H | ||
| 277 | | VT8500_RTC_CR_SM_ENABLE | VT8500_RTC_CR_SM_SEC, | ||
| 278 | vt8500_rtc->regbase + VT8500_RTC_CR); | ||
| 279 | |||
| 280 | vt8500_rtc->rtc = rtc_device_register("vt8500-rtc", &pdev->dev, | ||
| 281 | &vt8500_rtc_ops, THIS_MODULE); | ||
| 282 | if (IS_ERR(vt8500_rtc->rtc)) { | ||
| 283 | ret = PTR_ERR(vt8500_rtc->rtc); | ||
| 284 | dev_err(&pdev->dev, | ||
| 285 | "Failed to register RTC device -> %d\n", ret); | ||
| 286 | goto err_unmap; | ||
| 287 | } | ||
| 288 | |||
| 289 | ret = request_irq(vt8500_rtc->irq_hz, vt8500_rtc_irq, 0, | ||
| 290 | "rtc 1Hz", vt8500_rtc); | ||
| 291 | if (ret < 0) { | ||
| 292 | dev_err(&pdev->dev, "can't get irq %i, err %d\n", | ||
| 293 | vt8500_rtc->irq_hz, ret); | ||
| 294 | goto err_unreg; | ||
| 295 | } | ||
| 296 | |||
| 297 | ret = request_irq(vt8500_rtc->irq_alarm, vt8500_rtc_irq, 0, | ||
| 298 | "rtc alarm", vt8500_rtc); | ||
| 299 | if (ret < 0) { | ||
| 300 | dev_err(&pdev->dev, "can't get irq %i, err %d\n", | ||
| 301 | vt8500_rtc->irq_alarm, ret); | ||
| 302 | goto err_free_hz; | ||
| 303 | } | ||
| 304 | |||
| 305 | return 0; | ||
| 306 | |||
| 307 | err_free_hz: | ||
| 308 | free_irq(vt8500_rtc->irq_hz, vt8500_rtc); | ||
| 309 | err_unreg: | ||
| 310 | rtc_device_unregister(vt8500_rtc->rtc); | ||
| 311 | err_unmap: | ||
| 312 | iounmap(vt8500_rtc->regbase); | ||
| 313 | err_release: | ||
| 314 | release_mem_region(vt8500_rtc->res->start, | ||
| 315 | resource_size(vt8500_rtc->res)); | ||
| 316 | err_free: | ||
| 317 | kfree(vt8500_rtc); | ||
| 318 | return ret; | ||
| 319 | } | ||
| 320 | |||
| 321 | static int __devexit vt8500_rtc_remove(struct platform_device *pdev) | ||
| 322 | { | ||
| 323 | struct vt8500_rtc *vt8500_rtc = platform_get_drvdata(pdev); | ||
| 324 | |||
| 325 | free_irq(vt8500_rtc->irq_alarm, vt8500_rtc); | ||
| 326 | free_irq(vt8500_rtc->irq_hz, vt8500_rtc); | ||
| 327 | |||
| 328 | rtc_device_unregister(vt8500_rtc->rtc); | ||
| 329 | |||
| 330 | /* Disable alarm matching */ | ||
| 331 | writel(0, vt8500_rtc->regbase + VT8500_RTC_IS); | ||
| 332 | iounmap(vt8500_rtc->regbase); | ||
| 333 | release_mem_region(vt8500_rtc->res->start, | ||
| 334 | resource_size(vt8500_rtc->res)); | ||
| 335 | |||
| 336 | kfree(vt8500_rtc); | ||
| 337 | platform_set_drvdata(pdev, NULL); | ||
| 338 | |||
| 339 | return 0; | ||
| 340 | } | ||
| 341 | |||
| 342 | static struct platform_driver vt8500_rtc_driver = { | ||
| 343 | .probe = vt8500_rtc_probe, | ||
| 344 | .remove = __devexit_p(vt8500_rtc_remove), | ||
| 345 | .driver = { | ||
| 346 | .name = "vt8500-rtc", | ||
| 347 | .owner = THIS_MODULE, | ||
| 348 | }, | ||
| 349 | }; | ||
| 350 | |||
| 351 | static int __init vt8500_rtc_init(void) | ||
| 352 | { | ||
| 353 | return platform_driver_register(&vt8500_rtc_driver); | ||
| 354 | } | ||
| 355 | module_init(vt8500_rtc_init); | ||
| 356 | |||
| 357 | static void __exit vt8500_rtc_exit(void) | ||
| 358 | { | ||
| 359 | platform_driver_unregister(&vt8500_rtc_driver); | ||
| 360 | } | ||
| 361 | module_exit(vt8500_rtc_exit); | ||
| 362 | |||
| 363 | MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>"); | ||
| 364 | MODULE_DESCRIPTION("VIA VT8500 SoC Realtime Clock Driver (RTC)"); | ||
| 365 | MODULE_LICENSE("GPL"); | ||
| 366 | MODULE_ALIAS("platform:vt8500-rtc"); | ||
