rtc-nuc900.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. /*
  2. * Copyright (c) 2008-2009 Nuvoton technology corporation.
  3. *
  4. * Wan ZongShun <mcuos.com@gmail.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation;version 2 of the License.
  9. *
  10. */
  11. #include <linux/module.h>
  12. #include <linux/init.h>
  13. #include <linux/platform_device.h>
  14. #include <linux/slab.h>
  15. #include <linux/rtc.h>
  16. #include <linux/delay.h>
  17. #include <linux/io.h>
  18. #include <linux/bcd.h>
  19. /* RTC Control Registers */
  20. #define REG_RTC_INIR 0x00
  21. #define REG_RTC_AER 0x04
  22. #define REG_RTC_FCR 0x08
  23. #define REG_RTC_TLR 0x0C
  24. #define REG_RTC_CLR 0x10
  25. #define REG_RTC_TSSR 0x14
  26. #define REG_RTC_DWR 0x18
  27. #define REG_RTC_TAR 0x1C
  28. #define REG_RTC_CAR 0x20
  29. #define REG_RTC_LIR 0x24
  30. #define REG_RTC_RIER 0x28
  31. #define REG_RTC_RIIR 0x2C
  32. #define REG_RTC_TTR 0x30
  33. #define RTCSET 0x01
  34. #define AERRWENB 0x10000
  35. #define INIRRESET 0xa5eb1357
  36. #define AERPOWERON 0xA965
  37. #define AERPOWEROFF 0x0000
  38. #define LEAPYEAR 0x0001
  39. #define TICKENB 0x80
  40. #define TICKINTENB 0x0002
  41. #define ALARMINTENB 0x0001
  42. #define MODE24 0x0001
  43. struct nuc900_rtc {
  44. int irq_num;
  45. void __iomem *rtc_reg;
  46. struct rtc_device *rtcdev;
  47. };
  48. struct nuc900_bcd_time {
  49. int bcd_sec;
  50. int bcd_min;
  51. int bcd_hour;
  52. int bcd_mday;
  53. int bcd_mon;
  54. int bcd_year;
  55. };
  56. static irqreturn_t nuc900_rtc_interrupt(int irq, void *_rtc)
  57. {
  58. struct nuc900_rtc *rtc = _rtc;
  59. unsigned long events = 0, rtc_irq;
  60. rtc_irq = __raw_readl(rtc->rtc_reg + REG_RTC_RIIR);
  61. if (rtc_irq & ALARMINTENB) {
  62. rtc_irq &= ~ALARMINTENB;
  63. __raw_writel(rtc_irq, rtc->rtc_reg + REG_RTC_RIIR);
  64. events |= RTC_AF | RTC_IRQF;
  65. }
  66. if (rtc_irq & TICKINTENB) {
  67. rtc_irq &= ~TICKINTENB;
  68. __raw_writel(rtc_irq, rtc->rtc_reg + REG_RTC_RIIR);
  69. events |= RTC_UF | RTC_IRQF;
  70. }
  71. rtc_update_irq(rtc->rtcdev, 1, events);
  72. return IRQ_HANDLED;
  73. }
  74. static int *check_rtc_access_enable(struct nuc900_rtc *nuc900_rtc)
  75. {
  76. unsigned int i;
  77. __raw_writel(INIRRESET, nuc900_rtc->rtc_reg + REG_RTC_INIR);
  78. mdelay(10);
  79. __raw_writel(AERPOWERON, nuc900_rtc->rtc_reg + REG_RTC_AER);
  80. for (i = 0; i < 1000; i++) {
  81. if (__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_AER) & AERRWENB)
  82. return 0;
  83. }
  84. if ((__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_AER) & AERRWENB) == 0x0)
  85. return ERR_PTR(-ENODEV);
  86. return ERR_PTR(-EPERM);
  87. }
  88. static void nuc900_rtc_bcd2bin(unsigned int timereg,
  89. unsigned int calreg, struct rtc_time *tm)
  90. {
  91. tm->tm_mday = bcd2bin(calreg >> 0);
  92. tm->tm_mon = bcd2bin(calreg >> 8);
  93. tm->tm_year = bcd2bin(calreg >> 16) + 100;
  94. tm->tm_sec = bcd2bin(timereg >> 0);
  95. tm->tm_min = bcd2bin(timereg >> 8);
  96. tm->tm_hour = bcd2bin(timereg >> 16);
  97. rtc_valid_tm(tm);
  98. }
  99. static void nuc900_rtc_bin2bcd(struct rtc_time *settm,
  100. struct nuc900_bcd_time *gettm)
  101. {
  102. gettm->bcd_mday = bin2bcd(settm->tm_mday) << 0;
  103. gettm->bcd_mon = bin2bcd(settm->tm_mon) << 8;
  104. gettm->bcd_year = bin2bcd(settm->tm_year - 100) << 16;
  105. gettm->bcd_sec = bin2bcd(settm->tm_sec) << 0;
  106. gettm->bcd_min = bin2bcd(settm->tm_min) << 8;
  107. gettm->bcd_hour = bin2bcd(settm->tm_hour) << 16;
  108. }
  109. static int nuc900_update_irq_enable(struct device *dev, unsigned int enabled)
  110. {
  111. struct nuc900_rtc *rtc = dev_get_drvdata(dev);
  112. if (enabled)
  113. __raw_writel(__raw_readl(rtc->rtc_reg + REG_RTC_RIER)|
  114. (TICKINTENB), rtc->rtc_reg + REG_RTC_RIER);
  115. else
  116. __raw_writel(__raw_readl(rtc->rtc_reg + REG_RTC_RIER)&
  117. (~TICKINTENB), rtc->rtc_reg + REG_RTC_RIER);
  118. return 0;
  119. }
  120. static int nuc900_alarm_irq_enable(struct device *dev, unsigned int enabled)
  121. {
  122. struct nuc900_rtc *rtc = dev_get_drvdata(dev);
  123. if (enabled)
  124. __raw_writel(__raw_readl(rtc->rtc_reg + REG_RTC_RIER)|
  125. (ALARMINTENB), rtc->rtc_reg + REG_RTC_RIER);
  126. else
  127. __raw_writel(__raw_readl(rtc->rtc_reg + REG_RTC_RIER)&
  128. (~ALARMINTENB), rtc->rtc_reg + REG_RTC_RIER);
  129. return 0;
  130. }
  131. static int nuc900_rtc_read_time(struct device *dev, struct rtc_time *tm)
  132. {
  133. struct nuc900_rtc *rtc = dev_get_drvdata(dev);
  134. unsigned int timeval, clrval;
  135. timeval = __raw_readl(rtc->rtc_reg + REG_RTC_TLR);
  136. clrval = __raw_readl(rtc->rtc_reg + REG_RTC_CLR);
  137. nuc900_rtc_bcd2bin(timeval, clrval, tm);
  138. return 0;
  139. }
  140. static int nuc900_rtc_set_time(struct device *dev, struct rtc_time *tm)
  141. {
  142. struct nuc900_rtc *rtc = dev_get_drvdata(dev);
  143. struct nuc900_bcd_time gettm;
  144. unsigned long val;
  145. int *err;
  146. nuc900_rtc_bin2bcd(tm, &gettm);
  147. err = check_rtc_access_enable(rtc);
  148. if (IS_ERR(err))
  149. return PTR_ERR(err);
  150. val = gettm.bcd_mday | gettm.bcd_mon | gettm.bcd_year;
  151. __raw_writel(val, rtc->rtc_reg + REG_RTC_CLR);
  152. val = gettm.bcd_sec | gettm.bcd_min | gettm.bcd_hour;
  153. __raw_writel(val, rtc->rtc_reg + REG_RTC_TLR);
  154. return 0;
  155. }
  156. static int nuc900_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
  157. {
  158. struct nuc900_rtc *rtc = dev_get_drvdata(dev);
  159. unsigned int timeval, carval;
  160. timeval = __raw_readl(rtc->rtc_reg + REG_RTC_TAR);
  161. carval = __raw_readl(rtc->rtc_reg + REG_RTC_CAR);
  162. nuc900_rtc_bcd2bin(timeval, carval, &alrm->time);
  163. return 0;
  164. }
  165. static int nuc900_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
  166. {
  167. struct nuc900_rtc *rtc = dev_get_drvdata(dev);
  168. struct nuc900_bcd_time tm;
  169. unsigned long val;
  170. int *err;
  171. nuc900_rtc_bin2bcd(&alrm->time, &tm);
  172. err = check_rtc_access_enable(rtc);
  173. if (IS_ERR(err))
  174. return PTR_ERR(err);
  175. val = tm.bcd_mday | tm.bcd_mon | tm.bcd_year;
  176. __raw_writel(val, rtc->rtc_reg + REG_RTC_CAR);
  177. val = tm.bcd_sec | tm.bcd_min | tm.bcd_hour;
  178. __raw_writel(val, rtc->rtc_reg + REG_RTC_TAR);
  179. return 0;
  180. }
  181. static struct rtc_class_ops nuc900_rtc_ops = {
  182. .read_time = nuc900_rtc_read_time,
  183. .set_time = nuc900_rtc_set_time,
  184. .read_alarm = nuc900_rtc_read_alarm,
  185. .set_alarm = nuc900_rtc_set_alarm,
  186. .alarm_irq_enable = nuc900_alarm_irq_enable,
  187. .update_irq_enable = nuc900_update_irq_enable,
  188. };
  189. static int __devinit nuc900_rtc_probe(struct platform_device *pdev)
  190. {
  191. struct resource *res;
  192. struct nuc900_rtc *nuc900_rtc;
  193. int err = 0;
  194. nuc900_rtc = kzalloc(sizeof(struct nuc900_rtc), GFP_KERNEL);
  195. if (!nuc900_rtc) {
  196. dev_err(&pdev->dev, "kzalloc nuc900_rtc failed\n");
  197. return -ENOMEM;
  198. }
  199. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  200. if (!res) {
  201. dev_err(&pdev->dev, "platform_get_resource failed\n");
  202. err = -ENXIO;
  203. goto fail1;
  204. }
  205. if (!request_mem_region(res->start, resource_size(res),
  206. pdev->name)) {
  207. dev_err(&pdev->dev, "request_mem_region failed\n");
  208. err = -EBUSY;
  209. goto fail1;
  210. }
  211. nuc900_rtc->rtc_reg = ioremap(res->start, resource_size(res));
  212. if (!nuc900_rtc->rtc_reg) {
  213. dev_err(&pdev->dev, "ioremap rtc_reg failed\n");
  214. err = -ENOMEM;
  215. goto fail2;
  216. }
  217. nuc900_rtc->irq_num = platform_get_irq(pdev, 0);
  218. if (request_irq(nuc900_rtc->irq_num, nuc900_rtc_interrupt,
  219. IRQF_DISABLED, "nuc900rtc", nuc900_rtc)) {
  220. dev_err(&pdev->dev, "NUC900 RTC request irq failed\n");
  221. err = -EBUSY;
  222. goto fail3;
  223. }
  224. nuc900_rtc->rtcdev = rtc_device_register(pdev->name, &pdev->dev,
  225. &nuc900_rtc_ops, THIS_MODULE);
  226. if (IS_ERR(nuc900_rtc->rtcdev)) {
  227. dev_err(&pdev->dev, "rtc device register faild\n");
  228. err = PTR_ERR(nuc900_rtc->rtcdev);
  229. goto fail4;
  230. }
  231. platform_set_drvdata(pdev, nuc900_rtc);
  232. __raw_writel(__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_TSSR) | MODE24,
  233. nuc900_rtc->rtc_reg + REG_RTC_TSSR);
  234. return 0;
  235. fail4: free_irq(nuc900_rtc->irq_num, nuc900_rtc);
  236. fail3: iounmap(nuc900_rtc->rtc_reg);
  237. fail2: release_mem_region(res->start, resource_size(res));
  238. fail1: kfree(nuc900_rtc);
  239. return err;
  240. }
  241. static int __devexit nuc900_rtc_remove(struct platform_device *pdev)
  242. {
  243. struct nuc900_rtc *nuc900_rtc = platform_get_drvdata(pdev);
  244. struct resource *res;
  245. rtc_device_unregister(nuc900_rtc->rtcdev);
  246. free_irq(nuc900_rtc->irq_num, nuc900_rtc);
  247. iounmap(nuc900_rtc->rtc_reg);
  248. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  249. release_mem_region(res->start, resource_size(res));
  250. kfree(nuc900_rtc);
  251. platform_set_drvdata(pdev, NULL);
  252. return 0;
  253. }
  254. static struct platform_driver nuc900_rtc_driver = {
  255. .remove = __devexit_p(nuc900_rtc_remove),
  256. .driver = {
  257. .name = "nuc900-rtc",
  258. .owner = THIS_MODULE,
  259. },
  260. };
  261. static int __init nuc900_rtc_init(void)
  262. {
  263. return platform_driver_probe(&nuc900_rtc_driver, nuc900_rtc_probe);
  264. }
  265. static void __exit nuc900_rtc_exit(void)
  266. {
  267. platform_driver_unregister(&nuc900_rtc_driver);
  268. }
  269. module_init(nuc900_rtc_init);
  270. module_exit(nuc900_rtc_exit);
  271. MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
  272. MODULE_DESCRIPTION("nuc910/nuc920 RTC driver");
  273. MODULE_LICENSE("GPL");
  274. MODULE_ALIAS("platform:nuc900-rtc");