diff options
author | Jesper Nilsson <jesper.nilsson@axis.com> | 2008-01-17 09:17:07 -0500 |
---|---|---|
committer | Jesper Nilsson <jesper.nilsson@axis.com> | 2008-02-08 05:06:29 -0500 |
commit | 34a8e501fe83f3b572eee56a6fca5111ab8cdf65 (patch) | |
tree | a4f0aa32e741dbb5386d898f6690c41bf7711204 /arch/cris | |
parent | e5d5cf2442038b8ad3e0f90b00e5acdd18d5fa98 (diff) |
CRIS v10: Update driver for pcf8563
- Use mutex instead of spinlock, fixes kernel bugzilla report 8339.
- Make sure that pcf8563_init can be called multiple times but only setup once.
- Change RTC_VLOW_RD -> RTC_VL_READ, RTC_VLOW_SET -> RTC_VL_CLR
- Cache the voltage low value at driver init so the battery status
information does not get 'accidentally' cleared when setting the RTC time.
- Add weekday handling.
- Correct leapyear handling to include 100 and 400 year exceptions.
- Correct whitespace and formatting errors.
- Remove useless CVS id tag.
Diffstat (limited to 'arch/cris')
-rw-r--r-- | arch/cris/arch-v10/drivers/pcf8563.c | 393 |
1 files changed, 220 insertions, 173 deletions
diff --git a/arch/cris/arch-v10/drivers/pcf8563.c b/arch/cris/arch-v10/drivers/pcf8563.c index c263b8232dbc..52103d16dc6c 100644 --- a/arch/cris/arch-v10/drivers/pcf8563.c +++ b/arch/cris/arch-v10/drivers/pcf8563.c | |||
@@ -8,14 +8,13 @@ | |||
8 | * low detector are also provided. All address and data are transferred | 8 | * low detector are also provided. All address and data are transferred |
9 | * serially via two-line bidirectional I2C-bus. Maximum bus speed is | 9 | * serially via two-line bidirectional I2C-bus. Maximum bus speed is |
10 | * 400 kbits/s. The built-in word address register is incremented | 10 | * 400 kbits/s. The built-in word address register is incremented |
11 | * automatically after each written or read bute. | 11 | * automatically after each written or read byte. |
12 | * | 12 | * |
13 | * Copyright (c) 2002, Axis Communications AB | 13 | * Copyright (c) 2002-2007, Axis Communications AB |
14 | * All rights reserved. | 14 | * All rights reserved. |
15 | * | 15 | * |
16 | * Author: Tobias Anderberg <tobiasa@axis.com>. | 16 | * Author: Tobias Anderberg <tobiasa@axis.com>. |
17 | * | 17 | * |
18 | * $Id: pcf8563.c,v 1.11 2005/03/07 13:13:07 starvik Exp $ | ||
19 | */ | 18 | */ |
20 | 19 | ||
21 | #include <linux/module.h> | 20 | #include <linux/module.h> |
@@ -27,19 +26,19 @@ | |||
27 | #include <linux/ioctl.h> | 26 | #include <linux/ioctl.h> |
28 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
29 | #include <linux/bcd.h> | 28 | #include <linux/bcd.h> |
30 | #include <linux/capability.h> | 29 | #include <linux/mutex.h> |
31 | 30 | ||
32 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
33 | #include <asm/system.h> | 32 | #include <asm/system.h> |
34 | #include <asm/io.h> | 33 | #include <asm/io.h> |
35 | #include <asm/arch/svinto.h> | ||
36 | #include <asm/rtc.h> | 34 | #include <asm/rtc.h> |
35 | |||
37 | #include "i2c.h" | 36 | #include "i2c.h" |
38 | 37 | ||
39 | #define PCF8563_MAJOR 121 /* Local major number. */ | 38 | #define PCF8563_MAJOR 121 /* Local major number. */ |
40 | #define DEVICE_NAME "rtc" /* Name which is registered in /proc/devices. */ | 39 | #define DEVICE_NAME "rtc" /* Name which is registered in /proc/devices. */ |
41 | #define PCF8563_NAME "PCF8563" | 40 | #define PCF8563_NAME "PCF8563" |
42 | #define DRIVER_VERSION "$Revision: 1.11 $" | 41 | #define DRIVER_VERSION "$Revision: 1.24 $" |
43 | 42 | ||
44 | /* I2C bus slave registers. */ | 43 | /* I2C bus slave registers. */ |
45 | #define RTC_I2C_READ 0xa3 | 44 | #define RTC_I2C_READ 0xa3 |
@@ -49,71 +48,88 @@ | |||
49 | #define rtc_read(x) i2c_readreg(RTC_I2C_READ, x) | 48 | #define rtc_read(x) i2c_readreg(RTC_I2C_READ, x) |
50 | #define rtc_write(x,y) i2c_writereg(RTC_I2C_WRITE, x, y) | 49 | #define rtc_write(x,y) i2c_writereg(RTC_I2C_WRITE, x, y) |
51 | 50 | ||
52 | static DEFINE_SPINLOCK(rtc_lock); /* Protect state etc */ | 51 | static DEFINE_MUTEX(rtc_lock); /* Protect state etc */ |
53 | 52 | ||
54 | static const unsigned char days_in_month[] = | 53 | static const unsigned char days_in_month[] = |
55 | { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; | 54 | { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; |
56 | 55 | ||
57 | int pcf8563_ioctl(struct inode *, struct file *, unsigned int, unsigned long); | 56 | int pcf8563_ioctl(struct inode *, struct file *, unsigned int, unsigned long); |
58 | 57 | ||
58 | /* Cache VL bit value read at driver init since writing the RTC_SECOND | ||
59 | * register clears the VL status. | ||
60 | */ | ||
61 | static int voltage_low; | ||
62 | |||
59 | static const struct file_operations pcf8563_fops = { | 63 | static const struct file_operations pcf8563_fops = { |
60 | .owner = THIS_MODULE, | 64 | .owner = THIS_MODULE, |
61 | .ioctl = pcf8563_ioctl, | 65 | .ioctl = pcf8563_ioctl, |
62 | }; | 66 | }; |
63 | 67 | ||
64 | unsigned char | 68 | unsigned char |
65 | pcf8563_readreg(int reg) | 69 | pcf8563_readreg(int reg) |
66 | { | 70 | { |
67 | unsigned char res = i2c_readreg(RTC_I2C_READ, reg); | 71 | unsigned char res = rtc_read(reg); |
68 | 72 | ||
69 | /* The PCF8563 does not return 0 for unimplemented bits */ | 73 | /* The PCF8563 does not return 0 for unimplemented bits. */ |
70 | switch(reg) | 74 | switch (reg) { |
71 | { | 75 | case RTC_SECONDS: |
72 | case RTC_SECONDS: | 76 | case RTC_MINUTES: |
73 | case RTC_MINUTES: | 77 | res &= 0x7F; |
74 | res &= 0x7f; | 78 | break; |
75 | break; | 79 | case RTC_HOURS: |
76 | case RTC_HOURS: | 80 | case RTC_DAY_OF_MONTH: |
77 | case RTC_DAY_OF_MONTH: | 81 | res &= 0x3F; |
78 | res &= 0x3f; | 82 | break; |
79 | break; | 83 | case RTC_WEEKDAY: |
80 | case RTC_MONTH: | 84 | res &= 0x07; |
81 | res = (res & 0x1f) - 1; /* PCF8563 returns month in range 1-12 */ | 85 | break; |
82 | break; | 86 | case RTC_MONTH: |
87 | res &= 0x1F; | ||
88 | break; | ||
89 | case RTC_CONTROL1: | ||
90 | res &= 0xA8; | ||
91 | break; | ||
92 | case RTC_CONTROL2: | ||
93 | res &= 0x1F; | ||
94 | break; | ||
95 | case RTC_CLOCKOUT_FREQ: | ||
96 | case RTC_TIMER_CONTROL: | ||
97 | res &= 0x83; | ||
98 | break; | ||
83 | } | 99 | } |
84 | return res; | 100 | return res; |
85 | } | 101 | } |
86 | 102 | ||
87 | void | 103 | void |
88 | pcf8563_writereg(int reg, unsigned char val) | 104 | pcf8563_writereg(int reg, unsigned char val) |
89 | { | 105 | { |
90 | #ifdef CONFIG_ETRAX_RTC_READONLY | ||
91 | if (reg == RTC_CONTROL1 || (reg >= RTC_SECONDS && reg <= RTC_YEAR)) | ||
92 | return; | ||
93 | #endif | ||
94 | |||
95 | rtc_write(reg, val); | 106 | rtc_write(reg, val); |
96 | } | 107 | } |
97 | 108 | ||
98 | void | 109 | void |
99 | get_rtc_time(struct rtc_time *tm) | 110 | get_rtc_time(struct rtc_time *tm) |
100 | { | 111 | { |
101 | tm->tm_sec = rtc_read(RTC_SECONDS); | 112 | tm->tm_sec = rtc_read(RTC_SECONDS); |
102 | tm->tm_min = rtc_read(RTC_MINUTES); | 113 | tm->tm_min = rtc_read(RTC_MINUTES); |
103 | tm->tm_hour = rtc_read(RTC_HOURS); | 114 | tm->tm_hour = rtc_read(RTC_HOURS); |
104 | tm->tm_mday = rtc_read(RTC_DAY_OF_MONTH); | 115 | tm->tm_mday = rtc_read(RTC_DAY_OF_MONTH); |
105 | tm->tm_mon = rtc_read(RTC_MONTH); | 116 | tm->tm_wday = rtc_read(RTC_WEEKDAY); |
117 | tm->tm_mon = rtc_read(RTC_MONTH); | ||
106 | tm->tm_year = rtc_read(RTC_YEAR); | 118 | tm->tm_year = rtc_read(RTC_YEAR); |
107 | 119 | ||
108 | if (tm->tm_sec & 0x80) | 120 | if (tm->tm_sec & 0x80) { |
109 | printk(KERN_WARNING "%s: RTC Low Voltage - date/time is not reliable!\n", PCF8563_NAME); | 121 | printk(KERN_ERR "%s: RTC Voltage Low - reliable date/time " |
122 | "information is no longer guaranteed!\n", PCF8563_NAME); | ||
123 | } | ||
110 | 124 | ||
111 | tm->tm_year = BCD_TO_BIN(tm->tm_year) + ((tm->tm_mon & 0x80) ? 100 : 0); | 125 | tm->tm_year = BCD_TO_BIN(tm->tm_year) + |
112 | tm->tm_sec &= 0x7f; | 126 | ((tm->tm_mon & 0x80) ? 100 : 0); |
113 | tm->tm_min &= 0x7f; | 127 | tm->tm_sec &= 0x7F; |
114 | tm->tm_hour &= 0x3f; | 128 | tm->tm_min &= 0x7F; |
115 | tm->tm_mday &= 0x3f; | 129 | tm->tm_hour &= 0x3F; |
116 | tm->tm_mon &= 0x1f; | 130 | tm->tm_mday &= 0x3F; |
131 | tm->tm_wday &= 0x07; /* Not coded in BCD. */ | ||
132 | tm->tm_mon &= 0x1F; | ||
117 | 133 | ||
118 | BCD_TO_BIN(tm->tm_sec); | 134 | BCD_TO_BIN(tm->tm_sec); |
119 | BCD_TO_BIN(tm->tm_min); | 135 | BCD_TO_BIN(tm->tm_min); |
@@ -126,17 +142,24 @@ get_rtc_time(struct rtc_time *tm) | |||
126 | int __init | 142 | int __init |
127 | pcf8563_init(void) | 143 | pcf8563_init(void) |
128 | { | 144 | { |
129 | int ret; | 145 | static int res; |
130 | 146 | static int first = 1; | |
131 | if ((ret = i2c_init())) { | 147 | |
132 | printk(KERN_CRIT "pcf8563_init: failed to init i2c\n"); | 148 | if (!first) |
133 | return ret; | 149 | return res; |
150 | first = 0; | ||
151 | |||
152 | /* Initiate the i2c protocol. */ | ||
153 | res = i2c_init(); | ||
154 | if (res < 0) { | ||
155 | printk(KERN_CRIT "pcf8563_init: Failed to init i2c.\n"); | ||
156 | return res; | ||
134 | } | 157 | } |
135 | 158 | ||
136 | /* | 159 | /* |
137 | * First of all we need to reset the chip. This is done by | 160 | * First of all we need to reset the chip. This is done by |
138 | * clearing control1, control2 and clk freq, clear the | 161 | * clearing control1, control2 and clk freq and resetting |
139 | * Voltage Low bit, and resetting all alarms. | 162 | * all alarms. |
140 | */ | 163 | */ |
141 | if (rtc_write(RTC_CONTROL1, 0x00) < 0) | 164 | if (rtc_write(RTC_CONTROL1, 0x00) < 0) |
142 | goto err; | 165 | goto err; |
@@ -147,34 +170,36 @@ pcf8563_init(void) | |||
147 | if (rtc_write(RTC_CLOCKOUT_FREQ, 0x00) < 0) | 170 | if (rtc_write(RTC_CLOCKOUT_FREQ, 0x00) < 0) |
148 | goto err; | 171 | goto err; |
149 | 172 | ||
150 | /* Clear the VL bit in the seconds register. */ | 173 | if (rtc_write(RTC_TIMER_CONTROL, 0x03) < 0) |
151 | ret = rtc_read(RTC_SECONDS); | ||
152 | |||
153 | if (rtc_write(RTC_SECONDS, (ret & 0x7f)) < 0) | ||
154 | goto err; | 174 | goto err; |
155 | 175 | ||
156 | /* Reset the alarms. */ | 176 | /* Reset the alarms. */ |
157 | if (rtc_write(RTC_MINUTE_ALARM, 0x00) < 0) | 177 | if (rtc_write(RTC_MINUTE_ALARM, 0x80) < 0) |
158 | goto err; | 178 | goto err; |
159 | 179 | ||
160 | if (rtc_write(RTC_HOUR_ALARM, 0x00) < 0) | 180 | if (rtc_write(RTC_HOUR_ALARM, 0x80) < 0) |
161 | goto err; | 181 | goto err; |
162 | 182 | ||
163 | if (rtc_write(RTC_DAY_ALARM, 0x00) < 0) | 183 | if (rtc_write(RTC_DAY_ALARM, 0x80) < 0) |
164 | goto err; | 184 | goto err; |
165 | 185 | ||
166 | if (rtc_write(RTC_WEEKDAY_ALARM, 0x00) < 0) | 186 | if (rtc_write(RTC_WEEKDAY_ALARM, 0x80) < 0) |
167 | goto err; | 187 | goto err; |
168 | 188 | ||
169 | /* Check for low voltage, and warn about it.. */ | 189 | /* Check for low voltage, and warn about it. */ |
170 | if (rtc_read(RTC_SECONDS) & 0x80) | 190 | if (rtc_read(RTC_SECONDS) & 0x80) { |
171 | printk(KERN_WARNING "%s: RTC Low Voltage - date/time is not reliable!\n", PCF8563_NAME); | 191 | voltage_low = 1; |
172 | 192 | printk(KERN_WARNING "%s: RTC Voltage Low - reliable " | |
173 | return 0; | 193 | "date/time information is no longer guaranteed!\n", |
194 | PCF8563_NAME); | ||
195 | } | ||
196 | |||
197 | return res; | ||
174 | 198 | ||
175 | err: | 199 | err: |
176 | printk(KERN_INFO "%s: Error initializing chip.\n", PCF8563_NAME); | 200 | printk(KERN_INFO "%s: Error initializing chip.\n", PCF8563_NAME); |
177 | return -1; | 201 | res = -1; |
202 | return res; | ||
178 | } | 203 | } |
179 | 204 | ||
180 | void __exit | 205 | void __exit |
@@ -187,8 +212,8 @@ pcf8563_exit(void) | |||
187 | * ioctl calls for this driver. Why return -ENOTTY upon error? Because | 212 | * ioctl calls for this driver. Why return -ENOTTY upon error? Because |
188 | * POSIX says so! | 213 | * POSIX says so! |
189 | */ | 214 | */ |
190 | int | 215 | int pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, |
191 | pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) | 216 | unsigned long arg) |
192 | { | 217 | { |
193 | /* Some sanity checks. */ | 218 | /* Some sanity checks. */ |
194 | if (_IOC_TYPE(cmd) != RTC_MAGIC) | 219 | if (_IOC_TYPE(cmd) != RTC_MAGIC) |
@@ -198,124 +223,146 @@ pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned | |||
198 | return -ENOTTY; | 223 | return -ENOTTY; |
199 | 224 | ||
200 | switch (cmd) { | 225 | switch (cmd) { |
201 | case RTC_RD_TIME: | 226 | case RTC_RD_TIME: |
202 | { | 227 | { |
203 | struct rtc_time tm; | 228 | struct rtc_time tm; |
204 | |||
205 | spin_lock(&rtc_lock); | ||
206 | get_rtc_time(&tm); | ||
207 | |||
208 | if (copy_to_user((struct rtc_time *) arg, &tm, sizeof(struct rtc_time))) { | ||
209 | spin_unlock(&rtc_lock); | ||
210 | return -EFAULT; | ||
211 | } | ||
212 | |||
213 | spin_unlock(&rtc_lock); | ||
214 | return 0; | ||
215 | } | ||
216 | break; | ||
217 | case RTC_SET_TIME: | ||
218 | { | ||
219 | #ifdef CONFIG_ETRAX_RTC_READONLY | ||
220 | return -EPERM; | ||
221 | #else | ||
222 | int leap; | ||
223 | int century; | ||
224 | struct rtc_time tm; | ||
225 | |||
226 | memset(&tm, 0, sizeof (struct rtc_time)); | ||
227 | if (!capable(CAP_SYS_TIME)) | ||
228 | return -EPERM; | ||
229 | |||
230 | if (copy_from_user(&tm, (struct rtc_time *) arg, sizeof(struct rtc_time))) | ||
231 | return -EFAULT; | ||
232 | |||
233 | /* Convert from struct tm to struct rtc_time. */ | ||
234 | tm.tm_year += 1900; | ||
235 | tm.tm_mon += 1; | ||
236 | |||
237 | leap = ((tm.tm_mon == 2) && ((tm.tm_year % 4) == 0)) ? 1 : 0; | ||
238 | |||
239 | /* Perform some sanity checks. */ | ||
240 | if ((tm.tm_year < 1970) || | ||
241 | (tm.tm_mon > 12) || | ||
242 | (tm.tm_mday == 0) || | ||
243 | (tm.tm_mday > days_in_month[tm.tm_mon] + leap) || | ||
244 | (tm.tm_hour >= 24) || | ||
245 | (tm.tm_min >= 60) || | ||
246 | (tm.tm_sec >= 60)) | ||
247 | return -EINVAL; | ||
248 | |||
249 | century = (tm.tm_year >= 2000) ? 0x80 : 0; | ||
250 | tm.tm_year = tm.tm_year % 100; | ||
251 | |||
252 | BIN_TO_BCD(tm.tm_year); | ||
253 | BIN_TO_BCD(tm.tm_mday); | ||
254 | BIN_TO_BCD(tm.tm_hour); | ||
255 | BIN_TO_BCD(tm.tm_min); | ||
256 | BIN_TO_BCD(tm.tm_sec); | ||
257 | tm.tm_mon |= century; | ||
258 | |||
259 | spin_lock(&rtc_lock); | ||
260 | |||
261 | rtc_write(RTC_YEAR, tm.tm_year); | ||
262 | rtc_write(RTC_MONTH, tm.tm_mon); | ||
263 | rtc_write(RTC_DAY_OF_MONTH, tm.tm_mday); | ||
264 | rtc_write(RTC_HOURS, tm.tm_hour); | ||
265 | rtc_write(RTC_MINUTES, tm.tm_min); | ||
266 | rtc_write(RTC_SECONDS, tm.tm_sec); | ||
267 | |||
268 | spin_unlock(&rtc_lock); | ||
269 | |||
270 | return 0; | ||
271 | #endif /* !CONFIG_ETRAX_RTC_READONLY */ | ||
272 | } | ||
273 | |||
274 | case RTC_VLOW_RD: | ||
275 | { | ||
276 | int vl_bit = 0; | ||
277 | |||
278 | if (rtc_read(RTC_SECONDS) & 0x80) { | ||
279 | vl_bit = 1; | ||
280 | printk(KERN_WARNING "%s: RTC Voltage Low - reliable " | ||
281 | "date/time information is no longer guaranteed!\n", | ||
282 | PCF8563_NAME); | ||
283 | } | ||
284 | if (copy_to_user((int *) arg, &vl_bit, sizeof(int))) | ||
285 | return -EFAULT; | ||
286 | |||
287 | return 0; | ||
288 | } | ||
289 | 229 | ||
290 | case RTC_VLOW_SET: | 230 | mutex_lock(&rtc_lock); |
291 | { | 231 | memset(&tm, 0, sizeof tm); |
292 | /* Clear the VL bit in the seconds register */ | 232 | get_rtc_time(&tm); |
293 | int ret = rtc_read(RTC_SECONDS); | ||
294 | 233 | ||
295 | rtc_write(RTC_SECONDS, (ret & 0x7F)); | 234 | if (copy_to_user((struct rtc_time *) arg, &tm, |
235 | sizeof tm)) { | ||
236 | spin_unlock(&rtc_lock); | ||
237 | return -EFAULT; | ||
238 | } | ||
239 | |||
240 | mutex_unlock(&rtc_lock); | ||
296 | 241 | ||
297 | return 0; | 242 | return 0; |
243 | } | ||
244 | case RTC_SET_TIME: | ||
245 | { | ||
246 | int leap; | ||
247 | int year; | ||
248 | int century; | ||
249 | struct rtc_time tm; | ||
250 | |||
251 | memset(&tm, 0, sizeof tm); | ||
252 | if (!capable(CAP_SYS_TIME)) | ||
253 | return -EPERM; | ||
254 | |||
255 | if (copy_from_user(&tm, (struct rtc_time *) arg, sizeof tm)) | ||
256 | return -EFAULT; | ||
257 | |||
258 | /* Convert from struct tm to struct rtc_time. */ | ||
259 | tm.tm_year += 1900; | ||
260 | tm.tm_mon += 1; | ||
261 | |||
262 | /* | ||
263 | * Check if tm.tm_year is a leap year. A year is a leap | ||
264 | * year if it is divisible by 4 but not 100, except | ||
265 | * that years divisible by 400 _are_ leap years. | ||
266 | */ | ||
267 | year = tm.tm_year; | ||
268 | leap = (tm.tm_mon == 2) && | ||
269 | ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0); | ||
270 | |||
271 | /* Perform some sanity checks. */ | ||
272 | if ((tm.tm_year < 1970) || | ||
273 | (tm.tm_mon > 12) || | ||
274 | (tm.tm_mday == 0) || | ||
275 | (tm.tm_mday > days_in_month[tm.tm_mon] + leap) || | ||
276 | (tm.tm_wday >= 7) || | ||
277 | (tm.tm_hour >= 24) || | ||
278 | (tm.tm_min >= 60) || | ||
279 | (tm.tm_sec >= 60)) | ||
280 | return -EINVAL; | ||
281 | |||
282 | century = (tm.tm_year >= 2000) ? 0x80 : 0; | ||
283 | tm.tm_year = tm.tm_year % 100; | ||
284 | |||
285 | BIN_TO_BCD(tm.tm_year); | ||
286 | BIN_TO_BCD(tm.tm_mon); | ||
287 | BIN_TO_BCD(tm.tm_mday); | ||
288 | BIN_TO_BCD(tm.tm_hour); | ||
289 | BIN_TO_BCD(tm.tm_min); | ||
290 | BIN_TO_BCD(tm.tm_sec); | ||
291 | tm.tm_mon |= century; | ||
292 | |||
293 | mutex_lock(&rtc_lock); | ||
294 | |||
295 | rtc_write(RTC_YEAR, tm.tm_year); | ||
296 | rtc_write(RTC_MONTH, tm.tm_mon); | ||
297 | rtc_write(RTC_WEEKDAY, tm.tm_wday); /* Not coded in BCD. */ | ||
298 | rtc_write(RTC_DAY_OF_MONTH, tm.tm_mday); | ||
299 | rtc_write(RTC_HOURS, tm.tm_hour); | ||
300 | rtc_write(RTC_MINUTES, tm.tm_min); | ||
301 | rtc_write(RTC_SECONDS, tm.tm_sec); | ||
302 | |||
303 | mutex_unlock(&rtc_lock); | ||
304 | |||
305 | return 0; | ||
306 | } | ||
307 | case RTC_VL_READ: | ||
308 | if (voltage_low) { | ||
309 | printk(KERN_ERR "%s: RTC Voltage Low - " | ||
310 | "reliable date/time information is no " | ||
311 | "longer guaranteed!\n", PCF8563_NAME); | ||
298 | } | 312 | } |
299 | 313 | ||
300 | default: | 314 | if (copy_to_user((int *) arg, &voltage_low, sizeof(int))) |
301 | return -ENOTTY; | 315 | return -EFAULT; |
316 | return 0; | ||
317 | |||
318 | case RTC_VL_CLR: | ||
319 | { | ||
320 | /* Clear the VL bit in the seconds register in case | ||
321 | * the time has not been set already (which would | ||
322 | * have cleared it). This does not really matter | ||
323 | * because of the cached voltage_low value but do it | ||
324 | * anyway for consistency. */ | ||
325 | |||
326 | int ret = rtc_read(RTC_SECONDS); | ||
327 | |||
328 | rtc_write(RTC_SECONDS, (ret & 0x7F)); | ||
329 | |||
330 | /* Clear the cached value. */ | ||
331 | voltage_low = 0; | ||
332 | |||
333 | return 0; | ||
334 | } | ||
335 | default: | ||
336 | return -ENOTTY; | ||
302 | } | 337 | } |
303 | 338 | ||
304 | return 0; | 339 | return 0; |
305 | } | 340 | } |
306 | 341 | ||
307 | static int __init | 342 | static int __init pcf8563_register(void) |
308 | pcf8563_register(void) | ||
309 | { | 343 | { |
310 | pcf8563_init(); | 344 | if (pcf8563_init() < 0) { |
345 | printk(KERN_INFO "%s: Unable to initialize Real-Time Clock " | ||
346 | "Driver, %s\n", PCF8563_NAME, DRIVER_VERSION); | ||
347 | return -1; | ||
348 | } | ||
349 | |||
311 | if (register_chrdev(PCF8563_MAJOR, DEVICE_NAME, &pcf8563_fops) < 0) { | 350 | if (register_chrdev(PCF8563_MAJOR, DEVICE_NAME, &pcf8563_fops) < 0) { |
312 | printk(KERN_INFO "%s: Unable to get major number %d for RTC device.\n", | 351 | printk(KERN_INFO "%s: Unable to get major number %d for RTC device.\n", |
313 | PCF8563_NAME, PCF8563_MAJOR); | 352 | PCF8563_NAME, PCF8563_MAJOR); |
314 | return -1; | 353 | return -1; |
315 | } | 354 | } |
316 | 355 | ||
317 | printk(KERN_INFO "%s Real-Time Clock Driver, %s\n", PCF8563_NAME, DRIVER_VERSION); | 356 | printk(KERN_INFO "%s Real-Time Clock Driver, %s\n", PCF8563_NAME, |
318 | return 0; | 357 | DRIVER_VERSION); |
358 | |||
359 | /* Check for low voltage, and warn about it. */ | ||
360 | if (voltage_low) { | ||
361 | printk(KERN_WARNING "%s: RTC Voltage Low - reliable date/time " | ||
362 | "information is no longer guaranteed!\n", PCF8563_NAME); | ||
363 | } | ||
364 | |||
365 | return 0; | ||
319 | } | 366 | } |
320 | 367 | ||
321 | module_init(pcf8563_register); | 368 | module_init(pcf8563_register); |