summaryrefslogtreecommitdiff
path: root/firmware/drivers/rtc/rtc_s35380a.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/rtc/rtc_s35380a.c')
-rw-r--r--firmware/drivers/rtc/rtc_s35380a.c118
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
96static bool int_flag; 92static bool int_flag;
97 93
94/* s35380a chip has reversed bits order in byte
95 * This is little helper function to deal with
96 */
98static void reverse_bits(unsigned char* v, int size) 97static 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 */
114static 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 */
126static 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 */
111static inline void rtc_reset(void) 135static 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), &reg, 1); 138 rtc_write(STATUS_REG1, &reg, 1);
115} 139}
116 140
141/* Initialize RTC (according to scheme outlined in datasheet).
142 * Configure chip to 24h time format.
143 */
117void rtc_init(void) 144void 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), &reg, 1); 152 rtc_read(STATUS_REG1, &reg, 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), &reg, 1); 163 rtc_read(STATUS_REG2, &reg, 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), &reg, 1); 171 rtc_write(STATUS_REG1, &reg, 1);
145 172
146 initialized = true; 173 initialized = true;
147} 174}
148 175
176/* Read realtime data register */
149int rtc_read_datetime(struct tm *tm) 177int 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 */
174int rtc_write_datetime(const struct tm *tm) 202int 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 */
198void rtc_set_alarm(int h, int m) 226void 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 */
222void rtc_get_alarm(int *h, int *m) 250void 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 */
239bool rtc_check_alarm_flag(void) 275bool 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), &reg, 1); 278 rtc_read(STATUS_REG1, &reg, 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 */
247void rtc_enable_alarm(bool enable) 284void 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), &reg, 1); 291 rtc_write(STATUS_REG2, &reg, 1);
255} 292}
256 293
294/* Return true if wakeup is due to RTC alarm */
257bool rtc_check_alarm_started(bool release_alarm) 295bool rtc_check_alarm_started(bool release_alarm)
258{ 296{
259 static bool run_before; 297 static bool run_before;