diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2009-09-24 16:22:33 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2009-09-24 16:22:33 -0400 |
commit | baea7b946f00a291b166ccae7fcfed6c01530cc6 (patch) | |
tree | 4aa275fbdbec9c7b9b4629e8bee2bbecd3c6a6af /drivers/rtc | |
parent | ae19ffbadc1b2100285a5b5b3d0a4e0a11390904 (diff) | |
parent | 94e0fb086fc5663c38bbc0fe86d698be8314f82f (diff) |
Merge branch 'origin' into for-linus
Conflicts:
MAINTAINERS
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/Kconfig | 68 | ||||
-rw-r--r-- | drivers/rtc/Makefile | 19 | ||||
-rw-r--r-- | drivers/rtc/rtc-ab3100.c | 281 | ||||
-rw-r--r-- | drivers/rtc/rtc-at91rm9200.c | 24 | ||||
-rw-r--r-- | drivers/rtc/rtc-bfin.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-coh901331.c | 311 | ||||
-rw-r--r-- | drivers/rtc/rtc-ds1302.c | 69 | ||||
-rw-r--r-- | drivers/rtc/rtc-ds1305.c | 1 | ||||
-rw-r--r-- | drivers/rtc/rtc-ds1307.c | 3 | ||||
-rw-r--r-- | drivers/rtc/rtc-ds1390.c | 1 | ||||
-rw-r--r-- | drivers/rtc/rtc-ds3234.c | 1 | ||||
-rw-r--r-- | drivers/rtc/rtc-ep93xx.c | 14 | ||||
-rw-r--r-- | drivers/rtc/rtc-m41t94.c | 1 | ||||
-rw-r--r-- | drivers/rtc/rtc-max6902.c | 1 | ||||
-rw-r--r-- | drivers/rtc/rtc-mxc.c | 507 | ||||
-rw-r--r-- | drivers/rtc/rtc-omap.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-pcap.c | 224 | ||||
-rw-r--r-- | drivers/rtc/rtc-pcf2123.c | 364 | ||||
-rw-r--r-- | drivers/rtc/rtc-r9701.c | 1 | ||||
-rw-r--r-- | drivers/rtc/rtc-rs5c348.c | 1 | ||||
-rw-r--r-- | drivers/rtc/rtc-sh.c | 97 | ||||
-rw-r--r-- | drivers/rtc/rtc-stmp3xxx.c | 304 | ||||
-rw-r--r-- | drivers/rtc/rtc-sysfs.c | 14 | ||||
-rw-r--r-- | drivers/rtc/rtc-wm831x.c | 523 |
24 files changed, 2692 insertions, 141 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 81adbdbd5042..3c20dae43ce2 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
@@ -378,6 +378,15 @@ config RTC_DRV_DS3234 | |||
378 | This driver can also be built as a module. If so, the module | 378 | This driver can also be built as a module. If so, the module |
379 | will be called rtc-ds3234. | 379 | will be called rtc-ds3234. |
380 | 380 | ||
381 | config RTC_DRV_PCF2123 | ||
382 | tristate "NXP PCF2123" | ||
383 | help | ||
384 | If you say yes here you get support for the NXP PCF2123 | ||
385 | RTC chip. | ||
386 | |||
387 | This driver can also be built as a module. If so, the module | ||
388 | will be called rtc-pcf2123. | ||
389 | |||
381 | endif # SPI_MASTER | 390 | endif # SPI_MASTER |
382 | 391 | ||
383 | comment "Platform RTC drivers" | 392 | comment "Platform RTC drivers" |
@@ -500,6 +509,17 @@ config RTC_DRV_M48T59 | |||
500 | This driver can also be built as a module, if so, the module | 509 | This driver can also be built as a module, if so, the module |
501 | will be called "rtc-m48t59". | 510 | will be called "rtc-m48t59". |
502 | 511 | ||
512 | config RTC_MXC | ||
513 | tristate "Freescale MXC Real Time Clock" | ||
514 | depends on ARCH_MXC | ||
515 | depends on RTC_CLASS | ||
516 | help | ||
517 | If you say yes here you get support for the Freescale MXC | ||
518 | RTC module. | ||
519 | |||
520 | This driver can also be built as a module, if so, the module | ||
521 | will be called "rtc-mxc". | ||
522 | |||
503 | config RTC_DRV_BQ4802 | 523 | config RTC_DRV_BQ4802 |
504 | tristate "TI BQ4802" | 524 | tristate "TI BQ4802" |
505 | help | 525 | help |
@@ -518,6 +538,16 @@ config RTC_DRV_V3020 | |||
518 | This driver can also be built as a module. If so, the module | 538 | This driver can also be built as a module. If so, the module |
519 | will be called rtc-v3020. | 539 | will be called rtc-v3020. |
520 | 540 | ||
541 | config RTC_DRV_WM831X | ||
542 | tristate "Wolfson Microelectronics WM831x RTC" | ||
543 | depends on MFD_WM831X | ||
544 | help | ||
545 | If you say yes here you will get support for the RTC subsystem | ||
546 | of the Wolfson Microelectronics WM831X series PMICs. | ||
547 | |||
548 | This driver can also be built as a module. If so, the module | ||
549 | will be called "rtc-wm831x". | ||
550 | |||
521 | config RTC_DRV_WM8350 | 551 | config RTC_DRV_WM8350 |
522 | tristate "Wolfson Microelectronics WM8350 RTC" | 552 | tristate "Wolfson Microelectronics WM8350 RTC" |
523 | depends on MFD_WM8350 | 553 | depends on MFD_WM8350 |
@@ -535,6 +565,15 @@ config RTC_DRV_PCF50633 | |||
535 | If you say yes here you get support for the RTC subsystem of the | 565 | If you say yes here you get support for the RTC subsystem of the |
536 | NXP PCF50633 used in embedded systems. | 566 | NXP PCF50633 used in embedded systems. |
537 | 567 | ||
568 | config RTC_DRV_AB3100 | ||
569 | tristate "ST-Ericsson AB3100 RTC" | ||
570 | depends on AB3100_CORE | ||
571 | default y if AB3100_CORE | ||
572 | help | ||
573 | Select this to enable the ST-Ericsson AB3100 Mixed Signal IC RTC | ||
574 | support. This chip contains a battery- and capacitor-backed RTC. | ||
575 | |||
576 | |||
538 | comment "on-CPU RTC drivers" | 577 | comment "on-CPU RTC drivers" |
539 | 578 | ||
540 | config RTC_DRV_OMAP | 579 | config RTC_DRV_OMAP |
@@ -759,4 +798,33 @@ config RTC_DRV_PS3 | |||
759 | This driver can also be built as a module. If so, the module | 798 | This driver can also be built as a module. If so, the module |
760 | will be called rtc-ps3. | 799 | will be called rtc-ps3. |
761 | 800 | ||
801 | config RTC_DRV_COH901331 | ||
802 | tristate "ST-Ericsson COH 901 331 RTC" | ||
803 | depends on ARCH_U300 | ||
804 | help | ||
805 | If you say Y here you will get access to ST-Ericsson | ||
806 | COH 901 331 RTC clock found in some ST-Ericsson Mobile | ||
807 | Platforms. | ||
808 | |||
809 | This driver can also be built as a module. If so, the module | ||
810 | will be called "rtc-coh901331". | ||
811 | |||
812 | |||
813 | config RTC_DRV_STMP | ||
814 | tristate "Freescale STMP3xxx RTC" | ||
815 | depends on ARCH_STMP3XXX | ||
816 | help | ||
817 | If you say yes here you will get support for the onboard | ||
818 | STMP3xxx RTC. | ||
819 | |||
820 | This driver can also be built as a module. If so, the module | ||
821 | will be called rtc-stmp3xxx. | ||
822 | |||
823 | config RTC_DRV_PCAP | ||
824 | tristate "PCAP RTC" | ||
825 | depends on EZX_PCAP | ||
826 | help | ||
827 | If you say Y here you will get support for the RTC found on | ||
828 | the PCAP2 ASIC used on some Motorola phones. | ||
829 | |||
762 | endif # RTC_CLASS | 830 | endif # RTC_CLASS |
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 3c0f2b2ac927..aa3fbd5517a1 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile | |||
@@ -17,12 +17,15 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o | |||
17 | 17 | ||
18 | # Keep the list ordered. | 18 | # Keep the list ordered. |
19 | 19 | ||
20 | obj-$(CONFIG_RTC_DRV_AB3100) += rtc-ab3100.o | ||
20 | obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o | 21 | obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o |
21 | obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o | 22 | obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o |
22 | obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o | 23 | obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o |
23 | obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o | 24 | obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o |
24 | obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o | 25 | obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o |
26 | obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o | ||
25 | obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o | 27 | obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o |
28 | obj-$(CONFIG_RTC_DRV_COH901331) += rtc-coh901331.o | ||
26 | obj-$(CONFIG_RTC_DRV_DM355EVM) += rtc-dm355evm.o | 29 | obj-$(CONFIG_RTC_DRV_DM355EVM) += rtc-dm355evm.o |
27 | obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o | 30 | obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o |
28 | obj-$(CONFIG_RTC_DRV_DS1286) += rtc-ds1286.o | 31 | obj-$(CONFIG_RTC_DRV_DS1286) += rtc-ds1286.o |
@@ -39,24 +42,26 @@ obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o | |||
39 | obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o | 42 | obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o |
40 | obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o | 43 | obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o |
41 | obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o | 44 | obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o |
45 | obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o | ||
42 | obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o | 46 | obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o |
43 | obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o | 47 | obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o |
44 | obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o | 48 | obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o |
45 | obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o | 49 | obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o |
46 | obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o | 50 | obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o |
47 | obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o | 51 | obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o |
48 | obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o | 52 | obj-$(CONFIG_RTC_MXC) += rtc-mxc.o |
49 | obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o | ||
50 | obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o | ||
51 | obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o | 53 | obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o |
52 | obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o | 54 | obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o |
53 | obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o | 55 | obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o |
54 | obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o | 56 | obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o |
57 | obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.o | ||
55 | obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o | 58 | obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o |
56 | obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o | 59 | obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o |
60 | obj-$(CONFIG_RTC_DRV_PCF2123) += rtc-pcf2123.o | ||
61 | obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o | ||
57 | obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o | 62 | obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o |
58 | obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o | 63 | obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o |
59 | obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o | 64 | obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o |
60 | obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o | 65 | obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o |
61 | obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o | 66 | obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o |
62 | obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o | 67 | obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o |
@@ -68,13 +73,15 @@ obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o | |||
68 | obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o | 73 | obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o |
69 | obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o | 74 | obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o |
70 | obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o | 75 | obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o |
76 | obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o | ||
71 | obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o | 77 | obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o |
78 | obj-$(CONFIG_RTC_DRV_STMP) += rtc-stmp3xxx.o | ||
79 | obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o | ||
72 | obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o | 80 | obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o |
73 | obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl4030.o | 81 | obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl4030.o |
74 | obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o | 82 | obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o |
75 | obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o | 83 | obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o |
76 | obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o | 84 | obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o |
85 | obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o | ||
77 | obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o | 86 | obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o |
78 | obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o | 87 | obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o |
79 | obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o | ||
80 | obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o | ||
diff --git a/drivers/rtc/rtc-ab3100.c b/drivers/rtc/rtc-ab3100.c new file mode 100644 index 000000000000..4704aac2b5af --- /dev/null +++ b/drivers/rtc/rtc-ab3100.c | |||
@@ -0,0 +1,281 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2009 ST-Ericsson AB | ||
3 | * License terms: GNU General Public License (GPL) version 2 | ||
4 | * RTC clock driver for the AB3100 Analog Baseband Chip | ||
5 | * Author: Linus Walleij <linus.walleij@stericsson.com> | ||
6 | */ | ||
7 | #include <linux/module.h> | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/platform_device.h> | ||
11 | #include <linux/rtc.h> | ||
12 | #include <linux/mfd/ab3100.h> | ||
13 | |||
14 | /* Clock rate in Hz */ | ||
15 | #define AB3100_RTC_CLOCK_RATE 32768 | ||
16 | |||
17 | /* | ||
18 | * The AB3100 RTC registers. These are the same for | ||
19 | * AB3000 and AB3100. | ||
20 | * Control register: | ||
21 | * Bit 0: RTC Monitor cleared=0, active=1, if you set it | ||
22 | * to 1 it remains active until RTC power is lost. | ||
23 | * Bit 1: 32 kHz Oscillator, 0 = on, 1 = bypass | ||
24 | * Bit 2: Alarm on, 0 = off, 1 = on | ||
25 | * Bit 3: 32 kHz buffer disabling, 0 = enabled, 1 = disabled | ||
26 | */ | ||
27 | #define AB3100_RTC 0x53 | ||
28 | /* default setting, buffer disabled, alarm on */ | ||
29 | #define RTC_SETTING 0x30 | ||
30 | /* Alarm when AL0-AL3 == TI0-TI3 */ | ||
31 | #define AB3100_AL0 0x56 | ||
32 | #define AB3100_AL1 0x57 | ||
33 | #define AB3100_AL2 0x58 | ||
34 | #define AB3100_AL3 0x59 | ||
35 | /* This 48-bit register that counts up at 32768 Hz */ | ||
36 | #define AB3100_TI0 0x5a | ||
37 | #define AB3100_TI1 0x5b | ||
38 | #define AB3100_TI2 0x5c | ||
39 | #define AB3100_TI3 0x5d | ||
40 | #define AB3100_TI4 0x5e | ||
41 | #define AB3100_TI5 0x5f | ||
42 | |||
43 | /* | ||
44 | * RTC clock functions and device struct declaration | ||
45 | */ | ||
46 | static int ab3100_rtc_set_mmss(struct device *dev, unsigned long secs) | ||
47 | { | ||
48 | struct ab3100 *ab3100_data = dev_get_drvdata(dev); | ||
49 | u8 regs[] = {AB3100_TI0, AB3100_TI1, AB3100_TI2, | ||
50 | AB3100_TI3, AB3100_TI4, AB3100_TI5}; | ||
51 | unsigned char buf[6]; | ||
52 | u64 fat_time = (u64) secs * AB3100_RTC_CLOCK_RATE * 2; | ||
53 | int err = 0; | ||
54 | int i; | ||
55 | |||
56 | buf[0] = (fat_time) & 0xFF; | ||
57 | buf[1] = (fat_time >> 8) & 0xFF; | ||
58 | buf[2] = (fat_time >> 16) & 0xFF; | ||
59 | buf[3] = (fat_time >> 24) & 0xFF; | ||
60 | buf[4] = (fat_time >> 32) & 0xFF; | ||
61 | buf[5] = (fat_time >> 40) & 0xFF; | ||
62 | |||
63 | for (i = 0; i < 6; i++) { | ||
64 | err = ab3100_set_register_interruptible(ab3100_data, | ||
65 | regs[i], buf[i]); | ||
66 | if (err) | ||
67 | return err; | ||
68 | } | ||
69 | |||
70 | /* Set the flag to mark that the clock is now set */ | ||
71 | return ab3100_mask_and_set_register_interruptible(ab3100_data, | ||
72 | AB3100_RTC, | ||
73 | 0xFE, 0x01); | ||
74 | |||
75 | } | ||
76 | |||
77 | static int ab3100_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
78 | { | ||
79 | struct ab3100 *ab3100_data = dev_get_drvdata(dev); | ||
80 | unsigned long time; | ||
81 | u8 rtcval; | ||
82 | int err; | ||
83 | |||
84 | err = ab3100_get_register_interruptible(ab3100_data, | ||
85 | AB3100_RTC, &rtcval); | ||
86 | if (err) | ||
87 | return err; | ||
88 | |||
89 | if (!(rtcval & 0x01)) { | ||
90 | dev_info(dev, "clock not set (lost power)"); | ||
91 | return -EINVAL; | ||
92 | } else { | ||
93 | u64 fat_time; | ||
94 | u8 buf[6]; | ||
95 | |||
96 | /* Read out time registers */ | ||
97 | err = ab3100_get_register_page_interruptible(ab3100_data, | ||
98 | AB3100_TI0, | ||
99 | buf, 6); | ||
100 | if (err != 0) | ||
101 | return err; | ||
102 | |||
103 | fat_time = ((u64) buf[5] << 40) | ((u64) buf[4] << 32) | | ||
104 | ((u64) buf[3] << 24) | ((u64) buf[2] << 16) | | ||
105 | ((u64) buf[1] << 8) | (u64) buf[0]; | ||
106 | time = (unsigned long) (fat_time / | ||
107 | (u64) (AB3100_RTC_CLOCK_RATE * 2)); | ||
108 | } | ||
109 | |||
110 | rtc_time_to_tm(time, tm); | ||
111 | |||
112 | return rtc_valid_tm(tm); | ||
113 | } | ||
114 | |||
115 | static int ab3100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) | ||
116 | { | ||
117 | struct ab3100 *ab3100_data = dev_get_drvdata(dev); | ||
118 | unsigned long time; | ||
119 | u64 fat_time; | ||
120 | u8 buf[6]; | ||
121 | u8 rtcval; | ||
122 | int err; | ||
123 | |||
124 | /* Figure out if alarm is enabled or not */ | ||
125 | err = ab3100_get_register_interruptible(ab3100_data, | ||
126 | AB3100_RTC, &rtcval); | ||
127 | if (err) | ||
128 | return err; | ||
129 | if (rtcval & 0x04) | ||
130 | alarm->enabled = 1; | ||
131 | else | ||
132 | alarm->enabled = 0; | ||
133 | /* No idea how this could be represented */ | ||
134 | alarm->pending = 0; | ||
135 | /* Read out alarm registers, only 4 bytes */ | ||
136 | err = ab3100_get_register_page_interruptible(ab3100_data, | ||
137 | AB3100_AL0, buf, 4); | ||
138 | if (err) | ||
139 | return err; | ||
140 | fat_time = ((u64) buf[3] << 40) | ((u64) buf[2] << 32) | | ||
141 | ((u64) buf[1] << 24) | ((u64) buf[0] << 16); | ||
142 | time = (unsigned long) (fat_time / (u64) (AB3100_RTC_CLOCK_RATE * 2)); | ||
143 | |||
144 | rtc_time_to_tm(time, &alarm->time); | ||
145 | |||
146 | return rtc_valid_tm(&alarm->time); | ||
147 | } | ||
148 | |||
149 | static int ab3100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) | ||
150 | { | ||
151 | struct ab3100 *ab3100_data = dev_get_drvdata(dev); | ||
152 | u8 regs[] = {AB3100_AL0, AB3100_AL1, AB3100_AL2, AB3100_AL3}; | ||
153 | unsigned char buf[4]; | ||
154 | unsigned long secs; | ||
155 | u64 fat_time; | ||
156 | int err; | ||
157 | int i; | ||
158 | |||
159 | rtc_tm_to_time(&alarm->time, &secs); | ||
160 | fat_time = (u64) secs * AB3100_RTC_CLOCK_RATE * 2; | ||
161 | buf[0] = (fat_time >> 16) & 0xFF; | ||
162 | buf[1] = (fat_time >> 24) & 0xFF; | ||
163 | buf[2] = (fat_time >> 32) & 0xFF; | ||
164 | buf[3] = (fat_time >> 40) & 0xFF; | ||
165 | |||
166 | /* Set the alarm */ | ||
167 | for (i = 0; i < 4; i++) { | ||
168 | err = ab3100_set_register_interruptible(ab3100_data, | ||
169 | regs[i], buf[i]); | ||
170 | if (err) | ||
171 | return err; | ||
172 | } | ||
173 | /* Then enable the alarm */ | ||
174 | return ab3100_mask_and_set_register_interruptible(ab3100_data, | ||
175 | AB3100_RTC, ~(1 << 2), | ||
176 | alarm->enabled << 2); | ||
177 | } | ||
178 | |||
179 | static int ab3100_rtc_irq_enable(struct device *dev, unsigned int enabled) | ||
180 | { | ||
181 | struct ab3100 *ab3100_data = dev_get_drvdata(dev); | ||
182 | |||
183 | /* | ||
184 | * It's not possible to enable/disable the alarm IRQ for this RTC. | ||
185 | * It does not actually trigger any IRQ: instead its only function is | ||
186 | * to power up the system, if it wasn't on. This will manifest as | ||
187 | * a "power up cause" in the AB3100 power driver (battery charging etc) | ||
188 | * and need to be handled there instead. | ||
189 | */ | ||
190 | if (enabled) | ||
191 | return ab3100_mask_and_set_register_interruptible(ab3100_data, | ||
192 | AB3100_RTC, ~(1 << 2), | ||
193 | 1 << 2); | ||
194 | else | ||
195 | return ab3100_mask_and_set_register_interruptible(ab3100_data, | ||
196 | AB3100_RTC, ~(1 << 2), | ||
197 | 0); | ||
198 | } | ||
199 | |||
200 | static const struct rtc_class_ops ab3100_rtc_ops = { | ||
201 | .read_time = ab3100_rtc_read_time, | ||
202 | .set_mmss = ab3100_rtc_set_mmss, | ||
203 | .read_alarm = ab3100_rtc_read_alarm, | ||
204 | .set_alarm = ab3100_rtc_set_alarm, | ||
205 | .alarm_irq_enable = ab3100_rtc_irq_enable, | ||
206 | }; | ||
207 | |||
208 | static int __init ab3100_rtc_probe(struct platform_device *pdev) | ||
209 | { | ||
210 | int err; | ||
211 | u8 regval; | ||
212 | struct rtc_device *rtc; | ||
213 | struct ab3100 *ab3100_data = platform_get_drvdata(pdev); | ||
214 | |||
215 | /* The first RTC register needs special treatment */ | ||
216 | err = ab3100_get_register_interruptible(ab3100_data, | ||
217 | AB3100_RTC, ®val); | ||
218 | if (err) { | ||
219 | dev_err(&pdev->dev, "unable to read RTC register\n"); | ||
220 | return -ENODEV; | ||
221 | } | ||
222 | |||
223 | if ((regval & 0xFE) != RTC_SETTING) { | ||
224 | dev_warn(&pdev->dev, "not default value in RTC reg 0x%x\n", | ||
225 | regval); | ||
226 | } | ||
227 | |||
228 | if ((regval & 1) == 0) { | ||
229 | /* | ||
230 | * Set bit to detect power loss. | ||
231 | * This bit remains until RTC power is lost. | ||
232 | */ | ||
233 | regval = 1 | RTC_SETTING; | ||
234 | err = ab3100_set_register_interruptible(ab3100_data, | ||
235 | AB3100_RTC, regval); | ||
236 | /* Ignore any error on this write */ | ||
237 | } | ||
238 | |||
239 | rtc = rtc_device_register("ab3100-rtc", &pdev->dev, &ab3100_rtc_ops, | ||
240 | THIS_MODULE); | ||
241 | if (IS_ERR(rtc)) { | ||
242 | err = PTR_ERR(rtc); | ||
243 | return err; | ||
244 | } | ||
245 | |||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | static int __exit ab3100_rtc_remove(struct platform_device *pdev) | ||
250 | { | ||
251 | struct rtc_device *rtc = platform_get_drvdata(pdev); | ||
252 | |||
253 | rtc_device_unregister(rtc); | ||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | static struct platform_driver ab3100_rtc_driver = { | ||
258 | .driver = { | ||
259 | .name = "ab3100-rtc", | ||
260 | .owner = THIS_MODULE, | ||
261 | }, | ||
262 | .remove = __exit_p(ab3100_rtc_remove), | ||
263 | }; | ||
264 | |||
265 | static int __init ab3100_rtc_init(void) | ||
266 | { | ||
267 | return platform_driver_probe(&ab3100_rtc_driver, | ||
268 | ab3100_rtc_probe); | ||
269 | } | ||
270 | |||
271 | static void __exit ab3100_rtc_exit(void) | ||
272 | { | ||
273 | platform_driver_unregister(&ab3100_rtc_driver); | ||
274 | } | ||
275 | |||
276 | module_init(ab3100_rtc_init); | ||
277 | module_exit(ab3100_rtc_exit); | ||
278 | |||
279 | MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>"); | ||
280 | MODULE_DESCRIPTION("AB3100 RTC Driver"); | ||
281 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index b5bf93706913..bc8bbca9a2e2 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c | |||
@@ -289,7 +289,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev) | |||
289 | AT91_RTC_CALEV); | 289 | AT91_RTC_CALEV); |
290 | 290 | ||
291 | ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt, | 291 | ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt, |
292 | IRQF_DISABLED | IRQF_SHARED, | 292 | IRQF_SHARED, |
293 | "at91_rtc", pdev); | 293 | "at91_rtc", pdev); |
294 | if (ret) { | 294 | if (ret) { |
295 | printk(KERN_ERR "at91_rtc: IRQ %d already in use.\n", | 295 | printk(KERN_ERR "at91_rtc: IRQ %d already in use.\n", |
@@ -340,7 +340,7 @@ static int __exit at91_rtc_remove(struct platform_device *pdev) | |||
340 | 340 | ||
341 | static u32 at91_rtc_imr; | 341 | static u32 at91_rtc_imr; |
342 | 342 | ||
343 | static int at91_rtc_suspend(struct platform_device *pdev, pm_message_t state) | 343 | static int at91_rtc_suspend(struct device *dev) |
344 | { | 344 | { |
345 | /* this IRQ is shared with DBGU and other hardware which isn't | 345 | /* this IRQ is shared with DBGU and other hardware which isn't |
346 | * necessarily doing PM like we are... | 346 | * necessarily doing PM like we are... |
@@ -348,7 +348,7 @@ static int at91_rtc_suspend(struct platform_device *pdev, pm_message_t state) | |||
348 | at91_rtc_imr = at91_sys_read(AT91_RTC_IMR) | 348 | at91_rtc_imr = at91_sys_read(AT91_RTC_IMR) |
349 | & (AT91_RTC_ALARM|AT91_RTC_SECEV); | 349 | & (AT91_RTC_ALARM|AT91_RTC_SECEV); |
350 | if (at91_rtc_imr) { | 350 | if (at91_rtc_imr) { |
351 | if (device_may_wakeup(&pdev->dev)) | 351 | if (device_may_wakeup(dev)) |
352 | enable_irq_wake(AT91_ID_SYS); | 352 | enable_irq_wake(AT91_ID_SYS); |
353 | else | 353 | else |
354 | at91_sys_write(AT91_RTC_IDR, at91_rtc_imr); | 354 | at91_sys_write(AT91_RTC_IDR, at91_rtc_imr); |
@@ -356,28 +356,34 @@ static int at91_rtc_suspend(struct platform_device *pdev, pm_message_t state) | |||
356 | return 0; | 356 | return 0; |
357 | } | 357 | } |
358 | 358 | ||
359 | static int at91_rtc_resume(struct platform_device *pdev) | 359 | static int at91_rtc_resume(struct device *dev) |
360 | { | 360 | { |
361 | if (at91_rtc_imr) { | 361 | if (at91_rtc_imr) { |
362 | if (device_may_wakeup(&pdev->dev)) | 362 | if (device_may_wakeup(dev)) |
363 | disable_irq_wake(AT91_ID_SYS); | 363 | disable_irq_wake(AT91_ID_SYS); |
364 | else | 364 | else |
365 | at91_sys_write(AT91_RTC_IER, at91_rtc_imr); | 365 | at91_sys_write(AT91_RTC_IER, at91_rtc_imr); |
366 | } | 366 | } |
367 | return 0; | 367 | return 0; |
368 | } | 368 | } |
369 | |||
370 | static const struct dev_pm_ops at91_rtc_pm = { | ||
371 | .suspend = at91_rtc_suspend, | ||
372 | .resume = at91_rtc_resume, | ||
373 | }; | ||
374 | |||
375 | #define at91_rtc_pm_ptr &at91_rtc_pm | ||
376 | |||
369 | #else | 377 | #else |
370 | #define at91_rtc_suspend NULL | 378 | #define at91_rtc_pm_ptr NULL |
371 | #define at91_rtc_resume NULL | ||
372 | #endif | 379 | #endif |
373 | 380 | ||
374 | static struct platform_driver at91_rtc_driver = { | 381 | static struct platform_driver at91_rtc_driver = { |
375 | .remove = __exit_p(at91_rtc_remove), | 382 | .remove = __exit_p(at91_rtc_remove), |
376 | .suspend = at91_rtc_suspend, | ||
377 | .resume = at91_rtc_resume, | ||
378 | .driver = { | 383 | .driver = { |
379 | .name = "at91_rtc", | 384 | .name = "at91_rtc", |
380 | .owner = THIS_MODULE, | 385 | .owner = THIS_MODULE, |
386 | .pm = at91_rtc_pm_ptr, | ||
381 | }, | 387 | }, |
382 | }; | 388 | }; |
383 | 389 | ||
diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index a118eb0f1e67..b11485b9f21c 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c | |||
@@ -383,7 +383,7 @@ static int __devinit bfin_rtc_probe(struct platform_device *pdev) | |||
383 | } | 383 | } |
384 | 384 | ||
385 | /* Grab the IRQ and init the hardware */ | 385 | /* Grab the IRQ and init the hardware */ |
386 | ret = request_irq(IRQ_RTC, bfin_rtc_interrupt, IRQF_SHARED, pdev->name, dev); | 386 | ret = request_irq(IRQ_RTC, bfin_rtc_interrupt, 0, pdev->name, dev); |
387 | if (unlikely(ret)) | 387 | if (unlikely(ret)) |
388 | goto err_reg; | 388 | goto err_reg; |
389 | /* sometimes the bootloader touched things, but the write complete was not | 389 | /* sometimes the bootloader touched things, but the write complete was not |
diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c new file mode 100644 index 000000000000..7fe1fa26c52c --- /dev/null +++ b/drivers/rtc/rtc-coh901331.c | |||
@@ -0,0 +1,311 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2009 ST-Ericsson AB | ||
3 | * License terms: GNU General Public License (GPL) version 2 | ||
4 | * Real Time Clock interface for ST-Ericsson AB COH 901 331 RTC. | ||
5 | * Author: Linus Walleij <linus.walleij@stericsson.com> | ||
6 | * Based on rtc-pl031.c by Deepak Saxena <dsaxena@plexity.net> | ||
7 | * Copyright 2006 (c) MontaVista Software, Inc. | ||
8 | */ | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/rtc.h> | ||
12 | #include <linux/clk.h> | ||
13 | #include <linux/interrupt.h> | ||
14 | #include <linux/pm.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/io.h> | ||
17 | |||
18 | /* | ||
19 | * Registers in the COH 901 331 | ||
20 | */ | ||
21 | /* Alarm value 32bit (R/W) */ | ||
22 | #define COH901331_ALARM 0x00U | ||
23 | /* Used to set current time 32bit (R/W) */ | ||
24 | #define COH901331_SET_TIME 0x04U | ||
25 | /* Indication if current time is valid 32bit (R/-) */ | ||
26 | #define COH901331_VALID 0x08U | ||
27 | /* Read the current time 32bit (R/-) */ | ||
28 | #define COH901331_CUR_TIME 0x0cU | ||
29 | /* Event register for the "alarm" interrupt */ | ||
30 | #define COH901331_IRQ_EVENT 0x10U | ||
31 | /* Mask register for the "alarm" interrupt */ | ||
32 | #define COH901331_IRQ_MASK 0x14U | ||
33 | /* Force register for the "alarm" interrupt */ | ||
34 | #define COH901331_IRQ_FORCE 0x18U | ||
35 | |||
36 | /* | ||
37 | * Reference to RTC block clock | ||
38 | * Notice that the frequent clk_enable()/clk_disable() on this | ||
39 | * clock is mainly to be able to turn on/off other clocks in the | ||
40 | * hierarchy as needed, the RTC clock is always on anyway. | ||
41 | */ | ||
42 | struct coh901331_port { | ||
43 | struct rtc_device *rtc; | ||
44 | struct clk *clk; | ||
45 | u32 phybase; | ||
46 | u32 physize; | ||
47 | void __iomem *virtbase; | ||
48 | int irq; | ||
49 | #ifdef CONFIG_PM | ||
50 | u32 irqmaskstore; | ||
51 | #endif | ||
52 | }; | ||
53 | |||
54 | static irqreturn_t coh901331_interrupt(int irq, void *data) | ||
55 | { | ||
56 | struct coh901331_port *rtap = data; | ||
57 | |||
58 | clk_enable(rtap->clk); | ||
59 | /* Ack IRQ */ | ||
60 | writel(1, rtap->virtbase + COH901331_IRQ_EVENT); | ||
61 | clk_disable(rtap->clk); | ||
62 | /* Set alarm flag */ | ||
63 | rtc_update_irq(rtap->rtc, 1, RTC_AF); | ||
64 | |||
65 | return IRQ_HANDLED; | ||
66 | } | ||
67 | |||
68 | static int coh901331_read_time(struct device *dev, struct rtc_time *tm) | ||
69 | { | ||
70 | struct coh901331_port *rtap = dev_get_drvdata(dev); | ||
71 | |||
72 | clk_enable(rtap->clk); | ||
73 | /* Check if the time is valid */ | ||
74 | if (readl(rtap->virtbase + COH901331_VALID)) { | ||
75 | rtc_time_to_tm(readl(rtap->virtbase + COH901331_CUR_TIME), tm); | ||
76 | clk_disable(rtap->clk); | ||
77 | return rtc_valid_tm(tm); | ||
78 | } | ||
79 | clk_disable(rtap->clk); | ||
80 | return -EINVAL; | ||
81 | } | ||
82 | |||
83 | static int coh901331_set_mmss(struct device *dev, unsigned long secs) | ||
84 | { | ||
85 | struct coh901331_port *rtap = dev_get_drvdata(dev); | ||
86 | |||
87 | clk_enable(rtap->clk); | ||
88 | writel(secs, rtap->virtbase + COH901331_SET_TIME); | ||
89 | clk_disable(rtap->clk); | ||
90 | |||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | static int coh901331_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) | ||
95 | { | ||
96 | struct coh901331_port *rtap = dev_get_drvdata(dev); | ||
97 | |||
98 | clk_enable(rtap->clk); | ||
99 | rtc_time_to_tm(readl(rtap->virtbase + COH901331_ALARM), &alarm->time); | ||
100 | alarm->pending = readl(rtap->virtbase + COH901331_IRQ_EVENT) & 1U; | ||
101 | alarm->enabled = readl(rtap->virtbase + COH901331_IRQ_MASK) & 1U; | ||
102 | clk_disable(rtap->clk); | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static int coh901331_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) | ||
108 | { | ||
109 | struct coh901331_port *rtap = dev_get_drvdata(dev); | ||
110 | unsigned long time; | ||
111 | |||
112 | rtc_tm_to_time(&alarm->time, &time); | ||
113 | clk_enable(rtap->clk); | ||
114 | writel(time, rtap->virtbase + COH901331_ALARM); | ||
115 | writel(alarm->enabled, rtap->virtbase + COH901331_IRQ_MASK); | ||
116 | clk_disable(rtap->clk); | ||
117 | |||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | static int coh901331_alarm_irq_enable(struct device *dev, unsigned int enabled) | ||
122 | { | ||
123 | struct coh901331_port *rtap = dev_get_drvdata(dev); | ||
124 | |||
125 | clk_enable(rtap->clk); | ||
126 | if (enabled) | ||
127 | writel(1, rtap->virtbase + COH901331_IRQ_MASK); | ||
128 | else | ||
129 | writel(0, rtap->virtbase + COH901331_IRQ_MASK); | ||
130 | clk_disable(rtap->clk); | ||
131 | } | ||
132 | |||
133 | static struct rtc_class_ops coh901331_ops = { | ||
134 | .read_time = coh901331_read_time, | ||
135 | .set_mmss = coh901331_set_mmss, | ||
136 | .read_alarm = coh901331_read_alarm, | ||
137 | .set_alarm = coh901331_set_alarm, | ||
138 | .alarm_irq_enable = coh901331_alarm_irq_enable, | ||
139 | }; | ||
140 | |||
141 | static int __exit coh901331_remove(struct platform_device *pdev) | ||
142 | { | ||
143 | struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev); | ||
144 | |||
145 | if (rtap) { | ||
146 | free_irq(rtap->irq, rtap); | ||
147 | rtc_device_unregister(rtap->rtc); | ||
148 | clk_put(rtap->clk); | ||
149 | iounmap(rtap->virtbase); | ||
150 | release_mem_region(rtap->phybase, rtap->physize); | ||
151 | platform_set_drvdata(pdev, NULL); | ||
152 | kfree(rtap); | ||
153 | } | ||
154 | |||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | |||
159 | static int __init coh901331_probe(struct platform_device *pdev) | ||
160 | { | ||
161 | int ret; | ||
162 | struct coh901331_port *rtap; | ||
163 | struct resource *res; | ||
164 | |||
165 | rtap = kzalloc(sizeof(struct coh901331_port), GFP_KERNEL); | ||
166 | if (!rtap) | ||
167 | return -ENOMEM; | ||
168 | |||
169 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
170 | if (!res) { | ||
171 | ret = -ENOENT; | ||
172 | goto out_no_resource; | ||
173 | } | ||
174 | rtap->phybase = res->start; | ||
175 | rtap->physize = resource_size(res); | ||
176 | |||
177 | if (request_mem_region(rtap->phybase, rtap->physize, | ||
178 | "rtc-coh901331") == NULL) { | ||
179 | ret = -EBUSY; | ||
180 | goto out_no_memregion; | ||
181 | } | ||
182 | |||
183 | rtap->virtbase = ioremap(rtap->phybase, rtap->physize); | ||
184 | if (!rtap->virtbase) { | ||
185 | ret = -ENOMEM; | ||
186 | goto out_no_remap; | ||
187 | } | ||
188 | |||
189 | rtap->irq = platform_get_irq(pdev, 0); | ||
190 | if (request_irq(rtap->irq, coh901331_interrupt, IRQF_DISABLED, | ||
191 | "RTC COH 901 331 Alarm", rtap)) { | ||
192 | ret = -EIO; | ||
193 | goto out_no_irq; | ||
194 | } | ||
195 | |||
196 | rtap->clk = clk_get(&pdev->dev, NULL); | ||
197 | if (IS_ERR(rtap->clk)) { | ||
198 | ret = PTR_ERR(rtap->clk); | ||
199 | dev_err(&pdev->dev, "could not get clock\n"); | ||
200 | goto out_no_clk; | ||
201 | } | ||
202 | |||
203 | /* We enable/disable the clock only to assure it works */ | ||
204 | ret = clk_enable(rtap->clk); | ||
205 | if (ret) { | ||
206 | dev_err(&pdev->dev, "could not enable clock\n"); | ||
207 | goto out_no_clk_enable; | ||
208 | } | ||
209 | clk_disable(rtap->clk); | ||
210 | |||
211 | rtap->rtc = rtc_device_register("coh901331", &pdev->dev, &coh901331_ops, | ||
212 | THIS_MODULE); | ||
213 | if (IS_ERR(rtap->rtc)) { | ||
214 | ret = PTR_ERR(rtap->rtc); | ||
215 | goto out_no_rtc; | ||
216 | } | ||
217 | |||
218 | platform_set_drvdata(pdev, rtap); | ||
219 | |||
220 | return 0; | ||
221 | |||
222 | out_no_rtc: | ||
223 | out_no_clk_enable: | ||
224 | clk_put(rtap->clk); | ||
225 | out_no_clk: | ||
226 | free_irq(rtap->irq, rtap); | ||
227 | out_no_irq: | ||
228 | iounmap(rtap->virtbase); | ||
229 | out_no_remap: | ||
230 | platform_set_drvdata(pdev, NULL); | ||
231 | out_no_memregion: | ||
232 | release_mem_region(rtap->phybase, SZ_4K); | ||
233 | out_no_resource: | ||
234 | kfree(rtap); | ||
235 | return ret; | ||
236 | } | ||
237 | |||
238 | #ifdef CONFIG_PM | ||
239 | static int coh901331_suspend(struct platform_device *pdev, pm_message_t state) | ||
240 | { | ||
241 | struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev); | ||
242 | |||
243 | /* | ||
244 | * If this RTC alarm will be used for waking the system up, | ||
245 | * don't disable it of course. Else we just disable the alarm | ||
246 | * and await suspension. | ||
247 | */ | ||
248 | if (device_may_wakeup(&pdev->dev)) { | ||
249 | enable_irq_wake(rtap->irq); | ||
250 | } else { | ||
251 | clk_enable(rtap->clk); | ||
252 | rtap->irqmaskstore = readl(rtap->virtbase + COH901331_IRQ_MASK); | ||
253 | writel(0, rtap->virtbase + COH901331_IRQ_MASK); | ||
254 | clk_disable(rtap->clk); | ||
255 | } | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static int coh901331_resume(struct platform_device *pdev) | ||
260 | { | ||
261 | struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev); | ||
262 | |||
263 | if (device_may_wakeup(&pdev->dev)) | ||
264 | disable_irq_wake(rtap->irq); | ||
265 | else | ||
266 | clk_enable(rtap->clk); | ||
267 | writel(rtap->irqmaskstore, rtap->virtbase + COH901331_IRQ_MASK); | ||
268 | clk_disable(rtap->clk); | ||
269 | return 0; | ||
270 | } | ||
271 | #else | ||
272 | #define coh901331_suspend NULL | ||
273 | #define coh901331_resume NULL | ||
274 | #endif | ||
275 | |||
276 | static void coh901331_shutdown(struct platform_device *pdev) | ||
277 | { | ||
278 | struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev); | ||
279 | |||
280 | clk_enable(rtap->clk); | ||
281 | writel(0, rtap->virtbase + COH901331_IRQ_MASK); | ||
282 | clk_disable(rtap->clk); | ||
283 | } | ||
284 | |||
285 | static struct platform_driver coh901331_driver = { | ||
286 | .driver = { | ||
287 | .name = "rtc-coh901331", | ||
288 | .owner = THIS_MODULE, | ||
289 | }, | ||
290 | .remove = __exit_p(coh901331_remove), | ||
291 | .suspend = coh901331_suspend, | ||
292 | .resume = coh901331_resume, | ||
293 | .shutdown = coh901331_shutdown, | ||
294 | }; | ||
295 | |||
296 | static int __init coh901331_init(void) | ||
297 | { | ||
298 | return platform_driver_probe(&coh901331_driver, coh901331_probe); | ||
299 | } | ||
300 | |||
301 | static void __exit coh901331_exit(void) | ||
302 | { | ||
303 | platform_driver_unregister(&coh901331_driver); | ||
304 | } | ||
305 | |||
306 | module_init(coh901331_init); | ||
307 | module_exit(coh901331_exit); | ||
308 | |||
309 | MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>"); | ||
310 | MODULE_DESCRIPTION("ST-Ericsson AB COH 901 331 RTC Driver"); | ||
311 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c index 184556620778..d490628b64da 100644 --- a/drivers/rtc/rtc-ds1302.c +++ b/drivers/rtc/rtc-ds1302.c | |||
@@ -1,26 +1,25 @@ | |||
1 | /* | 1 | /* |
2 | * Dallas DS1302 RTC Support | 2 | * Dallas DS1302 RTC Support |
3 | * | 3 | * |
4 | * Copyright (C) 2002 David McCullough | 4 | * Copyright (C) 2002 David McCullough |
5 | * Copyright (C) 2003 - 2007 Paul Mundt | 5 | * Copyright (C) 2003 - 2007 Paul Mundt |
6 | * | 6 | * |
7 | * This file is subject to the terms and conditions of the GNU General Public | 7 | * This file is subject to the terms and conditions of the GNU General Public |
8 | * License version 2. See the file "COPYING" in the main directory of | 8 | * License version 2. See the file "COPYING" in the main directory of |
9 | * this archive for more details. | 9 | * this archive for more details. |
10 | */ | 10 | */ |
11 | |||
11 | #include <linux/init.h> | 12 | #include <linux/init.h> |
12 | #include <linux/module.h> | 13 | #include <linux/module.h> |
13 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
14 | #include <linux/platform_device.h> | 15 | #include <linux/platform_device.h> |
15 | #include <linux/time.h> | ||
16 | #include <linux/rtc.h> | 16 | #include <linux/rtc.h> |
17 | #include <linux/spinlock.h> | ||
18 | #include <linux/io.h> | 17 | #include <linux/io.h> |
19 | #include <linux/bcd.h> | 18 | #include <linux/bcd.h> |
20 | #include <asm/rtc.h> | 19 | #include <asm/rtc.h> |
21 | 20 | ||
22 | #define DRV_NAME "rtc-ds1302" | 21 | #define DRV_NAME "rtc-ds1302" |
23 | #define DRV_VERSION "0.1.0" | 22 | #define DRV_VERSION "0.1.1" |
24 | 23 | ||
25 | #define RTC_CMD_READ 0x81 /* Read command */ | 24 | #define RTC_CMD_READ 0x81 /* Read command */ |
26 | #define RTC_CMD_WRITE 0x80 /* Write command */ | 25 | #define RTC_CMD_WRITE 0x80 /* Write command */ |
@@ -47,11 +46,6 @@ | |||
47 | #error "Add support for your platform" | 46 | #error "Add support for your platform" |
48 | #endif | 47 | #endif |
49 | 48 | ||
50 | struct ds1302_rtc { | ||
51 | struct rtc_device *rtc_dev; | ||
52 | spinlock_t lock; | ||
53 | }; | ||
54 | |||
55 | static void ds1302_sendbits(unsigned int val) | 49 | static void ds1302_sendbits(unsigned int val) |
56 | { | 50 | { |
57 | int i; | 51 | int i; |
@@ -103,10 +97,6 @@ static void ds1302_writebyte(unsigned int addr, unsigned int val) | |||
103 | 97 | ||
104 | static int ds1302_rtc_read_time(struct device *dev, struct rtc_time *tm) | 98 | static int ds1302_rtc_read_time(struct device *dev, struct rtc_time *tm) |
105 | { | 99 | { |
106 | struct ds1302_rtc *rtc = dev_get_drvdata(dev); | ||
107 | |||
108 | spin_lock_irq(&rtc->lock); | ||
109 | |||
110 | tm->tm_sec = bcd2bin(ds1302_readbyte(RTC_ADDR_SEC)); | 100 | tm->tm_sec = bcd2bin(ds1302_readbyte(RTC_ADDR_SEC)); |
111 | tm->tm_min = bcd2bin(ds1302_readbyte(RTC_ADDR_MIN)); | 101 | tm->tm_min = bcd2bin(ds1302_readbyte(RTC_ADDR_MIN)); |
112 | tm->tm_hour = bcd2bin(ds1302_readbyte(RTC_ADDR_HOUR)); | 102 | tm->tm_hour = bcd2bin(ds1302_readbyte(RTC_ADDR_HOUR)); |
@@ -118,26 +108,17 @@ static int ds1302_rtc_read_time(struct device *dev, struct rtc_time *tm) | |||
118 | if (tm->tm_year < 70) | 108 | if (tm->tm_year < 70) |
119 | tm->tm_year += 100; | 109 | tm->tm_year += 100; |
120 | 110 | ||
121 | spin_unlock_irq(&rtc->lock); | ||
122 | |||
123 | dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " | 111 | dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " |
124 | "mday=%d, mon=%d, year=%d, wday=%d\n", | 112 | "mday=%d, mon=%d, year=%d, wday=%d\n", |
125 | __func__, | 113 | __func__, |
126 | tm->tm_sec, tm->tm_min, tm->tm_hour, | 114 | tm->tm_sec, tm->tm_min, tm->tm_hour, |
127 | tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday); | 115 | tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday); |
128 | 116 | ||
129 | if (rtc_valid_tm(tm) < 0) | 117 | return rtc_valid_tm(tm); |
130 | dev_err(dev, "invalid date\n"); | ||
131 | |||
132 | return 0; | ||
133 | } | 118 | } |
134 | 119 | ||
135 | static int ds1302_rtc_set_time(struct device *dev, struct rtc_time *tm) | 120 | static int ds1302_rtc_set_time(struct device *dev, struct rtc_time *tm) |
136 | { | 121 | { |
137 | struct ds1302_rtc *rtc = dev_get_drvdata(dev); | ||
138 | |||
139 | spin_lock_irq(&rtc->lock); | ||
140 | |||
141 | /* Stop RTC */ | 122 | /* Stop RTC */ |
142 | ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) | 0x80); | 123 | ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) | 0x80); |
143 | 124 | ||
@@ -152,8 +133,6 @@ static int ds1302_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
152 | /* Start RTC */ | 133 | /* Start RTC */ |
153 | ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) & ~0x80); | 134 | ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) & ~0x80); |
154 | 135 | ||
155 | spin_unlock_irq(&rtc->lock); | ||
156 | |||
157 | return 0; | 136 | return 0; |
158 | } | 137 | } |
159 | 138 | ||
@@ -170,9 +149,7 @@ static int ds1302_rtc_ioctl(struct device *dev, unsigned int cmd, | |||
170 | if (copy_from_user(&tcs_val, (int __user *)arg, sizeof(int))) | 149 | if (copy_from_user(&tcs_val, (int __user *)arg, sizeof(int))) |
171 | return -EFAULT; | 150 | return -EFAULT; |
172 | 151 | ||
173 | spin_lock_irq(&rtc->lock); | ||
174 | ds1302_writebyte(RTC_ADDR_TCR, (0xa0 | tcs_val * 0xf)); | 152 | ds1302_writebyte(RTC_ADDR_TCR, (0xa0 | tcs_val * 0xf)); |
175 | spin_unlock_irq(&rtc->lock); | ||
176 | return 0; | 153 | return 0; |
177 | } | 154 | } |
178 | #endif | 155 | #endif |
@@ -187,10 +164,9 @@ static struct rtc_class_ops ds1302_rtc_ops = { | |||
187 | .ioctl = ds1302_rtc_ioctl, | 164 | .ioctl = ds1302_rtc_ioctl, |
188 | }; | 165 | }; |
189 | 166 | ||
190 | static int __devinit ds1302_rtc_probe(struct platform_device *pdev) | 167 | static int __init ds1302_rtc_probe(struct platform_device *pdev) |
191 | { | 168 | { |
192 | struct ds1302_rtc *rtc; | 169 | struct rtc_device *rtc; |
193 | int ret; | ||
194 | 170 | ||
195 | /* Reset */ | 171 | /* Reset */ |
196 | set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK)); | 172 | set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK)); |
@@ -200,37 +176,23 @@ static int __devinit ds1302_rtc_probe(struct platform_device *pdev) | |||
200 | if (ds1302_readbyte(RTC_ADDR_RAM0) != 0x42) | 176 | if (ds1302_readbyte(RTC_ADDR_RAM0) != 0x42) |
201 | return -ENODEV; | 177 | return -ENODEV; |
202 | 178 | ||
203 | rtc = kzalloc(sizeof(struct ds1302_rtc), GFP_KERNEL); | 179 | rtc = rtc_device_register("ds1302", &pdev->dev, |
204 | if (unlikely(!rtc)) | ||
205 | return -ENOMEM; | ||
206 | |||
207 | spin_lock_init(&rtc->lock); | ||
208 | rtc->rtc_dev = rtc_device_register("ds1302", &pdev->dev, | ||
209 | &ds1302_rtc_ops, THIS_MODULE); | 180 | &ds1302_rtc_ops, THIS_MODULE); |
210 | if (IS_ERR(rtc->rtc_dev)) { | 181 | if (IS_ERR(rtc)) |
211 | ret = PTR_ERR(rtc->rtc_dev); | 182 | return PTR_ERR(rtc); |
212 | goto out; | ||
213 | } | ||
214 | 183 | ||
215 | platform_set_drvdata(pdev, rtc); | 184 | platform_set_drvdata(pdev, rtc); |
216 | 185 | ||
217 | return 0; | 186 | return 0; |
218 | out: | ||
219 | kfree(rtc); | ||
220 | return ret; | ||
221 | } | 187 | } |
222 | 188 | ||
223 | static int __devexit ds1302_rtc_remove(struct platform_device *pdev) | 189 | static int __devexit ds1302_rtc_remove(struct platform_device *pdev) |
224 | { | 190 | { |
225 | struct ds1302_rtc *rtc = platform_get_drvdata(pdev); | 191 | struct rtc_device *rtc = platform_get_drvdata(pdev); |
226 | |||
227 | if (likely(rtc->rtc_dev)) | ||
228 | rtc_device_unregister(rtc->rtc_dev); | ||
229 | 192 | ||
193 | rtc_device_unregister(rtc); | ||
230 | platform_set_drvdata(pdev, NULL); | 194 | platform_set_drvdata(pdev, NULL); |
231 | 195 | ||
232 | kfree(rtc); | ||
233 | |||
234 | return 0; | 196 | return 0; |
235 | } | 197 | } |
236 | 198 | ||
@@ -239,13 +201,12 @@ static struct platform_driver ds1302_platform_driver = { | |||
239 | .name = DRV_NAME, | 201 | .name = DRV_NAME, |
240 | .owner = THIS_MODULE, | 202 | .owner = THIS_MODULE, |
241 | }, | 203 | }, |
242 | .probe = ds1302_rtc_probe, | 204 | .remove = __exit_p(ds1302_rtc_remove), |
243 | .remove = __devexit_p(ds1302_rtc_remove), | ||
244 | }; | 205 | }; |
245 | 206 | ||
246 | static int __init ds1302_rtc_init(void) | 207 | static int __init ds1302_rtc_init(void) |
247 | { | 208 | { |
248 | return platform_driver_register(&ds1302_platform_driver); | 209 | return platform_driver_probe(&ds1302_platform_driver, ds1302_rtc_probe); |
249 | } | 210 | } |
250 | 211 | ||
251 | static void __exit ds1302_rtc_exit(void) | 212 | static void __exit ds1302_rtc_exit(void) |
diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index 8f410e59d9f5..2736b11a1b1e 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c | |||
@@ -841,3 +841,4 @@ module_exit(ds1305_exit); | |||
841 | 841 | ||
842 | MODULE_DESCRIPTION("RTC driver for DS1305 and DS1306 chips"); | 842 | MODULE_DESCRIPTION("RTC driver for DS1305 and DS1306 chips"); |
843 | MODULE_LICENSE("GPL"); | 843 | MODULE_LICENSE("GPL"); |
844 | MODULE_ALIAS("spi:rtc-ds1305"); | ||
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 47a93c022d91..eb99ee4fa0f5 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c | |||
@@ -896,8 +896,7 @@ read_rtc: | |||
896 | return 0; | 896 | return 0; |
897 | 897 | ||
898 | exit_irq: | 898 | exit_irq: |
899 | if (ds1307->rtc) | 899 | rtc_device_unregister(ds1307->rtc); |
900 | rtc_device_unregister(ds1307->rtc); | ||
901 | exit_free: | 900 | exit_free: |
902 | kfree(ds1307); | 901 | kfree(ds1307); |
903 | return err; | 902 | return err; |
diff --git a/drivers/rtc/rtc-ds1390.c b/drivers/rtc/rtc-ds1390.c index e01b955db077..cdb705057091 100644 --- a/drivers/rtc/rtc-ds1390.c +++ b/drivers/rtc/rtc-ds1390.c | |||
@@ -189,3 +189,4 @@ module_exit(ds1390_exit); | |||
189 | MODULE_DESCRIPTION("Dallas/Maxim DS1390/93/94 SPI RTC driver"); | 189 | MODULE_DESCRIPTION("Dallas/Maxim DS1390/93/94 SPI RTC driver"); |
190 | MODULE_AUTHOR("Mark Jackson <mpfj@mimc.co.uk>"); | 190 | MODULE_AUTHOR("Mark Jackson <mpfj@mimc.co.uk>"); |
191 | MODULE_LICENSE("GPL"); | 191 | MODULE_LICENSE("GPL"); |
192 | MODULE_ALIAS("spi:rtc-ds1390"); | ||
diff --git a/drivers/rtc/rtc-ds3234.c b/drivers/rtc/rtc-ds3234.c index c51589ede5b7..a774ca35b5f7 100644 --- a/drivers/rtc/rtc-ds3234.c +++ b/drivers/rtc/rtc-ds3234.c | |||
@@ -188,3 +188,4 @@ module_exit(ds3234_exit); | |||
188 | MODULE_DESCRIPTION("DS3234 SPI RTC driver"); | 188 | MODULE_DESCRIPTION("DS3234 SPI RTC driver"); |
189 | MODULE_AUTHOR("Dennis Aberilla <denzzzhome@yahoo.com>"); | 189 | MODULE_AUTHOR("Dennis Aberilla <denzzzhome@yahoo.com>"); |
190 | MODULE_LICENSE("GPL"); | 190 | MODULE_LICENSE("GPL"); |
191 | MODULE_ALIAS("spi:ds3234"); | ||
diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c index 551332e4ed02..9da02d108b73 100644 --- a/drivers/rtc/rtc-ep93xx.c +++ b/drivers/rtc/rtc-ep93xx.c | |||
@@ -128,12 +128,16 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev) | |||
128 | return -ENOMEM; | 128 | return -ENOMEM; |
129 | 129 | ||
130 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 130 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
131 | if (res == NULL) | 131 | if (res == NULL) { |
132 | return -ENXIO; | 132 | err = -ENXIO; |
133 | goto fail_free; | ||
134 | } | ||
133 | 135 | ||
134 | res = request_mem_region(res->start, resource_size(res), pdev->name); | 136 | res = request_mem_region(res->start, resource_size(res), pdev->name); |
135 | if (res == NULL) | 137 | if (res == NULL) { |
136 | return -EBUSY; | 138 | err = -EBUSY; |
139 | goto fail_free; | ||
140 | } | ||
137 | 141 | ||
138 | ep93xx_rtc->mmio_base = ioremap(res->start, resource_size(res)); | 142 | ep93xx_rtc->mmio_base = ioremap(res->start, resource_size(res)); |
139 | if (ep93xx_rtc->mmio_base == NULL) { | 143 | if (ep93xx_rtc->mmio_base == NULL) { |
@@ -169,6 +173,8 @@ fail: | |||
169 | pdev->dev.platform_data = NULL; | 173 | pdev->dev.platform_data = NULL; |
170 | } | 174 | } |
171 | release_mem_region(res->start, resource_size(res)); | 175 | release_mem_region(res->start, resource_size(res)); |
176 | fail_free: | ||
177 | kfree(ep93xx_rtc); | ||
172 | return err; | 178 | return err; |
173 | } | 179 | } |
174 | 180 | ||
diff --git a/drivers/rtc/rtc-m41t94.c b/drivers/rtc/rtc-m41t94.c index c3a18c58daf6..c8c97a4169d4 100644 --- a/drivers/rtc/rtc-m41t94.c +++ b/drivers/rtc/rtc-m41t94.c | |||
@@ -171,3 +171,4 @@ module_exit(m41t94_exit); | |||
171 | MODULE_AUTHOR("Kim B. Heino <Kim.Heino@bluegiga.com>"); | 171 | MODULE_AUTHOR("Kim B. Heino <Kim.Heino@bluegiga.com>"); |
172 | MODULE_DESCRIPTION("Driver for ST M41T94 SPI RTC"); | 172 | MODULE_DESCRIPTION("Driver for ST M41T94 SPI RTC"); |
173 | MODULE_LICENSE("GPL"); | 173 | MODULE_LICENSE("GPL"); |
174 | MODULE_ALIAS("spi:rtc-m41t94"); | ||
diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c index 36a8ea9ed8ba..657403ebd54a 100644 --- a/drivers/rtc/rtc-max6902.c +++ b/drivers/rtc/rtc-max6902.c | |||
@@ -175,3 +175,4 @@ module_exit(max6902_exit); | |||
175 | MODULE_DESCRIPTION ("max6902 spi RTC driver"); | 175 | MODULE_DESCRIPTION ("max6902 spi RTC driver"); |
176 | MODULE_AUTHOR ("Raphael Assenat"); | 176 | MODULE_AUTHOR ("Raphael Assenat"); |
177 | MODULE_LICENSE ("GPL"); | 177 | MODULE_LICENSE ("GPL"); |
178 | MODULE_ALIAS("spi:rtc-max6902"); | ||
diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c new file mode 100644 index 000000000000..6bd5072d4eb7 --- /dev/null +++ b/drivers/rtc/rtc-mxc.c | |||
@@ -0,0 +1,507 @@ | |||
1 | /* | ||
2 | * Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved. | ||
3 | * | ||
4 | * The code contained herein is licensed under the GNU General Public | ||
5 | * License. You may obtain a copy of the GNU General Public License | ||
6 | * Version 2 or later at the following locations: | ||
7 | * | ||
8 | * http://www.opensource.org/licenses/gpl-license.html | ||
9 | * http://www.gnu.org/copyleft/gpl.html | ||
10 | */ | ||
11 | |||
12 | #include <linux/io.h> | ||
13 | #include <linux/rtc.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/clk.h> | ||
18 | |||
19 | #include <mach/hardware.h> | ||
20 | |||
21 | #define RTC_INPUT_CLK_32768HZ (0x00 << 5) | ||
22 | #define RTC_INPUT_CLK_32000HZ (0x01 << 5) | ||
23 | #define RTC_INPUT_CLK_38400HZ (0x02 << 5) | ||
24 | |||
25 | #define RTC_SW_BIT (1 << 0) | ||
26 | #define RTC_ALM_BIT (1 << 2) | ||
27 | #define RTC_1HZ_BIT (1 << 4) | ||
28 | #define RTC_2HZ_BIT (1 << 7) | ||
29 | #define RTC_SAM0_BIT (1 << 8) | ||
30 | #define RTC_SAM1_BIT (1 << 9) | ||
31 | #define RTC_SAM2_BIT (1 << 10) | ||
32 | #define RTC_SAM3_BIT (1 << 11) | ||
33 | #define RTC_SAM4_BIT (1 << 12) | ||
34 | #define RTC_SAM5_BIT (1 << 13) | ||
35 | #define RTC_SAM6_BIT (1 << 14) | ||
36 | #define RTC_SAM7_BIT (1 << 15) | ||
37 | #define PIT_ALL_ON (RTC_2HZ_BIT | RTC_SAM0_BIT | RTC_SAM1_BIT | \ | ||
38 | RTC_SAM2_BIT | RTC_SAM3_BIT | RTC_SAM4_BIT | \ | ||
39 | RTC_SAM5_BIT | RTC_SAM6_BIT | RTC_SAM7_BIT) | ||
40 | |||
41 | #define RTC_ENABLE_BIT (1 << 7) | ||
42 | |||
43 | #define MAX_PIE_NUM 9 | ||
44 | #define MAX_PIE_FREQ 512 | ||
45 | static const u32 PIE_BIT_DEF[MAX_PIE_NUM][2] = { | ||
46 | { 2, RTC_2HZ_BIT }, | ||
47 | { 4, RTC_SAM0_BIT }, | ||
48 | { 8, RTC_SAM1_BIT }, | ||
49 | { 16, RTC_SAM2_BIT }, | ||
50 | { 32, RTC_SAM3_BIT }, | ||
51 | { 64, RTC_SAM4_BIT }, | ||
52 | { 128, RTC_SAM5_BIT }, | ||
53 | { 256, RTC_SAM6_BIT }, | ||
54 | { MAX_PIE_FREQ, RTC_SAM7_BIT }, | ||
55 | }; | ||
56 | |||
57 | /* Those are the bits from a classic RTC we want to mimic */ | ||
58 | #define RTC_IRQF 0x80 /* any of the following 3 is active */ | ||
59 | #define RTC_PF 0x40 /* Periodic interrupt */ | ||
60 | #define RTC_AF 0x20 /* Alarm interrupt */ | ||
61 | #define RTC_UF 0x10 /* Update interrupt for 1Hz RTC */ | ||
62 | |||
63 | #define MXC_RTC_TIME 0 | ||
64 | #define MXC_RTC_ALARM 1 | ||
65 | |||
66 | #define RTC_HOURMIN 0x00 /* 32bit rtc hour/min counter reg */ | ||
67 | #define RTC_SECOND 0x04 /* 32bit rtc seconds counter reg */ | ||
68 | #define RTC_ALRM_HM 0x08 /* 32bit rtc alarm hour/min reg */ | ||
69 | #define RTC_ALRM_SEC 0x0C /* 32bit rtc alarm seconds reg */ | ||
70 | #define RTC_RTCCTL 0x10 /* 32bit rtc control reg */ | ||
71 | #define RTC_RTCISR 0x14 /* 32bit rtc interrupt status reg */ | ||
72 | #define RTC_RTCIENR 0x18 /* 32bit rtc interrupt enable reg */ | ||
73 | #define RTC_STPWCH 0x1C /* 32bit rtc stopwatch min reg */ | ||
74 | #define RTC_DAYR 0x20 /* 32bit rtc days counter reg */ | ||
75 | #define RTC_DAYALARM 0x24 /* 32bit rtc day alarm reg */ | ||
76 | #define RTC_TEST1 0x28 /* 32bit rtc test reg 1 */ | ||
77 | #define RTC_TEST2 0x2C /* 32bit rtc test reg 2 */ | ||
78 | #define RTC_TEST3 0x30 /* 32bit rtc test reg 3 */ | ||
79 | |||
80 | struct rtc_plat_data { | ||
81 | struct rtc_device *rtc; | ||
82 | void __iomem *ioaddr; | ||
83 | int irq; | ||
84 | struct clk *clk; | ||
85 | unsigned int irqen; | ||
86 | int alrm_sec; | ||
87 | int alrm_min; | ||
88 | int alrm_hour; | ||
89 | int alrm_mday; | ||
90 | struct timespec mxc_rtc_delta; | ||
91 | struct rtc_time g_rtc_alarm; | ||
92 | }; | ||
93 | |||
94 | /* | ||
95 | * This function is used to obtain the RTC time or the alarm value in | ||
96 | * second. | ||
97 | */ | ||
98 | static u32 get_alarm_or_time(struct device *dev, int time_alarm) | ||
99 | { | ||
100 | struct platform_device *pdev = to_platform_device(dev); | ||
101 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
102 | void __iomem *ioaddr = pdata->ioaddr; | ||
103 | u32 day = 0, hr = 0, min = 0, sec = 0, hr_min = 0; | ||
104 | |||
105 | switch (time_alarm) { | ||
106 | case MXC_RTC_TIME: | ||
107 | day = readw(ioaddr + RTC_DAYR); | ||
108 | hr_min = readw(ioaddr + RTC_HOURMIN); | ||
109 | sec = readw(ioaddr + RTC_SECOND); | ||
110 | break; | ||
111 | case MXC_RTC_ALARM: | ||
112 | day = readw(ioaddr + RTC_DAYALARM); | ||
113 | hr_min = readw(ioaddr + RTC_ALRM_HM) & 0xffff; | ||
114 | sec = readw(ioaddr + RTC_ALRM_SEC); | ||
115 | break; | ||
116 | } | ||
117 | |||
118 | hr = hr_min >> 8; | ||
119 | min = hr_min & 0xff; | ||
120 | |||
121 | return (((day * 24 + hr) * 60) + min) * 60 + sec; | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * This function sets the RTC alarm value or the time value. | ||
126 | */ | ||
127 | static void set_alarm_or_time(struct device *dev, int time_alarm, u32 time) | ||
128 | { | ||
129 | u32 day, hr, min, sec, temp; | ||
130 | struct platform_device *pdev = to_platform_device(dev); | ||
131 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
132 | void __iomem *ioaddr = pdata->ioaddr; | ||
133 | |||
134 | day = time / 86400; | ||
135 | time -= day * 86400; | ||
136 | |||
137 | /* time is within a day now */ | ||
138 | hr = time / 3600; | ||
139 | time -= hr * 3600; | ||
140 | |||
141 | /* time is within an hour now */ | ||
142 | min = time / 60; | ||
143 | sec = time - min * 60; | ||
144 | |||
145 | temp = (hr << 8) + min; | ||
146 | |||
147 | switch (time_alarm) { | ||
148 | case MXC_RTC_TIME: | ||
149 | writew(day, ioaddr + RTC_DAYR); | ||
150 | writew(sec, ioaddr + RTC_SECOND); | ||
151 | writew(temp, ioaddr + RTC_HOURMIN); | ||
152 | break; | ||
153 | case MXC_RTC_ALARM: | ||
154 | writew(day, ioaddr + RTC_DAYALARM); | ||
155 | writew(sec, ioaddr + RTC_ALRM_SEC); | ||
156 | writew(temp, ioaddr + RTC_ALRM_HM); | ||
157 | break; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | /* | ||
162 | * This function updates the RTC alarm registers and then clears all the | ||
163 | * interrupt status bits. | ||
164 | */ | ||
165 | static int rtc_update_alarm(struct device *dev, struct rtc_time *alrm) | ||
166 | { | ||
167 | struct rtc_time alarm_tm, now_tm; | ||
168 | unsigned long now, time; | ||
169 | int ret; | ||
170 | struct platform_device *pdev = to_platform_device(dev); | ||
171 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
172 | void __iomem *ioaddr = pdata->ioaddr; | ||
173 | |||
174 | now = get_alarm_or_time(dev, MXC_RTC_TIME); | ||
175 | rtc_time_to_tm(now, &now_tm); | ||
176 | alarm_tm.tm_year = now_tm.tm_year; | ||
177 | alarm_tm.tm_mon = now_tm.tm_mon; | ||
178 | alarm_tm.tm_mday = now_tm.tm_mday; | ||
179 | alarm_tm.tm_hour = alrm->tm_hour; | ||
180 | alarm_tm.tm_min = alrm->tm_min; | ||
181 | alarm_tm.tm_sec = alrm->tm_sec; | ||
182 | rtc_tm_to_time(&now_tm, &now); | ||
183 | rtc_tm_to_time(&alarm_tm, &time); | ||
184 | |||
185 | if (time < now) { | ||
186 | time += 60 * 60 * 24; | ||
187 | rtc_time_to_tm(time, &alarm_tm); | ||
188 | } | ||
189 | |||
190 | ret = rtc_tm_to_time(&alarm_tm, &time); | ||
191 | |||
192 | /* clear all the interrupt status bits */ | ||
193 | writew(readw(ioaddr + RTC_RTCISR), ioaddr + RTC_RTCISR); | ||
194 | set_alarm_or_time(dev, MXC_RTC_ALARM, time); | ||
195 | |||
196 | return ret; | ||
197 | } | ||
198 | |||
199 | /* This function is the RTC interrupt service routine. */ | ||
200 | static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id) | ||
201 | { | ||
202 | struct platform_device *pdev = dev_id; | ||
203 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
204 | void __iomem *ioaddr = pdata->ioaddr; | ||
205 | u32 status; | ||
206 | u32 events = 0; | ||
207 | |||
208 | spin_lock_irq(&pdata->rtc->irq_lock); | ||
209 | status = readw(ioaddr + RTC_RTCISR) & readw(ioaddr + RTC_RTCIENR); | ||
210 | /* clear interrupt sources */ | ||
211 | writew(status, ioaddr + RTC_RTCISR); | ||
212 | |||
213 | /* clear alarm interrupt if it has occurred */ | ||
214 | if (status & RTC_ALM_BIT) | ||
215 | status &= ~RTC_ALM_BIT; | ||
216 | |||
217 | /* update irq data & counter */ | ||
218 | if (status & RTC_ALM_BIT) | ||
219 | events |= (RTC_AF | RTC_IRQF); | ||
220 | |||
221 | if (status & RTC_1HZ_BIT) | ||
222 | events |= (RTC_UF | RTC_IRQF); | ||
223 | |||
224 | if (status & PIT_ALL_ON) | ||
225 | events |= (RTC_PF | RTC_IRQF); | ||
226 | |||
227 | if ((status & RTC_ALM_BIT) && rtc_valid_tm(&pdata->g_rtc_alarm)) | ||
228 | rtc_update_alarm(&pdev->dev, &pdata->g_rtc_alarm); | ||
229 | |||
230 | rtc_update_irq(pdata->rtc, 1, events); | ||
231 | spin_unlock_irq(&pdata->rtc->irq_lock); | ||
232 | |||
233 | return IRQ_HANDLED; | ||
234 | } | ||
235 | |||
236 | /* | ||
237 | * Clear all interrupts and release the IRQ | ||
238 | */ | ||
239 | static void mxc_rtc_release(struct device *dev) | ||
240 | { | ||
241 | struct platform_device *pdev = to_platform_device(dev); | ||
242 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
243 | void __iomem *ioaddr = pdata->ioaddr; | ||
244 | |||
245 | spin_lock_irq(&pdata->rtc->irq_lock); | ||
246 | |||
247 | /* Disable all rtc interrupts */ | ||
248 | writew(0, ioaddr + RTC_RTCIENR); | ||
249 | |||
250 | /* Clear all interrupt status */ | ||
251 | writew(0xffffffff, ioaddr + RTC_RTCISR); | ||
252 | |||
253 | spin_unlock_irq(&pdata->rtc->irq_lock); | ||
254 | } | ||
255 | |||
256 | static void mxc_rtc_irq_enable(struct device *dev, unsigned int bit, | ||
257 | unsigned int enabled) | ||
258 | { | ||
259 | struct platform_device *pdev = to_platform_device(dev); | ||
260 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
261 | void __iomem *ioaddr = pdata->ioaddr; | ||
262 | u32 reg; | ||
263 | |||
264 | spin_lock_irq(&pdata->rtc->irq_lock); | ||
265 | reg = readw(ioaddr + RTC_RTCIENR); | ||
266 | |||
267 | if (enabled) | ||
268 | reg |= bit; | ||
269 | else | ||
270 | reg &= ~bit; | ||
271 | |||
272 | writew(reg, ioaddr + RTC_RTCIENR); | ||
273 | spin_unlock_irq(&pdata->rtc->irq_lock); | ||
274 | } | ||
275 | |||
276 | static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) | ||
277 | { | ||
278 | mxc_rtc_irq_enable(dev, RTC_ALM_BIT, enabled); | ||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | static int mxc_rtc_update_irq_enable(struct device *dev, unsigned int enabled) | ||
283 | { | ||
284 | mxc_rtc_irq_enable(dev, RTC_1HZ_BIT, enabled); | ||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | /* | ||
289 | * This function reads the current RTC time into tm in Gregorian date. | ||
290 | */ | ||
291 | static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
292 | { | ||
293 | u32 val; | ||
294 | |||
295 | /* Avoid roll-over from reading the different registers */ | ||
296 | do { | ||
297 | val = get_alarm_or_time(dev, MXC_RTC_TIME); | ||
298 | } while (val != get_alarm_or_time(dev, MXC_RTC_TIME)); | ||
299 | |||
300 | rtc_time_to_tm(val, tm); | ||
301 | |||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | /* | ||
306 | * This function sets the internal RTC time based on tm in Gregorian date. | ||
307 | */ | ||
308 | static int mxc_rtc_set_mmss(struct device *dev, unsigned long time) | ||
309 | { | ||
310 | /* Avoid roll-over from reading the different registers */ | ||
311 | do { | ||
312 | set_alarm_or_time(dev, MXC_RTC_TIME, time); | ||
313 | } while (time != get_alarm_or_time(dev, MXC_RTC_TIME)); | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | /* | ||
319 | * This function reads the current alarm value into the passed in 'alrm' | ||
320 | * argument. It updates the alrm's pending field value based on the whether | ||
321 | * an alarm interrupt occurs or not. | ||
322 | */ | ||
323 | static int mxc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
324 | { | ||
325 | struct platform_device *pdev = to_platform_device(dev); | ||
326 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
327 | void __iomem *ioaddr = pdata->ioaddr; | ||
328 | |||
329 | rtc_time_to_tm(get_alarm_or_time(dev, MXC_RTC_ALARM), &alrm->time); | ||
330 | alrm->pending = ((readw(ioaddr + RTC_RTCISR) & RTC_ALM_BIT)) ? 1 : 0; | ||
331 | |||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | /* | ||
336 | * This function sets the RTC alarm based on passed in alrm. | ||
337 | */ | ||
338 | static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
339 | { | ||
340 | struct platform_device *pdev = to_platform_device(dev); | ||
341 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
342 | int ret; | ||
343 | |||
344 | if (rtc_valid_tm(&alrm->time)) { | ||
345 | if (alrm->time.tm_sec > 59 || | ||
346 | alrm->time.tm_hour > 23 || | ||
347 | alrm->time.tm_min > 59) | ||
348 | return -EINVAL; | ||
349 | |||
350 | ret = rtc_update_alarm(dev, &alrm->time); | ||
351 | } else { | ||
352 | ret = rtc_valid_tm(&alrm->time); | ||
353 | if (ret) | ||
354 | return ret; | ||
355 | |||
356 | ret = rtc_update_alarm(dev, &alrm->time); | ||
357 | } | ||
358 | |||
359 | if (ret) | ||
360 | return ret; | ||
361 | |||
362 | memcpy(&pdata->g_rtc_alarm, &alrm->time, sizeof(struct rtc_time)); | ||
363 | mxc_rtc_irq_enable(dev, RTC_ALM_BIT, alrm->enabled); | ||
364 | |||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | /* RTC layer */ | ||
369 | static struct rtc_class_ops mxc_rtc_ops = { | ||
370 | .release = mxc_rtc_release, | ||
371 | .read_time = mxc_rtc_read_time, | ||
372 | .set_mmss = mxc_rtc_set_mmss, | ||
373 | .read_alarm = mxc_rtc_read_alarm, | ||
374 | .set_alarm = mxc_rtc_set_alarm, | ||
375 | .alarm_irq_enable = mxc_rtc_alarm_irq_enable, | ||
376 | .update_irq_enable = mxc_rtc_update_irq_enable, | ||
377 | }; | ||
378 | |||
379 | static int __init mxc_rtc_probe(struct platform_device *pdev) | ||
380 | { | ||
381 | struct clk *clk; | ||
382 | struct resource *res; | ||
383 | struct rtc_device *rtc; | ||
384 | struct rtc_plat_data *pdata = NULL; | ||
385 | u32 reg; | ||
386 | int ret, rate; | ||
387 | |||
388 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
389 | if (!res) | ||
390 | return -ENODEV; | ||
391 | |||
392 | pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); | ||
393 | if (!pdata) | ||
394 | return -ENOMEM; | ||
395 | |||
396 | pdata->ioaddr = ioremap(res->start, resource_size(res)); | ||
397 | |||
398 | clk = clk_get(&pdev->dev, "ckil"); | ||
399 | if (IS_ERR(clk)) | ||
400 | return PTR_ERR(clk); | ||
401 | |||
402 | rate = clk_get_rate(clk); | ||
403 | clk_put(clk); | ||
404 | |||
405 | if (rate == 32768) | ||
406 | reg = RTC_INPUT_CLK_32768HZ; | ||
407 | else if (rate == 32000) | ||
408 | reg = RTC_INPUT_CLK_32000HZ; | ||
409 | else if (rate == 38400) | ||
410 | reg = RTC_INPUT_CLK_38400HZ; | ||
411 | else { | ||
412 | dev_err(&pdev->dev, "rtc clock is not valid (%lu)\n", | ||
413 | clk_get_rate(clk)); | ||
414 | ret = -EINVAL; | ||
415 | goto exit_free_pdata; | ||
416 | } | ||
417 | |||
418 | reg |= RTC_ENABLE_BIT; | ||
419 | writew(reg, (pdata->ioaddr + RTC_RTCCTL)); | ||
420 | if (((readw(pdata->ioaddr + RTC_RTCCTL)) & RTC_ENABLE_BIT) == 0) { | ||
421 | dev_err(&pdev->dev, "hardware module can't be enabled!\n"); | ||
422 | ret = -EIO; | ||
423 | goto exit_free_pdata; | ||
424 | } | ||
425 | |||
426 | pdata->clk = clk_get(&pdev->dev, "rtc"); | ||
427 | if (IS_ERR(pdata->clk)) { | ||
428 | dev_err(&pdev->dev, "unable to get clock!\n"); | ||
429 | ret = PTR_ERR(pdata->clk); | ||
430 | goto exit_free_pdata; | ||
431 | } | ||
432 | |||
433 | clk_enable(pdata->clk); | ||
434 | |||
435 | rtc = rtc_device_register(pdev->name, &pdev->dev, &mxc_rtc_ops, | ||
436 | THIS_MODULE); | ||
437 | if (IS_ERR(rtc)) { | ||
438 | ret = PTR_ERR(rtc); | ||
439 | goto exit_put_clk; | ||
440 | } | ||
441 | |||
442 | pdata->rtc = rtc; | ||
443 | platform_set_drvdata(pdev, pdata); | ||
444 | |||
445 | /* Configure and enable the RTC */ | ||
446 | pdata->irq = platform_get_irq(pdev, 0); | ||
447 | |||
448 | if (pdata->irq >= 0 && | ||
449 | request_irq(pdata->irq, mxc_rtc_interrupt, IRQF_SHARED, | ||
450 | pdev->name, pdev) < 0) { | ||
451 | dev_warn(&pdev->dev, "interrupt not available.\n"); | ||
452 | pdata->irq = -1; | ||
453 | } | ||
454 | |||
455 | return 0; | ||
456 | |||
457 | exit_put_clk: | ||
458 | clk_put(pdata->clk); | ||
459 | |||
460 | exit_free_pdata: | ||
461 | kfree(pdata); | ||
462 | |||
463 | return ret; | ||
464 | } | ||
465 | |||
466 | static int __exit mxc_rtc_remove(struct platform_device *pdev) | ||
467 | { | ||
468 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
469 | |||
470 | rtc_device_unregister(pdata->rtc); | ||
471 | |||
472 | if (pdata->irq >= 0) | ||
473 | free_irq(pdata->irq, pdev); | ||
474 | |||
475 | clk_disable(pdata->clk); | ||
476 | clk_put(pdata->clk); | ||
477 | kfree(pdata); | ||
478 | platform_set_drvdata(pdev, NULL); | ||
479 | |||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | static struct platform_driver mxc_rtc_driver = { | ||
484 | .driver = { | ||
485 | .name = "mxc_rtc", | ||
486 | .owner = THIS_MODULE, | ||
487 | }, | ||
488 | .remove = __exit_p(mxc_rtc_remove), | ||
489 | }; | ||
490 | |||
491 | static int __init mxc_rtc_init(void) | ||
492 | { | ||
493 | return platform_driver_probe(&mxc_rtc_driver, mxc_rtc_probe); | ||
494 | } | ||
495 | |||
496 | static void __exit mxc_rtc_exit(void) | ||
497 | { | ||
498 | platform_driver_unregister(&mxc_rtc_driver); | ||
499 | } | ||
500 | |||
501 | module_init(mxc_rtc_init); | ||
502 | module_exit(mxc_rtc_exit); | ||
503 | |||
504 | MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); | ||
505 | MODULE_DESCRIPTION("RTC driver for Freescale MXC"); | ||
506 | MODULE_LICENSE("GPL"); | ||
507 | |||
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index bd1ce8e2bc18..0587d53987fe 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c | |||
@@ -430,7 +430,7 @@ fail: | |||
430 | 430 | ||
431 | static int __exit omap_rtc_remove(struct platform_device *pdev) | 431 | static int __exit omap_rtc_remove(struct platform_device *pdev) |
432 | { | 432 | { |
433 | struct rtc_device *rtc = platform_get_drvdata(pdev);; | 433 | struct rtc_device *rtc = platform_get_drvdata(pdev); |
434 | 434 | ||
435 | device_init_wakeup(&pdev->dev, 0); | 435 | device_init_wakeup(&pdev->dev, 0); |
436 | 436 | ||
diff --git a/drivers/rtc/rtc-pcap.c b/drivers/rtc/rtc-pcap.c new file mode 100644 index 000000000000..a99c28992d21 --- /dev/null +++ b/drivers/rtc/rtc-pcap.c | |||
@@ -0,0 +1,224 @@ | |||
1 | /* | ||
2 | * pcap rtc code for Motorola EZX phones | ||
3 | * | ||
4 | * Copyright (c) 2008 guiming zhuo <gmzhuo@gmail.com> | ||
5 | * Copyright (c) 2009 Daniel Ribeiro <drwyrm@gmail.com> | ||
6 | * | ||
7 | * Based on Motorola's rtc.c Copyright (c) 2003-2005 Motorola | ||
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 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/mfd/ezx-pcap.h> | ||
19 | #include <linux/rtc.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | |||
22 | struct pcap_rtc { | ||
23 | struct pcap_chip *pcap; | ||
24 | struct rtc_device *rtc; | ||
25 | }; | ||
26 | |||
27 | static irqreturn_t pcap_rtc_irq(int irq, void *_pcap_rtc) | ||
28 | { | ||
29 | struct pcap_rtc *pcap_rtc = _pcap_rtc; | ||
30 | unsigned long rtc_events; | ||
31 | |||
32 | if (irq == pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_1HZ)) | ||
33 | rtc_events = RTC_IRQF | RTC_UF; | ||
34 | else if (irq == pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_TODA)) | ||
35 | rtc_events = RTC_IRQF | RTC_AF; | ||
36 | else | ||
37 | rtc_events = 0; | ||
38 | |||
39 | rtc_update_irq(pcap_rtc->rtc, 1, rtc_events); | ||
40 | return IRQ_HANDLED; | ||
41 | } | ||
42 | |||
43 | static int pcap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
44 | { | ||
45 | struct platform_device *pdev = to_platform_device(dev); | ||
46 | struct pcap_rtc *pcap_rtc = platform_get_drvdata(pdev); | ||
47 | struct rtc_time *tm = &alrm->time; | ||
48 | unsigned long secs; | ||
49 | u32 tod; /* time of day, seconds since midnight */ | ||
50 | u32 days; /* days since 1/1/1970 */ | ||
51 | |||
52 | ezx_pcap_read(pcap_rtc->pcap, PCAP_REG_RTC_TODA, &tod); | ||
53 | secs = tod & PCAP_RTC_TOD_MASK; | ||
54 | |||
55 | ezx_pcap_read(pcap_rtc->pcap, PCAP_REG_RTC_DAYA, &days); | ||
56 | secs += (days & PCAP_RTC_DAY_MASK) * SEC_PER_DAY; | ||
57 | |||
58 | rtc_time_to_tm(secs, tm); | ||
59 | |||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | static int pcap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
64 | { | ||
65 | struct platform_device *pdev = to_platform_device(dev); | ||
66 | struct pcap_rtc *pcap_rtc = platform_get_drvdata(pdev); | ||
67 | struct rtc_time *tm = &alrm->time; | ||
68 | unsigned long secs; | ||
69 | u32 tod, days; | ||
70 | |||
71 | rtc_tm_to_time(tm, &secs); | ||
72 | |||
73 | tod = secs % SEC_PER_DAY; | ||
74 | ezx_pcap_write(pcap_rtc->pcap, PCAP_REG_RTC_TODA, tod); | ||
75 | |||
76 | days = secs / SEC_PER_DAY; | ||
77 | ezx_pcap_write(pcap_rtc->pcap, PCAP_REG_RTC_DAYA, days); | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static int pcap_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
83 | { | ||
84 | struct platform_device *pdev = to_platform_device(dev); | ||
85 | struct pcap_rtc *pcap_rtc = platform_get_drvdata(pdev); | ||
86 | unsigned long secs; | ||
87 | u32 tod, days; | ||
88 | |||
89 | ezx_pcap_read(pcap_rtc->pcap, PCAP_REG_RTC_TOD, &tod); | ||
90 | secs = tod & PCAP_RTC_TOD_MASK; | ||
91 | |||
92 | ezx_pcap_read(pcap_rtc->pcap, PCAP_REG_RTC_DAY, &days); | ||
93 | secs += (days & PCAP_RTC_DAY_MASK) * SEC_PER_DAY; | ||
94 | |||
95 | rtc_time_to_tm(secs, tm); | ||
96 | |||
97 | return rtc_valid_tm(tm); | ||
98 | } | ||
99 | |||
100 | static int pcap_rtc_set_mmss(struct device *dev, unsigned long secs) | ||
101 | { | ||
102 | struct platform_device *pdev = to_platform_device(dev); | ||
103 | struct pcap_rtc *pcap_rtc = platform_get_drvdata(pdev); | ||
104 | u32 tod, days; | ||
105 | |||
106 | tod = secs % SEC_PER_DAY; | ||
107 | ezx_pcap_write(pcap_rtc->pcap, PCAP_REG_RTC_TOD, tod); | ||
108 | |||
109 | days = secs / SEC_PER_DAY; | ||
110 | ezx_pcap_write(pcap_rtc->pcap, PCAP_REG_RTC_DAY, days); | ||
111 | |||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static int pcap_rtc_irq_enable(struct device *dev, int pirq, unsigned int en) | ||
116 | { | ||
117 | struct platform_device *pdev = to_platform_device(dev); | ||
118 | struct pcap_rtc *pcap_rtc = platform_get_drvdata(pdev); | ||
119 | |||
120 | if (en) | ||
121 | enable_irq(pcap_to_irq(pcap_rtc->pcap, pirq)); | ||
122 | else | ||
123 | disable_irq(pcap_to_irq(pcap_rtc->pcap, pirq)); | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static int pcap_rtc_alarm_irq_enable(struct device *dev, unsigned int en) | ||
129 | { | ||
130 | return pcap_rtc_irq_enable(dev, PCAP_IRQ_TODA, en); | ||
131 | } | ||
132 | |||
133 | static int pcap_rtc_update_irq_enable(struct device *dev, unsigned int en) | ||
134 | { | ||
135 | return pcap_rtc_irq_enable(dev, PCAP_IRQ_1HZ, en); | ||
136 | } | ||
137 | |||
138 | static const struct rtc_class_ops pcap_rtc_ops = { | ||
139 | .read_time = pcap_rtc_read_time, | ||
140 | .read_alarm = pcap_rtc_read_alarm, | ||
141 | .set_alarm = pcap_rtc_set_alarm, | ||
142 | .set_mmss = pcap_rtc_set_mmss, | ||
143 | .alarm_irq_enable = pcap_rtc_alarm_irq_enable, | ||
144 | .update_irq_enable = pcap_rtc_update_irq_enable, | ||
145 | }; | ||
146 | |||
147 | static int __devinit pcap_rtc_probe(struct platform_device *pdev) | ||
148 | { | ||
149 | struct pcap_rtc *pcap_rtc; | ||
150 | int timer_irq, alarm_irq; | ||
151 | int err = -ENOMEM; | ||
152 | |||
153 | pcap_rtc = kmalloc(sizeof(struct pcap_rtc), GFP_KERNEL); | ||
154 | if (!pcap_rtc) | ||
155 | return err; | ||
156 | |||
157 | pcap_rtc->pcap = dev_get_drvdata(pdev->dev.parent); | ||
158 | |||
159 | pcap_rtc->rtc = rtc_device_register("pcap", &pdev->dev, | ||
160 | &pcap_rtc_ops, THIS_MODULE); | ||
161 | if (IS_ERR(pcap_rtc->rtc)) { | ||
162 | err = PTR_ERR(pcap_rtc->rtc); | ||
163 | goto fail_rtc; | ||
164 | } | ||
165 | |||
166 | platform_set_drvdata(pdev, pcap_rtc); | ||
167 | |||
168 | timer_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_1HZ); | ||
169 | alarm_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_TODA); | ||
170 | |||
171 | err = request_irq(timer_irq, pcap_rtc_irq, 0, "RTC Timer", pcap_rtc); | ||
172 | if (err) | ||
173 | goto fail_timer; | ||
174 | |||
175 | err = request_irq(alarm_irq, pcap_rtc_irq, 0, "RTC Alarm", pcap_rtc); | ||
176 | if (err) | ||
177 | goto fail_alarm; | ||
178 | |||
179 | return 0; | ||
180 | fail_alarm: | ||
181 | free_irq(timer_irq, pcap_rtc); | ||
182 | fail_timer: | ||
183 | rtc_device_unregister(pcap_rtc->rtc); | ||
184 | fail_rtc: | ||
185 | kfree(pcap_rtc); | ||
186 | return err; | ||
187 | } | ||
188 | |||
189 | static int __devexit pcap_rtc_remove(struct platform_device *pdev) | ||
190 | { | ||
191 | struct pcap_rtc *pcap_rtc = platform_get_drvdata(pdev); | ||
192 | |||
193 | free_irq(pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_1HZ), pcap_rtc); | ||
194 | free_irq(pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_TODA), pcap_rtc); | ||
195 | rtc_device_unregister(pcap_rtc->rtc); | ||
196 | kfree(pcap_rtc); | ||
197 | |||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static struct platform_driver pcap_rtc_driver = { | ||
202 | .remove = __devexit_p(pcap_rtc_remove), | ||
203 | .driver = { | ||
204 | .name = "pcap-rtc", | ||
205 | .owner = THIS_MODULE, | ||
206 | }, | ||
207 | }; | ||
208 | |||
209 | static int __init rtc_pcap_init(void) | ||
210 | { | ||
211 | return platform_driver_probe(&pcap_rtc_driver, pcap_rtc_probe); | ||
212 | } | ||
213 | |||
214 | static void __exit rtc_pcap_exit(void) | ||
215 | { | ||
216 | platform_driver_unregister(&pcap_rtc_driver); | ||
217 | } | ||
218 | |||
219 | module_init(rtc_pcap_init); | ||
220 | module_exit(rtc_pcap_exit); | ||
221 | |||
222 | MODULE_DESCRIPTION("Motorola pcap rtc driver"); | ||
223 | MODULE_AUTHOR("guiming zhuo <gmzhuo@gmail.com>"); | ||
224 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c new file mode 100644 index 000000000000..e75df9d50e27 --- /dev/null +++ b/drivers/rtc/rtc-pcf2123.c | |||
@@ -0,0 +1,364 @@ | |||
1 | /* | ||
2 | * An SPI driver for the Philips PCF2123 RTC | ||
3 | * Copyright 2009 Cyber Switching, Inc. | ||
4 | * | ||
5 | * Author: Chris Verges <chrisv@cyberswitching.com> | ||
6 | * Maintainers: http://www.cyberswitching.com | ||
7 | * | ||
8 | * based on the RS5C348 driver in this same directory. | ||
9 | * | ||
10 | * Thanks to Christian Pellegrin <chripell@fsfe.org> for | ||
11 | * the sysfs contributions to this driver. | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License version 2 as | ||
15 | * published by the Free Software Foundation. | ||
16 | * | ||
17 | * Please note that the CS is active high, so platform data | ||
18 | * should look something like: | ||
19 | * | ||
20 | * static struct spi_board_info ek_spi_devices[] = { | ||
21 | * ... | ||
22 | * { | ||
23 | * .modalias = "rtc-pcf2123", | ||
24 | * .chip_select = 1, | ||
25 | * .controller_data = (void *)AT91_PIN_PA10, | ||
26 | * .max_speed_hz = 1000 * 1000, | ||
27 | * .mode = SPI_CS_HIGH, | ||
28 | * .bus_num = 0, | ||
29 | * }, | ||
30 | * ... | ||
31 | *}; | ||
32 | * | ||
33 | */ | ||
34 | |||
35 | #include <linux/bcd.h> | ||
36 | #include <linux/delay.h> | ||
37 | #include <linux/device.h> | ||
38 | #include <linux/errno.h> | ||
39 | #include <linux/init.h> | ||
40 | #include <linux/kernel.h> | ||
41 | #include <linux/string.h> | ||
42 | #include <linux/rtc.h> | ||
43 | #include <linux/spi/spi.h> | ||
44 | |||
45 | #define DRV_VERSION "0.6" | ||
46 | |||
47 | #define PCF2123_REG_CTRL1 (0x00) /* Control Register 1 */ | ||
48 | #define PCF2123_REG_CTRL2 (0x01) /* Control Register 2 */ | ||
49 | #define PCF2123_REG_SC (0x02) /* datetime */ | ||
50 | #define PCF2123_REG_MN (0x03) | ||
51 | #define PCF2123_REG_HR (0x04) | ||
52 | #define PCF2123_REG_DM (0x05) | ||
53 | #define PCF2123_REG_DW (0x06) | ||
54 | #define PCF2123_REG_MO (0x07) | ||
55 | #define PCF2123_REG_YR (0x08) | ||
56 | |||
57 | #define PCF2123_SUBADDR (1 << 4) | ||
58 | #define PCF2123_WRITE ((0 << 7) | PCF2123_SUBADDR) | ||
59 | #define PCF2123_READ ((1 << 7) | PCF2123_SUBADDR) | ||
60 | |||
61 | static struct spi_driver pcf2123_driver; | ||
62 | |||
63 | struct pcf2123_sysfs_reg { | ||
64 | struct device_attribute attr; | ||
65 | char name[2]; | ||
66 | }; | ||
67 | |||
68 | struct pcf2123_plat_data { | ||
69 | struct rtc_device *rtc; | ||
70 | struct pcf2123_sysfs_reg regs[16]; | ||
71 | }; | ||
72 | |||
73 | /* | ||
74 | * Causes a 30 nanosecond delay to ensure that the PCF2123 chip select | ||
75 | * is released properly after an SPI write. This function should be | ||
76 | * called after EVERY read/write call over SPI. | ||
77 | */ | ||
78 | static inline void pcf2123_delay_trec(void) | ||
79 | { | ||
80 | ndelay(30); | ||
81 | } | ||
82 | |||
83 | static ssize_t pcf2123_show(struct device *dev, struct device_attribute *attr, | ||
84 | char *buffer) | ||
85 | { | ||
86 | struct spi_device *spi = to_spi_device(dev); | ||
87 | struct pcf2123_sysfs_reg *r; | ||
88 | u8 txbuf[1], rxbuf[1]; | ||
89 | unsigned long reg; | ||
90 | int ret; | ||
91 | |||
92 | r = container_of(attr, struct pcf2123_sysfs_reg, attr); | ||
93 | |||
94 | if (strict_strtoul(r->name, 16, ®)) | ||
95 | return -EINVAL; | ||
96 | |||
97 | txbuf[0] = PCF2123_READ | reg; | ||
98 | ret = spi_write_then_read(spi, txbuf, 1, rxbuf, 1); | ||
99 | if (ret < 0) | ||
100 | return -EIO; | ||
101 | pcf2123_delay_trec(); | ||
102 | return sprintf(buffer, "0x%x\n", rxbuf[0]); | ||
103 | } | ||
104 | |||
105 | static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr, | ||
106 | const char *buffer, size_t count) { | ||
107 | struct spi_device *spi = to_spi_device(dev); | ||
108 | struct pcf2123_sysfs_reg *r; | ||
109 | u8 txbuf[2]; | ||
110 | unsigned long reg; | ||
111 | unsigned long val; | ||
112 | |||
113 | int ret; | ||
114 | |||
115 | r = container_of(attr, struct pcf2123_sysfs_reg, attr); | ||
116 | |||
117 | if (strict_strtoul(r->name, 16, ®) | ||
118 | || strict_strtoul(buffer, 10, &val)) | ||
119 | return -EINVAL; | ||
120 | |||
121 | txbuf[0] = PCF2123_WRITE | reg; | ||
122 | txbuf[1] = val; | ||
123 | ret = spi_write(spi, txbuf, sizeof(txbuf)); | ||
124 | if (ret < 0) | ||
125 | return -EIO; | ||
126 | pcf2123_delay_trec(); | ||
127 | return count; | ||
128 | } | ||
129 | |||
130 | static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
131 | { | ||
132 | struct spi_device *spi = to_spi_device(dev); | ||
133 | u8 txbuf[1], rxbuf[7]; | ||
134 | int ret; | ||
135 | |||
136 | txbuf[0] = PCF2123_READ | PCF2123_REG_SC; | ||
137 | ret = spi_write_then_read(spi, txbuf, sizeof(txbuf), | ||
138 | rxbuf, sizeof(rxbuf)); | ||
139 | if (ret < 0) | ||
140 | return ret; | ||
141 | pcf2123_delay_trec(); | ||
142 | |||
143 | tm->tm_sec = bcd2bin(rxbuf[0] & 0x7F); | ||
144 | tm->tm_min = bcd2bin(rxbuf[1] & 0x7F); | ||
145 | tm->tm_hour = bcd2bin(rxbuf[2] & 0x3F); /* rtc hr 0-23 */ | ||
146 | tm->tm_mday = bcd2bin(rxbuf[3] & 0x3F); | ||
147 | tm->tm_wday = rxbuf[4] & 0x07; | ||
148 | tm->tm_mon = bcd2bin(rxbuf[5] & 0x1F) - 1; /* rtc mn 1-12 */ | ||
149 | tm->tm_year = bcd2bin(rxbuf[6]); | ||
150 | if (tm->tm_year < 70) | ||
151 | tm->tm_year += 100; /* assume we are in 1970...2069 */ | ||
152 | |||
153 | dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " | ||
154 | "mday=%d, mon=%d, year=%d, wday=%d\n", | ||
155 | __func__, | ||
156 | tm->tm_sec, tm->tm_min, tm->tm_hour, | ||
157 | tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); | ||
158 | |||
159 | /* the clock can give out invalid datetime, but we cannot return | ||
160 | * -EINVAL otherwise hwclock will refuse to set the time on bootup. | ||
161 | */ | ||
162 | if (rtc_valid_tm(tm) < 0) | ||
163 | dev_err(dev, "retrieved date/time is not valid.\n"); | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
169 | { | ||
170 | struct spi_device *spi = to_spi_device(dev); | ||
171 | u8 txbuf[8]; | ||
172 | int ret; | ||
173 | |||
174 | dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " | ||
175 | "mday=%d, mon=%d, year=%d, wday=%d\n", | ||
176 | __func__, | ||
177 | tm->tm_sec, tm->tm_min, tm->tm_hour, | ||
178 | tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); | ||
179 | |||
180 | /* Stop the counter first */ | ||
181 | txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1; | ||
182 | txbuf[1] = 0x20; | ||
183 | ret = spi_write(spi, txbuf, 2); | ||
184 | if (ret < 0) | ||
185 | return ret; | ||
186 | pcf2123_delay_trec(); | ||
187 | |||
188 | /* Set the new time */ | ||
189 | txbuf[0] = PCF2123_WRITE | PCF2123_REG_SC; | ||
190 | txbuf[1] = bin2bcd(tm->tm_sec & 0x7F); | ||
191 | txbuf[2] = bin2bcd(tm->tm_min & 0x7F); | ||
192 | txbuf[3] = bin2bcd(tm->tm_hour & 0x3F); | ||
193 | txbuf[4] = bin2bcd(tm->tm_mday & 0x3F); | ||
194 | txbuf[5] = tm->tm_wday & 0x07; | ||
195 | txbuf[6] = bin2bcd((tm->tm_mon + 1) & 0x1F); /* rtc mn 1-12 */ | ||
196 | txbuf[7] = bin2bcd(tm->tm_year < 100 ? tm->tm_year : tm->tm_year - 100); | ||
197 | |||
198 | ret = spi_write(spi, txbuf, sizeof(txbuf)); | ||
199 | if (ret < 0) | ||
200 | return ret; | ||
201 | pcf2123_delay_trec(); | ||
202 | |||
203 | /* Start the counter */ | ||
204 | txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1; | ||
205 | txbuf[1] = 0x00; | ||
206 | ret = spi_write(spi, txbuf, 2); | ||
207 | if (ret < 0) | ||
208 | return ret; | ||
209 | pcf2123_delay_trec(); | ||
210 | |||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | static const struct rtc_class_ops pcf2123_rtc_ops = { | ||
215 | .read_time = pcf2123_rtc_read_time, | ||
216 | .set_time = pcf2123_rtc_set_time, | ||
217 | }; | ||
218 | |||
219 | static int __devinit pcf2123_probe(struct spi_device *spi) | ||
220 | { | ||
221 | struct rtc_device *rtc; | ||
222 | struct pcf2123_plat_data *pdata; | ||
223 | u8 txbuf[2], rxbuf[2]; | ||
224 | int ret, i; | ||
225 | |||
226 | pdata = kzalloc(sizeof(struct pcf2123_plat_data), GFP_KERNEL); | ||
227 | if (!pdata) | ||
228 | return -ENOMEM; | ||
229 | spi->dev.platform_data = pdata; | ||
230 | |||
231 | /* Send a software reset command */ | ||
232 | txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1; | ||
233 | txbuf[1] = 0x58; | ||
234 | dev_dbg(&spi->dev, "resetting RTC (0x%02X 0x%02X)\n", | ||
235 | txbuf[0], txbuf[1]); | ||
236 | ret = spi_write(spi, txbuf, 2 * sizeof(u8)); | ||
237 | if (ret < 0) | ||
238 | goto kfree_exit; | ||
239 | pcf2123_delay_trec(); | ||
240 | |||
241 | /* Stop the counter */ | ||
242 | txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1; | ||
243 | txbuf[1] = 0x20; | ||
244 | dev_dbg(&spi->dev, "stopping RTC (0x%02X 0x%02X)\n", | ||
245 | txbuf[0], txbuf[1]); | ||
246 | ret = spi_write(spi, txbuf, 2 * sizeof(u8)); | ||
247 | if (ret < 0) | ||
248 | goto kfree_exit; | ||
249 | pcf2123_delay_trec(); | ||
250 | |||
251 | /* See if the counter was actually stopped */ | ||
252 | txbuf[0] = PCF2123_READ | PCF2123_REG_CTRL1; | ||
253 | dev_dbg(&spi->dev, "checking for presence of RTC (0x%02X)\n", | ||
254 | txbuf[0]); | ||
255 | ret = spi_write_then_read(spi, txbuf, 1 * sizeof(u8), | ||
256 | rxbuf, 2 * sizeof(u8)); | ||
257 | dev_dbg(&spi->dev, "received data from RTC (0x%02X 0x%02X)\n", | ||
258 | rxbuf[0], rxbuf[1]); | ||
259 | if (ret < 0) | ||
260 | goto kfree_exit; | ||
261 | pcf2123_delay_trec(); | ||
262 | |||
263 | if (!(rxbuf[0] & 0x20)) { | ||
264 | dev_err(&spi->dev, "chip not found\n"); | ||
265 | goto kfree_exit; | ||
266 | } | ||
267 | |||
268 | dev_info(&spi->dev, "chip found, driver version " DRV_VERSION "\n"); | ||
269 | dev_info(&spi->dev, "spiclk %u KHz.\n", | ||
270 | (spi->max_speed_hz + 500) / 1000); | ||
271 | |||
272 | /* Start the counter */ | ||
273 | txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1; | ||
274 | txbuf[1] = 0x00; | ||
275 | ret = spi_write(spi, txbuf, sizeof(txbuf)); | ||
276 | if (ret < 0) | ||
277 | goto kfree_exit; | ||
278 | pcf2123_delay_trec(); | ||
279 | |||
280 | /* Finalize the initialization */ | ||
281 | rtc = rtc_device_register(pcf2123_driver.driver.name, &spi->dev, | ||
282 | &pcf2123_rtc_ops, THIS_MODULE); | ||
283 | |||
284 | if (IS_ERR(rtc)) { | ||
285 | dev_err(&spi->dev, "failed to register.\n"); | ||
286 | ret = PTR_ERR(rtc); | ||
287 | goto kfree_exit; | ||
288 | } | ||
289 | |||
290 | pdata->rtc = rtc; | ||
291 | |||
292 | for (i = 0; i < 16; i++) { | ||
293 | sprintf(pdata->regs[i].name, "%1x", i); | ||
294 | pdata->regs[i].attr.attr.mode = S_IRUGO | S_IWUSR; | ||
295 | pdata->regs[i].attr.attr.name = pdata->regs[i].name; | ||
296 | pdata->regs[i].attr.show = pcf2123_show; | ||
297 | pdata->regs[i].attr.store = pcf2123_store; | ||
298 | ret = device_create_file(&spi->dev, &pdata->regs[i].attr); | ||
299 | if (ret) { | ||
300 | dev_err(&spi->dev, "Unable to create sysfs %s\n", | ||
301 | pdata->regs[i].name); | ||
302 | goto sysfs_exit; | ||
303 | } | ||
304 | } | ||
305 | |||
306 | return 0; | ||
307 | |||
308 | sysfs_exit: | ||
309 | for (i--; i >= 0; i--) | ||
310 | device_remove_file(&spi->dev, &pdata->regs[i].attr); | ||
311 | |||
312 | kfree_exit: | ||
313 | kfree(pdata); | ||
314 | spi->dev.platform_data = NULL; | ||
315 | return ret; | ||
316 | } | ||
317 | |||
318 | static int pcf2123_remove(struct spi_device *spi) | ||
319 | { | ||
320 | struct pcf2123_plat_data *pdata = spi->dev.platform_data; | ||
321 | int i; | ||
322 | |||
323 | if (pdata) { | ||
324 | struct rtc_device *rtc = pdata->rtc; | ||
325 | |||
326 | if (rtc) | ||
327 | rtc_device_unregister(rtc); | ||
328 | for (i = 0; i < 16; i++) | ||
329 | if (pdata->regs[i].name[0]) | ||
330 | device_remove_file(&spi->dev, | ||
331 | &pdata->regs[i].attr); | ||
332 | kfree(pdata); | ||
333 | } | ||
334 | |||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | static struct spi_driver pcf2123_driver = { | ||
339 | .driver = { | ||
340 | .name = "rtc-pcf2123", | ||
341 | .bus = &spi_bus_type, | ||
342 | .owner = THIS_MODULE, | ||
343 | }, | ||
344 | .probe = pcf2123_probe, | ||
345 | .remove = __devexit_p(pcf2123_remove), | ||
346 | }; | ||
347 | |||
348 | static int __init pcf2123_init(void) | ||
349 | { | ||
350 | return spi_register_driver(&pcf2123_driver); | ||
351 | } | ||
352 | |||
353 | static void __exit pcf2123_exit(void) | ||
354 | { | ||
355 | spi_unregister_driver(&pcf2123_driver); | ||
356 | } | ||
357 | |||
358 | MODULE_AUTHOR("Chris Verges <chrisv@cyberswitching.com>"); | ||
359 | MODULE_DESCRIPTION("NXP PCF2123 RTC driver"); | ||
360 | MODULE_LICENSE("GPL"); | ||
361 | MODULE_VERSION(DRV_VERSION); | ||
362 | |||
363 | module_init(pcf2123_init); | ||
364 | module_exit(pcf2123_exit); | ||
diff --git a/drivers/rtc/rtc-r9701.c b/drivers/rtc/rtc-r9701.c index 42028f233bef..9beba49c3c5b 100644 --- a/drivers/rtc/rtc-r9701.c +++ b/drivers/rtc/rtc-r9701.c | |||
@@ -174,3 +174,4 @@ module_exit(r9701_exit); | |||
174 | MODULE_DESCRIPTION("r9701 spi RTC driver"); | 174 | MODULE_DESCRIPTION("r9701 spi RTC driver"); |
175 | MODULE_AUTHOR("Magnus Damm <damm@opensource.se>"); | 175 | MODULE_AUTHOR("Magnus Damm <damm@opensource.se>"); |
176 | MODULE_LICENSE("GPL"); | 176 | MODULE_LICENSE("GPL"); |
177 | MODULE_ALIAS("spi:rtc-r9701"); | ||
diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c index dd1e2bc7a472..2099037cb3ea 100644 --- a/drivers/rtc/rtc-rs5c348.c +++ b/drivers/rtc/rtc-rs5c348.c | |||
@@ -251,3 +251,4 @@ MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>"); | |||
251 | MODULE_DESCRIPTION("Ricoh RS5C348 RTC driver"); | 251 | MODULE_DESCRIPTION("Ricoh RS5C348 RTC driver"); |
252 | MODULE_LICENSE("GPL"); | 252 | MODULE_LICENSE("GPL"); |
253 | MODULE_VERSION(DRV_VERSION); | 253 | MODULE_VERSION(DRV_VERSION); |
254 | MODULE_ALIAS("spi:rtc-rs5c348"); | ||
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index d7310adb7152..e6ed5404bca0 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c | |||
@@ -29,7 +29,7 @@ | |||
29 | #include <asm/rtc.h> | 29 | #include <asm/rtc.h> |
30 | 30 | ||
31 | #define DRV_NAME "sh-rtc" | 31 | #define DRV_NAME "sh-rtc" |
32 | #define DRV_VERSION "0.2.2" | 32 | #define DRV_VERSION "0.2.3" |
33 | 33 | ||
34 | #define RTC_REG(r) ((r) * rtc_reg_size) | 34 | #define RTC_REG(r) ((r) * rtc_reg_size) |
35 | 35 | ||
@@ -215,7 +215,7 @@ static irqreturn_t sh_rtc_shared(int irq, void *dev_id) | |||
215 | return IRQ_RETVAL(ret); | 215 | return IRQ_RETVAL(ret); |
216 | } | 216 | } |
217 | 217 | ||
218 | static inline void sh_rtc_setpie(struct device *dev, unsigned int enable) | 218 | static int sh_rtc_irq_set_state(struct device *dev, int enable) |
219 | { | 219 | { |
220 | struct sh_rtc *rtc = dev_get_drvdata(dev); | 220 | struct sh_rtc *rtc = dev_get_drvdata(dev); |
221 | unsigned int tmp; | 221 | unsigned int tmp; |
@@ -225,17 +225,22 @@ static inline void sh_rtc_setpie(struct device *dev, unsigned int enable) | |||
225 | tmp = readb(rtc->regbase + RCR2); | 225 | tmp = readb(rtc->regbase + RCR2); |
226 | 226 | ||
227 | if (enable) { | 227 | if (enable) { |
228 | rtc->periodic_freq |= PF_KOU; | ||
228 | tmp &= ~RCR2_PEF; /* Clear PES bit */ | 229 | tmp &= ~RCR2_PEF; /* Clear PES bit */ |
229 | tmp |= (rtc->periodic_freq & ~PF_HP); /* Set PES2-0 */ | 230 | tmp |= (rtc->periodic_freq & ~PF_HP); /* Set PES2-0 */ |
230 | } else | 231 | } else { |
232 | rtc->periodic_freq &= ~PF_KOU; | ||
231 | tmp &= ~(RCR2_PESMASK | RCR2_PEF); | 233 | tmp &= ~(RCR2_PESMASK | RCR2_PEF); |
234 | } | ||
232 | 235 | ||
233 | writeb(tmp, rtc->regbase + RCR2); | 236 | writeb(tmp, rtc->regbase + RCR2); |
234 | 237 | ||
235 | spin_unlock_irq(&rtc->lock); | 238 | spin_unlock_irq(&rtc->lock); |
239 | |||
240 | return 0; | ||
236 | } | 241 | } |
237 | 242 | ||
238 | static inline int sh_rtc_setfreq(struct device *dev, unsigned int freq) | 243 | static int sh_rtc_irq_set_freq(struct device *dev, int freq) |
239 | { | 244 | { |
240 | struct sh_rtc *rtc = dev_get_drvdata(dev); | 245 | struct sh_rtc *rtc = dev_get_drvdata(dev); |
241 | int tmp, ret = 0; | 246 | int tmp, ret = 0; |
@@ -278,10 +283,8 @@ static inline int sh_rtc_setfreq(struct device *dev, unsigned int freq) | |||
278 | ret = -ENOTSUPP; | 283 | ret = -ENOTSUPP; |
279 | } | 284 | } |
280 | 285 | ||
281 | if (ret == 0) { | 286 | if (ret == 0) |
282 | rtc->periodic_freq |= tmp; | 287 | rtc->periodic_freq |= tmp; |
283 | rtc->rtc_dev->irq_freq = freq; | ||
284 | } | ||
285 | 288 | ||
286 | spin_unlock_irq(&rtc->lock); | 289 | spin_unlock_irq(&rtc->lock); |
287 | return ret; | 290 | return ret; |
@@ -346,10 +349,6 @@ static int sh_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) | |||
346 | unsigned int ret = 0; | 349 | unsigned int ret = 0; |
347 | 350 | ||
348 | switch (cmd) { | 351 | switch (cmd) { |
349 | case RTC_PIE_OFF: | ||
350 | case RTC_PIE_ON: | ||
351 | sh_rtc_setpie(dev, cmd == RTC_PIE_ON); | ||
352 | break; | ||
353 | case RTC_AIE_OFF: | 352 | case RTC_AIE_OFF: |
354 | case RTC_AIE_ON: | 353 | case RTC_AIE_ON: |
355 | sh_rtc_setaie(dev, cmd == RTC_AIE_ON); | 354 | sh_rtc_setaie(dev, cmd == RTC_AIE_ON); |
@@ -362,13 +361,6 @@ static int sh_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) | |||
362 | rtc->periodic_freq |= PF_OXS; | 361 | rtc->periodic_freq |= PF_OXS; |
363 | sh_rtc_setcie(dev, 1); | 362 | sh_rtc_setcie(dev, 1); |
364 | break; | 363 | break; |
365 | case RTC_IRQP_READ: | ||
366 | ret = put_user(rtc->rtc_dev->irq_freq, | ||
367 | (unsigned long __user *)arg); | ||
368 | break; | ||
369 | case RTC_IRQP_SET: | ||
370 | ret = sh_rtc_setfreq(dev, arg); | ||
371 | break; | ||
372 | default: | 364 | default: |
373 | ret = -ENOIOCTLCMD; | 365 | ret = -ENOIOCTLCMD; |
374 | } | 366 | } |
@@ -602,28 +594,6 @@ static int sh_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) | |||
602 | return 0; | 594 | return 0; |
603 | } | 595 | } |
604 | 596 | ||
605 | static int sh_rtc_irq_set_state(struct device *dev, int enabled) | ||
606 | { | ||
607 | struct platform_device *pdev = to_platform_device(dev); | ||
608 | struct sh_rtc *rtc = platform_get_drvdata(pdev); | ||
609 | |||
610 | if (enabled) { | ||
611 | rtc->periodic_freq |= PF_KOU; | ||
612 | return sh_rtc_ioctl(dev, RTC_PIE_ON, 0); | ||
613 | } else { | ||
614 | rtc->periodic_freq &= ~PF_KOU; | ||
615 | return sh_rtc_ioctl(dev, RTC_PIE_OFF, 0); | ||
616 | } | ||
617 | } | ||
618 | |||
619 | static int sh_rtc_irq_set_freq(struct device *dev, int freq) | ||
620 | { | ||
621 | if (!is_power_of_2(freq)) | ||
622 | return -EINVAL; | ||
623 | |||
624 | return sh_rtc_ioctl(dev, RTC_IRQP_SET, freq); | ||
625 | } | ||
626 | |||
627 | static struct rtc_class_ops sh_rtc_ops = { | 597 | static struct rtc_class_ops sh_rtc_ops = { |
628 | .ioctl = sh_rtc_ioctl, | 598 | .ioctl = sh_rtc_ioctl, |
629 | .read_time = sh_rtc_read_time, | 599 | .read_time = sh_rtc_read_time, |
@@ -635,7 +605,7 @@ static struct rtc_class_ops sh_rtc_ops = { | |||
635 | .proc = sh_rtc_proc, | 605 | .proc = sh_rtc_proc, |
636 | }; | 606 | }; |
637 | 607 | ||
638 | static int __devinit sh_rtc_probe(struct platform_device *pdev) | 608 | static int __init sh_rtc_probe(struct platform_device *pdev) |
639 | { | 609 | { |
640 | struct sh_rtc *rtc; | 610 | struct sh_rtc *rtc; |
641 | struct resource *res; | 611 | struct resource *res; |
@@ -702,13 +672,6 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) | |||
702 | 672 | ||
703 | clk_enable(rtc->clk); | 673 | clk_enable(rtc->clk); |
704 | 674 | ||
705 | rtc->rtc_dev = rtc_device_register("sh", &pdev->dev, | ||
706 | &sh_rtc_ops, THIS_MODULE); | ||
707 | if (IS_ERR(rtc->rtc_dev)) { | ||
708 | ret = PTR_ERR(rtc->rtc_dev); | ||
709 | goto err_unmap; | ||
710 | } | ||
711 | |||
712 | rtc->capabilities = RTC_DEF_CAPABILITIES; | 675 | rtc->capabilities = RTC_DEF_CAPABILITIES; |
713 | if (pdev->dev.platform_data) { | 676 | if (pdev->dev.platform_data) { |
714 | struct sh_rtc_platform_info *pinfo = pdev->dev.platform_data; | 677 | struct sh_rtc_platform_info *pinfo = pdev->dev.platform_data; |
@@ -720,10 +683,6 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) | |||
720 | rtc->capabilities |= pinfo->capabilities; | 683 | rtc->capabilities |= pinfo->capabilities; |
721 | } | 684 | } |
722 | 685 | ||
723 | rtc->rtc_dev->max_user_freq = 256; | ||
724 | |||
725 | platform_set_drvdata(pdev, rtc); | ||
726 | |||
727 | if (rtc->carry_irq <= 0) { | 686 | if (rtc->carry_irq <= 0) { |
728 | /* register shared periodic/carry/alarm irq */ | 687 | /* register shared periodic/carry/alarm irq */ |
729 | ret = request_irq(rtc->periodic_irq, sh_rtc_shared, | 688 | ret = request_irq(rtc->periodic_irq, sh_rtc_shared, |
@@ -767,13 +726,26 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) | |||
767 | } | 726 | } |
768 | } | 727 | } |
769 | 728 | ||
729 | platform_set_drvdata(pdev, rtc); | ||
730 | |||
770 | /* everything disabled by default */ | 731 | /* everything disabled by default */ |
771 | rtc->periodic_freq = 0; | 732 | sh_rtc_irq_set_freq(&pdev->dev, 0); |
772 | rtc->rtc_dev->irq_freq = 0; | 733 | sh_rtc_irq_set_state(&pdev->dev, 0); |
773 | sh_rtc_setpie(&pdev->dev, 0); | ||
774 | sh_rtc_setaie(&pdev->dev, 0); | 734 | sh_rtc_setaie(&pdev->dev, 0); |
775 | sh_rtc_setcie(&pdev->dev, 0); | 735 | sh_rtc_setcie(&pdev->dev, 0); |
776 | 736 | ||
737 | rtc->rtc_dev = rtc_device_register("sh", &pdev->dev, | ||
738 | &sh_rtc_ops, THIS_MODULE); | ||
739 | if (IS_ERR(rtc->rtc_dev)) { | ||
740 | ret = PTR_ERR(rtc->rtc_dev); | ||
741 | free_irq(rtc->periodic_irq, rtc); | ||
742 | free_irq(rtc->carry_irq, rtc); | ||
743 | free_irq(rtc->alarm_irq, rtc); | ||
744 | goto err_unmap; | ||
745 | } | ||
746 | |||
747 | rtc->rtc_dev->max_user_freq = 256; | ||
748 | |||
777 | /* reset rtc to epoch 0 if time is invalid */ | 749 | /* reset rtc to epoch 0 if time is invalid */ |
778 | if (rtc_read_time(rtc->rtc_dev, &r) < 0) { | 750 | if (rtc_read_time(rtc->rtc_dev, &r) < 0) { |
779 | rtc_time_to_tm(0, &r); | 751 | rtc_time_to_tm(0, &r); |
@@ -795,14 +767,13 @@ err_badres: | |||
795 | return ret; | 767 | return ret; |
796 | } | 768 | } |
797 | 769 | ||
798 | static int __devexit sh_rtc_remove(struct platform_device *pdev) | 770 | static int __exit sh_rtc_remove(struct platform_device *pdev) |
799 | { | 771 | { |
800 | struct sh_rtc *rtc = platform_get_drvdata(pdev); | 772 | struct sh_rtc *rtc = platform_get_drvdata(pdev); |
801 | 773 | ||
802 | if (likely(rtc->rtc_dev)) | 774 | rtc_device_unregister(rtc->rtc_dev); |
803 | rtc_device_unregister(rtc->rtc_dev); | 775 | sh_rtc_irq_set_state(&pdev->dev, 0); |
804 | 776 | ||
805 | sh_rtc_setpie(&pdev->dev, 0); | ||
806 | sh_rtc_setaie(&pdev->dev, 0); | 777 | sh_rtc_setaie(&pdev->dev, 0); |
807 | sh_rtc_setcie(&pdev->dev, 0); | 778 | sh_rtc_setcie(&pdev->dev, 0); |
808 | 779 | ||
@@ -813,9 +784,8 @@ static int __devexit sh_rtc_remove(struct platform_device *pdev) | |||
813 | free_irq(rtc->alarm_irq, rtc); | 784 | free_irq(rtc->alarm_irq, rtc); |
814 | } | 785 | } |
815 | 786 | ||
816 | release_resource(rtc->res); | ||
817 | |||
818 | iounmap(rtc->regbase); | 787 | iounmap(rtc->regbase); |
788 | release_resource(rtc->res); | ||
819 | 789 | ||
820 | clk_disable(rtc->clk); | 790 | clk_disable(rtc->clk); |
821 | clk_put(rtc->clk); | 791 | clk_put(rtc->clk); |
@@ -867,13 +837,12 @@ static struct platform_driver sh_rtc_platform_driver = { | |||
867 | .owner = THIS_MODULE, | 837 | .owner = THIS_MODULE, |
868 | .pm = &sh_rtc_dev_pm_ops, | 838 | .pm = &sh_rtc_dev_pm_ops, |
869 | }, | 839 | }, |
870 | .probe = sh_rtc_probe, | 840 | .remove = __exit_p(sh_rtc_remove), |
871 | .remove = __devexit_p(sh_rtc_remove), | ||
872 | }; | 841 | }; |
873 | 842 | ||
874 | static int __init sh_rtc_init(void) | 843 | static int __init sh_rtc_init(void) |
875 | { | 844 | { |
876 | return platform_driver_register(&sh_rtc_platform_driver); | 845 | return platform_driver_probe(&sh_rtc_platform_driver, sh_rtc_probe); |
877 | } | 846 | } |
878 | 847 | ||
879 | static void __exit sh_rtc_exit(void) | 848 | static void __exit sh_rtc_exit(void) |
diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c new file mode 100644 index 000000000000..d7ce1a5c857d --- /dev/null +++ b/drivers/rtc/rtc-stmp3xxx.c | |||
@@ -0,0 +1,304 @@ | |||
1 | /* | ||
2 | * Freescale STMP37XX/STMP378X Real Time Clock driver | ||
3 | * | ||
4 | * Copyright (c) 2007 Sigmatel, Inc. | ||
5 | * Peter Hartley, <peter.hartley@sigmatel.com> | ||
6 | * | ||
7 | * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. | ||
8 | * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. | ||
9 | */ | ||
10 | |||
11 | /* | ||
12 | * The code contained herein is licensed under the GNU General Public | ||
13 | * License. You may obtain a copy of the GNU General Public License | ||
14 | * Version 2 or later at the following locations: | ||
15 | * | ||
16 | * http://www.opensource.org/licenses/gpl-license.html | ||
17 | * http://www.gnu.org/copyleft/gpl.html | ||
18 | */ | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/rtc.h> | ||
25 | |||
26 | #include <mach/platform.h> | ||
27 | #include <mach/stmp3xxx.h> | ||
28 | #include <mach/regs-rtc.h> | ||
29 | |||
30 | struct stmp3xxx_rtc_data { | ||
31 | struct rtc_device *rtc; | ||
32 | unsigned irq_count; | ||
33 | void __iomem *io; | ||
34 | int irq_alarm, irq_1msec; | ||
35 | }; | ||
36 | |||
37 | static void stmp3xxx_wait_time(struct stmp3xxx_rtc_data *rtc_data) | ||
38 | { | ||
39 | /* | ||
40 | * The datasheet doesn't say which way round the | ||
41 | * NEW_REGS/STALE_REGS bitfields go. In fact it's 0x1=P0, | ||
42 | * 0x2=P1, .., 0x20=P5, 0x40=ALARM, 0x80=SECONDS | ||
43 | */ | ||
44 | while (__raw_readl(rtc_data->io + HW_RTC_STAT) & | ||
45 | BF(0x80, RTC_STAT_STALE_REGS)) | ||
46 | cpu_relax(); | ||
47 | } | ||
48 | |||
49 | /* Time read/write */ | ||
50 | static int stmp3xxx_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) | ||
51 | { | ||
52 | struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); | ||
53 | |||
54 | stmp3xxx_wait_time(rtc_data); | ||
55 | rtc_time_to_tm(__raw_readl(rtc_data->io + HW_RTC_SECONDS), rtc_tm); | ||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | static int stmp3xxx_rtc_set_mmss(struct device *dev, unsigned long t) | ||
60 | { | ||
61 | struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); | ||
62 | |||
63 | __raw_writel(t, rtc_data->io + HW_RTC_SECONDS); | ||
64 | stmp3xxx_wait_time(rtc_data); | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | /* interrupt(s) handler */ | ||
69 | static irqreturn_t stmp3xxx_rtc_interrupt(int irq, void *dev_id) | ||
70 | { | ||
71 | struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev_id); | ||
72 | u32 status; | ||
73 | u32 events = 0; | ||
74 | |||
75 | status = __raw_readl(rtc_data->io + HW_RTC_CTRL) & | ||
76 | (BM_RTC_CTRL_ALARM_IRQ | BM_RTC_CTRL_ONEMSEC_IRQ); | ||
77 | |||
78 | if (status & BM_RTC_CTRL_ALARM_IRQ) { | ||
79 | stmp3xxx_clearl(BM_RTC_CTRL_ALARM_IRQ, | ||
80 | rtc_data->io + HW_RTC_CTRL); | ||
81 | events |= RTC_AF | RTC_IRQF; | ||
82 | } | ||
83 | |||
84 | if (status & BM_RTC_CTRL_ONEMSEC_IRQ) { | ||
85 | stmp3xxx_clearl(BM_RTC_CTRL_ONEMSEC_IRQ, | ||
86 | rtc_data->io + HW_RTC_CTRL); | ||
87 | if (++rtc_data->irq_count % 1000 == 0) { | ||
88 | events |= RTC_UF | RTC_IRQF; | ||
89 | rtc_data->irq_count = 0; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | if (events) | ||
94 | rtc_update_irq(rtc_data->rtc, 1, events); | ||
95 | |||
96 | return IRQ_HANDLED; | ||
97 | } | ||
98 | |||
99 | static int stmp3xxx_alarm_irq_enable(struct device *dev, unsigned int enabled) | ||
100 | { | ||
101 | struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); | ||
102 | void __iomem *p = rtc_data->io + HW_RTC_PERSISTENT0, | ||
103 | *ctl = rtc_data->io + HW_RTC_CTRL; | ||
104 | |||
105 | if (enabled) { | ||
106 | stmp3xxx_setl(BM_RTC_PERSISTENT0_ALARM_EN | | ||
107 | BM_RTC_PERSISTENT0_ALARM_WAKE_EN, p); | ||
108 | stmp3xxx_setl(BM_RTC_CTRL_ALARM_IRQ_EN, ctl); | ||
109 | } else { | ||
110 | stmp3xxx_clearl(BM_RTC_PERSISTENT0_ALARM_EN | | ||
111 | BM_RTC_PERSISTENT0_ALARM_WAKE_EN, p); | ||
112 | stmp3xxx_clearl(BM_RTC_CTRL_ALARM_IRQ_EN, ctl); | ||
113 | } | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | static int stmp3xxx_update_irq_enable(struct device *dev, unsigned int enabled) | ||
118 | { | ||
119 | struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); | ||
120 | |||
121 | if (enabled) | ||
122 | stmp3xxx_setl(BM_RTC_CTRL_ONEMSEC_IRQ_EN, | ||
123 | rtc_data->io + HW_RTC_CTRL); | ||
124 | else | ||
125 | stmp3xxx_clearl(BM_RTC_CTRL_ONEMSEC_IRQ_EN, | ||
126 | rtc_data->io + HW_RTC_CTRL); | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | static int stmp3xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) | ||
131 | { | ||
132 | struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); | ||
133 | |||
134 | rtc_time_to_tm(__raw_readl(rtc_data->io + HW_RTC_ALARM), &alm->time); | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static int stmp3xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) | ||
139 | { | ||
140 | unsigned long t; | ||
141 | struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); | ||
142 | |||
143 | rtc_tm_to_time(&alm->time, &t); | ||
144 | __raw_writel(t, rtc_data->io + HW_RTC_ALARM); | ||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static struct rtc_class_ops stmp3xxx_rtc_ops = { | ||
149 | .alarm_irq_enable = | ||
150 | stmp3xxx_alarm_irq_enable, | ||
151 | .update_irq_enable = | ||
152 | stmp3xxx_update_irq_enable, | ||
153 | .read_time = stmp3xxx_rtc_gettime, | ||
154 | .set_mmss = stmp3xxx_rtc_set_mmss, | ||
155 | .read_alarm = stmp3xxx_rtc_read_alarm, | ||
156 | .set_alarm = stmp3xxx_rtc_set_alarm, | ||
157 | }; | ||
158 | |||
159 | static int stmp3xxx_rtc_remove(struct platform_device *pdev) | ||
160 | { | ||
161 | struct stmp3xxx_rtc_data *rtc_data = platform_get_drvdata(pdev); | ||
162 | |||
163 | if (!rtc_data) | ||
164 | return 0; | ||
165 | |||
166 | stmp3xxx_clearl(BM_RTC_CTRL_ONEMSEC_IRQ_EN | BM_RTC_CTRL_ALARM_IRQ_EN, | ||
167 | rtc_data->io + HW_RTC_CTRL); | ||
168 | free_irq(rtc_data->irq_alarm, &pdev->dev); | ||
169 | free_irq(rtc_data->irq_1msec, &pdev->dev); | ||
170 | rtc_device_unregister(rtc_data->rtc); | ||
171 | iounmap(rtc_data->io); | ||
172 | kfree(rtc_data); | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static int stmp3xxx_rtc_probe(struct platform_device *pdev) | ||
178 | { | ||
179 | struct stmp3xxx_rtc_data *rtc_data; | ||
180 | struct resource *r; | ||
181 | int err; | ||
182 | |||
183 | rtc_data = kzalloc(sizeof *rtc_data, GFP_KERNEL); | ||
184 | if (!rtc_data) | ||
185 | return -ENOMEM; | ||
186 | |||
187 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
188 | if (!r) { | ||
189 | dev_err(&pdev->dev, "failed to get resource\n"); | ||
190 | err = -ENXIO; | ||
191 | goto out_free; | ||
192 | } | ||
193 | |||
194 | rtc_data->io = ioremap(r->start, resource_size(r)); | ||
195 | if (!rtc_data->io) { | ||
196 | dev_err(&pdev->dev, "ioremap failed\n"); | ||
197 | err = -EIO; | ||
198 | goto out_free; | ||
199 | } | ||
200 | |||
201 | rtc_data->irq_alarm = platform_get_irq(pdev, 0); | ||
202 | rtc_data->irq_1msec = platform_get_irq(pdev, 1); | ||
203 | |||
204 | if (!(__raw_readl(HW_RTC_STAT + rtc_data->io) & | ||
205 | BM_RTC_STAT_RTC_PRESENT)) { | ||
206 | dev_err(&pdev->dev, "no device onboard\n"); | ||
207 | err = -ENODEV; | ||
208 | goto out_remap; | ||
209 | } | ||
210 | |||
211 | stmp3xxx_reset_block(rtc_data->io, true); | ||
212 | stmp3xxx_clearl(BM_RTC_PERSISTENT0_ALARM_EN | | ||
213 | BM_RTC_PERSISTENT0_ALARM_WAKE_EN | | ||
214 | BM_RTC_PERSISTENT0_ALARM_WAKE, | ||
215 | rtc_data->io + HW_RTC_PERSISTENT0); | ||
216 | rtc_data->rtc = rtc_device_register(pdev->name, &pdev->dev, | ||
217 | &stmp3xxx_rtc_ops, THIS_MODULE); | ||
218 | if (IS_ERR(rtc_data->rtc)) { | ||
219 | err = PTR_ERR(rtc_data->rtc); | ||
220 | goto out_remap; | ||
221 | } | ||
222 | |||
223 | rtc_data->irq_count = 0; | ||
224 | err = request_irq(rtc_data->irq_alarm, stmp3xxx_rtc_interrupt, | ||
225 | IRQF_DISABLED, "RTC alarm", &pdev->dev); | ||
226 | if (err) { | ||
227 | dev_err(&pdev->dev, "Cannot claim IRQ%d\n", | ||
228 | rtc_data->irq_alarm); | ||
229 | goto out_irq_alarm; | ||
230 | } | ||
231 | err = request_irq(rtc_data->irq_1msec, stmp3xxx_rtc_interrupt, | ||
232 | IRQF_DISABLED, "RTC tick", &pdev->dev); | ||
233 | if (err) { | ||
234 | dev_err(&pdev->dev, "Cannot claim IRQ%d\n", | ||
235 | rtc_data->irq_1msec); | ||
236 | goto out_irq1; | ||
237 | } | ||
238 | |||
239 | platform_set_drvdata(pdev, rtc_data); | ||
240 | |||
241 | return 0; | ||
242 | |||
243 | out_irq1: | ||
244 | free_irq(rtc_data->irq_alarm, &pdev->dev); | ||
245 | out_irq_alarm: | ||
246 | stmp3xxx_clearl(BM_RTC_CTRL_ONEMSEC_IRQ_EN | BM_RTC_CTRL_ALARM_IRQ_EN, | ||
247 | rtc_data->io + HW_RTC_CTRL); | ||
248 | rtc_device_unregister(rtc_data->rtc); | ||
249 | out_remap: | ||
250 | iounmap(rtc_data->io); | ||
251 | out_free: | ||
252 | kfree(rtc_data); | ||
253 | return err; | ||
254 | } | ||
255 | |||
256 | #ifdef CONFIG_PM | ||
257 | static int stmp3xxx_rtc_suspend(struct platform_device *dev, pm_message_t state) | ||
258 | { | ||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | static int stmp3xxx_rtc_resume(struct platform_device *dev) | ||
263 | { | ||
264 | struct stmp3xxx_rtc_data *rtc_data = platform_get_drvdata(dev); | ||
265 | |||
266 | stmp3xxx_reset_block(rtc_data->io, true); | ||
267 | stmp3xxx_clearl(BM_RTC_PERSISTENT0_ALARM_EN | | ||
268 | BM_RTC_PERSISTENT0_ALARM_WAKE_EN | | ||
269 | BM_RTC_PERSISTENT0_ALARM_WAKE, | ||
270 | rtc_data->io + HW_RTC_PERSISTENT0); | ||
271 | return 0; | ||
272 | } | ||
273 | #else | ||
274 | #define stmp3xxx_rtc_suspend NULL | ||
275 | #define stmp3xxx_rtc_resume NULL | ||
276 | #endif | ||
277 | |||
278 | static struct platform_driver stmp3xxx_rtcdrv = { | ||
279 | .probe = stmp3xxx_rtc_probe, | ||
280 | .remove = stmp3xxx_rtc_remove, | ||
281 | .suspend = stmp3xxx_rtc_suspend, | ||
282 | .resume = stmp3xxx_rtc_resume, | ||
283 | .driver = { | ||
284 | .name = "stmp3xxx-rtc", | ||
285 | .owner = THIS_MODULE, | ||
286 | }, | ||
287 | }; | ||
288 | |||
289 | static int __init stmp3xxx_rtc_init(void) | ||
290 | { | ||
291 | return platform_driver_register(&stmp3xxx_rtcdrv); | ||
292 | } | ||
293 | |||
294 | static void __exit stmp3xxx_rtc_exit(void) | ||
295 | { | ||
296 | platform_driver_unregister(&stmp3xxx_rtcdrv); | ||
297 | } | ||
298 | |||
299 | module_init(stmp3xxx_rtc_init); | ||
300 | module_exit(stmp3xxx_rtc_exit); | ||
301 | |||
302 | MODULE_DESCRIPTION("STMP3xxx RTC Driver"); | ||
303 | MODULE_AUTHOR("dmitry pervushin <dpervushin@embeddedalley.com>"); | ||
304 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index 2531ce4c9db0..7dd23a6fc825 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c | |||
@@ -102,6 +102,19 @@ rtc_sysfs_set_max_user_freq(struct device *dev, struct device_attribute *attr, | |||
102 | return n; | 102 | return n; |
103 | } | 103 | } |
104 | 104 | ||
105 | static ssize_t | ||
106 | rtc_sysfs_show_hctosys(struct device *dev, struct device_attribute *attr, | ||
107 | char *buf) | ||
108 | { | ||
109 | #ifdef CONFIG_RTC_HCTOSYS_DEVICE | ||
110 | if (strcmp(dev_name(&to_rtc_device(dev)->dev), | ||
111 | CONFIG_RTC_HCTOSYS_DEVICE) == 0) | ||
112 | return sprintf(buf, "1\n"); | ||
113 | else | ||
114 | #endif | ||
115 | return sprintf(buf, "0\n"); | ||
116 | } | ||
117 | |||
105 | static struct device_attribute rtc_attrs[] = { | 118 | static struct device_attribute rtc_attrs[] = { |
106 | __ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL), | 119 | __ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL), |
107 | __ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL), | 120 | __ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL), |
@@ -109,6 +122,7 @@ static struct device_attribute rtc_attrs[] = { | |||
109 | __ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL), | 122 | __ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL), |
110 | __ATTR(max_user_freq, S_IRUGO | S_IWUSR, rtc_sysfs_show_max_user_freq, | 123 | __ATTR(max_user_freq, S_IRUGO | S_IWUSR, rtc_sysfs_show_max_user_freq, |
111 | rtc_sysfs_set_max_user_freq), | 124 | rtc_sysfs_set_max_user_freq), |
125 | __ATTR(hctosys, S_IRUGO, rtc_sysfs_show_hctosys, NULL), | ||
112 | { }, | 126 | { }, |
113 | }; | 127 | }; |
114 | 128 | ||
diff --git a/drivers/rtc/rtc-wm831x.c b/drivers/rtc/rtc-wm831x.c new file mode 100644 index 000000000000..79795cdf6ed8 --- /dev/null +++ b/drivers/rtc/rtc-wm831x.c | |||
@@ -0,0 +1,523 @@ | |||
1 | /* | ||
2 | * Real Time Clock driver for Wolfson Microelectronics WM831x | ||
3 | * | ||
4 | * Copyright (C) 2009 Wolfson Microelectronics PLC. | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/time.h> | ||
18 | #include <linux/rtc.h> | ||
19 | #include <linux/bcd.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/ioctl.h> | ||
22 | #include <linux/completion.h> | ||
23 | #include <linux/mfd/wm831x/core.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | |||
27 | |||
28 | /* | ||
29 | * R16416 (0x4020) - RTC Write Counter | ||
30 | */ | ||
31 | #define WM831X_RTC_WR_CNT_MASK 0xFFFF /* RTC_WR_CNT - [15:0] */ | ||
32 | #define WM831X_RTC_WR_CNT_SHIFT 0 /* RTC_WR_CNT - [15:0] */ | ||
33 | #define WM831X_RTC_WR_CNT_WIDTH 16 /* RTC_WR_CNT - [15:0] */ | ||
34 | |||
35 | /* | ||
36 | * R16417 (0x4021) - RTC Time 1 | ||
37 | */ | ||
38 | #define WM831X_RTC_TIME_MASK 0xFFFF /* RTC_TIME - [15:0] */ | ||
39 | #define WM831X_RTC_TIME_SHIFT 0 /* RTC_TIME - [15:0] */ | ||
40 | #define WM831X_RTC_TIME_WIDTH 16 /* RTC_TIME - [15:0] */ | ||
41 | |||
42 | /* | ||
43 | * R16418 (0x4022) - RTC Time 2 | ||
44 | */ | ||
45 | #define WM831X_RTC_TIME_MASK 0xFFFF /* RTC_TIME - [15:0] */ | ||
46 | #define WM831X_RTC_TIME_SHIFT 0 /* RTC_TIME - [15:0] */ | ||
47 | #define WM831X_RTC_TIME_WIDTH 16 /* RTC_TIME - [15:0] */ | ||
48 | |||
49 | /* | ||
50 | * R16419 (0x4023) - RTC Alarm 1 | ||
51 | */ | ||
52 | #define WM831X_RTC_ALM_MASK 0xFFFF /* RTC_ALM - [15:0] */ | ||
53 | #define WM831X_RTC_ALM_SHIFT 0 /* RTC_ALM - [15:0] */ | ||
54 | #define WM831X_RTC_ALM_WIDTH 16 /* RTC_ALM - [15:0] */ | ||
55 | |||
56 | /* | ||
57 | * R16420 (0x4024) - RTC Alarm 2 | ||
58 | */ | ||
59 | #define WM831X_RTC_ALM_MASK 0xFFFF /* RTC_ALM - [15:0] */ | ||
60 | #define WM831X_RTC_ALM_SHIFT 0 /* RTC_ALM - [15:0] */ | ||
61 | #define WM831X_RTC_ALM_WIDTH 16 /* RTC_ALM - [15:0] */ | ||
62 | |||
63 | /* | ||
64 | * R16421 (0x4025) - RTC Control | ||
65 | */ | ||
66 | #define WM831X_RTC_VALID 0x8000 /* RTC_VALID */ | ||
67 | #define WM831X_RTC_VALID_MASK 0x8000 /* RTC_VALID */ | ||
68 | #define WM831X_RTC_VALID_SHIFT 15 /* RTC_VALID */ | ||
69 | #define WM831X_RTC_VALID_WIDTH 1 /* RTC_VALID */ | ||
70 | #define WM831X_RTC_SYNC_BUSY 0x4000 /* RTC_SYNC_BUSY */ | ||
71 | #define WM831X_RTC_SYNC_BUSY_MASK 0x4000 /* RTC_SYNC_BUSY */ | ||
72 | #define WM831X_RTC_SYNC_BUSY_SHIFT 14 /* RTC_SYNC_BUSY */ | ||
73 | #define WM831X_RTC_SYNC_BUSY_WIDTH 1 /* RTC_SYNC_BUSY */ | ||
74 | #define WM831X_RTC_ALM_ENA 0x0400 /* RTC_ALM_ENA */ | ||
75 | #define WM831X_RTC_ALM_ENA_MASK 0x0400 /* RTC_ALM_ENA */ | ||
76 | #define WM831X_RTC_ALM_ENA_SHIFT 10 /* RTC_ALM_ENA */ | ||
77 | #define WM831X_RTC_ALM_ENA_WIDTH 1 /* RTC_ALM_ENA */ | ||
78 | #define WM831X_RTC_PINT_FREQ_MASK 0x0070 /* RTC_PINT_FREQ - [6:4] */ | ||
79 | #define WM831X_RTC_PINT_FREQ_SHIFT 4 /* RTC_PINT_FREQ - [6:4] */ | ||
80 | #define WM831X_RTC_PINT_FREQ_WIDTH 3 /* RTC_PINT_FREQ - [6:4] */ | ||
81 | |||
82 | /* | ||
83 | * R16422 (0x4026) - RTC Trim | ||
84 | */ | ||
85 | #define WM831X_RTC_TRIM_MASK 0x03FF /* RTC_TRIM - [9:0] */ | ||
86 | #define WM831X_RTC_TRIM_SHIFT 0 /* RTC_TRIM - [9:0] */ | ||
87 | #define WM831X_RTC_TRIM_WIDTH 10 /* RTC_TRIM - [9:0] */ | ||
88 | |||
89 | #define WM831X_SET_TIME_RETRIES 5 | ||
90 | #define WM831X_GET_TIME_RETRIES 5 | ||
91 | |||
92 | struct wm831x_rtc { | ||
93 | struct wm831x *wm831x; | ||
94 | struct rtc_device *rtc; | ||
95 | unsigned int alarm_enabled:1; | ||
96 | }; | ||
97 | |||
98 | /* | ||
99 | * Read current time and date in RTC | ||
100 | */ | ||
101 | static int wm831x_rtc_readtime(struct device *dev, struct rtc_time *tm) | ||
102 | { | ||
103 | struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(dev); | ||
104 | struct wm831x *wm831x = wm831x_rtc->wm831x; | ||
105 | u16 time1[2], time2[2]; | ||
106 | int ret; | ||
107 | int count = 0; | ||
108 | |||
109 | /* Has the RTC been programmed? */ | ||
110 | ret = wm831x_reg_read(wm831x, WM831X_RTC_CONTROL); | ||
111 | if (ret < 0) { | ||
112 | dev_err(dev, "Failed to read RTC control: %d\n", ret); | ||
113 | return ret; | ||
114 | } | ||
115 | if (!(ret & WM831X_RTC_VALID)) { | ||
116 | dev_dbg(dev, "RTC not yet configured\n"); | ||
117 | return -EINVAL; | ||
118 | } | ||
119 | |||
120 | /* Read twice to make sure we don't read a corrupt, partially | ||
121 | * incremented, value. | ||
122 | */ | ||
123 | do { | ||
124 | ret = wm831x_bulk_read(wm831x, WM831X_RTC_TIME_1, | ||
125 | 2, time1); | ||
126 | if (ret != 0) | ||
127 | continue; | ||
128 | |||
129 | ret = wm831x_bulk_read(wm831x, WM831X_RTC_TIME_1, | ||
130 | 2, time2); | ||
131 | if (ret != 0) | ||
132 | continue; | ||
133 | |||
134 | if (memcmp(time1, time2, sizeof(time1)) == 0) { | ||
135 | u32 time = (time1[0] << 16) | time1[1]; | ||
136 | |||
137 | rtc_time_to_tm(time, tm); | ||
138 | return rtc_valid_tm(tm); | ||
139 | } | ||
140 | |||
141 | } while (++count < WM831X_GET_TIME_RETRIES); | ||
142 | |||
143 | dev_err(dev, "Timed out reading current time\n"); | ||
144 | |||
145 | return -EIO; | ||
146 | } | ||
147 | |||
148 | /* | ||
149 | * Set current time and date in RTC | ||
150 | */ | ||
151 | static int wm831x_rtc_set_mmss(struct device *dev, unsigned long time) | ||
152 | { | ||
153 | struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(dev); | ||
154 | struct wm831x *wm831x = wm831x_rtc->wm831x; | ||
155 | struct rtc_time new_tm; | ||
156 | unsigned long new_time; | ||
157 | int ret; | ||
158 | int count = 0; | ||
159 | |||
160 | ret = wm831x_reg_write(wm831x, WM831X_RTC_TIME_1, | ||
161 | (time >> 16) & 0xffff); | ||
162 | if (ret < 0) { | ||
163 | dev_err(dev, "Failed to write TIME_1: %d\n", ret); | ||
164 | return ret; | ||
165 | } | ||
166 | |||
167 | ret = wm831x_reg_write(wm831x, WM831X_RTC_TIME_2, time & 0xffff); | ||
168 | if (ret < 0) { | ||
169 | dev_err(dev, "Failed to write TIME_2: %d\n", ret); | ||
170 | return ret; | ||
171 | } | ||
172 | |||
173 | /* Wait for the update to complete - should happen first time | ||
174 | * round but be conservative. | ||
175 | */ | ||
176 | do { | ||
177 | msleep(1); | ||
178 | |||
179 | ret = wm831x_reg_read(wm831x, WM831X_RTC_CONTROL); | ||
180 | if (ret < 0) | ||
181 | ret = WM831X_RTC_SYNC_BUSY; | ||
182 | } while (!(ret & WM831X_RTC_SYNC_BUSY) && | ||
183 | ++count < WM831X_SET_TIME_RETRIES); | ||
184 | |||
185 | if (ret & WM831X_RTC_SYNC_BUSY) { | ||
186 | dev_err(dev, "Timed out writing RTC update\n"); | ||
187 | return -EIO; | ||
188 | } | ||
189 | |||
190 | /* Check that the update was accepted; security features may | ||
191 | * have caused the update to be ignored. | ||
192 | */ | ||
193 | ret = wm831x_rtc_readtime(dev, &new_tm); | ||
194 | if (ret < 0) | ||
195 | return ret; | ||
196 | |||
197 | ret = rtc_tm_to_time(&new_tm, &new_time); | ||
198 | if (ret < 0) { | ||
199 | dev_err(dev, "Failed to convert time: %d\n", ret); | ||
200 | return ret; | ||
201 | } | ||
202 | |||
203 | /* Allow a second of change in case of tick */ | ||
204 | if (new_time - time > 1) { | ||
205 | dev_err(dev, "RTC update not permitted by hardware\n"); | ||
206 | return -EPERM; | ||
207 | } | ||
208 | |||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | /* | ||
213 | * Read alarm time and date in RTC | ||
214 | */ | ||
215 | static int wm831x_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
216 | { | ||
217 | struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(dev); | ||
218 | int ret; | ||
219 | u16 data[2]; | ||
220 | u32 time; | ||
221 | |||
222 | ret = wm831x_bulk_read(wm831x_rtc->wm831x, WM831X_RTC_ALARM_1, | ||
223 | 2, data); | ||
224 | if (ret != 0) { | ||
225 | dev_err(dev, "Failed to read alarm time: %d\n", ret); | ||
226 | return ret; | ||
227 | } | ||
228 | |||
229 | time = (data[0] << 16) | data[1]; | ||
230 | |||
231 | rtc_time_to_tm(time, &alrm->time); | ||
232 | |||
233 | ret = wm831x_reg_read(wm831x_rtc->wm831x, WM831X_RTC_CONTROL); | ||
234 | if (ret < 0) { | ||
235 | dev_err(dev, "Failed to read RTC control: %d\n", ret); | ||
236 | return ret; | ||
237 | } | ||
238 | |||
239 | if (ret & WM831X_RTC_ALM_ENA) | ||
240 | alrm->enabled = 1; | ||
241 | else | ||
242 | alrm->enabled = 0; | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | static int wm831x_rtc_stop_alarm(struct wm831x_rtc *wm831x_rtc) | ||
248 | { | ||
249 | wm831x_rtc->alarm_enabled = 0; | ||
250 | |||
251 | return wm831x_set_bits(wm831x_rtc->wm831x, WM831X_RTC_CONTROL, | ||
252 | WM831X_RTC_ALM_ENA, 0); | ||
253 | } | ||
254 | |||
255 | static int wm831x_rtc_start_alarm(struct wm831x_rtc *wm831x_rtc) | ||
256 | { | ||
257 | wm831x_rtc->alarm_enabled = 1; | ||
258 | |||
259 | return wm831x_set_bits(wm831x_rtc->wm831x, WM831X_RTC_CONTROL, | ||
260 | WM831X_RTC_ALM_ENA, WM831X_RTC_ALM_ENA); | ||
261 | } | ||
262 | |||
263 | static int wm831x_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
264 | { | ||
265 | struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(dev); | ||
266 | struct wm831x *wm831x = wm831x_rtc->wm831x; | ||
267 | int ret; | ||
268 | unsigned long time; | ||
269 | |||
270 | ret = rtc_tm_to_time(&alrm->time, &time); | ||
271 | if (ret < 0) { | ||
272 | dev_err(dev, "Failed to convert time: %d\n", ret); | ||
273 | return ret; | ||
274 | } | ||
275 | |||
276 | ret = wm831x_rtc_stop_alarm(wm831x_rtc); | ||
277 | if (ret < 0) { | ||
278 | dev_err(dev, "Failed to stop alarm: %d\n", ret); | ||
279 | return ret; | ||
280 | } | ||
281 | |||
282 | ret = wm831x_reg_write(wm831x, WM831X_RTC_ALARM_1, | ||
283 | (time >> 16) & 0xffff); | ||
284 | if (ret < 0) { | ||
285 | dev_err(dev, "Failed to write ALARM_1: %d\n", ret); | ||
286 | return ret; | ||
287 | } | ||
288 | |||
289 | ret = wm831x_reg_write(wm831x, WM831X_RTC_ALARM_2, time & 0xffff); | ||
290 | if (ret < 0) { | ||
291 | dev_err(dev, "Failed to write ALARM_2: %d\n", ret); | ||
292 | return ret; | ||
293 | } | ||
294 | |||
295 | if (alrm->enabled) { | ||
296 | ret = wm831x_rtc_start_alarm(wm831x_rtc); | ||
297 | if (ret < 0) { | ||
298 | dev_err(dev, "Failed to start alarm: %d\n", ret); | ||
299 | return ret; | ||
300 | } | ||
301 | } | ||
302 | |||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static int wm831x_rtc_alarm_irq_enable(struct device *dev, | ||
307 | unsigned int enabled) | ||
308 | { | ||
309 | struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(dev); | ||
310 | |||
311 | if (enabled) | ||
312 | return wm831x_rtc_start_alarm(wm831x_rtc); | ||
313 | else | ||
314 | return wm831x_rtc_stop_alarm(wm831x_rtc); | ||
315 | } | ||
316 | |||
317 | static int wm831x_rtc_update_irq_enable(struct device *dev, | ||
318 | unsigned int enabled) | ||
319 | { | ||
320 | struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(dev); | ||
321 | int val; | ||
322 | |||
323 | if (enabled) | ||
324 | val = 1 << WM831X_RTC_PINT_FREQ_SHIFT; | ||
325 | else | ||
326 | val = 0; | ||
327 | |||
328 | return wm831x_set_bits(wm831x_rtc->wm831x, WM831X_RTC_CONTROL, | ||
329 | WM831X_RTC_PINT_FREQ_MASK, val); | ||
330 | } | ||
331 | |||
332 | static irqreturn_t wm831x_alm_irq(int irq, void *data) | ||
333 | { | ||
334 | struct wm831x_rtc *wm831x_rtc = data; | ||
335 | |||
336 | rtc_update_irq(wm831x_rtc->rtc, 1, RTC_IRQF | RTC_AF); | ||
337 | |||
338 | return IRQ_HANDLED; | ||
339 | } | ||
340 | |||
341 | static irqreturn_t wm831x_per_irq(int irq, void *data) | ||
342 | { | ||
343 | struct wm831x_rtc *wm831x_rtc = data; | ||
344 | |||
345 | rtc_update_irq(wm831x_rtc->rtc, 1, RTC_IRQF | RTC_UF); | ||
346 | |||
347 | return IRQ_HANDLED; | ||
348 | } | ||
349 | |||
350 | static const struct rtc_class_ops wm831x_rtc_ops = { | ||
351 | .read_time = wm831x_rtc_readtime, | ||
352 | .set_mmss = wm831x_rtc_set_mmss, | ||
353 | .read_alarm = wm831x_rtc_readalarm, | ||
354 | .set_alarm = wm831x_rtc_setalarm, | ||
355 | .alarm_irq_enable = wm831x_rtc_alarm_irq_enable, | ||
356 | .update_irq_enable = wm831x_rtc_update_irq_enable, | ||
357 | }; | ||
358 | |||
359 | #ifdef CONFIG_PM | ||
360 | /* Turn off the alarm if it should not be a wake source. */ | ||
361 | static int wm831x_rtc_suspend(struct device *dev) | ||
362 | { | ||
363 | struct platform_device *pdev = to_platform_device(dev); | ||
364 | struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(&pdev->dev); | ||
365 | int ret, enable; | ||
366 | |||
367 | if (wm831x_rtc->alarm_enabled && device_may_wakeup(&pdev->dev)) | ||
368 | enable = WM831X_RTC_ALM_ENA; | ||
369 | else | ||
370 | enable = 0; | ||
371 | |||
372 | ret = wm831x_set_bits(wm831x_rtc->wm831x, WM831X_RTC_CONTROL, | ||
373 | WM831X_RTC_ALM_ENA, enable); | ||
374 | if (ret != 0) | ||
375 | dev_err(&pdev->dev, "Failed to update RTC alarm: %d\n", ret); | ||
376 | |||
377 | return 0; | ||
378 | } | ||
379 | |||
380 | /* Enable the alarm if it should be enabled (in case it was disabled to | ||
381 | * prevent use as a wake source). | ||
382 | */ | ||
383 | static int wm831x_rtc_resume(struct device *dev) | ||
384 | { | ||
385 | struct platform_device *pdev = to_platform_device(dev); | ||
386 | struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(&pdev->dev); | ||
387 | int ret; | ||
388 | |||
389 | if (wm831x_rtc->alarm_enabled) { | ||
390 | ret = wm831x_rtc_start_alarm(wm831x_rtc); | ||
391 | if (ret != 0) | ||
392 | dev_err(&pdev->dev, | ||
393 | "Failed to restart RTC alarm: %d\n", ret); | ||
394 | } | ||
395 | |||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | /* Unconditionally disable the alarm */ | ||
400 | static int wm831x_rtc_freeze(struct device *dev) | ||
401 | { | ||
402 | struct platform_device *pdev = to_platform_device(dev); | ||
403 | struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(&pdev->dev); | ||
404 | int ret; | ||
405 | |||
406 | ret = wm831x_set_bits(wm831x_rtc->wm831x, WM831X_RTC_CONTROL, | ||
407 | WM831X_RTC_ALM_ENA, 0); | ||
408 | if (ret != 0) | ||
409 | dev_err(&pdev->dev, "Failed to stop RTC alarm: %d\n", ret); | ||
410 | |||
411 | return 0; | ||
412 | } | ||
413 | #else | ||
414 | #define wm831x_rtc_suspend NULL | ||
415 | #define wm831x_rtc_resume NULL | ||
416 | #define wm831x_rtc_freeze NULL | ||
417 | #endif | ||
418 | |||
419 | static int wm831x_rtc_probe(struct platform_device *pdev) | ||
420 | { | ||
421 | struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); | ||
422 | struct wm831x_rtc *wm831x_rtc; | ||
423 | int per_irq = platform_get_irq_byname(pdev, "PER"); | ||
424 | int alm_irq = platform_get_irq_byname(pdev, "ALM"); | ||
425 | int ret = 0; | ||
426 | |||
427 | wm831x_rtc = kzalloc(sizeof(*wm831x_rtc), GFP_KERNEL); | ||
428 | if (wm831x_rtc == NULL) | ||
429 | return -ENOMEM; | ||
430 | |||
431 | platform_set_drvdata(pdev, wm831x_rtc); | ||
432 | wm831x_rtc->wm831x = wm831x; | ||
433 | |||
434 | ret = wm831x_reg_read(wm831x, WM831X_RTC_CONTROL); | ||
435 | if (ret < 0) { | ||
436 | dev_err(&pdev->dev, "Failed to read RTC control: %d\n", ret); | ||
437 | goto err; | ||
438 | } | ||
439 | if (ret & WM831X_RTC_ALM_ENA) | ||
440 | wm831x_rtc->alarm_enabled = 1; | ||
441 | |||
442 | device_init_wakeup(&pdev->dev, 1); | ||
443 | |||
444 | wm831x_rtc->rtc = rtc_device_register("wm831x", &pdev->dev, | ||
445 | &wm831x_rtc_ops, THIS_MODULE); | ||
446 | if (IS_ERR(wm831x_rtc->rtc)) { | ||
447 | ret = PTR_ERR(wm831x_rtc->rtc); | ||
448 | goto err; | ||
449 | } | ||
450 | |||
451 | ret = wm831x_request_irq(wm831x, per_irq, wm831x_per_irq, | ||
452 | IRQF_TRIGGER_RISING, "wm831x_rtc_per", | ||
453 | wm831x_rtc); | ||
454 | if (ret != 0) { | ||
455 | dev_err(&pdev->dev, "Failed to request periodic IRQ %d: %d\n", | ||
456 | per_irq, ret); | ||
457 | } | ||
458 | |||
459 | ret = wm831x_request_irq(wm831x, alm_irq, wm831x_alm_irq, | ||
460 | IRQF_TRIGGER_RISING, "wm831x_rtc_alm", | ||
461 | wm831x_rtc); | ||
462 | if (ret != 0) { | ||
463 | dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n", | ||
464 | alm_irq, ret); | ||
465 | } | ||
466 | |||
467 | return 0; | ||
468 | |||
469 | err: | ||
470 | kfree(wm831x_rtc); | ||
471 | return ret; | ||
472 | } | ||
473 | |||
474 | static int __devexit wm831x_rtc_remove(struct platform_device *pdev) | ||
475 | { | ||
476 | struct wm831x_rtc *wm831x_rtc = platform_get_drvdata(pdev); | ||
477 | int per_irq = platform_get_irq_byname(pdev, "PER"); | ||
478 | int alm_irq = platform_get_irq_byname(pdev, "ALM"); | ||
479 | |||
480 | wm831x_free_irq(wm831x_rtc->wm831x, alm_irq, wm831x_rtc); | ||
481 | wm831x_free_irq(wm831x_rtc->wm831x, per_irq, wm831x_rtc); | ||
482 | rtc_device_unregister(wm831x_rtc->rtc); | ||
483 | kfree(wm831x_rtc); | ||
484 | |||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | static struct dev_pm_ops wm831x_rtc_pm_ops = { | ||
489 | .suspend = wm831x_rtc_suspend, | ||
490 | .resume = wm831x_rtc_resume, | ||
491 | |||
492 | .freeze = wm831x_rtc_freeze, | ||
493 | .thaw = wm831x_rtc_resume, | ||
494 | .restore = wm831x_rtc_resume, | ||
495 | |||
496 | .poweroff = wm831x_rtc_suspend, | ||
497 | }; | ||
498 | |||
499 | static struct platform_driver wm831x_rtc_driver = { | ||
500 | .probe = wm831x_rtc_probe, | ||
501 | .remove = __devexit_p(wm831x_rtc_remove), | ||
502 | .driver = { | ||
503 | .name = "wm831x-rtc", | ||
504 | .pm = &wm831x_rtc_pm_ops, | ||
505 | }, | ||
506 | }; | ||
507 | |||
508 | static int __init wm831x_rtc_init(void) | ||
509 | { | ||
510 | return platform_driver_register(&wm831x_rtc_driver); | ||
511 | } | ||
512 | module_init(wm831x_rtc_init); | ||
513 | |||
514 | static void __exit wm831x_rtc_exit(void) | ||
515 | { | ||
516 | platform_driver_unregister(&wm831x_rtc_driver); | ||
517 | } | ||
518 | module_exit(wm831x_rtc_exit); | ||
519 | |||
520 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | ||
521 | MODULE_DESCRIPTION("RTC driver for the WM831x series PMICs"); | ||
522 | MODULE_LICENSE("GPL"); | ||
523 | MODULE_ALIAS("platform:wm831x-rtc"); | ||