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
00080 #include <cfg/os.h>
00081 #include <cfg/eeprom.h>
00082
00083 #include <dev/twif.h>
00084 #include <sys/event.h>
00085 #include <sys/timer.h>
00086
00087 #include <time.h>
00088 #include <stdlib.h>
00089 #include <string.h>
00090 #include <memdebug.h>
00091
00092 #include <dev/x12rtc.h>
00093
00094 #if 0
00095
00096 #define NUTDEBUG
00097 #include <stdio.h>
00098 #endif
00099
00100 #ifndef I2C_SLA_RTC
00101 #define I2C_SLA_RTC 0x6F
00102 #endif
00103
00104 #ifndef I2C_SLA_EEPROM
00105 #define I2C_SLA_EEPROM 0x57
00106 #endif
00107
00108 #ifndef EEPROM_PAGE_SIZE
00109 #define EEPROM_PAGE_SIZE 64
00110 #endif
00111
00112 static uint8_t rtc_chip;
00113 static uint32_t rtc_status;
00114
00123 static int X12WriteEnable(int on)
00124 {
00125 int rc;
00126 uint8_t buf[3];
00127
00128 buf[0] = 0;
00129 buf[1] = 0x3F;
00130 if (on) {
00131 buf[2] = 0x02;
00132 if ((rc = TwMasterTransact(I2C_SLA_RTC, buf, 3, 0, 0, NUT_WAIT_INFINITE)) == 0) {
00133 buf[2] = 0x06;
00134 rc = TwMasterTransact(I2C_SLA_RTC, buf, 3, 0, 0, NUT_WAIT_INFINITE);
00135 }
00136 } else {
00137 buf[2] = 0x00;
00138 rc = TwMasterTransact(I2C_SLA_RTC, buf, 3, 0, 0, NUT_WAIT_INFINITE);
00139 }
00140 return rc;
00141 }
00142
00148 static int X12WaitReady(void)
00149 {
00150 uint8_t poll;
00151 int cnt = 200;
00152
00153
00154
00155
00156
00157 while (--cnt && TwMasterTransact(I2C_SLA_EEPROM, 0, 0, &poll, 1, NUT_WAIT_INFINITE) == -1);
00158 #ifdef NUTDEBUG
00159 printf("[RtcRdy:%d]", 200 - cnt);
00160 #endif
00161
00162 return cnt ? 0 : -1;
00163 }
00164
00174 int X12RtcReadRegs(uint8_t reg, uint8_t *buff, size_t cnt)
00175 {
00176 int rc = -1;
00177 uint8_t wbuf[2];
00178
00179 wbuf[0] = 0;
00180 wbuf[1] = reg;
00181 if (TwMasterTransact(I2C_SLA_RTC, wbuf, 2, buff, cnt, NUT_WAIT_INFINITE) == cnt) {
00182 #ifdef NUTDEBUG
00183 printf("[Rtc$%02x>", reg);
00184 while(cnt--) {
00185 printf(" %02x", *buff++);
00186 }
00187 putchar(']');
00188 #endif
00189 rc = 0;
00190 }
00191 return rc;
00192 }
00193
00207 int X12RtcWrite(int nv, CONST uint8_t *buff, size_t cnt)
00208 {
00209 int rc;
00210
00211 if ((rc = X12WriteEnable(1)) == 0) {
00212 rc = TwMasterTransact(I2C_SLA_RTC, buff, cnt, 0, 0, NUT_WAIT_INFINITE);
00213 if (rc == 0 && nv) {
00214 rc = X12WaitReady();
00215 }
00216 X12WriteEnable(0);
00217 #ifdef NUTDEBUG
00218 printf("[Rtc$%02X<", *++buff);
00219 cnt -= 2;
00220 while(cnt--) {
00221 printf(" %02x", *++buff);
00222 }
00223 putchar(']');
00224 #endif
00225 }
00226 return rc;
00227 }
00228
00239 int X12RtcGetClock(struct _tm *tm)
00240 {
00241 int rc;
00242 uint8_t data[8];
00243
00244 if ((rc = X12RtcReadRegs(X12RTC_SC, data, 8)) == 0) {
00245 tm->tm_sec = BCD2BIN(data[0]);
00246 tm->tm_min = BCD2BIN(data[1]);
00247 tm->tm_hour = BCD2BIN(data[2] & 0x3F);
00248 tm->tm_mday = BCD2BIN(data[3]);
00249 tm->tm_mon = BCD2BIN(data[4]) - 1;
00250 if (rtc_chip) {
00251 tm->tm_year = BCD2BIN(data[5]) + 100;
00252 }
00253 else {
00254 tm->tm_year = BCD2BIN(data[5]);
00255 if (data[7] == 0x20) {
00256 tm->tm_year += 100;
00257 }
00258 }
00259 tm->tm_wday = data[6];
00260 }
00261 return rc;
00262 }
00263
00276 int X12RtcSetClock(CONST struct _tm *tm)
00277 {
00278 uint8_t data[10];
00279
00280 memset(data, 0, sizeof(data));
00281 if (tm) {
00282 data[1] = X12RTC_SC;
00283 data[2] = BIN2BCD(tm->tm_sec);
00284 data[3] = BIN2BCD(tm->tm_min);
00285 data[4] = BIN2BCD(tm->tm_hour) | 0x80;
00286 data[5] = BIN2BCD(tm->tm_mday);
00287 data[6] = BIN2BCD(tm->tm_mon + 1);
00288
00289 if (rtc_chip) {
00290
00291 data[7] = BIN2BCD(tm->tm_year % 100);
00292 }
00293
00294 else if (tm->tm_year > 99) {
00295 data[7] = BIN2BCD(tm->tm_year - 100);
00296 data[9] = 0x20;
00297 }
00298 else {
00299 data[7] = BIN2BCD(tm->tm_year);
00300 data[9] = 0x19;
00301 }
00302 data[8] = tm->tm_wday;
00303 }
00304 return X12RtcWrite(0, data, 10);
00305 }
00306
00320 int X12RtcGetAlarm(int idx, struct _tm *tm, int *aflgs)
00321 {
00322 int rc;
00323 uint8_t data[8];
00324
00325 *aflgs = 0;
00326 memset(tm, 0, sizeof(struct _tm));
00327 if ((rc = X12RtcReadRegs(idx * 8, data, 8)) == 0) {
00328 if (data[0] & X12RTC_SCA_ESC) {
00329 *aflgs |= RTC_ALARM_SECOND;
00330 tm->tm_sec = BCD2BIN(data[0] & 0x7F);
00331 }
00332 if (data[1] & X12RTC_MNA_EMN) {
00333 *aflgs |= RTC_ALARM_MINUTE;
00334 tm->tm_min = BCD2BIN(data[1]);
00335 }
00336 if (data[2] & X12RTC_HRA_EHR) {
00337 *aflgs |= RTC_ALARM_HOUR;
00338 tm->tm_hour = BCD2BIN(data[2] & ~0x80);
00339 }
00340 if (data[3] & X12RTC_DTA_EDT) {
00341 *aflgs |= RTC_ALARM_MDAY;
00342 tm->tm_mday = BCD2BIN(data[3]);
00343 }
00344 if (data[4] & X12RTC_MOA_EMO) {
00345 *aflgs |= RTC_ALARM_MONTH;
00346 tm->tm_mon = BCD2BIN(data[4]) - 1;
00347 }
00348 if (data[6] & X12RTC_DWA_EDW) {
00349 *aflgs |= RTC_ALARM_WDAY;
00350 tm->tm_wday = BCD2BIN(data[6]);
00351 }
00352 }
00353 return rc;
00354 }
00355
00374 int X12RtcSetAlarm(int idx, CONST struct _tm *tm, int aflgs)
00375 {
00376 uint8_t data[10];
00377
00378 memset(data, 0, sizeof(data));
00379 data[1] = idx * 8;
00380 if (tm) {
00381 if (aflgs & RTC_ALARM_SECOND) {
00382 data[2] = BIN2BCD(tm->tm_sec) | X12RTC_SCA_ESC;
00383 }
00384 if (aflgs & RTC_ALARM_MINUTE) {
00385 data[3] = BIN2BCD(tm->tm_min) | X12RTC_MNA_EMN;
00386 }
00387 if (aflgs & RTC_ALARM_HOUR) {
00388 data[4] = BIN2BCD(tm->tm_hour) | X12RTC_HRA_EHR;
00389 }
00390 if (aflgs & RTC_ALARM_MDAY) {
00391 data[5] = BIN2BCD(tm->tm_mday) | X12RTC_DTA_EDT;
00392 }
00393 if (aflgs & RTC_ALARM_MONTH) {
00394 data[6] = BIN2BCD(tm->tm_mon + 1) | X12RTC_MOA_EMO;
00395 }
00396 if (aflgs & RTC_ALARM_WDAY) {
00397 data[8] = BIN2BCD(tm->tm_wday) | X12RTC_DWA_EDW;
00398 }
00399 }
00400 return X12RtcWrite(1, data, 10);
00401 }
00402
00415 int X12RtcGetStatus(uint32_t *sflgs)
00416 {
00417 int rc;
00418 uint8_t data;
00419
00420 if ((rc = X12RtcReadRegs(X12RTC_SR, &data, 1)) == 0) {
00421 rtc_status |= data;
00422 *sflgs = rtc_status;
00423 }
00424 return rc;
00425 }
00426
00436 int X12RtcClearStatus(uint32_t sflgs)
00437 {
00438 rtc_status &= ~sflgs;
00439
00440 return 0;
00441 }
00442
00443 NUTRTC rtcX12x6 = {
00444 X12Init,
00445 X12RtcGetClock,
00446 X12RtcSetClock,
00447 X12RtcGetAlarm,
00448 X12RtcSetAlarm,
00449 X12RtcGetStatus,
00450 X12RtcClearStatus
00451 };
00452
00453
00463 int X12EepromRead(unsigned int addr, void *buff, size_t len)
00464 {
00465 int rc = -1;
00466 uint8_t wbuf[2];
00467
00468 wbuf[0] = (uint8_t)(addr >> 8);
00469 wbuf[1] = (uint8_t)addr;
00470 if (TwMasterTransact(I2C_SLA_EEPROM, wbuf, 2, buff, len, NUT_WAIT_INFINITE) == len) {
00471 rc = 0;
00472 }
00473 return rc;
00474 }
00475
00488 int X12EepromWrite(unsigned int addr, CONST void *buff, size_t len)
00489 {
00490 int rc = 0;
00491 uint8_t *wbuf;
00492 size_t wlen;
00493 CONST uint8_t *wp = buff;
00494
00495
00496
00497
00498 while (len) {
00499
00500 wlen = EEPROM_PAGE_SIZE - (addr & (EEPROM_PAGE_SIZE - 1));
00501 if (wlen > len) {
00502 wlen = len;
00503 }
00504
00505
00506 if ((wbuf = malloc(wlen + 2)) == 0) {
00507 rc = -1;
00508 break;
00509 }
00510 wbuf[0] = (uint8_t)(addr >> 8);
00511 wbuf[1] = (uint8_t)addr;
00512 memcpy(wbuf + 2, (void *)wp, wlen);
00513
00514
00515 if ((rc = X12WriteEnable(1)) == 0) {
00516 rc = TwMasterTransact(I2C_SLA_EEPROM, wbuf, wlen + 2, 0, 0, NUT_WAIT_INFINITE);
00517 }
00518
00519
00520 free(wbuf);
00521 if (rc) {
00522 break;
00523 }
00524 len -= wlen;
00525 addr += wlen;
00526 wp += wlen;
00527
00528
00529 if ((rc = X12WaitReady()) != 0) {
00530 break;
00531 }
00532 }
00533 X12WriteEnable(0);
00534
00535 return rc;
00536 }
00537
00546 int X12Init(void)
00547 {
00548 int rc;
00549 uint32_t tmp;
00550 uint8_t data[2];
00551
00552
00553 if ((rc = TwInit(0)) == 0) {
00554
00555 if ((rc = X12RtcGetStatus(&tmp)) == 0) {
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566 X12RtcReadRegs(X128xRTC_SSEC, &data[0], 1);
00567 NutSleep(20);
00568 X12RtcReadRegs(X128xRTC_SSEC, &data[1], 1);
00569 if (data[0] != data[1]) {
00570 rtc_chip = 1;
00571 }
00572 #ifdef NUTDEBUG
00573 printf("[RTC=X12%c6]", rtc_chip ? '8' : '2');
00574 #endif
00575 }
00576 }
00577 return rc;
00578 }