clk-impd1.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Clock driver for the ARM Integrator/IM-PD1 board
  4. * Copyright (C) 2012-2013 Linus Walleij
  5. */
  6. #include <linux/clk-provider.h>
  7. #include <linux/clkdev.h>
  8. #include <linux/err.h>
  9. #include <linux/io.h>
  10. #include <linux/platform_device.h>
  11. #include <linux/module.h>
  12. #include <linux/mfd/syscon.h>
  13. #include <linux/regmap.h>
  14. #include "icst.h"
  15. #include "clk-icst.h"
  16. #define IMPD1_OSC1 0x00
  17. #define IMPD1_OSC2 0x04
  18. #define IMPD1_LOCK 0x08
  19. /*
  20. * There are two VCO's on the IM-PD1
  21. */
  22. static const struct icst_params impd1_vco1_params = {
  23. .ref = 24000000, /* 24 MHz */
  24. .vco_max = ICST525_VCO_MAX_3V,
  25. .vco_min = ICST525_VCO_MIN,
  26. .vd_min = 12,
  27. .vd_max = 519,
  28. .rd_min = 3,
  29. .rd_max = 120,
  30. .s2div = icst525_s2div,
  31. .idx2s = icst525_idx2s,
  32. };
  33. static const struct clk_icst_desc impd1_icst1_desc = {
  34. .params = &impd1_vco1_params,
  35. .vco_offset = IMPD1_OSC1,
  36. .lock_offset = IMPD1_LOCK,
  37. };
  38. static const struct icst_params impd1_vco2_params = {
  39. .ref = 24000000, /* 24 MHz */
  40. .vco_max = ICST525_VCO_MAX_3V,
  41. .vco_min = ICST525_VCO_MIN,
  42. .vd_min = 12,
  43. .vd_max = 519,
  44. .rd_min = 3,
  45. .rd_max = 120,
  46. .s2div = icst525_s2div,
  47. .idx2s = icst525_idx2s,
  48. };
  49. static const struct clk_icst_desc impd1_icst2_desc = {
  50. .params = &impd1_vco2_params,
  51. .vco_offset = IMPD1_OSC2,
  52. .lock_offset = IMPD1_LOCK,
  53. };
  54. static int integrator_impd1_clk_spawn(struct device *dev,
  55. struct device_node *parent,
  56. struct device_node *np)
  57. {
  58. struct regmap *map;
  59. struct clk *clk = ERR_PTR(-EINVAL);
  60. const char *name = np->name;
  61. const char *parent_name;
  62. const struct clk_icst_desc *desc;
  63. int ret;
  64. map = syscon_node_to_regmap(parent);
  65. if (IS_ERR(map)) {
  66. pr_err("no regmap for syscon IM-PD1 ICST clock parent\n");
  67. return PTR_ERR(map);
  68. }
  69. if (of_device_is_compatible(np, "arm,impd1-vco1")) {
  70. desc = &impd1_icst1_desc;
  71. } else if (of_device_is_compatible(np, "arm,impd1-vco2")) {
  72. desc = &impd1_icst2_desc;
  73. } else {
  74. dev_err(dev, "not a clock node %s\n", name);
  75. return -ENODEV;
  76. }
  77. of_property_read_string(np, "clock-output-names", &name);
  78. parent_name = of_clk_get_parent_name(np, 0);
  79. clk = icst_clk_setup(NULL, desc, name, parent_name, map,
  80. ICST_INTEGRATOR_IM_PD1);
  81. if (!IS_ERR(clk)) {
  82. of_clk_add_provider(np, of_clk_src_simple_get, clk);
  83. ret = 0;
  84. } else {
  85. dev_err(dev, "error setting up IM-PD1 ICST clock\n");
  86. ret = PTR_ERR(clk);
  87. }
  88. return ret;
  89. }
  90. static int integrator_impd1_clk_probe(struct platform_device *pdev)
  91. {
  92. struct device *dev = &pdev->dev;
  93. struct device_node *np = dev->of_node;
  94. struct device_node *child;
  95. int ret = 0;
  96. for_each_available_child_of_node(np, child) {
  97. ret = integrator_impd1_clk_spawn(dev, np, child);
  98. if (ret) {
  99. of_node_put(child);
  100. break;
  101. }
  102. }
  103. return ret;
  104. }
  105. static const struct of_device_id impd1_syscon_match[] = {
  106. { .compatible = "arm,im-pd1-syscon", },
  107. {}
  108. };
  109. MODULE_DEVICE_TABLE(of, impd1_syscon_match);
  110. static struct platform_driver impd1_clk_driver = {
  111. .driver = {
  112. .name = "impd1-clk",
  113. .of_match_table = impd1_syscon_match,
  114. },
  115. .probe = integrator_impd1_clk_probe,
  116. };
  117. builtin_platform_driver(impd1_clk_driver);
  118. MODULE_AUTHOR("Linus Walleij <linusw@kernel.org>");
  119. MODULE_DESCRIPTION("Arm IM-PD1 module clock driver");
  120. MODULE_LICENSE("GPL v2");