ds1302.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:12k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*!***************************************************************************
  2. *!
  3. *! FILE NAME  : ds1302.c
  4. *!
  5. *! DESCRIPTION: Implements an interface for the DS1302 RTC through Etrax I/O
  6. *!
  7. *! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status
  8. *!
  9. *! $Log: ds1302.c,v $
  10. *! Revision 1.11  2001/06/14 12:35:52  jonashg
  11. *! The ATA hack is back. It is unfortunately the only way to set g27 to output.
  12. *!
  13. *! Revision 1.9  2001/06/14 10:00:14  jonashg
  14. *! No need for tempudelay to be inline anymore (had to adjust the usec to
  15. *! loops conversion because of this to make it slow enough to be a udelay).
  16. *!
  17. *! Revision 1.8  2001/06/14 08:06:32  jonashg
  18. *! Made tempudelay delay usecs (well, just a tad more).
  19. *!
  20. *! Revision 1.7  2001/06/13 14:18:11  jonashg
  21. *! Only allow processes with SYS_TIME capability to set time and charge.
  22. *!
  23. *! Revision 1.6  2001/06/12 15:22:07  jonashg
  24. *! * Made init function __init.
  25. *! * Parameter to out_byte() is unsigned char.
  26. *! * The magic number 42 has got a name.
  27. *! * Removed comment about /proc (nothing is exported there).
  28. *!
  29. *! Revision 1.5  2001/06/12 14:35:13  jonashg
  30. *! Gave the module a name and added it to printk's.
  31. *!
  32. *! Revision 1.4  2001/05/31 14:53:40  jonashg
  33. *! Made tempudelay() inline so that the watchdog doesn't reset (see
  34. *! function comment).
  35. *!
  36. *! Revision 1.3  2001/03/26 16:03:06  bjornw
  37. *! Needs linux/config.h
  38. *!
  39. *! Revision 1.2  2001/03/20 19:42:00  bjornw
  40. *! Use the ETRAX prefix on the DS1302 options
  41. *!
  42. *! Revision 1.1  2001/03/20 09:13:50  magnusmn
  43. *! Linux 2.4 port
  44. *!
  45. *! Revision 1.10  2000/07/05 15:38:23  bjornw
  46. *! Dont update kernel time when a RTC_SET_TIME is done
  47. *!
  48. *! Revision 1.9  2000/03/02 15:42:59  macce
  49. *! * Hack to make RTC work on all 2100/2400
  50. *!
  51. *! Revision 1.8  2000/02/23 16:59:18  torbjore
  52. *! added setup of R_GEN_CONFIG when RTC is connected to the generic port.
  53. *!
  54. *! Revision 1.7  2000/01/17 15:51:43  johana
  55. *! Added RTC_SET_CHARGE ioctl to enable trickle charger.
  56. *!
  57. *! Revision 1.6  1999/10/27 13:19:47  bjornw
  58. *! Added update_xtime_from_cmos which reads back the updated RTC into the kernel.
  59. *! /dev/rtc calls it now.
  60. *!
  61. *! Revision 1.5  1999/10/27 12:39:37  bjornw
  62. *! Disabled superuser check. Anyone can now set the time.
  63. *!
  64. *! Revision 1.4  1999/09/02 13:27:46  pkj
  65. *! Added shadow for R_PORT_PB_CONFIG.
  66. *! Renamed port_g_shadow to port_g_data_shadow.
  67. *!
  68. *! Revision 1.3  1999/09/02 08:28:06  pkj
  69. *! Made it possible to select either port PB or the generic port for the RST
  70. *! signal line to the DS1302 RTC.
  71. *! Also make sure the RST bit is configured as output on Port PB (if used).
  72. *!
  73. *! Revision 1.2  1999/09/01 14:47:20  bjornw
  74. *! Added support for /dev/rtc operations with ioctl RD_TIME and SET_TIME to read
  75. *! and set the date. Register as major 121.
  76. *!
  77. *! Revision 1.1  1999/09/01 09:45:29  bjornw
  78. *! Implemented a DS1302 RTC driver.
  79. *!
  80. *!
  81. *! ---------------------------------------------------------------------------
  82. *!
  83. *! (C) Copyright 1999, 2000, 2001  Axis Communications AB, LUND, SWEDEN
  84. *!
  85. *! $Id: ds1302.c,v 1.11 2001/06/14 12:35:52 jonashg Exp $
  86. *!
  87. *!***************************************************************************/
  88. #include <linux/config.h>
  89. #include <linux/fs.h>
  90. #include <linux/init.h>
  91. #include <linux/mm.h>
  92. #include <linux/module.h>
  93. #include <linux/miscdevice.h>
  94. #include <linux/delay.h>
  95. #include <asm/uaccess.h>
  96. #include <asm/system.h>
  97. #include <asm/svinto.h>
  98. #include <asm/io.h>
  99. #include <asm/rtc.h>
  100. #define RTC_MAJOR_NR 121 /* local major, change later */
  101. static const char ds1302_name[] = "ds1302";
  102. /* The DS1302 might be connected to different bits on different products. 
  103.  * It has three signals - SDA, SCL and RST. RST and SCL are always outputs,
  104.  * but SDA can have a selected direction.
  105.  * For now, only PORT_PB is hardcoded.
  106.  */
  107. /* The RST bit may be on either the Generic Port or Port PB. */
  108. #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
  109. #define TK_RST_OUT(x) REG_SHADOW_SET(R_PORT_G_DATA,  port_g_data_shadow,  CONFIG_ETRAX_DS1302_RSTBIT, x)
  110. #define TK_RST_DIR(x)
  111. #else
  112. #define TK_RST_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x)
  113. #define TK_RST_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR,  port_pb_dir_shadow,  CONFIG_ETRAX_DS1302_RSTBIT, x)
  114. #endif
  115. #define TK_SDA_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_SDABIT, x)
  116. #define TK_SCL_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_SCLBIT, x)
  117. #define TK_SDA_IN()   ((*R_PORT_PB_READ >> CONFIG_ETRAX_DS1302_SDABIT) & 1)
  118. /* 1 is out, 0 is in */
  119. #define TK_SDA_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR,  port_pb_dir_shadow,  CONFIG_ETRAX_DS1302_SDABIT, x)
  120. #define TK_SCL_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR,  port_pb_dir_shadow,  CONFIG_ETRAX_DS1302_SCLBIT, x)
  121. /*
  122.  * The reason for tempudelay and not udelay is that loops_per_usec
  123.  * (used in udelay) is not set when functions here are called from time.c 
  124.  */
  125. static void tempudelay(int usecs) 
  126. {
  127. volatile int loops;
  128. for(loops = usecs * 12; loops > 0; loops--)
  129. /* nothing */;
  130. }
  131. /* Send 8 bits. */
  132. static void
  133. out_byte(unsigned char x) 
  134. {
  135. int i;
  136. TK_SDA_DIR(1);
  137. for (i = 8; i--;) {
  138. /* The chip latches incoming bits on the rising edge of SCL. */
  139. TK_SCL_OUT(0);
  140. TK_SDA_OUT(x & 1);
  141. tempudelay(1);
  142. TK_SCL_OUT(1);
  143. tempudelay(1);
  144. x >>= 1;
  145. }
  146. TK_SDA_DIR(0);
  147. }
  148. static unsigned char
  149. in_byte(void) 
  150. {
  151. unsigned char x = 0;
  152. int i;
  153. /* Read byte. Bits come LSB first, on the falling edge of SCL.
  154.  * Assume SDA is in input direction already.
  155.  */
  156. TK_SDA_DIR(0);
  157. for (i = 8; i--;) {
  158. TK_SCL_OUT(0);
  159. tempudelay(1);
  160. x >>= 1;
  161. x |= (TK_SDA_IN() << 7);
  162. TK_SCL_OUT(1);
  163. tempudelay(1);
  164. }
  165. return x;
  166. }
  167. /* Prepares for a transaction by de-activating RST (active-low). */
  168. static void
  169. start(void) 
  170. {
  171. TK_SCL_OUT(0);
  172. tempudelay(1);
  173. TK_RST_OUT(0);
  174. tempudelay(5);
  175. TK_RST_OUT(1);
  176. }
  177. /* Ends a transaction by taking RST active again. */
  178. static void
  179. stop(void) 
  180. {
  181. tempudelay(2);
  182. TK_RST_OUT(0);
  183. }
  184. /* Enable writing. */
  185. static void
  186. ds1302_wenable(void) 
  187. {
  188. start(); 
  189. out_byte(0x8e); /* Write control register  */
  190. out_byte(0x00); /* Disable write protect bit 7 = 0 */
  191. stop();
  192. }
  193. /* Disable writing. */
  194. static void
  195. ds1302_wdisable(void) 
  196. {
  197. start();
  198. out_byte(0x8e); /* Write control register  */
  199. out_byte(0x80); /* Disable write protect bit 7 = 0 */
  200. stop();
  201. }
  202. /* Probe for the chip by writing something to its RAM and try reading it back. */
  203. #define MAGIC_PATTERN 0x42
  204. static int
  205. ds1302_probe(void) 
  206. {
  207. int retval, res; 
  208. TK_RST_DIR(1);
  209. TK_SCL_DIR(1);
  210. TK_SDA_DIR(0);
  211. /* Try to talk to timekeeper. */
  212. ds1302_wenable();  
  213. start();
  214. out_byte(0xc0); /* write RAM byte 0 */
  215. out_byte(MAGIC_PATTERN); /* write something magic */
  216. start();
  217. out_byte(0xc1); /* read RAM byte 0 */
  218. if((res = in_byte()) == MAGIC_PATTERN) {
  219. char buf[100];
  220. stop();
  221. ds1302_wdisable();
  222. printk("%s: RTC found.n", ds1302_name);
  223. printk("%s: SDA, SCL, RST on PB%i, PB%i, %s%in",
  224.        ds1302_name,
  225.        CONFIG_ETRAX_DS1302_SDABIT,
  226.        CONFIG_ETRAX_DS1302_SCLBIT,
  227. #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
  228.        "GENIO",
  229. #else
  230.        "PB",
  231. #endif
  232.        CONFIG_ETRAX_DS1302_RSTBIT);
  233.                 get_rtc_status(buf);
  234.                 printk(buf);
  235. retval = 1;
  236. } else {
  237. stop();
  238. printk("%s: RTC not found.n", ds1302_name);
  239. retval = 0;
  240. }
  241. return retval;
  242. }
  243. /* Read a byte from the selected register in the DS1302. */
  244. unsigned char
  245. ds1302_readreg(int reg) 
  246. {
  247. unsigned char x;
  248. start();
  249. out_byte(0x81 | (reg << 1)); /* read register */
  250. x = in_byte();
  251. stop();
  252. return x;
  253. }
  254. /* Write a byte to the selected register. */
  255. void
  256. ds1302_writereg(int reg, unsigned char val) 
  257. {
  258. ds1302_wenable();
  259. start();
  260. out_byte(0x80 | (reg << 1)); /* write register */
  261. out_byte(val);
  262. stop();
  263. ds1302_wdisable();
  264. }
  265. void
  266. get_rtc_time(struct rtc_time *rtc_tm) 
  267. {
  268. unsigned long flags;
  269. save_flags(flags);
  270. cli();
  271. rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
  272. rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
  273. rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
  274. rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
  275. rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
  276. rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
  277. restore_flags(flags);
  278. BCD_TO_BIN(rtc_tm->tm_sec);
  279. BCD_TO_BIN(rtc_tm->tm_min);
  280. BCD_TO_BIN(rtc_tm->tm_hour);
  281. BCD_TO_BIN(rtc_tm->tm_mday);
  282. BCD_TO_BIN(rtc_tm->tm_mon);
  283. BCD_TO_BIN(rtc_tm->tm_year);
  284. /*
  285.  * Account for differences between how the RTC uses the values
  286.  * and how they are defined in a struct rtc_time;
  287.  */
  288. if (rtc_tm->tm_year <= 69)
  289. rtc_tm->tm_year += 100;
  290. rtc_tm->tm_mon--;
  291. }
  292. static unsigned char days_in_mo[] = 
  293.     {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  294. /* ioctl that supports RTC_RD_TIME and RTC_SET_TIME (read and set time/date). */
  295. static int
  296. rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
  297.   unsigned long arg) 
  298. {
  299.         unsigned long flags;
  300. switch(cmd) {
  301. case RTC_RD_TIME: /* read the time/date from RTC */
  302. {
  303. struct rtc_time rtc_tm;
  304. get_rtc_time(&rtc_tm);
  305. if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time)))
  306. return -EFAULT;
  307. return 0;
  308. }
  309. case RTC_SET_TIME: /* set the RTC */
  310. {
  311. struct rtc_time rtc_tm;
  312. unsigned char mon, day, hrs, min, sec, leap_yr;
  313. unsigned char save_control, save_freq_select;
  314. unsigned int yrs;
  315. if (!capable(CAP_SYS_TIME))
  316. return -EPERM;
  317. if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)))
  318. return -EFAULT;    
  319. yrs = rtc_tm.tm_year + 1900;
  320. mon = rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
  321. day = rtc_tm.tm_mday;
  322. hrs = rtc_tm.tm_hour;
  323. min = rtc_tm.tm_min;
  324. sec = rtc_tm.tm_sec;
  325. if ((yrs < 1970) || (yrs > 2069))
  326. return -EINVAL;
  327. leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
  328. if ((mon > 12) || (day == 0))
  329. return -EINVAL;
  330. if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
  331. return -EINVAL;
  332. if ((hrs >= 24) || (min >= 60) || (sec >= 60))
  333. return -EINVAL;
  334. if (yrs >= 2000)
  335. yrs -= 2000; /* RTC (0, 1, ... 69) */
  336. else
  337. yrs -= 1900; /* RTC (70, 71, ... 99) */
  338. BIN_TO_BCD(sec);
  339. BIN_TO_BCD(min);
  340. BIN_TO_BCD(hrs);
  341. BIN_TO_BCD(day);
  342. BIN_TO_BCD(mon);
  343. BIN_TO_BCD(yrs);
  344. save_flags(flags);
  345. cli();
  346. CMOS_WRITE(yrs, RTC_YEAR);
  347. CMOS_WRITE(mon, RTC_MONTH);
  348. CMOS_WRITE(day, RTC_DAY_OF_MONTH);
  349. CMOS_WRITE(hrs, RTC_HOURS);
  350. CMOS_WRITE(min, RTC_MINUTES);
  351. CMOS_WRITE(sec, RTC_SECONDS);
  352. restore_flags(flags);
  353. /* Notice that at this point, the RTC is updated but
  354.  * the kernel is still running with the old time.
  355.  * You need to set that separately with settimeofday
  356.  * or adjtimex.
  357.  */
  358. return 0;
  359. }
  360. case RTC_SET_CHARGE: /* set the RTC TRICKLE CHARGE register */
  361. {
  362. int tcs_val;                        
  363. unsigned char save_control, save_freq_select;
  364. if (!capable(CAP_SYS_TIME))
  365. return -EPERM;
  366. if(copy_from_user(&tcs_val, (int*)arg, sizeof(int)))
  367. return -EFAULT;
  368. tcs_val = RTC_TCR_PATTERN | (tcs_val & 0x0F);
  369. ds1302_writereg(RTC_TRICKLECHARGER, tcs_val);
  370. return 0;
  371. }                
  372. default:
  373. return -ENOIOCTLCMD;
  374. }
  375. }
  376. int
  377. get_rtc_status(char *buf) 
  378. {
  379. char *p;
  380. struct rtc_time tm;
  381. p = buf;
  382. get_rtc_time(&tm);
  383. /*
  384.  * There is no way to tell if the luser has the RTC set for local
  385.  * time or for Universal Standard Time (GMT). Probably local though.
  386.  */
  387. p += sprintf(p,
  388. "rtc_timet: %02d:%02d:%02dn"
  389. "rtc_datet: %04d-%02d-%02dn",
  390. tm.tm_hour, tm.tm_min, tm.tm_sec,
  391. tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
  392. return  p - buf;
  393. }
  394. /* The various file operations we support. */
  395. static struct file_operations rtc_fops = {
  396.         owner:          THIS_MODULE,
  397.         ioctl:          rtc_ioctl,
  398. }; 
  399. /* Just probe for the RTC and register the device to handle the ioctl needed. */
  400. int __init
  401. ds1302_init(void) 
  402. if (!ds1302_probe()) {
  403. #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
  404. /*
  405.  * The only way to set g27 to output is to enable ATA.
  406.  *
  407.  * Make sure that R_GEN_CONFIG is setup correct.
  408.  */
  409.      genconfig_shadow = ((genconfig_shadow &
  410.      ~IO_MASK(R_GEN_CONFIG, ata))
  411.    | 
  412.    (IO_STATE(R_GEN_CONFIG, ata, select)));    
  413.      *R_GEN_CONFIG = genconfig_shadow;
  414.      if (!ds1302_probe())
  415.        return -1;
  416. #else
  417.      return -1;
  418. #endif
  419.    }
  420.   
  421. if (register_chrdev(RTC_MAJOR_NR, ds1302_name, &rtc_fops)) {
  422. printk(KERN_INFO "%s: unable to get major %d for rtcn", 
  423.        ds1302_name, RTC_MAJOR_NR);
  424. return -1;
  425. }
  426. return 0;
  427. }