i2c_pcf85xx.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /*
  2. * Copyright (C) 2012 by egnite GmbH
  3. * Copyright (C) 2006 by egnite Software GmbH
  4. *
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. * 3. Neither the name of the copyright holders nor the names of
  17. * contributors may be used to endorse or promote products derived
  18. * from this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  23. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  24. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  26. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  27. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  28. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  29. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  30. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. *
  33. * For additional information see http://www.ethernut.de/
  34. */
  35. /*!
  36. * \file dev/pcf85xx.c
  37. * \brief RTC for NXP PCF85XX clock chips.
  38. *
  39. * \verbatim
  40. * $Id$
  41. * \endverbatim
  42. */
  43. #include <sys/event.h>
  44. #include <sys/timer.h>
  45. #include <time.h>
  46. #include <dev/i2cbus.h>
  47. #include <dev/i2c_pcf85xx.h>
  48. /*!
  49. * \addtogroup xgI2cPcf85xx
  50. */
  51. /*@{*/
  52. #ifndef I2C_SLA_RTC
  53. #define I2C_SLA_RTC 0x51
  54. #endif
  55. static uint32_t rtc_status;
  56. /*!
  57. * \brief Get date and time from an PCF85XX hardware clock.
  58. *
  59. * \param rtc Specifies the RTC device.
  60. * \param tm Points to a structure that receives the date and time
  61. * information.
  62. *
  63. * \return 0 on success or -1 in case of an error.
  64. */
  65. static int I2cPcfGetClock(NUTRTC *rtc, struct _tm *tm)
  66. {
  67. uint8_t data[7];
  68. data[0] = 2;
  69. if (NutI2cMasterTransceive(rtc->dcb, data, 1, data, 7) != 7) {
  70. return -1;
  71. }
  72. tm->tm_sec = BCD2BIN(data[0] & 0x7F);
  73. tm->tm_min = BCD2BIN(data[1] & 0x7F);
  74. tm->tm_hour = BCD2BIN(data[2] & 0x3F);
  75. tm->tm_mday = BCD2BIN(data[3] & 0x3F);
  76. tm->tm_mon = BCD2BIN(data[5] & 0x1F) - 1;
  77. tm->tm_year = BCD2BIN(data[6]);
  78. if (data[5] & 0x80) {
  79. tm->tm_year += 100;
  80. }
  81. tm->tm_wday = data[4] & 0x07;
  82. return 0;
  83. }
  84. /*!
  85. * \brief Set an PCF85XX hardware clock.
  86. *
  87. * New time will be taken over at the beginning of the next second.
  88. *
  89. * \param rtc Specifies the RTC device.
  90. * \param tm Points to a structure which contains the date and time
  91. * information.
  92. *
  93. * \return 0 on success or -1 in case of an error.
  94. */
  95. static int I2cPcfSetClock(NUTRTC *rtc, const struct _tm *tm)
  96. {
  97. uint8_t data[8];
  98. data[0] = 2;
  99. data[1] = BIN2BCD(tm->tm_sec);
  100. data[2] = BIN2BCD(tm->tm_min);
  101. data[3] = BIN2BCD(tm->tm_hour);
  102. data[4] = BIN2BCD(tm->tm_mday);
  103. data[5] = tm->tm_wday;
  104. data[6] = BIN2BCD(tm->tm_mon + 1);
  105. if (tm->tm_year > 99) {
  106. data[7] = BIN2BCD(tm->tm_year - 100);
  107. data[6] |= 0x80;
  108. }
  109. else {
  110. data[7] = BIN2BCD(tm->tm_year);
  111. }
  112. return NutI2cMasterTransceive(rtc->dcb, data, 8, NULL, 0);
  113. }
  114. /*!
  115. * \brief Get alarm date and time of an PCF85XX hardware clock.
  116. *
  117. * Not implemented.
  118. *
  119. * \param idx Zero based index. Two alarms are supported.
  120. * \param tm Points to a structure that receives the date and time
  121. * information.
  122. * \param aflgs Points to an unsigned long that receives the enable flags.
  123. *
  124. * \return 0 on success or -1 in case of an error.
  125. *
  126. */
  127. static int I2cPcfGetAlarm(NUTRTC *rtc, int idx, struct _tm *tm, int *aflgs)
  128. {
  129. return -1;
  130. }
  131. /*!
  132. * \brief Set alarm of an PCF85XX hardware clock.
  133. *
  134. * Not implemented.
  135. *
  136. * \param idx Zero based index. Two alarms are supported.
  137. * \param tm Points to a structure which contains the date and time
  138. * information. May be NULL to clear the alarm.
  139. * \param aflgs Each bit enables a specific comparison.
  140. * - Bit 0: Seconds
  141. * - Bit 1: Minutes
  142. * - Bit 2: Hours
  143. * - Bit 3: Day of month
  144. * - Bit 4: Month
  145. * - Bit 7: Day of week (Sunday is zero)
  146. *
  147. * \return 0 on success or -1 in case of an error.
  148. */
  149. static int I2cPcfSetAlarm(NUTRTC *rtc, int idx, const struct _tm *tm, int aflgs)
  150. {
  151. return -1;
  152. }
  153. /*!
  154. * \brief Query RTC status flags.
  155. *
  156. * \param rtc Specifies the RTC device.
  157. * \param sflgs Points to an unsigned long that receives the status flags.
  158. * - Bit 0: Power fail.
  159. * - Bit 5: Alarm 0 occured (not implemented).
  160. * - Bit 6: Alarm 1 occured (not implemented).
  161. *
  162. * \return 0 on success or -1 in case of an error.
  163. */
  164. static int I2cPcfGetStatus(NUTRTC *rtc, uint32_t *sflgs)
  165. {
  166. uint8_t data;
  167. data = 2;
  168. if (NutI2cMasterTransceive(rtc->dcb, &data, 1, &data, 1) != 1) {
  169. return -1;
  170. }
  171. if (data & 0x80) {
  172. rtc_status |= RTC_STATUS_PF;
  173. }
  174. *sflgs = rtc_status;
  175. return 0;
  176. }
  177. /*!
  178. * \brief Clear RTC status flags.
  179. *
  180. * \param rtc Specifies the RTC device.
  181. * \param sflgs Status flags to clear.
  182. *
  183. * \return Always 0.
  184. */
  185. static int I2cPcfClearStatus(NUTRTC *rtc, uint32_t sflgs)
  186. {
  187. rtc_status &= ~sflgs;
  188. return 0;
  189. }
  190. /*!
  191. * \brief Initialize the interface to a PCF85XX hardware clock.
  192. *
  193. * \return 0 on success or -1 in case of an error.
  194. */
  195. static int I2cPcfInit(NUTRTC *rtc)
  196. {
  197. uint32_t tmp;
  198. return I2cPcfGetStatus(rtc, &tmp);
  199. }
  200. /*!
  201. * \brief I2C driver control block.
  202. */
  203. static NUTI2C_SLAVE i2cPcf85xx = {
  204. NULL,
  205. I2C_SLA_RTC,
  206. 100,
  207. NULL
  208. };
  209. /*!
  210. * \brief PCF85XX RTC driver information structure.
  211. *
  212. * This driver has been tested with the PCF8563, but may also work
  213. * with PCF8564, PCF8565, PCF8583 and PCF8593 chips. It will not
  214. * work with PFC8523.
  215. *
  216. * Two steps are required to register this driver. First, we must
  217. * attach the I2C slave to an I2C bus by calling
  218. * /code
  219. * NutRegisterI2cSlave((NUTI2C_SLAVE *) rtcI2cPcf85xx.dcb, &i2cBus);
  220. * /endcode
  221. * In a second step the driver must be registered as the system's
  222. * real time clock by calling
  223. * /code
  224. * NutRegisterRtc(&rtcI2cPcf85xx);
  225. * /endcode
  226. */
  227. NUTRTC rtcI2cPcf85xx = {
  228. &i2cPcf85xx, /*!< Driver control block */
  229. I2cPcfInit, /*!< Hardware initialization, rtc_init */
  230. I2cPcfGetClock, /*!< Read date and time, rtc_gettime */
  231. I2cPcfSetClock, /*!< Set date and time, rtc_settime */
  232. I2cPcfGetAlarm, /*!< Read alarm date and time, rtc_getalarm */
  233. I2cPcfSetAlarm, /*!< Set alarm date and time, rtc_setalarm */
  234. I2cPcfGetStatus, /*!< Read status flags, rtc_getstatus */
  235. I2cPcfClearStatus, /*!< Clear status flags, rtc_clrstatus */
  236. NULL /*!< Handle for alarm event queue, not supported right now */
  237. };
  238. /*@}*/