clk-vexpress-osc.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /*
  2. * This program is free software; you can redistribute it and/or modify
  3. * it under the terms of the GNU General Public License version 2 as
  4. * published by the Free Software Foundation.
  5. *
  6. * This program is distributed in the hope that it will be useful,
  7. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. * GNU General Public License for more details.
  10. *
  11. * Copyright (C) 2012 ARM Limited
  12. */
  13. #define pr_fmt(fmt) "vexpress-osc: " fmt
  14. #include <linux/clkdev.h>
  15. #include <linux/clk-provider.h>
  16. #include <linux/err.h>
  17. #include <linux/of.h>
  18. #include <linux/platform_device.h>
  19. #include <linux/slab.h>
  20. #include <linux/vexpress.h>
  21. struct vexpress_osc {
  22. struct vexpress_config_func *func;
  23. struct clk_hw hw;
  24. unsigned long rate_min;
  25. unsigned long rate_max;
  26. };
  27. #define to_vexpress_osc(osc) container_of(osc, struct vexpress_osc, hw)
  28. static unsigned long vexpress_osc_recalc_rate(struct clk_hw *hw,
  29. unsigned long parent_rate)
  30. {
  31. struct vexpress_osc *osc = to_vexpress_osc(hw);
  32. u32 rate;
  33. vexpress_config_read(osc->func, 0, &rate);
  34. return rate;
  35. }
  36. static long vexpress_osc_round_rate(struct clk_hw *hw, unsigned long rate,
  37. unsigned long *parent_rate)
  38. {
  39. struct vexpress_osc *osc = to_vexpress_osc(hw);
  40. if (WARN_ON(osc->rate_min && rate < osc->rate_min))
  41. rate = osc->rate_min;
  42. if (WARN_ON(osc->rate_max && rate > osc->rate_max))
  43. rate = osc->rate_max;
  44. return rate;
  45. }
  46. static int vexpress_osc_set_rate(struct clk_hw *hw, unsigned long rate,
  47. unsigned long parent_rate)
  48. {
  49. struct vexpress_osc *osc = to_vexpress_osc(hw);
  50. return vexpress_config_write(osc->func, 0, rate);
  51. }
  52. static struct clk_ops vexpress_osc_ops = {
  53. .recalc_rate = vexpress_osc_recalc_rate,
  54. .round_rate = vexpress_osc_round_rate,
  55. .set_rate = vexpress_osc_set_rate,
  56. };
  57. struct clk * __init vexpress_osc_setup(struct device *dev)
  58. {
  59. struct clk_init_data init;
  60. struct vexpress_osc *osc = kzalloc(sizeof(*osc), GFP_KERNEL);
  61. if (!osc)
  62. return NULL;
  63. osc->func = vexpress_config_func_get_by_dev(dev);
  64. if (!osc->func) {
  65. kfree(osc);
  66. return NULL;
  67. }
  68. init.name = dev_name(dev);
  69. init.ops = &vexpress_osc_ops;
  70. init.flags = CLK_IS_ROOT;
  71. init.num_parents = 0;
  72. osc->hw.init = &init;
  73. return clk_register(NULL, &osc->hw);
  74. }
  75. void __init vexpress_osc_of_setup(struct device_node *node)
  76. {
  77. struct clk_init_data init;
  78. struct vexpress_osc *osc;
  79. struct clk *clk;
  80. u32 range[2];
  81. osc = kzalloc(sizeof(*osc), GFP_KERNEL);
  82. if (!osc)
  83. goto error;
  84. osc->func = vexpress_config_func_get_by_node(node);
  85. if (!osc->func) {
  86. pr_err("Failed to obtain config func for node '%s'!\n",
  87. node->name);
  88. goto error;
  89. }
  90. if (of_property_read_u32_array(node, "freq-range", range,
  91. ARRAY_SIZE(range)) == 0) {
  92. osc->rate_min = range[0];
  93. osc->rate_max = range[1];
  94. }
  95. of_property_read_string(node, "clock-output-names", &init.name);
  96. if (!init.name)
  97. init.name = node->name;
  98. init.ops = &vexpress_osc_ops;
  99. init.flags = CLK_IS_ROOT;
  100. init.num_parents = 0;
  101. osc->hw.init = &init;
  102. clk = clk_register(NULL, &osc->hw);
  103. if (IS_ERR(clk)) {
  104. pr_err("Failed to register clock '%s'!\n", init.name);
  105. goto error;
  106. }
  107. of_clk_add_provider(node, of_clk_src_simple_get, clk);
  108. pr_debug("Registered clock '%s'\n", init.name);
  109. return;
  110. error:
  111. if (osc->func)
  112. vexpress_config_func_put(osc->func);
  113. kfree(osc);
  114. }
  115. CLK_OF_DECLARE(vexpress_soc, "arm,vexpress-osc", vexpress_osc_of_setup);