Rev 422 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
422 | giacomo | 1 | /* |
2 | * Constant and architecture independent procedures |
||
3 | * for NEC uPD4990A serial I/O real-time clock. |
||
4 | * |
||
5 | * Copyright 2001 TAKAI Kousuke <tak@kmc.kyoto-u.ac.jp> |
||
6 | * Kyoto University Microcomputer Club (KMC). |
||
7 | * |
||
8 | * References: |
||
9 | * uPD4990A serial I/O real-time clock users' manual (Japanese) |
||
10 | * No. S12828JJ4V0UM00 (4th revision), NEC Corporation, 1999. |
||
11 | */ |
||
12 | |||
13 | #ifndef _LINUX_uPD4990A_H |
||
14 | #define _LINUX_uPD4990A_H |
||
15 | |||
16 | #include <asm/byteorder.h> |
||
17 | |||
18 | #include <asm/upd4990a.h> |
||
19 | |||
20 | /* Serial commands (4 bits) */ |
||
21 | #define UPD4990A_REGISTER_HOLD (0x0) |
||
22 | #define UPD4990A_REGISTER_SHIFT (0x1) |
||
23 | #define UPD4990A_TIME_SET_AND_COUNTER_HOLD (0x2) |
||
24 | #define UPD4990A_TIME_READ (0x3) |
||
25 | #define UPD4990A_TP_64HZ (0x4) |
||
26 | #define UPD4990A_TP_256HZ (0x5) |
||
27 | #define UPD4990A_TP_2048HZ (0x6) |
||
28 | #define UPD4990A_TP_4096HZ (0x7) |
||
29 | #define UPD4990A_TP_1S (0x8) |
||
30 | #define UPD4990A_TP_10S (0x9) |
||
31 | #define UPD4990A_TP_30S (0xA) |
||
32 | #define UPD4990A_TP_60S (0xB) |
||
33 | #define UPD4990A_INTERRUPT_RESET (0xC) |
||
34 | #define UPD4990A_INTERRUPT_TIMER_START (0xD) |
||
35 | #define UPD4990A_INTERRUPT_TIMER_STOP (0xE) |
||
36 | #define UPD4990A_TEST_MODE_SET (0xF) |
||
37 | |||
38 | /* Parallel commands (3 bits) |
||
39 | 0-6 are same with serial commands. */ |
||
40 | #define UPD4990A_PAR_SERIAL_MODE 7 |
||
41 | |||
42 | #ifndef UPD4990A_DELAY |
||
43 | # include <linux/delay.h> |
||
44 | # define UPD4990A_DELAY(usec) udelay((usec)) |
||
45 | #endif |
||
46 | #ifndef UPD4990A_OUTPUT_DATA |
||
47 | # define UPD4990A_OUTPUT_DATA(bit) \ |
||
48 | do { \ |
||
49 | UPD4990A_OUTPUT_DATA_CLK((bit), 0); \ |
||
50 | UPD4990A_DELAY(1); /* t-DSU */ \ |
||
51 | UPD4990A_OUTPUT_DATA_CLK((bit), 1); \ |
||
52 | UPD4990A_DELAY(1); /* t-DHLD */ \ |
||
53 | } while (0) |
||
54 | #endif |
||
55 | |||
56 | static __inline__ void upd4990a_serial_command(int command) |
||
57 | { |
||
58 | UPD4990A_OUTPUT_DATA(command >> 0); |
||
59 | UPD4990A_OUTPUT_DATA(command >> 1); |
||
60 | UPD4990A_OUTPUT_DATA(command >> 2); |
||
61 | UPD4990A_OUTPUT_DATA(command >> 3); |
||
62 | UPD4990A_DELAY(1); /* t-HLD */ |
||
63 | UPD4990A_OUTPUT_STROBE(1); |
||
64 | UPD4990A_DELAY(1); /* t-STB & t-d1 */ |
||
65 | UPD4990A_OUTPUT_STROBE(0); |
||
66 | /* 19 microseconds extra delay is needed |
||
67 | iff previous mode is TIME READ command */ |
||
68 | } |
||
69 | |||
70 | struct upd4990a_raw_data { |
||
71 | u8 sec; /* BCD */ |
||
72 | u8 min; /* BCD */ |
||
73 | u8 hour; /* BCD */ |
||
74 | u8 mday; /* BCD */ |
||
75 | #if defined __LITTLE_ENDIAN_BITFIELD |
||
76 | unsigned wday :4; /* 0-6 */ |
||
77 | unsigned mon :4; /* 1-based */ |
||
78 | #elif defined __BIG_ENDIAN_BITFIELD |
||
79 | unsigned mon :4; /* 1-based */ |
||
80 | unsigned wday :4; /* 0-6 */ |
||
81 | #else |
||
82 | # error Unknown bitfield endian! |
||
83 | #endif |
||
84 | u8 year; /* BCD */ |
||
85 | }; |
||
86 | |||
87 | static __inline__ void upd4990a_get_time(struct upd4990a_raw_data *buf, |
||
88 | int leave_register_hold) |
||
89 | { |
||
90 | int byte; |
||
91 | |||
92 | upd4990a_serial_command(UPD4990A_TIME_READ); |
||
93 | upd4990a_serial_command(UPD4990A_REGISTER_SHIFT); |
||
94 | UPD4990A_DELAY(19); /* t-d2 - t-d1 */ |
||
95 | |||
96 | for (byte = 0; byte < 6; byte++) { |
||
97 | u8 tmp; |
||
98 | int bit; |
||
99 | |||
100 | for (tmp = 0, bit = 0; bit < 8; bit++) { |
||
101 | tmp = (tmp | (UPD4990A_READ_DATA() << 8)) >> 1; |
||
102 | UPD4990A_OUTPUT_CLK(1); |
||
103 | UPD4990A_DELAY(1); |
||
104 | UPD4990A_OUTPUT_CLK(0); |
||
105 | UPD4990A_DELAY(1); |
||
106 | } |
||
107 | ((u8 *) buf)[byte] = tmp; |
||
108 | } |
||
109 | |||
110 | /* The uPD4990A users' manual says that we should issue `Register |
||
111 | Hold' command after each data retrieval, or next `Time Read' |
||
112 | command may not work correctly. */ |
||
113 | if (!leave_register_hold) |
||
114 | upd4990a_serial_command(UPD4990A_REGISTER_HOLD); |
||
115 | } |
||
116 | |||
117 | static __inline__ void upd4990a_set_time(const struct upd4990a_raw_data *data, |
||
118 | int time_set_only) |
||
119 | { |
||
120 | int byte; |
||
121 | |||
122 | if (!time_set_only) |
||
123 | upd4990a_serial_command(UPD4990A_REGISTER_SHIFT); |
||
124 | |||
125 | for (byte = 0; byte < 6; byte++) { |
||
126 | int bit; |
||
127 | u8 tmp = ((const u8 *) data)[byte]; |
||
128 | |||
129 | for (bit = 0; bit < 8; bit++, tmp >>= 1) |
||
130 | UPD4990A_OUTPUT_DATA(tmp); |
||
131 | } |
||
132 | |||
133 | upd4990a_serial_command(UPD4990A_TIME_SET_AND_COUNTER_HOLD); |
||
134 | |||
135 | /* Release counter hold and start the clock. */ |
||
136 | if (!time_set_only) |
||
137 | upd4990a_serial_command(UPD4990A_REGISTER_HOLD); |
||
138 | } |
||
139 | |||
140 | #endif /* _LINUX_uPD4990A_H */ |