diff options
| author | Dave Jones <davej@redhat.com> | 2006-06-29 16:01:54 -0400 |
|---|---|---|
| committer | Dave Jones <davej@redhat.com> | 2006-06-29 16:01:54 -0400 |
| commit | 55b4d6a52195a8f277ffddf755ddaff359878f41 (patch) | |
| tree | 06a3183a562f8da4688f65023f7a18dcad702956 /drivers/rtc | |
| parent | adf8a287150667feb5747f8beade62acacc17d4e (diff) | |
| parent | 1f1332f727c3229eb2166a83fec5d3de6a73dce2 (diff) | |
Merge ../linus
Conflicts:
drivers/char/agp/Kconfig
Diffstat (limited to 'drivers/rtc')
| -rw-r--r-- | drivers/rtc/Kconfig | 101 | ||||
| -rw-r--r-- | drivers/rtc/Makefile | 9 | ||||
| -rw-r--r-- | drivers/rtc/class.c | 3 | ||||
| -rw-r--r-- | drivers/rtc/interface.c | 22 | ||||
| -rw-r--r-- | drivers/rtc/rtc-at91.c | 407 | ||||
| -rw-r--r-- | drivers/rtc/rtc-dev.c | 131 | ||||
| -rw-r--r-- | drivers/rtc/rtc-ds1307.c | 388 | ||||
| -rw-r--r-- | drivers/rtc/rtc-ds1553.c | 414 | ||||
| -rw-r--r-- | drivers/rtc/rtc-ds1742.c | 259 | ||||
| -rw-r--r-- | drivers/rtc/rtc-lib.c | 19 | ||||
| -rw-r--r-- | drivers/rtc/rtc-max6902.c | 286 | ||||
| -rw-r--r-- | drivers/rtc/rtc-pcf8583.c | 394 | ||||
| -rw-r--r-- | drivers/rtc/rtc-pl031.c | 233 | ||||
| -rw-r--r-- | drivers/rtc/rtc-rs5c348.c | 246 | ||||
| -rw-r--r-- | drivers/rtc/rtc-sa1100.c | 6 | ||||
| -rw-r--r-- | drivers/rtc/rtc-v3020.c | 264 | ||||
| -rw-r--r-- | drivers/rtc/rtc-vr41xx.c | 10 |
17 files changed, 3155 insertions, 37 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 65d090dbef46..f2fc81a9074d 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
| @@ -73,6 +73,13 @@ config RTC_INTF_DEV | |||
| 73 | This driver can also be built as a module. If so, the module | 73 | This driver can also be built as a module. If so, the module |
| 74 | will be called rtc-dev. | 74 | will be called rtc-dev. |
| 75 | 75 | ||
| 76 | config RTC_INTF_DEV_UIE_EMUL | ||
| 77 | bool "RTC UIE emulation on dev interface" | ||
| 78 | depends on RTC_INTF_DEV | ||
| 79 | help | ||
| 80 | Provides an emulation for RTC_UIE if the underlaying rtc chip | ||
| 81 | driver did not provide RTC_UIE ioctls. | ||
| 82 | |||
| 76 | comment "RTC drivers" | 83 | comment "RTC drivers" |
| 77 | depends on RTC_CLASS | 84 | depends on RTC_CLASS |
| 78 | 85 | ||
| @@ -86,6 +93,34 @@ config RTC_DRV_X1205 | |||
| 86 | This driver can also be built as a module. If so, the module | 93 | This driver can also be built as a module. If so, the module |
| 87 | will be called rtc-x1205. | 94 | will be called rtc-x1205. |
| 88 | 95 | ||
| 96 | config RTC_DRV_DS1307 | ||
| 97 | tristate "Dallas/Maxim DS1307 and similar I2C RTC chips" | ||
| 98 | depends on RTC_CLASS && I2C | ||
| 99 | help | ||
| 100 | If you say yes here you get support for various compatible RTC | ||
| 101 | chips (often with battery backup) connected with I2C. This driver | ||
| 102 | should handle DS1307, DS1337, DS1338, DS1339, DS1340, ST M41T00, | ||
| 103 | and probably other chips. In some cases the RTC must already | ||
| 104 | have been initialized (by manufacturing or a bootloader). | ||
| 105 | |||
| 106 | The first seven registers on these chips hold an RTC, and other | ||
| 107 | registers may add features such as NVRAM, a trickle charger for | ||
| 108 | the RTC/NVRAM backup power, and alarms. This driver may not | ||
| 109 | expose all those available chip features. | ||
| 110 | |||
| 111 | This driver can also be built as a module. If so, the module | ||
| 112 | will be called rtc-ds1307. | ||
| 113 | |||
| 114 | config RTC_DRV_DS1553 | ||
| 115 | tristate "Dallas DS1553" | ||
| 116 | depends on RTC_CLASS | ||
| 117 | help | ||
| 118 | If you say yes here you get support for the | ||
| 119 | Dallas DS1553 timekeeping chip. | ||
| 120 | |||
| 121 | This driver can also be built as a module. If so, the module | ||
| 122 | will be called rtc-ds1553. | ||
| 123 | |||
| 89 | config RTC_DRV_DS1672 | 124 | config RTC_DRV_DS1672 |
| 90 | tristate "Dallas/Maxim DS1672" | 125 | tristate "Dallas/Maxim DS1672" |
| 91 | depends on RTC_CLASS && I2C | 126 | depends on RTC_CLASS && I2C |
| @@ -96,6 +131,16 @@ config RTC_DRV_DS1672 | |||
| 96 | This driver can also be built as a module. If so, the module | 131 | This driver can also be built as a module. If so, the module |
| 97 | will be called rtc-ds1672. | 132 | will be called rtc-ds1672. |
| 98 | 133 | ||
| 134 | config RTC_DRV_DS1742 | ||
| 135 | tristate "Dallas DS1742" | ||
| 136 | depends on RTC_CLASS | ||
| 137 | help | ||
| 138 | If you say yes here you get support for the | ||
| 139 | Dallas DS1742 timekeeping chip. | ||
| 140 | |||
| 141 | This driver can also be built as a module. If so, the module | ||
| 142 | will be called rtc-ds1742. | ||
| 143 | |||
| 99 | config RTC_DRV_PCF8563 | 144 | config RTC_DRV_PCF8563 |
| 100 | tristate "Philips PCF8563/Epson RTC8564" | 145 | tristate "Philips PCF8563/Epson RTC8564" |
| 101 | depends on RTC_CLASS && I2C | 146 | depends on RTC_CLASS && I2C |
| @@ -107,6 +152,26 @@ config RTC_DRV_PCF8563 | |||
| 107 | This driver can also be built as a module. If so, the module | 152 | This driver can also be built as a module. If so, the module |
| 108 | will be called rtc-pcf8563. | 153 | will be called rtc-pcf8563. |
| 109 | 154 | ||
| 155 | config RTC_DRV_PCF8583 | ||
| 156 | tristate "Philips PCF8583" | ||
| 157 | depends on RTC_CLASS && I2C | ||
| 158 | help | ||
| 159 | If you say yes here you get support for the | ||
| 160 | Philips PCF8583 RTC chip. | ||
| 161 | |||
| 162 | This driver can also be built as a module. If so, the module | ||
| 163 | will be called rtc-pcf8583. | ||
| 164 | |||
| 165 | config RTC_DRV_RS5C348 | ||
| 166 | tristate "Ricoh RS5C348A/B" | ||
| 167 | depends on RTC_CLASS && SPI | ||
| 168 | help | ||
| 169 | If you say yes here you get support for the | ||
| 170 | Ricoh RS5C348A and RS5C348B RTC chips. | ||
| 171 | |||
| 172 | This driver can also be built as a module. If so, the module | ||
| 173 | will be called rtc-rs5c348. | ||
| 174 | |||
| 110 | config RTC_DRV_RS5C372 | 175 | config RTC_DRV_RS5C372 |
| 111 | tristate "Ricoh RS5C372A/B" | 176 | tristate "Ricoh RS5C372A/B" |
| 112 | depends on RTC_CLASS && I2C | 177 | depends on RTC_CLASS && I2C |
| @@ -157,6 +222,22 @@ config RTC_DRV_VR41XX | |||
| 157 | To compile this driver as a module, choose M here: the | 222 | To compile this driver as a module, choose M here: the |
| 158 | module will be called rtc-vr41xx. | 223 | module will be called rtc-vr41xx. |
| 159 | 224 | ||
| 225 | config RTC_DRV_PL031 | ||
| 226 | tristate "ARM AMBA PL031 RTC" | ||
| 227 | depends on RTC_CLASS && ARM_AMBA | ||
| 228 | help | ||
| 229 | If you say Y here you will get access to ARM AMBA | ||
| 230 | PrimeCell PL031 UART found on certain ARM SOCs. | ||
| 231 | |||
| 232 | To compile this driver as a module, choose M here: the | ||
| 233 | module will be called rtc-pl031. | ||
| 234 | |||
| 235 | config RTC_DRV_AT91 | ||
| 236 | tristate "AT91RM9200" | ||
| 237 | depends on RTC_CLASS && ARCH_AT91RM9200 | ||
| 238 | help | ||
| 239 | Driver for the Atmel AT91RM9200's internal RTC (Realtime Clock). | ||
| 240 | |||
| 160 | config RTC_DRV_TEST | 241 | config RTC_DRV_TEST |
| 161 | tristate "Test driver/device" | 242 | tristate "Test driver/device" |
| 162 | depends on RTC_CLASS | 243 | depends on RTC_CLASS |
| @@ -172,4 +253,24 @@ config RTC_DRV_TEST | |||
| 172 | This driver can also be built as a module. If so, the module | 253 | This driver can also be built as a module. If so, the module |
| 173 | will be called rtc-test. | 254 | will be called rtc-test. |
| 174 | 255 | ||
| 256 | config RTC_DRV_MAX6902 | ||
| 257 | tristate "Maxim 6902" | ||
| 258 | depends on RTC_CLASS && SPI | ||
| 259 | help | ||
| 260 | If you say yes here you will get support for the | ||
| 261 | Maxim MAX6902 spi RTC chip. | ||
| 262 | |||
| 263 | This driver can also be built as a module. If so, the module | ||
| 264 | will be called rtc-max6902. | ||
| 265 | |||
| 266 | config RTC_DRV_V3020 | ||
| 267 | tristate "EM Microelectronic V3020" | ||
| 268 | depends on RTC_CLASS | ||
| 269 | help | ||
| 270 | If you say yes here you will get support for the | ||
| 271 | EM Microelectronic v3020 RTC chip. | ||
| 272 | |||
| 273 | This driver can also be built as a module. If so, the module | ||
| 274 | will be called rtc-v3020. | ||
| 275 | |||
| 175 | endmenu | 276 | endmenu |
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index a9ca0f171686..da5e38774e13 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile | |||
| @@ -13,10 +13,19 @@ obj-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o | |||
| 13 | 13 | ||
| 14 | obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o | 14 | obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o |
| 15 | obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o | 15 | obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o |
| 16 | obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o | ||
| 16 | obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o | 17 | obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o |
| 18 | obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o | ||
| 17 | obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o | 19 | obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o |
| 20 | obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o | ||
| 18 | obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o | 21 | obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o |
| 22 | obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o | ||
| 19 | obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o | 23 | obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o |
| 24 | obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o | ||
| 20 | obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o | 25 | obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o |
| 21 | obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o | 26 | obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o |
| 22 | obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o | 27 | obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o |
| 28 | obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o | ||
| 29 | obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o | ||
| 30 | obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o | ||
| 31 | obj-$(CONFIG_RTC_DRV_AT91) += rtc-at91.o | ||
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 413c7d54ea10..1cb61a761cb2 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c | |||
| @@ -69,6 +69,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, | |||
| 69 | rtc->id = id; | 69 | rtc->id = id; |
| 70 | rtc->ops = ops; | 70 | rtc->ops = ops; |
| 71 | rtc->owner = owner; | 71 | rtc->owner = owner; |
| 72 | rtc->max_user_freq = 64; | ||
| 72 | rtc->class_dev.dev = dev; | 73 | rtc->class_dev.dev = dev; |
| 73 | rtc->class_dev.class = rtc_class; | 74 | rtc->class_dev.class = rtc_class; |
| 74 | rtc->class_dev.release = rtc_device_release; | 75 | rtc->class_dev.release = rtc_device_release; |
| @@ -93,7 +94,9 @@ exit_kfree: | |||
| 93 | kfree(rtc); | 94 | kfree(rtc); |
| 94 | 95 | ||
| 95 | exit_idr: | 96 | exit_idr: |
| 97 | mutex_lock(&idr_lock); | ||
| 96 | idr_remove(&rtc_idr, id); | 98 | idr_remove(&rtc_idr, id); |
| 99 | mutex_unlock(&idr_lock); | ||
| 97 | 100 | ||
| 98 | exit: | 101 | exit: |
| 99 | dev_err(dev, "rtc core: unable to register %s, err = %d\n", | 102 | dev_err(dev, "rtc core: unable to register %s, err = %d\n", |
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 56e490709b87..579cd667b16f 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c | |||
| @@ -229,6 +229,9 @@ int rtc_irq_set_state(struct class_device *class_dev, struct rtc_task *task, int | |||
| 229 | unsigned long flags; | 229 | unsigned long flags; |
| 230 | struct rtc_device *rtc = to_rtc_device(class_dev); | 230 | struct rtc_device *rtc = to_rtc_device(class_dev); |
| 231 | 231 | ||
| 232 | if (rtc->ops->irq_set_state == NULL) | ||
| 233 | return -ENXIO; | ||
| 234 | |||
| 232 | spin_lock_irqsave(&rtc->irq_task_lock, flags); | 235 | spin_lock_irqsave(&rtc->irq_task_lock, flags); |
| 233 | if (rtc->irq_task != task) | 236 | if (rtc->irq_task != task) |
| 234 | err = -ENXIO; | 237 | err = -ENXIO; |
| @@ -243,25 +246,12 @@ EXPORT_SYMBOL_GPL(rtc_irq_set_state); | |||
| 243 | 246 | ||
| 244 | int rtc_irq_set_freq(struct class_device *class_dev, struct rtc_task *task, int freq) | 247 | int rtc_irq_set_freq(struct class_device *class_dev, struct rtc_task *task, int freq) |
| 245 | { | 248 | { |
| 246 | int err = 0, tmp = 0; | 249 | int err = 0; |
| 247 | unsigned long flags; | 250 | unsigned long flags; |
| 248 | struct rtc_device *rtc = to_rtc_device(class_dev); | 251 | struct rtc_device *rtc = to_rtc_device(class_dev); |
| 249 | 252 | ||
| 250 | /* allowed range is 2-8192 */ | 253 | if (rtc->ops->irq_set_freq == NULL) |
| 251 | if (freq < 2 || freq > 8192) | 254 | return -ENXIO; |
| 252 | return -EINVAL; | ||
| 253 | /* | ||
| 254 | FIXME: this does not belong here, will move where appropriate | ||
| 255 | at a later stage. It cannot hurt right now, trust me :) | ||
| 256 | if ((freq > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE))) | ||
| 257 | return -EACCES; | ||
| 258 | */ | ||
| 259 | /* check if freq is a power of 2 */ | ||
| 260 | while (freq > (1 << tmp)) | ||
| 261 | tmp++; | ||
| 262 | |||
| 263 | if (freq != (1 << tmp)) | ||
| 264 | return -EINVAL; | ||
| 265 | 255 | ||
| 266 | spin_lock_irqsave(&rtc->irq_task_lock, flags); | 256 | spin_lock_irqsave(&rtc->irq_task_lock, flags); |
| 267 | if (rtc->irq_task != task) | 257 | if (rtc->irq_task != task) |
diff --git a/drivers/rtc/rtc-at91.c b/drivers/rtc/rtc-at91.c new file mode 100644 index 000000000000..b676f443c17e --- /dev/null +++ b/drivers/rtc/rtc-at91.c | |||
| @@ -0,0 +1,407 @@ | |||
| 1 | /* | ||
| 2 | * Real Time Clock interface for Linux on Atmel AT91RM9200 | ||
| 3 | * | ||
| 4 | * Copyright (C) 2002 Rick Bronson | ||
| 5 | * | ||
| 6 | * Converted to RTC class model by Andrew Victor | ||
| 7 | * | ||
| 8 | * Ported to Linux 2.6 by Steven Scholz | ||
| 9 | * Based on s3c2410-rtc.c Simtec Electronics | ||
| 10 | * | ||
| 11 | * Based on sa1100-rtc.c by Nils Faerber | ||
| 12 | * Based on rtc.c by Paul Gortmaker | ||
| 13 | * | ||
| 14 | * This program is free software; you can redistribute it and/or | ||
| 15 | * modify it under the terms of the GNU General Public License | ||
| 16 | * as published by the Free Software Foundation; either version | ||
| 17 | * 2 of the License, or (at your option) any later version. | ||
| 18 | * | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/module.h> | ||
| 22 | #include <linux/kernel.h> | ||
| 23 | #include <linux/platform_device.h> | ||
| 24 | #include <linux/time.h> | ||
| 25 | #include <linux/rtc.h> | ||
| 26 | #include <linux/bcd.h> | ||
| 27 | #include <linux/interrupt.h> | ||
| 28 | #include <linux/ioctl.h> | ||
| 29 | #include <linux/completion.h> | ||
| 30 | |||
| 31 | #include <asm/uaccess.h> | ||
| 32 | #include <asm/rtc.h> | ||
| 33 | |||
| 34 | #include <asm/mach/time.h> | ||
| 35 | |||
| 36 | |||
| 37 | #define AT91_RTC_FREQ 1 | ||
| 38 | #define AT91_RTC_EPOCH 1900UL /* just like arch/arm/common/rtctime.c */ | ||
| 39 | |||
| 40 | static DECLARE_COMPLETION(at91_rtc_updated); | ||
| 41 | static unsigned int at91_alarm_year = AT91_RTC_EPOCH; | ||
| 42 | |||
| 43 | /* | ||
| 44 | * Decode time/date into rtc_time structure | ||
| 45 | */ | ||
| 46 | static void at91_rtc_decodetime(unsigned int timereg, unsigned int calreg, | ||
| 47 | struct rtc_time *tm) | ||
| 48 | { | ||
| 49 | unsigned int time, date; | ||
| 50 | |||
| 51 | /* must read twice in case it changes */ | ||
| 52 | do { | ||
| 53 | time = at91_sys_read(timereg); | ||
| 54 | date = at91_sys_read(calreg); | ||
| 55 | } while ((time != at91_sys_read(timereg)) || | ||
| 56 | (date != at91_sys_read(calreg))); | ||
| 57 | |||
| 58 | tm->tm_sec = BCD2BIN((time & AT91_RTC_SEC) >> 0); | ||
| 59 | tm->tm_min = BCD2BIN((time & AT91_RTC_MIN) >> 8); | ||
| 60 | tm->tm_hour = BCD2BIN((time & AT91_RTC_HOUR) >> 16); | ||
| 61 | |||
| 62 | /* | ||
| 63 | * The Calendar Alarm register does not have a field for | ||
| 64 | * the year - so these will return an invalid value. When an | ||
| 65 | * alarm is set, at91_alarm_year wille store the current year. | ||
| 66 | */ | ||
| 67 | tm->tm_year = BCD2BIN(date & AT91_RTC_CENT) * 100; /* century */ | ||
| 68 | tm->tm_year += BCD2BIN((date & AT91_RTC_YEAR) >> 8); /* year */ | ||
| 69 | |||
| 70 | tm->tm_wday = BCD2BIN((date & AT91_RTC_DAY) >> 21) - 1; /* day of the week [0-6], Sunday=0 */ | ||
| 71 | tm->tm_mon = BCD2BIN((date & AT91_RTC_MONTH) >> 16) - 1; | ||
| 72 | tm->tm_mday = BCD2BIN((date & AT91_RTC_DATE) >> 24); | ||
| 73 | } | ||
| 74 | |||
| 75 | /* | ||
| 76 | * Read current time and date in RTC | ||
| 77 | */ | ||
| 78 | static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm) | ||
| 79 | { | ||
| 80 | at91_rtc_decodetime(AT91_RTC_TIMR, AT91_RTC_CALR, tm); | ||
| 81 | tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year); | ||
| 82 | tm->tm_year = tm->tm_year - 1900; | ||
| 83 | |||
| 84 | pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__, | ||
| 85 | 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, | ||
| 86 | tm->tm_hour, tm->tm_min, tm->tm_sec); | ||
| 87 | |||
| 88 | return 0; | ||
| 89 | } | ||
| 90 | |||
| 91 | /* | ||
| 92 | * Set current time and date in RTC | ||
| 93 | */ | ||
| 94 | static int at91_rtc_settime(struct device *dev, struct rtc_time *tm) | ||
| 95 | { | ||
| 96 | unsigned long cr; | ||
| 97 | |||
| 98 | pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__, | ||
| 99 | 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, | ||
| 100 | tm->tm_hour, tm->tm_min, tm->tm_sec); | ||
| 101 | |||
| 102 | /* Stop Time/Calendar from counting */ | ||
| 103 | cr = at91_sys_read(AT91_RTC_CR); | ||
| 104 | at91_sys_write(AT91_RTC_CR, cr | AT91_RTC_UPDCAL | AT91_RTC_UPDTIM); | ||
| 105 | |||
| 106 | at91_sys_write(AT91_RTC_IER, AT91_RTC_ACKUPD); | ||
| 107 | wait_for_completion(&at91_rtc_updated); /* wait for ACKUPD interrupt */ | ||
| 108 | at91_sys_write(AT91_RTC_IDR, AT91_RTC_ACKUPD); | ||
| 109 | |||
| 110 | at91_sys_write(AT91_RTC_TIMR, | ||
| 111 | BIN2BCD(tm->tm_sec) << 0 | ||
| 112 | | BIN2BCD(tm->tm_min) << 8 | ||
| 113 | | BIN2BCD(tm->tm_hour) << 16); | ||
| 114 | |||
| 115 | at91_sys_write(AT91_RTC_CALR, | ||
| 116 | BIN2BCD((tm->tm_year + 1900) / 100) /* century */ | ||
| 117 | | BIN2BCD(tm->tm_year % 100) << 8 /* year */ | ||
| 118 | | BIN2BCD(tm->tm_mon + 1) << 16 /* tm_mon starts at zero */ | ||
| 119 | | BIN2BCD(tm->tm_wday + 1) << 21 /* day of the week [0-6], Sunday=0 */ | ||
| 120 | | BIN2BCD(tm->tm_mday) << 24); | ||
| 121 | |||
| 122 | /* Restart Time/Calendar */ | ||
| 123 | cr = at91_sys_read(AT91_RTC_CR); | ||
| 124 | at91_sys_write(AT91_RTC_CR, cr & ~(AT91_RTC_UPDCAL | AT91_RTC_UPDTIM)); | ||
| 125 | |||
| 126 | return 0; | ||
| 127 | } | ||
| 128 | |||
| 129 | /* | ||
| 130 | * Read alarm time and date in RTC | ||
| 131 | */ | ||
| 132 | static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
| 133 | { | ||
| 134 | struct rtc_time *tm = &alrm->time; | ||
| 135 | |||
| 136 | at91_rtc_decodetime(AT91_RTC_TIMALR, AT91_RTC_CALALR, tm); | ||
| 137 | tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year); | ||
| 138 | tm->tm_year = at91_alarm_year - 1900; | ||
| 139 | |||
| 140 | pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__, | ||
| 141 | 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, | ||
| 142 | tm->tm_hour, tm->tm_min, tm->tm_sec); | ||
| 143 | |||
| 144 | return 0; | ||
| 145 | } | ||
| 146 | |||
| 147 | /* | ||
| 148 | * Set alarm time and date in RTC | ||
| 149 | */ | ||
| 150 | static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
| 151 | { | ||
| 152 | struct rtc_time tm; | ||
| 153 | |||
| 154 | at91_rtc_decodetime(AT91_RTC_TIMR, AT91_RTC_CALR, &tm); | ||
| 155 | |||
| 156 | at91_alarm_year = tm.tm_year; | ||
| 157 | |||
| 158 | tm.tm_hour = alrm->time.tm_hour; | ||
| 159 | tm.tm_min = alrm->time.tm_min; | ||
| 160 | tm.tm_sec = alrm->time.tm_sec; | ||
| 161 | |||
| 162 | at91_sys_write(AT91_RTC_TIMALR, | ||
| 163 | BIN2BCD(tm.tm_sec) << 0 | ||
| 164 | | BIN2BCD(tm.tm_min) << 8 | ||
| 165 | | BIN2BCD(tm.tm_hour) << 16 | ||
| 166 | | AT91_RTC_HOUREN | AT91_RTC_MINEN | AT91_RTC_SECEN); | ||
| 167 | at91_sys_write(AT91_RTC_CALALR, | ||
| 168 | BIN2BCD(tm.tm_mon + 1) << 16 /* tm_mon starts at zero */ | ||
| 169 | | BIN2BCD(tm.tm_mday) << 24 | ||
| 170 | | AT91_RTC_DATEEN | AT91_RTC_MTHEN); | ||
| 171 | |||
| 172 | pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__, | ||
| 173 | at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, | ||
| 174 | tm.tm_min, tm.tm_sec); | ||
| 175 | |||
| 176 | return 0; | ||
| 177 | } | ||
| 178 | |||
| 179 | /* | ||
| 180 | * Handle commands from user-space | ||
| 181 | */ | ||
| 182 | static int at91_rtc_ioctl(struct device *dev, unsigned int cmd, | ||
| 183 | unsigned long arg) | ||
| 184 | { | ||
| 185 | int ret = 0; | ||
| 186 | |||
| 187 | pr_debug("%s(): cmd=%08x, arg=%08lx.\n", __FUNCTION__, cmd, arg); | ||
| 188 | |||
| 189 | switch (cmd) { | ||
| 190 | case RTC_AIE_OFF: /* alarm off */ | ||
| 191 | at91_sys_write(AT91_RTC_IDR, AT91_RTC_ALARM); | ||
| 192 | break; | ||
| 193 | case RTC_AIE_ON: /* alarm on */ | ||
| 194 | at91_sys_write(AT91_RTC_IER, AT91_RTC_ALARM); | ||
| 195 | break; | ||
| 196 | case RTC_UIE_OFF: /* update off */ | ||
| 197 | case RTC_PIE_OFF: /* periodic off */ | ||
| 198 | at91_sys_write(AT91_RTC_IDR, AT91_RTC_SECEV); | ||
| 199 | break; | ||
| 200 | case RTC_UIE_ON: /* update on */ | ||
| 201 | case RTC_PIE_ON: /* periodic on */ | ||
| 202 | at91_sys_write(AT91_RTC_IER, AT91_RTC_SECEV); | ||
| 203 | break; | ||
| 204 | case RTC_IRQP_READ: /* read periodic alarm frequency */ | ||
| 205 | ret = put_user(AT91_RTC_FREQ, (unsigned long *) arg); | ||
| 206 | break; | ||
| 207 | case RTC_IRQP_SET: /* set periodic alarm frequency */ | ||
| 208 | if (arg != AT91_RTC_FREQ) | ||
| 209 | ret = -EINVAL; | ||
| 210 | break; | ||
| 211 | default: | ||
| 212 | ret = -ENOIOCTLCMD; | ||
| 213 | break; | ||
| 214 | } | ||
| 215 | |||
| 216 | return ret; | ||
| 217 | } | ||
| 218 | |||
| 219 | /* | ||
| 220 | * Provide additional RTC information in /proc/driver/rtc | ||
| 221 | */ | ||
| 222 | static int at91_rtc_proc(struct device *dev, struct seq_file *seq) | ||
| 223 | { | ||
| 224 | unsigned long imr = at91_sys_read(AT91_RTC_IMR); | ||
| 225 | |||
| 226 | seq_printf(seq, "alarm_IRQ\t: %s\n", | ||
| 227 | (imr & AT91_RTC_ALARM) ? "yes" : "no"); | ||
| 228 | seq_printf(seq, "update_IRQ\t: %s\n", | ||
| 229 | (imr & AT91_RTC_ACKUPD) ? "yes" : "no"); | ||
| 230 | seq_printf(seq, "periodic_IRQ\t: %s\n", | ||
| 231 | (imr & AT91_RTC_SECEV) ? "yes" : "no"); | ||
| 232 | seq_printf(seq, "periodic_freq\t: %ld\n", | ||
| 233 | (unsigned long) AT91_RTC_FREQ); | ||
| 234 | |||
| 235 | return 0; | ||
| 236 | } | ||
| 237 | |||
| 238 | /* | ||
| 239 | * IRQ handler for the RTC | ||
| 240 | */ | ||
| 241 | static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id, | ||
| 242 | struct pt_regs *regs) | ||
| 243 | { | ||
| 244 | struct platform_device *pdev = dev_id; | ||
| 245 | struct rtc_device *rtc = platform_get_drvdata(pdev); | ||
| 246 | unsigned int rtsr; | ||
| 247 | unsigned long events = 0; | ||
| 248 | |||
| 249 | rtsr = at91_sys_read(AT91_RTC_SR) & at91_sys_read(AT91_RTC_IMR); | ||
| 250 | if (rtsr) { /* this interrupt is shared! Is it ours? */ | ||
| 251 | if (rtsr & AT91_RTC_ALARM) | ||
| 252 | events |= (RTC_AF | RTC_IRQF); | ||
| 253 | if (rtsr & AT91_RTC_SECEV) | ||
| 254 | events |= (RTC_UF | RTC_IRQF); | ||
| 255 | if (rtsr & AT91_RTC_ACKUPD) | ||
| 256 | complete(&at91_rtc_updated); | ||
| 257 | |||
| 258 | at91_sys_write(AT91_RTC_SCCR, rtsr); /* clear status reg */ | ||
| 259 | |||
| 260 | rtc_update_irq(&rtc->class_dev, 1, events); | ||
| 261 | |||
| 262 | pr_debug("%s(): num=%ld, events=0x%02lx\n", __FUNCTION__, | ||
| 263 | events >> 8, events & 0x000000FF); | ||
| 264 | |||
| 265 | return IRQ_HANDLED; | ||
| 266 | } | ||
| 267 | return IRQ_NONE; /* not handled */ | ||
| 268 | } | ||
| 269 | |||
| 270 | static struct rtc_class_ops at91_rtc_ops = { | ||
| 271 | .ioctl = at91_rtc_ioctl, | ||
| 272 | .read_time = at91_rtc_readtime, | ||
| 273 | .set_time = at91_rtc_settime, | ||
| 274 | .read_alarm = at91_rtc_readalarm, | ||
| 275 | .set_alarm = at91_rtc_setalarm, | ||
| 276 | .proc = at91_rtc_proc, | ||
| 277 | }; | ||
| 278 | |||
| 279 | /* | ||
| 280 | * Initialize and install RTC driver | ||
| 281 | */ | ||
| 282 | static int __init at91_rtc_probe(struct platform_device *pdev) | ||
| 283 | { | ||
| 284 | struct rtc_device *rtc; | ||
| 285 | int ret; | ||
| 286 | |||
| 287 | at91_sys_write(AT91_RTC_CR, 0); | ||
| 288 | at91_sys_write(AT91_RTC_MR, 0); /* 24 hour mode */ | ||
| 289 | |||
| 290 | /* Disable all interrupts */ | ||
| 291 | at91_sys_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM | | ||
| 292 | AT91_RTC_SECEV | AT91_RTC_TIMEV | | ||
| 293 | AT91_RTC_CALEV); | ||
| 294 | |||
| 295 | ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt, | ||
| 296 | SA_SHIRQ, "at91_rtc", pdev); | ||
| 297 | if (ret) { | ||
| 298 | printk(KERN_ERR "at91_rtc: IRQ %d already in use.\n", | ||
| 299 | AT91_ID_SYS); | ||
| 300 | return ret; | ||
| 301 | } | ||
| 302 | |||
| 303 | rtc = rtc_device_register(pdev->name, &pdev->dev, | ||
| 304 | &at91_rtc_ops, THIS_MODULE); | ||
| 305 | if (IS_ERR(rtc)) { | ||
| 306 | free_irq(AT91_ID_SYS, pdev); | ||
| 307 | return PTR_ERR(rtc); | ||
| 308 | } | ||
| 309 | platform_set_drvdata(pdev, rtc); | ||
| 310 | |||
| 311 | printk(KERN_INFO "AT91 Real Time Clock driver.\n"); | ||
| 312 | return 0; | ||
| 313 | } | ||
| 314 | |||
| 315 | /* | ||
| 316 | * Disable and remove the RTC driver | ||
| 317 | */ | ||
| 318 | static int __devexit at91_rtc_remove(struct platform_device *pdev) | ||
| 319 | { | ||
| 320 | struct rtc_device *rtc = platform_get_drvdata(pdev); | ||
| 321 | |||
| 322 | /* Disable all interrupts */ | ||
| 323 | at91_sys_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM | | ||
| 324 | AT91_RTC_SECEV | AT91_RTC_TIMEV | | ||
| 325 | AT91_RTC_CALEV); | ||
| 326 | free_irq(AT91_ID_SYS, pdev); | ||
| 327 | |||
| 328 | rtc_device_unregister(rtc); | ||
| 329 | platform_set_drvdata(pdev, NULL); | ||
| 330 | |||
| 331 | return 0; | ||
| 332 | } | ||
| 333 | |||
| 334 | #ifdef CONFIG_PM | ||
| 335 | |||
| 336 | /* AT91RM9200 RTC Power management control */ | ||
| 337 | |||
| 338 | static struct timespec at91_rtc_delta; | ||
| 339 | |||
| 340 | static int at91_rtc_suspend(struct platform_device *pdev, pm_message_t state) | ||
| 341 | { | ||
| 342 | struct rtc_time tm; | ||
| 343 | struct timespec time; | ||
| 344 | |||
| 345 | time.tv_nsec = 0; | ||
| 346 | |||
| 347 | /* calculate time delta for suspend */ | ||
| 348 | at91_rtc_readtime(&pdev->dev, &tm); | ||
| 349 | rtc_tm_to_time(&tm, &time.tv_sec); | ||
| 350 | save_time_delta(&at91_rtc_delta, &time); | ||
| 351 | |||
| 352 | pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__, | ||
| 353 | 1900 + tm.tm_year, tm.tm_mon, tm.tm_mday, | ||
| 354 | tm.tm_hour, tm.tm_min, tm.tm_sec); | ||
| 355 | |||
| 356 | return 0; | ||
| 357 | } | ||
| 358 | |||
| 359 | static int at91_rtc_resume(struct platform_device *pdev) | ||
| 360 | { | ||
| 361 | struct rtc_time tm; | ||
| 362 | struct timespec time; | ||
| 363 | |||
| 364 | time.tv_nsec = 0; | ||
| 365 | |||
| 366 | at91_rtc_readtime(&pdev->dev, &tm); | ||
| 367 | rtc_tm_to_time(&tm, &time.tv_sec); | ||
| 368 | restore_time_delta(&at91_rtc_delta, &time); | ||
| 369 | |||
| 370 | pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__, | ||
| 371 | 1900 + tm.tm_year, tm.tm_mon, tm.tm_mday, | ||
| 372 | tm.tm_hour, tm.tm_min, tm.tm_sec); | ||
| 373 | |||
| 374 | return 0; | ||
| 375 | } | ||
| 376 | #else | ||
| 377 | #define at91_rtc_suspend NULL | ||
| 378 | #define at91_rtc_resume NULL | ||
| 379 | #endif | ||
| 380 | |||
| 381 | static struct platform_driver at91_rtc_driver = { | ||
| 382 | .probe = at91_rtc_probe, | ||
| 383 | .remove = at91_rtc_remove, | ||
| 384 | .suspend = at91_rtc_suspend, | ||
| 385 | .resume = at91_rtc_resume, | ||
| 386 | .driver = { | ||
| 387 | .name = "at91_rtc", | ||
| 388 | .owner = THIS_MODULE, | ||
| 389 | }, | ||
| 390 | }; | ||
| 391 | |||
| 392 | static int __init at91_rtc_init(void) | ||
| 393 | { | ||
| 394 | return platform_driver_register(&at91_rtc_driver); | ||
| 395 | } | ||
| 396 | |||
| 397 | static void __exit at91_rtc_exit(void) | ||
| 398 | { | ||
| 399 | platform_driver_unregister(&at91_rtc_driver); | ||
| 400 | } | ||
| 401 | |||
| 402 | module_init(at91_rtc_init); | ||
| 403 | module_exit(at91_rtc_exit); | ||
| 404 | |||
| 405 | MODULE_AUTHOR("Rick Bronson"); | ||
| 406 | MODULE_DESCRIPTION("RTC driver for Atmel AT91RM9200"); | ||
| 407 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 2011567005f9..61a58259c93f 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c | |||
| @@ -48,6 +48,93 @@ static int rtc_dev_open(struct inode *inode, struct file *file) | |||
| 48 | return err; | 48 | return err; |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL | ||
| 52 | /* | ||
| 53 | * Routine to poll RTC seconds field for change as often as possible, | ||
| 54 | * after first RTC_UIE use timer to reduce polling | ||
| 55 | */ | ||
| 56 | static void rtc_uie_task(void *data) | ||
| 57 | { | ||
| 58 | struct rtc_device *rtc = data; | ||
| 59 | struct rtc_time tm; | ||
| 60 | int num = 0; | ||
| 61 | int err; | ||
| 62 | |||
| 63 | err = rtc_read_time(&rtc->class_dev, &tm); | ||
| 64 | spin_lock_irq(&rtc->irq_lock); | ||
| 65 | if (rtc->stop_uie_polling || err) { | ||
| 66 | rtc->uie_task_active = 0; | ||
| 67 | } else if (rtc->oldsecs != tm.tm_sec) { | ||
| 68 | num = (tm.tm_sec + 60 - rtc->oldsecs) % 60; | ||
| 69 | rtc->oldsecs = tm.tm_sec; | ||
| 70 | rtc->uie_timer.expires = jiffies + HZ - (HZ/10); | ||
| 71 | rtc->uie_timer_active = 1; | ||
| 72 | rtc->uie_task_active = 0; | ||
| 73 | add_timer(&rtc->uie_timer); | ||
| 74 | } else if (schedule_work(&rtc->uie_task) == 0) { | ||
| 75 | rtc->uie_task_active = 0; | ||
| 76 | } | ||
| 77 | spin_unlock_irq(&rtc->irq_lock); | ||
| 78 | if (num) | ||
| 79 | rtc_update_irq(&rtc->class_dev, num, RTC_UF | RTC_IRQF); | ||
| 80 | } | ||
| 81 | |||
| 82 | static void rtc_uie_timer(unsigned long data) | ||
| 83 | { | ||
| 84 | struct rtc_device *rtc = (struct rtc_device *)data; | ||
| 85 | unsigned long flags; | ||
| 86 | |||
| 87 | spin_lock_irqsave(&rtc->irq_lock, flags); | ||
| 88 | rtc->uie_timer_active = 0; | ||
| 89 | rtc->uie_task_active = 1; | ||
| 90 | if ((schedule_work(&rtc->uie_task) == 0)) | ||
| 91 | rtc->uie_task_active = 0; | ||
| 92 | spin_unlock_irqrestore(&rtc->irq_lock, flags); | ||
| 93 | } | ||
| 94 | |||
| 95 | static void clear_uie(struct rtc_device *rtc) | ||
| 96 | { | ||
| 97 | spin_lock_irq(&rtc->irq_lock); | ||
| 98 | if (rtc->irq_active) { | ||
| 99 | rtc->stop_uie_polling = 1; | ||
| 100 | if (rtc->uie_timer_active) { | ||
| 101 | spin_unlock_irq(&rtc->irq_lock); | ||
| 102 | del_timer_sync(&rtc->uie_timer); | ||
| 103 | spin_lock_irq(&rtc->irq_lock); | ||
| 104 | rtc->uie_timer_active = 0; | ||
| 105 | } | ||
| 106 | if (rtc->uie_task_active) { | ||
| 107 | spin_unlock_irq(&rtc->irq_lock); | ||
| 108 | flush_scheduled_work(); | ||
| 109 | spin_lock_irq(&rtc->irq_lock); | ||
| 110 | } | ||
| 111 | rtc->irq_active = 0; | ||
| 112 | } | ||
| 113 | spin_unlock_irq(&rtc->irq_lock); | ||
| 114 | } | ||
| 115 | |||
| 116 | static int set_uie(struct rtc_device *rtc) | ||
| 117 | { | ||
| 118 | struct rtc_time tm; | ||
| 119 | int err; | ||
| 120 | |||
| 121 | err = rtc_read_time(&rtc->class_dev, &tm); | ||
| 122 | if (err) | ||
| 123 | return err; | ||
| 124 | spin_lock_irq(&rtc->irq_lock); | ||
| 125 | if (!rtc->irq_active) { | ||
| 126 | rtc->irq_active = 1; | ||
| 127 | rtc->stop_uie_polling = 0; | ||
| 128 | rtc->oldsecs = tm.tm_sec; | ||
| 129 | rtc->uie_task_active = 1; | ||
| 130 | if (schedule_work(&rtc->uie_task) == 0) | ||
| 131 | rtc->uie_task_active = 0; | ||
| 132 | } | ||
| 133 | rtc->irq_data = 0; | ||
| 134 | spin_unlock_irq(&rtc->irq_lock); | ||
| 135 | return 0; | ||
| 136 | } | ||
| 137 | #endif /* CONFIG_RTC_INTF_DEV_UIE_EMUL */ | ||
| 51 | 138 | ||
| 52 | static ssize_t | 139 | static ssize_t |
| 53 | rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | 140 | rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) |
| @@ -127,6 +214,28 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, | |||
| 127 | struct rtc_wkalrm alarm; | 214 | struct rtc_wkalrm alarm; |
| 128 | void __user *uarg = (void __user *) arg; | 215 | void __user *uarg = (void __user *) arg; |
| 129 | 216 | ||
| 217 | /* check that the calles has appropriate permissions | ||
| 218 | * for certain ioctls. doing this check here is useful | ||
| 219 | * to avoid duplicate code in each driver. | ||
| 220 | */ | ||
| 221 | switch (cmd) { | ||
| 222 | case RTC_EPOCH_SET: | ||
| 223 | case RTC_SET_TIME: | ||
| 224 | if (!capable(CAP_SYS_TIME)) | ||
| 225 | return -EACCES; | ||
| 226 | break; | ||
| 227 | |||
| 228 | case RTC_IRQP_SET: | ||
| 229 | if (arg > rtc->max_user_freq && !capable(CAP_SYS_RESOURCE)) | ||
| 230 | return -EACCES; | ||
| 231 | break; | ||
| 232 | |||
| 233 | case RTC_PIE_ON: | ||
| 234 | if (!capable(CAP_SYS_RESOURCE)) | ||
| 235 | return -EACCES; | ||
| 236 | break; | ||
| 237 | } | ||
| 238 | |||
| 130 | /* avoid conflicting IRQ users */ | 239 | /* avoid conflicting IRQ users */ |
| 131 | if (cmd == RTC_PIE_ON || cmd == RTC_PIE_OFF || cmd == RTC_IRQP_SET) { | 240 | if (cmd == RTC_PIE_ON || cmd == RTC_PIE_OFF || cmd == RTC_IRQP_SET) { |
| 132 | spin_lock(&rtc->irq_task_lock); | 241 | spin_lock(&rtc->irq_task_lock); |
| @@ -185,9 +294,6 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, | |||
| 185 | break; | 294 | break; |
| 186 | 295 | ||
| 187 | case RTC_SET_TIME: | 296 | case RTC_SET_TIME: |
| 188 | if (!capable(CAP_SYS_TIME)) | ||
| 189 | return -EACCES; | ||
| 190 | |||
| 191 | if (copy_from_user(&tm, uarg, sizeof(tm))) | 297 | if (copy_from_user(&tm, uarg, sizeof(tm))) |
| 192 | return -EFAULT; | 298 | return -EFAULT; |
| 193 | 299 | ||
| @@ -203,10 +309,6 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, | |||
| 203 | err = -EINVAL; | 309 | err = -EINVAL; |
| 204 | break; | 310 | break; |
| 205 | } | 311 | } |
| 206 | if (!capable(CAP_SYS_TIME)) { | ||
| 207 | err = -EACCES; | ||
| 208 | break; | ||
| 209 | } | ||
| 210 | rtc_epoch = arg; | 312 | rtc_epoch = arg; |
| 211 | err = 0; | 313 | err = 0; |
| 212 | #endif | 314 | #endif |
| @@ -232,6 +334,14 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, | |||
| 232 | return -EFAULT; | 334 | return -EFAULT; |
| 233 | break; | 335 | break; |
| 234 | 336 | ||
| 337 | #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL | ||
| 338 | case RTC_UIE_OFF: | ||
| 339 | clear_uie(rtc); | ||
| 340 | return 0; | ||
| 341 | |||
| 342 | case RTC_UIE_ON: | ||
| 343 | return set_uie(rtc); | ||
| 344 | #endif | ||
| 235 | default: | 345 | default: |
| 236 | err = -ENOTTY; | 346 | err = -ENOTTY; |
| 237 | break; | 347 | break; |
| @@ -244,6 +354,9 @@ static int rtc_dev_release(struct inode *inode, struct file *file) | |||
| 244 | { | 354 | { |
| 245 | struct rtc_device *rtc = to_rtc_device(file->private_data); | 355 | struct rtc_device *rtc = to_rtc_device(file->private_data); |
| 246 | 356 | ||
| 357 | #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL | ||
| 358 | clear_uie(rtc); | ||
| 359 | #endif | ||
| 247 | if (rtc->ops->release) | 360 | if (rtc->ops->release) |
| 248 | rtc->ops->release(rtc->class_dev.dev); | 361 | rtc->ops->release(rtc->class_dev.dev); |
| 249 | 362 | ||
| @@ -284,6 +397,10 @@ static int rtc_dev_add_device(struct class_device *class_dev, | |||
| 284 | mutex_init(&rtc->char_lock); | 397 | mutex_init(&rtc->char_lock); |
| 285 | spin_lock_init(&rtc->irq_lock); | 398 | spin_lock_init(&rtc->irq_lock); |
| 286 | init_waitqueue_head(&rtc->irq_queue); | 399 | init_waitqueue_head(&rtc->irq_queue); |
| 400 | #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL | ||
| 401 | INIT_WORK(&rtc->uie_task, rtc_uie_task, rtc); | ||
| 402 | setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc); | ||
| 403 | #endif | ||
| 287 | 404 | ||
| 288 | cdev_init(&rtc->char_dev, &rtc_dev_fops); | 405 | cdev_init(&rtc->char_dev, &rtc_dev_fops); |
| 289 | rtc->char_dev.owner = rtc->owner; | 406 | rtc->char_dev.owner = rtc->owner; |
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c new file mode 100644 index 000000000000..e8afb9384786 --- /dev/null +++ b/drivers/rtc/rtc-ds1307.c | |||
| @@ -0,0 +1,388 @@ | |||
| 1 | /* | ||
| 2 | * rtc-ds1307.c - RTC driver for some mostly-compatible I2C chips. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2005 James Chapman (ds1337 core) | ||
| 5 | * Copyright (C) 2006 David Brownell | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/init.h> | ||
| 14 | #include <linux/slab.h> | ||
| 15 | #include <linux/i2c.h> | ||
| 16 | #include <linux/string.h> | ||
| 17 | #include <linux/rtc.h> | ||
| 18 | #include <linux/bcd.h> | ||
| 19 | |||
| 20 | |||
| 21 | |||
| 22 | /* We can't determine type by probing, but if we expect pre-Linux code | ||
| 23 | * to have set the chip up as a clock (turning on the oscillator and | ||
| 24 | * setting the date and time), Linux can ignore the non-clock features. | ||
| 25 | * That's a natural job for a factory or repair bench. | ||
| 26 | * | ||
| 27 | * If the I2C "force" mechanism is used, we assume the chip is a ds1337. | ||
| 28 | * (Much better would be board-specific tables of I2C devices, along with | ||
| 29 | * the platform_data drivers would use to sort such issues out.) | ||
| 30 | */ | ||
| 31 | enum ds_type { | ||
| 32 | unknown = 0, | ||
| 33 | ds_1307, /* or ds1338, ... */ | ||
| 34 | ds_1337, /* or ds1339, ... */ | ||
| 35 | ds_1340, /* or st m41t00, ... */ | ||
| 36 | // rs5c372 too? different address... | ||
| 37 | }; | ||
| 38 | |||
| 39 | static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END }; | ||
| 40 | |||
| 41 | I2C_CLIENT_INSMOD; | ||
| 42 | |||
| 43 | |||
| 44 | |||
| 45 | /* RTC registers don't differ much, except for the century flag */ | ||
| 46 | #define DS1307_REG_SECS 0x00 /* 00-59 */ | ||
| 47 | # define DS1307_BIT_CH 0x80 | ||
| 48 | #define DS1307_REG_MIN 0x01 /* 00-59 */ | ||
| 49 | #define DS1307_REG_HOUR 0x02 /* 00-23, or 1-12{am,pm} */ | ||
| 50 | # define DS1340_BIT_CENTURY_EN 0x80 /* in REG_HOUR */ | ||
| 51 | # define DS1340_BIT_CENTURY 0x40 /* in REG_HOUR */ | ||
| 52 | #define DS1307_REG_WDAY 0x03 /* 01-07 */ | ||
| 53 | #define DS1307_REG_MDAY 0x04 /* 01-31 */ | ||
| 54 | #define DS1307_REG_MONTH 0x05 /* 01-12 */ | ||
| 55 | # define DS1337_BIT_CENTURY 0x80 /* in REG_MONTH */ | ||
| 56 | #define DS1307_REG_YEAR 0x06 /* 00-99 */ | ||
| 57 | |||
| 58 | /* Other registers (control, status, alarms, trickle charge, NVRAM, etc) | ||
| 59 | * start at 7, and they differ a lot. Only control and status matter for RTC; | ||
| 60 | * be careful using them. | ||
| 61 | */ | ||
| 62 | #define DS1307_REG_CONTROL 0x07 | ||
| 63 | # define DS1307_BIT_OUT 0x80 | ||
| 64 | # define DS1307_BIT_SQWE 0x10 | ||
| 65 | # define DS1307_BIT_RS1 0x02 | ||
| 66 | # define DS1307_BIT_RS0 0x01 | ||
| 67 | #define DS1337_REG_CONTROL 0x0e | ||
| 68 | # define DS1337_BIT_nEOSC 0x80 | ||
| 69 | # define DS1337_BIT_RS2 0x10 | ||
| 70 | # define DS1337_BIT_RS1 0x08 | ||
| 71 | # define DS1337_BIT_INTCN 0x04 | ||
| 72 | # define DS1337_BIT_A2IE 0x02 | ||
| 73 | # define DS1337_BIT_A1IE 0x01 | ||
| 74 | #define DS1337_REG_STATUS 0x0f | ||
| 75 | # define DS1337_BIT_OSF 0x80 | ||
| 76 | # define DS1337_BIT_A2I 0x02 | ||
| 77 | # define DS1337_BIT_A1I 0x01 | ||
| 78 | #define DS1339_REG_TRICKLE 0x10 | ||
| 79 | |||
| 80 | |||
| 81 | |||
| 82 | struct ds1307 { | ||
| 83 | u8 reg_addr; | ||
| 84 | u8 regs[8]; | ||
| 85 | enum ds_type type; | ||
| 86 | struct i2c_msg msg[2]; | ||
| 87 | struct i2c_client client; | ||
| 88 | struct rtc_device *rtc; | ||
| 89 | }; | ||
| 90 | |||
| 91 | |||
| 92 | static int ds1307_get_time(struct device *dev, struct rtc_time *t) | ||
| 93 | { | ||
| 94 | struct ds1307 *ds1307 = dev_get_drvdata(dev); | ||
| 95 | int tmp; | ||
| 96 | |||
| 97 | /* read the RTC registers all at once */ | ||
| 98 | ds1307->msg[1].flags = I2C_M_RD; | ||
| 99 | ds1307->msg[1].len = 7; | ||
| 100 | |||
| 101 | tmp = i2c_transfer(ds1307->client.adapter, ds1307->msg, 2); | ||
| 102 | if (tmp != 2) { | ||
| 103 | dev_err(dev, "%s error %d\n", "read", tmp); | ||
| 104 | return -EIO; | ||
| 105 | } | ||
| 106 | |||
| 107 | dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n", | ||
| 108 | "read", | ||
| 109 | ds1307->regs[0], ds1307->regs[1], | ||
| 110 | ds1307->regs[2], ds1307->regs[3], | ||
| 111 | ds1307->regs[4], ds1307->regs[5], | ||
| 112 | ds1307->regs[6]); | ||
| 113 | |||
| 114 | t->tm_sec = BCD2BIN(ds1307->regs[DS1307_REG_SECS] & 0x7f); | ||
| 115 | t->tm_min = BCD2BIN(ds1307->regs[DS1307_REG_MIN] & 0x7f); | ||
| 116 | tmp = ds1307->regs[DS1307_REG_HOUR] & 0x3f; | ||
| 117 | t->tm_hour = BCD2BIN(tmp); | ||
| 118 | t->tm_wday = BCD2BIN(ds1307->regs[DS1307_REG_WDAY] & 0x07) - 1; | ||
| 119 | t->tm_mday = BCD2BIN(ds1307->regs[DS1307_REG_MDAY] & 0x3f); | ||
| 120 | tmp = ds1307->regs[DS1307_REG_MONTH] & 0x1f; | ||
| 121 | t->tm_mon = BCD2BIN(tmp) - 1; | ||
| 122 | |||
| 123 | /* assume 20YY not 19YY, and ignore DS1337_BIT_CENTURY */ | ||
| 124 | t->tm_year = BCD2BIN(ds1307->regs[DS1307_REG_YEAR]) + 100; | ||
| 125 | |||
| 126 | dev_dbg(dev, "%s secs=%d, mins=%d, " | ||
| 127 | "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", | ||
| 128 | "read", t->tm_sec, t->tm_min, | ||
| 129 | t->tm_hour, t->tm_mday, | ||
| 130 | t->tm_mon, t->tm_year, t->tm_wday); | ||
| 131 | |||
| 132 | return 0; | ||
| 133 | } | ||
| 134 | |||
| 135 | static int ds1307_set_time(struct device *dev, struct rtc_time *t) | ||
| 136 | { | ||
| 137 | struct ds1307 *ds1307 = dev_get_drvdata(dev); | ||
| 138 | int result; | ||
| 139 | int tmp; | ||
| 140 | u8 *buf = ds1307->regs; | ||
| 141 | |||
| 142 | dev_dbg(dev, "%s secs=%d, mins=%d, " | ||
| 143 | "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", | ||
| 144 | "write", dt->tm_sec, dt->tm_min, | ||
| 145 | dt->tm_hour, dt->tm_mday, | ||
| 146 | dt->tm_mon, dt->tm_year, dt->tm_wday); | ||
| 147 | |||
| 148 | *buf++ = 0; /* first register addr */ | ||
| 149 | buf[DS1307_REG_SECS] = BIN2BCD(t->tm_sec); | ||
| 150 | buf[DS1307_REG_MIN] = BIN2BCD(t->tm_min); | ||
| 151 | buf[DS1307_REG_HOUR] = BIN2BCD(t->tm_hour); | ||
| 152 | buf[DS1307_REG_WDAY] = BIN2BCD(t->tm_wday + 1); | ||
| 153 | buf[DS1307_REG_MDAY] = BIN2BCD(t->tm_mday); | ||
| 154 | buf[DS1307_REG_MONTH] = BIN2BCD(t->tm_mon + 1); | ||
| 155 | |||
| 156 | /* assume 20YY not 19YY */ | ||
| 157 | tmp = t->tm_year - 100; | ||
| 158 | buf[DS1307_REG_YEAR] = BIN2BCD(tmp); | ||
| 159 | |||
| 160 | if (ds1307->type == ds_1337) | ||
| 161 | buf[DS1307_REG_MONTH] |= DS1337_BIT_CENTURY; | ||
| 162 | else if (ds1307->type == ds_1340) | ||
| 163 | buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY_EN | ||
| 164 | | DS1340_BIT_CENTURY; | ||
| 165 | |||
| 166 | ds1307->msg[1].flags = 0; | ||
| 167 | ds1307->msg[1].len = 8; | ||
| 168 | |||
| 169 | dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n", | ||
| 170 | "write", buf[0], buf[1], buf[2], buf[3], | ||
| 171 | buf[4], buf[5], buf[6]); | ||
| 172 | |||
| 173 | result = i2c_transfer(ds1307->client.adapter, &ds1307->msg[1], 1); | ||
| 174 | if (result != 1) { | ||
| 175 | dev_err(dev, "%s error %d\n", "write", tmp); | ||
| 176 | return -EIO; | ||
| 177 | } | ||
| 178 | return 0; | ||
| 179 | } | ||
| 180 | |||
| 181 | static struct rtc_class_ops ds13xx_rtc_ops = { | ||
| 182 | .read_time = ds1307_get_time, | ||
| 183 | .set_time = ds1307_set_time, | ||
| 184 | }; | ||
| 185 | |||
| 186 | static struct i2c_driver ds1307_driver; | ||
| 187 | |||
| 188 | static int __devinit | ||
| 189 | ds1307_detect(struct i2c_adapter *adapter, int address, int kind) | ||
| 190 | { | ||
| 191 | struct ds1307 *ds1307; | ||
| 192 | int err = -ENODEV; | ||
| 193 | struct i2c_client *client; | ||
| 194 | int tmp; | ||
| 195 | |||
| 196 | if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) { | ||
| 197 | err = -ENOMEM; | ||
| 198 | goto exit; | ||
| 199 | } | ||
| 200 | |||
| 201 | client = &ds1307->client; | ||
| 202 | client->addr = address; | ||
| 203 | client->adapter = adapter; | ||
| 204 | client->driver = &ds1307_driver; | ||
| 205 | client->flags = 0; | ||
| 206 | |||
| 207 | i2c_set_clientdata(client, ds1307); | ||
| 208 | |||
| 209 | ds1307->msg[0].addr = client->addr; | ||
| 210 | ds1307->msg[0].flags = 0; | ||
| 211 | ds1307->msg[0].len = 1; | ||
| 212 | ds1307->msg[0].buf = &ds1307->reg_addr; | ||
| 213 | |||
| 214 | ds1307->msg[1].addr = client->addr; | ||
| 215 | ds1307->msg[1].flags = I2C_M_RD; | ||
| 216 | ds1307->msg[1].len = sizeof(ds1307->regs); | ||
| 217 | ds1307->msg[1].buf = ds1307->regs; | ||
| 218 | |||
| 219 | /* HACK: "force" implies "needs ds1337-style-oscillator setup" */ | ||
| 220 | if (kind >= 0) { | ||
| 221 | ds1307->type = ds_1337; | ||
| 222 | |||
| 223 | ds1307->reg_addr = DS1337_REG_CONTROL; | ||
| 224 | ds1307->msg[1].len = 2; | ||
| 225 | |||
| 226 | tmp = i2c_transfer(client->adapter, ds1307->msg, 2); | ||
| 227 | if (tmp != 2) { | ||
| 228 | pr_debug("read error %d\n", tmp); | ||
| 229 | err = -EIO; | ||
| 230 | goto exit_free; | ||
| 231 | } | ||
| 232 | |||
| 233 | ds1307->reg_addr = 0; | ||
| 234 | ds1307->msg[1].len = sizeof(ds1307->regs); | ||
| 235 | |||
| 236 | /* oscillator is off; need to turn it on */ | ||
| 237 | if ((ds1307->regs[0] & DS1337_BIT_nEOSC) | ||
| 238 | || (ds1307->regs[1] & DS1337_BIT_OSF)) { | ||
| 239 | printk(KERN_ERR "no ds1337 oscillator code\n"); | ||
| 240 | goto exit_free; | ||
| 241 | } | ||
| 242 | } else | ||
| 243 | ds1307->type = ds_1307; | ||
| 244 | |||
| 245 | read_rtc: | ||
| 246 | /* read RTC registers */ | ||
| 247 | |||
| 248 | tmp = i2c_transfer(client->adapter, ds1307->msg, 2); | ||
| 249 | if (tmp != 2) { | ||
| 250 | pr_debug("read error %d\n", tmp); | ||
| 251 | err = -EIO; | ||
| 252 | goto exit_free; | ||
| 253 | } | ||
| 254 | |||
| 255 | /* minimal sanity checking; some chips (like DS1340) don't | ||
| 256 | * specify the extra bits as must-be-zero, but there are | ||
| 257 | * still a few values that are clearly out-of-range. | ||
| 258 | */ | ||
| 259 | tmp = ds1307->regs[DS1307_REG_SECS]; | ||
| 260 | if (tmp & DS1307_BIT_CH) { | ||
| 261 | if (ds1307->type && ds1307->type != ds_1307) { | ||
| 262 | pr_debug("not a ds1307?\n"); | ||
| 263 | goto exit_free; | ||
| 264 | } | ||
| 265 | ds1307->type = ds_1307; | ||
| 266 | |||
| 267 | /* this partial initialization should work for ds1307, | ||
| 268 | * ds1338, ds1340, st m41t00, and more. | ||
| 269 | */ | ||
| 270 | dev_warn(&client->dev, "oscillator started; SET TIME!\n"); | ||
| 271 | i2c_smbus_write_byte_data(client, 0, 0); | ||
| 272 | goto read_rtc; | ||
| 273 | } | ||
| 274 | tmp = BCD2BIN(tmp & 0x7f); | ||
| 275 | if (tmp > 60) | ||
| 276 | goto exit_free; | ||
| 277 | tmp = BCD2BIN(ds1307->regs[DS1307_REG_MIN] & 0x7f); | ||
| 278 | if (tmp > 60) | ||
| 279 | goto exit_free; | ||
| 280 | |||
| 281 | tmp = BCD2BIN(ds1307->regs[DS1307_REG_MDAY] & 0x3f); | ||
| 282 | if (tmp == 0 || tmp > 31) | ||
| 283 | goto exit_free; | ||
| 284 | |||
| 285 | tmp = BCD2BIN(ds1307->regs[DS1307_REG_MONTH] & 0x1f); | ||
| 286 | if (tmp == 0 || tmp > 12) | ||
| 287 | goto exit_free; | ||
| 288 | |||
| 289 | /* force into in 24 hour mode (most chips) or | ||
| 290 | * disable century bit (ds1340) | ||
| 291 | */ | ||
| 292 | tmp = ds1307->regs[DS1307_REG_HOUR]; | ||
| 293 | if (tmp & (1 << 6)) { | ||
| 294 | if (tmp & (1 << 5)) | ||
| 295 | tmp = BCD2BIN(tmp & 0x1f) + 12; | ||
| 296 | else | ||
| 297 | tmp = BCD2BIN(tmp); | ||
| 298 | i2c_smbus_write_byte_data(client, | ||
| 299 | DS1307_REG_HOUR, | ||
| 300 | BIN2BCD(tmp)); | ||
| 301 | } | ||
| 302 | |||
| 303 | /* FIXME chips like 1337 can generate alarm irqs too; those are | ||
| 304 | * worth exposing through the API (especially when the irq is | ||
| 305 | * wakeup-capable). | ||
| 306 | */ | ||
| 307 | |||
| 308 | switch (ds1307->type) { | ||
| 309 | case unknown: | ||
| 310 | strlcpy(client->name, "unknown", I2C_NAME_SIZE); | ||
| 311 | break; | ||
| 312 | case ds_1307: | ||
| 313 | strlcpy(client->name, "ds1307", I2C_NAME_SIZE); | ||
| 314 | break; | ||
| 315 | case ds_1337: | ||
| 316 | strlcpy(client->name, "ds1337", I2C_NAME_SIZE); | ||
| 317 | break; | ||
| 318 | case ds_1340: | ||
| 319 | strlcpy(client->name, "ds1340", I2C_NAME_SIZE); | ||
| 320 | break; | ||
| 321 | } | ||
| 322 | |||
| 323 | /* Tell the I2C layer a new client has arrived */ | ||
| 324 | if ((err = i2c_attach_client(client))) | ||
| 325 | goto exit_free; | ||
| 326 | |||
| 327 | ds1307->rtc = rtc_device_register(client->name, &client->dev, | ||
| 328 | &ds13xx_rtc_ops, THIS_MODULE); | ||
| 329 | if (IS_ERR(ds1307->rtc)) { | ||
| 330 | err = PTR_ERR(ds1307->rtc); | ||
| 331 | dev_err(&client->dev, | ||
| 332 | "unable to register the class device\n"); | ||
| 333 | goto exit_detach; | ||
| 334 | } | ||
| 335 | |||
| 336 | return 0; | ||
| 337 | |||
| 338 | exit_detach: | ||
| 339 | i2c_detach_client(client); | ||
| 340 | exit_free: | ||
| 341 | kfree(ds1307); | ||
| 342 | exit: | ||
| 343 | return err; | ||
| 344 | } | ||
| 345 | |||
| 346 | static int __devinit | ||
| 347 | ds1307_attach_adapter(struct i2c_adapter *adapter) | ||
| 348 | { | ||
| 349 | if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) | ||
| 350 | return 0; | ||
| 351 | return i2c_probe(adapter, &addr_data, ds1307_detect); | ||
| 352 | } | ||
| 353 | |||
| 354 | static int __devexit ds1307_detach_client(struct i2c_client *client) | ||
| 355 | { | ||
| 356 | int err; | ||
| 357 | struct ds1307 *ds1307 = i2c_get_clientdata(client); | ||
| 358 | |||
| 359 | rtc_device_unregister(ds1307->rtc); | ||
| 360 | if ((err = i2c_detach_client(client))) | ||
| 361 | return err; | ||
| 362 | kfree(ds1307); | ||
| 363 | return 0; | ||
| 364 | } | ||
| 365 | |||
| 366 | static struct i2c_driver ds1307_driver = { | ||
| 367 | .driver = { | ||
| 368 | .name = "ds1307", | ||
| 369 | .owner = THIS_MODULE, | ||
| 370 | }, | ||
| 371 | .attach_adapter = ds1307_attach_adapter, | ||
| 372 | .detach_client = __devexit_p(ds1307_detach_client), | ||
| 373 | }; | ||
| 374 | |||
| 375 | static int __init ds1307_init(void) | ||
| 376 | { | ||
| 377 | return i2c_add_driver(&ds1307_driver); | ||
| 378 | } | ||
| 379 | module_init(ds1307_init); | ||
| 380 | |||
| 381 | static void __exit ds1307_exit(void) | ||
| 382 | { | ||
| 383 | i2c_del_driver(&ds1307_driver); | ||
| 384 | } | ||
| 385 | module_exit(ds1307_exit); | ||
| 386 | |||
| 387 | MODULE_DESCRIPTION("RTC driver for DS1307 and similar chips"); | ||
| 388 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c new file mode 100644 index 000000000000..762521a1419c --- /dev/null +++ b/drivers/rtc/rtc-ds1553.c | |||
| @@ -0,0 +1,414 @@ | |||
| 1 | /* | ||
| 2 | * An rtc driver for the Dallas DS1553 | ||
| 3 | * | ||
| 4 | * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/bcd.h> | ||
| 12 | #include <linux/init.h> | ||
| 13 | #include <linux/kernel.h> | ||
| 14 | #include <linux/delay.h> | ||
| 15 | #include <linux/jiffies.h> | ||
| 16 | #include <linux/interrupt.h> | ||
| 17 | #include <linux/rtc.h> | ||
| 18 | #include <linux/platform_device.h> | ||
| 19 | #include <linux/io.h> | ||
| 20 | |||
| 21 | #define DRV_VERSION "0.1" | ||
| 22 | |||
| 23 | #define RTC_REG_SIZE 0x2000 | ||
| 24 | #define RTC_OFFSET 0x1ff0 | ||
| 25 | |||
| 26 | #define RTC_FLAGS (RTC_OFFSET + 0) | ||
| 27 | #define RTC_SECONDS_ALARM (RTC_OFFSET + 2) | ||
| 28 | #define RTC_MINUTES_ALARM (RTC_OFFSET + 3) | ||
| 29 | #define RTC_HOURS_ALARM (RTC_OFFSET + 4) | ||
| 30 | #define RTC_DATE_ALARM (RTC_OFFSET + 5) | ||
| 31 | #define RTC_INTERRUPTS (RTC_OFFSET + 6) | ||
| 32 | #define RTC_WATCHDOG (RTC_OFFSET + 7) | ||
| 33 | #define RTC_CONTROL (RTC_OFFSET + 8) | ||
| 34 | #define RTC_CENTURY (RTC_OFFSET + 8) | ||
| 35 | #define RTC_SECONDS (RTC_OFFSET + 9) | ||
| 36 | #define RTC_MINUTES (RTC_OFFSET + 10) | ||
| 37 | #define RTC_HOURS (RTC_OFFSET + 11) | ||
| 38 | #define RTC_DAY (RTC_OFFSET + 12) | ||
| 39 | #define RTC_DATE (RTC_OFFSET + 13) | ||
| 40 | #define RTC_MONTH (RTC_OFFSET + 14) | ||
| 41 | #define RTC_YEAR (RTC_OFFSET + 15) | ||
| 42 | |||
| 43 | #define RTC_CENTURY_MASK 0x3f | ||
| 44 | #define RTC_SECONDS_MASK 0x7f | ||
| 45 | #define RTC_DAY_MASK 0x07 | ||
| 46 | |||
| 47 | /* Bits in the Control/Century register */ | ||
| 48 | #define RTC_WRITE 0x80 | ||
| 49 | #define RTC_READ 0x40 | ||
| 50 | |||
| 51 | /* Bits in the Seconds register */ | ||
| 52 | #define RTC_STOP 0x80 | ||
| 53 | |||
| 54 | /* Bits in the Flags register */ | ||
| 55 | #define RTC_FLAGS_AF 0x40 | ||
| 56 | #define RTC_FLAGS_BLF 0x10 | ||
| 57 | |||
| 58 | /* Bits in the Interrupts register */ | ||
| 59 | #define RTC_INTS_AE 0x80 | ||
| 60 | |||
| 61 | struct rtc_plat_data { | ||
| 62 | struct rtc_device *rtc; | ||
| 63 | void __iomem *ioaddr; | ||
| 64 | unsigned long baseaddr; | ||
| 65 | unsigned long last_jiffies; | ||
| 66 | int irq; | ||
| 67 | unsigned int irqen; | ||
| 68 | int alrm_sec; | ||
| 69 | int alrm_min; | ||
| 70 | int alrm_hour; | ||
| 71 | int alrm_mday; | ||
| 72 | }; | ||
| 73 | |||
| 74 | static int ds1553_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
| 75 | { | ||
| 76 | struct platform_device *pdev = to_platform_device(dev); | ||
| 77 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
| 78 | void __iomem *ioaddr = pdata->ioaddr; | ||
| 79 | u8 century; | ||
| 80 | |||
| 81 | century = BIN2BCD((tm->tm_year + 1900) / 100); | ||
| 82 | |||
| 83 | writeb(RTC_WRITE, pdata->ioaddr + RTC_CONTROL); | ||
| 84 | |||
| 85 | writeb(BIN2BCD(tm->tm_year % 100), ioaddr + RTC_YEAR); | ||
| 86 | writeb(BIN2BCD(tm->tm_mon + 1), ioaddr + RTC_MONTH); | ||
| 87 | writeb(BIN2BCD(tm->tm_wday) & RTC_DAY_MASK, ioaddr + RTC_DAY); | ||
| 88 | writeb(BIN2BCD(tm->tm_mday), ioaddr + RTC_DATE); | ||
| 89 | writeb(BIN2BCD(tm->tm_hour), ioaddr + RTC_HOURS); | ||
| 90 | writeb(BIN2BCD(tm->tm_min), ioaddr + RTC_MINUTES); | ||
| 91 | writeb(BIN2BCD(tm->tm_sec) & RTC_SECONDS_MASK, ioaddr + RTC_SECONDS); | ||
| 92 | |||
| 93 | /* RTC_CENTURY and RTC_CONTROL share same register */ | ||
| 94 | writeb(RTC_WRITE | (century & RTC_CENTURY_MASK), ioaddr + RTC_CENTURY); | ||
| 95 | writeb(century & RTC_CENTURY_MASK, ioaddr + RTC_CONTROL); | ||
| 96 | return 0; | ||
| 97 | } | ||
| 98 | |||
| 99 | static int ds1553_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
| 100 | { | ||
| 101 | struct platform_device *pdev = to_platform_device(dev); | ||
| 102 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
| 103 | void __iomem *ioaddr = pdata->ioaddr; | ||
| 104 | unsigned int year, month, day, hour, minute, second, week; | ||
| 105 | unsigned int century; | ||
| 106 | |||
| 107 | /* give enough time to update RTC in case of continuous read */ | ||
| 108 | if (pdata->last_jiffies == jiffies) | ||
| 109 | msleep(1); | ||
| 110 | pdata->last_jiffies = jiffies; | ||
| 111 | writeb(RTC_READ, ioaddr + RTC_CONTROL); | ||
| 112 | second = readb(ioaddr + RTC_SECONDS) & RTC_SECONDS_MASK; | ||
| 113 | minute = readb(ioaddr + RTC_MINUTES); | ||
| 114 | hour = readb(ioaddr + RTC_HOURS); | ||
| 115 | day = readb(ioaddr + RTC_DATE); | ||
| 116 | week = readb(ioaddr + RTC_DAY) & RTC_DAY_MASK; | ||
| 117 | month = readb(ioaddr + RTC_MONTH); | ||
| 118 | year = readb(ioaddr + RTC_YEAR); | ||
| 119 | century = readb(ioaddr + RTC_CENTURY) & RTC_CENTURY_MASK; | ||
| 120 | writeb(0, ioaddr + RTC_CONTROL); | ||
| 121 | tm->tm_sec = BCD2BIN(second); | ||
| 122 | tm->tm_min = BCD2BIN(minute); | ||
| 123 | tm->tm_hour = BCD2BIN(hour); | ||
| 124 | tm->tm_mday = BCD2BIN(day); | ||
| 125 | tm->tm_wday = BCD2BIN(week); | ||
| 126 | tm->tm_mon = BCD2BIN(month) - 1; | ||
| 127 | /* year is 1900 + tm->tm_year */ | ||
| 128 | tm->tm_year = BCD2BIN(year) + BCD2BIN(century) * 100 - 1900; | ||
| 129 | |||
| 130 | if (rtc_valid_tm(tm) < 0) { | ||
| 131 | dev_err(dev, "retrieved date/time is not valid.\n"); | ||
| 132 | rtc_time_to_tm(0, tm); | ||
| 133 | } | ||
| 134 | return 0; | ||
| 135 | } | ||
| 136 | |||
| 137 | static void ds1553_rtc_update_alarm(struct rtc_plat_data *pdata) | ||
| 138 | { | ||
| 139 | void __iomem *ioaddr = pdata->ioaddr; | ||
| 140 | unsigned long flags; | ||
| 141 | |||
| 142 | spin_lock_irqsave(&pdata->rtc->irq_lock, flags); | ||
| 143 | writeb(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ? | ||
| 144 | 0x80 : BIN2BCD(pdata->alrm_mday), | ||
| 145 | ioaddr + RTC_DATE_ALARM); | ||
| 146 | writeb(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ? | ||
| 147 | 0x80 : BIN2BCD(pdata->alrm_hour), | ||
| 148 | ioaddr + RTC_HOURS_ALARM); | ||
| 149 | writeb(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ? | ||
| 150 | 0x80 : BIN2BCD(pdata->alrm_min), | ||
| 151 | ioaddr + RTC_MINUTES_ALARM); | ||
| 152 | writeb(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ? | ||
| 153 | 0x80 : BIN2BCD(pdata->alrm_sec), | ||
| 154 | ioaddr + RTC_SECONDS_ALARM); | ||
| 155 | writeb(pdata->irqen ? RTC_INTS_AE : 0, ioaddr + RTC_INTERRUPTS); | ||
| 156 | readb(ioaddr + RTC_FLAGS); /* clear interrupts */ | ||
| 157 | spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags); | ||
| 158 | } | ||
| 159 | |||
| 160 | static int ds1553_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
| 161 | { | ||
| 162 | struct platform_device *pdev = to_platform_device(dev); | ||
| 163 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
| 164 | |||
| 165 | if (pdata->irq < 0) | ||
| 166 | return -EINVAL; | ||
| 167 | pdata->alrm_mday = alrm->time.tm_mday; | ||
| 168 | pdata->alrm_hour = alrm->time.tm_hour; | ||
| 169 | pdata->alrm_min = alrm->time.tm_min; | ||
| 170 | pdata->alrm_sec = alrm->time.tm_sec; | ||
| 171 | if (alrm->enabled) | ||
| 172 | pdata->irqen |= RTC_AF; | ||
| 173 | ds1553_rtc_update_alarm(pdata); | ||
| 174 | return 0; | ||
| 175 | } | ||
| 176 | |||
| 177 | static int ds1553_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
| 178 | { | ||
| 179 | struct platform_device *pdev = to_platform_device(dev); | ||
| 180 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
| 181 | |||
| 182 | if (pdata->irq < 0) | ||
| 183 | return -EINVAL; | ||
| 184 | alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday; | ||
| 185 | alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour; | ||
| 186 | alrm->time.tm_min = pdata->alrm_min < 0 ? 0 : pdata->alrm_min; | ||
| 187 | alrm->time.tm_sec = pdata->alrm_sec < 0 ? 0 : pdata->alrm_sec; | ||
| 188 | alrm->enabled = (pdata->irqen & RTC_AF) ? 1 : 0; | ||
| 189 | return 0; | ||
| 190 | } | ||
| 191 | |||
| 192 | static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id, | ||
| 193 | struct pt_regs *regs) | ||
| 194 | { | ||
| 195 | struct platform_device *pdev = dev_id; | ||
| 196 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
| 197 | void __iomem *ioaddr = pdata->ioaddr; | ||
| 198 | unsigned long events = RTC_IRQF; | ||
| 199 | |||
| 200 | /* read and clear interrupt */ | ||
| 201 | if (!(readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF)) | ||
| 202 | return IRQ_NONE; | ||
| 203 | if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80) | ||
| 204 | events |= RTC_UF; | ||
| 205 | else | ||
| 206 | events |= RTC_AF; | ||
| 207 | rtc_update_irq(&pdata->rtc->class_dev, 1, events); | ||
| 208 | return IRQ_HANDLED; | ||
| 209 | } | ||
| 210 | |||
| 211 | static void ds1553_rtc_release(struct device *dev) | ||
| 212 | { | ||
| 213 | struct platform_device *pdev = to_platform_device(dev); | ||
| 214 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
| 215 | |||
| 216 | if (pdata->irq >= 0) { | ||
| 217 | pdata->irqen = 0; | ||
| 218 | ds1553_rtc_update_alarm(pdata); | ||
| 219 | } | ||
| 220 | } | ||
| 221 | |||
| 222 | static int ds1553_rtc_ioctl(struct device *dev, unsigned int cmd, | ||
| 223 | unsigned long arg) | ||
| 224 | { | ||
| 225 | struct platform_device *pdev = to_platform_device(dev); | ||
| 226 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
| 227 | |||
| 228 | if (pdata->irq < 0) | ||
| 229 | return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ | ||
| 230 | switch (cmd) { | ||
| 231 | case RTC_AIE_OFF: | ||
| 232 | pdata->irqen &= ~RTC_AF; | ||
| 233 | ds1553_rtc_update_alarm(pdata); | ||
| 234 | break; | ||
| 235 | case RTC_AIE_ON: | ||
| 236 | pdata->irqen |= RTC_AF; | ||
| 237 | ds1553_rtc_update_alarm(pdata); | ||
| 238 | break; | ||
| 239 | case RTC_UIE_OFF: | ||
| 240 | pdata->irqen &= ~RTC_UF; | ||
| 241 | ds1553_rtc_update_alarm(pdata); | ||
| 242 | break; | ||
| 243 | case RTC_UIE_ON: | ||
| 244 | pdata->irqen |= RTC_UF; | ||
| 245 | ds1553_rtc_update_alarm(pdata); | ||
| 246 | break; | ||
| 247 | default: | ||
| 248 | return -ENOIOCTLCMD; | ||
| 249 | } | ||
| 250 | return 0; | ||
| 251 | } | ||
| 252 | |||
| 253 | static struct rtc_class_ops ds1553_rtc_ops = { | ||
| 254 | .read_time = ds1553_rtc_read_time, | ||
| 255 | .set_time = ds1553_rtc_set_time, | ||
| 256 | .read_alarm = ds1553_rtc_read_alarm, | ||
| 257 | .set_alarm = ds1553_rtc_set_alarm, | ||
| 258 | .release = ds1553_rtc_release, | ||
| 259 | .ioctl = ds1553_rtc_ioctl, | ||
| 260 | }; | ||
| 261 | |||
| 262 | static ssize_t ds1553_nvram_read(struct kobject *kobj, char *buf, | ||
| 263 | loff_t pos, size_t size) | ||
| 264 | { | ||
| 265 | struct platform_device *pdev = | ||
| 266 | to_platform_device(container_of(kobj, struct device, kobj)); | ||
| 267 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
| 268 | void __iomem *ioaddr = pdata->ioaddr; | ||
| 269 | ssize_t count; | ||
| 270 | |||
| 271 | for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--) | ||
| 272 | *buf++ = readb(ioaddr + pos++); | ||
| 273 | return count; | ||
| 274 | } | ||
| 275 | |||
| 276 | static ssize_t ds1553_nvram_write(struct kobject *kobj, char *buf, | ||
| 277 | loff_t pos, size_t size) | ||
| 278 | { | ||
| 279 | struct platform_device *pdev = | ||
| 280 | to_platform_device(container_of(kobj, struct device, kobj)); | ||
| 281 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
| 282 | void __iomem *ioaddr = pdata->ioaddr; | ||
| 283 | ssize_t count; | ||
| 284 | |||
| 285 | for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--) | ||
| 286 | writeb(*buf++, ioaddr + pos++); | ||
| 287 | return count; | ||
| 288 | } | ||
| 289 | |||
| 290 | static struct bin_attribute ds1553_nvram_attr = { | ||
| 291 | .attr = { | ||
| 292 | .name = "nvram", | ||
| 293 | .mode = S_IRUGO | S_IWUGO, | ||
| 294 | .owner = THIS_MODULE, | ||
| 295 | }, | ||
| 296 | .size = RTC_OFFSET, | ||
| 297 | .read = ds1553_nvram_read, | ||
| 298 | .write = ds1553_nvram_write, | ||
| 299 | }; | ||
| 300 | |||
| 301 | static int __init ds1553_rtc_probe(struct platform_device *pdev) | ||
| 302 | { | ||
| 303 | struct rtc_device *rtc; | ||
| 304 | struct resource *res; | ||
| 305 | unsigned int cen, sec; | ||
| 306 | struct rtc_plat_data *pdata = NULL; | ||
| 307 | void __iomem *ioaddr = NULL; | ||
| 308 | int ret = 0; | ||
| 309 | |||
| 310 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 311 | if (!res) | ||
| 312 | return -ENODEV; | ||
| 313 | pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); | ||
| 314 | if (!pdata) | ||
| 315 | return -ENOMEM; | ||
| 316 | pdata->irq = -1; | ||
| 317 | if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) { | ||
| 318 | ret = -EBUSY; | ||
| 319 | goto out; | ||
| 320 | } | ||
| 321 | pdata->baseaddr = res->start; | ||
| 322 | ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE); | ||
| 323 | if (!ioaddr) { | ||
| 324 | ret = -ENOMEM; | ||
| 325 | goto out; | ||
| 326 | } | ||
| 327 | pdata->ioaddr = ioaddr; | ||
| 328 | pdata->irq = platform_get_irq(pdev, 0); | ||
| 329 | |||
| 330 | /* turn RTC on if it was not on */ | ||
| 331 | sec = readb(ioaddr + RTC_SECONDS); | ||
| 332 | if (sec & RTC_STOP) { | ||
| 333 | sec &= RTC_SECONDS_MASK; | ||
| 334 | cen = readb(ioaddr + RTC_CENTURY) & RTC_CENTURY_MASK; | ||
| 335 | writeb(RTC_WRITE, ioaddr + RTC_CONTROL); | ||
| 336 | writeb(sec, ioaddr + RTC_SECONDS); | ||
| 337 | writeb(cen & RTC_CENTURY_MASK, ioaddr + RTC_CONTROL); | ||
| 338 | } | ||
| 339 | if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_BLF) | ||
| 340 | dev_warn(&pdev->dev, "voltage-low detected.\n"); | ||
| 341 | |||
| 342 | if (pdata->irq >= 0) { | ||
| 343 | writeb(0, ioaddr + RTC_INTERRUPTS); | ||
| 344 | if (request_irq(pdata->irq, ds1553_rtc_interrupt, SA_SHIRQ, | ||
| 345 | pdev->name, pdev) < 0) { | ||
| 346 | dev_warn(&pdev->dev, "interrupt not available.\n"); | ||
| 347 | pdata->irq = -1; | ||
| 348 | } | ||
| 349 | } | ||
| 350 | |||
| 351 | rtc = rtc_device_register(pdev->name, &pdev->dev, | ||
| 352 | &ds1553_rtc_ops, THIS_MODULE); | ||
| 353 | if (IS_ERR(rtc)) { | ||
| 354 | ret = PTR_ERR(rtc); | ||
| 355 | goto out; | ||
| 356 | } | ||
| 357 | pdata->rtc = rtc; | ||
| 358 | pdata->last_jiffies = jiffies; | ||
| 359 | platform_set_drvdata(pdev, pdata); | ||
| 360 | sysfs_create_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr); | ||
| 361 | return 0; | ||
| 362 | out: | ||
| 363 | if (pdata->irq >= 0) | ||
| 364 | free_irq(pdata->irq, pdev); | ||
| 365 | if (ioaddr) | ||
| 366 | iounmap(ioaddr); | ||
| 367 | if (pdata->baseaddr) | ||
| 368 | release_mem_region(pdata->baseaddr, RTC_REG_SIZE); | ||
| 369 | kfree(pdata); | ||
| 370 | return ret; | ||
| 371 | } | ||
| 372 | |||
| 373 | static int __devexit ds1553_rtc_remove(struct platform_device *pdev) | ||
| 374 | { | ||
| 375 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
| 376 | |||
| 377 | sysfs_remove_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr); | ||
| 378 | rtc_device_unregister(pdata->rtc); | ||
| 379 | if (pdata->irq >= 0) { | ||
| 380 | writeb(0, pdata->ioaddr + RTC_INTERRUPTS); | ||
| 381 | free_irq(pdata->irq, pdev); | ||
| 382 | } | ||
| 383 | iounmap(pdata->ioaddr); | ||
| 384 | release_mem_region(pdata->baseaddr, RTC_REG_SIZE); | ||
| 385 | kfree(pdata); | ||
| 386 | return 0; | ||
| 387 | } | ||
| 388 | |||
| 389 | static struct platform_driver ds1553_rtc_driver = { | ||
| 390 | .probe = ds1553_rtc_probe, | ||
| 391 | .remove = __devexit_p(ds1553_rtc_remove), | ||
| 392 | .driver = { | ||
| 393 | .name = "ds1553", | ||
| 394 | .owner = THIS_MODULE, | ||
| 395 | }, | ||
| 396 | }; | ||
| 397 | |||
| 398 | static __init int ds1553_init(void) | ||
| 399 | { | ||
| 400 | return platform_driver_register(&ds1553_rtc_driver); | ||
| 401 | } | ||
| 402 | |||
| 403 | static __exit void ds1553_exit(void) | ||
| 404 | { | ||
| 405 | return platform_driver_unregister(&ds1553_rtc_driver); | ||
| 406 | } | ||
| 407 | |||
| 408 | module_init(ds1553_init); | ||
| 409 | module_exit(ds1553_exit); | ||
| 410 | |||
| 411 | MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>"); | ||
| 412 | MODULE_DESCRIPTION("Dallas DS1553 RTC driver"); | ||
| 413 | MODULE_LICENSE("GPL"); | ||
| 414 | MODULE_VERSION(DRV_VERSION); | ||
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c new file mode 100644 index 000000000000..8e47e5a06d2a --- /dev/null +++ b/drivers/rtc/rtc-ds1742.c | |||
| @@ -0,0 +1,259 @@ | |||
| 1 | /* | ||
| 2 | * An rtc driver for the Dallas DS1742 | ||
| 3 | * | ||
| 4 | * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/bcd.h> | ||
| 12 | #include <linux/init.h> | ||
| 13 | #include <linux/kernel.h> | ||
| 14 | #include <linux/delay.h> | ||
| 15 | #include <linux/jiffies.h> | ||
| 16 | #include <linux/rtc.h> | ||
| 17 | #include <linux/platform_device.h> | ||
| 18 | #include <linux/io.h> | ||
| 19 | |||
| 20 | #define DRV_VERSION "0.1" | ||
| 21 | |||
| 22 | #define RTC_REG_SIZE 0x800 | ||
| 23 | #define RTC_OFFSET 0x7f8 | ||
| 24 | |||
| 25 | #define RTC_CONTROL (RTC_OFFSET + 0) | ||
| 26 | #define RTC_CENTURY (RTC_OFFSET + 0) | ||
| 27 | #define RTC_SECONDS (RTC_OFFSET + 1) | ||
| 28 | #define RTC_MINUTES (RTC_OFFSET + 2) | ||
| 29 | #define RTC_HOURS (RTC_OFFSET + 3) | ||
| 30 | #define RTC_DAY (RTC_OFFSET + 4) | ||
| 31 | #define RTC_DATE (RTC_OFFSET + 5) | ||
| 32 | #define RTC_MONTH (RTC_OFFSET + 6) | ||
| 33 | #define RTC_YEAR (RTC_OFFSET + 7) | ||
| 34 | |||
| 35 | #define RTC_CENTURY_MASK 0x3f | ||
| 36 | #define RTC_SECONDS_MASK 0x7f | ||
| 37 | #define RTC_DAY_MASK 0x07 | ||
| 38 | |||
| 39 | /* Bits in the Control/Century register */ | ||
| 40 | #define RTC_WRITE 0x80 | ||
| 41 | #define RTC_READ 0x40 | ||
| 42 | |||
| 43 | /* Bits in the Seconds register */ | ||
| 44 | #define RTC_STOP 0x80 | ||
| 45 | |||
| 46 | /* Bits in the Day register */ | ||
| 47 | #define RTC_BATT_FLAG 0x80 | ||
| 48 | |||
| 49 | struct rtc_plat_data { | ||
| 50 | struct rtc_device *rtc; | ||
| 51 | void __iomem *ioaddr; | ||
| 52 | unsigned long baseaddr; | ||
| 53 | unsigned long last_jiffies; | ||
| 54 | }; | ||
| 55 | |||
| 56 | static int ds1742_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
| 57 | { | ||
| 58 | struct platform_device *pdev = to_platform_device(dev); | ||
| 59 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
| 60 | void __iomem *ioaddr = pdata->ioaddr; | ||
| 61 | u8 century; | ||
| 62 | |||
| 63 | century = BIN2BCD((tm->tm_year + 1900) / 100); | ||
| 64 | |||
| 65 | writeb(RTC_WRITE, ioaddr + RTC_CONTROL); | ||
| 66 | |||
| 67 | writeb(BIN2BCD(tm->tm_year % 100), ioaddr + RTC_YEAR); | ||
| 68 | writeb(BIN2BCD(tm->tm_mon + 1), ioaddr + RTC_MONTH); | ||
| 69 | writeb(BIN2BCD(tm->tm_wday) & RTC_DAY_MASK, ioaddr + RTC_DAY); | ||
| 70 | writeb(BIN2BCD(tm->tm_mday), ioaddr + RTC_DATE); | ||
| 71 | writeb(BIN2BCD(tm->tm_hour), ioaddr + RTC_HOURS); | ||
| 72 | writeb(BIN2BCD(tm->tm_min), ioaddr + RTC_MINUTES); | ||
| 73 | writeb(BIN2BCD(tm->tm_sec) & RTC_SECONDS_MASK, ioaddr + RTC_SECONDS); | ||
| 74 | |||
| 75 | /* RTC_CENTURY and RTC_CONTROL share same register */ | ||
| 76 | writeb(RTC_WRITE | (century & RTC_CENTURY_MASK), ioaddr + RTC_CENTURY); | ||
| 77 | writeb(century & RTC_CENTURY_MASK, ioaddr + RTC_CONTROL); | ||
| 78 | return 0; | ||
| 79 | } | ||
| 80 | |||
| 81 | static int ds1742_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
| 82 | { | ||
| 83 | struct platform_device *pdev = to_platform_device(dev); | ||
| 84 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
| 85 | void __iomem *ioaddr = pdata->ioaddr; | ||
| 86 | unsigned int year, month, day, hour, minute, second, week; | ||
| 87 | unsigned int century; | ||
| 88 | |||
| 89 | /* give enough time to update RTC in case of continuous read */ | ||
| 90 | if (pdata->last_jiffies == jiffies) | ||
| 91 | msleep(1); | ||
| 92 | pdata->last_jiffies = jiffies; | ||
| 93 | writeb(RTC_READ, ioaddr + RTC_CONTROL); | ||
| 94 | second = readb(ioaddr + RTC_SECONDS) & RTC_SECONDS_MASK; | ||
| 95 | minute = readb(ioaddr + RTC_MINUTES); | ||
| 96 | hour = readb(ioaddr + RTC_HOURS); | ||
| 97 | day = readb(ioaddr + RTC_DATE); | ||
| 98 | week = readb(ioaddr + RTC_DAY) & RTC_DAY_MASK; | ||
| 99 | month = readb(ioaddr + RTC_MONTH); | ||
| 100 | year = readb(ioaddr + RTC_YEAR); | ||
| 101 | century = readb(ioaddr + RTC_CENTURY) & RTC_CENTURY_MASK; | ||
| 102 | writeb(0, ioaddr + RTC_CONTROL); | ||
| 103 | tm->tm_sec = BCD2BIN(second); | ||
| 104 | tm->tm_min = BCD2BIN(minute); | ||
| 105 | tm->tm_hour = BCD2BIN(hour); | ||
| 106 | tm->tm_mday = BCD2BIN(day); | ||
| 107 | tm->tm_wday = BCD2BIN(week); | ||
| 108 | tm->tm_mon = BCD2BIN(month) - 1; | ||
| 109 | /* year is 1900 + tm->tm_year */ | ||
| 110 | tm->tm_year = BCD2BIN(year) + BCD2BIN(century) * 100 - 1900; | ||
| 111 | |||
| 112 | if (rtc_valid_tm(tm) < 0) { | ||
| 113 | dev_err(dev, "retrieved date/time is not valid.\n"); | ||
| 114 | rtc_time_to_tm(0, tm); | ||
| 115 | } | ||
| 116 | return 0; | ||
| 117 | } | ||
| 118 | |||
| 119 | static struct rtc_class_ops ds1742_rtc_ops = { | ||
| 120 | .read_time = ds1742_rtc_read_time, | ||
| 121 | .set_time = ds1742_rtc_set_time, | ||
| 122 | }; | ||
| 123 | |||
| 124 | static ssize_t ds1742_nvram_read(struct kobject *kobj, char *buf, | ||
| 125 | loff_t pos, size_t size) | ||
| 126 | { | ||
| 127 | struct platform_device *pdev = | ||
| 128 | to_platform_device(container_of(kobj, struct device, kobj)); | ||
| 129 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
| 130 | void __iomem *ioaddr = pdata->ioaddr; | ||
| 131 | ssize_t count; | ||
| 132 | |||
| 133 | for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--) | ||
| 134 | *buf++ = readb(ioaddr + pos++); | ||
| 135 | return count; | ||
| 136 | } | ||
| 137 | |||
| 138 | static ssize_t ds1742_nvram_write(struct kobject *kobj, char *buf, | ||
| 139 | loff_t pos, size_t size) | ||
| 140 | { | ||
| 141 | struct platform_device *pdev = | ||
| 142 | to_platform_device(container_of(kobj, struct device, kobj)); | ||
| 143 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
| 144 | void __iomem *ioaddr = pdata->ioaddr; | ||
| 145 | ssize_t count; | ||
| 146 | |||
| 147 | for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--) | ||
| 148 | writeb(*buf++, ioaddr + pos++); | ||
| 149 | return count; | ||
| 150 | } | ||
| 151 | |||
| 152 | static struct bin_attribute ds1742_nvram_attr = { | ||
| 153 | .attr = { | ||
| 154 | .name = "nvram", | ||
| 155 | .mode = S_IRUGO | S_IWUGO, | ||
| 156 | .owner = THIS_MODULE, | ||
| 157 | }, | ||
| 158 | .size = RTC_OFFSET, | ||
| 159 | .read = ds1742_nvram_read, | ||
| 160 | .write = ds1742_nvram_write, | ||
| 161 | }; | ||
| 162 | |||
| 163 | static int __init ds1742_rtc_probe(struct platform_device *pdev) | ||
| 164 | { | ||
| 165 | struct rtc_device *rtc; | ||
| 166 | struct resource *res; | ||
| 167 | unsigned int cen, sec; | ||
| 168 | struct rtc_plat_data *pdata = NULL; | ||
| 169 | void __iomem *ioaddr = NULL; | ||
| 170 | int ret = 0; | ||
| 171 | |||
| 172 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 173 | if (!res) | ||
| 174 | return -ENODEV; | ||
| 175 | pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); | ||
| 176 | if (!pdata) | ||
| 177 | return -ENOMEM; | ||
| 178 | if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) { | ||
| 179 | ret = -EBUSY; | ||
| 180 | goto out; | ||
| 181 | } | ||
| 182 | pdata->baseaddr = res->start; | ||
| 183 | ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE); | ||
| 184 | if (!ioaddr) { | ||
| 185 | ret = -ENOMEM; | ||
| 186 | goto out; | ||
| 187 | } | ||
| 188 | pdata->ioaddr = ioaddr; | ||
| 189 | |||
| 190 | /* turn RTC on if it was not on */ | ||
| 191 | sec = readb(ioaddr + RTC_SECONDS); | ||
| 192 | if (sec & RTC_STOP) { | ||
| 193 | sec &= RTC_SECONDS_MASK; | ||
| 194 | cen = readb(ioaddr + RTC_CENTURY) & RTC_CENTURY_MASK; | ||
| 195 | writeb(RTC_WRITE, ioaddr + RTC_CONTROL); | ||
| 196 | writeb(sec, ioaddr + RTC_SECONDS); | ||
| 197 | writeb(cen & RTC_CENTURY_MASK, ioaddr + RTC_CONTROL); | ||
| 198 | } | ||
| 199 | if (readb(ioaddr + RTC_DAY) & RTC_BATT_FLAG) | ||
| 200 | dev_warn(&pdev->dev, "voltage-low detected.\n"); | ||
| 201 | |||
| 202 | rtc = rtc_device_register(pdev->name, &pdev->dev, | ||
| 203 | &ds1742_rtc_ops, THIS_MODULE); | ||
| 204 | if (IS_ERR(rtc)) { | ||
| 205 | ret = PTR_ERR(rtc); | ||
| 206 | goto out; | ||
| 207 | } | ||
| 208 | pdata->rtc = rtc; | ||
| 209 | pdata->last_jiffies = jiffies; | ||
| 210 | platform_set_drvdata(pdev, pdata); | ||
| 211 | sysfs_create_bin_file(&pdev->dev.kobj, &ds1742_nvram_attr); | ||
| 212 | return 0; | ||
| 213 | out: | ||
| 214 | if (ioaddr) | ||
| 215 | iounmap(ioaddr); | ||
| 216 | if (pdata->baseaddr) | ||
| 217 | release_mem_region(pdata->baseaddr, RTC_REG_SIZE); | ||
| 218 | kfree(pdata); | ||
| 219 | return ret; | ||
| 220 | } | ||
| 221 | |||
| 222 | static int __devexit ds1742_rtc_remove(struct platform_device *pdev) | ||
| 223 | { | ||
| 224 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
| 225 | |||
| 226 | sysfs_remove_bin_file(&pdev->dev.kobj, &ds1742_nvram_attr); | ||
| 227 | rtc_device_unregister(pdata->rtc); | ||
| 228 | iounmap(pdata->ioaddr); | ||
| 229 | release_mem_region(pdata->baseaddr, RTC_REG_SIZE); | ||
| 230 | kfree(pdata); | ||
| 231 | return 0; | ||
| 232 | } | ||
| 233 | |||
| 234 | static struct platform_driver ds1742_rtc_driver = { | ||
| 235 | .probe = ds1742_rtc_probe, | ||
| 236 | .remove = __devexit_p(ds1742_rtc_remove), | ||
| 237 | .driver = { | ||
| 238 | .name = "ds1742", | ||
| 239 | .owner = THIS_MODULE, | ||
| 240 | }, | ||
| 241 | }; | ||
| 242 | |||
| 243 | static __init int ds1742_init(void) | ||
| 244 | { | ||
| 245 | return platform_driver_register(&ds1742_rtc_driver); | ||
| 246 | } | ||
| 247 | |||
| 248 | static __exit void ds1742_exit(void) | ||
| 249 | { | ||
| 250 | return platform_driver_unregister(&ds1742_rtc_driver); | ||
| 251 | } | ||
| 252 | |||
| 253 | module_init(ds1742_init); | ||
| 254 | module_exit(ds1742_exit); | ||
| 255 | |||
| 256 | MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>"); | ||
| 257 | MODULE_DESCRIPTION("Dallas DS1742 RTC driver"); | ||
| 258 | MODULE_LICENSE("GPL"); | ||
| 259 | MODULE_VERSION(DRV_VERSION); | ||
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c index cfedc1d28ee1..9812120f3a7c 100644 --- a/drivers/rtc/rtc-lib.c +++ b/drivers/rtc/rtc-lib.c | |||
| @@ -18,9 +18,19 @@ static const unsigned char rtc_days_in_month[] = { | |||
| 18 | 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 | 18 | 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 |
| 19 | }; | 19 | }; |
| 20 | 20 | ||
| 21 | static const unsigned short rtc_ydays[2][13] = { | ||
| 22 | /* Normal years */ | ||
| 23 | { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, | ||
| 24 | /* Leap years */ | ||
| 25 | { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } | ||
| 26 | }; | ||
| 27 | |||
| 21 | #define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400) | 28 | #define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400) |
| 22 | #define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400)) | 29 | #define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400)) |
| 23 | 30 | ||
| 31 | /* | ||
| 32 | * The number of days in the month. | ||
| 33 | */ | ||
| 24 | int rtc_month_days(unsigned int month, unsigned int year) | 34 | int rtc_month_days(unsigned int month, unsigned int year) |
| 25 | { | 35 | { |
| 26 | return rtc_days_in_month[month] + (LEAP_YEAR(year) && month == 1); | 36 | return rtc_days_in_month[month] + (LEAP_YEAR(year) && month == 1); |
| @@ -28,6 +38,15 @@ int rtc_month_days(unsigned int month, unsigned int year) | |||
| 28 | EXPORT_SYMBOL(rtc_month_days); | 38 | EXPORT_SYMBOL(rtc_month_days); |
| 29 | 39 | ||
| 30 | /* | 40 | /* |
| 41 | * The number of days since January 1. (0 to 365) | ||
| 42 | */ | ||
| 43 | int rtc_year_days(unsigned int day, unsigned int month, unsigned int year) | ||
| 44 | { | ||
| 45 | return rtc_ydays[LEAP_YEAR(year)][month] + day-1; | ||
| 46 | } | ||
| 47 | EXPORT_SYMBOL(rtc_year_days); | ||
| 48 | |||
| 49 | /* | ||
| 31 | * Convert seconds since 01-01-1970 00:00:00 to Gregorian date. | 50 | * Convert seconds since 01-01-1970 00:00:00 to Gregorian date. |
| 32 | */ | 51 | */ |
| 33 | void rtc_time_to_tm(unsigned long time, struct rtc_time *tm) | 52 | void rtc_time_to_tm(unsigned long time, struct rtc_time *tm) |
diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c new file mode 100644 index 000000000000..2c9739562b5c --- /dev/null +++ b/drivers/rtc/rtc-max6902.c | |||
| @@ -0,0 +1,286 @@ | |||
| 1 | /* drivers/char/max6902.c | ||
| 2 | * | ||
| 3 | * Copyright (C) 2006 8D Technologies inc. | ||
| 4 | * Copyright (C) 2004 Compulab Ltd. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * Driver for MAX6902 spi RTC | ||
| 11 | * | ||
| 12 | * Changelog: | ||
| 13 | * | ||
| 14 | * 24-May-2006: Raphael Assenat <raph@8d.com> | ||
| 15 | * - Major rework | ||
| 16 | * Converted to rtc_device and uses the SPI layer. | ||
| 17 | * | ||
| 18 | * ??-???-2005: Someone at Compulab | ||
| 19 | * - Initial driver creation. | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <linux/config.h> | ||
| 23 | #include <linux/module.h> | ||
| 24 | #include <linux/version.h> | ||
| 25 | |||
| 26 | #include <linux/kernel.h> | ||
| 27 | #include <linux/platform_device.h> | ||
| 28 | #include <linux/init.h> | ||
| 29 | #include <linux/rtc.h> | ||
| 30 | #include <linux/spi/spi.h> | ||
| 31 | #include <linux/bcd.h> | ||
| 32 | #include <linux/delay.h> | ||
| 33 | |||
| 34 | #define MAX6902_REG_SECONDS 0x01 | ||
| 35 | #define MAX6902_REG_MINUTES 0x03 | ||
| 36 | #define MAX6902_REG_HOURS 0x05 | ||
| 37 | #define MAX6902_REG_DATE 0x07 | ||
| 38 | #define MAX6902_REG_MONTH 0x09 | ||
| 39 | #define MAX6902_REG_DAY 0x0B | ||
| 40 | #define MAX6902_REG_YEAR 0x0D | ||
| 41 | #define MAX6902_REG_CONTROL 0x0F | ||
| 42 | #define MAX6902_REG_CENTURY 0x13 | ||
| 43 | |||
| 44 | #undef MAX6902_DEBUG | ||
| 45 | |||
| 46 | struct max6902 { | ||
| 47 | struct rtc_device *rtc; | ||
| 48 | u8 buf[9]; /* Burst read cmd + 8 registers */ | ||
| 49 | u8 tx_buf[2]; | ||
| 50 | u8 rx_buf[2]; | ||
| 51 | }; | ||
| 52 | |||
| 53 | static void max6902_set_reg(struct device *dev, unsigned char address, | ||
| 54 | unsigned char data) | ||
| 55 | { | ||
| 56 | struct spi_device *spi = to_spi_device(dev); | ||
| 57 | unsigned char buf[2]; | ||
| 58 | |||
| 59 | /* MSB must be '0' to write */ | ||
| 60 | buf[0] = address & 0x7f; | ||
| 61 | buf[1] = data; | ||
| 62 | |||
| 63 | spi_write(spi, buf, 2); | ||
| 64 | } | ||
| 65 | |||
| 66 | static int max6902_get_reg(struct device *dev, unsigned char address, | ||
| 67 | unsigned char *data) | ||
| 68 | { | ||
| 69 | struct spi_device *spi = to_spi_device(dev); | ||
| 70 | struct max6902 *chip = dev_get_drvdata(dev); | ||
| 71 | struct spi_message message; | ||
| 72 | struct spi_transfer xfer; | ||
| 73 | int status; | ||
| 74 | |||
| 75 | if (!data) | ||
| 76 | return -EINVAL; | ||
| 77 | |||
| 78 | /* Build our spi message */ | ||
| 79 | spi_message_init(&message); | ||
| 80 | memset(&xfer, 0, sizeof(xfer)); | ||
| 81 | xfer.len = 2; | ||
| 82 | /* Can tx_buf and rx_buf be equal? The doc in spi.h is not sure... */ | ||
| 83 | xfer.tx_buf = chip->tx_buf; | ||
| 84 | xfer.rx_buf = chip->rx_buf; | ||
| 85 | |||
| 86 | /* Set MSB to indicate read */ | ||
| 87 | chip->tx_buf[0] = address | 0x80; | ||
| 88 | |||
| 89 | spi_message_add_tail(&xfer, &message); | ||
| 90 | |||
| 91 | /* do the i/o */ | ||
| 92 | status = spi_sync(spi, &message); | ||
| 93 | if (status == 0) | ||
| 94 | status = message.status; | ||
| 95 | else | ||
| 96 | return status; | ||
| 97 | |||
| 98 | *data = chip->rx_buf[1]; | ||
| 99 | |||
| 100 | return status; | ||
| 101 | } | ||
| 102 | |||
| 103 | static int max6902_get_datetime(struct device *dev, struct rtc_time *dt) | ||
| 104 | { | ||
| 105 | unsigned char tmp; | ||
| 106 | int century; | ||
| 107 | int err; | ||
| 108 | struct spi_device *spi = to_spi_device(dev); | ||
| 109 | struct max6902 *chip = dev_get_drvdata(dev); | ||
| 110 | struct spi_message message; | ||
| 111 | struct spi_transfer xfer; | ||
| 112 | int status; | ||
| 113 | |||
| 114 | err = max6902_get_reg(dev, MAX6902_REG_CENTURY, &tmp); | ||
| 115 | if (err) | ||
| 116 | return err; | ||
| 117 | |||
| 118 | /* build the message */ | ||
| 119 | spi_message_init(&message); | ||
| 120 | memset(&xfer, 0, sizeof(xfer)); | ||
| 121 | xfer.len = 1 + 7; /* Burst read command + 7 registers */ | ||
| 122 | xfer.tx_buf = chip->buf; | ||
| 123 | xfer.rx_buf = chip->buf; | ||
| 124 | chip->buf[0] = 0xbf; /* Burst read */ | ||
| 125 | spi_message_add_tail(&xfer, &message); | ||
| 126 | |||
| 127 | /* do the i/o */ | ||
| 128 | status = spi_sync(spi, &message); | ||
| 129 | if (status == 0) | ||
| 130 | status = message.status; | ||
| 131 | else | ||
| 132 | return status; | ||
| 133 | |||
| 134 | /* The chip sends data in this order: | ||
| 135 | * Seconds, Minutes, Hours, Date, Month, Day, Year */ | ||
| 136 | dt->tm_sec = BCD2BIN(chip->buf[1]); | ||
| 137 | dt->tm_min = BCD2BIN(chip->buf[2]); | ||
| 138 | dt->tm_hour = BCD2BIN(chip->buf[3]); | ||
| 139 | dt->tm_mday = BCD2BIN(chip->buf[4]); | ||
| 140 | dt->tm_mon = BCD2BIN(chip->buf[5] - 1); | ||
| 141 | dt->tm_wday = BCD2BIN(chip->buf[6]); | ||
| 142 | dt->tm_year = BCD2BIN(chip->buf[7]); | ||
| 143 | |||
| 144 | century = BCD2BIN(tmp) * 100; | ||
| 145 | |||
| 146 | dt->tm_year += century; | ||
| 147 | dt->tm_year -= 1900; | ||
| 148 | |||
| 149 | #ifdef MAX6902_DEBUG | ||
| 150 | printk("\n%s : Read RTC values\n",__FUNCTION__); | ||
| 151 | printk("tm_hour: %i\n",dt->tm_hour); | ||
| 152 | printk("tm_min : %i\n",dt->tm_min); | ||
| 153 | printk("tm_sec : %i\n",dt->tm_sec); | ||
| 154 | printk("tm_year: %i\n",dt->tm_year); | ||
| 155 | printk("tm_mon : %i\n",dt->tm_mon); | ||
| 156 | printk("tm_mday: %i\n",dt->tm_mday); | ||
| 157 | printk("tm_wday: %i\n",dt->tm_wday); | ||
| 158 | #endif | ||
| 159 | |||
| 160 | return 0; | ||
| 161 | } | ||
| 162 | |||
| 163 | static int max6902_set_datetime(struct device *dev, struct rtc_time *dt) | ||
| 164 | { | ||
| 165 | dt->tm_year = dt->tm_year+1900; | ||
| 166 | |||
| 167 | #ifdef MAX6902_DEBUG | ||
| 168 | printk("\n%s : Setting RTC values\n",__FUNCTION__); | ||
| 169 | printk("tm_sec : %i\n",dt->tm_sec); | ||
| 170 | printk("tm_min : %i\n",dt->tm_min); | ||
| 171 | printk("tm_hour: %i\n",dt->tm_hour); | ||
| 172 | printk("tm_mday: %i\n",dt->tm_mday); | ||
| 173 | printk("tm_wday: %i\n",dt->tm_wday); | ||
| 174 | printk("tm_year: %i\n",dt->tm_year); | ||
| 175 | #endif | ||
| 176 | |||
| 177 | /* Remove write protection */ | ||
| 178 | max6902_set_reg(dev, 0xF, 0); | ||
| 179 | |||
| 180 | max6902_set_reg(dev, 0x01, BIN2BCD(dt->tm_sec)); | ||
| 181 | max6902_set_reg(dev, 0x03, BIN2BCD(dt->tm_min)); | ||
| 182 | max6902_set_reg(dev, 0x05, BIN2BCD(dt->tm_hour)); | ||
| 183 | |||
| 184 | max6902_set_reg(dev, 0x07, BIN2BCD(dt->tm_mday)); | ||
| 185 | max6902_set_reg(dev, 0x09, BIN2BCD(dt->tm_mon+1)); | ||
| 186 | max6902_set_reg(dev, 0x0B, BIN2BCD(dt->tm_wday)); | ||
| 187 | max6902_set_reg(dev, 0x0D, BIN2BCD(dt->tm_year%100)); | ||
| 188 | max6902_set_reg(dev, 0x13, BIN2BCD(dt->tm_year/100)); | ||
| 189 | |||
| 190 | /* Compulab used a delay here. However, the datasheet | ||
| 191 | * does not mention a delay being required anywhere... */ | ||
| 192 | /* delay(2000); */ | ||
| 193 | |||
| 194 | /* Write protect */ | ||
| 195 | max6902_set_reg(dev, 0xF, 0x80); | ||
| 196 | |||
| 197 | return 0; | ||
| 198 | } | ||
| 199 | |||
| 200 | static int max6902_read_time(struct device *dev, struct rtc_time *tm) | ||
| 201 | { | ||
| 202 | return max6902_get_datetime(dev, tm); | ||
| 203 | } | ||
| 204 | |||
| 205 | static int max6902_set_time(struct device *dev, struct rtc_time *tm) | ||
| 206 | { | ||
| 207 | return max6902_set_datetime(dev, tm); | ||
| 208 | } | ||
| 209 | |||
| 210 | static struct rtc_class_ops max6902_rtc_ops = { | ||
| 211 | .read_time = max6902_read_time, | ||
| 212 | .set_time = max6902_set_time, | ||
| 213 | }; | ||
| 214 | |||
| 215 | static int __devinit max6902_probe(struct spi_device *spi) | ||
| 216 | { | ||
| 217 | struct rtc_device *rtc; | ||
| 218 | unsigned char tmp; | ||
| 219 | struct max6902 *chip; | ||
| 220 | int res; | ||
| 221 | |||
| 222 | rtc = rtc_device_register("max6902", | ||
| 223 | &spi->dev, &max6902_rtc_ops, THIS_MODULE); | ||
| 224 | if (IS_ERR(rtc)) | ||
| 225 | return PTR_ERR(rtc); | ||
| 226 | |||
| 227 | spi->mode = SPI_MODE_3; | ||
| 228 | spi->bits_per_word = 8; | ||
| 229 | spi_setup(spi); | ||
| 230 | |||
| 231 | chip = kzalloc(sizeof *chip, GFP_KERNEL); | ||
| 232 | if (!chip) { | ||
| 233 | rtc_device_unregister(rtc); | ||
| 234 | return -ENOMEM; | ||
| 235 | } | ||
| 236 | chip->rtc = rtc; | ||
| 237 | dev_set_drvdata(&spi->dev, chip); | ||
| 238 | |||
| 239 | res = max6902_get_reg(&spi->dev, MAX6902_REG_SECONDS, &tmp); | ||
| 240 | if (res) { | ||
| 241 | rtc_device_unregister(rtc); | ||
| 242 | return res; | ||
| 243 | } | ||
| 244 | |||
| 245 | return 0; | ||
| 246 | } | ||
| 247 | |||
| 248 | static int __devexit max6902_remove(struct spi_device *spi) | ||
| 249 | { | ||
| 250 | struct max6902 *chip = platform_get_drvdata(spi); | ||
| 251 | struct rtc_device *rtc = chip->rtc; | ||
| 252 | |||
| 253 | if (rtc) | ||
| 254 | rtc_device_unregister(rtc); | ||
| 255 | |||
| 256 | kfree(chip); | ||
| 257 | |||
| 258 | return 0; | ||
| 259 | } | ||
| 260 | |||
| 261 | static struct spi_driver max6902_driver = { | ||
| 262 | .driver = { | ||
| 263 | .name = "max6902", | ||
| 264 | .bus = &spi_bus_type, | ||
| 265 | .owner = THIS_MODULE, | ||
| 266 | }, | ||
| 267 | .probe = max6902_probe, | ||
| 268 | .remove = __devexit_p(max6902_remove), | ||
| 269 | }; | ||
| 270 | |||
| 271 | static __init int max6902_init(void) | ||
| 272 | { | ||
| 273 | printk("max6902 spi driver\n"); | ||
| 274 | return spi_register_driver(&max6902_driver); | ||
| 275 | } | ||
| 276 | module_init(max6902_init); | ||
| 277 | |||
| 278 | static __exit void max6902_exit(void) | ||
| 279 | { | ||
| 280 | spi_unregister_driver(&max6902_driver); | ||
| 281 | } | ||
| 282 | module_exit(max6902_exit); | ||
| 283 | |||
| 284 | MODULE_DESCRIPTION ("max6902 spi RTC driver"); | ||
| 285 | MODULE_AUTHOR ("Raphael Assenat"); | ||
| 286 | MODULE_LICENSE ("GPL"); | ||
diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c new file mode 100644 index 000000000000..b235a30cb661 --- /dev/null +++ b/drivers/rtc/rtc-pcf8583.c | |||
| @@ -0,0 +1,394 @@ | |||
| 1 | /* | ||
| 2 | * drivers/rtc/rtc-pcf8583.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2000 Russell King | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * Driver for PCF8583 RTC & RAM chip | ||
| 11 | * | ||
| 12 | * Converted to the generic RTC susbsystem by G. Liakhovetski (2006) | ||
| 13 | */ | ||
| 14 | #include <linux/module.h> | ||
| 15 | #include <linux/i2c.h> | ||
| 16 | #include <linux/slab.h> | ||
| 17 | #include <linux/string.h> | ||
| 18 | #include <linux/mc146818rtc.h> | ||
| 19 | #include <linux/init.h> | ||
| 20 | #include <linux/errno.h> | ||
| 21 | #include <linux/bcd.h> | ||
| 22 | |||
| 23 | struct rtc_mem { | ||
| 24 | unsigned int loc; | ||
| 25 | unsigned int nr; | ||
| 26 | unsigned char *data; | ||
| 27 | }; | ||
| 28 | |||
| 29 | struct pcf8583 { | ||
| 30 | struct i2c_client client; | ||
| 31 | struct rtc_device *rtc; | ||
| 32 | unsigned char ctrl; | ||
| 33 | }; | ||
| 34 | |||
| 35 | #define CTRL_STOP 0x80 | ||
| 36 | #define CTRL_HOLD 0x40 | ||
| 37 | #define CTRL_32KHZ 0x00 | ||
| 38 | #define CTRL_MASK 0x08 | ||
| 39 | #define CTRL_ALARMEN 0x04 | ||
| 40 | #define CTRL_ALARM 0x02 | ||
| 41 | #define CTRL_TIMER 0x01 | ||
| 42 | |||
| 43 | static unsigned short normal_i2c[] = { I2C_CLIENT_END }; | ||
| 44 | |||
| 45 | /* Module parameters */ | ||
| 46 | I2C_CLIENT_INSMOD; | ||
| 47 | |||
| 48 | static struct i2c_driver pcf8583_driver; | ||
| 49 | |||
| 50 | #define get_ctrl(x) ((struct pcf8583 *)i2c_get_clientdata(x))->ctrl | ||
| 51 | #define set_ctrl(x, v) get_ctrl(x) = v | ||
| 52 | |||
| 53 | #define CMOS_YEAR (64 + 128) | ||
| 54 | #define CMOS_CHECKSUM (63) | ||
| 55 | |||
| 56 | static int pcf8583_get_datetime(struct i2c_client *client, struct rtc_time *dt) | ||
| 57 | { | ||
| 58 | unsigned char buf[8], addr[1] = { 1 }; | ||
| 59 | struct i2c_msg msgs[2] = { | ||
| 60 | { | ||
| 61 | .addr = client->addr, | ||
| 62 | .flags = 0, | ||
| 63 | .len = 1, | ||
| 64 | .buf = addr, | ||
| 65 | }, { | ||
| 66 | .addr = client->addr, | ||
| 67 | .flags = I2C_M_RD, | ||
| 68 | .len = 6, | ||
| 69 | .buf = buf, | ||
| 70 | } | ||
| 71 | }; | ||
| 72 | int ret; | ||
| 73 | |||
| 74 | memset(buf, 0, sizeof(buf)); | ||
| 75 | |||
| 76 | ret = i2c_transfer(client->adapter, msgs, 2); | ||
| 77 | if (ret == 2) { | ||
| 78 | dt->tm_year = buf[4] >> 6; | ||
| 79 | dt->tm_wday = buf[5] >> 5; | ||
| 80 | |||
| 81 | buf[4] &= 0x3f; | ||
| 82 | buf[5] &= 0x1f; | ||
| 83 | |||
| 84 | dt->tm_sec = BCD_TO_BIN(buf[1]); | ||
| 85 | dt->tm_min = BCD_TO_BIN(buf[2]); | ||
| 86 | dt->tm_hour = BCD_TO_BIN(buf[3]); | ||
| 87 | dt->tm_mday = BCD_TO_BIN(buf[4]); | ||
| 88 | dt->tm_mon = BCD_TO_BIN(buf[5]); | ||
| 89 | } | ||
| 90 | |||
| 91 | return ret == 2 ? 0 : -EIO; | ||
| 92 | } | ||
| 93 | |||
| 94 | static int pcf8583_set_datetime(struct i2c_client *client, struct rtc_time *dt, int datetoo) | ||
| 95 | { | ||
| 96 | unsigned char buf[8]; | ||
| 97 | int ret, len = 6; | ||
| 98 | |||
| 99 | buf[0] = 0; | ||
| 100 | buf[1] = get_ctrl(client) | 0x80; | ||
| 101 | buf[2] = 0; | ||
| 102 | buf[3] = BIN_TO_BCD(dt->tm_sec); | ||
| 103 | buf[4] = BIN_TO_BCD(dt->tm_min); | ||
| 104 | buf[5] = BIN_TO_BCD(dt->tm_hour); | ||
| 105 | |||
| 106 | if (datetoo) { | ||
| 107 | len = 8; | ||
| 108 | buf[6] = BIN_TO_BCD(dt->tm_mday) | (dt->tm_year << 6); | ||
| 109 | buf[7] = BIN_TO_BCD(dt->tm_mon) | (dt->tm_wday << 5); | ||
| 110 | } | ||
| 111 | |||
| 112 | ret = i2c_master_send(client, (char *)buf, len); | ||
| 113 | if (ret != len) | ||
| 114 | return -EIO; | ||
| 115 | |||
| 116 | buf[1] = get_ctrl(client); | ||
| 117 | ret = i2c_master_send(client, (char *)buf, 2); | ||
| 118 | |||
| 119 | return ret == 2 ? 0 : -EIO; | ||
| 120 | } | ||
| 121 | |||
| 122 | static int pcf8583_get_ctrl(struct i2c_client *client, unsigned char *ctrl) | ||
| 123 | { | ||
| 124 | *ctrl = get_ctrl(client); | ||
| 125 | return 0; | ||
| 126 | } | ||
| 127 | |||
| 128 | static int pcf8583_set_ctrl(struct i2c_client *client, unsigned char *ctrl) | ||
| 129 | { | ||
| 130 | unsigned char buf[2]; | ||
| 131 | |||
| 132 | buf[0] = 0; | ||
| 133 | buf[1] = *ctrl; | ||
| 134 | set_ctrl(client, *ctrl); | ||
| 135 | |||
| 136 | return i2c_master_send(client, (char *)buf, 2); | ||
| 137 | } | ||
| 138 | |||
| 139 | static int pcf8583_read_mem(struct i2c_client *client, struct rtc_mem *mem) | ||
| 140 | { | ||
| 141 | unsigned char addr[1]; | ||
| 142 | struct i2c_msg msgs[2] = { | ||
| 143 | { | ||
| 144 | .addr = client->addr, | ||
| 145 | .flags = 0, | ||
| 146 | .len = 1, | ||
| 147 | .buf = addr, | ||
| 148 | }, { | ||
| 149 | .addr = client->addr, | ||
| 150 | .flags = I2C_M_RD, | ||
| 151 | .len = mem->nr, | ||
| 152 | .buf = mem->data, | ||
| 153 | } | ||
| 154 | }; | ||
| 155 | |||
| 156 | if (mem->loc < 8) | ||
| 157 | return -EINVAL; | ||
| 158 | |||
| 159 | addr[0] = mem->loc; | ||
| 160 | |||
| 161 | return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO; | ||
| 162 | } | ||
| 163 | |||
| 164 | static int pcf8583_write_mem(struct i2c_client *client, struct rtc_mem *mem) | ||
| 165 | { | ||
| 166 | unsigned char addr[1]; | ||
| 167 | struct i2c_msg msgs[2] = { | ||
| 168 | { | ||
| 169 | .addr = client->addr, | ||
| 170 | .flags = 0, | ||
| 171 | .len = 1, | ||
| 172 | .buf = addr, | ||
| 173 | }, { | ||
| 174 | .addr = client->addr, | ||
| 175 | .flags = I2C_M_NOSTART, | ||
| 176 | .len = mem->nr, | ||
| 177 | .buf = mem->data, | ||
| 178 | } | ||
| 179 | }; | ||
| 180 | |||
| 181 | if (mem->loc < 8) | ||
| 182 | return -EINVAL; | ||
| 183 | |||
| 184 | addr[0] = mem->loc; | ||
| 185 | |||
| 186 | return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO; | ||
| 187 | } | ||
| 188 | |||
| 189 | static int pcf8583_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
| 190 | { | ||
| 191 | struct i2c_client *client = to_i2c_client(dev); | ||
| 192 | unsigned char ctrl, year[2]; | ||
| 193 | struct rtc_mem mem = { CMOS_YEAR, sizeof(year), year }; | ||
| 194 | int real_year, year_offset, err; | ||
| 195 | |||
| 196 | /* | ||
| 197 | * Ensure that the RTC is running. | ||
| 198 | */ | ||
| 199 | pcf8583_get_ctrl(client, &ctrl); | ||
| 200 | if (ctrl & (CTRL_STOP | CTRL_HOLD)) { | ||
| 201 | unsigned char new_ctrl = ctrl & ~(CTRL_STOP | CTRL_HOLD); | ||
| 202 | |||
| 203 | printk(KERN_WARNING "RTC: resetting control %02x -> %02x\n", | ||
| 204 | ctrl, new_ctrl); | ||
| 205 | |||
| 206 | if ((err = pcf8583_set_ctrl(client, &new_ctrl)) < 0) | ||
| 207 | return err; | ||
| 208 | } | ||
| 209 | |||
| 210 | if (pcf8583_get_datetime(client, tm) || | ||
| 211 | pcf8583_read_mem(client, &mem)) | ||
| 212 | return -EIO; | ||
| 213 | |||
| 214 | real_year = year[0]; | ||
| 215 | |||
| 216 | /* | ||
| 217 | * The RTC year holds the LSB two bits of the current | ||
| 218 | * year, which should reflect the LSB two bits of the | ||
| 219 | * CMOS copy of the year. Any difference indicates | ||
| 220 | * that we have to correct the CMOS version. | ||
| 221 | */ | ||
| 222 | year_offset = tm->tm_year - (real_year & 3); | ||
| 223 | if (year_offset < 0) | ||
| 224 | /* | ||
| 225 | * RTC year wrapped. Adjust it appropriately. | ||
| 226 | */ | ||
| 227 | year_offset += 4; | ||
| 228 | |||
| 229 | tm->tm_year = real_year + year_offset + year[1] * 100; | ||
| 230 | |||
| 231 | return 0; | ||
| 232 | } | ||
| 233 | |||
| 234 | static int pcf8583_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
| 235 | { | ||
| 236 | struct i2c_client *client = to_i2c_client(dev); | ||
| 237 | unsigned char year[2], chk; | ||
| 238 | struct rtc_mem cmos_year = { CMOS_YEAR, sizeof(year), year }; | ||
| 239 | struct rtc_mem cmos_check = { CMOS_CHECKSUM, 1, &chk }; | ||
| 240 | int ret; | ||
| 241 | |||
| 242 | /* | ||
| 243 | * The RTC's own 2-bit year must reflect the least | ||
| 244 | * significant two bits of the CMOS year. | ||
| 245 | */ | ||
| 246 | |||
| 247 | ret = pcf8583_set_datetime(client, tm, 1); | ||
| 248 | if (ret) | ||
| 249 | return ret; | ||
| 250 | |||
| 251 | ret = pcf8583_read_mem(client, &cmos_check); | ||
| 252 | if (ret) | ||
| 253 | return ret; | ||
| 254 | |||
| 255 | ret = pcf8583_read_mem(client, &cmos_year); | ||
| 256 | if (ret) | ||
| 257 | return ret; | ||
| 258 | |||
| 259 | chk -= year[1] + year[0]; | ||
| 260 | |||
| 261 | year[1] = tm->tm_year / 100; | ||
| 262 | year[0] = tm->tm_year % 100; | ||
| 263 | |||
| 264 | chk += year[1] + year[0]; | ||
| 265 | |||
| 266 | ret = pcf8583_write_mem(client, &cmos_year); | ||
| 267 | |||
| 268 | if (ret) | ||
| 269 | return ret; | ||
| 270 | |||
| 271 | ret = pcf8583_write_mem(client, &cmos_check); | ||
| 272 | |||
| 273 | return ret; | ||
| 274 | } | ||
| 275 | |||
| 276 | static struct rtc_class_ops pcf8583_rtc_ops = { | ||
| 277 | .read_time = pcf8583_rtc_read_time, | ||
| 278 | .set_time = pcf8583_rtc_set_time, | ||
| 279 | }; | ||
| 280 | |||
| 281 | static int pcf8583_probe(struct i2c_adapter *adap, int addr, int kind); | ||
| 282 | |||
| 283 | static int pcf8583_attach(struct i2c_adapter *adap) | ||
| 284 | { | ||
| 285 | return i2c_probe(adap, &addr_data, pcf8583_probe); | ||
| 286 | } | ||
| 287 | |||
| 288 | static int pcf8583_detach(struct i2c_client *client) | ||
| 289 | { | ||
| 290 | int err; | ||
| 291 | struct pcf8583 *pcf = i2c_get_clientdata(client); | ||
| 292 | struct rtc_device *rtc = pcf->rtc; | ||
| 293 | |||
| 294 | if (rtc) | ||
| 295 | rtc_device_unregister(rtc); | ||
| 296 | |||
| 297 | if ((err = i2c_detach_client(client))) | ||
| 298 | return err; | ||
| 299 | |||
| 300 | kfree(pcf); | ||
| 301 | return 0; | ||
| 302 | } | ||
| 303 | |||
| 304 | static struct i2c_driver pcf8583_driver = { | ||
| 305 | .driver = { | ||
| 306 | .name = "pcf8583", | ||
| 307 | }, | ||
| 308 | .id = I2C_DRIVERID_PCF8583, | ||
| 309 | .attach_adapter = pcf8583_attach, | ||
| 310 | .detach_client = pcf8583_detach, | ||
| 311 | }; | ||
| 312 | |||
| 313 | static int pcf8583_probe(struct i2c_adapter *adap, int addr, int kind) | ||
| 314 | { | ||
| 315 | struct pcf8583 *pcf; | ||
| 316 | struct i2c_client *client; | ||
| 317 | struct rtc_device *rtc; | ||
| 318 | unsigned char buf[1], ad[1] = { 0 }; | ||
| 319 | int err; | ||
| 320 | struct i2c_msg msgs[2] = { | ||
| 321 | { | ||
| 322 | .addr = addr, | ||
| 323 | .flags = 0, | ||
| 324 | .len = 1, | ||
| 325 | .buf = ad, | ||
| 326 | }, { | ||
| 327 | .addr = addr, | ||
| 328 | .flags = I2C_M_RD, | ||
| 329 | .len = 1, | ||
| 330 | .buf = buf, | ||
| 331 | } | ||
| 332 | }; | ||
| 333 | |||
| 334 | pcf = kzalloc(sizeof(*pcf), GFP_KERNEL); | ||
| 335 | if (!pcf) | ||
| 336 | return -ENOMEM; | ||
| 337 | |||
| 338 | client = &pcf->client; | ||
| 339 | |||
| 340 | client->addr = addr; | ||
| 341 | client->adapter = adap; | ||
| 342 | client->driver = &pcf8583_driver; | ||
| 343 | |||
| 344 | strlcpy(client->name, pcf8583_driver.driver.name, I2C_NAME_SIZE); | ||
| 345 | |||
| 346 | if (i2c_transfer(client->adapter, msgs, 2) != 2) { | ||
| 347 | err = -EIO; | ||
| 348 | goto exit_kfree; | ||
| 349 | } | ||
| 350 | |||
| 351 | err = i2c_attach_client(client); | ||
| 352 | |||
| 353 | if (err) | ||
| 354 | goto exit_kfree; | ||
| 355 | |||
| 356 | rtc = rtc_device_register(pcf8583_driver.driver.name, &client->dev, | ||
| 357 | &pcf8583_rtc_ops, THIS_MODULE); | ||
| 358 | |||
| 359 | if (IS_ERR(rtc)) { | ||
| 360 | err = PTR_ERR(rtc); | ||
| 361 | goto exit_detach; | ||
| 362 | } | ||
| 363 | |||
| 364 | pcf->rtc = rtc; | ||
| 365 | i2c_set_clientdata(client, pcf); | ||
| 366 | set_ctrl(client, buf[0]); | ||
| 367 | |||
| 368 | return 0; | ||
| 369 | |||
| 370 | exit_detach: | ||
| 371 | i2c_detach_client(client); | ||
| 372 | |||
| 373 | exit_kfree: | ||
| 374 | kfree(pcf); | ||
| 375 | |||
| 376 | return err; | ||
| 377 | } | ||
| 378 | |||
| 379 | static __init int pcf8583_init(void) | ||
| 380 | { | ||
| 381 | return i2c_add_driver(&pcf8583_driver); | ||
| 382 | } | ||
| 383 | |||
| 384 | static __exit void pcf8583_exit(void) | ||
| 385 | { | ||
| 386 | i2c_del_driver(&pcf8583_driver); | ||
| 387 | } | ||
| 388 | |||
| 389 | module_init(pcf8583_init); | ||
| 390 | module_exit(pcf8583_exit); | ||
| 391 | |||
| 392 | MODULE_AUTHOR("Russell King"); | ||
| 393 | MODULE_DESCRIPTION("PCF8583 I2C RTC driver"); | ||
| 394 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c new file mode 100644 index 000000000000..ee538632660b --- /dev/null +++ b/drivers/rtc/rtc-pl031.c | |||
| @@ -0,0 +1,233 @@ | |||
| 1 | /* | ||
| 2 | * drivers/rtc/rtc-pl031.c | ||
| 3 | * | ||
| 4 | * Real Time Clock interface for ARM AMBA PrimeCell 031 RTC | ||
| 5 | * | ||
| 6 | * Author: Deepak Saxena <dsaxena@plexity.net> | ||
| 7 | * | ||
| 8 | * Copyright 2006 (c) MontaVista Software, Inc. | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or | ||
| 11 | * modify it under the terms of the GNU General Public License | ||
| 12 | * as published by the Free Software Foundation; either version | ||
| 13 | * 2 of the License, or (at your option) any later version. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/platform_device.h> | ||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/rtc.h> | ||
| 19 | #include <linux/init.h> | ||
| 20 | #include <linux/fs.h> | ||
| 21 | #include <linux/interrupt.h> | ||
| 22 | #include <linux/string.h> | ||
| 23 | #include <linux/pm.h> | ||
| 24 | |||
| 25 | #include <linux/amba/bus.h> | ||
| 26 | |||
| 27 | #include <asm/io.h> | ||
| 28 | #include <asm/bitops.h> | ||
| 29 | #include <asm/hardware.h> | ||
| 30 | #include <asm/irq.h> | ||
| 31 | #include <asm/rtc.h> | ||
| 32 | |||
| 33 | /* | ||
| 34 | * Register definitions | ||
| 35 | */ | ||
| 36 | #define RTC_DR 0x00 /* Data read register */ | ||
| 37 | #define RTC_MR 0x04 /* Match register */ | ||
| 38 | #define RTC_LR 0x08 /* Data load register */ | ||
| 39 | #define RTC_CR 0x0c /* Control register */ | ||
| 40 | #define RTC_IMSC 0x10 /* Interrupt mask and set register */ | ||
| 41 | #define RTC_RIS 0x14 /* Raw interrupt status register */ | ||
| 42 | #define RTC_MIS 0x18 /* Masked interrupt status register */ | ||
| 43 | #define RTC_ICR 0x1c /* Interrupt clear register */ | ||
| 44 | |||
| 45 | struct pl031_local { | ||
| 46 | struct rtc_device *rtc; | ||
| 47 | void __iomem *base; | ||
| 48 | }; | ||
| 49 | |||
| 50 | static irqreturn_t pl031_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
| 51 | { | ||
| 52 | struct rtc_device *rtc = dev_id; | ||
| 53 | |||
| 54 | rtc_update_irq(&rtc->class_dev, 1, RTC_AF); | ||
| 55 | |||
| 56 | return IRQ_HANDLED; | ||
| 57 | } | ||
| 58 | |||
| 59 | static int pl031_open(struct device *dev) | ||
| 60 | { | ||
| 61 | /* | ||
| 62 | * We request IRQ in pl031_probe, so nothing to do here... | ||
| 63 | */ | ||
| 64 | return 0; | ||
| 65 | } | ||
| 66 | |||
| 67 | static void pl031_release(struct device *dev) | ||
| 68 | { | ||
| 69 | } | ||
| 70 | |||
| 71 | static int pl031_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) | ||
| 72 | { | ||
| 73 | struct pl031_local *ldata = dev_get_drvdata(dev); | ||
| 74 | |||
| 75 | switch (cmd) { | ||
| 76 | case RTC_AIE_OFF: | ||
| 77 | __raw_writel(1, ldata->base + RTC_MIS); | ||
| 78 | return 0; | ||
| 79 | case RTC_AIE_ON: | ||
| 80 | __raw_writel(0, ldata->base + RTC_MIS); | ||
| 81 | return 0; | ||
| 82 | } | ||
| 83 | |||
| 84 | return -ENOIOCTLCMD; | ||
| 85 | } | ||
| 86 | |||
| 87 | static int pl031_read_time(struct device *dev, struct rtc_time *tm) | ||
| 88 | { | ||
| 89 | struct pl031_local *ldata = dev_get_drvdata(dev); | ||
| 90 | |||
| 91 | rtc_time_to_tm(__raw_readl(ldata->base + RTC_DR), tm); | ||
| 92 | |||
| 93 | return 0; | ||
| 94 | } | ||
| 95 | |||
| 96 | static int pl031_set_time(struct device *dev, struct rtc_time *tm) | ||
| 97 | { | ||
| 98 | unsigned long time; | ||
| 99 | struct pl031_local *ldata = dev_get_drvdata(dev); | ||
| 100 | |||
| 101 | rtc_tm_to_time(tm, &time); | ||
| 102 | __raw_writel(time, ldata->base + RTC_LR); | ||
| 103 | |||
| 104 | return 0; | ||
| 105 | } | ||
| 106 | |||
| 107 | static int pl031_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) | ||
| 108 | { | ||
| 109 | struct pl031_local *ldata = dev_get_drvdata(dev); | ||
| 110 | |||
| 111 | rtc_time_to_tm(__raw_readl(ldata->base + RTC_MR), &alarm->time); | ||
| 112 | alarm->pending = __raw_readl(ldata->base + RTC_RIS); | ||
| 113 | alarm->enabled = __raw_readl(ldata->base + RTC_IMSC); | ||
| 114 | |||
| 115 | return 0; | ||
| 116 | } | ||
| 117 | |||
| 118 | static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) | ||
| 119 | { | ||
| 120 | struct pl031_local *ldata = dev_get_drvdata(dev); | ||
| 121 | unsigned long time; | ||
| 122 | |||
| 123 | rtc_tm_to_time(&alarm->time, &time); | ||
| 124 | |||
| 125 | __raw_writel(time, ldata->base + RTC_MR); | ||
| 126 | __raw_writel(!alarm->enabled, ldata->base + RTC_MIS); | ||
| 127 | |||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | |||
| 131 | static struct rtc_class_ops pl031_ops = { | ||
| 132 | .open = pl031_open, | ||
| 133 | .release = pl031_release, | ||
| 134 | .ioctl = pl031_ioctl, | ||
| 135 | .read_time = pl031_read_time, | ||
| 136 | .set_time = pl031_set_time, | ||
| 137 | .read_alarm = pl031_read_alarm, | ||
| 138 | .set_alarm = pl031_set_alarm, | ||
| 139 | }; | ||
| 140 | |||
| 141 | static int pl031_remove(struct amba_device *adev) | ||
| 142 | { | ||
| 143 | struct pl031_local *ldata = dev_get_drvdata(&adev->dev); | ||
| 144 | |||
| 145 | if (ldata) { | ||
| 146 | dev_set_drvdata(&adev->dev, NULL); | ||
| 147 | free_irq(adev->irq[0], ldata->rtc); | ||
| 148 | rtc_device_unregister(ldata->rtc); | ||
| 149 | iounmap(ldata->base); | ||
| 150 | kfree(ldata); | ||
| 151 | } | ||
| 152 | |||
| 153 | return 0; | ||
| 154 | } | ||
| 155 | |||
| 156 | static int pl031_probe(struct amba_device *adev, void *id) | ||
| 157 | { | ||
| 158 | int ret; | ||
| 159 | struct pl031_local *ldata; | ||
| 160 | |||
| 161 | |||
| 162 | ldata = kmalloc(sizeof(struct pl031_local), GFP_KERNEL); | ||
| 163 | if (!ldata) { | ||
| 164 | ret = -ENOMEM; | ||
| 165 | goto out; | ||
| 166 | } | ||
| 167 | dev_set_drvdata(&adev->dev, ldata); | ||
| 168 | |||
| 169 | ldata->base = ioremap(adev->res.start, | ||
| 170 | adev->res.end - adev->res.start + 1); | ||
| 171 | if (!ldata->base) { | ||
| 172 | ret = -ENOMEM; | ||
| 173 | goto out_no_remap; | ||
| 174 | } | ||
| 175 | |||
| 176 | if (request_irq(adev->irq[0], pl031_interrupt, SA_INTERRUPT, | ||
| 177 | "rtc-pl031", ldata->rtc)) { | ||
| 178 | ret = -EIO; | ||
| 179 | goto out_no_irq; | ||
| 180 | } | ||
| 181 | |||
| 182 | ldata->rtc = rtc_device_register("pl031", &adev->dev, &pl031_ops, | ||
| 183 | THIS_MODULE); | ||
| 184 | if (IS_ERR(ldata->rtc)) { | ||
| 185 | ret = PTR_ERR(ldata->rtc); | ||
| 186 | goto out_no_rtc; | ||
| 187 | } | ||
| 188 | |||
| 189 | return 0; | ||
| 190 | |||
| 191 | out_no_rtc: | ||
| 192 | free_irq(adev->irq[0], ldata->rtc); | ||
| 193 | out_no_irq: | ||
| 194 | iounmap(ldata->base); | ||
| 195 | out_no_remap: | ||
| 196 | dev_set_drvdata(&adev->dev, NULL); | ||
| 197 | kfree(ldata); | ||
| 198 | out: | ||
| 199 | return ret; | ||
| 200 | } | ||
| 201 | |||
| 202 | static struct amba_id pl031_ids[] __initdata = { | ||
| 203 | { | ||
| 204 | .id = 0x00041031, | ||
| 205 | .mask = 0x000fffff, }, | ||
| 206 | {0, 0}, | ||
| 207 | }; | ||
| 208 | |||
| 209 | static struct amba_driver pl031_driver = { | ||
| 210 | .drv = { | ||
| 211 | .name = "rtc-pl031", | ||
| 212 | }, | ||
| 213 | .id_table = pl031_ids, | ||
| 214 | .probe = pl031_probe, | ||
| 215 | .remove = pl031_remove, | ||
| 216 | }; | ||
| 217 | |||
| 218 | static int __init pl031_init(void) | ||
| 219 | { | ||
| 220 | return amba_driver_register(&pl031_driver); | ||
| 221 | } | ||
| 222 | |||
| 223 | static void __exit pl031_exit(void) | ||
| 224 | { | ||
| 225 | amba_driver_unregister(&pl031_driver); | ||
| 226 | } | ||
| 227 | |||
| 228 | module_init(pl031_init); | ||
| 229 | module_exit(pl031_exit); | ||
| 230 | |||
| 231 | MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net"); | ||
| 232 | MODULE_DESCRIPTION("ARM AMBA PL031 RTC Driver"); | ||
| 233 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c new file mode 100644 index 000000000000..0964d1dba925 --- /dev/null +++ b/drivers/rtc/rtc-rs5c348.c | |||
| @@ -0,0 +1,246 @@ | |||
| 1 | /* | ||
| 2 | * A SPI driver for the Ricoh RS5C348 RTC | ||
| 3 | * | ||
| 4 | * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * The board specific init code should provide characteristics of this | ||
| 11 | * device: | ||
| 12 | * Mode 1 (High-Active, Shift-Then-Sample), High Avtive CS | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/bcd.h> | ||
| 16 | #include <linux/delay.h> | ||
| 17 | #include <linux/device.h> | ||
| 18 | #include <linux/errno.h> | ||
| 19 | #include <linux/init.h> | ||
| 20 | #include <linux/kernel.h> | ||
| 21 | #include <linux/string.h> | ||
| 22 | #include <linux/rtc.h> | ||
| 23 | #include <linux/workqueue.h> | ||
| 24 | #include <linux/spi/spi.h> | ||
| 25 | |||
| 26 | #define DRV_VERSION "0.1" | ||
| 27 | |||
| 28 | #define RS5C348_REG_SECS 0 | ||
| 29 | #define RS5C348_REG_MINS 1 | ||
| 30 | #define RS5C348_REG_HOURS 2 | ||
| 31 | #define RS5C348_REG_WDAY 3 | ||
| 32 | #define RS5C348_REG_DAY 4 | ||
| 33 | #define RS5C348_REG_MONTH 5 | ||
| 34 | #define RS5C348_REG_YEAR 6 | ||
| 35 | #define RS5C348_REG_CTL1 14 | ||
| 36 | #define RS5C348_REG_CTL2 15 | ||
| 37 | |||
| 38 | #define RS5C348_SECS_MASK 0x7f | ||
| 39 | #define RS5C348_MINS_MASK 0x7f | ||
| 40 | #define RS5C348_HOURS_MASK 0x3f | ||
| 41 | #define RS5C348_WDAY_MASK 0x03 | ||
| 42 | #define RS5C348_DAY_MASK 0x3f | ||
| 43 | #define RS5C348_MONTH_MASK 0x1f | ||
| 44 | |||
| 45 | #define RS5C348_BIT_PM 0x20 /* REG_HOURS */ | ||
| 46 | #define RS5C348_BIT_Y2K 0x80 /* REG_MONTH */ | ||
| 47 | #define RS5C348_BIT_24H 0x20 /* REG_CTL1 */ | ||
| 48 | #define RS5C348_BIT_XSTP 0x10 /* REG_CTL2 */ | ||
| 49 | #define RS5C348_BIT_VDET 0x40 /* REG_CTL2 */ | ||
| 50 | |||
| 51 | #define RS5C348_CMD_W(addr) (((addr) << 4) | 0x08) /* single write */ | ||
| 52 | #define RS5C348_CMD_R(addr) (((addr) << 4) | 0x0c) /* single read */ | ||
| 53 | #define RS5C348_CMD_MW(addr) (((addr) << 4) | 0x00) /* burst write */ | ||
| 54 | #define RS5C348_CMD_MR(addr) (((addr) << 4) | 0x04) /* burst read */ | ||
| 55 | |||
| 56 | struct rs5c348_plat_data { | ||
| 57 | struct rtc_device *rtc; | ||
| 58 | int rtc_24h; | ||
| 59 | }; | ||
| 60 | |||
| 61 | static int | ||
| 62 | rs5c348_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
| 63 | { | ||
| 64 | struct spi_device *spi = to_spi_device(dev); | ||
| 65 | struct rs5c348_plat_data *pdata = spi->dev.platform_data; | ||
| 66 | u8 txbuf[5+7], *txp; | ||
| 67 | int ret; | ||
| 68 | |||
| 69 | /* Transfer 5 bytes before writing SEC. This gives 31us for carry. */ | ||
| 70 | txp = txbuf; | ||
| 71 | txbuf[0] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */ | ||
| 72 | txbuf[1] = 0; /* dummy */ | ||
| 73 | txbuf[2] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */ | ||
| 74 | txbuf[3] = 0; /* dummy */ | ||
| 75 | txbuf[4] = RS5C348_CMD_MW(RS5C348_REG_SECS); /* cmd, sec, ... */ | ||
| 76 | txp = &txbuf[5]; | ||
| 77 | txp[RS5C348_REG_SECS] = BIN2BCD(tm->tm_sec); | ||
| 78 | txp[RS5C348_REG_MINS] = BIN2BCD(tm->tm_min); | ||
| 79 | if (pdata->rtc_24h) { | ||
| 80 | txp[RS5C348_REG_HOURS] = BIN2BCD(tm->tm_hour); | ||
| 81 | } else { | ||
| 82 | /* hour 0 is AM12, noon is PM12 */ | ||
| 83 | txp[RS5C348_REG_HOURS] = BIN2BCD((tm->tm_hour + 11) % 12 + 1) | | ||
| 84 | (tm->tm_hour >= 12 ? RS5C348_BIT_PM : 0); | ||
| 85 | } | ||
| 86 | txp[RS5C348_REG_WDAY] = BIN2BCD(tm->tm_wday); | ||
| 87 | txp[RS5C348_REG_DAY] = BIN2BCD(tm->tm_mday); | ||
| 88 | txp[RS5C348_REG_MONTH] = BIN2BCD(tm->tm_mon + 1) | | ||
| 89 | (tm->tm_year >= 100 ? RS5C348_BIT_Y2K : 0); | ||
| 90 | txp[RS5C348_REG_YEAR] = BIN2BCD(tm->tm_year % 100); | ||
| 91 | /* write in one transfer to avoid data inconsistency */ | ||
| 92 | ret = spi_write_then_read(spi, txbuf, sizeof(txbuf), NULL, 0); | ||
| 93 | udelay(62); /* Tcsr 62us */ | ||
| 94 | return ret; | ||
| 95 | } | ||
| 96 | |||
| 97 | static int | ||
| 98 | rs5c348_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
| 99 | { | ||
| 100 | struct spi_device *spi = to_spi_device(dev); | ||
| 101 | struct rs5c348_plat_data *pdata = spi->dev.platform_data; | ||
| 102 | u8 txbuf[5], rxbuf[7]; | ||
| 103 | int ret; | ||
| 104 | |||
| 105 | /* Transfer 5 byte befores reading SEC. This gives 31us for carry. */ | ||
| 106 | txbuf[0] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */ | ||
| 107 | txbuf[1] = 0; /* dummy */ | ||
| 108 | txbuf[2] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */ | ||
| 109 | txbuf[3] = 0; /* dummy */ | ||
| 110 | txbuf[4] = RS5C348_CMD_MR(RS5C348_REG_SECS); /* cmd, sec, ... */ | ||
| 111 | |||
| 112 | /* read in one transfer to avoid data inconsistency */ | ||
| 113 | ret = spi_write_then_read(spi, txbuf, sizeof(txbuf), | ||
| 114 | rxbuf, sizeof(rxbuf)); | ||
| 115 | udelay(62); /* Tcsr 62us */ | ||
| 116 | if (ret < 0) | ||
| 117 | return ret; | ||
| 118 | |||
| 119 | tm->tm_sec = BCD2BIN(rxbuf[RS5C348_REG_SECS] & RS5C348_SECS_MASK); | ||
| 120 | tm->tm_min = BCD2BIN(rxbuf[RS5C348_REG_MINS] & RS5C348_MINS_MASK); | ||
| 121 | tm->tm_hour = BCD2BIN(rxbuf[RS5C348_REG_HOURS] & RS5C348_HOURS_MASK); | ||
| 122 | if (!pdata->rtc_24h) { | ||
| 123 | tm->tm_hour %= 12; | ||
| 124 | if (rxbuf[RS5C348_REG_HOURS] & RS5C348_BIT_PM) | ||
| 125 | tm->tm_hour += 12; | ||
| 126 | } | ||
| 127 | tm->tm_wday = BCD2BIN(rxbuf[RS5C348_REG_WDAY] & RS5C348_WDAY_MASK); | ||
| 128 | tm->tm_mday = BCD2BIN(rxbuf[RS5C348_REG_DAY] & RS5C348_DAY_MASK); | ||
| 129 | tm->tm_mon = | ||
| 130 | BCD2BIN(rxbuf[RS5C348_REG_MONTH] & RS5C348_MONTH_MASK) - 1; | ||
| 131 | /* year is 1900 + tm->tm_year */ | ||
| 132 | tm->tm_year = BCD2BIN(rxbuf[RS5C348_REG_YEAR]) + | ||
| 133 | ((rxbuf[RS5C348_REG_MONTH] & RS5C348_BIT_Y2K) ? 100 : 0); | ||
| 134 | |||
| 135 | if (rtc_valid_tm(tm) < 0) { | ||
| 136 | dev_err(&spi->dev, "retrieved date/time is not valid.\n"); | ||
| 137 | rtc_time_to_tm(0, tm); | ||
| 138 | } | ||
| 139 | |||
| 140 | return 0; | ||
| 141 | } | ||
| 142 | |||
| 143 | static struct rtc_class_ops rs5c348_rtc_ops = { | ||
| 144 | .read_time = rs5c348_rtc_read_time, | ||
| 145 | .set_time = rs5c348_rtc_set_time, | ||
| 146 | }; | ||
| 147 | |||
| 148 | static struct spi_driver rs5c348_driver; | ||
| 149 | |||
| 150 | static int __devinit rs5c348_probe(struct spi_device *spi) | ||
| 151 | { | ||
| 152 | int ret; | ||
| 153 | struct rtc_device *rtc; | ||
| 154 | struct rs5c348_plat_data *pdata; | ||
| 155 | |||
| 156 | pdata = kzalloc(sizeof(struct rs5c348_plat_data), GFP_KERNEL); | ||
| 157 | if (!pdata) | ||
| 158 | return -ENOMEM; | ||
| 159 | spi->dev.platform_data = pdata; | ||
| 160 | |||
| 161 | /* Check D7 of SECOND register */ | ||
| 162 | ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_SECS)); | ||
| 163 | if (ret < 0 || (ret & 0x80)) { | ||
| 164 | dev_err(&spi->dev, "not found.\n"); | ||
| 165 | goto kfree_exit; | ||
| 166 | } | ||
| 167 | |||
| 168 | dev_info(&spi->dev, "chip found, driver version " DRV_VERSION "\n"); | ||
| 169 | dev_info(&spi->dev, "spiclk %u KHz.\n", | ||
| 170 | (spi->max_speed_hz + 500) / 1000); | ||
| 171 | |||
| 172 | /* turn RTC on if it was not on */ | ||
| 173 | ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_CTL2)); | ||
| 174 | if (ret < 0) | ||
| 175 | goto kfree_exit; | ||
| 176 | if (ret & (RS5C348_BIT_XSTP | RS5C348_BIT_VDET)) { | ||
| 177 | u8 buf[2]; | ||
| 178 | if (ret & RS5C348_BIT_VDET) | ||
| 179 | dev_warn(&spi->dev, "voltage-low detected.\n"); | ||
| 180 | buf[0] = RS5C348_CMD_W(RS5C348_REG_CTL2); | ||
| 181 | buf[1] = 0; | ||
| 182 | ret = spi_write_then_read(spi, buf, sizeof(buf), NULL, 0); | ||
| 183 | if (ret < 0) | ||
| 184 | goto kfree_exit; | ||
| 185 | } | ||
| 186 | |||
| 187 | ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_CTL1)); | ||
| 188 | if (ret < 0) | ||
| 189 | goto kfree_exit; | ||
| 190 | if (ret & RS5C348_BIT_24H) | ||
| 191 | pdata->rtc_24h = 1; | ||
| 192 | |||
| 193 | rtc = rtc_device_register(rs5c348_driver.driver.name, &spi->dev, | ||
| 194 | &rs5c348_rtc_ops, THIS_MODULE); | ||
| 195 | |||
| 196 | if (IS_ERR(rtc)) { | ||
| 197 | ret = PTR_ERR(rtc); | ||
| 198 | goto kfree_exit; | ||
| 199 | } | ||
| 200 | |||
| 201 | pdata->rtc = rtc; | ||
| 202 | |||
| 203 | return 0; | ||
| 204 | kfree_exit: | ||
| 205 | kfree(pdata); | ||
| 206 | return ret; | ||
| 207 | } | ||
| 208 | |||
| 209 | static int __devexit rs5c348_remove(struct spi_device *spi) | ||
| 210 | { | ||
| 211 | struct rs5c348_plat_data *pdata = spi->dev.platform_data; | ||
| 212 | struct rtc_device *rtc = pdata->rtc; | ||
| 213 | |||
| 214 | if (rtc) | ||
| 215 | rtc_device_unregister(rtc); | ||
| 216 | kfree(pdata); | ||
| 217 | return 0; | ||
| 218 | } | ||
| 219 | |||
| 220 | static struct spi_driver rs5c348_driver = { | ||
| 221 | .driver = { | ||
| 222 | .name = "rs5c348", | ||
| 223 | .bus = &spi_bus_type, | ||
| 224 | .owner = THIS_MODULE, | ||
| 225 | }, | ||
| 226 | .probe = rs5c348_probe, | ||
| 227 | .remove = __devexit_p(rs5c348_remove), | ||
| 228 | }; | ||
| 229 | |||
| 230 | static __init int rs5c348_init(void) | ||
| 231 | { | ||
| 232 | return spi_register_driver(&rs5c348_driver); | ||
| 233 | } | ||
| 234 | |||
| 235 | static __exit void rs5c348_exit(void) | ||
| 236 | { | ||
| 237 | spi_unregister_driver(&rs5c348_driver); | ||
| 238 | } | ||
| 239 | |||
| 240 | module_init(rs5c348_init); | ||
| 241 | module_exit(rs5c348_exit); | ||
| 242 | |||
| 243 | MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>"); | ||
| 244 | MODULE_DESCRIPTION("Ricoh RS5C348 RTC driver"); | ||
| 245 | MODULE_LICENSE("GPL"); | ||
| 246 | MODULE_VERSION(DRV_VERSION); | ||
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index a997529f8926..9cd1cb304bb2 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c | |||
| @@ -45,7 +45,7 @@ | |||
| 45 | 45 | ||
| 46 | static unsigned long rtc_freq = 1024; | 46 | static unsigned long rtc_freq = 1024; |
| 47 | static struct rtc_time rtc_alarm; | 47 | static struct rtc_time rtc_alarm; |
| 48 | static spinlock_t sa1100_rtc_lock = SPIN_LOCK_UNLOCKED; | 48 | static DEFINE_SPINLOCK(sa1100_rtc_lock); |
| 49 | 49 | ||
| 50 | static int rtc_update_alarm(struct rtc_time *alrm) | 50 | static int rtc_update_alarm(struct rtc_time *alrm) |
| 51 | { | 51 | { |
| @@ -229,8 +229,6 @@ static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd, | |||
| 229 | spin_unlock_irq(&sa1100_rtc_lock); | 229 | spin_unlock_irq(&sa1100_rtc_lock); |
| 230 | return 0; | 230 | return 0; |
| 231 | case RTC_PIE_ON: | 231 | case RTC_PIE_ON: |
| 232 | if ((rtc_freq > 64) && !capable(CAP_SYS_RESOURCE)) | ||
| 233 | return -EACCES; | ||
| 234 | spin_lock_irq(&sa1100_rtc_lock); | 232 | spin_lock_irq(&sa1100_rtc_lock); |
| 235 | OSMR1 = TIMER_FREQ/rtc_freq + OSCR; | 233 | OSMR1 = TIMER_FREQ/rtc_freq + OSCR; |
| 236 | OIER |= OIER_E1; | 234 | OIER |= OIER_E1; |
| @@ -242,8 +240,6 @@ static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd, | |||
| 242 | case RTC_IRQP_SET: | 240 | case RTC_IRQP_SET: |
| 243 | if (arg < 1 || arg > TIMER_FREQ) | 241 | if (arg < 1 || arg > TIMER_FREQ) |
| 244 | return -EINVAL; | 242 | return -EINVAL; |
| 245 | if ((arg > 64) && (!capable(CAP_SYS_RESOURCE))) | ||
| 246 | return -EACCES; | ||
| 247 | rtc_freq = arg; | 243 | rtc_freq = arg; |
| 248 | return 0; | 244 | return 0; |
| 249 | } | 245 | } |
diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c new file mode 100644 index 000000000000..a40f400acff6 --- /dev/null +++ b/drivers/rtc/rtc-v3020.c | |||
| @@ -0,0 +1,264 @@ | |||
| 1 | /* drivers/rtc/rtc-v3020.c | ||
| 2 | * | ||
| 3 | * Copyright (C) 2006 8D Technologies inc. | ||
| 4 | * Copyright (C) 2004 Compulab Ltd. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * Driver for the V3020 RTC | ||
| 11 | * | ||
| 12 | * Changelog: | ||
| 13 | * | ||
| 14 | * 10-May-2006: Raphael Assenat <raph@8d.com> | ||
| 15 | * - Converted to platform driver | ||
| 16 | * - Use the generic rtc class | ||
| 17 | * | ||
| 18 | * ??-???-2004: Someone at Compulab | ||
| 19 | * - Initial driver creation. | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | #include <linux/platform_device.h> | ||
| 23 | #include <linux/module.h> | ||
| 24 | #include <linux/init.h> | ||
| 25 | #include <linux/rtc.h> | ||
| 26 | #include <linux/types.h> | ||
| 27 | #include <linux/bcd.h> | ||
| 28 | #include <linux/rtc-v3020.h> | ||
| 29 | |||
| 30 | #include <asm/io.h> | ||
| 31 | |||
| 32 | #undef DEBUG | ||
| 33 | |||
| 34 | struct v3020 { | ||
| 35 | void __iomem *ioaddress; | ||
| 36 | int leftshift; | ||
| 37 | struct rtc_device *rtc; | ||
| 38 | }; | ||
| 39 | |||
| 40 | static void v3020_set_reg(struct v3020 *chip, unsigned char address, | ||
| 41 | unsigned char data) | ||
| 42 | { | ||
| 43 | int i; | ||
| 44 | unsigned char tmp; | ||
| 45 | |||
| 46 | tmp = address; | ||
| 47 | for (i = 0; i < 4; i++) { | ||
| 48 | writel((tmp & 1) << chip->leftshift, chip->ioaddress); | ||
| 49 | tmp >>= 1; | ||
| 50 | } | ||
| 51 | |||
| 52 | /* Commands dont have data */ | ||
| 53 | if (!V3020_IS_COMMAND(address)) { | ||
| 54 | for (i = 0; i < 8; i++) { | ||
| 55 | writel((data & 1) << chip->leftshift, chip->ioaddress); | ||
| 56 | data >>= 1; | ||
| 57 | } | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | static unsigned char v3020_get_reg(struct v3020 *chip, unsigned char address) | ||
| 62 | { | ||
| 63 | unsigned int data=0; | ||
| 64 | int i; | ||
| 65 | |||
| 66 | for (i = 0; i < 4; i++) { | ||
| 67 | writel((address & 1) << chip->leftshift, chip->ioaddress); | ||
| 68 | address >>= 1; | ||
| 69 | } | ||
| 70 | |||
| 71 | for (i = 0; i < 8; i++) { | ||
| 72 | data >>= 1; | ||
| 73 | if (readl(chip->ioaddress) & (1 << chip->leftshift)) | ||
| 74 | data |= 0x80; | ||
| 75 | } | ||
| 76 | |||
| 77 | return data; | ||
| 78 | } | ||
| 79 | |||
| 80 | static int v3020_read_time(struct device *dev, struct rtc_time *dt) | ||
| 81 | { | ||
| 82 | struct v3020 *chip = dev_get_drvdata(dev); | ||
| 83 | int tmp; | ||
| 84 | |||
| 85 | /* Copy the current time to ram... */ | ||
| 86 | v3020_set_reg(chip, V3020_CMD_CLOCK2RAM, 0); | ||
| 87 | |||
| 88 | /* ...and then read constant values. */ | ||
| 89 | tmp = v3020_get_reg(chip, V3020_SECONDS); | ||
| 90 | dt->tm_sec = BCD2BIN(tmp); | ||
| 91 | tmp = v3020_get_reg(chip, V3020_MINUTES); | ||
| 92 | dt->tm_min = BCD2BIN(tmp); | ||
| 93 | tmp = v3020_get_reg(chip, V3020_HOURS); | ||
| 94 | dt->tm_hour = BCD2BIN(tmp); | ||
| 95 | tmp = v3020_get_reg(chip, V3020_MONTH_DAY); | ||
| 96 | dt->tm_mday = BCD2BIN(tmp); | ||
| 97 | tmp = v3020_get_reg(chip, V3020_MONTH); | ||
| 98 | dt->tm_mon = BCD2BIN(tmp); | ||
| 99 | tmp = v3020_get_reg(chip, V3020_WEEK_DAY); | ||
| 100 | dt->tm_wday = BCD2BIN(tmp); | ||
| 101 | tmp = v3020_get_reg(chip, V3020_YEAR); | ||
| 102 | dt->tm_year = BCD2BIN(tmp)+100; | ||
| 103 | |||
| 104 | #ifdef DEBUG | ||
| 105 | printk("\n%s : Read RTC values\n",__FUNCTION__); | ||
| 106 | printk("tm_hour: %i\n",dt->tm_hour); | ||
| 107 | printk("tm_min : %i\n",dt->tm_min); | ||
| 108 | printk("tm_sec : %i\n",dt->tm_sec); | ||
| 109 | printk("tm_year: %i\n",dt->tm_year); | ||
| 110 | printk("tm_mon : %i\n",dt->tm_mon); | ||
| 111 | printk("tm_mday: %i\n",dt->tm_mday); | ||
| 112 | printk("tm_wday: %i\n",dt->tm_wday); | ||
| 113 | #endif | ||
| 114 | |||
| 115 | return 0; | ||
| 116 | } | ||
| 117 | |||
| 118 | |||
| 119 | static int v3020_set_time(struct device *dev, struct rtc_time *dt) | ||
| 120 | { | ||
| 121 | struct v3020 *chip = dev_get_drvdata(dev); | ||
| 122 | |||
| 123 | #ifdef DEBUG | ||
| 124 | printk("\n%s : Setting RTC values\n",__FUNCTION__); | ||
| 125 | printk("tm_sec : %i\n",dt->tm_sec); | ||
| 126 | printk("tm_min : %i\n",dt->tm_min); | ||
| 127 | printk("tm_hour: %i\n",dt->tm_hour); | ||
| 128 | printk("tm_mday: %i\n",dt->tm_mday); | ||
| 129 | printk("tm_wday: %i\n",dt->tm_wday); | ||
| 130 | printk("tm_year: %i\n",dt->tm_year); | ||
| 131 | #endif | ||
| 132 | |||
| 133 | /* Write all the values to ram... */ | ||
| 134 | v3020_set_reg(chip, V3020_SECONDS, BIN2BCD(dt->tm_sec)); | ||
| 135 | v3020_set_reg(chip, V3020_MINUTES, BIN2BCD(dt->tm_min)); | ||
| 136 | v3020_set_reg(chip, V3020_HOURS, BIN2BCD(dt->tm_hour)); | ||
| 137 | v3020_set_reg(chip, V3020_MONTH_DAY, BIN2BCD(dt->tm_mday)); | ||
| 138 | v3020_set_reg(chip, V3020_MONTH, BIN2BCD(dt->tm_mon)); | ||
| 139 | v3020_set_reg(chip, V3020_WEEK_DAY, BIN2BCD(dt->tm_wday)); | ||
| 140 | v3020_set_reg(chip, V3020_YEAR, BIN2BCD(dt->tm_year % 100)); | ||
| 141 | |||
| 142 | /* ...and set the clock. */ | ||
| 143 | v3020_set_reg(chip, V3020_CMD_RAM2CLOCK, 0); | ||
| 144 | |||
| 145 | /* Compulab used this delay here. I dont know why, | ||
| 146 | * the datasheet does not specify a delay. */ | ||
| 147 | /*mdelay(5);*/ | ||
| 148 | |||
| 149 | return 0; | ||
| 150 | } | ||
| 151 | |||
| 152 | static struct rtc_class_ops v3020_rtc_ops = { | ||
| 153 | .read_time = v3020_read_time, | ||
| 154 | .set_time = v3020_set_time, | ||
| 155 | }; | ||
| 156 | |||
| 157 | static int rtc_probe(struct platform_device *pdev) | ||
| 158 | { | ||
| 159 | struct v3020_platform_data *pdata = pdev->dev.platform_data; | ||
| 160 | struct v3020 *chip; | ||
| 161 | struct rtc_device *rtc; | ||
| 162 | int retval = -EBUSY; | ||
| 163 | int i; | ||
| 164 | int temp; | ||
| 165 | |||
| 166 | if (pdev->num_resources != 1) | ||
| 167 | return -EBUSY; | ||
| 168 | |||
| 169 | if (pdev->resource[0].flags != IORESOURCE_MEM) | ||
| 170 | return -EBUSY; | ||
| 171 | |||
| 172 | if (pdev == NULL) | ||
| 173 | return -EBUSY; | ||
| 174 | |||
| 175 | chip = kzalloc(sizeof *chip, GFP_KERNEL); | ||
| 176 | if (!chip) | ||
| 177 | return -ENOMEM; | ||
| 178 | |||
| 179 | chip->leftshift = pdata->leftshift; | ||
| 180 | chip->ioaddress = ioremap(pdev->resource[0].start, 1); | ||
| 181 | if (chip->ioaddress == NULL) | ||
| 182 | goto err_chip; | ||
| 183 | |||
| 184 | /* Make sure the v3020 expects a communication cycle | ||
| 185 | * by reading 8 times */ | ||
| 186 | for (i = 0; i < 8; i++) | ||
| 187 | temp = readl(chip->ioaddress); | ||
| 188 | |||
| 189 | /* Test chip by doing a write/read sequence | ||
| 190 | * to the chip ram */ | ||
| 191 | v3020_set_reg(chip, V3020_SECONDS, 0x33); | ||
| 192 | if(v3020_get_reg(chip, V3020_SECONDS) != 0x33) { | ||
| 193 | retval = -ENODEV; | ||
| 194 | goto err_io; | ||
| 195 | } | ||
| 196 | |||
| 197 | /* Make sure frequency measurment mode, test modes, and lock | ||
| 198 | * are all disabled */ | ||
| 199 | v3020_set_reg(chip, V3020_STATUS_0, 0x0); | ||
| 200 | |||
| 201 | dev_info(&pdev->dev, "Chip available at physical address 0x%p," | ||
| 202 | "data connected to D%d\n", | ||
| 203 | (void*)pdev->resource[0].start, | ||
| 204 | chip->leftshift); | ||
| 205 | |||
| 206 | platform_set_drvdata(pdev, chip); | ||
| 207 | |||
| 208 | rtc = rtc_device_register("v3020", | ||
| 209 | &pdev->dev, &v3020_rtc_ops, THIS_MODULE); | ||
| 210 | if (IS_ERR(rtc)) { | ||
| 211 | retval = PTR_ERR(rtc); | ||
| 212 | goto err_io; | ||
| 213 | } | ||
| 214 | chip->rtc = rtc; | ||
| 215 | |||
| 216 | return 0; | ||
| 217 | |||
| 218 | err_io: | ||
| 219 | iounmap(chip->ioaddress); | ||
| 220 | err_chip: | ||
| 221 | kfree(chip); | ||
| 222 | |||
| 223 | return retval; | ||
| 224 | } | ||
| 225 | |||
| 226 | static int rtc_remove(struct platform_device *dev) | ||
| 227 | { | ||
| 228 | struct v3020 *chip = platform_get_drvdata(dev); | ||
| 229 | struct rtc_device *rtc = chip->rtc; | ||
| 230 | |||
| 231 | if (rtc) | ||
| 232 | rtc_device_unregister(rtc); | ||
| 233 | |||
| 234 | iounmap(chip->ioaddress); | ||
| 235 | kfree(chip); | ||
| 236 | |||
| 237 | return 0; | ||
| 238 | } | ||
| 239 | |||
| 240 | static struct platform_driver rtc_device_driver = { | ||
| 241 | .probe = rtc_probe, | ||
| 242 | .remove = rtc_remove, | ||
| 243 | .driver = { | ||
| 244 | .name = "v3020", | ||
| 245 | .owner = THIS_MODULE, | ||
| 246 | }, | ||
| 247 | }; | ||
| 248 | |||
| 249 | static __init int v3020_init(void) | ||
| 250 | { | ||
| 251 | return platform_driver_register(&rtc_device_driver); | ||
| 252 | } | ||
| 253 | |||
| 254 | static __exit void v3020_exit(void) | ||
| 255 | { | ||
| 256 | platform_driver_unregister(&rtc_device_driver); | ||
| 257 | } | ||
| 258 | |||
| 259 | module_init(v3020_init); | ||
| 260 | module_exit(v3020_exit); | ||
| 261 | |||
| 262 | MODULE_DESCRIPTION("V3020 RTC"); | ||
| 263 | MODULE_AUTHOR("Raphael Assenat"); | ||
| 264 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index 277596c302e3..4b9291dd4443 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c | |||
| @@ -81,7 +81,6 @@ MODULE_LICENSE("GPL"); | |||
| 81 | 81 | ||
| 82 | #define RTC_FREQUENCY 32768 | 82 | #define RTC_FREQUENCY 32768 |
| 83 | #define MAX_PERIODIC_RATE 6553 | 83 | #define MAX_PERIODIC_RATE 6553 |
| 84 | #define MAX_USER_PERIODIC_RATE 64 | ||
| 85 | 84 | ||
| 86 | static void __iomem *rtc1_base; | 85 | static void __iomem *rtc1_base; |
| 87 | static void __iomem *rtc2_base; | 86 | static void __iomem *rtc2_base; |
| @@ -94,7 +93,7 @@ static void __iomem *rtc2_base; | |||
| 94 | 93 | ||
| 95 | static unsigned long epoch = 1970; /* Jan 1 1970 00:00:00 */ | 94 | static unsigned long epoch = 1970; /* Jan 1 1970 00:00:00 */ |
| 96 | 95 | ||
| 97 | static spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; | 96 | static DEFINE_SPINLOCK(rtc_lock); |
| 98 | static char rtc_name[] = "RTC"; | 97 | static char rtc_name[] = "RTC"; |
| 99 | static unsigned long periodic_frequency; | 98 | static unsigned long periodic_frequency; |
| 100 | static unsigned long periodic_count; | 99 | static unsigned long periodic_count; |
| @@ -240,9 +239,6 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long | |||
| 240 | if (arg > MAX_PERIODIC_RATE) | 239 | if (arg > MAX_PERIODIC_RATE) |
| 241 | return -EINVAL; | 240 | return -EINVAL; |
| 242 | 241 | ||
| 243 | if (arg > MAX_USER_PERIODIC_RATE && capable(CAP_SYS_RESOURCE) == 0) | ||
| 244 | return -EACCES; | ||
| 245 | |||
| 246 | periodic_frequency = arg; | 242 | periodic_frequency = arg; |
| 247 | 243 | ||
| 248 | count = RTC_FREQUENCY; | 244 | count = RTC_FREQUENCY; |
| @@ -263,10 +259,6 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long | |||
| 263 | /* Doesn't support before 1900 */ | 259 | /* Doesn't support before 1900 */ |
| 264 | if (arg < 1900) | 260 | if (arg < 1900) |
| 265 | return -EINVAL; | 261 | return -EINVAL; |
| 266 | |||
| 267 | if (capable(CAP_SYS_TIME) == 0) | ||
| 268 | return -EACCES; | ||
| 269 | |||
| 270 | epoch = arg; | 262 | epoch = arg; |
| 271 | break; | 263 | break; |
| 272 | default: | 264 | default: |
