diff options
Diffstat (limited to 'firmware/drivers')
-rw-r--r-- | firmware/drivers/rtc/rtc_s35380a.c | 118 |
1 files changed, 78 insertions, 40 deletions
diff --git a/firmware/drivers/rtc/rtc_s35380a.c b/firmware/drivers/rtc/rtc_s35380a.c index 05796e0462..0a889cf655 100644 --- a/firmware/drivers/rtc/rtc_s35380a.c +++ b/firmware/drivers/rtc/rtc_s35380a.c | |||
@@ -42,29 +42,25 @@ | |||
42 | #define CLOCK_CORR_REG 6 | 42 | #define CLOCK_CORR_REG 6 |
43 | #define FREE_REG 7 | 43 | #define FREE_REG 7 |
44 | 44 | ||
45 | /* STATUS_REG1 flags | 45 | /* STATUS_REG1 flags */ |
46 | * bits order is reversed | 46 | #define STATUS_REG1_POC 0x80 |
47 | */ | 47 | #define STATUS_REG1_BLD 0x40 |
48 | #define STATUS_REG1_POC 0x01 | 48 | #define STATUS_REG1_INT2 0x20 |
49 | #define STATUS_REG1_BLD 0x02 | 49 | #define STATUS_REG1_INT1 0x10 |
50 | #define STATUS_REG1_INT2 0x04 | 50 | #define STATUS_REG1_SC1 0x08 |
51 | #define STATUS_REG1_INT1 0x08 | 51 | #define STATUS_REG1_SC0 0x04 |
52 | #define STATUS_REG1_SC1 0x10 | 52 | #define STATUS_REG1_H1224 0x02 |
53 | #define STATUS_REG1_SC0 0x20 | 53 | #define STATUS_REG1_RESET 0x01 |
54 | #define STATUS_REG1_H1224 0x40 | 54 | |
55 | #define STATUS_REG1_RESET 0x80 | 55 | /* STATUS_REG2 flags */ |
56 | 56 | #define STATUS_REG2_TEST 0x80 | |
57 | /* STATUS_REG2 flags | 57 | #define STATUS_REG2_INT2AE 0x40 |
58 | * bits order is reversed | 58 | #define STATUS_REG2_INT2ME 0x20 |
59 | */ | 59 | #define STATUS_REG2_INT2FE 0x10 |
60 | #define STATUS_REG2_TEST 0x01 | 60 | #define STATUS_REG2_32kE 0x08 |
61 | #define STATUS_REG2_INT2AE 0x02 | 61 | #define STATUS_REG2_INT1AE 0x04 |
62 | #define STATUS_REG2_INT2ME 0x04 | 62 | #define STATUS_REG2_INT1ME 0x02 |
63 | #define STATUS_REG2_INT2FE 0x08 | 63 | #define STATUS_REG2_INT1FE 0x01 |
64 | #define STATUS_REG2_32kE 0x10 | ||
65 | #define STATUS_REG2_INT1AE 0x20 | ||
66 | #define STATUS_REG2_INT1ME 0x40 | ||
67 | #define STATUS_REG2_INT1FE 0x80 | ||
68 | 64 | ||
69 | /* REALTIME_DATA register bytes */ | 65 | /* REALTIME_DATA register bytes */ |
70 | #define TIME_YEAR 0 | 66 | #define TIME_YEAR 0 |
@@ -95,6 +91,9 @@ | |||
95 | 91 | ||
96 | static bool int_flag; | 92 | static bool int_flag; |
97 | 93 | ||
94 | /* s35380a chip has reversed bits order in byte | ||
95 | * This is little helper function to deal with | ||
96 | */ | ||
98 | static void reverse_bits(unsigned char* v, int size) | 97 | static void reverse_bits(unsigned char* v, int size) |
99 | { | 98 | { |
100 | static const unsigned char flipnibble[] = | 99 | static const unsigned char flipnibble[] = |
@@ -108,12 +107,40 @@ static void reverse_bits(unsigned char* v, int size) | |||
108 | } | 107 | } |
109 | } | 108 | } |
110 | 109 | ||
110 | /* Read 'size' bytes from RTC 'reg' and put data in 'buf' | ||
111 | * bits are reversed in data bytes afterwards so they appear in regular order | ||
112 | * return i2c transfer code | ||
113 | */ | ||
114 | static int rtc_read(unsigned char reg, unsigned char *buf, int size) | ||
115 | { | ||
116 | int rc; | ||
117 | rc = i2c_read(I2C_IFACE_1, RTC_ADDR|(reg<<1), buf, size); | ||
118 | reverse_bits(buf, size); | ||
119 | return rc; | ||
120 | } | ||
121 | |||
122 | /* Write 'size' bytes to RTC 'reg' and put data in 'buf' | ||
123 | * bits are reversed in data bytes prior to sending them to RTC | ||
124 | * return i2c transfer code | ||
125 | */ | ||
126 | static int rtc_write(unsigned char reg, unsigned char *buf, int size) | ||
127 | { | ||
128 | int rc; | ||
129 | reverse_bits(buf, size); | ||
130 | rc = i2c_write(I2C_IFACE_1, RTC_ADDR|(reg<<1), buf, size); | ||
131 | return rc; | ||
132 | } | ||
133 | |||
134 | /* Reset RTC by writing '1' to RESET bit in STATUS_REG1 */ | ||
111 | static inline void rtc_reset(void) | 135 | static inline void rtc_reset(void) |
112 | { | 136 | { |
113 | unsigned char reg = STATUS_REG1_RESET; | 137 | unsigned char reg = STATUS_REG1_RESET; |
114 | i2c_write(I2C_IFACE_1, RTC_ADDR|(STATUS_REG1<<1), ®, 1); | 138 | rtc_write(STATUS_REG1, ®, 1); |
115 | } | 139 | } |
116 | 140 | ||
141 | /* Initialize RTC (according to scheme outlined in datasheet). | ||
142 | * Configure chip to 24h time format. | ||
143 | */ | ||
117 | void rtc_init(void) | 144 | void rtc_init(void) |
118 | { | 145 | { |
119 | unsigned char reg; | 146 | unsigned char reg; |
@@ -122,7 +149,7 @@ void rtc_init(void) | |||
122 | if ( initialized ) | 149 | if ( initialized ) |
123 | return; | 150 | return; |
124 | 151 | ||
125 | i2c_read(I2C_IFACE_1, RTC_ADDR|(STATUS_REG1<<1), ®, 1); | 152 | rtc_read(STATUS_REG1, ®, 1); |
126 | 153 | ||
127 | /* cache INT1, INT2 flags as reading the register seem to clear | 154 | /* cache INT1, INT2 flags as reading the register seem to clear |
128 | * this bits (which is not described in datasheet) | 155 | * this bits (which is not described in datasheet) |
@@ -133,7 +160,7 @@ void rtc_init(void) | |||
133 | if ( (reg & STATUS_REG1_POC) || (reg & STATUS_REG1_BLD)) | 160 | if ( (reg & STATUS_REG1_POC) || (reg & STATUS_REG1_BLD)) |
134 | rtc_reset(); | 161 | rtc_reset(); |
135 | 162 | ||
136 | i2c_read(I2C_IFACE_1, RTC_ADDR|(STATUS_REG2<<1), ®, 1); | 163 | rtc_read(STATUS_REG2, ®, 1); |
137 | 164 | ||
138 | /* test TEST flag */ | 165 | /* test TEST flag */ |
139 | if ( reg & STATUS_REG2_TEST ) | 166 | if ( reg & STATUS_REG2_TEST ) |
@@ -141,19 +168,19 @@ void rtc_init(void) | |||
141 | 168 | ||
142 | /* setup 24h time format */ | 169 | /* setup 24h time format */ |
143 | reg = STATUS_REG1_H1224; | 170 | reg = STATUS_REG1_H1224; |
144 | i2c_write(I2C_IFACE_1, RTC_ADDR|(STATUS_REG1<<1), ®, 1); | 171 | rtc_write(STATUS_REG1, ®, 1); |
145 | 172 | ||
146 | initialized = true; | 173 | initialized = true; |
147 | } | 174 | } |
148 | 175 | ||
176 | /* Read realtime data register */ | ||
149 | int rtc_read_datetime(struct tm *tm) | 177 | int rtc_read_datetime(struct tm *tm) |
150 | { | 178 | { |
151 | unsigned char buf[TIME_REG_SIZE]; | 179 | unsigned char buf[TIME_REG_SIZE]; |
152 | unsigned int i; | 180 | unsigned int i; |
153 | int ret; | 181 | int ret; |
154 | 182 | ||
155 | ret = i2c_read(I2C_IFACE_1, RTC_ADDR|(REALTIME_DATA1<<1), buf, sizeof(buf)); | 183 | ret = rtc_read(REALTIME_DATA1, buf, sizeof(buf)); |
156 | reverse_bits(buf, sizeof(buf)); | ||
157 | 184 | ||
158 | buf[TIME_HOUR] &= 0x3f; /* mask out p.m. flag */ | 185 | buf[TIME_HOUR] &= 0x3f; /* mask out p.m. flag */ |
159 | 186 | ||
@@ -171,6 +198,7 @@ int rtc_read_datetime(struct tm *tm) | |||
171 | return ret; | 198 | return ret; |
172 | } | 199 | } |
173 | 200 | ||
201 | /* Write to realtime data register */ | ||
174 | int rtc_write_datetime(const struct tm *tm) | 202 | int rtc_write_datetime(const struct tm *tm) |
175 | { | 203 | { |
176 | unsigned char buf[TIME_REG_SIZE]; | 204 | unsigned char buf[TIME_REG_SIZE]; |
@@ -188,13 +216,13 @@ int rtc_write_datetime(const struct tm *tm) | |||
188 | for (i = 0; i < sizeof(buf); i++) | 216 | for (i = 0; i < sizeof(buf); i++) |
189 | buf[i] = DEC2BCD(buf[i]); | 217 | buf[i] = DEC2BCD(buf[i]); |
190 | 218 | ||
191 | reverse_bits(buf, sizeof(buf)); | 219 | ret = rtc_write(REALTIME_DATA1, buf, sizeof(buf)); |
192 | ret = i2c_write(I2C_IFACE_1, RTC_ADDR|(REALTIME_DATA1<<1), buf, sizeof(buf)); | ||
193 | 220 | ||
194 | return ret; | 221 | return ret; |
195 | } | 222 | } |
196 | 223 | ||
197 | #ifdef HAVE_RTC_ALARM | 224 | #ifdef HAVE_RTC_ALARM |
225 | /* Set alarm (INT1) data register */ | ||
198 | void rtc_set_alarm(int h, int m) | 226 | void rtc_set_alarm(int h, int m) |
199 | { | 227 | { |
200 | unsigned char buf[ALARM_REG_SIZE]; | 228 | unsigned char buf[ALARM_REG_SIZE]; |
@@ -207,7 +235,7 @@ void rtc_set_alarm(int h, int m) | |||
207 | buf[ALARM_HOUR] = DEC2BCD(h) | A1HE; | 235 | buf[ALARM_HOUR] = DEC2BCD(h) | A1HE; |
208 | buf[ALARM_WEEKDAY] = 0; | 236 | buf[ALARM_WEEKDAY] = 0; |
209 | 237 | ||
210 | /* AM/PM flag have to be set properly regardles of | 238 | /* AM/PM flag has to be set properly regardles of |
211 | * time format used (H1224 flag in STATUS_REG1) | 239 | * time format used (H1224 flag in STATUS_REG1) |
212 | * this is not described in datasheet for s35380a | 240 | * this is not described in datasheet for s35380a |
213 | * but is somehow described in datasheet for s35390a | 241 | * but is somehow described in datasheet for s35390a |
@@ -215,10 +243,10 @@ void rtc_set_alarm(int h, int m) | |||
215 | if ( h >= 12 ) | 243 | if ( h >= 12 ) |
216 | buf[ALARM_HOUR] |= AMPM; | 244 | buf[ALARM_HOUR] |= AMPM; |
217 | 245 | ||
218 | reverse_bits(buf, sizeof(buf)); | 246 | rtc_write(INT1_REG, buf, sizeof(buf)); |
219 | i2c_write(I2C_IFACE_1, RTC_ADDR|(INT1_REG<<1), buf, sizeof(buf)); | ||
220 | } | 247 | } |
221 | 248 | ||
249 | /* Read alarm (INT1) data register */ | ||
222 | void rtc_get_alarm(int *h, int *m) | 250 | void rtc_get_alarm(int *h, int *m) |
223 | { | 251 | { |
224 | unsigned char buf[ALARM_REG_SIZE]; | 252 | unsigned char buf[ALARM_REG_SIZE]; |
@@ -227,23 +255,32 @@ void rtc_get_alarm(int *h, int *m) | |||
227 | rtc_enable_alarm(true); | 255 | rtc_enable_alarm(true); |
228 | 256 | ||
229 | /* read the content of INT1 register */ | 257 | /* read the content of INT1 register */ |
230 | i2c_read(I2C_IFACE_1, RTC_ADDR|(INT1_REG<<1), buf, sizeof(buf)); | 258 | rtc_read(INT1_REG, buf, sizeof(buf)); |
231 | reverse_bits(buf, sizeof(buf)); | ||
232 | 259 | ||
233 | *h = BCD2DEC(buf[ALARM_HOUR] & 0x3f); /* mask out A1HE and PM/AM flag */ | 260 | *h = BCD2DEC(buf[ALARM_HOUR] & 0x3f); /* mask out A1HE and PM/AM bits */ |
234 | *m = BCD2DEC(buf[ALARM_MINUTE] & 0x7f); /* mask out A1mE */ | 261 | *m = BCD2DEC(buf[ALARM_MINUTE] & 0x7f); /* mask out A1mE bit */ |
235 | 262 | ||
263 | /* Disable alarm - this is not strictly needed in rockbox | ||
264 | * as after rtc_get_alarm() rtc_set_alarm() or rtc_enable_alarm(false) | ||
265 | * are called. I just found this weird that simple reading register | ||
266 | * changes alarm settings. | ||
267 | */ | ||
236 | rtc_enable_alarm(false); | 268 | rtc_enable_alarm(false); |
237 | } | 269 | } |
238 | 270 | ||
271 | /* Check if we just triggered alarm. | ||
272 | * We check both INT1 and INT2. Rockbox uses only INT1 but | ||
273 | * OF in MPIO HD300 uses both | ||
274 | */ | ||
239 | bool rtc_check_alarm_flag(void) | 275 | bool rtc_check_alarm_flag(void) |
240 | { | 276 | { |
241 | unsigned char reg; | 277 | unsigned char reg; |
242 | i2c_read(I2C_IFACE_1, RTC_ADDR|(STATUS_REG1<<1), ®, 1); | 278 | rtc_read(STATUS_REG1, ®, 1); |
243 | 279 | ||
244 | return ((reg & STATUS_REG1_INT1) || (reg & STATUS_REG1_INT2)); | 280 | return ((reg & STATUS_REG1_INT1) || (reg & STATUS_REG1_INT2)); |
245 | } | 281 | } |
246 | 282 | ||
283 | /* Enable/disable alarm function */ | ||
247 | void rtc_enable_alarm(bool enable) | 284 | void rtc_enable_alarm(bool enable) |
248 | { | 285 | { |
249 | unsigned char reg = 0; | 286 | unsigned char reg = 0; |
@@ -251,9 +288,10 @@ void rtc_enable_alarm(bool enable) | |||
251 | if (enable) | 288 | if (enable) |
252 | reg = STATUS_REG2_INT1AE; | 289 | reg = STATUS_REG2_INT1AE; |
253 | 290 | ||
254 | i2c_write(I2C_IFACE_1, RTC_ADDR|(STATUS_REG2<<1), ®, 1); | 291 | rtc_write(STATUS_REG2, ®, 1); |
255 | } | 292 | } |
256 | 293 | ||
294 | /* Return true if wakeup is due to RTC alarm */ | ||
257 | bool rtc_check_alarm_started(bool release_alarm) | 295 | bool rtc_check_alarm_started(bool release_alarm) |
258 | { | 296 | { |
259 | static bool run_before; | 297 | static bool run_before; |