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
00070 #include <cfg/os.h>
00071 #include <cfg/eeprom.h>
00072
00073 #include <dev/twif.h>
00074 #include <sys/event.h>
00075 #include <sys/timer.h>
00076
00077 #include <time.h>
00078 #include <stdlib.h>
00079 #include <string.h>
00080
00081 #include <dev/x12rtc.h>
00082
00083 #if 0
00084
00085 #define NUTDEBUG
00086 #include <stdio.h>
00087 #endif
00088
00089 #ifndef I2C_SLA_RTC
00090 #define I2C_SLA_RTC 0x6F
00091 #endif
00092
00093 #ifndef I2C_SLA_EEPROM
00094 #define I2C_SLA_EEPROM 0x57
00095 #endif
00096
00097 #ifndef EEPROM_PAGE_SIZE
00098 #define EEPROM_PAGE_SIZE 64
00099 #endif
00100
00101 static u_char rtc_chip;
00102 static u_long rtc_status;
00103
00112 static int X12WriteEnable(int on)
00113 {
00114 int rc;
00115 u_char buf[3];
00116
00117 buf[0] = 0;
00118 buf[1] = 0x3F;
00119 if (on) {
00120 buf[2] = 0x02;
00121 if ((rc = TwMasterTransact(I2C_SLA_RTC, buf, 3, 0, 0, NUT_WAIT_INFINITE)) == 0) {
00122 buf[2] = 0x06;
00123 rc = TwMasterTransact(I2C_SLA_RTC, buf, 3, 0, 0, NUT_WAIT_INFINITE);
00124 }
00125 } else {
00126 buf[2] = 0x00;
00127 rc = TwMasterTransact(I2C_SLA_RTC, buf, 3, 0, 0, NUT_WAIT_INFINITE);
00128 }
00129 return rc;
00130 }
00131
00137 static int X12WaitReady(void)
00138 {
00139 u_char poll;
00140 int cnt = 200;
00141
00142
00143
00144
00145
00146 while (--cnt && TwMasterTransact(I2C_SLA_EEPROM, 0, 0, &poll, 1, NUT_WAIT_INFINITE) == -1);
00147 #ifdef NUTDEBUG
00148 printf("[RtcRdy:%d]", 200 - cnt);
00149 #endif
00150
00151 return cnt ? 0 : -1;
00152 }
00153
00163 int X12RtcReadRegs(u_char reg, u_char *buff, size_t cnt)
00164 {
00165 int rc = -1;
00166 u_char wbuf[2];
00167
00168 wbuf[0] = 0;
00169 wbuf[1] = reg;
00170 if (TwMasterTransact(I2C_SLA_RTC, wbuf, 2, buff, cnt, NUT_WAIT_INFINITE) == cnt) {
00171 #ifdef NUTDEBUG
00172 printf("[Rtc$%02x>", reg);
00173 while(cnt--) {
00174 printf(" %02x", *buff++);
00175 }
00176 putchar(']');
00177 #endif
00178 rc = 0;
00179 }
00180 return rc;
00181 }
00182
00196 int X12RtcWrite(int nv, CONST u_char *buff, size_t cnt)
00197 {
00198 int rc;
00199
00200 if ((rc = X12WriteEnable(1)) == 0) {
00201 rc = TwMasterTransact(I2C_SLA_RTC, buff, cnt, 0, 0, NUT_WAIT_INFINITE);
00202 if (rc == 0 && nv) {
00203 rc = X12WaitReady();
00204 }
00205 X12WriteEnable(0);
00206 #ifdef NUTDEBUG
00207 printf("[Rtc$%02X<", *++buff);
00208 cnt -= 2;
00209 while(cnt--) {
00210 printf(" %02x", *++buff);
00211 }
00212 putchar(']');
00213 #endif
00214 }
00215 return rc;
00216 }
00217
00228 int X12RtcGetClock(struct _tm *tm)
00229 {
00230 int rc;
00231 u_char data[8];
00232
00233 if ((rc = X12RtcReadRegs(X12RTC_SC, data, 8)) == 0) {
00234 tm->tm_sec = BCD2BIN(data[0]);
00235 tm->tm_min = BCD2BIN(data[1]);
00236 tm->tm_hour = BCD2BIN(data[2] & 0x3F);
00237 tm->tm_mday = BCD2BIN(data[3]);
00238 tm->tm_mon = BCD2BIN(data[4]) - 1;
00239 if (rtc_chip) {
00240 tm->tm_year = BCD2BIN(data[5]) + 100;
00241 }
00242 else {
00243 tm->tm_year = BCD2BIN(data[5]);
00244 if (data[7] == 0x20) {
00245 tm->tm_year += 100;
00246 }
00247 }
00248 tm->tm_wday = data[6];
00249 }
00250 return rc;
00251 }
00252
00265 int X12RtcSetClock(CONST struct _tm *tm)
00266 {
00267 u_char data[10];
00268
00269 memset(data, 0, sizeof(data));
00270 if (tm) {
00271 data[1] = X12RTC_SC;
00272 data[2] = BIN2BCD(tm->tm_sec);
00273 data[3] = BIN2BCD(tm->tm_min);
00274 data[4] = BIN2BCD(tm->tm_hour) | 0x80;
00275 data[5] = BIN2BCD(tm->tm_mday);
00276 data[6] = BIN2BCD(tm->tm_mon + 1);
00277
00278 if (rtc_chip) {
00279
00280 data[7] = BIN2BCD(tm->tm_year % 100);
00281 }
00282
00283 else if (tm->tm_year > 99) {
00284 data[7] = BIN2BCD(tm->tm_year - 100);
00285 data[9] = 0x20;
00286 }
00287 else {
00288 data[7] = BIN2BCD(tm->tm_year);
00289 data[9] = 0x19;
00290 }
00291 data[8] = tm->tm_wday;
00292 }
00293 return X12RtcWrite(0, data, 10);
00294 }
00295
00309 int X12RtcGetAlarm(int idx, struct _tm *tm, int *aflgs)
00310 {
00311 int rc;
00312 u_char data[8];
00313
00314 *aflgs = 0;
00315 memset(tm, 0, sizeof(struct _tm));
00316 if ((rc = X12RtcReadRegs(idx * 8, data, 8)) == 0) {
00317 if (data[0] & X12RTC_SCA_ESC) {
00318 *aflgs |= RTC_ALARM_SECOND;
00319 tm->tm_sec = BCD2BIN(data[0] & 0x7F);
00320 }
00321 if (data[1] & X12RTC_MNA_EMN) {
00322 *aflgs |= RTC_ALARM_MINUTE;
00323 tm->tm_min = BCD2BIN(data[1]);
00324 }
00325 if (data[2] & X12RTC_HRA_EHR) {
00326 *aflgs |= RTC_ALARM_HOUR;
00327 tm->tm_hour = BCD2BIN(data[2] & ~0x80);
00328 }
00329 if (data[3] & X12RTC_DTA_EDT) {
00330 *aflgs |= RTC_ALARM_MDAY;
00331 tm->tm_mday = BCD2BIN(data[3]);
00332 }
00333 if (data[4] & X12RTC_MOA_EMO) {
00334 *aflgs |= RTC_ALARM_MONTH;
00335 tm->tm_mon = BCD2BIN(data[4]) - 1;
00336 }
00337 if (data[6] & X12RTC_DWA_EDW) {
00338 *aflgs |= RTC_ALARM_WDAY;
00339 tm->tm_wday = BCD2BIN(data[6]);
00340 }
00341 }
00342 return rc;
00343 }
00344
00363 int X12RtcSetAlarm(int idx, CONST struct _tm *tm, int aflgs)
00364 {
00365 u_char data[10];
00366
00367 memset(data, 0, sizeof(data));
00368 data[1] = idx * 8;
00369 if (tm) {
00370 if (aflgs & RTC_ALARM_SECOND) {
00371 data[2] = BIN2BCD(tm->tm_sec) | X12RTC_SCA_ESC;
00372 }
00373 if (aflgs & RTC_ALARM_MINUTE) {
00374 data[3] = BIN2BCD(tm->tm_min) | X12RTC_MNA_EMN;
00375 }
00376 if (aflgs & RTC_ALARM_HOUR) {
00377 data[4] = BIN2BCD(tm->tm_hour) | X12RTC_HRA_EHR;
00378 }
00379 if (aflgs & RTC_ALARM_MDAY) {
00380 data[5] = BIN2BCD(tm->tm_mday) | X12RTC_DTA_EDT;
00381 }
00382 if (aflgs & RTC_ALARM_MONTH) {
00383 data[6] = BIN2BCD(tm->tm_mon + 1) | X12RTC_MOA_EMO;
00384 }
00385 if (aflgs & RTC_ALARM_WDAY) {
00386 data[8] = BIN2BCD(tm->tm_wday) | X12RTC_DWA_EDW;
00387 }
00388 }
00389 return X12RtcWrite(1, data, 10);
00390 }
00391
00404 int X12RtcGetStatus(u_long *sflgs)
00405 {
00406 int rc;
00407 u_char data;
00408
00409 if ((rc = X12RtcReadRegs(X12RTC_SR, &data, 1)) == 0) {
00410 rtc_status |= data;
00411 *sflgs = rtc_status;
00412 }
00413 return rc;
00414 }
00415
00425 int X12RtcClearStatus(u_long sflgs)
00426 {
00427 rtc_status &= ~sflgs;
00428
00429 return 0;
00430 }
00431
00432 NUTRTC rtcX12x6 = {
00433 X12Init,
00434 X12RtcGetClock,
00435 X12RtcSetClock,
00436 X12RtcGetAlarm,
00437 X12RtcSetAlarm,
00438 X12RtcGetStatus,
00439 X12RtcClearStatus
00440 };
00441
00442
00452 int X12EepromRead(u_int addr, void *buff, size_t len)
00453 {
00454 int rc = -1;
00455 u_char wbuf[2];
00456
00457 wbuf[0] = (u_char)(addr >> 8);
00458 wbuf[1] = (u_char)addr;
00459 if (TwMasterTransact(I2C_SLA_EEPROM, wbuf, 2, buff, len, NUT_WAIT_INFINITE) == len) {
00460 rc = 0;
00461 }
00462 return rc;
00463 }
00464
00477 int X12EepromWrite(u_int addr, CONST void *buff, size_t len)
00478 {
00479 int rc = 0;
00480 u_char *wbuf;
00481 size_t wlen;
00482 CONST u_char *wp = buff;
00483
00484
00485
00486
00487 while (len) {
00488
00489 wlen = EEPROM_PAGE_SIZE - (addr & (EEPROM_PAGE_SIZE - 1));
00490 if (wlen > len) {
00491 wlen = len;
00492 }
00493
00494
00495 if ((wbuf = malloc(wlen + 2)) == 0) {
00496 rc = -1;
00497 break;
00498 }
00499 wbuf[0] = (u_char)(addr >> 8);
00500 wbuf[1] = (u_char)addr;
00501 memcpy(wbuf + 2, (void *)wp, wlen);
00502
00503
00504 if ((rc = X12WriteEnable(1)) == 0) {
00505 rc = TwMasterTransact(I2C_SLA_EEPROM, wbuf, wlen + 2, 0, 0, NUT_WAIT_INFINITE);
00506 }
00507
00508
00509 free(wbuf);
00510 if (rc) {
00511 break;
00512 }
00513 len -= wlen;
00514 addr += wlen;
00515 wp += wlen;
00516
00517
00518 if ((rc = X12WaitReady()) != 0) {
00519 break;
00520 }
00521 }
00522 X12WriteEnable(0);
00523
00524 return rc;
00525 }
00526
00535 int X12Init(void)
00536 {
00537 int rc;
00538 u_long tmp;
00539 u_char data[2];
00540
00541
00542 if ((rc = TwInit(0)) == 0) {
00543
00544 if ((rc = X12RtcGetStatus(&tmp)) == 0) {
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555 X12RtcReadRegs(X128xRTC_SSEC, &data[0], 1);
00556 NutSleep(20);
00557 X12RtcReadRegs(X128xRTC_SSEC, &data[1], 1);
00558 if (data[0] != data[1]) {
00559 rtc_chip = 1;
00560 }
00561 #ifdef NUTDEBUG
00562 printf("[RTC=X12%c6]", rtc_chip ? '8' : '2');
00563 #endif
00564 }
00565 }
00566 return rc;
00567 }