diff options
Diffstat (limited to 'drivers/rtc')
28 files changed, 2723 insertions, 164 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/interface.c b/drivers/rtc/interface.c index 4cdb31a362ca..a0c816238aa9 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | */ | 12 | */ |
| 13 | 13 | ||
| 14 | #include <linux/rtc.h> | 14 | #include <linux/rtc.h> |
| 15 | #include <linux/sched.h> | ||
| 15 | #include <linux/log2.h> | 16 | #include <linux/log2.h> |
| 16 | 17 | ||
| 17 | int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) | 18 | int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) |
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-dev.c b/drivers/rtc/rtc-dev.c index 8a11de9552cd..62227cd52410 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | 13 | ||
| 14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
| 15 | #include <linux/rtc.h> | 15 | #include <linux/rtc.h> |
| 16 | #include <linux/sched.h> | ||
| 16 | #include "rtc-core.h" | 17 | #include "rtc-core.h" |
| 17 | 18 | ||
| 18 | static dev_t rtc_devt; | 19 | static dev_t rtc_devt; |
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-pxa.c b/drivers/rtc/rtc-pxa.c index bb8cc05605ac..747ca194fad4 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c | |||
| @@ -438,34 +438,37 @@ static int __exit pxa_rtc_remove(struct platform_device *pdev) | |||
| 438 | } | 438 | } |
| 439 | 439 | ||
| 440 | #ifdef CONFIG_PM | 440 | #ifdef CONFIG_PM |
| 441 | static int pxa_rtc_suspend(struct platform_device *pdev, pm_message_t state) | 441 | static int pxa_rtc_suspend(struct device *dev) |
| 442 | { | 442 | { |
| 443 | struct pxa_rtc *pxa_rtc = platform_get_drvdata(pdev); | 443 | struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); |
| 444 | 444 | ||
| 445 | if (device_may_wakeup(&pdev->dev)) | 445 | if (device_may_wakeup(dev)) |
| 446 | enable_irq_wake(pxa_rtc->irq_Alrm); | 446 | enable_irq_wake(pxa_rtc->irq_Alrm); |
| 447 | return 0; | 447 | return 0; |
| 448 | } | 448 | } |
| 449 | 449 | ||
| 450 | static int pxa_rtc_resume(struct platform_device *pdev) | 450 | static int pxa_rtc_resume(struct device *dev) |
| 451 | { | 451 | { |
| 452 | struct pxa_rtc *pxa_rtc = platform_get_drvdata(pdev); | 452 | struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); |
| 453 | 453 | ||
| 454 | if (device_may_wakeup(&pdev->dev)) | 454 | if (device_may_wakeup(dev)) |
| 455 | disable_irq_wake(pxa_rtc->irq_Alrm); | 455 | disable_irq_wake(pxa_rtc->irq_Alrm); |
| 456 | return 0; | 456 | return 0; |
| 457 | } | 457 | } |
| 458 | #else | 458 | |
| 459 | #define pxa_rtc_suspend NULL | 459 | static struct dev_pm_ops pxa_rtc_pm_ops = { |
| 460 | #define pxa_rtc_resume NULL | 460 | .suspend = pxa_rtc_suspend, |
| 461 | .resume = pxa_rtc_resume, | ||
| 462 | }; | ||
| 461 | #endif | 463 | #endif |
| 462 | 464 | ||
| 463 | static struct platform_driver pxa_rtc_driver = { | 465 | static struct platform_driver pxa_rtc_driver = { |
| 464 | .remove = __exit_p(pxa_rtc_remove), | 466 | .remove = __exit_p(pxa_rtc_remove), |
| 465 | .suspend = pxa_rtc_suspend, | ||
| 466 | .resume = pxa_rtc_resume, | ||
| 467 | .driver = { | 467 | .driver = { |
| 468 | .name = "pxa-rtc", | 468 | .name = "pxa-rtc", |
| 469 | #ifdef CONFIG_PM | ||
| 470 | .pm = &pxa_rtc_pm_ops, | ||
| 471 | #endif | ||
| 469 | }, | 472 | }, |
| 470 | }; | 473 | }; |
| 471 | 474 | ||
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-sa1100.c b/drivers/rtc/rtc-sa1100.c index 4f247e4dd3f9..29f98a70586e 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c | |||
| @@ -9,7 +9,7 @@ | |||
| 9 | * | 9 | * |
| 10 | * Modifications from: | 10 | * Modifications from: |
| 11 | * CIH <cih@coventive.com> | 11 | * CIH <cih@coventive.com> |
| 12 | * Nicolas Pitre <nico@cam.org> | 12 | * Nicolas Pitre <nico@fluxnic.net> |
| 13 | * Andrew Christian <andrew.christian@hp.com> | 13 | * Andrew Christian <andrew.christian@hp.com> |
| 14 | * | 14 | * |
| 15 | * Converted to the RTC subsystem and Driver Model | 15 | * Converted to the RTC subsystem and Driver Model |
| @@ -393,31 +393,34 @@ static int sa1100_rtc_remove(struct platform_device *pdev) | |||
| 393 | } | 393 | } |
| 394 | 394 | ||
| 395 | #ifdef CONFIG_PM | 395 | #ifdef CONFIG_PM |
| 396 | static int sa1100_rtc_suspend(struct platform_device *pdev, pm_message_t state) | 396 | static int sa1100_rtc_suspend(struct device *dev) |
| 397 | { | 397 | { |
| 398 | if (device_may_wakeup(&pdev->dev)) | 398 | if (device_may_wakeup(dev)) |
| 399 | enable_irq_wake(IRQ_RTCAlrm); | 399 | enable_irq_wake(IRQ_RTCAlrm); |
| 400 | return 0; | 400 | return 0; |
| 401 | } | 401 | } |
| 402 | 402 | ||
| 403 | static int sa1100_rtc_resume(struct platform_device *pdev) | 403 | static int sa1100_rtc_resume(struct device *dev) |
| 404 | { | 404 | { |
| 405 | if (device_may_wakeup(&pdev->dev)) | 405 | if (device_may_wakeup(dev)) |
| 406 | disable_irq_wake(IRQ_RTCAlrm); | 406 | disable_irq_wake(IRQ_RTCAlrm); |
| 407 | return 0; | 407 | return 0; |
| 408 | } | 408 | } |
| 409 | #else | 409 | |
| 410 | #define sa1100_rtc_suspend NULL | 410 | static struct dev_pm_ops sa1100_rtc_pm_ops = { |
| 411 | #define sa1100_rtc_resume NULL | 411 | .suspend = sa1100_rtc_suspend, |
| 412 | .resume = sa1100_rtc_resume, | ||
| 413 | }; | ||
| 412 | #endif | 414 | #endif |
| 413 | 415 | ||
| 414 | static struct platform_driver sa1100_rtc_driver = { | 416 | static struct platform_driver sa1100_rtc_driver = { |
| 415 | .probe = sa1100_rtc_probe, | 417 | .probe = sa1100_rtc_probe, |
| 416 | .remove = sa1100_rtc_remove, | 418 | .remove = sa1100_rtc_remove, |
| 417 | .suspend = sa1100_rtc_suspend, | ||
| 418 | .resume = sa1100_rtc_resume, | ||
| 419 | .driver = { | 419 | .driver = { |
| 420 | .name = "sa1100-rtc", | 420 | .name = "sa1100-rtc", |
| 421 | #ifdef CONFIG_PM | ||
| 422 | .pm = &sa1100_rtc_pm_ops, | ||
| 423 | #endif | ||
| 421 | }, | 424 | }, |
| 422 | }; | 425 | }; |
| 423 | 426 | ||
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"); | ||
