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
00067 #include <cfg/os.h>
00068 #include <dev/twif.h>
00069 #include <sys/event.h>
00070 #include <sys/timer.h>
00071
00072 #include <time.h>
00073 #include <stdlib.h>
00074 #include <string.h>
00075
00076 #include <dev/x12rtc.h>
00077
00078 #if 0
00079
00080 #define NUTDEBUG
00081 #include <stdio.h>
00082 #endif
00083
00084 #ifndef I2C_SLA_RTC
00085 #define I2C_SLA_RTC 0x6F
00086 #endif
00087
00088 #ifndef I2C_SLA_EEPROM
00089 #define I2C_SLA_EEPROM 0x57
00090 #endif
00091
00092 #ifndef EEPROM_PAGE_SIZE
00093 #define EEPROM_PAGE_SIZE 64
00094 #endif
00095
00096 static u_char rtc_chip;
00097 static u_long rtc_status;
00098
00107 static int X12WriteEnable(int on)
00108 {
00109 int rc;
00110 u_char buf[3];
00111
00112 buf[0] = 0;
00113 buf[1] = 0x3F;
00114 if (on) {
00115 buf[2] = 0x02;
00116 if ((rc = TwMasterTransact(I2C_SLA_RTC, buf, 3, 0, 0, NUT_WAIT_INFINITE)) == 0) {
00117 buf[2] = 0x06;
00118 rc = TwMasterTransact(I2C_SLA_RTC, buf, 3, 0, 0, NUT_WAIT_INFINITE);
00119 }
00120 } else {
00121 buf[2] = 0x00;
00122 rc = TwMasterTransact(I2C_SLA_RTC, buf, 3, 0, 0, NUT_WAIT_INFINITE);
00123 }
00124 return rc;
00125 }
00126
00132 static int X12WaitReady(void)
00133 {
00134 u_char poll;
00135 int cnt = 200;
00136
00137
00138
00139
00140
00141 while (--cnt && TwMasterTransact(I2C_SLA_EEPROM, 0, 0, &poll, 1, NUT_WAIT_INFINITE) == -1);
00142 #ifdef NUTDEBUG
00143 printf("[RtcRdy:%d]", 200 - cnt);
00144 #endif
00145
00146 return cnt ? 0 : -1;
00147 }
00148
00158 int X12RtcReadRegs(u_char reg, u_char *buff, size_t cnt)
00159 {
00160 int rc = -1;
00161 u_char wbuf[2];
00162
00163 wbuf[0] = 0;
00164 wbuf[1] = reg;
00165 if (TwMasterTransact(I2C_SLA_RTC, wbuf, 2, buff, cnt, NUT_WAIT_INFINITE) == cnt) {
00166 #ifdef NUTDEBUG
00167 printf("[Rtc$%02x>", reg);
00168 while(cnt--) {
00169 printf(" %02x", *buff++);
00170 }
00171 putchar(']');
00172 #endif
00173 rc = 0;
00174 }
00175 return rc;
00176 }
00177
00191 int X12RtcWrite(int nv, CONST u_char *buff, size_t cnt)
00192 {
00193 int rc;
00194
00195 if ((rc = X12WriteEnable(1)) == 0) {
00196 rc = TwMasterTransact(I2C_SLA_RTC, buff, cnt, 0, 0, NUT_WAIT_INFINITE);
00197 if (rc == 0 && nv) {
00198 rc = X12WaitReady();
00199 }
00200 X12WriteEnable(0);
00201 #ifdef NUTDEBUG
00202 printf("[Rtc$%02X<", *++buff);
00203 cnt -= 2;
00204 while(cnt--) {
00205 printf(" %02x", *++buff);
00206 }
00207 putchar(']');
00208 #endif
00209 }
00210 return rc;
00211 }
00212
00223 int X12RtcGetClock(struct _tm *tm)
00224 {
00225 int rc;
00226 u_char data[8];
00227
00228 if ((rc = X12RtcReadRegs(X12RTC_SC, data, 8)) == 0) {
00229 tm->tm_sec = BCD2BIN(data[0]);
00230 tm->tm_min = BCD2BIN(data[1]);
00231 tm->tm_hour = BCD2BIN(data[2] & 0x3F);
00232 tm->tm_mday = BCD2BIN(data[3]);
00233 tm->tm_mon = BCD2BIN(data[4]) - 1;
00234 if (rtc_chip) {
00235 tm->tm_year = BCD2BIN(data[5]) + 100;
00236 }
00237 else {
00238 tm->tm_year = BCD2BIN(data[5]);
00239 if (data[7] == 0x20) {
00240 tm->tm_year += 100;
00241 }
00242 }
00243 tm->tm_wday = data[6];
00244 }
00245 return rc;
00246 }
00247
00260 int X12RtcSetClock(CONST struct _tm *tm)
00261 {
00262 u_char data[10];
00263
00264 memset(data, 0, sizeof(data));
00265 if (tm) {
00266 data[1] = X12RTC_SC;
00267 data[2] = BIN2BCD(tm->tm_sec);
00268 data[3] = BIN2BCD(tm->tm_min);
00269 data[4] = BIN2BCD(tm->tm_hour) | 0x80;
00270 data[5] = BIN2BCD(tm->tm_mday);
00271 data[6] = BIN2BCD(tm->tm_mon + 1);
00272
00273 if (rtc_chip) {
00274
00275 data[7] = BIN2BCD(tm->tm_year % 100);
00276 }
00277
00278 else if (tm->tm_year > 99) {
00279 data[7] = BIN2BCD(tm->tm_year - 100);
00280 data[9] = 0x20;
00281 }
00282 else {
00283 data[7] = BIN2BCD(tm->tm_year);
00284 data[9] = 0x19;
00285 }
00286 data[8] = tm->tm_wday;
00287 }
00288 return X12RtcWrite(0, data, 10);
00289 }
00290
00304 int X12RtcGetAlarm(int idx, struct _tm *tm, int *aflgs)
00305 {
00306 int rc;
00307 u_char data[8];
00308
00309 *aflgs = 0;
00310 memset(tm, 0, sizeof(struct _tm));
00311 if ((rc = X12RtcReadRegs(idx * 8, data, 8)) == 0) {
00312 if (data[0] & X12RTC_SCA_ESC) {
00313 *aflgs |= RTC_ALARM_SECOND;
00314 tm->tm_sec = BCD2BIN(data[0] & 0x7F);
00315 }
00316 if (data[1] & X12RTC_MNA_EMN) {
00317 *aflgs |= RTC_ALARM_MINUTE;
00318 tm->tm_min = BCD2BIN(data[1]);
00319 }
00320 if (data[2] & X12RTC_HRA_EHR) {
00321 *aflgs |= RTC_ALARM_HOUR;
00322 tm->tm_hour = BCD2BIN(data[2] & ~0x80);
00323 }
00324 if (data[3] & X12RTC_DTA_EDT) {
00325 *aflgs |= RTC_ALARM_MDAY;
00326 tm->tm_mday = BCD2BIN(data[3]);
00327 }
00328 if (data[4] & X12RTC_MOA_EMO) {
00329 *aflgs |= RTC_ALARM_MONTH;
00330 tm->tm_mon = BCD2BIN(data[4]) - 1;
00331 }
00332 if (data[6] & X12RTC_DWA_EDW) {
00333 *aflgs |= RTC_ALARM_WDAY;
00334 tm->tm_wday = BCD2BIN(data[6]);
00335 }
00336 }
00337 return rc;
00338 }
00339
00358 int X12RtcSetAlarm(int idx, CONST struct _tm *tm, int aflgs)
00359 {
00360 u_char data[10];
00361
00362 memset(data, 0, sizeof(data));
00363 data[1] = idx * 8;
00364 if (tm) {
00365 if (aflgs & RTC_ALARM_SECOND) {
00366 data[2] = BIN2BCD(tm->tm_sec) | X12RTC_SCA_ESC;
00367 }
00368 if (aflgs & RTC_ALARM_MINUTE) {
00369 data[3] = BIN2BCD(tm->tm_min) | X12RTC_MNA_EMN;
00370 }
00371 if (aflgs & RTC_ALARM_HOUR) {
00372 data[4] = BIN2BCD(tm->tm_hour) | X12RTC_HRA_EHR;
00373 }
00374 if (aflgs & RTC_ALARM_MDAY) {
00375 data[5] = BIN2BCD(tm->tm_mday) | X12RTC_DTA_EDT;
00376 }
00377 if (aflgs & RTC_ALARM_MONTH) {
00378 data[6] = BIN2BCD(tm->tm_mon + 1) | X12RTC_MOA_EMO;
00379 }
00380 if (aflgs & RTC_ALARM_WDAY) {
00381 data[8] = BIN2BCD(tm->tm_wday) | X12RTC_DWA_EDW;
00382 }
00383 }
00384 return X12RtcWrite(1, data, 10);
00385 }
00386
00399 int X12RtcGetStatus(u_long *sflgs)
00400 {
00401 int rc;
00402 u_char data;
00403
00404 if ((rc = X12RtcReadRegs(X12RTC_SR, &data, 1)) == 0) {
00405 rtc_status |= data;
00406 *sflgs = rtc_status;
00407 }
00408 return rc;
00409 }
00410
00420 int X12RtcClearStatus(u_long sflgs)
00421 {
00422 rtc_status &= ~sflgs;
00423
00424 return 0;
00425 }
00426
00427 NUTRTC rtcX12x6 = {
00428 X12Init,
00429 X12RtcGetClock,
00430 X12RtcSetClock,
00431 X12RtcGetAlarm,
00432 X12RtcSetAlarm,
00433 X12RtcGetStatus,
00434 X12RtcClearStatus
00435 };
00436
00437
00447 int X12EepromRead(u_int addr, void *buff, size_t len)
00448 {
00449 int rc = -1;
00450 u_char wbuf[2];
00451
00452 wbuf[0] = (u_char)(addr >> 8);
00453 wbuf[1] = (u_char)addr;
00454 if (TwMasterTransact(I2C_SLA_EEPROM, wbuf, 2, buff, len, NUT_WAIT_INFINITE) == len) {
00455 rc = 0;
00456 }
00457 return rc;
00458 }
00459
00472 int X12EepromWrite(u_int addr, CONST void *buff, size_t len)
00473 {
00474 int rc = 0;
00475 u_char *wbuf;
00476 size_t wlen;
00477 CONST u_char *wp = buff;
00478
00479
00480
00481
00482 while (len) {
00483
00484 wlen = EEPROM_PAGE_SIZE - (addr & (EEPROM_PAGE_SIZE - 1));
00485 if (wlen > len) {
00486 wlen = len;
00487 }
00488
00489
00490 if ((wbuf = malloc(wlen + 2)) == 0) {
00491 rc = -1;
00492 break;
00493 }
00494 wbuf[0] = (u_char)(addr >> 8);
00495 wbuf[1] = (u_char)addr;
00496 memcpy(wbuf + 2, (void *)wp, wlen);
00497
00498
00499 if ((rc = X12WriteEnable(1)) == 0) {
00500 rc = TwMasterTransact(I2C_SLA_EEPROM, wbuf, wlen + 2, 0, 0, NUT_WAIT_INFINITE);
00501 }
00502
00503
00504 free(wbuf);
00505 if (rc) {
00506 break;
00507 }
00508 len -= wlen;
00509 addr += wlen;
00510 wp += wlen;
00511
00512
00513 if ((rc = X12WaitReady()) != 0) {
00514 break;
00515 }
00516 }
00517 X12WriteEnable(0);
00518
00519 return rc;
00520 }
00521
00530 int X12Init(void)
00531 {
00532 int rc;
00533 u_long tmp;
00534 u_char data[2];
00535
00536
00537 if ((rc = TwInit(0)) == 0) {
00538
00539 if ((rc = X12RtcGetStatus(&tmp)) == 0) {
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550 X12RtcReadRegs(X128xRTC_SSEC, &data[0], 1);
00551 NutSleep(20);
00552 X12RtcReadRegs(X128xRTC_SSEC, &data[1], 1);
00553 if (data[0] != data[1]) {
00554 rtc_chip = 1;
00555 }
00556 #ifdef NUTDEBUG
00557 printf("[RTC=X12%c6]", rtc_chip ? '8' : '2');
00558 #endif
00559 }
00560 }
00561 return rc;
00562 }