diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/cris/arch-v10/drivers/ds1302.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/cris/arch-v10/drivers/ds1302.c')
-rw-r--r-- | arch/cris/arch-v10/drivers/ds1302.c | 602 |
1 files changed, 602 insertions, 0 deletions
diff --git a/arch/cris/arch-v10/drivers/ds1302.c b/arch/cris/arch-v10/drivers/ds1302.c new file mode 100644 index 000000000000..fba530fcfaeb --- /dev/null +++ b/arch/cris/arch-v10/drivers/ds1302.c | |||
@@ -0,0 +1,602 @@ | |||
1 | /*!*************************************************************************** | ||
2 | *! | ||
3 | *! FILE NAME : ds1302.c | ||
4 | *! | ||
5 | *! DESCRIPTION: Implements an interface for the DS1302 RTC through Etrax I/O | ||
6 | *! | ||
7 | *! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init | ||
8 | *! | ||
9 | *! $Log: ds1302.c,v $ | ||
10 | *! Revision 1.14 2004/08/24 06:48:43 starvik | ||
11 | *! Whitespace cleanup | ||
12 | *! | ||
13 | *! Revision 1.13 2004/05/28 09:26:59 starvik | ||
14 | *! Modified I2C initialization to work in 2.6. | ||
15 | *! | ||
16 | *! Revision 1.12 2004/05/14 07:58:03 starvik | ||
17 | *! Merge of changes from 2.4 | ||
18 | *! | ||
19 | *! Revision 1.10 2004/02/04 09:25:12 starvik | ||
20 | *! Merge of Linux 2.6.2 | ||
21 | *! | ||
22 | *! Revision 1.9 2003/07/04 08:27:37 starvik | ||
23 | *! Merge of Linux 2.5.74 | ||
24 | *! | ||
25 | *! Revision 1.8 2003/04/09 05:20:47 starvik | ||
26 | *! Merge of Linux 2.5.67 | ||
27 | *! | ||
28 | *! Revision 1.6 2003/01/09 14:42:51 starvik | ||
29 | *! Merge of Linux 2.5.55 | ||
30 | *! | ||
31 | *! Revision 1.4 2002/12/11 13:13:57 starvik | ||
32 | *! Added arch/ to v10 specific includes | ||
33 | *! Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer) | ||
34 | *! | ||
35 | *! Revision 1.3 2002/11/20 11:56:10 starvik | ||
36 | *! Merge of Linux 2.5.48 | ||
37 | *! | ||
38 | *! Revision 1.2 2002/11/18 13:16:06 starvik | ||
39 | *! Linux 2.5 port of latest 2.4 drivers | ||
40 | *! | ||
41 | *! Revision 1.15 2002/10/11 16:14:33 johana | ||
42 | *! Added CONFIG_ETRAX_DS1302_TRICKLE_CHARGE and initial setting of the | ||
43 | *! trcklecharge register. | ||
44 | *! | ||
45 | *! Revision 1.14 2002/10/10 12:15:38 magnusmn | ||
46 | *! Added support for having the RST signal on bit g0 | ||
47 | *! | ||
48 | *! Revision 1.13 2002/05/29 15:16:08 johana | ||
49 | *! Removed unused variables. | ||
50 | *! | ||
51 | *! Revision 1.12 2002/04/10 15:35:25 johana | ||
52 | *! Moved probe function closer to init function and marked it __init. | ||
53 | *! | ||
54 | *! Revision 1.11 2001/06/14 12:35:52 jonashg | ||
55 | *! The ATA hack is back. It is unfortunately the only way to set g27 to output. | ||
56 | *! | ||
57 | *! Revision 1.9 2001/06/14 10:00:14 jonashg | ||
58 | *! No need for tempudelay to be inline anymore (had to adjust the usec to | ||
59 | *! loops conversion because of this to make it slow enough to be a udelay). | ||
60 | *! | ||
61 | *! Revision 1.8 2001/06/14 08:06:32 jonashg | ||
62 | *! Made tempudelay delay usecs (well, just a tad more). | ||
63 | *! | ||
64 | *! Revision 1.7 2001/06/13 14:18:11 jonashg | ||
65 | *! Only allow processes with SYS_TIME capability to set time and charge. | ||
66 | *! | ||
67 | *! Revision 1.6 2001/06/12 15:22:07 jonashg | ||
68 | *! * Made init function __init. | ||
69 | *! * Parameter to out_byte() is unsigned char. | ||
70 | *! * The magic number 42 has got a name. | ||
71 | *! * Removed comment about /proc (nothing is exported there). | ||
72 | *! | ||
73 | *! Revision 1.5 2001/06/12 14:35:13 jonashg | ||
74 | *! Gave the module a name and added it to printk's. | ||
75 | *! | ||
76 | *! Revision 1.4 2001/05/31 14:53:40 jonashg | ||
77 | *! Made tempudelay() inline so that the watchdog doesn't reset (see | ||
78 | *! function comment). | ||
79 | *! | ||
80 | *! Revision 1.3 2001/03/26 16:03:06 bjornw | ||
81 | *! Needs linux/config.h | ||
82 | *! | ||
83 | *! Revision 1.2 2001/03/20 19:42:00 bjornw | ||
84 | *! Use the ETRAX prefix on the DS1302 options | ||
85 | *! | ||
86 | *! Revision 1.1 2001/03/20 09:13:50 magnusmn | ||
87 | *! Linux 2.4 port | ||
88 | *! | ||
89 | *! Revision 1.10 2000/07/05 15:38:23 bjornw | ||
90 | *! Dont update kernel time when a RTC_SET_TIME is done | ||
91 | *! | ||
92 | *! Revision 1.9 2000/03/02 15:42:59 macce | ||
93 | *! * Hack to make RTC work on all 2100/2400 | ||
94 | *! | ||
95 | *! Revision 1.8 2000/02/23 16:59:18 torbjore | ||
96 | *! added setup of R_GEN_CONFIG when RTC is connected to the generic port. | ||
97 | *! | ||
98 | *! Revision 1.7 2000/01/17 15:51:43 johana | ||
99 | *! Added RTC_SET_CHARGE ioctl to enable trickle charger. | ||
100 | *! | ||
101 | *! Revision 1.6 1999/10/27 13:19:47 bjornw | ||
102 | *! Added update_xtime_from_cmos which reads back the updated RTC into the kernel. | ||
103 | *! /dev/rtc calls it now. | ||
104 | *! | ||
105 | *! Revision 1.5 1999/10/27 12:39:37 bjornw | ||
106 | *! Disabled superuser check. Anyone can now set the time. | ||
107 | *! | ||
108 | *! Revision 1.4 1999/09/02 13:27:46 pkj | ||
109 | *! Added shadow for R_PORT_PB_CONFIG. | ||
110 | *! Renamed port_g_shadow to port_g_data_shadow. | ||
111 | *! | ||
112 | *! Revision 1.3 1999/09/02 08:28:06 pkj | ||
113 | *! Made it possible to select either port PB or the generic port for the RST | ||
114 | *! signal line to the DS1302 RTC. | ||
115 | *! Also make sure the RST bit is configured as output on Port PB (if used). | ||
116 | *! | ||
117 | *! Revision 1.2 1999/09/01 14:47:20 bjornw | ||
118 | *! Added support for /dev/rtc operations with ioctl RD_TIME and SET_TIME to read | ||
119 | *! and set the date. Register as major 121. | ||
120 | *! | ||
121 | *! Revision 1.1 1999/09/01 09:45:29 bjornw | ||
122 | *! Implemented a DS1302 RTC driver. | ||
123 | *! | ||
124 | *! | ||
125 | *! --------------------------------------------------------------------------- | ||
126 | *! | ||
127 | *! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN | ||
128 | *! | ||
129 | *! $Id: ds1302.c,v 1.14 2004/08/24 06:48:43 starvik Exp $ | ||
130 | *! | ||
131 | *!***************************************************************************/ | ||
132 | |||
133 | #include <linux/config.h> | ||
134 | |||
135 | #include <linux/fs.h> | ||
136 | #include <linux/init.h> | ||
137 | #include <linux/mm.h> | ||
138 | #include <linux/module.h> | ||
139 | #include <linux/miscdevice.h> | ||
140 | #include <linux/delay.h> | ||
141 | #include <linux/bcd.h> | ||
142 | |||
143 | #include <asm/uaccess.h> | ||
144 | #include <asm/system.h> | ||
145 | #include <asm/arch/svinto.h> | ||
146 | #include <asm/io.h> | ||
147 | #include <asm/rtc.h> | ||
148 | |||
149 | #define RTC_MAJOR_NR 121 /* local major, change later */ | ||
150 | |||
151 | static const char ds1302_name[] = "ds1302"; | ||
152 | |||
153 | /* The DS1302 might be connected to different bits on different products. | ||
154 | * It has three signals - SDA, SCL and RST. RST and SCL are always outputs, | ||
155 | * but SDA can have a selected direction. | ||
156 | * For now, only PORT_PB is hardcoded. | ||
157 | */ | ||
158 | |||
159 | /* The RST bit may be on either the Generic Port or Port PB. */ | ||
160 | #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT | ||
161 | #define TK_RST_OUT(x) REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x) | ||
162 | #define TK_RST_DIR(x) | ||
163 | #else | ||
164 | #define TK_RST_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x) | ||
165 | #define TK_RST_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x) | ||
166 | #endif | ||
167 | |||
168 | |||
169 | #define TK_SDA_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_SDABIT, x) | ||
170 | #define TK_SCL_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_SCLBIT, x) | ||
171 | |||
172 | #define TK_SDA_IN() ((*R_PORT_PB_READ >> CONFIG_ETRAX_DS1302_SDABIT) & 1) | ||
173 | /* 1 is out, 0 is in */ | ||
174 | #define TK_SDA_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, CONFIG_ETRAX_DS1302_SDABIT, x) | ||
175 | #define TK_SCL_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, CONFIG_ETRAX_DS1302_SCLBIT, x) | ||
176 | |||
177 | |||
178 | /* | ||
179 | * The reason for tempudelay and not udelay is that loops_per_usec | ||
180 | * (used in udelay) is not set when functions here are called from time.c | ||
181 | */ | ||
182 | |||
183 | static void tempudelay(int usecs) | ||
184 | { | ||
185 | volatile int loops; | ||
186 | |||
187 | for(loops = usecs * 12; loops > 0; loops--) | ||
188 | /* nothing */; | ||
189 | } | ||
190 | |||
191 | |||
192 | /* Send 8 bits. */ | ||
193 | static void | ||
194 | out_byte(unsigned char x) | ||
195 | { | ||
196 | int i; | ||
197 | TK_SDA_DIR(1); | ||
198 | for (i = 8; i--;) { | ||
199 | /* The chip latches incoming bits on the rising edge of SCL. */ | ||
200 | TK_SCL_OUT(0); | ||
201 | TK_SDA_OUT(x & 1); | ||
202 | tempudelay(1); | ||
203 | TK_SCL_OUT(1); | ||
204 | tempudelay(1); | ||
205 | x >>= 1; | ||
206 | } | ||
207 | TK_SDA_DIR(0); | ||
208 | } | ||
209 | |||
210 | static unsigned char | ||
211 | in_byte(void) | ||
212 | { | ||
213 | unsigned char x = 0; | ||
214 | int i; | ||
215 | |||
216 | /* Read byte. Bits come LSB first, on the falling edge of SCL. | ||
217 | * Assume SDA is in input direction already. | ||
218 | */ | ||
219 | TK_SDA_DIR(0); | ||
220 | |||
221 | for (i = 8; i--;) { | ||
222 | TK_SCL_OUT(0); | ||
223 | tempudelay(1); | ||
224 | x >>= 1; | ||
225 | x |= (TK_SDA_IN() << 7); | ||
226 | TK_SCL_OUT(1); | ||
227 | tempudelay(1); | ||
228 | } | ||
229 | |||
230 | return x; | ||
231 | } | ||
232 | |||
233 | /* Prepares for a transaction by de-activating RST (active-low). */ | ||
234 | |||
235 | static void | ||
236 | start(void) | ||
237 | { | ||
238 | TK_SCL_OUT(0); | ||
239 | tempudelay(1); | ||
240 | TK_RST_OUT(0); | ||
241 | tempudelay(5); | ||
242 | TK_RST_OUT(1); | ||
243 | } | ||
244 | |||
245 | /* Ends a transaction by taking RST active again. */ | ||
246 | |||
247 | static void | ||
248 | stop(void) | ||
249 | { | ||
250 | tempudelay(2); | ||
251 | TK_RST_OUT(0); | ||
252 | } | ||
253 | |||
254 | /* Enable writing. */ | ||
255 | |||
256 | static void | ||
257 | ds1302_wenable(void) | ||
258 | { | ||
259 | start(); | ||
260 | out_byte(0x8e); /* Write control register */ | ||
261 | out_byte(0x00); /* Disable write protect bit 7 = 0 */ | ||
262 | stop(); | ||
263 | } | ||
264 | |||
265 | /* Disable writing. */ | ||
266 | |||
267 | static void | ||
268 | ds1302_wdisable(void) | ||
269 | { | ||
270 | start(); | ||
271 | out_byte(0x8e); /* Write control register */ | ||
272 | out_byte(0x80); /* Disable write protect bit 7 = 0 */ | ||
273 | stop(); | ||
274 | } | ||
275 | |||
276 | |||
277 | |||
278 | /* Read a byte from the selected register in the DS1302. */ | ||
279 | |||
280 | unsigned char | ||
281 | ds1302_readreg(int reg) | ||
282 | { | ||
283 | unsigned char x; | ||
284 | |||
285 | start(); | ||
286 | out_byte(0x81 | (reg << 1)); /* read register */ | ||
287 | x = in_byte(); | ||
288 | stop(); | ||
289 | |||
290 | return x; | ||
291 | } | ||
292 | |||
293 | /* Write a byte to the selected register. */ | ||
294 | |||
295 | void | ||
296 | ds1302_writereg(int reg, unsigned char val) | ||
297 | { | ||
298 | #ifndef CONFIG_ETRAX_RTC_READONLY | ||
299 | int do_writereg = 1; | ||
300 | #else | ||
301 | int do_writereg = 0; | ||
302 | |||
303 | if (reg == RTC_TRICKLECHARGER) | ||
304 | do_writereg = 1; | ||
305 | #endif | ||
306 | |||
307 | if (do_writereg) { | ||
308 | ds1302_wenable(); | ||
309 | start(); | ||
310 | out_byte(0x80 | (reg << 1)); /* write register */ | ||
311 | out_byte(val); | ||
312 | stop(); | ||
313 | ds1302_wdisable(); | ||
314 | } | ||
315 | } | ||
316 | |||
317 | void | ||
318 | get_rtc_time(struct rtc_time *rtc_tm) | ||
319 | { | ||
320 | unsigned long flags; | ||
321 | |||
322 | local_irq_save(flags); | ||
323 | local_irq_disable(); | ||
324 | |||
325 | rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); | ||
326 | rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); | ||
327 | rtc_tm->tm_hour = CMOS_READ(RTC_HOURS); | ||
328 | rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); | ||
329 | rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); | ||
330 | rtc_tm->tm_year = CMOS_READ(RTC_YEAR); | ||
331 | |||
332 | local_irq_restore(flags); | ||
333 | |||
334 | BCD_TO_BIN(rtc_tm->tm_sec); | ||
335 | BCD_TO_BIN(rtc_tm->tm_min); | ||
336 | BCD_TO_BIN(rtc_tm->tm_hour); | ||
337 | BCD_TO_BIN(rtc_tm->tm_mday); | ||
338 | BCD_TO_BIN(rtc_tm->tm_mon); | ||
339 | BCD_TO_BIN(rtc_tm->tm_year); | ||
340 | |||
341 | /* | ||
342 | * Account for differences between how the RTC uses the values | ||
343 | * and how they are defined in a struct rtc_time; | ||
344 | */ | ||
345 | |||
346 | if (rtc_tm->tm_year <= 69) | ||
347 | rtc_tm->tm_year += 100; | ||
348 | |||
349 | rtc_tm->tm_mon--; | ||
350 | } | ||
351 | |||
352 | static unsigned char days_in_mo[] = | ||
353 | {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; | ||
354 | |||
355 | /* ioctl that supports RTC_RD_TIME and RTC_SET_TIME (read and set time/date). */ | ||
356 | |||
357 | static int | ||
358 | rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | ||
359 | unsigned long arg) | ||
360 | { | ||
361 | unsigned long flags; | ||
362 | |||
363 | switch(cmd) { | ||
364 | case RTC_RD_TIME: /* read the time/date from RTC */ | ||
365 | { | ||
366 | struct rtc_time rtc_tm; | ||
367 | |||
368 | memset(&rtc_tm, 0, sizeof (struct rtc_time)); | ||
369 | get_rtc_time(&rtc_tm); | ||
370 | if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time))) | ||
371 | return -EFAULT; | ||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | case RTC_SET_TIME: /* set the RTC */ | ||
376 | { | ||
377 | struct rtc_time rtc_tm; | ||
378 | unsigned char mon, day, hrs, min, sec, leap_yr; | ||
379 | unsigned int yrs; | ||
380 | |||
381 | if (!capable(CAP_SYS_TIME)) | ||
382 | return -EPERM; | ||
383 | |||
384 | if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) | ||
385 | return -EFAULT; | ||
386 | |||
387 | yrs = rtc_tm.tm_year + 1900; | ||
388 | mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ | ||
389 | day = rtc_tm.tm_mday; | ||
390 | hrs = rtc_tm.tm_hour; | ||
391 | min = rtc_tm.tm_min; | ||
392 | sec = rtc_tm.tm_sec; | ||
393 | |||
394 | |||
395 | if ((yrs < 1970) || (yrs > 2069)) | ||
396 | return -EINVAL; | ||
397 | |||
398 | leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); | ||
399 | |||
400 | if ((mon > 12) || (day == 0)) | ||
401 | return -EINVAL; | ||
402 | |||
403 | if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) | ||
404 | return -EINVAL; | ||
405 | |||
406 | if ((hrs >= 24) || (min >= 60) || (sec >= 60)) | ||
407 | return -EINVAL; | ||
408 | |||
409 | if (yrs >= 2000) | ||
410 | yrs -= 2000; /* RTC (0, 1, ... 69) */ | ||
411 | else | ||
412 | yrs -= 1900; /* RTC (70, 71, ... 99) */ | ||
413 | |||
414 | BIN_TO_BCD(sec); | ||
415 | BIN_TO_BCD(min); | ||
416 | BIN_TO_BCD(hrs); | ||
417 | BIN_TO_BCD(day); | ||
418 | BIN_TO_BCD(mon); | ||
419 | BIN_TO_BCD(yrs); | ||
420 | |||
421 | local_irq_save(flags); | ||
422 | local_irq_disable(); | ||
423 | CMOS_WRITE(yrs, RTC_YEAR); | ||
424 | CMOS_WRITE(mon, RTC_MONTH); | ||
425 | CMOS_WRITE(day, RTC_DAY_OF_MONTH); | ||
426 | CMOS_WRITE(hrs, RTC_HOURS); | ||
427 | CMOS_WRITE(min, RTC_MINUTES); | ||
428 | CMOS_WRITE(sec, RTC_SECONDS); | ||
429 | local_irq_restore(flags); | ||
430 | |||
431 | /* Notice that at this point, the RTC is updated but | ||
432 | * the kernel is still running with the old time. | ||
433 | * You need to set that separately with settimeofday | ||
434 | * or adjtimex. | ||
435 | */ | ||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | case RTC_SET_CHARGE: /* set the RTC TRICKLE CHARGE register */ | ||
440 | { | ||
441 | int tcs_val; | ||
442 | |||
443 | if (!capable(CAP_SYS_TIME)) | ||
444 | return -EPERM; | ||
445 | |||
446 | if(copy_from_user(&tcs_val, (int*)arg, sizeof(int))) | ||
447 | return -EFAULT; | ||
448 | |||
449 | tcs_val = RTC_TCR_PATTERN | (tcs_val & 0x0F); | ||
450 | ds1302_writereg(RTC_TRICKLECHARGER, tcs_val); | ||
451 | return 0; | ||
452 | } | ||
453 | case RTC_VLOW_RD: | ||
454 | { | ||
455 | /* TODO: | ||
456 | * Implement voltage low detection support | ||
457 | */ | ||
458 | printk(KERN_WARNING "DS1302: RTC Voltage Low detection" | ||
459 | " is not supported\n"); | ||
460 | return 0; | ||
461 | } | ||
462 | case RTC_VLOW_SET: | ||
463 | { | ||
464 | /* TODO: | ||
465 | * Nothing to do since Voltage Low detection is not supported | ||
466 | */ | ||
467 | return 0; | ||
468 | } | ||
469 | default: | ||
470 | return -ENOIOCTLCMD; | ||
471 | } | ||
472 | } | ||
473 | |||
474 | static void | ||
475 | print_rtc_status(void) | ||
476 | { | ||
477 | struct rtc_time tm; | ||
478 | |||
479 | get_rtc_time(&tm); | ||
480 | |||
481 | /* | ||
482 | * There is no way to tell if the luser has the RTC set for local | ||
483 | * time or for Universal Standard Time (GMT). Probably local though. | ||
484 | */ | ||
485 | |||
486 | printk(KERN_INFO "rtc_time\t: %02d:%02d:%02d\n", | ||
487 | tm.tm_hour, tm.tm_min, tm.tm_sec); | ||
488 | printk(KERN_INFO "rtc_date\t: %04d-%02d-%02d\n", | ||
489 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); | ||
490 | } | ||
491 | |||
492 | /* The various file operations we support. */ | ||
493 | |||
494 | static struct file_operations rtc_fops = { | ||
495 | .owner = THIS_MODULE, | ||
496 | .ioctl = rtc_ioctl, | ||
497 | }; | ||
498 | |||
499 | /* Probe for the chip by writing something to its RAM and try reading it back. */ | ||
500 | |||
501 | #define MAGIC_PATTERN 0x42 | ||
502 | |||
503 | static int __init | ||
504 | ds1302_probe(void) | ||
505 | { | ||
506 | int retval, res; | ||
507 | |||
508 | TK_RST_DIR(1); | ||
509 | TK_SCL_DIR(1); | ||
510 | TK_SDA_DIR(0); | ||
511 | |||
512 | /* Try to talk to timekeeper. */ | ||
513 | |||
514 | ds1302_wenable(); | ||
515 | start(); | ||
516 | out_byte(0xc0); /* write RAM byte 0 */ | ||
517 | out_byte(MAGIC_PATTERN); /* write something magic */ | ||
518 | start(); | ||
519 | out_byte(0xc1); /* read RAM byte 0 */ | ||
520 | |||
521 | if((res = in_byte()) == MAGIC_PATTERN) { | ||
522 | stop(); | ||
523 | ds1302_wdisable(); | ||
524 | printk(KERN_INFO "%s: RTC found.\n", ds1302_name); | ||
525 | printk(KERN_INFO "%s: SDA, SCL, RST on PB%i, PB%i, %s%i\n", | ||
526 | ds1302_name, | ||
527 | CONFIG_ETRAX_DS1302_SDABIT, | ||
528 | CONFIG_ETRAX_DS1302_SCLBIT, | ||
529 | #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT | ||
530 | "GENIO", | ||
531 | #else | ||
532 | "PB", | ||
533 | #endif | ||
534 | CONFIG_ETRAX_DS1302_RSTBIT); | ||
535 | print_rtc_status(); | ||
536 | retval = 1; | ||
537 | } else { | ||
538 | stop(); | ||
539 | retval = 0; | ||
540 | } | ||
541 | |||
542 | return retval; | ||
543 | } | ||
544 | |||
545 | |||
546 | /* Just probe for the RTC and register the device to handle the ioctl needed. */ | ||
547 | |||
548 | int __init | ||
549 | ds1302_init(void) | ||
550 | { | ||
551 | i2c_init(); | ||
552 | |||
553 | if (!ds1302_probe()) { | ||
554 | #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT | ||
555 | #if CONFIG_ETRAX_DS1302_RSTBIT == 27 | ||
556 | /* | ||
557 | * The only way to set g27 to output is to enable ATA. | ||
558 | * | ||
559 | * Make sure that R_GEN_CONFIG is setup correct. | ||
560 | */ | ||
561 | genconfig_shadow = ((genconfig_shadow & | ||
562 | ~IO_MASK(R_GEN_CONFIG, ata)) | | ||
563 | (IO_STATE(R_GEN_CONFIG, ata, select))); | ||
564 | *R_GEN_CONFIG = genconfig_shadow; | ||
565 | #elif CONFIG_ETRAX_DS1302_RSTBIT == 0 | ||
566 | |||
567 | /* Set the direction of this bit to out. */ | ||
568 | genconfig_shadow = ((genconfig_shadow & | ||
569 | ~IO_MASK(R_GEN_CONFIG, g0dir)) | | ||
570 | (IO_STATE(R_GEN_CONFIG, g0dir, out))); | ||
571 | *R_GEN_CONFIG = genconfig_shadow; | ||
572 | #endif | ||
573 | if (!ds1302_probe()) { | ||
574 | printk(KERN_WARNING "%s: RTC not found.\n", ds1302_name); | ||
575 | return -1; | ||
576 | } | ||
577 | #else | ||
578 | printk(KERN_WARNING "%s: RTC not found.\n", ds1302_name); | ||
579 | return -1; | ||
580 | #endif | ||
581 | } | ||
582 | /* Initialise trickle charger */ | ||
583 | ds1302_writereg(RTC_TRICKLECHARGER, | ||
584 | RTC_TCR_PATTERN |(CONFIG_ETRAX_DS1302_TRICKLE_CHARGE & 0x0F)); | ||
585 | /* Start clock by resetting CLOCK_HALT */ | ||
586 | ds1302_writereg(RTC_SECONDS, (ds1302_readreg(RTC_SECONDS) & 0x7F)); | ||
587 | return 0; | ||
588 | } | ||
589 | |||
590 | static int __init ds1302_register(void) | ||
591 | { | ||
592 | ds1302_init(); | ||
593 | if (register_chrdev(RTC_MAJOR_NR, ds1302_name, &rtc_fops)) { | ||
594 | printk(KERN_INFO "%s: unable to get major %d for rtc\n", | ||
595 | ds1302_name, RTC_MAJOR_NR); | ||
596 | return -1; | ||
597 | } | ||
598 | return 0; | ||
599 | |||
600 | } | ||
601 | |||
602 | module_init(ds1302_register); | ||