diff options
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/Kconfig | 141 | ||||
-rw-r--r-- | drivers/rtc/Makefile | 12 | ||||
-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-isl1208.c | 591 | ||||
-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 | 253 | ||||
-rw-r--r-- | drivers/rtc/rtc-s3c.c | 621 | ||||
-rw-r--r-- | drivers/rtc/rtc-sa1100.c | 12 | ||||
-rw-r--r-- | drivers/rtc/rtc-sh.c | 467 | ||||
-rw-r--r-- | drivers/rtc/rtc-v3020.c | 264 | ||||
-rw-r--r-- | drivers/rtc/rtc-vr41xx.c | 16 |
20 files changed, 4888 insertions, 45 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 65d090dbef4..62c804af9fb 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
@@ -15,7 +15,7 @@ config RTC_CLASS | |||
15 | help | 15 | help |
16 | Generic RTC class support. If you say yes here, you will | 16 | Generic RTC class support. If you say yes here, you will |
17 | be allowed to plug one or more RTCs to your system. You will | 17 | be allowed to plug one or more RTCs to your system. You will |
18 | probably want to enable one of more of the interfaces below. | 18 | probably want to enable one or more of the interfaces below. |
19 | 19 | ||
20 | This driver can also be built as a module. If so, the module | 20 | This driver can also be built as a module. If so, the module |
21 | will be called rtc-class. | 21 | will be called rtc-class. |
@@ -27,7 +27,7 @@ config RTC_HCTOSYS | |||
27 | help | 27 | help |
28 | If you say yes here, the system time will be set using | 28 | If you say yes here, the system time will be set using |
29 | the value read from the specified RTC device. This is useful | 29 | the value read from the specified RTC device. This is useful |
30 | in order to avoid unnecessary fschk runs. | 30 | in order to avoid unnecessary fsck runs. |
31 | 31 | ||
32 | config RTC_HCTOSYS_DEVICE | 32 | config RTC_HCTOSYS_DEVICE |
33 | string "The RTC to read the time from" | 33 | string "The RTC to read the time from" |
@@ -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,44 @@ 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 | |||
124 | config RTC_DRV_ISL1208 | ||
125 | tristate "Intersil 1208" | ||
126 | depends on RTC_CLASS && I2C | ||
127 | help | ||
128 | If you say yes here you get support for the | ||
129 | Intersil 1208 RTC chip. | ||
130 | |||
131 | This driver can also be built as a module. If so, the module | ||
132 | will be called rtc-isl1208. | ||
133 | |||
89 | config RTC_DRV_DS1672 | 134 | config RTC_DRV_DS1672 |
90 | tristate "Dallas/Maxim DS1672" | 135 | tristate "Dallas/Maxim DS1672" |
91 | depends on RTC_CLASS && I2C | 136 | depends on RTC_CLASS && I2C |
@@ -96,6 +141,16 @@ config RTC_DRV_DS1672 | |||
96 | This driver can also be built as a module. If so, the module | 141 | This driver can also be built as a module. If so, the module |
97 | will be called rtc-ds1672. | 142 | will be called rtc-ds1672. |
98 | 143 | ||
144 | config RTC_DRV_DS1742 | ||
145 | tristate "Dallas DS1742" | ||
146 | depends on RTC_CLASS | ||
147 | help | ||
148 | If you say yes here you get support for the | ||
149 | Dallas DS1742 timekeeping chip. | ||
150 | |||
151 | This driver can also be built as a module. If so, the module | ||
152 | will be called rtc-ds1742. | ||
153 | |||
99 | config RTC_DRV_PCF8563 | 154 | config RTC_DRV_PCF8563 |
100 | tristate "Philips PCF8563/Epson RTC8564" | 155 | tristate "Philips PCF8563/Epson RTC8564" |
101 | depends on RTC_CLASS && I2C | 156 | depends on RTC_CLASS && I2C |
@@ -107,6 +162,26 @@ config RTC_DRV_PCF8563 | |||
107 | This driver can also be built as a module. If so, the module | 162 | This driver can also be built as a module. If so, the module |
108 | will be called rtc-pcf8563. | 163 | will be called rtc-pcf8563. |
109 | 164 | ||
165 | config RTC_DRV_PCF8583 | ||
166 | tristate "Philips PCF8583" | ||
167 | depends on RTC_CLASS && I2C | ||
168 | help | ||
169 | If you say yes here you get support for the | ||
170 | Philips PCF8583 RTC chip. | ||
171 | |||
172 | This driver can also be built as a module. If so, the module | ||
173 | will be called rtc-pcf8583. | ||
174 | |||
175 | config RTC_DRV_RS5C348 | ||
176 | tristate "Ricoh RS5C348A/B" | ||
177 | depends on RTC_CLASS && SPI | ||
178 | help | ||
179 | If you say yes here you get support for the | ||
180 | Ricoh RS5C348A and RS5C348B RTC chips. | ||
181 | |||
182 | This driver can also be built as a module. If so, the module | ||
183 | will be called rtc-rs5c348. | ||
184 | |||
110 | config RTC_DRV_RS5C372 | 185 | config RTC_DRV_RS5C372 |
111 | tristate "Ricoh RS5C372A/B" | 186 | tristate "Ricoh RS5C372A/B" |
112 | depends on RTC_CLASS && I2C | 187 | depends on RTC_CLASS && I2C |
@@ -117,6 +192,22 @@ config RTC_DRV_RS5C372 | |||
117 | This driver can also be built as a module. If so, the module | 192 | This driver can also be built as a module. If so, the module |
118 | will be called rtc-rs5c372. | 193 | will be called rtc-rs5c372. |
119 | 194 | ||
195 | config RTC_DRV_S3C | ||
196 | tristate "Samsung S3C series SoC RTC" | ||
197 | depends on RTC_CLASS && ARCH_S3C2410 | ||
198 | help | ||
199 | RTC (Realtime Clock) driver for the clock inbuilt into the | ||
200 | Samsung S3C24XX series of SoCs. This can provide periodic | ||
201 | interrupt rates from 1Hz to 64Hz for user programs, and | ||
202 | wakeup from Alarm. | ||
203 | |||
204 | The driver currently supports the common features on all the | ||
205 | S3C24XX range, such as the S3C2410, S3C2412, S3C2413, S3C2440 | ||
206 | and S3C2442. | ||
207 | |||
208 | This driver can also be build as a module. If so, the module | ||
209 | will be called rtc-s3c. | ||
210 | |||
120 | config RTC_DRV_M48T86 | 211 | config RTC_DRV_M48T86 |
121 | tristate "ST M48T86/Dallas DS12887" | 212 | tristate "ST M48T86/Dallas DS12887" |
122 | depends on RTC_CLASS | 213 | depends on RTC_CLASS |
@@ -147,6 +238,16 @@ config RTC_DRV_SA1100 | |||
147 | To compile this driver as a module, choose M here: the | 238 | To compile this driver as a module, choose M here: the |
148 | module will be called rtc-sa1100. | 239 | module will be called rtc-sa1100. |
149 | 240 | ||
241 | config RTC_DRV_SH | ||
242 | tristate "SuperH On-Chip RTC" | ||
243 | depends on RTC_CLASS && SUPERH | ||
244 | help | ||
245 | Say Y here to enable support for the on-chip RTC found in | ||
246 | most SuperH processors. | ||
247 | |||
248 | To compile this driver as a module, choose M here: the | ||
249 | module will be called rtc-sh. | ||
250 | |||
150 | config RTC_DRV_VR41XX | 251 | config RTC_DRV_VR41XX |
151 | tristate "NEC VR41XX" | 252 | tristate "NEC VR41XX" |
152 | depends on RTC_CLASS && CPU_VR41XX | 253 | depends on RTC_CLASS && CPU_VR41XX |
@@ -157,6 +258,22 @@ config RTC_DRV_VR41XX | |||
157 | To compile this driver as a module, choose M here: the | 258 | To compile this driver as a module, choose M here: the |
158 | module will be called rtc-vr41xx. | 259 | module will be called rtc-vr41xx. |
159 | 260 | ||
261 | config RTC_DRV_PL031 | ||
262 | tristate "ARM AMBA PL031 RTC" | ||
263 | depends on RTC_CLASS && ARM_AMBA | ||
264 | help | ||
265 | If you say Y here you will get access to ARM AMBA | ||
266 | PrimeCell PL031 UART found on certain ARM SOCs. | ||
267 | |||
268 | To compile this driver as a module, choose M here: the | ||
269 | module will be called rtc-pl031. | ||
270 | |||
271 | config RTC_DRV_AT91 | ||
272 | tristate "AT91RM9200" | ||
273 | depends on RTC_CLASS && ARCH_AT91RM9200 | ||
274 | help | ||
275 | Driver for the Atmel AT91RM9200's internal RTC (Realtime Clock). | ||
276 | |||
160 | config RTC_DRV_TEST | 277 | config RTC_DRV_TEST |
161 | tristate "Test driver/device" | 278 | tristate "Test driver/device" |
162 | depends on RTC_CLASS | 279 | depends on RTC_CLASS |
@@ -172,4 +289,24 @@ config RTC_DRV_TEST | |||
172 | This driver can also be built as a module. If so, the module | 289 | This driver can also be built as a module. If so, the module |
173 | will be called rtc-test. | 290 | will be called rtc-test. |
174 | 291 | ||
292 | config RTC_DRV_MAX6902 | ||
293 | tristate "Maxim 6902" | ||
294 | depends on RTC_CLASS && SPI | ||
295 | help | ||
296 | If you say yes here you will get support for the | ||
297 | Maxim MAX6902 spi RTC chip. | ||
298 | |||
299 | This driver can also be built as a module. If so, the module | ||
300 | will be called rtc-max6902. | ||
301 | |||
302 | config RTC_DRV_V3020 | ||
303 | tristate "EM Microelectronic V3020" | ||
304 | depends on RTC_CLASS | ||
305 | help | ||
306 | If you say yes here you will get support for the | ||
307 | EM Microelectronic v3020 RTC chip. | ||
308 | |||
309 | This driver can also be built as a module. If so, the module | ||
310 | will be called rtc-v3020. | ||
311 | |||
175 | endmenu | 312 | endmenu |
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index a9ca0f17168..e72d467ab21 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile | |||
@@ -12,11 +12,23 @@ obj-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o | |||
12 | obj-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o | 12 | 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_ISL1208) += rtc-isl1208.o | ||
15 | obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o | 16 | obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o |
17 | obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o | ||
16 | obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o | 18 | obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o |
19 | obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o | ||
17 | obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o | 20 | obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o |
21 | obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o | ||
18 | obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o | 22 | obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o |
23 | obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o | ||
24 | obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o | ||
19 | obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o | 25 | obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o |
26 | obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o | ||
20 | obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o | 27 | obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o |
21 | obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o | 28 | obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o |
22 | obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o | 29 | obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o |
30 | obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o | ||
31 | obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o | ||
32 | obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o | ||
33 | obj-$(CONFIG_RTC_DRV_AT91) += rtc-at91.o | ||
34 | obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o | ||
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 413c7d54ea1..1cb61a761cb 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 56e490709b8..579cd667b16 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 00000000000..dfd0ce86f6a --- /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 | IRQF_SHARED, "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 2011567005f..61a58259c93 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 00000000000..e8afb938478 --- /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 00000000000..20900149547 --- /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, IRQF_SHARED, | ||
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 00000000000..8e47e5a06d2 --- /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-isl1208.c b/drivers/rtc/rtc-isl1208.c new file mode 100644 index 00000000000..f324d0a635d --- /dev/null +++ b/drivers/rtc/rtc-isl1208.c | |||
@@ -0,0 +1,591 @@ | |||
1 | /* | ||
2 | * Intersil ISL1208 rtc class driver | ||
3 | * | ||
4 | * Copyright 2005,2006 Hebert Valerio Riedel <hvr@gnu.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/i2c.h> | ||
15 | #include <linux/bcd.h> | ||
16 | #include <linux/rtc.h> | ||
17 | |||
18 | #define DRV_NAME "isl1208" | ||
19 | #define DRV_VERSION "0.2" | ||
20 | |||
21 | /* Register map */ | ||
22 | /* rtc section */ | ||
23 | #define ISL1208_REG_SC 0x00 | ||
24 | #define ISL1208_REG_MN 0x01 | ||
25 | #define ISL1208_REG_HR 0x02 | ||
26 | #define ISL1208_REG_HR_MIL (1<<7) /* 24h/12h mode */ | ||
27 | #define ISL1208_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */ | ||
28 | #define ISL1208_REG_DT 0x03 | ||
29 | #define ISL1208_REG_MO 0x04 | ||
30 | #define ISL1208_REG_YR 0x05 | ||
31 | #define ISL1208_REG_DW 0x06 | ||
32 | #define ISL1208_RTC_SECTION_LEN 7 | ||
33 | |||
34 | /* control/status section */ | ||
35 | #define ISL1208_REG_SR 0x07 | ||
36 | #define ISL1208_REG_SR_ARST (1<<7) /* auto reset */ | ||
37 | #define ISL1208_REG_SR_XTOSCB (1<<6) /* crystal oscillator */ | ||
38 | #define ISL1208_REG_SR_WRTC (1<<4) /* write rtc */ | ||
39 | #define ISL1208_REG_SR_ALM (1<<2) /* alarm */ | ||
40 | #define ISL1208_REG_SR_BAT (1<<1) /* battery */ | ||
41 | #define ISL1208_REG_SR_RTCF (1<<0) /* rtc fail */ | ||
42 | #define ISL1208_REG_INT 0x08 | ||
43 | #define ISL1208_REG_09 0x09 /* reserved */ | ||
44 | #define ISL1208_REG_ATR 0x0a | ||
45 | #define ISL1208_REG_DTR 0x0b | ||
46 | |||
47 | /* alarm section */ | ||
48 | #define ISL1208_REG_SCA 0x0c | ||
49 | #define ISL1208_REG_MNA 0x0d | ||
50 | #define ISL1208_REG_HRA 0x0e | ||
51 | #define ISL1208_REG_DTA 0x0f | ||
52 | #define ISL1208_REG_MOA 0x10 | ||
53 | #define ISL1208_REG_DWA 0x11 | ||
54 | #define ISL1208_ALARM_SECTION_LEN 6 | ||
55 | |||
56 | /* user section */ | ||
57 | #define ISL1208_REG_USR1 0x12 | ||
58 | #define ISL1208_REG_USR2 0x13 | ||
59 | #define ISL1208_USR_SECTION_LEN 2 | ||
60 | |||
61 | /* i2c configuration */ | ||
62 | #define ISL1208_I2C_ADDR 0xde | ||
63 | |||
64 | static unsigned short normal_i2c[] = { | ||
65 | ISL1208_I2C_ADDR>>1, I2C_CLIENT_END | ||
66 | }; | ||
67 | I2C_CLIENT_INSMOD; /* defines addr_data */ | ||
68 | |||
69 | static int isl1208_attach_adapter(struct i2c_adapter *adapter); | ||
70 | static int isl1208_detach_client(struct i2c_client *client); | ||
71 | |||
72 | static struct i2c_driver isl1208_driver = { | ||
73 | .driver = { | ||
74 | .name = DRV_NAME, | ||
75 | }, | ||
76 | .id = I2C_DRIVERID_ISL1208, | ||
77 | .attach_adapter = &isl1208_attach_adapter, | ||
78 | .detach_client = &isl1208_detach_client, | ||
79 | }; | ||
80 | |||
81 | /* block read */ | ||
82 | static int | ||
83 | isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[], | ||
84 | unsigned len) | ||
85 | { | ||
86 | u8 reg_addr[1] = { reg }; | ||
87 | struct i2c_msg msgs[2] = { | ||
88 | { client->addr, client->flags, sizeof(reg_addr), reg_addr }, | ||
89 | { client->addr, client->flags | I2C_M_RD, len, buf } | ||
90 | }; | ||
91 | int ret; | ||
92 | |||
93 | BUG_ON(len == 0); | ||
94 | BUG_ON(reg > ISL1208_REG_USR2); | ||
95 | BUG_ON(reg + len > ISL1208_REG_USR2 + 1); | ||
96 | |||
97 | ret = i2c_transfer(client->adapter, msgs, 2); | ||
98 | if (ret > 0) | ||
99 | ret = 0; | ||
100 | return ret; | ||
101 | } | ||
102 | |||
103 | /* block write */ | ||
104 | static int | ||
105 | isl1208_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[], | ||
106 | unsigned len) | ||
107 | { | ||
108 | u8 i2c_buf[ISL1208_REG_USR2 + 2]; | ||
109 | struct i2c_msg msgs[1] = { | ||
110 | { client->addr, client->flags, len + 1, i2c_buf } | ||
111 | }; | ||
112 | int ret; | ||
113 | |||
114 | BUG_ON(len == 0); | ||
115 | BUG_ON(reg > ISL1208_REG_USR2); | ||
116 | BUG_ON(reg + len > ISL1208_REG_USR2 + 1); | ||
117 | |||
118 | i2c_buf[0] = reg; | ||
119 | memcpy(&i2c_buf[1], &buf[0], len); | ||
120 | |||
121 | ret = i2c_transfer(client->adapter, msgs, 1); | ||
122 | if (ret > 0) | ||
123 | ret = 0; | ||
124 | return ret; | ||
125 | } | ||
126 | |||
127 | /* simple check to see wether we have a isl1208 */ | ||
128 | static int isl1208_i2c_validate_client(struct i2c_client *client) | ||
129 | { | ||
130 | u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, }; | ||
131 | u8 zero_mask[ISL1208_RTC_SECTION_LEN] = { | ||
132 | 0x80, 0x80, 0x40, 0xc0, 0xe0, 0x00, 0xf8 | ||
133 | }; | ||
134 | int i; | ||
135 | int ret; | ||
136 | |||
137 | ret = isl1208_i2c_read_regs(client, 0, regs, ISL1208_RTC_SECTION_LEN); | ||
138 | if (ret < 0) | ||
139 | return ret; | ||
140 | |||
141 | for (i = 0; i < ISL1208_RTC_SECTION_LEN; ++i) { | ||
142 | if (regs[i] & zero_mask[i]) /* check if bits are cleared */ | ||
143 | return -ENODEV; | ||
144 | } | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static int isl1208_i2c_get_sr(struct i2c_client *client) | ||
150 | { | ||
151 | return i2c_smbus_read_byte_data(client, ISL1208_REG_SR) == -1 ? -EIO:0; | ||
152 | } | ||
153 | |||
154 | static int isl1208_i2c_get_atr(struct i2c_client *client) | ||
155 | { | ||
156 | int atr = i2c_smbus_read_byte_data(client, ISL1208_REG_ATR); | ||
157 | |||
158 | if (atr < 0) | ||
159 | return -EIO; | ||
160 | |||
161 | /* The 6bit value in the ATR register controls the load | ||
162 | * capacitance C_load * in steps of 0.25pF | ||
163 | * | ||
164 | * bit (1<<5) of the ATR register is inverted | ||
165 | * | ||
166 | * C_load(ATR=0x20) = 4.50pF | ||
167 | * C_load(ATR=0x00) = 12.50pF | ||
168 | * C_load(ATR=0x1f) = 20.25pF | ||
169 | * | ||
170 | */ | ||
171 | |||
172 | atr &= 0x3f; /* mask out lsb */ | ||
173 | atr ^= 1<<5; /* invert 6th bit */ | ||
174 | atr += 2*9; /* add offset of 4.5pF; unit[atr] = 0.25pF */ | ||
175 | |||
176 | return atr; | ||
177 | } | ||
178 | |||
179 | static int isl1208_i2c_get_dtr(struct i2c_client *client) | ||
180 | { | ||
181 | int dtr = i2c_smbus_read_byte_data(client, ISL1208_REG_DTR); | ||
182 | |||
183 | if (dtr < 0) | ||
184 | return -EIO; | ||
185 | |||
186 | /* dtr encodes adjustments of {-60,-40,-20,0,20,40,60} ppm */ | ||
187 | dtr = ((dtr & 0x3) * 20) * (dtr & (1<<2) ? -1 : 1); | ||
188 | |||
189 | return dtr; | ||
190 | } | ||
191 | |||
192 | static int isl1208_i2c_get_usr(struct i2c_client *client) | ||
193 | { | ||
194 | u8 buf[ISL1208_USR_SECTION_LEN] = { 0, }; | ||
195 | int ret; | ||
196 | |||
197 | ret = isl1208_i2c_read_regs (client, ISL1208_REG_USR1, buf, | ||
198 | ISL1208_USR_SECTION_LEN); | ||
199 | if (ret < 0) | ||
200 | return ret; | ||
201 | |||
202 | return (buf[1] << 8) | buf[0]; | ||
203 | } | ||
204 | |||
205 | static int isl1208_i2c_set_usr(struct i2c_client *client, u16 usr) | ||
206 | { | ||
207 | u8 buf[ISL1208_USR_SECTION_LEN]; | ||
208 | |||
209 | buf[0] = usr & 0xff; | ||
210 | buf[1] = (usr >> 8) & 0xff; | ||
211 | |||
212 | return isl1208_i2c_set_regs (client, ISL1208_REG_USR1, buf, | ||
213 | ISL1208_USR_SECTION_LEN); | ||
214 | } | ||
215 | |||
216 | static int isl1208_rtc_proc(struct device *dev, struct seq_file *seq) | ||
217 | { | ||
218 | struct i2c_client *const client = to_i2c_client(dev); | ||
219 | int sr, dtr, atr, usr; | ||
220 | |||
221 | sr = isl1208_i2c_get_sr(client); | ||
222 | if (sr < 0) { | ||
223 | dev_err(&client->dev, "%s: reading SR failed\n", __func__); | ||
224 | return sr; | ||
225 | } | ||
226 | |||
227 | seq_printf(seq, "status_reg\t:%s%s%s%s%s%s (0x%.2x)\n", | ||
228 | (sr & ISL1208_REG_SR_RTCF) ? " RTCF" : "", | ||
229 | (sr & ISL1208_REG_SR_BAT) ? " BAT" : "", | ||
230 | (sr & ISL1208_REG_SR_ALM) ? " ALM" : "", | ||
231 | (sr & ISL1208_REG_SR_WRTC) ? " WRTC" : "", | ||
232 | (sr & ISL1208_REG_SR_XTOSCB) ? " XTOSCB" : "", | ||
233 | (sr & ISL1208_REG_SR_ARST) ? " ARST" : "", | ||
234 | sr); | ||
235 | |||
236 | seq_printf(seq, "batt_status\t: %s\n", | ||
237 | (sr & ISL1208_REG_SR_RTCF) ? "bad" : "okay"); | ||
238 | |||
239 | dtr = isl1208_i2c_get_dtr(client); | ||
240 | if (dtr >= 0 -1) | ||
241 | seq_printf(seq, "digital_trim\t: %d ppm\n", dtr); | ||
242 | |||
243 | atr = isl1208_i2c_get_atr(client); | ||
244 | if (atr >= 0) | ||
245 | seq_printf(seq, "analog_trim\t: %d.%.2d pF\n", | ||
246 | atr>>2, (atr&0x3)*25); | ||
247 | |||
248 | usr = isl1208_i2c_get_usr(client); | ||
249 | if (usr >= 0) | ||
250 | seq_printf(seq, "user_data\t: 0x%.4x\n", usr); | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | |||
256 | static int isl1208_i2c_read_time(struct i2c_client *client, | ||
257 | struct rtc_time *tm) | ||
258 | { | ||
259 | int sr; | ||
260 | u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, }; | ||
261 | |||
262 | sr = isl1208_i2c_get_sr(client); | ||
263 | if (sr < 0) { | ||
264 | dev_err(&client->dev, "%s: reading SR failed\n", __func__); | ||
265 | return -EIO; | ||
266 | } | ||
267 | |||
268 | sr = isl1208_i2c_read_regs(client, 0, regs, ISL1208_RTC_SECTION_LEN); | ||
269 | if (sr < 0) { | ||
270 | dev_err(&client->dev, "%s: reading RTC section failed\n", | ||
271 | __func__); | ||
272 | return sr; | ||
273 | } | ||
274 | |||
275 | tm->tm_sec = BCD2BIN(regs[ISL1208_REG_SC]); | ||
276 | tm->tm_min = BCD2BIN(regs[ISL1208_REG_MN]); | ||
277 | { /* HR field has a more complex interpretation */ | ||
278 | const u8 _hr = regs[ISL1208_REG_HR]; | ||
279 | if (_hr & ISL1208_REG_HR_MIL) /* 24h format */ | ||
280 | tm->tm_hour = BCD2BIN(_hr & 0x3f); | ||
281 | else { // 12h format | ||
282 | tm->tm_hour = BCD2BIN(_hr & 0x1f); | ||
283 | if (_hr & ISL1208_REG_HR_PM) /* PM flag set */ | ||
284 | tm->tm_hour += 12; | ||
285 | } | ||
286 | } | ||
287 | |||
288 | tm->tm_mday = BCD2BIN(regs[ISL1208_REG_DT]); | ||
289 | tm->tm_mon = BCD2BIN(regs[ISL1208_REG_MO]) - 1; /* rtc starts at 1 */ | ||
290 | tm->tm_year = BCD2BIN(regs[ISL1208_REG_YR]) + 100; | ||
291 | tm->tm_wday = BCD2BIN(regs[ISL1208_REG_DW]); | ||
292 | |||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | static int isl1208_i2c_read_alarm(struct i2c_client *client, | ||
297 | struct rtc_wkalrm *alarm) | ||
298 | { | ||
299 | struct rtc_time *const tm = &alarm->time; | ||
300 | u8 regs[ISL1208_ALARM_SECTION_LEN] = { 0, }; | ||
301 | int sr; | ||
302 | |||
303 | sr = isl1208_i2c_get_sr(client); | ||
304 | if (sr < 0) { | ||
305 | dev_err(&client->dev, "%s: reading SR failed\n", __func__); | ||
306 | return sr; | ||
307 | } | ||
308 | |||
309 | sr = isl1208_i2c_read_regs(client, ISL1208_REG_SCA, regs, | ||
310 | ISL1208_ALARM_SECTION_LEN); | ||
311 | if (sr < 0) { | ||
312 | dev_err(&client->dev, "%s: reading alarm section failed\n", | ||
313 | __func__); | ||
314 | return sr; | ||
315 | } | ||
316 | |||
317 | /* MSB of each alarm register is an enable bit */ | ||
318 | tm->tm_sec = BCD2BIN(regs[ISL1208_REG_SCA-ISL1208_REG_SCA] & 0x7f); | ||
319 | tm->tm_min = BCD2BIN(regs[ISL1208_REG_MNA-ISL1208_REG_SCA] & 0x7f); | ||
320 | tm->tm_hour = BCD2BIN(regs[ISL1208_REG_HRA-ISL1208_REG_SCA] & 0x3f); | ||
321 | tm->tm_mday = BCD2BIN(regs[ISL1208_REG_DTA-ISL1208_REG_SCA] & 0x3f); | ||
322 | tm->tm_mon = BCD2BIN(regs[ISL1208_REG_MOA-ISL1208_REG_SCA] & 0x1f)-1; | ||
323 | tm->tm_wday = BCD2BIN(regs[ISL1208_REG_DWA-ISL1208_REG_SCA] & 0x03); | ||
324 | |||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | static int isl1208_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
329 | { | ||
330 | return isl1208_i2c_read_time(to_i2c_client(dev), tm); | ||
331 | } | ||
332 | |||
333 | static int isl1208_i2c_set_time(struct i2c_client *client, | ||
334 | struct rtc_time const *tm) | ||
335 | { | ||
336 | int sr; | ||
337 | u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, }; | ||
338 | |||
339 | regs[ISL1208_REG_SC] = BIN2BCD(tm->tm_sec); | ||
340 | regs[ISL1208_REG_MN] = BIN2BCD(tm->tm_min); | ||
341 | regs[ISL1208_REG_HR] = BIN2BCD(tm->tm_hour) | ISL1208_REG_HR_MIL; | ||
342 | |||
343 | regs[ISL1208_REG_DT] = BIN2BCD(tm->tm_mday); | ||
344 | regs[ISL1208_REG_MO] = BIN2BCD(tm->tm_mon + 1); | ||
345 | regs[ISL1208_REG_YR] = BIN2BCD(tm->tm_year - 100); | ||
346 | |||
347 | regs[ISL1208_REG_DW] = BIN2BCD(tm->tm_wday & 7); | ||
348 | |||
349 | sr = isl1208_i2c_get_sr(client); | ||
350 | if (sr < 0) { | ||
351 | dev_err(&client->dev, "%s: reading SR failed\n", __func__); | ||
352 | return sr; | ||
353 | } | ||
354 | |||
355 | /* set WRTC */ | ||
356 | sr = i2c_smbus_write_byte_data (client, ISL1208_REG_SR, | ||
357 | sr | ISL1208_REG_SR_WRTC); | ||
358 | if (sr < 0) { | ||
359 | dev_err(&client->dev, "%s: writing SR failed\n", __func__); | ||
360 | return sr; | ||
361 | } | ||
362 | |||
363 | /* write RTC registers */ | ||
364 | sr = isl1208_i2c_set_regs(client, 0, regs, ISL1208_RTC_SECTION_LEN); | ||
365 | if (sr < 0) { | ||
366 | dev_err(&client->dev, "%s: writing RTC section failed\n", | ||
367 | __func__); | ||
368 | return sr; | ||
369 | } | ||
370 | |||
371 | /* clear WRTC again */ | ||
372 | sr = i2c_smbus_write_byte_data (client, ISL1208_REG_SR, | ||
373 | sr & ~ISL1208_REG_SR_WRTC); | ||
374 | if (sr < 0) { | ||
375 | dev_err(&client->dev, "%s: writing SR failed\n", __func__); | ||
376 | return sr; | ||
377 | } | ||
378 | |||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | |||
383 | static int isl1208_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
384 | { | ||
385 | return isl1208_i2c_set_time(to_i2c_client(dev), tm); | ||
386 | } | ||
387 | |||
388 | static int isl1208_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) | ||
389 | { | ||
390 | return isl1208_i2c_read_alarm(to_i2c_client(dev), alarm); | ||
391 | } | ||
392 | |||
393 | static struct rtc_class_ops isl1208_rtc_ops = { | ||
394 | .proc = isl1208_rtc_proc, | ||
395 | .read_time = isl1208_rtc_read_time, | ||
396 | .set_time = isl1208_rtc_set_time, | ||
397 | .read_alarm = isl1208_rtc_read_alarm, | ||
398 | //.set_alarm = isl1208_rtc_set_alarm, | ||
399 | }; | ||
400 | |||
401 | /* sysfs interface */ | ||
402 | |||
403 | static ssize_t isl1208_sysfs_show_atrim(struct device *dev, | ||
404 | struct device_attribute *attr, | ||
405 | char *buf) | ||
406 | { | ||
407 | int atr; | ||
408 | |||
409 | atr = isl1208_i2c_get_atr(to_i2c_client(dev)); | ||
410 | if (atr < 0) | ||
411 | return atr; | ||
412 | |||
413 | return sprintf(buf, "%d.%.2d pF\n", atr>>2, (atr&0x3)*25); | ||
414 | } | ||
415 | static DEVICE_ATTR(atrim, S_IRUGO, isl1208_sysfs_show_atrim, NULL); | ||
416 | |||
417 | static ssize_t isl1208_sysfs_show_dtrim(struct device *dev, | ||
418 | struct device_attribute *attr, | ||
419 | char *buf) | ||
420 | { | ||
421 | int dtr; | ||
422 | |||
423 | dtr = isl1208_i2c_get_dtr(to_i2c_client(dev)); | ||
424 | if (dtr < 0) | ||
425 | return dtr; | ||
426 | |||
427 | return sprintf(buf, "%d ppm\n", dtr); | ||
428 | } | ||
429 | static DEVICE_ATTR(dtrim, S_IRUGO, isl1208_sysfs_show_dtrim, NULL); | ||
430 | |||
431 | static ssize_t isl1208_sysfs_show_usr(struct device *dev, | ||
432 | struct device_attribute *attr, | ||
433 | char *buf) | ||
434 | { | ||
435 | int usr; | ||
436 | |||
437 | usr = isl1208_i2c_get_usr(to_i2c_client(dev)); | ||
438 | if (usr < 0) | ||
439 | return usr; | ||
440 | |||
441 | return sprintf(buf, "0x%.4x\n", usr); | ||
442 | } | ||
443 | |||
444 | static ssize_t isl1208_sysfs_store_usr(struct device *dev, | ||
445 | struct device_attribute *attr, | ||
446 | const char *buf, size_t count) | ||
447 | { | ||
448 | int usr = -1; | ||
449 | |||
450 | if (buf[0] == '0' && (buf[1] == 'x' || buf[1] == 'X')) { | ||
451 | if (sscanf(buf, "%x", &usr) != 1) | ||
452 | return -EINVAL; | ||
453 | } else { | ||
454 | if (sscanf(buf, "%d", &usr) != 1) | ||
455 | return -EINVAL; | ||
456 | } | ||
457 | |||
458 | if (usr < 0 || usr > 0xffff) | ||
459 | return -EINVAL; | ||
460 | |||
461 | return isl1208_i2c_set_usr(to_i2c_client(dev), usr) ? -EIO : count; | ||
462 | } | ||
463 | static DEVICE_ATTR(usr, S_IRUGO | S_IWUSR, isl1208_sysfs_show_usr, | ||
464 | isl1208_sysfs_store_usr); | ||
465 | |||
466 | static int | ||
467 | isl1208_probe(struct i2c_adapter *adapter, int addr, int kind) | ||
468 | { | ||
469 | int rc = 0; | ||
470 | struct i2c_client *new_client = NULL; | ||
471 | struct rtc_device *rtc = NULL; | ||
472 | |||
473 | if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { | ||
474 | rc = -ENODEV; | ||
475 | goto failout; | ||
476 | } | ||
477 | |||
478 | new_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); | ||
479 | if (new_client == NULL) { | ||
480 | rc = -ENOMEM; | ||
481 | goto failout; | ||
482 | } | ||
483 | |||
484 | new_client->addr = addr; | ||
485 | new_client->adapter = adapter; | ||
486 | new_client->driver = &isl1208_driver; | ||
487 | new_client->flags = 0; | ||
488 | strcpy(new_client->name, DRV_NAME); | ||
489 | |||
490 | if (kind < 0) { | ||
491 | rc = isl1208_i2c_validate_client(new_client); | ||
492 | if (rc < 0) | ||
493 | goto failout; | ||
494 | } | ||
495 | |||
496 | rc = i2c_attach_client(new_client); | ||
497 | if (rc < 0) | ||
498 | goto failout; | ||
499 | |||
500 | dev_info(&new_client->dev, | ||
501 | "chip found, driver version " DRV_VERSION "\n"); | ||
502 | |||
503 | rtc = rtc_device_register(isl1208_driver.driver.name, | ||
504 | &new_client->dev, | ||
505 | &isl1208_rtc_ops, THIS_MODULE); | ||
506 | |||
507 | if (IS_ERR(rtc)) { | ||
508 | rc = PTR_ERR(rtc); | ||
509 | goto failout_detach; | ||
510 | } | ||
511 | |||
512 | i2c_set_clientdata(new_client, rtc); | ||
513 | |||
514 | rc = isl1208_i2c_get_sr(new_client); | ||
515 | if (rc < 0) { | ||
516 | dev_err(&new_client->dev, "reading status failed\n"); | ||
517 | goto failout_unregister; | ||
518 | } | ||
519 | |||
520 | if (rc & ISL1208_REG_SR_RTCF) | ||
521 | dev_warn(&new_client->dev, "rtc power failure detected, " | ||
522 | "please set clock.\n"); | ||
523 | |||
524 | rc = device_create_file(&new_client->dev, &dev_attr_atrim); | ||
525 | if (rc < 0) | ||
526 | goto failout_unregister; | ||
527 | rc = device_create_file(&new_client->dev, &dev_attr_dtrim); | ||
528 | if (rc < 0) | ||
529 | goto failout_atrim; | ||
530 | rc = device_create_file(&new_client->dev, &dev_attr_usr); | ||
531 | if (rc < 0) | ||
532 | goto failout_dtrim; | ||
533 | |||
534 | return 0; | ||
535 | |||
536 | failout_dtrim: | ||
537 | device_remove_file(&new_client->dev, &dev_attr_dtrim); | ||
538 | failout_atrim: | ||
539 | device_remove_file(&new_client->dev, &dev_attr_atrim); | ||
540 | failout_unregister: | ||
541 | rtc_device_unregister(rtc); | ||
542 | failout_detach: | ||
543 | i2c_detach_client(new_client); | ||
544 | failout: | ||
545 | kfree(new_client); | ||
546 | return rc; | ||
547 | } | ||
548 | |||
549 | static int | ||
550 | isl1208_attach_adapter (struct i2c_adapter *adapter) | ||
551 | { | ||
552 | return i2c_probe(adapter, &addr_data, isl1208_probe); | ||
553 | } | ||
554 | |||
555 | static int | ||
556 | isl1208_detach_client(struct i2c_client *client) | ||
557 | { | ||
558 | int rc; | ||
559 | struct rtc_device *const rtc = i2c_get_clientdata(client); | ||
560 | |||
561 | if (rtc) | ||
562 | rtc_device_unregister(rtc); /* do we need to kfree? */ | ||
563 | |||
564 | rc = i2c_detach_client(client); | ||
565 | if (rc) | ||
566 | return rc; | ||
567 | |||
568 | kfree(client); | ||
569 | |||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | /* module management */ | ||
574 | |||
575 | static int __init isl1208_init(void) | ||
576 | { | ||
577 | return i2c_add_driver(&isl1208_driver); | ||
578 | } | ||
579 | |||
580 | static void __exit isl1208_exit(void) | ||
581 | { | ||
582 | i2c_del_driver(&isl1208_driver); | ||
583 | } | ||
584 | |||
585 | MODULE_AUTHOR("Herbert Valerio Riedel <hvr@gnu.org>"); | ||
586 | MODULE_DESCRIPTION("Intersil ISL1208 RTC driver"); | ||
587 | MODULE_LICENSE("GPL"); | ||
588 | MODULE_VERSION(DRV_VERSION); | ||
589 | |||
590 | module_init(isl1208_init); | ||
591 | module_exit(isl1208_exit); | ||
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c index cfedc1d28ee..9812120f3a7 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 00000000000..2c9739562b5 --- /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 00000000000..b235a30cb66 --- /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 00000000000..d6d1c5726b0 --- /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, IRQF_DISABLED, | ||
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 00000000000..25589061f93 --- /dev/null +++ b/drivers/rtc/rtc-rs5c348.c | |||
@@ -0,0 +1,253 @@ | |||
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.2" | ||
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 | struct rtc_time tm; | ||
179 | if (ret & RS5C348_BIT_VDET) | ||
180 | dev_warn(&spi->dev, "voltage-low detected.\n"); | ||
181 | if (ret & RS5C348_BIT_XSTP) | ||
182 | dev_warn(&spi->dev, "oscillator-stop detected.\n"); | ||
183 | rtc_time_to_tm(0, &tm); /* 1970/1/1 */ | ||
184 | ret = rs5c348_rtc_set_time(&spi->dev, &tm); | ||
185 | if (ret < 0) | ||
186 | goto kfree_exit; | ||
187 | buf[0] = RS5C348_CMD_W(RS5C348_REG_CTL2); | ||
188 | buf[1] = 0; | ||
189 | ret = spi_write_then_read(spi, buf, sizeof(buf), NULL, 0); | ||
190 | if (ret < 0) | ||
191 | goto kfree_exit; | ||
192 | } | ||
193 | |||
194 | ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_CTL1)); | ||
195 | if (ret < 0) | ||
196 | goto kfree_exit; | ||
197 | if (ret & RS5C348_BIT_24H) | ||
198 | pdata->rtc_24h = 1; | ||
199 | |||
200 | rtc = rtc_device_register(rs5c348_driver.driver.name, &spi->dev, | ||
201 | &rs5c348_rtc_ops, THIS_MODULE); | ||
202 | |||
203 | if (IS_ERR(rtc)) { | ||
204 | ret = PTR_ERR(rtc); | ||
205 | goto kfree_exit; | ||
206 | } | ||
207 | |||
208 | pdata->rtc = rtc; | ||
209 | |||
210 | return 0; | ||
211 | kfree_exit: | ||
212 | kfree(pdata); | ||
213 | return ret; | ||
214 | } | ||
215 | |||
216 | static int __devexit rs5c348_remove(struct spi_device *spi) | ||
217 | { | ||
218 | struct rs5c348_plat_data *pdata = spi->dev.platform_data; | ||
219 | struct rtc_device *rtc = pdata->rtc; | ||
220 | |||
221 | if (rtc) | ||
222 | rtc_device_unregister(rtc); | ||
223 | kfree(pdata); | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static struct spi_driver rs5c348_driver = { | ||
228 | .driver = { | ||
229 | .name = "rs5c348", | ||
230 | .bus = &spi_bus_type, | ||
231 | .owner = THIS_MODULE, | ||
232 | }, | ||
233 | .probe = rs5c348_probe, | ||
234 | .remove = __devexit_p(rs5c348_remove), | ||
235 | }; | ||
236 | |||
237 | static __init int rs5c348_init(void) | ||
238 | { | ||
239 | return spi_register_driver(&rs5c348_driver); | ||
240 | } | ||
241 | |||
242 | static __exit void rs5c348_exit(void) | ||
243 | { | ||
244 | spi_unregister_driver(&rs5c348_driver); | ||
245 | } | ||
246 | |||
247 | module_init(rs5c348_init); | ||
248 | module_exit(rs5c348_exit); | ||
249 | |||
250 | MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>"); | ||
251 | MODULE_DESCRIPTION("Ricoh RS5C348 RTC driver"); | ||
252 | MODULE_LICENSE("GPL"); | ||
253 | MODULE_VERSION(DRV_VERSION); | ||
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c new file mode 100644 index 00000000000..2c7de79c83b --- /dev/null +++ b/drivers/rtc/rtc-s3c.c | |||
@@ -0,0 +1,621 @@ | |||
1 | /* drivers/rtc/rtc-s3c.c | ||
2 | * | ||
3 | * Copyright (c) 2004,2006 Simtec Electronics | ||
4 | * Ben Dooks, <ben@simtec.co.uk> | ||
5 | * http://armlinux.simtec.co.uk/ | ||
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 | * S3C2410/S3C2440/S3C24XX Internal RTC Driver | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/fs.h> | ||
16 | #include <linux/string.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/rtc.h> | ||
21 | #include <linux/bcd.h> | ||
22 | #include <linux/clk.h> | ||
23 | |||
24 | #include <asm/hardware.h> | ||
25 | #include <asm/uaccess.h> | ||
26 | #include <asm/io.h> | ||
27 | #include <asm/irq.h> | ||
28 | #include <asm/rtc.h> | ||
29 | |||
30 | #include <asm/mach/time.h> | ||
31 | |||
32 | #include <asm/arch/regs-rtc.h> | ||
33 | |||
34 | /* I have yet to find an S3C implementation with more than one | ||
35 | * of these rtc blocks in */ | ||
36 | |||
37 | static struct resource *s3c_rtc_mem; | ||
38 | |||
39 | static void __iomem *s3c_rtc_base; | ||
40 | static int s3c_rtc_alarmno = NO_IRQ; | ||
41 | static int s3c_rtc_tickno = NO_IRQ; | ||
42 | static int s3c_rtc_freq = 1; | ||
43 | |||
44 | static DEFINE_SPINLOCK(s3c_rtc_pie_lock); | ||
45 | static unsigned int tick_count; | ||
46 | |||
47 | /* IRQ Handlers */ | ||
48 | |||
49 | static irqreturn_t s3c_rtc_alarmirq(int irq, void *id, struct pt_regs *r) | ||
50 | { | ||
51 | struct rtc_device *rdev = id; | ||
52 | |||
53 | rtc_update_irq(&rdev->class_dev, 1, RTC_AF | RTC_IRQF); | ||
54 | return IRQ_HANDLED; | ||
55 | } | ||
56 | |||
57 | static irqreturn_t s3c_rtc_tickirq(int irq, void *id, struct pt_regs *r) | ||
58 | { | ||
59 | struct rtc_device *rdev = id; | ||
60 | |||
61 | rtc_update_irq(&rdev->class_dev, tick_count++, RTC_PF | RTC_IRQF); | ||
62 | return IRQ_HANDLED; | ||
63 | } | ||
64 | |||
65 | /* Update control registers */ | ||
66 | static void s3c_rtc_setaie(int to) | ||
67 | { | ||
68 | unsigned int tmp; | ||
69 | |||
70 | pr_debug("%s: aie=%d\n", __FUNCTION__, to); | ||
71 | |||
72 | tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN; | ||
73 | |||
74 | if (to) | ||
75 | tmp |= S3C2410_RTCALM_ALMEN; | ||
76 | |||
77 | writeb(tmp, s3c_rtc_base + S3C2410_RTCALM); | ||
78 | } | ||
79 | |||
80 | static void s3c_rtc_setpie(int to) | ||
81 | { | ||
82 | unsigned int tmp; | ||
83 | |||
84 | pr_debug("%s: pie=%d\n", __FUNCTION__, to); | ||
85 | |||
86 | spin_lock_irq(&s3c_rtc_pie_lock); | ||
87 | tmp = readb(s3c_rtc_base + S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE; | ||
88 | |||
89 | if (to) | ||
90 | tmp |= S3C2410_TICNT_ENABLE; | ||
91 | |||
92 | writeb(tmp, s3c_rtc_base + S3C2410_TICNT); | ||
93 | spin_unlock_irq(&s3c_rtc_pie_lock); | ||
94 | } | ||
95 | |||
96 | static void s3c_rtc_setfreq(int freq) | ||
97 | { | ||
98 | unsigned int tmp; | ||
99 | |||
100 | spin_lock_irq(&s3c_rtc_pie_lock); | ||
101 | tmp = readb(s3c_rtc_base + S3C2410_TICNT) & S3C2410_TICNT_ENABLE; | ||
102 | |||
103 | s3c_rtc_freq = freq; | ||
104 | |||
105 | tmp |= (128 / freq)-1; | ||
106 | |||
107 | writeb(tmp, s3c_rtc_base + S3C2410_TICNT); | ||
108 | spin_unlock_irq(&s3c_rtc_pie_lock); | ||
109 | } | ||
110 | |||
111 | /* Time read/write */ | ||
112 | |||
113 | static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) | ||
114 | { | ||
115 | unsigned int have_retried = 0; | ||
116 | void __iomem *base = s3c_rtc_base; | ||
117 | |||
118 | retry_get_time: | ||
119 | rtc_tm->tm_min = readb(base + S3C2410_RTCMIN); | ||
120 | rtc_tm->tm_hour = readb(base + S3C2410_RTCHOUR); | ||
121 | rtc_tm->tm_mday = readb(base + S3C2410_RTCDATE); | ||
122 | rtc_tm->tm_mon = readb(base + S3C2410_RTCMON); | ||
123 | rtc_tm->tm_year = readb(base + S3C2410_RTCYEAR); | ||
124 | rtc_tm->tm_sec = readb(base + S3C2410_RTCSEC); | ||
125 | |||
126 | /* the only way to work out wether the system was mid-update | ||
127 | * when we read it is to check the second counter, and if it | ||
128 | * is zero, then we re-try the entire read | ||
129 | */ | ||
130 | |||
131 | if (rtc_tm->tm_sec == 0 && !have_retried) { | ||
132 | have_retried = 1; | ||
133 | goto retry_get_time; | ||
134 | } | ||
135 | |||
136 | pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n", | ||
137 | rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, | ||
138 | rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec); | ||
139 | |||
140 | BCD_TO_BIN(rtc_tm->tm_sec); | ||
141 | BCD_TO_BIN(rtc_tm->tm_min); | ||
142 | BCD_TO_BIN(rtc_tm->tm_hour); | ||
143 | BCD_TO_BIN(rtc_tm->tm_mday); | ||
144 | BCD_TO_BIN(rtc_tm->tm_mon); | ||
145 | BCD_TO_BIN(rtc_tm->tm_year); | ||
146 | |||
147 | rtc_tm->tm_year += 100; | ||
148 | rtc_tm->tm_mon -= 1; | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) | ||
154 | { | ||
155 | void __iomem *base = s3c_rtc_base; | ||
156 | int year = tm->tm_year - 100; | ||
157 | |||
158 | pr_debug("set time %02d.%02d.%02d %02d/%02d/%02d\n", | ||
159 | tm->tm_year, tm->tm_mon, tm->tm_mday, | ||
160 | tm->tm_hour, tm->tm_min, tm->tm_sec); | ||
161 | |||
162 | /* we get around y2k by simply not supporting it */ | ||
163 | |||
164 | if (year < 0 || year >= 100) { | ||
165 | dev_err(dev, "rtc only supports 100 years\n"); | ||
166 | return -EINVAL; | ||
167 | } | ||
168 | |||
169 | writeb(BIN2BCD(tm->tm_sec), base + S3C2410_RTCSEC); | ||
170 | writeb(BIN2BCD(tm->tm_min), base + S3C2410_RTCMIN); | ||
171 | writeb(BIN2BCD(tm->tm_hour), base + S3C2410_RTCHOUR); | ||
172 | writeb(BIN2BCD(tm->tm_mday), base + S3C2410_RTCDATE); | ||
173 | writeb(BIN2BCD(tm->tm_mon + 1), base + S3C2410_RTCMON); | ||
174 | writeb(BIN2BCD(year), base + S3C2410_RTCYEAR); | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
180 | { | ||
181 | struct rtc_time *alm_tm = &alrm->time; | ||
182 | void __iomem *base = s3c_rtc_base; | ||
183 | unsigned int alm_en; | ||
184 | |||
185 | alm_tm->tm_sec = readb(base + S3C2410_ALMSEC); | ||
186 | alm_tm->tm_min = readb(base + S3C2410_ALMMIN); | ||
187 | alm_tm->tm_hour = readb(base + S3C2410_ALMHOUR); | ||
188 | alm_tm->tm_mon = readb(base + S3C2410_ALMMON); | ||
189 | alm_tm->tm_mday = readb(base + S3C2410_ALMDATE); | ||
190 | alm_tm->tm_year = readb(base + S3C2410_ALMYEAR); | ||
191 | |||
192 | alm_en = readb(base + S3C2410_RTCALM); | ||
193 | |||
194 | pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n", | ||
195 | alm_en, | ||
196 | alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, | ||
197 | alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec); | ||
198 | |||
199 | |||
200 | /* decode the alarm enable field */ | ||
201 | |||
202 | if (alm_en & S3C2410_RTCALM_SECEN) | ||
203 | BCD_TO_BIN(alm_tm->tm_sec); | ||
204 | else | ||
205 | alm_tm->tm_sec = 0xff; | ||
206 | |||
207 | if (alm_en & S3C2410_RTCALM_MINEN) | ||
208 | BCD_TO_BIN(alm_tm->tm_min); | ||
209 | else | ||
210 | alm_tm->tm_min = 0xff; | ||
211 | |||
212 | if (alm_en & S3C2410_RTCALM_HOUREN) | ||
213 | BCD_TO_BIN(alm_tm->tm_hour); | ||
214 | else | ||
215 | alm_tm->tm_hour = 0xff; | ||
216 | |||
217 | if (alm_en & S3C2410_RTCALM_DAYEN) | ||
218 | BCD_TO_BIN(alm_tm->tm_mday); | ||
219 | else | ||
220 | alm_tm->tm_mday = 0xff; | ||
221 | |||
222 | if (alm_en & S3C2410_RTCALM_MONEN) { | ||
223 | BCD_TO_BIN(alm_tm->tm_mon); | ||
224 | alm_tm->tm_mon -= 1; | ||
225 | } else { | ||
226 | alm_tm->tm_mon = 0xff; | ||
227 | } | ||
228 | |||
229 | if (alm_en & S3C2410_RTCALM_YEAREN) | ||
230 | BCD_TO_BIN(alm_tm->tm_year); | ||
231 | else | ||
232 | alm_tm->tm_year = 0xffff; | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
238 | { | ||
239 | struct rtc_time *tm = &alrm->time; | ||
240 | void __iomem *base = s3c_rtc_base; | ||
241 | unsigned int alrm_en; | ||
242 | |||
243 | pr_debug("s3c_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n", | ||
244 | alrm->enabled, | ||
245 | tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff, | ||
246 | tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec); | ||
247 | |||
248 | |||
249 | alrm_en = readb(base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN; | ||
250 | writeb(0x00, base + S3C2410_RTCALM); | ||
251 | |||
252 | if (tm->tm_sec < 60 && tm->tm_sec >= 0) { | ||
253 | alrm_en |= S3C2410_RTCALM_SECEN; | ||
254 | writeb(BIN2BCD(tm->tm_sec), base + S3C2410_ALMSEC); | ||
255 | } | ||
256 | |||
257 | if (tm->tm_min < 60 && tm->tm_min >= 0) { | ||
258 | alrm_en |= S3C2410_RTCALM_MINEN; | ||
259 | writeb(BIN2BCD(tm->tm_min), base + S3C2410_ALMMIN); | ||
260 | } | ||
261 | |||
262 | if (tm->tm_hour < 24 && tm->tm_hour >= 0) { | ||
263 | alrm_en |= S3C2410_RTCALM_HOUREN; | ||
264 | writeb(BIN2BCD(tm->tm_hour), base + S3C2410_ALMHOUR); | ||
265 | } | ||
266 | |||
267 | pr_debug("setting S3C2410_RTCALM to %08x\n", alrm_en); | ||
268 | |||
269 | writeb(alrm_en, base + S3C2410_RTCALM); | ||
270 | |||
271 | if (0) { | ||
272 | alrm_en = readb(base + S3C2410_RTCALM); | ||
273 | alrm_en &= ~S3C2410_RTCALM_ALMEN; | ||
274 | writeb(alrm_en, base + S3C2410_RTCALM); | ||
275 | disable_irq_wake(s3c_rtc_alarmno); | ||
276 | } | ||
277 | |||
278 | if (alrm->enabled) | ||
279 | enable_irq_wake(s3c_rtc_alarmno); | ||
280 | else | ||
281 | disable_irq_wake(s3c_rtc_alarmno); | ||
282 | |||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | static int s3c_rtc_ioctl(struct device *dev, | ||
287 | unsigned int cmd, unsigned long arg) | ||
288 | { | ||
289 | unsigned int ret = -ENOIOCTLCMD; | ||
290 | |||
291 | switch (cmd) { | ||
292 | case RTC_AIE_OFF: | ||
293 | case RTC_AIE_ON: | ||
294 | s3c_rtc_setaie((cmd == RTC_AIE_ON) ? 1 : 0); | ||
295 | ret = 0; | ||
296 | break; | ||
297 | |||
298 | case RTC_PIE_OFF: | ||
299 | case RTC_PIE_ON: | ||
300 | tick_count = 0; | ||
301 | s3c_rtc_setpie((cmd == RTC_PIE_ON) ? 1 : 0); | ||
302 | ret = 0; | ||
303 | break; | ||
304 | |||
305 | case RTC_IRQP_READ: | ||
306 | ret = put_user(s3c_rtc_freq, (unsigned long __user *)arg); | ||
307 | break; | ||
308 | |||
309 | case RTC_IRQP_SET: | ||
310 | /* check for power of 2 */ | ||
311 | |||
312 | if ((arg & (arg-1)) != 0 || arg < 1) { | ||
313 | ret = -EINVAL; | ||
314 | goto exit; | ||
315 | } | ||
316 | |||
317 | pr_debug("s3c2410_rtc: setting frequency %ld\n", arg); | ||
318 | |||
319 | s3c_rtc_setfreq(arg); | ||
320 | ret = 0; | ||
321 | break; | ||
322 | |||
323 | case RTC_UIE_ON: | ||
324 | case RTC_UIE_OFF: | ||
325 | ret = -EINVAL; | ||
326 | } | ||
327 | |||
328 | exit: | ||
329 | return ret; | ||
330 | } | ||
331 | |||
332 | static int s3c_rtc_proc(struct device *dev, struct seq_file *seq) | ||
333 | { | ||
334 | unsigned int rtcalm = readb(s3c_rtc_base + S3C2410_RTCALM); | ||
335 | unsigned int ticnt = readb(s3c_rtc_base + S3C2410_TICNT); | ||
336 | |||
337 | seq_printf(seq, "alarm_IRQ\t: %s\n", | ||
338 | (rtcalm & S3C2410_RTCALM_ALMEN) ? "yes" : "no" ); | ||
339 | |||
340 | seq_printf(seq, "periodic_IRQ\t: %s\n", | ||
341 | (ticnt & S3C2410_TICNT_ENABLE) ? "yes" : "no" ); | ||
342 | |||
343 | seq_printf(seq, "periodic_freq\t: %d\n", s3c_rtc_freq); | ||
344 | |||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static int s3c_rtc_open(struct device *dev) | ||
349 | { | ||
350 | struct platform_device *pdev = to_platform_device(dev); | ||
351 | struct rtc_device *rtc_dev = platform_get_drvdata(pdev); | ||
352 | int ret; | ||
353 | |||
354 | ret = request_irq(s3c_rtc_alarmno, s3c_rtc_alarmirq, | ||
355 | SA_INTERRUPT, "s3c2410-rtc alarm", rtc_dev); | ||
356 | |||
357 | if (ret) { | ||
358 | dev_err(dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret); | ||
359 | return ret; | ||
360 | } | ||
361 | |||
362 | ret = request_irq(s3c_rtc_tickno, s3c_rtc_tickirq, | ||
363 | SA_INTERRUPT, "s3c2410-rtc tick", rtc_dev); | ||
364 | |||
365 | if (ret) { | ||
366 | dev_err(dev, "IRQ%d error %d\n", s3c_rtc_tickno, ret); | ||
367 | goto tick_err; | ||
368 | } | ||
369 | |||
370 | return ret; | ||
371 | |||
372 | tick_err: | ||
373 | free_irq(s3c_rtc_alarmno, rtc_dev); | ||
374 | return ret; | ||
375 | } | ||
376 | |||
377 | static void s3c_rtc_release(struct device *dev) | ||
378 | { | ||
379 | struct platform_device *pdev = to_platform_device(dev); | ||
380 | struct rtc_device *rtc_dev = platform_get_drvdata(pdev); | ||
381 | |||
382 | /* do not clear AIE here, it may be needed for wake */ | ||
383 | |||
384 | s3c_rtc_setpie(0); | ||
385 | free_irq(s3c_rtc_alarmno, rtc_dev); | ||
386 | free_irq(s3c_rtc_tickno, rtc_dev); | ||
387 | } | ||
388 | |||
389 | static struct rtc_class_ops s3c_rtcops = { | ||
390 | .open = s3c_rtc_open, | ||
391 | .release = s3c_rtc_release, | ||
392 | .ioctl = s3c_rtc_ioctl, | ||
393 | .read_time = s3c_rtc_gettime, | ||
394 | .set_time = s3c_rtc_settime, | ||
395 | .read_alarm = s3c_rtc_getalarm, | ||
396 | .set_alarm = s3c_rtc_setalarm, | ||
397 | .proc = s3c_rtc_proc, | ||
398 | }; | ||
399 | |||
400 | static void s3c_rtc_enable(struct platform_device *pdev, int en) | ||
401 | { | ||
402 | void __iomem *base = s3c_rtc_base; | ||
403 | unsigned int tmp; | ||
404 | |||
405 | if (s3c_rtc_base == NULL) | ||
406 | return; | ||
407 | |||
408 | if (!en) { | ||
409 | tmp = readb(base + S3C2410_RTCCON); | ||
410 | writeb(tmp & ~S3C2410_RTCCON_RTCEN, base + S3C2410_RTCCON); | ||
411 | |||
412 | tmp = readb(base + S3C2410_TICNT); | ||
413 | writeb(tmp & ~S3C2410_TICNT_ENABLE, base + S3C2410_TICNT); | ||
414 | } else { | ||
415 | /* re-enable the device, and check it is ok */ | ||
416 | |||
417 | if ((readb(base+S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0){ | ||
418 | dev_info(&pdev->dev, "rtc disabled, re-enabling\n"); | ||
419 | |||
420 | tmp = readb(base + S3C2410_RTCCON); | ||
421 | writeb(tmp|S3C2410_RTCCON_RTCEN, base+S3C2410_RTCCON); | ||
422 | } | ||
423 | |||
424 | if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)){ | ||
425 | dev_info(&pdev->dev, "removing RTCCON_CNTSEL\n"); | ||
426 | |||
427 | tmp = readb(base + S3C2410_RTCCON); | ||
428 | writeb(tmp& ~S3C2410_RTCCON_CNTSEL, base+S3C2410_RTCCON); | ||
429 | } | ||
430 | |||
431 | if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)){ | ||
432 | dev_info(&pdev->dev, "removing RTCCON_CLKRST\n"); | ||
433 | |||
434 | tmp = readb(base + S3C2410_RTCCON); | ||
435 | writeb(tmp & ~S3C2410_RTCCON_CLKRST, base+S3C2410_RTCCON); | ||
436 | } | ||
437 | } | ||
438 | } | ||
439 | |||
440 | static int s3c_rtc_remove(struct platform_device *dev) | ||
441 | { | ||
442 | struct rtc_device *rtc = platform_get_drvdata(dev); | ||
443 | |||
444 | platform_set_drvdata(dev, NULL); | ||
445 | rtc_device_unregister(rtc); | ||
446 | |||
447 | s3c_rtc_setpie(0); | ||
448 | s3c_rtc_setaie(0); | ||
449 | |||
450 | iounmap(s3c_rtc_base); | ||
451 | release_resource(s3c_rtc_mem); | ||
452 | kfree(s3c_rtc_mem); | ||
453 | |||
454 | return 0; | ||
455 | } | ||
456 | |||
457 | static int s3c_rtc_probe(struct platform_device *pdev) | ||
458 | { | ||
459 | struct rtc_device *rtc; | ||
460 | struct resource *res; | ||
461 | int ret; | ||
462 | |||
463 | pr_debug("%s: probe=%p\n", __FUNCTION__, pdev); | ||
464 | |||
465 | /* find the IRQs */ | ||
466 | |||
467 | s3c_rtc_tickno = platform_get_irq(pdev, 1); | ||
468 | if (s3c_rtc_tickno < 0) { | ||
469 | dev_err(&pdev->dev, "no irq for rtc tick\n"); | ||
470 | return -ENOENT; | ||
471 | } | ||
472 | |||
473 | s3c_rtc_alarmno = platform_get_irq(pdev, 0); | ||
474 | if (s3c_rtc_alarmno < 0) { | ||
475 | dev_err(&pdev->dev, "no irq for alarm\n"); | ||
476 | return -ENOENT; | ||
477 | } | ||
478 | |||
479 | pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d\n", | ||
480 | s3c_rtc_tickno, s3c_rtc_alarmno); | ||
481 | |||
482 | /* get the memory region */ | ||
483 | |||
484 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
485 | if (res == NULL) { | ||
486 | dev_err(&pdev->dev, "failed to get memory region resource\n"); | ||
487 | return -ENOENT; | ||
488 | } | ||
489 | |||
490 | s3c_rtc_mem = request_mem_region(res->start, | ||
491 | res->end-res->start+1, | ||
492 | pdev->name); | ||
493 | |||
494 | if (s3c_rtc_mem == NULL) { | ||
495 | dev_err(&pdev->dev, "failed to reserve memory region\n"); | ||
496 | ret = -ENOENT; | ||
497 | goto err_nores; | ||
498 | } | ||
499 | |||
500 | s3c_rtc_base = ioremap(res->start, res->end - res->start + 1); | ||
501 | if (s3c_rtc_base == NULL) { | ||
502 | dev_err(&pdev->dev, "failed ioremap()\n"); | ||
503 | ret = -EINVAL; | ||
504 | goto err_nomap; | ||
505 | } | ||
506 | |||
507 | /* check to see if everything is setup correctly */ | ||
508 | |||
509 | s3c_rtc_enable(pdev, 1); | ||
510 | |||
511 | pr_debug("s3c2410_rtc: RTCCON=%02x\n", | ||
512 | readb(s3c_rtc_base + S3C2410_RTCCON)); | ||
513 | |||
514 | s3c_rtc_setfreq(s3c_rtc_freq); | ||
515 | |||
516 | /* register RTC and exit */ | ||
517 | |||
518 | rtc = rtc_device_register("s3c", &pdev->dev, &s3c_rtcops, | ||
519 | THIS_MODULE); | ||
520 | |||
521 | if (IS_ERR(rtc)) { | ||
522 | dev_err(&pdev->dev, "cannot attach rtc\n"); | ||
523 | ret = PTR_ERR(rtc); | ||
524 | goto err_nortc; | ||
525 | } | ||
526 | |||
527 | rtc->max_user_freq = 128; | ||
528 | |||
529 | platform_set_drvdata(pdev, rtc); | ||
530 | return 0; | ||
531 | |||
532 | err_nortc: | ||
533 | s3c_rtc_enable(pdev, 0); | ||
534 | iounmap(s3c_rtc_base); | ||
535 | |||
536 | err_nomap: | ||
537 | release_resource(s3c_rtc_mem); | ||
538 | |||
539 | err_nores: | ||
540 | return ret; | ||
541 | } | ||
542 | |||
543 | #ifdef CONFIG_PM | ||
544 | |||
545 | /* RTC Power management control */ | ||
546 | |||
547 | static struct timespec s3c_rtc_delta; | ||
548 | |||
549 | static int ticnt_save; | ||
550 | |||
551 | static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state) | ||
552 | { | ||
553 | struct rtc_time tm; | ||
554 | struct timespec time; | ||
555 | |||
556 | time.tv_nsec = 0; | ||
557 | |||
558 | /* save TICNT for anyone using periodic interrupts */ | ||
559 | |||
560 | ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT); | ||
561 | |||
562 | /* calculate time delta for suspend */ | ||
563 | |||
564 | s3c_rtc_gettime(&pdev->dev, &tm); | ||
565 | rtc_tm_to_time(&tm, &time.tv_sec); | ||
566 | save_time_delta(&s3c_rtc_delta, &time); | ||
567 | s3c_rtc_enable(pdev, 0); | ||
568 | |||
569 | return 0; | ||
570 | } | ||
571 | |||
572 | static int s3c_rtc_resume(struct platform_device *pdev) | ||
573 | { | ||
574 | struct rtc_time tm; | ||
575 | struct timespec time; | ||
576 | |||
577 | time.tv_nsec = 0; | ||
578 | |||
579 | s3c_rtc_enable(pdev, 1); | ||
580 | s3c_rtc_gettime(&pdev->dev, &tm); | ||
581 | rtc_tm_to_time(&tm, &time.tv_sec); | ||
582 | restore_time_delta(&s3c_rtc_delta, &time); | ||
583 | |||
584 | writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT); | ||
585 | return 0; | ||
586 | } | ||
587 | #else | ||
588 | #define s3c_rtc_suspend NULL | ||
589 | #define s3c_rtc_resume NULL | ||
590 | #endif | ||
591 | |||
592 | static struct platform_driver s3c2410_rtcdrv = { | ||
593 | .probe = s3c_rtc_probe, | ||
594 | .remove = s3c_rtc_remove, | ||
595 | .suspend = s3c_rtc_suspend, | ||
596 | .resume = s3c_rtc_resume, | ||
597 | .driver = { | ||
598 | .name = "s3c2410-rtc", | ||
599 | .owner = THIS_MODULE, | ||
600 | }, | ||
601 | }; | ||
602 | |||
603 | static char __initdata banner[] = "S3C24XX RTC, (c) 2004,2006 Simtec Electronics\n"; | ||
604 | |||
605 | static int __init s3c_rtc_init(void) | ||
606 | { | ||
607 | printk(banner); | ||
608 | return platform_driver_register(&s3c2410_rtcdrv); | ||
609 | } | ||
610 | |||
611 | static void __exit s3c_rtc_exit(void) | ||
612 | { | ||
613 | platform_driver_unregister(&s3c2410_rtcdrv); | ||
614 | } | ||
615 | |||
616 | module_init(s3c_rtc_init); | ||
617 | module_exit(s3c_rtc_exit); | ||
618 | |||
619 | MODULE_DESCRIPTION("Samsung S3C RTC Driver"); | ||
620 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); | ||
621 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index a997529f892..ee4b61ee67b 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 | { |
@@ -157,19 +157,19 @@ static int sa1100_rtc_open(struct device *dev) | |||
157 | { | 157 | { |
158 | int ret; | 158 | int ret; |
159 | 159 | ||
160 | ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, SA_INTERRUPT, | 160 | ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, IRQF_DISABLED, |
161 | "rtc 1Hz", dev); | 161 | "rtc 1Hz", dev); |
162 | if (ret) { | 162 | if (ret) { |
163 | dev_err(dev, "IRQ %d already in use.\n", IRQ_RTC1Hz); | 163 | dev_err(dev, "IRQ %d already in use.\n", IRQ_RTC1Hz); |
164 | goto fail_ui; | 164 | goto fail_ui; |
165 | } | 165 | } |
166 | ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, SA_INTERRUPT, | 166 | ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, IRQF_DISABLED, |
167 | "rtc Alrm", dev); | 167 | "rtc Alrm", dev); |
168 | if (ret) { | 168 | if (ret) { |
169 | dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm); | 169 | dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm); |
170 | goto fail_ai; | 170 | goto fail_ai; |
171 | } | 171 | } |
172 | ret = request_irq(IRQ_OST1, timer1_interrupt, SA_INTERRUPT, | 172 | ret = request_irq(IRQ_OST1, timer1_interrupt, IRQF_DISABLED, |
173 | "rtc timer", dev); | 173 | "rtc timer", dev); |
174 | if (ret) { | 174 | if (ret) { |
175 | dev_err(dev, "IRQ %d already in use.\n", IRQ_OST1); | 175 | dev_err(dev, "IRQ %d already in use.\n", IRQ_OST1); |
@@ -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-sh.c b/drivers/rtc/rtc-sh.c new file mode 100644 index 00000000000..d2ce0c8bb8f --- /dev/null +++ b/drivers/rtc/rtc-sh.c | |||
@@ -0,0 +1,467 @@ | |||
1 | /* | ||
2 | * SuperH On-Chip RTC Support | ||
3 | * | ||
4 | * Copyright (C) 2006 Paul Mundt | ||
5 | * | ||
6 | * Based on the old arch/sh/kernel/cpu/rtc.c by: | ||
7 | * | ||
8 | * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> | ||
9 | * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka | ||
10 | * | ||
11 | * This file is subject to the terms and conditions of the GNU General Public | ||
12 | * License. See the file "COPYING" in the main directory of this archive | ||
13 | * for more details. | ||
14 | */ | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/bcd.h> | ||
18 | #include <linux/rtc.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/seq_file.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/spinlock.h> | ||
24 | #include <asm/io.h> | ||
25 | |||
26 | #ifdef CONFIG_CPU_SH3 | ||
27 | #define rtc_reg_size sizeof(u16) | ||
28 | #define RTC_BIT_INVERTED 0 /* No bug on SH7708, SH7709A */ | ||
29 | #elif defined(CONFIG_CPU_SH4) | ||
30 | #define rtc_reg_size sizeof(u32) | ||
31 | #define RTC_BIT_INVERTED 0x40 /* bug on SH7750, SH7750S */ | ||
32 | #endif | ||
33 | |||
34 | #define RTC_REG(r) ((r) * rtc_reg_size) | ||
35 | |||
36 | #define R64CNT RTC_REG(0) | ||
37 | #define RSECCNT RTC_REG(1) | ||
38 | #define RMINCNT RTC_REG(2) | ||
39 | #define RHRCNT RTC_REG(3) | ||
40 | #define RWKCNT RTC_REG(4) | ||
41 | #define RDAYCNT RTC_REG(5) | ||
42 | #define RMONCNT RTC_REG(6) | ||
43 | #define RYRCNT RTC_REG(7) | ||
44 | #define RSECAR RTC_REG(8) | ||
45 | #define RMINAR RTC_REG(9) | ||
46 | #define RHRAR RTC_REG(10) | ||
47 | #define RWKAR RTC_REG(11) | ||
48 | #define RDAYAR RTC_REG(12) | ||
49 | #define RMONAR RTC_REG(13) | ||
50 | #define RCR1 RTC_REG(14) | ||
51 | #define RCR2 RTC_REG(15) | ||
52 | |||
53 | /* RCR1 Bits */ | ||
54 | #define RCR1_CF 0x80 /* Carry Flag */ | ||
55 | #define RCR1_CIE 0x10 /* Carry Interrupt Enable */ | ||
56 | #define RCR1_AIE 0x08 /* Alarm Interrupt Enable */ | ||
57 | #define RCR1_AF 0x01 /* Alarm Flag */ | ||
58 | |||
59 | /* RCR2 Bits */ | ||
60 | #define RCR2_PEF 0x80 /* PEriodic interrupt Flag */ | ||
61 | #define RCR2_PESMASK 0x70 /* Periodic interrupt Set */ | ||
62 | #define RCR2_RTCEN 0x08 /* ENable RTC */ | ||
63 | #define RCR2_ADJ 0x04 /* ADJustment (30-second) */ | ||
64 | #define RCR2_RESET 0x02 /* Reset bit */ | ||
65 | #define RCR2_START 0x01 /* Start bit */ | ||
66 | |||
67 | struct sh_rtc { | ||
68 | void __iomem *regbase; | ||
69 | unsigned long regsize; | ||
70 | struct resource *res; | ||
71 | unsigned int alarm_irq, periodic_irq, carry_irq; | ||
72 | struct rtc_device *rtc_dev; | ||
73 | spinlock_t lock; | ||
74 | }; | ||
75 | |||
76 | static irqreturn_t sh_rtc_interrupt(int irq, void *id, struct pt_regs *regs) | ||
77 | { | ||
78 | struct platform_device *pdev = id; | ||
79 | struct sh_rtc *rtc = platform_get_drvdata(pdev); | ||
80 | unsigned int tmp, events = 0; | ||
81 | |||
82 | spin_lock(&rtc->lock); | ||
83 | |||
84 | tmp = readb(rtc->regbase + RCR1); | ||
85 | |||
86 | if (tmp & RCR1_AF) | ||
87 | events |= RTC_AF | RTC_IRQF; | ||
88 | |||
89 | tmp &= ~(RCR1_CF | RCR1_AF); | ||
90 | |||
91 | writeb(tmp, rtc->regbase + RCR1); | ||
92 | |||
93 | rtc_update_irq(&rtc->rtc_dev->class_dev, 1, events); | ||
94 | |||
95 | spin_unlock(&rtc->lock); | ||
96 | |||
97 | return IRQ_HANDLED; | ||
98 | } | ||
99 | |||
100 | static irqreturn_t sh_rtc_periodic(int irq, void *id, struct pt_regs *regs) | ||
101 | { | ||
102 | struct sh_rtc *rtc = dev_get_drvdata(id); | ||
103 | |||
104 | spin_lock(&rtc->lock); | ||
105 | |||
106 | rtc_update_irq(&rtc->rtc_dev->class_dev, 1, RTC_PF | RTC_IRQF); | ||
107 | |||
108 | spin_unlock(&rtc->lock); | ||
109 | |||
110 | return IRQ_HANDLED; | ||
111 | } | ||
112 | |||
113 | static inline void sh_rtc_setpie(struct device *dev, unsigned int enable) | ||
114 | { | ||
115 | struct sh_rtc *rtc = dev_get_drvdata(dev); | ||
116 | unsigned int tmp; | ||
117 | |||
118 | spin_lock_irq(&rtc->lock); | ||
119 | |||
120 | tmp = readb(rtc->regbase + RCR2); | ||
121 | |||
122 | if (enable) { | ||
123 | tmp &= ~RCR2_PESMASK; | ||
124 | tmp |= RCR2_PEF | (2 << 4); | ||
125 | } else | ||
126 | tmp &= ~(RCR2_PESMASK | RCR2_PEF); | ||
127 | |||
128 | writeb(tmp, rtc->regbase + RCR2); | ||
129 | |||
130 | spin_unlock_irq(&rtc->lock); | ||
131 | } | ||
132 | |||
133 | static inline void sh_rtc_setaie(struct device *dev, unsigned int enable) | ||
134 | { | ||
135 | struct sh_rtc *rtc = dev_get_drvdata(dev); | ||
136 | unsigned int tmp; | ||
137 | |||
138 | spin_lock_irq(&rtc->lock); | ||
139 | |||
140 | tmp = readb(rtc->regbase + RCR1); | ||
141 | |||
142 | if (enable) | ||
143 | tmp |= RCR1_AIE; | ||
144 | else | ||
145 | tmp &= ~RCR1_AIE; | ||
146 | |||
147 | writeb(tmp, rtc->regbase + RCR1); | ||
148 | |||
149 | spin_unlock_irq(&rtc->lock); | ||
150 | } | ||
151 | |||
152 | static int sh_rtc_open(struct device *dev) | ||
153 | { | ||
154 | struct sh_rtc *rtc = dev_get_drvdata(dev); | ||
155 | unsigned int tmp; | ||
156 | int ret; | ||
157 | |||
158 | tmp = readb(rtc->regbase + RCR1); | ||
159 | tmp &= ~RCR1_CF; | ||
160 | tmp |= RCR1_CIE; | ||
161 | writeb(tmp, rtc->regbase + RCR1); | ||
162 | |||
163 | ret = request_irq(rtc->periodic_irq, sh_rtc_periodic, SA_INTERRUPT, | ||
164 | "sh-rtc period", dev); | ||
165 | if (unlikely(ret)) { | ||
166 | dev_err(dev, "request period IRQ failed with %d, IRQ %d\n", | ||
167 | ret, rtc->periodic_irq); | ||
168 | return ret; | ||
169 | } | ||
170 | |||
171 | ret = request_irq(rtc->carry_irq, sh_rtc_interrupt, SA_INTERRUPT, | ||
172 | "sh-rtc carry", dev); | ||
173 | if (unlikely(ret)) { | ||
174 | dev_err(dev, "request carry IRQ failed with %d, IRQ %d\n", | ||
175 | ret, rtc->carry_irq); | ||
176 | free_irq(rtc->periodic_irq, dev); | ||
177 | goto err_bad_carry; | ||
178 | } | ||
179 | |||
180 | ret = request_irq(rtc->alarm_irq, sh_rtc_interrupt, SA_INTERRUPT, | ||
181 | "sh-rtc alarm", dev); | ||
182 | if (unlikely(ret)) { | ||
183 | dev_err(dev, "request alarm IRQ failed with %d, IRQ %d\n", | ||
184 | ret, rtc->alarm_irq); | ||
185 | goto err_bad_alarm; | ||
186 | } | ||
187 | |||
188 | return 0; | ||
189 | |||
190 | err_bad_alarm: | ||
191 | free_irq(rtc->carry_irq, dev); | ||
192 | err_bad_carry: | ||
193 | free_irq(rtc->periodic_irq, dev); | ||
194 | |||
195 | return ret; | ||
196 | } | ||
197 | |||
198 | static void sh_rtc_release(struct device *dev) | ||
199 | { | ||
200 | struct sh_rtc *rtc = dev_get_drvdata(dev); | ||
201 | |||
202 | sh_rtc_setpie(dev, 0); | ||
203 | |||
204 | free_irq(rtc->periodic_irq, dev); | ||
205 | free_irq(rtc->carry_irq, dev); | ||
206 | free_irq(rtc->alarm_irq, dev); | ||
207 | } | ||
208 | |||
209 | static int sh_rtc_proc(struct device *dev, struct seq_file *seq) | ||
210 | { | ||
211 | struct sh_rtc *rtc = dev_get_drvdata(dev); | ||
212 | unsigned int tmp; | ||
213 | |||
214 | tmp = readb(rtc->regbase + RCR1); | ||
215 | seq_printf(seq, "alarm_IRQ\t: %s\n", | ||
216 | (tmp & RCR1_AIE) ? "yes" : "no"); | ||
217 | seq_printf(seq, "carry_IRQ\t: %s\n", | ||
218 | (tmp & RCR1_CIE) ? "yes" : "no"); | ||
219 | |||
220 | tmp = readb(rtc->regbase + RCR2); | ||
221 | seq_printf(seq, "periodic_IRQ\t: %s\n", | ||
222 | (tmp & RCR2_PEF) ? "yes" : "no"); | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static int sh_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) | ||
228 | { | ||
229 | unsigned int ret = -ENOIOCTLCMD; | ||
230 | |||
231 | switch (cmd) { | ||
232 | case RTC_PIE_OFF: | ||
233 | case RTC_PIE_ON: | ||
234 | sh_rtc_setpie(dev, cmd == RTC_PIE_ON); | ||
235 | ret = 0; | ||
236 | break; | ||
237 | case RTC_AIE_OFF: | ||
238 | case RTC_AIE_ON: | ||
239 | sh_rtc_setaie(dev, cmd == RTC_AIE_ON); | ||
240 | ret = 0; | ||
241 | break; | ||
242 | } | ||
243 | |||
244 | return ret; | ||
245 | } | ||
246 | |||
247 | static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
248 | { | ||
249 | struct platform_device *pdev = to_platform_device(dev); | ||
250 | struct sh_rtc *rtc = platform_get_drvdata(pdev); | ||
251 | unsigned int sec128, sec2, yr, yr100, cf_bit; | ||
252 | |||
253 | do { | ||
254 | unsigned int tmp; | ||
255 | |||
256 | spin_lock_irq(&rtc->lock); | ||
257 | |||
258 | tmp = readb(rtc->regbase + RCR1); | ||
259 | tmp &= ~RCR1_CF; /* Clear CF-bit */ | ||
260 | tmp |= RCR1_CIE; | ||
261 | writeb(tmp, rtc->regbase + RCR1); | ||
262 | |||
263 | sec128 = readb(rtc->regbase + R64CNT); | ||
264 | |||
265 | tm->tm_sec = BCD2BIN(readb(rtc->regbase + RSECCNT)); | ||
266 | tm->tm_min = BCD2BIN(readb(rtc->regbase + RMINCNT)); | ||
267 | tm->tm_hour = BCD2BIN(readb(rtc->regbase + RHRCNT)); | ||
268 | tm->tm_wday = BCD2BIN(readb(rtc->regbase + RWKCNT)); | ||
269 | tm->tm_mday = BCD2BIN(readb(rtc->regbase + RDAYCNT)); | ||
270 | tm->tm_mon = BCD2BIN(readb(rtc->regbase + RMONCNT)); | ||
271 | |||
272 | #if defined(CONFIG_CPU_SH4) | ||
273 | yr = readw(rtc->regbase + RYRCNT); | ||
274 | yr100 = BCD2BIN(yr >> 8); | ||
275 | yr &= 0xff; | ||
276 | #else | ||
277 | yr = readb(rtc->regbase + RYRCNT); | ||
278 | yr100 = BCD2BIN((yr == 0x99) ? 0x19 : 0x20); | ||
279 | #endif | ||
280 | |||
281 | tm->tm_year = (yr100 * 100 + BCD2BIN(yr)) - 1900; | ||
282 | |||
283 | sec2 = readb(rtc->regbase + R64CNT); | ||
284 | cf_bit = readb(rtc->regbase + RCR1) & RCR1_CF; | ||
285 | |||
286 | spin_unlock_irq(&rtc->lock); | ||
287 | } while (cf_bit != 0 || ((sec128 ^ sec2) & RTC_BIT_INVERTED) != 0); | ||
288 | |||
289 | #if RTC_BIT_INVERTED != 0 | ||
290 | if ((sec128 & RTC_BIT_INVERTED)) | ||
291 | tm->tm_sec--; | ||
292 | #endif | ||
293 | |||
294 | dev_dbg(&dev, "%s: tm is secs=%d, mins=%d, hours=%d, " | ||
295 | "mday=%d, mon=%d, year=%d, wday=%d\n", | ||
296 | __FUNCTION__, | ||
297 | tm->tm_sec, tm->tm_min, tm->tm_hour, | ||
298 | tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); | ||
299 | |||
300 | if (rtc_valid_tm(tm) < 0) | ||
301 | dev_err(dev, "invalid date\n"); | ||
302 | |||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
307 | { | ||
308 | struct platform_device *pdev = to_platform_device(dev); | ||
309 | struct sh_rtc *rtc = platform_get_drvdata(pdev); | ||
310 | unsigned int tmp; | ||
311 | int year; | ||
312 | |||
313 | spin_lock_irq(&rtc->lock); | ||
314 | |||
315 | /* Reset pre-scaler & stop RTC */ | ||
316 | tmp = readb(rtc->regbase + RCR2); | ||
317 | tmp |= RCR2_RESET; | ||
318 | writeb(tmp, rtc->regbase + RCR2); | ||
319 | |||
320 | writeb(BIN2BCD(tm->tm_sec), rtc->regbase + RSECCNT); | ||
321 | writeb(BIN2BCD(tm->tm_min), rtc->regbase + RMINCNT); | ||
322 | writeb(BIN2BCD(tm->tm_hour), rtc->regbase + RHRCNT); | ||
323 | writeb(BIN2BCD(tm->tm_wday), rtc->regbase + RWKCNT); | ||
324 | writeb(BIN2BCD(tm->tm_mday), rtc->regbase + RDAYCNT); | ||
325 | writeb(BIN2BCD(tm->tm_mon), rtc->regbase + RMONCNT); | ||
326 | |||
327 | #ifdef CONFIG_CPU_SH3 | ||
328 | year = tm->tm_year % 100; | ||
329 | writeb(BIN2BCD(year), rtc->regbase + RYRCNT); | ||
330 | #else | ||
331 | year = (BIN2BCD((tm->tm_year + 1900) / 100) << 8) | | ||
332 | BIN2BCD(tm->tm_year % 100); | ||
333 | writew(year, rtc->regbase + RYRCNT); | ||
334 | #endif | ||
335 | |||
336 | /* Start RTC */ | ||
337 | tmp = readb(rtc->regbase + RCR2); | ||
338 | tmp &= ~RCR2_RESET; | ||
339 | tmp |= RCR2_RTCEN | RCR2_START; | ||
340 | writeb(tmp, rtc->regbase + RCR2); | ||
341 | |||
342 | spin_unlock_irq(&rtc->lock); | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static struct rtc_class_ops sh_rtc_ops = { | ||
348 | .open = sh_rtc_open, | ||
349 | .release = sh_rtc_release, | ||
350 | .ioctl = sh_rtc_ioctl, | ||
351 | .read_time = sh_rtc_read_time, | ||
352 | .set_time = sh_rtc_set_time, | ||
353 | .proc = sh_rtc_proc, | ||
354 | }; | ||
355 | |||
356 | static int __devinit sh_rtc_probe(struct platform_device *pdev) | ||
357 | { | ||
358 | struct sh_rtc *rtc; | ||
359 | struct resource *res; | ||
360 | int ret = -ENOENT; | ||
361 | |||
362 | rtc = kzalloc(sizeof(struct sh_rtc), GFP_KERNEL); | ||
363 | if (unlikely(!rtc)) | ||
364 | return -ENOMEM; | ||
365 | |||
366 | spin_lock_init(&rtc->lock); | ||
367 | |||
368 | rtc->periodic_irq = platform_get_irq(pdev, 0); | ||
369 | if (unlikely(rtc->periodic_irq < 0)) { | ||
370 | dev_err(&pdev->dev, "No IRQ for period\n"); | ||
371 | goto err_badres; | ||
372 | } | ||
373 | |||
374 | rtc->carry_irq = platform_get_irq(pdev, 1); | ||
375 | if (unlikely(rtc->carry_irq < 0)) { | ||
376 | dev_err(&pdev->dev, "No IRQ for carry\n"); | ||
377 | goto err_badres; | ||
378 | } | ||
379 | |||
380 | rtc->alarm_irq = platform_get_irq(pdev, 2); | ||
381 | if (unlikely(rtc->alarm_irq < 0)) { | ||
382 | dev_err(&pdev->dev, "No IRQ for alarm\n"); | ||
383 | goto err_badres; | ||
384 | } | ||
385 | |||
386 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); | ||
387 | if (unlikely(res == NULL)) { | ||
388 | dev_err(&pdev->dev, "No IO resource\n"); | ||
389 | goto err_badres; | ||
390 | } | ||
391 | |||
392 | rtc->regsize = res->end - res->start + 1; | ||
393 | |||
394 | rtc->res = request_mem_region(res->start, rtc->regsize, pdev->name); | ||
395 | if (unlikely(!rtc->res)) { | ||
396 | ret = -EBUSY; | ||
397 | goto err_badres; | ||
398 | } | ||
399 | |||
400 | rtc->regbase = (void __iomem *)rtc->res->start; | ||
401 | if (unlikely(!rtc->regbase)) { | ||
402 | ret = -EINVAL; | ||
403 | goto err_badmap; | ||
404 | } | ||
405 | |||
406 | rtc->rtc_dev = rtc_device_register("sh", &pdev->dev, | ||
407 | &sh_rtc_ops, THIS_MODULE); | ||
408 | if (IS_ERR(rtc)) { | ||
409 | ret = PTR_ERR(rtc->rtc_dev); | ||
410 | goto err_badmap; | ||
411 | } | ||
412 | |||
413 | platform_set_drvdata(pdev, rtc); | ||
414 | |||
415 | return 0; | ||
416 | |||
417 | err_badmap: | ||
418 | release_resource(rtc->res); | ||
419 | err_badres: | ||
420 | kfree(rtc); | ||
421 | |||
422 | return ret; | ||
423 | } | ||
424 | |||
425 | static int __devexit sh_rtc_remove(struct platform_device *pdev) | ||
426 | { | ||
427 | struct sh_rtc *rtc = platform_get_drvdata(pdev); | ||
428 | |||
429 | if (likely(rtc->rtc_dev)) | ||
430 | rtc_device_unregister(rtc->rtc_dev); | ||
431 | |||
432 | sh_rtc_setpie(&pdev->dev, 0); | ||
433 | sh_rtc_setaie(&pdev->dev, 0); | ||
434 | |||
435 | release_resource(rtc->res); | ||
436 | |||
437 | platform_set_drvdata(pdev, NULL); | ||
438 | |||
439 | kfree(rtc); | ||
440 | |||
441 | return 0; | ||
442 | } | ||
443 | static struct platform_driver sh_rtc_platform_driver = { | ||
444 | .driver = { | ||
445 | .name = "sh-rtc", | ||
446 | .owner = THIS_MODULE, | ||
447 | }, | ||
448 | .probe = sh_rtc_probe, | ||
449 | .remove = __devexit_p(sh_rtc_remove), | ||
450 | }; | ||
451 | |||
452 | static int __init sh_rtc_init(void) | ||
453 | { | ||
454 | return platform_driver_register(&sh_rtc_platform_driver); | ||
455 | } | ||
456 | |||
457 | static void __exit sh_rtc_exit(void) | ||
458 | { | ||
459 | platform_driver_unregister(&sh_rtc_platform_driver); | ||
460 | } | ||
461 | |||
462 | module_init(sh_rtc_init); | ||
463 | module_exit(sh_rtc_exit); | ||
464 | |||
465 | MODULE_DESCRIPTION("SuperH on-chip RTC driver"); | ||
466 | MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>"); | ||
467 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c new file mode 100644 index 00000000000..a40f400acff --- /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 277596c302e..596764fd29f 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c | |||
@@ -30,7 +30,7 @@ | |||
30 | #include <asm/div64.h> | 30 | #include <asm/div64.h> |
31 | #include <asm/io.h> | 31 | #include <asm/io.h> |
32 | #include <asm/uaccess.h> | 32 | #include <asm/uaccess.h> |
33 | #include <asm/vr41xx/vr41xx.h> | 33 | #include <asm/vr41xx/irq.h> |
34 | 34 | ||
35 | MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>"); | 35 | MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>"); |
36 | MODULE_DESCRIPTION("NEC VR4100 series RTC driver"); | 36 | MODULE_DESCRIPTION("NEC VR4100 series RTC driver"); |
@@ -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: |
@@ -353,11 +345,11 @@ static int __devinit rtc_probe(struct platform_device *pdev) | |||
353 | spin_unlock_irq(&rtc_lock); | 345 | spin_unlock_irq(&rtc_lock); |
354 | 346 | ||
355 | irq = ELAPSEDTIME_IRQ; | 347 | irq = ELAPSEDTIME_IRQ; |
356 | retval = request_irq(irq, elapsedtime_interrupt, SA_INTERRUPT, | 348 | retval = request_irq(irq, elapsedtime_interrupt, IRQF_DISABLED, |
357 | "elapsed_time", pdev); | 349 | "elapsed_time", pdev); |
358 | if (retval == 0) { | 350 | if (retval == 0) { |
359 | irq = RTCLONG1_IRQ; | 351 | irq = RTCLONG1_IRQ; |
360 | retval = request_irq(irq, rtclong1_interrupt, SA_INTERRUPT, | 352 | retval = request_irq(irq, rtclong1_interrupt, IRQF_DISABLED, |
361 | "rtclong1", pdev); | 353 | "rtclong1", pdev); |
362 | } | 354 | } |
363 | 355 | ||