ptp_ixp46x.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * PTP 1588 clock using the IXP46X
  4. *
  5. * Copyright (C) 2010 OMICRON electronics GmbH
  6. */
  7. #include <linux/device.h>
  8. #include <linux/module.h>
  9. #include <linux/mod_devicetable.h>
  10. #include <linux/err.h>
  11. #include <linux/init.h>
  12. #include <linux/interrupt.h>
  13. #include <linux/io.h>
  14. #include <linux/irq.h>
  15. #include <linux/kernel.h>
  16. #include <linux/ptp_clock_kernel.h>
  17. #include <linux/platform_device.h>
  18. #include <linux/soc/ixp4xx/cpu.h>
  19. #include "ixp46x_ts.h"
  20. #define DRIVER "ptp_ixp46x"
  21. #define N_EXT_TS 2
  22. struct ixp_clock {
  23. struct ixp46x_ts_regs *regs;
  24. struct ptp_clock *ptp_clock;
  25. struct ptp_clock_info caps;
  26. int exts0_enabled;
  27. int exts1_enabled;
  28. int slave_irq;
  29. int master_irq;
  30. };
  31. static DEFINE_SPINLOCK(register_lock);
  32. /*
  33. * Register access functions
  34. */
  35. static u64 ixp_systime_read(struct ixp46x_ts_regs *regs)
  36. {
  37. u64 ns;
  38. u32 lo, hi;
  39. lo = __raw_readl(&regs->systime_lo);
  40. hi = __raw_readl(&regs->systime_hi);
  41. ns = ((u64) hi) << 32;
  42. ns |= lo;
  43. ns <<= TICKS_NS_SHIFT;
  44. return ns;
  45. }
  46. static void ixp_systime_write(struct ixp46x_ts_regs *regs, u64 ns)
  47. {
  48. u32 hi, lo;
  49. ns >>= TICKS_NS_SHIFT;
  50. hi = ns >> 32;
  51. lo = ns & 0xffffffff;
  52. __raw_writel(lo, &regs->systime_lo);
  53. __raw_writel(hi, &regs->systime_hi);
  54. }
  55. /*
  56. * Interrupt service routine
  57. */
  58. static irqreturn_t isr(int irq, void *priv)
  59. {
  60. struct ixp_clock *ixp_clock = priv;
  61. struct ixp46x_ts_regs *regs = ixp_clock->regs;
  62. struct ptp_clock_event event;
  63. u32 ack = 0, lo, hi, val;
  64. val = __raw_readl(&regs->event);
  65. if (val & TSER_SNS) {
  66. ack |= TSER_SNS;
  67. if (ixp_clock->exts0_enabled) {
  68. hi = __raw_readl(&regs->asms_hi);
  69. lo = __raw_readl(&regs->asms_lo);
  70. event.type = PTP_CLOCK_EXTTS;
  71. event.index = 0;
  72. event.timestamp = ((u64) hi) << 32;
  73. event.timestamp |= lo;
  74. event.timestamp <<= TICKS_NS_SHIFT;
  75. ptp_clock_event(ixp_clock->ptp_clock, &event);
  76. }
  77. }
  78. if (val & TSER_SNM) {
  79. ack |= TSER_SNM;
  80. if (ixp_clock->exts1_enabled) {
  81. hi = __raw_readl(&regs->amms_hi);
  82. lo = __raw_readl(&regs->amms_lo);
  83. event.type = PTP_CLOCK_EXTTS;
  84. event.index = 1;
  85. event.timestamp = ((u64) hi) << 32;
  86. event.timestamp |= lo;
  87. event.timestamp <<= TICKS_NS_SHIFT;
  88. ptp_clock_event(ixp_clock->ptp_clock, &event);
  89. }
  90. }
  91. if (val & TTIPEND)
  92. ack |= TTIPEND; /* this bit seems to be always set */
  93. if (ack) {
  94. __raw_writel(ack, &regs->event);
  95. return IRQ_HANDLED;
  96. } else
  97. return IRQ_NONE;
  98. }
  99. /*
  100. * PTP clock operations
  101. */
  102. static int ptp_ixp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
  103. {
  104. u64 adj;
  105. u32 diff, addend;
  106. int neg_adj = 0;
  107. struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps);
  108. struct ixp46x_ts_regs *regs = ixp_clock->regs;
  109. if (ppb < 0) {
  110. neg_adj = 1;
  111. ppb = -ppb;
  112. }
  113. addend = DEFAULT_ADDEND;
  114. adj = addend;
  115. adj *= ppb;
  116. diff = div_u64(adj, 1000000000ULL);
  117. addend = neg_adj ? addend - diff : addend + diff;
  118. __raw_writel(addend, &regs->addend);
  119. return 0;
  120. }
  121. static int ptp_ixp_adjtime(struct ptp_clock_info *ptp, s64 delta)
  122. {
  123. s64 now;
  124. unsigned long flags;
  125. struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps);
  126. struct ixp46x_ts_regs *regs = ixp_clock->regs;
  127. spin_lock_irqsave(&register_lock, flags);
  128. now = ixp_systime_read(regs);
  129. now += delta;
  130. ixp_systime_write(regs, now);
  131. spin_unlock_irqrestore(&register_lock, flags);
  132. return 0;
  133. }
  134. static int ptp_ixp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
  135. {
  136. u64 ns;
  137. unsigned long flags;
  138. struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps);
  139. struct ixp46x_ts_regs *regs = ixp_clock->regs;
  140. spin_lock_irqsave(&register_lock, flags);
  141. ns = ixp_systime_read(regs);
  142. spin_unlock_irqrestore(&register_lock, flags);
  143. *ts = ns_to_timespec64(ns);
  144. return 0;
  145. }
  146. static int ptp_ixp_settime(struct ptp_clock_info *ptp,
  147. const struct timespec64 *ts)
  148. {
  149. u64 ns;
  150. unsigned long flags;
  151. struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps);
  152. struct ixp46x_ts_regs *regs = ixp_clock->regs;
  153. ns = timespec64_to_ns(ts);
  154. spin_lock_irqsave(&register_lock, flags);
  155. ixp_systime_write(regs, ns);
  156. spin_unlock_irqrestore(&register_lock, flags);
  157. return 0;
  158. }
  159. static int ptp_ixp_enable(struct ptp_clock_info *ptp,
  160. struct ptp_clock_request *rq, int on)
  161. {
  162. struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps);
  163. switch (rq->type) {
  164. case PTP_CLK_REQ_EXTTS:
  165. switch (rq->extts.index) {
  166. case 0:
  167. ixp_clock->exts0_enabled = on ? 1 : 0;
  168. break;
  169. case 1:
  170. ixp_clock->exts1_enabled = on ? 1 : 0;
  171. break;
  172. default:
  173. return -EINVAL;
  174. }
  175. return 0;
  176. default:
  177. break;
  178. }
  179. return -EOPNOTSUPP;
  180. }
  181. static const struct ptp_clock_info ptp_ixp_caps = {
  182. .owner = THIS_MODULE,
  183. .name = "IXP46X timer",
  184. .max_adj = 66666655,
  185. .n_ext_ts = N_EXT_TS,
  186. .n_pins = 0,
  187. .pps = 0,
  188. .adjfreq = ptp_ixp_adjfreq,
  189. .adjtime = ptp_ixp_adjtime,
  190. .gettime64 = ptp_ixp_gettime,
  191. .settime64 = ptp_ixp_settime,
  192. .enable = ptp_ixp_enable,
  193. };
  194. /* module operations */
  195. static struct ixp_clock ixp_clock;
  196. int ixp46x_ptp_find(struct ixp46x_ts_regs *__iomem *regs, int *phc_index)
  197. {
  198. *regs = ixp_clock.regs;
  199. *phc_index = ptp_clock_index(ixp_clock.ptp_clock);
  200. if (!ixp_clock.ptp_clock)
  201. return -EPROBE_DEFER;
  202. return 0;
  203. }
  204. EXPORT_SYMBOL_GPL(ixp46x_ptp_find);
  205. /* Called from the registered devm action */
  206. static void ptp_ixp_unregister_action(void *d)
  207. {
  208. struct ptp_clock *ptp_clock = d;
  209. ptp_clock_unregister(ptp_clock);
  210. ixp_clock.ptp_clock = NULL;
  211. }
  212. static int ptp_ixp_probe(struct platform_device *pdev)
  213. {
  214. struct device *dev = &pdev->dev;
  215. int ret;
  216. ixp_clock.regs = devm_platform_ioremap_resource(pdev, 0);
  217. ixp_clock.master_irq = platform_get_irq(pdev, 0);
  218. ixp_clock.slave_irq = platform_get_irq(pdev, 1);
  219. if (IS_ERR(ixp_clock.regs) ||
  220. ixp_clock.master_irq < 0 || ixp_clock.slave_irq < 0)
  221. return -ENXIO;
  222. ixp_clock.caps = ptp_ixp_caps;
  223. ixp_clock.ptp_clock = ptp_clock_register(&ixp_clock.caps, NULL);
  224. if (IS_ERR(ixp_clock.ptp_clock))
  225. return PTR_ERR(ixp_clock.ptp_clock);
  226. ret = devm_add_action_or_reset(dev, ptp_ixp_unregister_action,
  227. ixp_clock.ptp_clock);
  228. if (ret) {
  229. dev_err(dev, "failed to install clock removal handler\n");
  230. return ret;
  231. }
  232. __raw_writel(DEFAULT_ADDEND, &ixp_clock.regs->addend);
  233. __raw_writel(1, &ixp_clock.regs->trgt_lo);
  234. __raw_writel(0, &ixp_clock.regs->trgt_hi);
  235. __raw_writel(TTIPEND, &ixp_clock.regs->event);
  236. ret = devm_request_irq(dev, ixp_clock.master_irq, isr,
  237. 0, DRIVER, &ixp_clock);
  238. if (ret)
  239. return dev_err_probe(dev, ret,
  240. "request_irq failed for irq %d\n",
  241. ixp_clock.master_irq);
  242. ret = devm_request_irq(dev, ixp_clock.slave_irq, isr,
  243. 0, DRIVER, &ixp_clock);
  244. if (ret)
  245. return dev_err_probe(dev, ret,
  246. "request_irq failed for irq %d\n",
  247. ixp_clock.slave_irq);
  248. return 0;
  249. }
  250. static const struct of_device_id ptp_ixp_match[] = {
  251. {
  252. .compatible = "intel,ixp46x-ptp-timer",
  253. },
  254. { },
  255. };
  256. static struct platform_driver ptp_ixp_driver = {
  257. .driver = {
  258. .name = "ptp-ixp46x",
  259. .of_match_table = ptp_ixp_match,
  260. .suppress_bind_attrs = true,
  261. },
  262. .probe = ptp_ixp_probe,
  263. };
  264. module_platform_driver(ptp_ixp_driver);
  265. MODULE_AUTHOR("Richard Cochran <[email protected]>");
  266. MODULE_DESCRIPTION("PTP clock using the IXP46X timer");
  267. MODULE_LICENSE("GPL");