rtc-nuc900.c 8.3 KB

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