00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00073 #include <cfg/os.h>
00074 #include <cfg/eeprom.h>
00075
00076 #include <dev/twif.h>
00077 #include <sys/event.h>
00078 #include <sys/timer.h>
00079
00080 #include <time.h>
00081 #include <stdlib.h>
00082 #include <string.h>
00083
00084 #include <dev/x12rtc.h>
00085
00086 #if 0
00087
00088 #define NUTDEBUG
00089 #include <stdio.h>
00090 #endif
00091
00092 #ifndef I2C_SLA_RTC
00093 #define I2C_SLA_RTC 0x6F
00094 #endif
00095
00096 #ifndef I2C_SLA_EEPROM
00097 #define I2C_SLA_EEPROM 0x57
00098 #endif
00099
00100 #ifndef EEPROM_PAGE_SIZE
00101 #define EEPROM_PAGE_SIZE 64
00102 #endif
00103
00104 static uint8_t rtc_chip;
00105 static uint32_t rtc_status;
00106
00115 static int X12WriteEnable(int on)
00116 {
00117 int rc;
00118 uint8_t buf[3];
00119
00120 buf[0] = 0;
00121 buf[1] = 0x3F;
00122 if (on) {
00123 buf[2] = 0x02;
00124 if ((rc = TwMasterTransact(I2C_SLA_RTC, buf, 3, 0, 0, NUT_WAIT_INFINITE)) == 0) {
00125 buf[2] = 0x06;
00126 rc = TwMasterTransact(I2C_SLA_RTC, buf, 3, 0, 0, NUT_WAIT_INFINITE);
00127 }
00128 } else {
00129 buf[2] = 0x00;
00130 rc = TwMasterTransact(I2C_SLA_RTC, buf, 3, 0, 0, NUT_WAIT_INFINITE);
00131 }
00132 return rc;
00133 }
00134
00140 static int X12WaitReady(void)
00141 {
00142 uint8_t poll;
00143 int cnt = 200;
00144
00145
00146
00147
00148
00149 while (--cnt && TwMasterTransact(I2C_SLA_EEPROM, 0, 0, &poll, 1, NUT_WAIT_INFINITE) == -1);
00150 #ifdef NUTDEBUG
00151 printf("[RtcRdy:%d]", 200 - cnt);
00152 #endif
00153
00154 return cnt ? 0 : -1;
00155 }
00156
00166 int X12RtcReadRegs(uint8_t reg, uint8_t *buff, size_t cnt)
00167 {
00168 int rc = -1;
00169 uint8_t wbuf[2];
00170
00171 wbuf[0] = 0;
00172 wbuf[1] = reg;
00173 if (TwMasterTransact(I2C_SLA_RTC, wbuf, 2, buff, cnt, NUT_WAIT_INFINITE) == cnt) {
00174 #ifdef NUTDEBUG
00175 printf("[Rtc$%02x>", reg);
00176 while(cnt--) {
00177 printf(" %02x", *buff++);
00178 }
00179 putchar(']');
00180 #endif
00181 rc = 0;
00182 }
00183 return rc;
00184 }
00185
00199 int X12RtcWrite(int nv, CONST uint8_t *buff, size_t cnt)
00200 {
00201 int rc;
00202
00203 if ((rc = X12WriteEnable(1)) == 0) {
00204 rc = TwMasterTransact(I2C_SLA_RTC, buff, cnt, 0, 0, NUT_WAIT_INFINITE);
00205 if (rc == 0 && nv) {
00206 rc = X12WaitReady();
00207 }
00208 X12WriteEnable(0);
00209 #ifdef NUTDEBUG
00210 printf("[Rtc$%02X<", *++buff);
00211 cnt -= 2;
00212 while(cnt--) {
00213 printf(" %02x", *++buff);
00214 }
00215 putchar(']');
00216 #endif
00217 }
00218 return rc;
00219 }
00220
00231 int X12RtcGetClock(struct _tm *tm)
00232 {
00233 int rc;
00234 uint8_t data[8];
00235
00236 if ((rc = X12RtcReadRegs(X12RTC_SC, data, 8)) == 0) {
00237 tm->tm_sec = BCD2BIN(data[0]);
00238 tm->tm_min = BCD2BIN(data[1]);
00239 tm->tm_hour = BCD2BIN(data[2] & 0x3F);
00240 tm->tm_mday = BCD2BIN(data[3]);
00241 tm->tm_mon = BCD2BIN(data[4]) - 1;
00242 if (rtc_chip) {
00243 tm->tm_year = BCD2BIN(data[5]) + 100;
00244 }
00245 else {
00246 tm->tm_year = BCD2BIN(data[5]);
00247 if (data[7] == 0x20) {
00248 tm->tm_year += 100;
00249 }
00250 }
00251 tm->tm_wday = data[6];
00252 }
00253 return rc;
00254 }
00255
00268 int X12RtcSetClock(CONST struct _tm *tm)
00269 {
00270 uint8_t data[10];
00271
00272 memset(data, 0, sizeof(data));
00273 if (tm) {
00274 data[1] = X12RTC_SC;
00275 data[2] = BIN2BCD(tm->tm_sec);
00276 data[3] = BIN2BCD(tm->tm_min);
00277 data[4] = BIN2BCD(tm->tm_hour) | 0x80;
00278 data[5] = BIN2BCD(tm->tm_mday);
00279 data[6] = BIN2BCD(tm->tm_mon + 1);
00280
00281 if (rtc_chip) {
00282
00283 data[7] = BIN2BCD(tm->tm_year % 100);
00284 }
00285
00286 else if (tm->tm_year > 99) {
00287 data[7] = BIN2BCD(tm->tm_year - 100);
00288 data[9] = 0x20;
00289 }
00290 else {
00291 data[7] = BIN2BCD(tm->tm_year);
00292 data[9] = 0x19;
00293 }
00294 data[8] = tm->tm_wday;
00295 }
00296 return X12RtcWrite(0, data, 10);
00297 }
00298
00312 int X12RtcGetAlarm(int idx, struct _tm *tm, int *aflgs)
00313 {
00314 int rc;
00315 uint8_t data[8];
00316
00317 *aflgs = 0;
00318 memset(tm, 0, sizeof(struct _tm));
00319 if ((rc = X12RtcReadRegs(idx * 8, data, 8)) == 0) {
00320 if (data[0] & X12RTC_SCA_ESC) {
00321 *aflgs |= RTC_ALARM_SECOND;
00322 tm->tm_sec = BCD2BIN(data[0] & 0x7F);
00323 }
00324 if (data[1] & X12RTC_MNA_EMN) {
00325 *aflgs |= RTC_ALARM_MINUTE;
00326 tm->tm_min = BCD2BIN(data[1]);
00327 }
00328 if (data[2] & X12RTC_HRA_EHR) {
00329 *aflgs |= RTC_ALARM_HOUR;
00330 tm->tm_hour = BCD2BIN(data[2] & ~0x80);
00331 }
00332 if (data[3] & X12RTC_DTA_EDT) {
00333 *aflgs |= RTC_ALARM_MDAY;
00334 tm->tm_mday = BCD2BIN(data[3]);
00335 }
00336 if (data[4] & X12RTC_MOA_EMO) {
00337 *aflgs |= RTC_ALARM_MONTH;
00338 tm->tm_mon = BCD2BIN(data[4]) - 1;
00339 }
00340 if (data[6] & X12RTC_DWA_EDW) {
00341 *aflgs |= RTC_ALARM_WDAY;
00342 tm->tm_wday = BCD2BIN(data[6]);
00343 }
00344 }
00345 return rc;
00346 }
00347
00366 int X12RtcSetAlarm(int idx, CONST struct _tm *tm, int aflgs)
00367 {
00368 uint8_t data[10];
00369
00370 memset(data, 0, sizeof(data));
00371 data[1] = idx * 8;
00372 if (tm) {
00373 if (aflgs & RTC_ALARM_SECOND) {
00374 data[2] = BIN2BCD(tm->tm_sec) | X12RTC_SCA_ESC;
00375 }
00376 if (aflgs & RTC_ALARM_MINUTE) {
00377 data[3] = BIN2BCD(tm->tm_min) | X12RTC_MNA_EMN;
00378 }
00379 if (aflgs & RTC_ALARM_HOUR) {
00380 data[4] = BIN2BCD(tm->tm_hour) | X12RTC_HRA_EHR;
00381 }
00382 if (aflgs & RTC_ALARM_MDAY) {
00383 data[5] = BIN2BCD(tm->tm_mday) | X12RTC_DTA_EDT;
00384 }
00385 if (aflgs & RTC_ALARM_MONTH) {
00386 data[6] = BIN2BCD(tm->tm_mon + 1) | X12RTC_MOA_EMO;
00387 }
00388 if (aflgs & RTC_ALARM_WDAY) {
00389 data[8] = BIN2BCD(tm->tm_wday) | X12RTC_DWA_EDW;
00390 }
00391 }
00392 return X12RtcWrite(1, data, 10);
00393 }
00394
00407 int X12RtcGetStatus(uint32_t *sflgs)
00408 {
00409 int rc;
00410 uint8_t data;
00411
00412 if ((rc = X12RtcReadRegs(X12RTC_SR, &data, 1)) == 0) {
00413 rtc_status |= data;
00414 *sflgs = rtc_status;
00415 }
00416 return rc;
00417 }
00418
00428 int X12RtcClearStatus(uint32_t sflgs)
00429 {
00430 rtc_status &= ~sflgs;
00431
00432 return 0;
00433 }
00434
00435 NUTRTC rtcX12x6 = {
00436 X12Init,
00437 X12RtcGetClock,
00438 X12RtcSetClock,
00439 X12RtcGetAlarm,
00440 X12RtcSetAlarm,
00441 X12RtcGetStatus,
00442 X12RtcClearStatus
00443 };
00444
00445
00455 int X12EepromRead(u_int addr, void *buff, size_t len)
00456 {
00457 int rc = -1;
00458 uint8_t wbuf[2];
00459
00460 wbuf[0] = (uint8_t)(addr >> 8);
00461 wbuf[1] = (uint8_t)addr;
00462 if (TwMasterTransact(I2C_SLA_EEPROM, wbuf, 2, buff, len, NUT_WAIT_INFINITE) == len) {
00463 rc = 0;
00464 }
00465 return rc;
00466 }
00467
00480 int X12EepromWrite(u_int addr, CONST void *buff, size_t len)
00481 {
00482 int rc = 0;
00483 uint8_t *wbuf;
00484 size_t wlen;
00485 CONST uint8_t *wp = buff;
00486
00487
00488
00489
00490 while (len) {
00491
00492 wlen = EEPROM_PAGE_SIZE - (addr & (EEPROM_PAGE_SIZE - 1));
00493 if (wlen > len) {
00494 wlen = len;
00495 }
00496
00497
00498 if ((wbuf = malloc(wlen + 2)) == 0) {
00499 rc = -1;
00500 break;
00501 }
00502 wbuf[0] = (uint8_t)(addr >> 8);
00503 wbuf[1] = (uint8_t)addr;
00504 memcpy(wbuf + 2, (void *)wp, wlen);
00505
00506
00507 if ((rc = X12WriteEnable(1)) == 0) {
00508 rc = TwMasterTransact(I2C_SLA_EEPROM, wbuf, wlen + 2, 0, 0, NUT_WAIT_INFINITE);
00509 }
00510
00511
00512 free(wbuf);
00513 if (rc) {
00514 break;
00515 }
00516 len -= wlen;
00517 addr += wlen;
00518 wp += wlen;
00519
00520
00521 if ((rc = X12WaitReady()) != 0) {
00522 break;
00523 }
00524 }
00525 X12WriteEnable(0);
00526
00527 return rc;
00528 }
00529
00538 int X12Init(void)
00539 {
00540 int rc;
00541 uint32_t tmp;
00542 uint8_t data[2];
00543
00544
00545 if ((rc = TwInit(0)) == 0) {
00546
00547 if ((rc = X12RtcGetStatus(&tmp)) == 0) {
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558 X12RtcReadRegs(X128xRTC_SSEC, &data[0], 1);
00559 NutSleep(20);
00560 X12RtcReadRegs(X128xRTC_SSEC, &data[1], 1);
00561 if (data[0] != data[1]) {
00562 rtc_chip = 1;
00563 }
00564 #ifdef NUTDEBUG
00565 printf("[RTC=X12%c6]", rtc_chip ? '8' : '2');
00566 #endif
00567 }
00568 }
00569 return rc;
00570 }