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"); | ||