806-flextimer-support-layerscape.patch 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. From a5b3155b532289af793c26251cb087b4a24d5c15 Mon Sep 17 00:00:00 2001
  2. From: Yangbo Lu <[email protected]>
  3. Date: Mon, 25 Sep 2017 12:13:12 +0800
  4. Subject: [PATCH] flextimer: support layerscape
  5. This is a integrated patch for layerscape flextimer support.
  6. Signed-off-by: Wang Dongsheng <[email protected]>
  7. Signed-off-by: Meng Yi <[email protected]>
  8. Signed-off-by: Yangbo Lu <[email protected]>
  9. ---
  10. drivers/clocksource/fsl_ftm_timer.c | 8 +-
  11. drivers/soc/fsl/layerscape/ftm_alarm.c | 286 +++++++++++++++++++++++++++++++++
  12. 2 files changed, 290 insertions(+), 4 deletions(-)
  13. create mode 100644 drivers/soc/fsl/layerscape/ftm_alarm.c
  14. --- a/drivers/clocksource/fsl_ftm_timer.c
  15. +++ b/drivers/clocksource/fsl_ftm_timer.c
  16. @@ -83,11 +83,11 @@ static inline void ftm_counter_disable(v
  17. static inline void ftm_irq_acknowledge(void __iomem *base)
  18. {
  19. - u32 val;
  20. + unsigned int timeout = 100;
  21. - val = ftm_readl(base + FTM_SC);
  22. - val &= ~FTM_SC_TOF;
  23. - ftm_writel(val, base + FTM_SC);
  24. + while ((FTM_SC_TOF & ftm_readl(base + FTM_SC)) && timeout--)
  25. + ftm_writel(ftm_readl(base + FTM_SC) & (~FTM_SC_TOF),
  26. + base + FTM_SC);
  27. }
  28. static inline void ftm_irq_enable(void __iomem *base)
  29. --- /dev/null
  30. +++ b/drivers/soc/fsl/layerscape/ftm_alarm.c
  31. @@ -0,0 +1,286 @@
  32. +/*
  33. + * Freescale FlexTimer Module (FTM) Alarm driver.
  34. + *
  35. + * Copyright 2014 Freescale Semiconductor, Inc.
  36. + *
  37. + * This program is free software; you can redistribute it and/or
  38. + * modify it under the terms of the GNU General Public License
  39. + * as published by the Free Software Foundation; either version 2
  40. + * of the License, or (at your option) any later version.
  41. + */
  42. +
  43. +#include <linux/device.h>
  44. +#include <linux/err.h>
  45. +#include <linux/interrupt.h>
  46. +#include <linux/io.h>
  47. +#include <linux/of_address.h>
  48. +#include <linux/of_irq.h>
  49. +#include <linux/platform_device.h>
  50. +
  51. +#define FTM_SC 0x00
  52. +#define FTM_SC_CLK_SHIFT 3
  53. +#define FTM_SC_CLK_MASK (0x3 << FTM_SC_CLK_SHIFT)
  54. +#define FTM_SC_CLK(c) ((c) << FTM_SC_CLK_SHIFT)
  55. +#define FTM_SC_PS_MASK 0x7
  56. +#define FTM_SC_TOIE BIT(6)
  57. +#define FTM_SC_TOF BIT(7)
  58. +
  59. +#define FTM_SC_CLKS_FIXED_FREQ 0x02
  60. +
  61. +#define FTM_CNT 0x04
  62. +#define FTM_MOD 0x08
  63. +#define FTM_CNTIN 0x4C
  64. +
  65. +#define FIXED_FREQ_CLK 32000
  66. +#define MAX_FREQ_DIV (1 << FTM_SC_PS_MASK)
  67. +#define MAX_COUNT_VAL 0xffff
  68. +
  69. +static void __iomem *ftm1_base;
  70. +static void __iomem *rcpm_ftm_addr;
  71. +static u32 alarm_freq;
  72. +static bool big_endian;
  73. +
  74. +static inline u32 ftm_readl(void __iomem *addr)
  75. +{
  76. + if (big_endian)
  77. + return ioread32be(addr);
  78. +
  79. + return ioread32(addr);
  80. +}
  81. +
  82. +static inline void ftm_writel(u32 val, void __iomem *addr)
  83. +{
  84. + if (big_endian)
  85. + iowrite32be(val, addr);
  86. + else
  87. + iowrite32(val, addr);
  88. +}
  89. +
  90. +static inline void ftm_counter_enable(void __iomem *base)
  91. +{
  92. + u32 val;
  93. +
  94. + /* select and enable counter clock source */
  95. + val = ftm_readl(base + FTM_SC);
  96. + val &= ~(FTM_SC_PS_MASK | FTM_SC_CLK_MASK);
  97. + val |= (FTM_SC_PS_MASK | FTM_SC_CLK(FTM_SC_CLKS_FIXED_FREQ));
  98. + ftm_writel(val, base + FTM_SC);
  99. +}
  100. +
  101. +static inline void ftm_counter_disable(void __iomem *base)
  102. +{
  103. + u32 val;
  104. +
  105. + /* disable counter clock source */
  106. + val = ftm_readl(base + FTM_SC);
  107. + val &= ~(FTM_SC_PS_MASK | FTM_SC_CLK_MASK);
  108. + ftm_writel(val, base + FTM_SC);
  109. +}
  110. +
  111. +static inline void ftm_irq_acknowledge(void __iomem *base)
  112. +{
  113. + unsigned int timeout = 100;
  114. +
  115. + while ((FTM_SC_TOF & ftm_readl(base + FTM_SC)) && timeout--)
  116. + ftm_writel(ftm_readl(base + FTM_SC) & (~FTM_SC_TOF),
  117. + base + FTM_SC);
  118. +}
  119. +
  120. +static inline void ftm_irq_enable(void __iomem *base)
  121. +{
  122. + u32 val;
  123. +
  124. + val = ftm_readl(base + FTM_SC);
  125. + val |= FTM_SC_TOIE;
  126. + ftm_writel(val, base + FTM_SC);
  127. +}
  128. +
  129. +static inline void ftm_irq_disable(void __iomem *base)
  130. +{
  131. + u32 val;
  132. +
  133. + val = ftm_readl(base + FTM_SC);
  134. + val &= ~FTM_SC_TOIE;
  135. + ftm_writel(val, base + FTM_SC);
  136. +}
  137. +
  138. +static inline void ftm_reset_counter(void __iomem *base)
  139. +{
  140. + /*
  141. + * The CNT register contains the FTM counter value.
  142. + * Reset clears the CNT register. Writing any value to COUNT
  143. + * updates the counter with its initial value, CNTIN.
  144. + */
  145. + ftm_writel(0x00, base + FTM_CNT);
  146. +}
  147. +
  148. +static u32 time_to_cycle(unsigned long time)
  149. +{
  150. + u32 cycle;
  151. +
  152. + cycle = time * alarm_freq;
  153. + if (cycle > MAX_COUNT_VAL) {
  154. + pr_err("Out of alarm range.\n");
  155. + cycle = 0;
  156. + }
  157. +
  158. + return cycle;
  159. +}
  160. +
  161. +static u32 cycle_to_time(u32 cycle)
  162. +{
  163. + return cycle / alarm_freq + 1;
  164. +}
  165. +
  166. +static void ftm_clean_alarm(void)
  167. +{
  168. + ftm_counter_disable(ftm1_base);
  169. +
  170. + ftm_writel(0x00, ftm1_base + FTM_CNTIN);
  171. + ftm_writel(~0U, ftm1_base + FTM_MOD);
  172. +
  173. + ftm_reset_counter(ftm1_base);
  174. +}
  175. +
  176. +static int ftm_set_alarm(u64 cycle)
  177. +{
  178. + ftm_irq_disable(ftm1_base);
  179. +
  180. + /*
  181. + * The counter increments until the value of MOD is reached,
  182. + * at which point the counter is reloaded with the value of CNTIN.
  183. + * The TOF (the overflow flag) bit is set when the FTM counter
  184. + * changes from MOD to CNTIN. So we should using the cycle - 1.
  185. + */
  186. + ftm_writel(cycle - 1, ftm1_base + FTM_MOD);
  187. +
  188. + ftm_counter_enable(ftm1_base);
  189. +
  190. + ftm_irq_enable(ftm1_base);
  191. +
  192. + return 0;
  193. +}
  194. +
  195. +static irqreturn_t ftm_alarm_interrupt(int irq, void *dev_id)
  196. +{
  197. + ftm_irq_acknowledge(ftm1_base);
  198. + ftm_irq_disable(ftm1_base);
  199. + ftm_clean_alarm();
  200. +
  201. + return IRQ_HANDLED;
  202. +}
  203. +
  204. +static ssize_t ftm_alarm_show(struct device *dev,
  205. + struct device_attribute *attr,
  206. + char *buf)
  207. +{
  208. + u32 count, val;
  209. +
  210. + count = ftm_readl(ftm1_base + FTM_MOD);
  211. + val = ftm_readl(ftm1_base + FTM_CNT);
  212. + val = (count & MAX_COUNT_VAL) - val;
  213. + val = cycle_to_time(val);
  214. +
  215. + return sprintf(buf, "%u\n", val);
  216. +}
  217. +
  218. +static ssize_t ftm_alarm_store(struct device *dev,
  219. + struct device_attribute *attr,
  220. + const char *buf, size_t count)
  221. +{
  222. + u32 cycle;
  223. + unsigned long time;
  224. +
  225. + if (kstrtoul(buf, 0, &time))
  226. + return -EINVAL;
  227. +
  228. + ftm_clean_alarm();
  229. +
  230. + cycle = time_to_cycle(time);
  231. + if (!cycle)
  232. + return -EINVAL;
  233. +
  234. + ftm_set_alarm(cycle);
  235. +
  236. + return count;
  237. +}
  238. +
  239. +static struct device_attribute ftm_alarm_attributes = __ATTR(ftm_alarm, 0644,
  240. + ftm_alarm_show, ftm_alarm_store);
  241. +
  242. +static int ftm_alarm_probe(struct platform_device *pdev)
  243. +{
  244. + struct device_node *np = pdev->dev.of_node;
  245. + struct resource *r;
  246. + int irq;
  247. + int ret;
  248. + u32 ippdexpcr;
  249. +
  250. + r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  251. + if (!r)
  252. + return -ENODEV;
  253. +
  254. + ftm1_base = devm_ioremap_resource(&pdev->dev, r);
  255. + if (IS_ERR(ftm1_base))
  256. + return PTR_ERR(ftm1_base);
  257. +
  258. + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "FlexTimer1");
  259. + if (r) {
  260. + rcpm_ftm_addr = devm_ioremap_resource(&pdev->dev, r);
  261. + if (IS_ERR(rcpm_ftm_addr))
  262. + return PTR_ERR(rcpm_ftm_addr);
  263. + ippdexpcr = ioread32be(rcpm_ftm_addr);
  264. + ippdexpcr |= 0x20000;
  265. + iowrite32be(ippdexpcr, rcpm_ftm_addr);
  266. + }
  267. +
  268. + irq = irq_of_parse_and_map(np, 0);
  269. + if (irq <= 0) {
  270. + pr_err("ftm: unable to get IRQ from DT, %d\n", irq);
  271. + return -EINVAL;
  272. + }
  273. +
  274. + big_endian = of_property_read_bool(np, "big-endian");
  275. +
  276. + ret = devm_request_irq(&pdev->dev, irq, ftm_alarm_interrupt,
  277. + IRQF_NO_SUSPEND, dev_name(&pdev->dev), NULL);
  278. + if (ret < 0) {
  279. + dev_err(&pdev->dev, "failed to request irq\n");
  280. + return ret;
  281. + }
  282. +
  283. + ret = device_create_file(&pdev->dev, &ftm_alarm_attributes);
  284. + if (ret) {
  285. + dev_err(&pdev->dev, "create sysfs fail.\n");
  286. + return ret;
  287. + }
  288. +
  289. + alarm_freq = (u32)FIXED_FREQ_CLK / (u32)MAX_FREQ_DIV;
  290. +
  291. + ftm_clean_alarm();
  292. +
  293. + device_init_wakeup(&pdev->dev, true);
  294. +
  295. + return ret;
  296. +}
  297. +
  298. +static const struct of_device_id ftm_alarm_match[] = {
  299. + { .compatible = "fsl,ftm-alarm", },
  300. + { .compatible = "fsl,ftm-timer", },
  301. + { },
  302. +};
  303. +
  304. +static struct platform_driver ftm_alarm_driver = {
  305. + .probe = ftm_alarm_probe,
  306. + .driver = {
  307. + .name = "ftm-alarm",
  308. + .owner = THIS_MODULE,
  309. + .of_match_table = ftm_alarm_match,
  310. + },
  311. +};
  312. +
  313. +static int __init ftm_alarm_init(void)
  314. +{
  315. + return platform_driver_register(&ftm_alarm_driver);
  316. +}
  317. +device_initcall(ftm_alarm_init);