timer.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Ralink RT2880 timer
  4. * Author: John Crispin
  5. *
  6. * Copyright (C) 2013 John Crispin <[email protected]>
  7. */
  8. #include <linux/platform_device.h>
  9. #include <linux/interrupt.h>
  10. #include <linux/timer.h>
  11. #include <linux/of_gpio.h>
  12. #include <linux/clk.h>
  13. #include <asm/mach-ralink/ralink_regs.h>
  14. #define TIMER_REG_TMRSTAT 0x00
  15. #define TIMER_REG_TMR0LOAD 0x10
  16. #define TIMER_REG_TMR0CTL 0x18
  17. #define TMRSTAT_TMR0INT BIT(0)
  18. #define TMR0CTL_ENABLE BIT(7)
  19. #define TMR0CTL_MODE_PERIODIC BIT(4)
  20. #define TMR0CTL_PRESCALER 1
  21. #define TMR0CTL_PRESCALE_VAL (0xf - TMR0CTL_PRESCALER)
  22. #define TMR0CTL_PRESCALE_DIV (65536 / BIT(TMR0CTL_PRESCALER))
  23. struct rt_timer {
  24. struct device *dev;
  25. void __iomem *membase;
  26. int irq;
  27. unsigned long timer_freq;
  28. unsigned long timer_div;
  29. };
  30. static inline void rt_timer_w32(struct rt_timer *rt, u8 reg, u32 val)
  31. {
  32. __raw_writel(val, rt->membase + reg);
  33. }
  34. static inline u32 rt_timer_r32(struct rt_timer *rt, u8 reg)
  35. {
  36. return __raw_readl(rt->membase + reg);
  37. }
  38. static irqreturn_t rt_timer_irq(int irq, void *_rt)
  39. {
  40. struct rt_timer *rt = (struct rt_timer *) _rt;
  41. rt_timer_w32(rt, TIMER_REG_TMR0LOAD, rt->timer_freq / rt->timer_div);
  42. rt_timer_w32(rt, TIMER_REG_TMRSTAT, TMRSTAT_TMR0INT);
  43. return IRQ_HANDLED;
  44. }
  45. static int rt_timer_request(struct rt_timer *rt)
  46. {
  47. int err = request_irq(rt->irq, rt_timer_irq, 0,
  48. dev_name(rt->dev), rt);
  49. if (err) {
  50. dev_err(rt->dev, "failed to request irq\n");
  51. } else {
  52. u32 t = TMR0CTL_MODE_PERIODIC | TMR0CTL_PRESCALE_VAL;
  53. rt_timer_w32(rt, TIMER_REG_TMR0CTL, t);
  54. }
  55. return err;
  56. }
  57. static int rt_timer_config(struct rt_timer *rt, unsigned long divisor)
  58. {
  59. if (rt->timer_freq < divisor)
  60. rt->timer_div = rt->timer_freq;
  61. else
  62. rt->timer_div = divisor;
  63. rt_timer_w32(rt, TIMER_REG_TMR0LOAD, rt->timer_freq / rt->timer_div);
  64. return 0;
  65. }
  66. static int rt_timer_enable(struct rt_timer *rt)
  67. {
  68. u32 t;
  69. rt_timer_w32(rt, TIMER_REG_TMR0LOAD, rt->timer_freq / rt->timer_div);
  70. t = rt_timer_r32(rt, TIMER_REG_TMR0CTL);
  71. t |= TMR0CTL_ENABLE;
  72. rt_timer_w32(rt, TIMER_REG_TMR0CTL, t);
  73. return 0;
  74. }
  75. static int rt_timer_probe(struct platform_device *pdev)
  76. {
  77. struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  78. struct rt_timer *rt;
  79. struct clk *clk;
  80. rt = devm_kzalloc(&pdev->dev, sizeof(*rt), GFP_KERNEL);
  81. if (!rt) {
  82. dev_err(&pdev->dev, "failed to allocate memory\n");
  83. return -ENOMEM;
  84. }
  85. rt->irq = platform_get_irq(pdev, 0);
  86. if (rt->irq < 0)
  87. return rt->irq;
  88. rt->membase = devm_ioremap_resource(&pdev->dev, res);
  89. if (IS_ERR(rt->membase))
  90. return PTR_ERR(rt->membase);
  91. clk = devm_clk_get(&pdev->dev, NULL);
  92. if (IS_ERR(clk)) {
  93. dev_err(&pdev->dev, "failed get clock rate\n");
  94. return PTR_ERR(clk);
  95. }
  96. rt->timer_freq = clk_get_rate(clk) / TMR0CTL_PRESCALE_DIV;
  97. if (!rt->timer_freq)
  98. return -EINVAL;
  99. rt->dev = &pdev->dev;
  100. platform_set_drvdata(pdev, rt);
  101. rt_timer_request(rt);
  102. rt_timer_config(rt, 2);
  103. rt_timer_enable(rt);
  104. dev_info(&pdev->dev, "maximum frequency is %luHz\n", rt->timer_freq);
  105. return 0;
  106. }
  107. static const struct of_device_id rt_timer_match[] = {
  108. { .compatible = "ralink,rt2880-timer" },
  109. {},
  110. };
  111. static struct platform_driver rt_timer_driver = {
  112. .probe = rt_timer_probe,
  113. .driver = {
  114. .name = "rt-timer",
  115. .of_match_table = rt_timer_match,
  116. .suppress_bind_attrs = true,
  117. },
  118. };
  119. builtin_platform_driver(rt_timer_driver);