clk-icst.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. /*
  2. * Driver for the ICST307 VCO clock found in the ARM Reference designs.
  3. * We wrap the custom interface from <asm/hardware/icst.h> into the generic
  4. * clock framework.
  5. *
  6. * TODO: when all ARM reference designs are migrated to generic clocks, the
  7. * ICST clock code from the ARM tree should probably be merged into this
  8. * file.
  9. */
  10. #include <linux/clk.h>
  11. #include <linux/clkdev.h>
  12. #include <linux/err.h>
  13. #include <linux/clk-provider.h>
  14. #include "clk-icst.h"
  15. /**
  16. * struct clk_icst - ICST VCO clock wrapper
  17. * @hw: corresponding clock hardware entry
  18. * @params: parameters for this ICST instance
  19. * @rate: current rate
  20. * @setvco: function to commit ICST settings to hardware
  21. */
  22. struct clk_icst {
  23. struct clk_hw hw;
  24. const struct icst_params *params;
  25. unsigned long rate;
  26. struct icst_vco (*getvco)(void);
  27. void (*setvco)(struct icst_vco);
  28. };
  29. #define to_icst(_hw) container_of(_hw, struct clk_icst, hw)
  30. static unsigned long icst_recalc_rate(struct clk_hw *hw,
  31. unsigned long parent_rate)
  32. {
  33. struct clk_icst *icst = to_icst(hw);
  34. struct icst_vco vco;
  35. vco = icst->getvco();
  36. icst->rate = icst_hz(icst->params, vco);
  37. return icst->rate;
  38. }
  39. static long icst_round_rate(struct clk_hw *hw, unsigned long rate,
  40. unsigned long *prate)
  41. {
  42. struct clk_icst *icst = to_icst(hw);
  43. struct icst_vco vco;
  44. vco = icst_hz_to_vco(icst->params, rate);
  45. return icst_hz(icst->params, vco);
  46. }
  47. static int icst_set_rate(struct clk_hw *hw, unsigned long rate,
  48. unsigned long parent_rate)
  49. {
  50. struct clk_icst *icst = to_icst(hw);
  51. struct icst_vco vco;
  52. vco = icst_hz_to_vco(icst->params, rate);
  53. icst->rate = icst_hz(icst->params, vco);
  54. icst->setvco(vco);
  55. return 0;
  56. }
  57. static const struct clk_ops icst_ops = {
  58. .recalc_rate = icst_recalc_rate,
  59. .round_rate = icst_round_rate,
  60. .set_rate = icst_set_rate,
  61. };
  62. struct clk * __init icst_clk_register(struct device *dev,
  63. const struct clk_icst_desc *desc)
  64. {
  65. struct clk *clk;
  66. struct clk_icst *icst;
  67. struct clk_init_data init;
  68. icst = kzalloc(sizeof(struct clk_icst), GFP_KERNEL);
  69. if (!icst) {
  70. pr_err("could not allocate ICST clock!\n");
  71. return ERR_PTR(-ENOMEM);
  72. }
  73. init.name = "icst";
  74. init.ops = &icst_ops;
  75. init.flags = CLK_IS_ROOT;
  76. init.parent_names = NULL;
  77. init.num_parents = 0;
  78. icst->hw.init = &init;
  79. icst->params = desc->params;
  80. icst->getvco = desc->getvco;
  81. icst->setvco = desc->setvco;
  82. clk = clk_register(dev, &icst->hw);
  83. if (IS_ERR(clk))
  84. kfree(icst);
  85. return clk;
  86. }