clk-frac.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright 2012 Freescale Semiconductor, Inc.
  4. */
  5. #include <linux/clk-provider.h>
  6. #include <linux/err.h>
  7. #include <linux/io.h>
  8. #include <linux/slab.h>
  9. #include "clk.h"
  10. /**
  11. * struct clk_frac - mxs fractional divider clock
  12. * @hw: clk_hw for the fractional divider clock
  13. * @reg: register address
  14. * @shift: the divider bit shift
  15. * @width: the divider bit width
  16. * @busy: busy bit shift
  17. *
  18. * The clock is an adjustable fractional divider with a busy bit to wait
  19. * when the divider is adjusted.
  20. */
  21. struct clk_frac {
  22. struct clk_hw hw;
  23. void __iomem *reg;
  24. u8 shift;
  25. u8 width;
  26. u8 busy;
  27. };
  28. #define to_clk_frac(_hw) container_of(_hw, struct clk_frac, hw)
  29. static unsigned long clk_frac_recalc_rate(struct clk_hw *hw,
  30. unsigned long parent_rate)
  31. {
  32. struct clk_frac *frac = to_clk_frac(hw);
  33. u32 div;
  34. u64 tmp_rate;
  35. div = readl_relaxed(frac->reg) >> frac->shift;
  36. div &= (1 << frac->width) - 1;
  37. tmp_rate = (u64)parent_rate * div;
  38. return tmp_rate >> frac->width;
  39. }
  40. static long clk_frac_round_rate(struct clk_hw *hw, unsigned long rate,
  41. unsigned long *prate)
  42. {
  43. struct clk_frac *frac = to_clk_frac(hw);
  44. unsigned long parent_rate = *prate;
  45. u32 div;
  46. u64 tmp, tmp_rate, result;
  47. if (rate > parent_rate)
  48. return -EINVAL;
  49. tmp = rate;
  50. tmp <<= frac->width;
  51. do_div(tmp, parent_rate);
  52. div = tmp;
  53. if (!div)
  54. return -EINVAL;
  55. tmp_rate = (u64)parent_rate * div;
  56. result = tmp_rate >> frac->width;
  57. if ((result << frac->width) < tmp_rate)
  58. result += 1;
  59. return result;
  60. }
  61. static int clk_frac_set_rate(struct clk_hw *hw, unsigned long rate,
  62. unsigned long parent_rate)
  63. {
  64. struct clk_frac *frac = to_clk_frac(hw);
  65. unsigned long flags;
  66. u32 div, val;
  67. u64 tmp;
  68. if (rate > parent_rate)
  69. return -EINVAL;
  70. tmp = rate;
  71. tmp <<= frac->width;
  72. do_div(tmp, parent_rate);
  73. div = tmp;
  74. if (!div)
  75. return -EINVAL;
  76. spin_lock_irqsave(&mxs_lock, flags);
  77. val = readl_relaxed(frac->reg);
  78. val &= ~(((1 << frac->width) - 1) << frac->shift);
  79. val |= div << frac->shift;
  80. writel_relaxed(val, frac->reg);
  81. spin_unlock_irqrestore(&mxs_lock, flags);
  82. return mxs_clk_wait(frac->reg, frac->busy);
  83. }
  84. static const struct clk_ops clk_frac_ops = {
  85. .recalc_rate = clk_frac_recalc_rate,
  86. .round_rate = clk_frac_round_rate,
  87. .set_rate = clk_frac_set_rate,
  88. };
  89. struct clk *mxs_clk_frac(const char *name, const char *parent_name,
  90. void __iomem *reg, u8 shift, u8 width, u8 busy)
  91. {
  92. struct clk_frac *frac;
  93. struct clk *clk;
  94. struct clk_init_data init;
  95. frac = kzalloc(sizeof(*frac), GFP_KERNEL);
  96. if (!frac)
  97. return ERR_PTR(-ENOMEM);
  98. init.name = name;
  99. init.ops = &clk_frac_ops;
  100. init.flags = CLK_SET_RATE_PARENT;
  101. init.parent_names = (parent_name ? &parent_name: NULL);
  102. init.num_parents = (parent_name ? 1 : 0);
  103. frac->reg = reg;
  104. frac->shift = shift;
  105. frac->width = width;
  106. frac->busy = busy;
  107. frac->hw.init = &init;
  108. clk = clk_register(NULL, &frac->hw);
  109. if (IS_ERR(clk))
  110. kfree(frac);
  111. return clk;
  112. }