summaryrefslogtreecommitdiff
path: root/firmware/drivers
diff options
context:
space:
mode:
authorMarcin Bukat <marcin.bukat@gmail.com>2010-12-07 22:04:02 +0000
committerMarcin Bukat <marcin.bukat@gmail.com>2010-12-07 22:04:02 +0000
commit3b6b4f90509acaa068d78cce746ef83318d85903 (patch)
tree2a33c7003320f8071a9cb0d9d36ceffb7ac43cdd /firmware/drivers
parent1930e9f4baee8086195e147b9580ebbf3042b3cc (diff)
downloadrockbox-3b6b4f90509acaa068d78cce746ef83318d85903.tar.gz
rockbox-3b6b4f90509acaa068d78cce746ef83318d85903.zip
RTC s35380a - proper alarm support
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28763 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/drivers')
-rw-r--r--firmware/drivers/rtc/rtc_s35380a.c189
1 files changed, 116 insertions, 73 deletions
diff --git a/firmware/drivers/rtc/rtc_s35380a.c b/firmware/drivers/rtc/rtc_s35380a.c
index 9f935b9541..05796e0462 100644
--- a/firmware/drivers/rtc/rtc_s35380a.c
+++ b/firmware/drivers/rtc/rtc_s35380a.c
@@ -66,6 +66,35 @@
66#define STATUS_REG2_INT1ME 0x40 66#define STATUS_REG2_INT1ME 0x40
67#define STATUS_REG2_INT1FE 0x80 67#define STATUS_REG2_INT1FE 0x80
68 68
69/* REALTIME_DATA register bytes */
70#define TIME_YEAR 0
71#define TIME_MONTH 1
72#define TIME_DAY 2
73#define TIME_WEEKDAY 3
74#define TIME_HOUR 4
75#define TIME_MINUTE 5
76#define TIME_SECOND 6
77#define TIME_REG_SIZE 7
78
79/* INT1, INT2 register bytes */
80#define ALARM_WEEKDAY 0
81#define ALARM_HOUR 1
82#define ALARM_MINUTE 2
83#define ALARM_REG_SIZE 3
84
85/* INT1, INT2 register bits */
86#define A1WE 0x80
87#define A1HE 0x80
88#define A1mE 0x80
89
90#define A2WE 0x80
91#define A2HE 0x80
92#define A2mE 0x80
93
94#define AMPM 0x40
95
96static bool int_flag;
97
69static void reverse_bits(unsigned char* v, int size) 98static void reverse_bits(unsigned char* v, int size)
70{ 99{
71 static const unsigned char flipnibble[] = 100 static const unsigned char flipnibble[] =
@@ -79,75 +108,88 @@ static void reverse_bits(unsigned char* v, int size)
79 } 108 }
80} 109}
81 110
111static inline void rtc_reset(void)
112{
113 unsigned char reg = STATUS_REG1_RESET;
114 i2c_write(I2C_IFACE_1, RTC_ADDR|(STATUS_REG1<<1), &reg, 1);
115}
116
82void rtc_init(void) 117void rtc_init(void)
83{ 118{
84 unsigned char status_reg; 119 unsigned char reg;
85 i2c_read(I2C_IFACE_1, RTC_ADDR | (STATUS_REG1<<1), &status_reg, 1); 120 static bool initialized = false;
86 121
87 if ( (status_reg & STATUS_REG1_POC) || 122 if ( initialized )
88 (status_reg & STATUS_REG1_BLD) ) 123 return;
89 { 124
90 /* perform rtc reset*/ 125 i2c_read(I2C_IFACE_1, RTC_ADDR|(STATUS_REG1<<1), &reg, 1);
91 status_reg |= STATUS_REG1_RESET; 126
92 i2c_write(I2C_IFACE_1, RTC_ADDR | (STATUS_REG1<<1), &status_reg, 1); 127 /* cache INT1, INT2 flags as reading the register seem to clear
93 } 128 * this bits (which is not described in datasheet)
129 */
130 int_flag = ((reg & STATUS_REG1_INT1) || (reg & STATUS_REG1_INT2));
131
132 /* test POC and BLD flags */
133 if ( (reg & STATUS_REG1_POC) || (reg & STATUS_REG1_BLD))
134 rtc_reset();
135
136 i2c_read(I2C_IFACE_1, RTC_ADDR|(STATUS_REG2<<1), &reg, 1);
137
138 /* test TEST flag */
139 if ( reg & STATUS_REG2_TEST )
140 rtc_reset();
94 141
95 /* setup 24h time format */ 142 /* setup 24h time format */
96 status_reg = STATUS_REG1_H1224; 143 reg = STATUS_REG1_H1224;
97 i2c_write(I2C_IFACE_1, RTC_ADDR | (STATUS_REG1<<1), &status_reg, 1); 144 i2c_write(I2C_IFACE_1, RTC_ADDR|(STATUS_REG1<<1), &reg, 1);
98 145
99#ifdef HAVE_RTC_ALARM 146 initialized = true;
100 rtc_check_alarm_started(false);
101#endif
102 /* disable all alarms */
103 status_reg = 0;
104 i2c_write(I2C_IFACE_1, RTC_ADDR | (STATUS_REG2<<1), &status_reg, 1);
105} 147}
106 148
107int rtc_read_datetime(struct tm *tm) 149int rtc_read_datetime(struct tm *tm)
108{ 150{
109 unsigned char buf[7]; 151 unsigned char buf[TIME_REG_SIZE];
110 unsigned int i; 152 unsigned int i;
111 int ret; 153 int ret;
112 154
113 ret = i2c_read(I2C_IFACE_1, RTC_ADDR | (REALTIME_DATA1<<1), buf, sizeof(buf)); 155 ret = i2c_read(I2C_IFACE_1, RTC_ADDR|(REALTIME_DATA1<<1), buf, sizeof(buf));
114 reverse_bits(buf, sizeof(buf)); 156 reverse_bits(buf, sizeof(buf));
115 157
116 buf[4] &= 0x3f; /* mask out p.m. flag */ 158 buf[TIME_HOUR] &= 0x3f; /* mask out p.m. flag */
117 159
118 for (i = 0; i < sizeof(buf); i++) 160 for (i = 0; i < sizeof(buf); i++)
119 buf[i] = BCD2DEC(buf[i]); 161 buf[i] = BCD2DEC(buf[i]);
120 162
121 tm->tm_sec = buf[6]; 163 tm->tm_sec = buf[TIME_SECOND];
122 tm->tm_min = buf[5]; 164 tm->tm_min = buf[TIME_MINUTE];
123 tm->tm_hour = buf[4]; 165 tm->tm_hour = buf[TIME_HOUR];
124 tm->tm_wday = buf[3]; 166 tm->tm_wday = buf[TIME_WEEKDAY];
125 tm->tm_mday = buf[2]; 167 tm->tm_mday = buf[TIME_DAY];
126 tm->tm_mon = buf[1] - 1; 168 tm->tm_mon = buf[TIME_MONTH] - 1;
127 tm->tm_year = buf[0] + 100; 169 tm->tm_year = buf[TIME_YEAR] + 100;
128 170
129 return ret; 171 return ret;
130} 172}
131 173
132int rtc_write_datetime(const struct tm *tm) 174int rtc_write_datetime(const struct tm *tm)
133{ 175{
134 unsigned char buf[7]; 176 unsigned char buf[TIME_REG_SIZE];
135 unsigned int i; 177 unsigned int i;
136 int ret; 178 int ret;
137 179
138 buf[6] = tm->tm_sec; 180 buf[TIME_SECOND] = tm->tm_sec;
139 buf[5] = tm->tm_min; 181 buf[TIME_MINUTE] = tm->tm_min;
140 buf[4] = tm->tm_hour; 182 buf[TIME_HOUR] = tm->tm_hour;
141 buf[3] = tm->tm_wday; 183 buf[TIME_WEEKDAY] = tm->tm_wday;
142 buf[2] = tm->tm_mday; 184 buf[TIME_DAY] = tm->tm_mday;
143 buf[1] = tm->tm_mon + 1; 185 buf[TIME_MONTH] = tm->tm_mon + 1;
144 buf[0] = tm->tm_year - 100; 186 buf[TIME_YEAR] = tm->tm_year - 100;
145 187
146 for (i = 0; i < sizeof(buf); i++) 188 for (i = 0; i < sizeof(buf); i++)
147 buf[i] = DEC2BCD(buf[i]); 189 buf[i] = DEC2BCD(buf[i]);
148 190
149 reverse_bits(buf, sizeof(buf)); 191 reverse_bits(buf, sizeof(buf));
150 ret = i2c_write(I2C_IFACE_1, RTC_ADDR | (REALTIME_DATA1<<1), buf, sizeof(buf)); 192 ret = i2c_write(I2C_IFACE_1, RTC_ADDR|(REALTIME_DATA1<<1), buf, sizeof(buf));
151 193
152 return ret; 194 return ret;
153} 195}
@@ -155,75 +197,76 @@ int rtc_write_datetime(const struct tm *tm)
155#ifdef HAVE_RTC_ALARM 197#ifdef HAVE_RTC_ALARM
156void rtc_set_alarm(int h, int m) 198void rtc_set_alarm(int h, int m)
157{ 199{
158 /* 1) get the date 200 unsigned char buf[ALARM_REG_SIZE];
159 * 2) compare h:m with current time
160 if alarm time < current time set day += 1
161 3) check day if it is not needed to wrap around
162 4) set the validity bits
163 5) write to alarm register
164 */
165 201
166 unsigned char buf[3]; 202 /* INT1 register can be accessed only when IN1AE flag is set */
167 unsigned char reg; 203 rtc_enable_alarm(true);
168 204
169 /* 0x80 - validity flag */ 205 /* A1mE, A1HE - validity flags */
170 buf[2] = DEC2BCD(m) | 0x80; 206 buf[ALARM_MINUTE] = DEC2BCD(m) | A1mE;
171 buf[1] = DEC2BCD(h) | 0x80; 207 buf[ALARM_HOUR] = DEC2BCD(h) | A1HE;
172 buf[0] = 0; 208 buf[ALARM_WEEKDAY] = 0;
173 209
174 reverse_bits(buf, sizeof(buf)); 210 /* AM/PM flag have to be set properly regardles of
211 * time format used (H1224 flag in STATUS_REG1)
212 * this is not described in datasheet for s35380a
213 * but is somehow described in datasheet for s35390a
214 */
215 if ( h >= 12 )
216 buf[ALARM_HOUR] |= AMPM;
175 217
176 reg = STATUS_REG2_INT1AE; 218 reverse_bits(buf, sizeof(buf));
177 i2c_write(I2C_IFACE_1, RTC_ADDR | (STATUS_REG2<<1), &reg, 1); 219 i2c_write(I2C_IFACE_1, RTC_ADDR|(INT1_REG<<1), buf, sizeof(buf));
178 i2c_write(I2C_IFACE_1, RTC_ADDR | (INT1_REG<<1), buf, sizeof(buf));
179} 220}
180 221
181void rtc_get_alarm(int *h, int *m) 222void rtc_get_alarm(int *h, int *m)
182{ 223{
183 unsigned char buf[3]; 224 unsigned char buf[ALARM_REG_SIZE];
184 unsigned char reg,reg2;
185
186 i2c_read(I2C_IFACE_1, RTC_ADDR | (STATUS_REG2<<1), &reg, 1);
187 225
188 reg2 = reg | STATUS_REG2_INT1AE; 226 /* INT1 alarm register can be accessed only when INT1AE is set */
189 i2c_write(I2C_IFACE_1, RTC_ADDR | (STATUS_REG2<<1), &reg2, 1); 227 rtc_enable_alarm(true);
190 i2c_read(I2C_IFACE_1, RTC_ADDR | (INT1_REG<<1), buf, sizeof(buf));
191 i2c_write(I2C_IFACE_1, RTC_ADDR | (STATUS_REG2<<1), &reg, 1);
192 228
229 /* read the content of INT1 register */
230 i2c_read(I2C_IFACE_1, RTC_ADDR|(INT1_REG<<1), buf, sizeof(buf));
193 reverse_bits(buf, sizeof(buf)); 231 reverse_bits(buf, sizeof(buf));
194 232
195 *h = BCD2DEC(buf[1] & 0x3f); /* mask out A1HE and PM/AM flag */ 233 *h = BCD2DEC(buf[ALARM_HOUR] & 0x3f); /* mask out A1HE and PM/AM flag */
196 *m = BCD2DEC(buf[2] & 0x7f); /* mask out A1mE */ 234 *m = BCD2DEC(buf[ALARM_MINUTE] & 0x7f); /* mask out A1mE */
235
236 rtc_enable_alarm(false);
197} 237}
198 238
199bool rtc_check_alarm_flag(void) 239bool rtc_check_alarm_flag(void)
200{ 240{
201 unsigned char status_reg; 241 unsigned char reg;
202 i2c_read(I2C_IFACE_1, RTC_ADDR | (STATUS_REG1<<1), &status_reg, 1); 242 i2c_read(I2C_IFACE_1, RTC_ADDR|(STATUS_REG1<<1), &reg, 1);
203 243
204 return (status_reg & (STATUS_REG1_INT1 | STATUS_REG1_INT2)); 244 return ((reg & STATUS_REG1_INT1) || (reg & STATUS_REG1_INT2));
205} 245}
206 246
207void rtc_enable_alarm(bool enable) 247void rtc_enable_alarm(bool enable)
208{ 248{
209 unsigned char status_reg2; 249 unsigned char reg = 0;
210 status_reg2 = enable ? STATUS_REG2_INT1AE:0; 250
211 i2c_write(I2C_IFACE_1, RTC_ADDR | (STATUS_REG2<<1), &status_reg2, 1); 251 if (enable)
252 reg = STATUS_REG2_INT1AE;
253
254 i2c_write(I2C_IFACE_1, RTC_ADDR|(STATUS_REG2<<1), &reg, 1);
212} 255}
213 256
214bool rtc_check_alarm_started(bool release_alarm) 257bool rtc_check_alarm_started(bool release_alarm)
215{ 258{
216 static bool run_before = false, alarm_state; 259 static bool run_before;
217 bool rc; 260 bool rc;
218 261
219 if (run_before) 262 if (run_before)
220 { 263 {
221 rc = alarm_state; 264 rc = int_flag;
222 alarm_state &= ~release_alarm; 265 int_flag &= ~release_alarm;
223 } 266 }
224 else 267 else
225 { 268 {
226 rc = rtc_check_alarm_flag(); 269 rc = int_flag;
227 run_before = true; 270 run_before = true;
228 } 271 }
229 272