ds1302.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /*
  2. * ds1302.c - Support for the Dallas Semiconductor DS1302 Timekeeping Chip
  3. *
  4. * Rex G. Feany <rfeany@zumanetworks.com>
  5. *
  6. */
  7. #include <common.h>
  8. #include <command.h>
  9. #include <rtc.h>
  10. /* GPP Pins */
  11. #define DATA 0x200
  12. #define SCLK 0x400
  13. #define RST 0x800
  14. /* Happy Fun Defines(tm) */
  15. #define RESET rtc_go_low(RST), rtc_go_low(SCLK)
  16. #define N_RESET rtc_go_high(RST), rtc_go_low(SCLK)
  17. #define CLOCK_HIGH rtc_go_high(SCLK)
  18. #define CLOCK_LOW rtc_go_low(SCLK)
  19. #define DATA_HIGH rtc_go_high(DATA)
  20. #define DATA_LOW rtc_go_low(DATA)
  21. #define DATA_READ (GTREGREAD(GPP_VALUE) & DATA)
  22. #undef RTC_DEBUG
  23. #ifdef RTC_DEBUG
  24. # define DPRINTF(x,args...) printf("ds1302: " x , ##args)
  25. static inline void DUMP(const char *ptr, int num)
  26. {
  27. while (num--) printf("%x ", *ptr++);
  28. printf("]\n");
  29. }
  30. #else
  31. # define DPRINTF(x,args...)
  32. # define DUMP(ptr, num)
  33. #endif
  34. /* time data format for DS1302 */
  35. struct ds1302_st
  36. {
  37. unsigned char CH:1; /* clock halt 1=stop 0=start */
  38. unsigned char sec10:3;
  39. unsigned char sec:4;
  40. unsigned char zero0:1;
  41. unsigned char min10:3;
  42. unsigned char min:4;
  43. unsigned char fmt:1; /* 1=12 hour 0=24 hour */
  44. unsigned char zero1:1;
  45. unsigned char hr10:2; /* 10 (0-2) or am/pm (am/pm, 0-1) */
  46. unsigned char hr:4;
  47. unsigned char zero2:2;
  48. unsigned char date10:2;
  49. unsigned char date:4;
  50. unsigned char zero3:3;
  51. unsigned char month10:1;
  52. unsigned char month:4;
  53. unsigned char zero4:5;
  54. unsigned char day:3; /* day of week */
  55. unsigned char year10:4;
  56. unsigned char year:4;
  57. unsigned char WP:1; /* write protect 1=protect 0=unprot */
  58. unsigned char zero5:7;
  59. };
  60. static int ds1302_initted=0;
  61. /* Pin control */
  62. static inline void
  63. rtc_go_high(unsigned int mask)
  64. {
  65. unsigned int f = GTREGREAD(GPP_VALUE) | mask;
  66. GT_REG_WRITE(GPP_VALUE, f);
  67. }
  68. static inline void
  69. rtc_go_low(unsigned int mask)
  70. {
  71. unsigned int f = GTREGREAD(GPP_VALUE) & ~mask;
  72. GT_REG_WRITE(GPP_VALUE, f);
  73. }
  74. static inline void
  75. rtc_go_input(unsigned int mask)
  76. {
  77. unsigned int f = GTREGREAD(GPP_IO_CONTROL) & ~mask;
  78. GT_REG_WRITE(GPP_IO_CONTROL, f);
  79. }
  80. static inline void
  81. rtc_go_output(unsigned int mask)
  82. {
  83. unsigned int f = GTREGREAD(GPP_IO_CONTROL) | mask;
  84. GT_REG_WRITE(GPP_IO_CONTROL, f);
  85. }
  86. /* Access data in RTC */
  87. static void
  88. write_byte(unsigned char b)
  89. {
  90. int i;
  91. unsigned char mask=1;
  92. for(i=0;i<8;i++) {
  93. CLOCK_LOW; /* Lower clock */
  94. (b&mask)?DATA_HIGH:DATA_LOW; /* set data */
  95. udelay(1);
  96. CLOCK_HIGH; /* latch data with rising clock */
  97. udelay(1);
  98. mask=mask<<1;
  99. }
  100. }
  101. static unsigned char
  102. read_byte(void)
  103. {
  104. int i;
  105. unsigned char mask=1;
  106. unsigned char b=0;
  107. for(i=0;i<8;i++) {
  108. CLOCK_LOW;
  109. udelay(1);
  110. if (DATA_READ) b|=mask; /* if this bit is high, set in b */
  111. CLOCK_HIGH; /* clock out next bit */
  112. udelay(1);
  113. mask=mask<<1;
  114. }
  115. return b;
  116. }
  117. static void
  118. read_ser_drv(unsigned char addr, unsigned char *buf, int count)
  119. {
  120. int i;
  121. #ifdef RTC_DEBUG
  122. char *foo = buf;
  123. #endif
  124. DPRINTF("READ 0x%x bytes @ 0x%x [ ", count, addr);
  125. addr|=1; /* READ */
  126. N_RESET;
  127. udelay(4);
  128. write_byte(addr);
  129. rtc_go_input(DATA); /* Put gpp pin into input mode */
  130. udelay(1);
  131. for(i=0;i<count;i++) *(buf++)=read_byte();
  132. RESET;
  133. rtc_go_output(DATA);/* Reset gpp for output */
  134. udelay(4);
  135. DUMP(foo, count);
  136. }
  137. static void
  138. write_ser_drv(unsigned char addr, unsigned char *buf, int count)
  139. {
  140. int i;
  141. DPRINTF("WRITE 0x%x bytes @ 0x%x [ ", count, addr);
  142. DUMP(buf, count);
  143. addr&=~1; /* WRITE */
  144. N_RESET;
  145. udelay(4);
  146. write_byte(addr);
  147. for(i=0;i<count;i++) write_byte(*(buf++));
  148. RESET;
  149. udelay(4);
  150. }
  151. void
  152. rtc_init(void)
  153. {
  154. struct ds1302_st bbclk;
  155. unsigned char b;
  156. int mod;
  157. DPRINTF("init\n");
  158. rtc_go_output(DATA|SCLK|RST);
  159. /* disable write protect */
  160. b = 0;
  161. write_ser_drv(0x8e,&b,1);
  162. /* enable trickle */
  163. b = 0xa5; /* 1010.0101 */
  164. write_ser_drv(0x90,&b,1);
  165. /* read burst */
  166. read_ser_drv(0xbe, (unsigned char *)&bbclk, 8);
  167. /* Sanity checks */
  168. mod = 0;
  169. if (bbclk.CH) {
  170. printf("ds1302: Clock was halted, starting clock\n");
  171. bbclk.CH=0;
  172. mod=1;
  173. }
  174. if (bbclk.fmt) {
  175. printf("ds1302: Clock was in 12 hour mode, fixing\n");
  176. bbclk.fmt=0;
  177. mod=1;
  178. }
  179. if (bbclk.year>9) {
  180. printf("ds1302: Year was corrupted, fixing\n");
  181. bbclk.year10=100/10; /* 2000 - why not? ;) */
  182. bbclk.year=0;
  183. mod=1;
  184. }
  185. /* Write out the changes if needed */
  186. if (mod) {
  187. /* enable write protect */
  188. bbclk.WP = 1;
  189. write_ser_drv(0xbe,(unsigned char *)&bbclk,8);
  190. } else {
  191. /* Else just turn write protect on */
  192. b = 0x80;
  193. write_ser_drv(0x8e,&b,1);
  194. }
  195. DPRINTF("init done\n");
  196. ds1302_initted=1;
  197. }
  198. void
  199. rtc_reset(void)
  200. {
  201. if(!ds1302_initted) rtc_init();
  202. /* TODO */
  203. }
  204. int
  205. rtc_get(struct rtc_time *tmp)
  206. {
  207. int rel = 0;
  208. struct ds1302_st bbclk;
  209. if(!ds1302_initted) rtc_init();
  210. read_ser_drv(0xbe,(unsigned char *)&bbclk, 8); /* read burst */
  211. if (bbclk.CH) {
  212. printf("ds1302: rtc_get: Clock was halted, clock probably "
  213. "corrupt\n");
  214. rel = -1;
  215. }
  216. tmp->tm_sec=10*bbclk.sec10+bbclk.sec;
  217. tmp->tm_min=10*bbclk.min10+bbclk.min;
  218. tmp->tm_hour=10*bbclk.hr10+bbclk.hr;
  219. tmp->tm_wday=bbclk.day;
  220. tmp->tm_mday=10*bbclk.date10+bbclk.date;
  221. tmp->tm_mon=10*bbclk.month10+bbclk.month;
  222. tmp->tm_year=10*bbclk.year10+bbclk.year + 1900;
  223. tmp->tm_yday = 0;
  224. tmp->tm_isdst= 0;
  225. DPRINTF("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
  226. tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
  227. tmp->tm_hour, tmp->tm_min, tmp->tm_sec );
  228. return rel;
  229. }
  230. int rtc_set(struct rtc_time *tmp)
  231. {
  232. struct ds1302_st bbclk;
  233. unsigned char b=0;
  234. if(!ds1302_initted) rtc_init();
  235. DPRINTF("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
  236. tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
  237. tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
  238. memset(&bbclk,0,sizeof(bbclk));
  239. bbclk.CH=0; /* dont halt */
  240. bbclk.WP=1; /* write protect when we're done */
  241. bbclk.sec10=tmp->tm_sec/10;
  242. bbclk.sec=tmp->tm_sec%10;
  243. bbclk.min10=tmp->tm_min/10;
  244. bbclk.min=tmp->tm_min%10;
  245. bbclk.hr10=tmp->tm_hour/10;
  246. bbclk.hr=tmp->tm_hour%10;
  247. bbclk.day=tmp->tm_wday;
  248. bbclk.date10=tmp->tm_mday/10;
  249. bbclk.date=tmp->tm_mday%10;
  250. bbclk.month10=tmp->tm_mon/10;
  251. bbclk.month=tmp->tm_mon%10;
  252. tmp->tm_year -= 1900;
  253. bbclk.year10=tmp->tm_year/10;
  254. bbclk.year=tmp->tm_year%10;
  255. write_ser_drv(0x8e,&b,1); /* disable write protect */
  256. write_ser_drv(0xbe,(unsigned char *)&bbclk, 8); /* write burst */
  257. return 0;
  258. }