armv7m_systick.c 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. /*
  2. * Copyright (C) Maxime Coquelin 2015
  3. * Author: Maxime Coquelin <[email protected]>
  4. * License terms: GNU General Public License (GPL), version 2
  5. */
  6. #include <linux/kernel.h>
  7. #include <linux/clocksource.h>
  8. #include <linux/clockchips.h>
  9. #include <linux/io.h>
  10. #include <linux/of.h>
  11. #include <linux/of_address.h>
  12. #include <linux/clk.h>
  13. #include <linux/bitops.h>
  14. #define SYST_CSR 0x00
  15. #define SYST_RVR 0x04
  16. #define SYST_CVR 0x08
  17. #define SYST_CALIB 0x0c
  18. #define SYST_CSR_ENABLE BIT(0)
  19. #define SYSTICK_LOAD_RELOAD_MASK 0x00FFFFFF
  20. static int __init system_timer_of_register(struct device_node *np)
  21. {
  22. struct clk *clk = NULL;
  23. void __iomem *base;
  24. u32 rate;
  25. int ret;
  26. base = of_iomap(np, 0);
  27. if (!base) {
  28. pr_warn("system-timer: invalid base address\n");
  29. return -ENXIO;
  30. }
  31. ret = of_property_read_u32(np, "clock-frequency", &rate);
  32. if (ret) {
  33. clk = of_clk_get(np, 0);
  34. if (IS_ERR(clk)) {
  35. ret = PTR_ERR(clk);
  36. goto out_unmap;
  37. }
  38. ret = clk_prepare_enable(clk);
  39. if (ret)
  40. goto out_clk_put;
  41. rate = clk_get_rate(clk);
  42. if (!rate) {
  43. ret = -EINVAL;
  44. goto out_clk_disable;
  45. }
  46. }
  47. writel_relaxed(SYSTICK_LOAD_RELOAD_MASK, base + SYST_RVR);
  48. writel_relaxed(SYST_CSR_ENABLE, base + SYST_CSR);
  49. ret = clocksource_mmio_init(base + SYST_CVR, "arm_system_timer", rate,
  50. 200, 24, clocksource_mmio_readl_down);
  51. if (ret) {
  52. pr_err("failed to init clocksource (%d)\n", ret);
  53. if (clk)
  54. goto out_clk_disable;
  55. else
  56. goto out_unmap;
  57. }
  58. pr_info("ARM System timer initialized as clocksource\n");
  59. return 0;
  60. out_clk_disable:
  61. clk_disable_unprepare(clk);
  62. out_clk_put:
  63. clk_put(clk);
  64. out_unmap:
  65. iounmap(base);
  66. pr_warn("ARM System timer register failed (%d)\n", ret);
  67. return ret;
  68. }
  69. CLOCKSOURCE_OF_DECLARE(arm_systick, "arm,armv7m-systick",
  70. system_timer_of_register);