rtc-s3c.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* drivers/rtc/rtc-s3c.c
  3. *
  4. * Copyright (c) 2010 Samsung Electronics Co., Ltd.
  5. * http://www.samsung.com/
  6. *
  7. * Copyright (c) 2004,2006 Simtec Electronics
  8. * Ben Dooks, <ben@simtec.co.uk>
  9. * http://armlinux.simtec.co.uk/
  10. *
  11. * S3C2410/S3C2440/S3C24XX Internal RTC Driver
  12. */
  13. #include <linux/module.h>
  14. #include <linux/fs.h>
  15. #include <linux/string.h>
  16. #include <linux/init.h>
  17. #include <linux/platform_device.h>
  18. #include <linux/interrupt.h>
  19. #include <linux/rtc.h>
  20. #include <linux/bcd.h>
  21. #include <linux/clk.h>
  22. #include <linux/log2.h>
  23. #include <linux/slab.h>
  24. #include <linux/of.h>
  25. #include <linux/uaccess.h>
  26. #include <linux/io.h>
  27. #include <asm/irq.h>
  28. #include "rtc-s3c.h"
  29. struct s3c_rtc {
  30. struct device *dev;
  31. struct rtc_device *rtc;
  32. void __iomem *base;
  33. struct clk *rtc_clk;
  34. struct clk *rtc_src_clk;
  35. bool alarm_enabled;
  36. const struct s3c_rtc_data *data;
  37. int irq_alarm;
  38. spinlock_t alarm_lock;
  39. bool wake_en;
  40. };
  41. struct s3c_rtc_data {
  42. bool needs_src_clk;
  43. void (*irq_handler) (struct s3c_rtc *info, int mask);
  44. void (*enable) (struct s3c_rtc *info);
  45. void (*disable) (struct s3c_rtc *info);
  46. };
  47. static int s3c_rtc_enable_clk(struct s3c_rtc *info)
  48. {
  49. int ret;
  50. ret = clk_enable(info->rtc_clk);
  51. if (ret)
  52. return ret;
  53. if (info->data->needs_src_clk) {
  54. ret = clk_enable(info->rtc_src_clk);
  55. if (ret) {
  56. clk_disable(info->rtc_clk);
  57. return ret;
  58. }
  59. }
  60. return 0;
  61. }
  62. static void s3c_rtc_disable_clk(struct s3c_rtc *info)
  63. {
  64. if (info->data->needs_src_clk)
  65. clk_disable(info->rtc_src_clk);
  66. clk_disable(info->rtc_clk);
  67. }
  68. /* IRQ Handler */
  69. static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
  70. {
  71. struct s3c_rtc *info = (struct s3c_rtc *)id;
  72. if (info->data->irq_handler)
  73. info->data->irq_handler(info, S3C2410_INTP_ALM);
  74. return IRQ_HANDLED;
  75. }
  76. /* Update control registers */
  77. static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
  78. {
  79. struct s3c_rtc *info = dev_get_drvdata(dev);
  80. unsigned long flags;
  81. unsigned int tmp;
  82. int ret;
  83. dev_dbg(info->dev, "%s: aie=%d\n", __func__, enabled);
  84. ret = s3c_rtc_enable_clk(info);
  85. if (ret)
  86. return ret;
  87. tmp = readb(info->base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
  88. if (enabled)
  89. tmp |= S3C2410_RTCALM_ALMEN;
  90. writeb(tmp, info->base + S3C2410_RTCALM);
  91. spin_lock_irqsave(&info->alarm_lock, flags);
  92. if (info->alarm_enabled && !enabled)
  93. s3c_rtc_disable_clk(info);
  94. else if (!info->alarm_enabled && enabled)
  95. ret = s3c_rtc_enable_clk(info);
  96. info->alarm_enabled = enabled;
  97. spin_unlock_irqrestore(&info->alarm_lock, flags);
  98. s3c_rtc_disable_clk(info);
  99. return ret;
  100. }
  101. /* Read time from RTC and convert it from BCD */
  102. static int s3c_rtc_read_time(struct s3c_rtc *info, struct rtc_time *tm)
  103. {
  104. unsigned int have_retried = 0;
  105. int ret;
  106. ret = s3c_rtc_enable_clk(info);
  107. if (ret)
  108. return ret;
  109. retry_get_time:
  110. tm->tm_min = readb(info->base + S3C2410_RTCMIN);
  111. tm->tm_hour = readb(info->base + S3C2410_RTCHOUR);
  112. tm->tm_mday = readb(info->base + S3C2410_RTCDATE);
  113. tm->tm_mon = readb(info->base + S3C2410_RTCMON);
  114. tm->tm_year = readb(info->base + S3C2410_RTCYEAR);
  115. tm->tm_sec = readb(info->base + S3C2410_RTCSEC);
  116. /*
  117. * The only way to work out whether the system was mid-update
  118. * when we read it is to check the second counter, and if it
  119. * is zero, then we re-try the entire read
  120. */
  121. if (tm->tm_sec == 0 && !have_retried) {
  122. have_retried = 1;
  123. goto retry_get_time;
  124. }
  125. s3c_rtc_disable_clk(info);
  126. tm->tm_sec = bcd2bin(tm->tm_sec);
  127. tm->tm_min = bcd2bin(tm->tm_min);
  128. tm->tm_hour = bcd2bin(tm->tm_hour);
  129. tm->tm_mday = bcd2bin(tm->tm_mday);
  130. tm->tm_mon = bcd2bin(tm->tm_mon);
  131. tm->tm_year = bcd2bin(tm->tm_year);
  132. return 0;
  133. }
  134. /* Convert time to BCD and write it to RTC */
  135. static int s3c_rtc_write_time(struct s3c_rtc *info, const struct rtc_time *tm)
  136. {
  137. int ret;
  138. ret = s3c_rtc_enable_clk(info);
  139. if (ret)
  140. return ret;
  141. writeb(bin2bcd(tm->tm_sec), info->base + S3C2410_RTCSEC);
  142. writeb(bin2bcd(tm->tm_min), info->base + S3C2410_RTCMIN);
  143. writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_RTCHOUR);
  144. writeb(bin2bcd(tm->tm_mday), info->base + S3C2410_RTCDATE);
  145. writeb(bin2bcd(tm->tm_mon), info->base + S3C2410_RTCMON);
  146. writeb(bin2bcd(tm->tm_year), info->base + S3C2410_RTCYEAR);
  147. s3c_rtc_disable_clk(info);
  148. return 0;
  149. }
  150. static int s3c_rtc_gettime(struct device *dev, struct rtc_time *tm)
  151. {
  152. struct s3c_rtc *info = dev_get_drvdata(dev);
  153. int ret;
  154. ret = s3c_rtc_read_time(info, tm);
  155. if (ret)
  156. return ret;
  157. /* Convert internal representation to actual date/time */
  158. tm->tm_year += 100;
  159. tm->tm_mon -= 1;
  160. dev_dbg(dev, "read time %ptR\n", tm);
  161. return 0;
  162. }
  163. static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
  164. {
  165. struct s3c_rtc *info = dev_get_drvdata(dev);
  166. struct rtc_time rtc_tm = *tm;
  167. dev_dbg(dev, "set time %ptR\n", tm);
  168. /*
  169. * Convert actual date/time to internal representation.
  170. * We get around Y2K by simply not supporting it.
  171. */
  172. rtc_tm.tm_year -= 100;
  173. rtc_tm.tm_mon += 1;
  174. return s3c_rtc_write_time(info, &rtc_tm);
  175. }
  176. static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
  177. {
  178. struct s3c_rtc *info = dev_get_drvdata(dev);
  179. struct rtc_time *alm_tm = &alrm->time;
  180. unsigned int alm_en;
  181. int ret;
  182. ret = s3c_rtc_enable_clk(info);
  183. if (ret)
  184. return ret;
  185. alm_tm->tm_sec = readb(info->base + S3C2410_ALMSEC);
  186. alm_tm->tm_min = readb(info->base + S3C2410_ALMMIN);
  187. alm_tm->tm_hour = readb(info->base + S3C2410_ALMHOUR);
  188. alm_tm->tm_mon = readb(info->base + S3C2410_ALMMON);
  189. alm_tm->tm_mday = readb(info->base + S3C2410_ALMDATE);
  190. alm_tm->tm_year = readb(info->base + S3C2410_ALMYEAR);
  191. alm_en = readb(info->base + S3C2410_RTCALM);
  192. s3c_rtc_disable_clk(info);
  193. alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0;
  194. dev_dbg(dev, "read alarm %d, %ptR\n", alm_en, alm_tm);
  195. /* decode the alarm enable field */
  196. if (alm_en & S3C2410_RTCALM_SECEN)
  197. alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec);
  198. if (alm_en & S3C2410_RTCALM_MINEN)
  199. alm_tm->tm_min = bcd2bin(alm_tm->tm_min);
  200. if (alm_en & S3C2410_RTCALM_HOUREN)
  201. alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);
  202. if (alm_en & S3C2410_RTCALM_DAYEN)
  203. alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday);
  204. if (alm_en & S3C2410_RTCALM_MONEN) {
  205. alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon);
  206. alm_tm->tm_mon -= 1;
  207. }
  208. if (alm_en & S3C2410_RTCALM_YEAREN)
  209. alm_tm->tm_year = bcd2bin(alm_tm->tm_year);
  210. return 0;
  211. }
  212. static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
  213. {
  214. struct s3c_rtc *info = dev_get_drvdata(dev);
  215. struct rtc_time *tm = &alrm->time;
  216. unsigned int alrm_en;
  217. int ret;
  218. dev_dbg(dev, "s3c_rtc_setalarm: %d, %ptR\n", alrm->enabled, tm);
  219. ret = s3c_rtc_enable_clk(info);
  220. if (ret)
  221. return ret;
  222. alrm_en = readb(info->base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
  223. writeb(0x00, info->base + S3C2410_RTCALM);
  224. if (tm->tm_sec < 60 && tm->tm_sec >= 0) {
  225. alrm_en |= S3C2410_RTCALM_SECEN;
  226. writeb(bin2bcd(tm->tm_sec), info->base + S3C2410_ALMSEC);
  227. }
  228. if (tm->tm_min < 60 && tm->tm_min >= 0) {
  229. alrm_en |= S3C2410_RTCALM_MINEN;
  230. writeb(bin2bcd(tm->tm_min), info->base + S3C2410_ALMMIN);
  231. }
  232. if (tm->tm_hour < 24 && tm->tm_hour >= 0) {
  233. alrm_en |= S3C2410_RTCALM_HOUREN;
  234. writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_ALMHOUR);
  235. }
  236. if (tm->tm_mon < 12 && tm->tm_mon >= 0) {
  237. alrm_en |= S3C2410_RTCALM_MONEN;
  238. writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_ALMMON);
  239. }
  240. if (tm->tm_mday <= 31 && tm->tm_mday >= 1) {
  241. alrm_en |= S3C2410_RTCALM_DAYEN;
  242. writeb(bin2bcd(tm->tm_mday), info->base + S3C2410_ALMDATE);
  243. }
  244. dev_dbg(dev, "setting S3C2410_RTCALM to %08x\n", alrm_en);
  245. writeb(alrm_en, info->base + S3C2410_RTCALM);
  246. s3c_rtc_setaie(dev, alrm->enabled);
  247. s3c_rtc_disable_clk(info);
  248. return 0;
  249. }
  250. static const struct rtc_class_ops s3c_rtcops = {
  251. .read_time = s3c_rtc_gettime,
  252. .set_time = s3c_rtc_settime,
  253. .read_alarm = s3c_rtc_getalarm,
  254. .set_alarm = s3c_rtc_setalarm,
  255. .alarm_irq_enable = s3c_rtc_setaie,
  256. };
  257. static void s3c6410_rtc_enable(struct s3c_rtc *info)
  258. {
  259. unsigned int con, tmp;
  260. con = readw(info->base + S3C2410_RTCCON);
  261. /* re-enable the device, and check it is ok */
  262. if ((con & S3C2410_RTCCON_RTCEN) == 0) {
  263. dev_info(info->dev, "rtc disabled, re-enabling\n");
  264. tmp = readw(info->base + S3C2410_RTCCON);
  265. writew(tmp | S3C2410_RTCCON_RTCEN, info->base + S3C2410_RTCCON);
  266. }
  267. if (con & S3C2410_RTCCON_CNTSEL) {
  268. dev_info(info->dev, "removing RTCCON_CNTSEL\n");
  269. tmp = readw(info->base + S3C2410_RTCCON);
  270. writew(tmp & ~S3C2410_RTCCON_CNTSEL,
  271. info->base + S3C2410_RTCCON);
  272. }
  273. if (con & S3C2410_RTCCON_CLKRST) {
  274. dev_info(info->dev, "removing RTCCON_CLKRST\n");
  275. tmp = readw(info->base + S3C2410_RTCCON);
  276. writew(tmp & ~S3C2410_RTCCON_CLKRST,
  277. info->base + S3C2410_RTCCON);
  278. }
  279. }
  280. static void s3c6410_rtc_disable(struct s3c_rtc *info)
  281. {
  282. unsigned int con;
  283. con = readw(info->base + S3C2410_RTCCON);
  284. con &= ~S3C64XX_RTCCON_TICEN;
  285. con &= ~S3C2410_RTCCON_RTCEN;
  286. writew(con, info->base + S3C2410_RTCCON);
  287. }
  288. static void s3c_rtc_remove(struct platform_device *pdev)
  289. {
  290. struct s3c_rtc *info = platform_get_drvdata(pdev);
  291. s3c_rtc_setaie(info->dev, 0);
  292. if (info->data->needs_src_clk)
  293. clk_unprepare(info->rtc_src_clk);
  294. clk_unprepare(info->rtc_clk);
  295. }
  296. static int s3c_rtc_probe(struct platform_device *pdev)
  297. {
  298. struct s3c_rtc *info = NULL;
  299. int ret;
  300. info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
  301. if (!info)
  302. return -ENOMEM;
  303. info->dev = &pdev->dev;
  304. info->data = of_device_get_match_data(&pdev->dev);
  305. if (!info->data) {
  306. dev_err(&pdev->dev, "failed getting s3c_rtc_data\n");
  307. return -EINVAL;
  308. }
  309. spin_lock_init(&info->alarm_lock);
  310. platform_set_drvdata(pdev, info);
  311. info->irq_alarm = platform_get_irq(pdev, 0);
  312. if (info->irq_alarm < 0)
  313. return info->irq_alarm;
  314. dev_dbg(&pdev->dev, "s3c2410_rtc: alarm irq %d\n", info->irq_alarm);
  315. /* get the memory region */
  316. info->base = devm_platform_ioremap_resource(pdev, 0);
  317. if (IS_ERR(info->base))
  318. return PTR_ERR(info->base);
  319. info->rtc_clk = devm_clk_get(&pdev->dev, "rtc");
  320. if (IS_ERR(info->rtc_clk))
  321. return dev_err_probe(&pdev->dev, PTR_ERR(info->rtc_clk),
  322. "failed to find rtc clock\n");
  323. ret = clk_prepare_enable(info->rtc_clk);
  324. if (ret)
  325. return ret;
  326. if (info->data->needs_src_clk) {
  327. info->rtc_src_clk = devm_clk_get(&pdev->dev, "rtc_src");
  328. if (IS_ERR(info->rtc_src_clk)) {
  329. ret = dev_err_probe(&pdev->dev, PTR_ERR(info->rtc_src_clk),
  330. "failed to find rtc source clock\n");
  331. goto err_src_clk;
  332. }
  333. ret = clk_prepare_enable(info->rtc_src_clk);
  334. if (ret)
  335. goto err_src_clk;
  336. }
  337. /* disable RTC enable bits potentially set by the bootloader */
  338. if (info->data->disable)
  339. info->data->disable(info);
  340. /* check to see if everything is setup correctly */
  341. if (info->data->enable)
  342. info->data->enable(info);
  343. dev_dbg(&pdev->dev, "s3c2410_rtc: RTCCON=%02x\n",
  344. readw(info->base + S3C2410_RTCCON));
  345. device_init_wakeup(&pdev->dev, true);
  346. info->rtc = devm_rtc_allocate_device(&pdev->dev);
  347. if (IS_ERR(info->rtc)) {
  348. ret = PTR_ERR(info->rtc);
  349. goto err_nortc;
  350. }
  351. info->rtc->ops = &s3c_rtcops;
  352. info->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
  353. info->rtc->range_max = RTC_TIMESTAMP_END_2099;
  354. ret = devm_rtc_register_device(info->rtc);
  355. if (ret)
  356. goto err_nortc;
  357. ret = devm_request_irq(&pdev->dev, info->irq_alarm, s3c_rtc_alarmirq,
  358. 0, "s3c2410-rtc alarm", info);
  359. if (ret) {
  360. dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_alarm, ret);
  361. goto err_nortc;
  362. }
  363. s3c_rtc_disable_clk(info);
  364. return 0;
  365. err_nortc:
  366. if (info->data->disable)
  367. info->data->disable(info);
  368. if (info->data->needs_src_clk)
  369. clk_disable_unprepare(info->rtc_src_clk);
  370. err_src_clk:
  371. clk_disable_unprepare(info->rtc_clk);
  372. return ret;
  373. }
  374. #ifdef CONFIG_PM_SLEEP
  375. static int s3c_rtc_suspend(struct device *dev)
  376. {
  377. struct s3c_rtc *info = dev_get_drvdata(dev);
  378. int ret;
  379. ret = s3c_rtc_enable_clk(info);
  380. if (ret)
  381. return ret;
  382. if (info->data->disable)
  383. info->data->disable(info);
  384. if (device_may_wakeup(dev) && !info->wake_en) {
  385. if (enable_irq_wake(info->irq_alarm) == 0)
  386. info->wake_en = true;
  387. else
  388. dev_err(dev, "enable_irq_wake failed\n");
  389. }
  390. return 0;
  391. }
  392. static int s3c_rtc_resume(struct device *dev)
  393. {
  394. struct s3c_rtc *info = dev_get_drvdata(dev);
  395. if (info->data->enable)
  396. info->data->enable(info);
  397. s3c_rtc_disable_clk(info);
  398. if (device_may_wakeup(dev) && info->wake_en) {
  399. disable_irq_wake(info->irq_alarm);
  400. info->wake_en = false;
  401. }
  402. return 0;
  403. }
  404. #endif
  405. static SIMPLE_DEV_PM_OPS(s3c_rtc_pm_ops, s3c_rtc_suspend, s3c_rtc_resume);
  406. static void s3c6410_rtc_irq(struct s3c_rtc *info, int mask)
  407. {
  408. rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF);
  409. writeb(mask, info->base + S3C2410_INTP);
  410. }
  411. static const struct s3c_rtc_data s3c6410_rtc_data = {
  412. .needs_src_clk = true,
  413. .irq_handler = s3c6410_rtc_irq,
  414. .enable = s3c6410_rtc_enable,
  415. .disable = s3c6410_rtc_disable,
  416. };
  417. static const __maybe_unused struct of_device_id s3c_rtc_dt_match[] = {
  418. {
  419. .compatible = "samsung,s3c6410-rtc",
  420. .data = &s3c6410_rtc_data,
  421. }, {
  422. .compatible = "samsung,exynos3250-rtc",
  423. .data = &s3c6410_rtc_data,
  424. },
  425. { /* sentinel */ },
  426. };
  427. MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match);
  428. static struct platform_driver s3c_rtc_driver = {
  429. .probe = s3c_rtc_probe,
  430. .remove = s3c_rtc_remove,
  431. .driver = {
  432. .name = "s3c-rtc",
  433. .pm = &s3c_rtc_pm_ops,
  434. .of_match_table = of_match_ptr(s3c_rtc_dt_match),
  435. },
  436. };
  437. module_platform_driver(s3c_rtc_driver);
  438. MODULE_DESCRIPTION("Samsung S3C RTC Driver");
  439. MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
  440. MODULE_LICENSE("GPL");