ds1302.c 6.2 KB

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