rtc-fsl-ftm-alarm.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Freescale FlexTimer Module (FTM) alarm device driver.
  4. *
  5. * Copyright 2014 Freescale Semiconductor, Inc.
  6. * Copyright 2019-2020 NXP
  7. *
  8. */
  9. #include <linux/device.h>
  10. #include <linux/err.h>
  11. #include <linux/interrupt.h>
  12. #include <linux/io.h>
  13. #include <linux/platform_device.h>
  14. #include <linux/mod_devicetable.h>
  15. #include <linux/module.h>
  16. #include <linux/fsl/ftm.h>
  17. #include <linux/rtc.h>
  18. #include <linux/time.h>
  19. #include <linux/acpi.h>
  20. #include <linux/pm_wakeirq.h>
  21. #define FTM_SC_CLK(c) ((c) << FTM_SC_CLK_MASK_SHIFT)
  22. /*
  23. * Select Fixed frequency clock (32KHz) as clock source
  24. * of FlexTimer Module
  25. */
  26. #define FTM_SC_CLKS_FIXED_FREQ 0x02
  27. #define FIXED_FREQ_CLK 32000
  28. /* Select 128 (2^7) as divider factor */
  29. #define MAX_FREQ_DIV (1 << FTM_SC_PS_MASK)
  30. /* Maximum counter value in FlexTimer's CNT registers */
  31. #define MAX_COUNT_VAL 0xffff
  32. struct ftm_rtc {
  33. struct rtc_device *rtc_dev;
  34. void __iomem *base;
  35. bool big_endian;
  36. u32 alarm_freq;
  37. };
  38. static inline u32 rtc_readl(struct ftm_rtc *dev, u32 reg)
  39. {
  40. if (dev->big_endian)
  41. return ioread32be(dev->base + reg);
  42. else
  43. return ioread32(dev->base + reg);
  44. }
  45. static inline void rtc_writel(struct ftm_rtc *dev, u32 reg, u32 val)
  46. {
  47. if (dev->big_endian)
  48. iowrite32be(val, dev->base + reg);
  49. else
  50. iowrite32(val, dev->base + reg);
  51. }
  52. static inline void ftm_counter_enable(struct ftm_rtc *rtc)
  53. {
  54. u32 val;
  55. /* select and enable counter clock source */
  56. val = rtc_readl(rtc, FTM_SC);
  57. val &= ~(FTM_SC_PS_MASK | FTM_SC_CLK_MASK);
  58. val |= (FTM_SC_PS_MASK | FTM_SC_CLK(FTM_SC_CLKS_FIXED_FREQ));
  59. rtc_writel(rtc, FTM_SC, val);
  60. }
  61. static inline void ftm_counter_disable(struct ftm_rtc *rtc)
  62. {
  63. u32 val;
  64. /* disable counter clock source */
  65. val = rtc_readl(rtc, FTM_SC);
  66. val &= ~(FTM_SC_PS_MASK | FTM_SC_CLK_MASK);
  67. rtc_writel(rtc, FTM_SC, val);
  68. }
  69. static inline void ftm_irq_acknowledge(struct ftm_rtc *rtc)
  70. {
  71. unsigned int timeout = 100;
  72. /*
  73. *Fix errata A-007728 for flextimer
  74. * If the FTM counter reaches the FTM_MOD value between
  75. * the reading of the TOF bit and the writing of 0 to
  76. * the TOF bit, the process of clearing the TOF bit
  77. * does not work as expected when FTMx_CONF[NUMTOF] != 0
  78. * and the current TOF count is less than FTMx_CONF[NUMTOF].
  79. * If the above condition is met, the TOF bit remains set.
  80. * If the TOF interrupt is enabled (FTMx_SC[TOIE] = 1),the
  81. * TOF interrupt also remains asserted.
  82. *
  83. * Above is the errata discription
  84. *
  85. * In one word: software clearing TOF bit not works when
  86. * FTMx_CONF[NUMTOF] was seted as nonzero and FTM counter
  87. * reaches the FTM_MOD value.
  88. *
  89. * The workaround is clearing TOF bit until it works
  90. * (FTM counter doesn't always reache the FTM_MOD anyway),
  91. * which may cost some cycles.
  92. */
  93. while ((FTM_SC_TOF & rtc_readl(rtc, FTM_SC)) && timeout--)
  94. rtc_writel(rtc, FTM_SC, rtc_readl(rtc, FTM_SC) & (~FTM_SC_TOF));
  95. }
  96. static inline void ftm_irq_enable(struct ftm_rtc *rtc)
  97. {
  98. u32 val;
  99. val = rtc_readl(rtc, FTM_SC);
  100. val |= FTM_SC_TOIE;
  101. rtc_writel(rtc, FTM_SC, val);
  102. }
  103. static inline void ftm_irq_disable(struct ftm_rtc *rtc)
  104. {
  105. u32 val;
  106. val = rtc_readl(rtc, FTM_SC);
  107. val &= ~FTM_SC_TOIE;
  108. rtc_writel(rtc, FTM_SC, val);
  109. }
  110. static inline void ftm_reset_counter(struct ftm_rtc *rtc)
  111. {
  112. /*
  113. * The CNT register contains the FTM counter value.
  114. * Reset clears the CNT register. Writing any value to COUNT
  115. * updates the counter with its initial value, CNTIN.
  116. */
  117. rtc_writel(rtc, FTM_CNT, 0x00);
  118. }
  119. static void ftm_clean_alarm(struct ftm_rtc *rtc)
  120. {
  121. ftm_counter_disable(rtc);
  122. rtc_writel(rtc, FTM_CNTIN, 0x00);
  123. rtc_writel(rtc, FTM_MOD, ~0U);
  124. ftm_reset_counter(rtc);
  125. }
  126. static irqreturn_t ftm_rtc_alarm_interrupt(int irq, void *dev)
  127. {
  128. struct ftm_rtc *rtc = dev;
  129. rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
  130. ftm_irq_acknowledge(rtc);
  131. ftm_irq_disable(rtc);
  132. ftm_clean_alarm(rtc);
  133. return IRQ_HANDLED;
  134. }
  135. static int ftm_rtc_alarm_irq_enable(struct device *dev,
  136. unsigned int enabled)
  137. {
  138. struct ftm_rtc *rtc = dev_get_drvdata(dev);
  139. if (enabled)
  140. ftm_irq_enable(rtc);
  141. else
  142. ftm_irq_disable(rtc);
  143. return 0;
  144. }
  145. /*
  146. * Note:
  147. * The function is not really getting time from the RTC
  148. * since FlexTimer is not a RTC device, but we need to
  149. * get time to setup alarm, so we are using system time
  150. * for now.
  151. */
  152. static int ftm_rtc_read_time(struct device *dev, struct rtc_time *tm)
  153. {
  154. rtc_time64_to_tm(ktime_get_real_seconds(), tm);
  155. return 0;
  156. }
  157. static int ftm_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
  158. {
  159. return 0;
  160. }
  161. /*
  162. * 1. Select fixed frequency clock (32KHz) as clock source;
  163. * 2. Select 128 (2^7) as divider factor;
  164. * So clock is 250 Hz (32KHz/128).
  165. *
  166. * 3. FlexTimer's CNT register is a 32bit register,
  167. * but the register's 16 bit as counter value,it's other 16 bit
  168. * is reserved.So minimum counter value is 0x0,maximum counter
  169. * value is 0xffff.
  170. * So max alarm value is 262 (65536 / 250) seconds
  171. */
  172. static int ftm_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
  173. {
  174. time64_t alm_time;
  175. unsigned long long cycle;
  176. struct ftm_rtc *rtc = dev_get_drvdata(dev);
  177. alm_time = rtc_tm_to_time64(&alm->time);
  178. ftm_clean_alarm(rtc);
  179. cycle = (alm_time - ktime_get_real_seconds()) * rtc->alarm_freq;
  180. if (cycle > MAX_COUNT_VAL) {
  181. pr_err("Out of alarm range {0~262} seconds.\n");
  182. return -ERANGE;
  183. }
  184. ftm_irq_disable(rtc);
  185. /*
  186. * The counter increments until the value of MOD is reached,
  187. * at which point the counter is reloaded with the value of CNTIN.
  188. * The TOF (the overflow flag) bit is set when the FTM counter
  189. * changes from MOD to CNTIN. So we should using the cycle - 1.
  190. */
  191. rtc_writel(rtc, FTM_MOD, cycle - 1);
  192. ftm_counter_enable(rtc);
  193. ftm_irq_enable(rtc);
  194. return 0;
  195. }
  196. static const struct rtc_class_ops ftm_rtc_ops = {
  197. .read_time = ftm_rtc_read_time,
  198. .read_alarm = ftm_rtc_read_alarm,
  199. .set_alarm = ftm_rtc_set_alarm,
  200. .alarm_irq_enable = ftm_rtc_alarm_irq_enable,
  201. };
  202. static int ftm_rtc_probe(struct platform_device *pdev)
  203. {
  204. int irq;
  205. int ret;
  206. struct ftm_rtc *rtc;
  207. rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
  208. if (unlikely(!rtc)) {
  209. dev_err(&pdev->dev, "cannot alloc memory for rtc\n");
  210. return -ENOMEM;
  211. }
  212. platform_set_drvdata(pdev, rtc);
  213. rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
  214. if (IS_ERR(rtc->rtc_dev))
  215. return PTR_ERR(rtc->rtc_dev);
  216. rtc->base = devm_platform_ioremap_resource(pdev, 0);
  217. if (IS_ERR(rtc->base)) {
  218. dev_err(&pdev->dev, "cannot ioremap resource for rtc\n");
  219. return PTR_ERR(rtc->base);
  220. }
  221. irq = platform_get_irq(pdev, 0);
  222. if (irq < 0)
  223. return irq;
  224. ret = devm_request_irq(&pdev->dev, irq, ftm_rtc_alarm_interrupt,
  225. 0, dev_name(&pdev->dev), rtc);
  226. if (ret < 0) {
  227. dev_err(&pdev->dev, "failed to request irq\n");
  228. return ret;
  229. }
  230. rtc->big_endian =
  231. device_property_read_bool(&pdev->dev, "big-endian");
  232. rtc->alarm_freq = (u32)FIXED_FREQ_CLK / (u32)MAX_FREQ_DIV;
  233. rtc->rtc_dev->ops = &ftm_rtc_ops;
  234. device_init_wakeup(&pdev->dev, true);
  235. ret = dev_pm_set_wake_irq(&pdev->dev, irq);
  236. if (ret)
  237. dev_err(&pdev->dev, "failed to enable irq wake\n");
  238. ret = devm_rtc_register_device(rtc->rtc_dev);
  239. if (ret) {
  240. dev_err(&pdev->dev, "can't register rtc device\n");
  241. return ret;
  242. }
  243. return 0;
  244. }
  245. static const struct of_device_id ftm_rtc_match[] = {
  246. { .compatible = "fsl,ls1012a-ftm-alarm", },
  247. { .compatible = "fsl,ls1021a-ftm-alarm", },
  248. { .compatible = "fsl,ls1028a-ftm-alarm", },
  249. { .compatible = "fsl,ls1043a-ftm-alarm", },
  250. { .compatible = "fsl,ls1046a-ftm-alarm", },
  251. { .compatible = "fsl,ls1088a-ftm-alarm", },
  252. { .compatible = "fsl,ls208xa-ftm-alarm", },
  253. { .compatible = "fsl,lx2160a-ftm-alarm", },
  254. { },
  255. };
  256. MODULE_DEVICE_TABLE(of, ftm_rtc_match);
  257. static const struct acpi_device_id ftm_imx_acpi_ids[] = {
  258. {"NXP0014",},
  259. { }
  260. };
  261. MODULE_DEVICE_TABLE(acpi, ftm_imx_acpi_ids);
  262. static struct platform_driver ftm_rtc_driver = {
  263. .probe = ftm_rtc_probe,
  264. .driver = {
  265. .name = "ftm-alarm",
  266. .of_match_table = ftm_rtc_match,
  267. .acpi_match_table = ACPI_PTR(ftm_imx_acpi_ids),
  268. },
  269. };
  270. module_platform_driver(ftm_rtc_driver);
  271. MODULE_DESCRIPTION("NXP/Freescale FlexTimer alarm driver");
  272. MODULE_AUTHOR("Biwen Li <biwen.li@nxp.com>");
  273. MODULE_LICENSE("GPL");