rtc.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. /* ========================================================================
  2. * [PROJECT] SIR
  3. * [MODULE] Real Time Clock
  4. * [TITLE] High- and low level Routines for INtersil X1205 RTC chip
  5. * [FILE] rtc.c
  6. * [VSN] 1.0
  7. * [CREATED] 13042007
  8. * [LASTCHNGD] 131042007
  9. * [COPYRIGHT] Copyright (C) STREAMIT BV 2010
  10. * [PURPOSE] contains all interface- and low-level routines to
  11. * read/write date/time/status strings from the X1205
  12. * ======================================================================== */
  13. #define LOG_MODULE LOG_RTC_MODULE
  14. #include <cfg/os.h>
  15. #include <dev/twif.h>
  16. #include <sys/event.h>
  17. #include <sys/timer.h>
  18. #include <time.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include "rtc.h"
  22. #include "portio.h"
  23. #define I2C_SLA_RTC 0x6F
  24. #define I2C_SLA_EEPROM 0x57
  25. #define EEPROM_PAGE_SIZE 64
  26. static u_long rtc_status;
  27. /*!
  28. * \brief Enable or disable write access.
  29. *
  30. * \param on Write access is disabled if this parameter is 0, or
  31. * enabled otherwise.
  32. *
  33. * \return 0 on success or -1 in case of an error.
  34. */
  35. static int X12WriteEnable(int on)
  36. {
  37. int rc;
  38. u_char buf[3];
  39. buf[0] = 0;
  40. buf[1] = 0x3F;
  41. if (on)
  42. {
  43. buf[2] = 0x02;
  44. if ((rc = TwMasterTransact(I2C_SLA_RTC, buf, 3, 0, 0, NUT_WAIT_INFINITE)) == 0)
  45. {
  46. buf[2] = 0x06;
  47. rc = TwMasterTransact(I2C_SLA_RTC, buf, 3, 0, 0, NUT_WAIT_INFINITE);
  48. }
  49. }
  50. else
  51. {
  52. buf[2] = 0x00;
  53. rc = TwMasterTransact(I2C_SLA_RTC, buf, 3, 0, 0, NUT_WAIT_INFINITE);
  54. }
  55. return(rc);
  56. }
  57. /*!
  58. * \brief Wait until non-volatile write cycle finished.
  59. *
  60. * \return 0 on success or -1 in case of an error.
  61. */
  62. static int X12WaitReady(void)
  63. {
  64. u_char poll;
  65. int cnt = 20;
  66. /* Poll for write cycle finished. */
  67. while (--cnt && TwMasterTransact(I2C_SLA_EEPROM, 0, 0, &poll, 1, NUT_WAIT_INFINITE) == -1)
  68. {
  69. NutSleep(1);
  70. }
  71. return(cnt ? 0 : -1);
  72. }
  73. /*!
  74. * \brief Read RTC registers.
  75. *
  76. * \param reg The first register to read.
  77. * \param buff Pointer to a buffer that receives the register contents.
  78. * \param cnt The number of registers to read.
  79. *
  80. * \return 0 on success or -1 in case of an error.
  81. */
  82. int X12RtcReadRegs(u_char reg, u_char *buff, size_t cnt)
  83. {
  84. int rc = -1;
  85. u_char wbuf[2];
  86. wbuf[0] = 0;
  87. wbuf[1] = reg;
  88. if (TwMasterTransact(I2C_SLA_RTC, wbuf, 2, buff, cnt, NUT_WAIT_INFINITE) == cnt)
  89. {
  90. rc = 0;
  91. }
  92. return(rc);
  93. }
  94. /*!
  95. * \brief Write to RTC registers.
  96. *
  97. * \param nv Must be set to 1 when writing to non-volatile registers.
  98. * In this case the routine will poll for write cycle
  99. * completion before returning to the caller. Set to zero
  100. * if writing to volatile registers.
  101. * \param buff This buffer must contain all bytes to be transfered to
  102. * the RTC chip, including the register address.
  103. * \param cnt Number of valid bytes in the buffer.
  104. *
  105. * \return 0 on success or -1 in case of an error.
  106. */
  107. int X12RtcWrite(int nv, CONST u_char *buff, size_t cnt)
  108. {
  109. int rc;
  110. if ((rc = X12WriteEnable(1)) == 0)
  111. {
  112. rc = TwMasterTransact(I2C_SLA_RTC, buff, cnt, 0, 0, NUT_WAIT_INFINITE);
  113. if (rc == 0 && nv)
  114. {
  115. rc = X12WaitReady();
  116. }
  117. X12WriteEnable(0);
  118. }
  119. return(rc);
  120. }
  121. /*!
  122. * \brief Get date and time from an X12xx hardware clock.
  123. *
  124. * \deprecated New applications must use NutRtcGetTime().
  125. *
  126. * \param tm Points to a structure that receives the date and time
  127. * information.
  128. *
  129. * \return 0 on success or -1 in case of an error.
  130. */
  131. int X12RtcGetClock(struct _tm *tm)
  132. {
  133. int rc;
  134. u_char data[8];
  135. if ((rc = X12RtcReadRegs(X12RTC_SC, data, 8)) == 0)
  136. {
  137. tm->tm_sec = BCD2BIN(data[0]);
  138. tm->tm_min = BCD2BIN(data[1]);
  139. tm->tm_hour = BCD2BIN(data[2] & 0x3F);
  140. tm->tm_mday = BCD2BIN(data[3]);
  141. tm->tm_mon = BCD2BIN(data[4]) - 1;
  142. tm->tm_year = BCD2BIN(data[5]) + 100;
  143. if (BCD2BIN(data[7]) > 0x19)
  144. {
  145. tm->tm_year += 100;
  146. }
  147. tm->tm_wday = data[6];
  148. }
  149. return(rc);
  150. }
  151. /*!
  152. * \brief Set an X12xx hardware clock.
  153. *
  154. * \deprecated New applications must use NutRtcSetTime().
  155. *
  156. * New time will be taken over at the beginning of the next second.
  157. *
  158. * \param tm Points to a structure which contains the date and time
  159. * information.
  160. *
  161. * \return 0 on success or -1 in case of an error.
  162. */
  163. int X12RtcSetClock(CONST struct _tm *tm)
  164. {
  165. u_char data[10];
  166. memset(data, 0, sizeof(data));
  167. if (tm)
  168. {
  169. data[1] = X12RTC_SC;
  170. data[2] = BIN2BCD(tm->tm_sec);
  171. data[3] = BIN2BCD(tm->tm_min);
  172. data[4] = BIN2BCD(tm->tm_hour) | 0x80;
  173. data[5] = BIN2BCD(tm->tm_mday);
  174. data[6] = BIN2BCD(tm->tm_mon + 1);
  175. if (tm->tm_year > 99)
  176. {
  177. data[7] = BIN2BCD(tm->tm_year - 100);
  178. data[9] = 0x20;
  179. }
  180. else
  181. {
  182. data[7] = BIN2BCD(tm->tm_year);
  183. data[9] = 0x19;
  184. }
  185. data[8] = tm->tm_wday;
  186. }
  187. return(X12RtcWrite(0, data, 10));
  188. }
  189. /*!
  190. * \brief Get alarm date and time of an X12xx hardware clock.
  191. *
  192. * \deprecated New applications must use NutRtcGetAlarm().
  193. *
  194. * \param idx Zero based index. Two alarms are supported.
  195. * \param tm Points to a structure that receives the date and time
  196. * information.
  197. * \param aflgs Points to an unsigned long that receives the enable flags.
  198. *
  199. * \return 0 on success or -1 in case of an error.
  200. *
  201. */
  202. int X12RtcGetAlarm(int idx, struct _tm *tm, int *aflgs)
  203. {
  204. int rc;
  205. u_char data[8];
  206. *aflgs = 0;
  207. memset(tm, 0, sizeof(struct _tm));
  208. if ((rc = X12RtcReadRegs(idx * 8, data, 8)) == 0)
  209. {
  210. if (data[0] & X12RTC_SCA_ESC)
  211. {
  212. *aflgs |= RTC_ALARM_SECOND;
  213. tm->tm_sec = BCD2BIN(data[0] & 0x7F);
  214. }
  215. if (data[1] & X12RTC_MNA_EMN)
  216. {
  217. *aflgs |= RTC_ALARM_MINUTE;
  218. tm->tm_min = BCD2BIN(data[1]);
  219. }
  220. if (data[2] & X12RTC_HRA_EHR)
  221. {
  222. *aflgs |= RTC_ALARM_HOUR;
  223. tm->tm_hour = BCD2BIN(data[2] & ~0x80);
  224. }
  225. if (data[3] & X12RTC_DTA_EDT)
  226. {
  227. *aflgs |= RTC_ALARM_MDAY;
  228. tm->tm_mday = BCD2BIN(data[3]);
  229. }
  230. if (data[4] & X12RTC_MOA_EMO)
  231. {
  232. *aflgs |= RTC_ALARM_MONTH;
  233. tm->tm_mon = BCD2BIN(data[4]) - 1;
  234. }
  235. if (data[6] & X12RTC_DWA_EDW)
  236. {
  237. *aflgs |= RTC_ALARM_WDAY;
  238. tm->tm_wday = BCD2BIN(data[6]);
  239. }
  240. }
  241. return(rc);
  242. }
  243. /*!
  244. * \brief Set alarm of an X12xx hardware clock.
  245. *
  246. * \deprecated New applications must use NutRtcSetAlarm().
  247. *
  248. * \param idx Zero based index. Two alarms are supported.
  249. * \param tm Points to a structure which contains the date and time
  250. * information. May be NULL to clear the alarm.
  251. * \param aflgs Each bit enables a specific comparision.
  252. * - Bit 0: Seconds
  253. * - Bit 1: Minutes
  254. * - Bit 2: Hours
  255. * - Bit 3: Day of month
  256. * - Bit 4: Month
  257. * - Bit 7: Day of week (Sunday is zero)
  258. *
  259. * \return 0 on success or -1 in case of an error.
  260. */
  261. int X12RtcSetAlarm(int idx, CONST struct _tm *tm, int aflgs)
  262. {
  263. u_char data[10];
  264. memset(data, 0, sizeof(data));
  265. data[1] = idx * 8;
  266. if (tm)
  267. {
  268. if (aflgs & RTC_ALARM_SECOND)
  269. {
  270. data[2] = BIN2BCD(tm->tm_sec) | X12RTC_SCA_ESC;
  271. }
  272. if (aflgs & RTC_ALARM_MINUTE)
  273. {
  274. data[3] = BIN2BCD(tm->tm_min) | X12RTC_MNA_EMN;
  275. }
  276. if (aflgs & RTC_ALARM_HOUR)
  277. {
  278. data[4] = BIN2BCD(tm->tm_hour) | X12RTC_HRA_EHR;
  279. }
  280. if (aflgs & RTC_ALARM_MDAY)
  281. {
  282. data[5] = BIN2BCD(tm->tm_mday) | X12RTC_DTA_EDT;
  283. }
  284. if (aflgs & RTC_ALARM_MONTH)
  285. {
  286. data[6] = BIN2BCD(tm->tm_mon + 1) | X12RTC_MOA_EMO;
  287. }
  288. if (aflgs & RTC_ALARM_WDAY)
  289. {
  290. data[8] = BIN2BCD(tm->tm_wday) | X12RTC_DWA_EDW;
  291. }
  292. }
  293. return(X12RtcWrite(1, data, 10));
  294. }
  295. /*!
  296. * \brief Query RTC status flags.
  297. *
  298. * \deprecated New applications must use NutRtcGetStatus().
  299. *
  300. * \param sflgs Points to an unsigned long that receives the status flags.
  301. * - Bit 0: Power fail.
  302. * - Bit 5: Alarm 0 occured.
  303. * - Bit 6: Alarm 1 occured.
  304. *
  305. * \return 0 on success or -1 in case of an error.
  306. */
  307. int X12RtcGetStatus(u_long *sflgs)
  308. {
  309. int rc;
  310. u_char data;
  311. if ((rc = X12RtcReadRegs(X12RTC_SR, &data, 1)) == 0)
  312. {
  313. rtc_status |= data;
  314. *sflgs = rtc_status;
  315. }
  316. return(rtc_status);
  317. }
  318. /*!
  319. * \brief Clear RTC status flags.
  320. *
  321. * \deprecated New applications must use NutRtcClearStatus().
  322. *
  323. * \param sflgs Status flags to clear.
  324. *
  325. * \return Always 0.
  326. */
  327. int X12RtcClearStatus(u_long sflgs)
  328. {
  329. rtc_status &= sflgs;
  330. return(0);
  331. }
  332. /*!
  333. * \brief Read contents from non-volatile EEPROM.
  334. *
  335. * \param addr Start location.
  336. * \param buff Points to a buffer that receives the contents.
  337. * \param len Number of bytes to read.
  338. *
  339. * \return 0 on success or -1 in case of an error.
  340. */
  341. int X12EepromRead(u_int addr, void *buff, size_t len)
  342. {
  343. int rc = -1;
  344. u_char wbuf[2];
  345. wbuf[0] = (u_char)(addr >> 8);
  346. wbuf[1] = (u_char)addr;
  347. if (TwMasterTransact(I2C_SLA_EEPROM, wbuf, 2, buff, len, NUT_WAIT_INFINITE) == len)
  348. {
  349. rc = 0;
  350. }
  351. return(rc);
  352. }
  353. /*!
  354. * \brief Store buffer contents in non-volatile EEPROM.
  355. *
  356. * The EEPROM of the X122x has a capacity of 512 bytes, while the X1286 is
  357. * able to store 32 kBytes.
  358. *
  359. * \param addr Storage start location.
  360. * \param buff Points to a buffer that contains the bytes to store.
  361. * \param len Number of valid bytes in the buffer.
  362. *
  363. * \return 0 on success or -1 in case of an error.
  364. */
  365. int X12EepromWrite(u_int addr, CONST void *buff, size_t len)
  366. {
  367. int rc = 0;
  368. u_char *wbuf;
  369. size_t wlen;
  370. CONST u_char *wp = buff;
  371. /*
  372. * Loop for each page to be written to.
  373. */
  374. while (len)
  375. {
  376. /* Do not cross page boundaries. */
  377. wlen = EEPROM_PAGE_SIZE - (addr & (EEPROM_PAGE_SIZE - 1));
  378. if (wlen > len)
  379. {
  380. wlen = len;
  381. }
  382. /* Allocate and set a TWI write buffer. */
  383. if ((wbuf = malloc(wlen + 2)) == 0)
  384. {
  385. rc = -1;
  386. break;
  387. }
  388. wbuf[0] = (u_char)(addr >> 8);
  389. wbuf[1] = (u_char)addr;
  390. memcpy(wbuf + 2, (void *)wp, wlen);
  391. /* Enable EEPROM write access and send the write buffer. */
  392. if ((rc = X12WriteEnable(1)) == 0)
  393. {
  394. rc = TwMasterTransact(I2C_SLA_EEPROM, wbuf, wlen + 2, 0, 0, NUT_WAIT_INFINITE);
  395. }
  396. /* Release the buffer and check the result. */
  397. free(wbuf);
  398. if (rc)
  399. {
  400. break;
  401. }
  402. len -= wlen;
  403. addr += wlen;
  404. wp += wlen;
  405. /* Poll for write cycle finished. */
  406. if ((rc = X12WaitReady()) != 0)
  407. {
  408. break;
  409. }
  410. }
  411. X12WriteEnable(0);
  412. return(rc);
  413. }
  414. /*!
  415. * \brief Initialize the interface to an Intersil X12xx hardware clock.
  416. *
  417. * \deprecated New applications must use NutRegisterRtc().
  418. *
  419. * \return 0 on success or -1 in case of an error.
  420. *
  421. */
  422. int X12Init(void)
  423. {
  424. int rc;
  425. u_long tmp;
  426. if ((rc = TwInit(0)) == 0)
  427. {
  428. rc = X12RtcGetStatus(&tmp);
  429. }
  430. return (rc);
  431. }
  432. struct _tm GetRTCTime(){
  433. struct _tm gmt;
  434. X12RtcGetClock(&gmt);
  435. return gmt;
  436. }