div.c 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. // SPDX-License-Identifier: GPL-2.0
  2. //
  3. // Spreadtrum divider clock driver
  4. //
  5. // Copyright (C) 2017 Spreadtrum, Inc.
  6. // Author: Chunyan Zhang <[email protected]>
  7. #include <linux/clk-provider.h>
  8. #include "div.h"
  9. long sprd_div_helper_round_rate(struct sprd_clk_common *common,
  10. const struct sprd_div_internal *div,
  11. unsigned long rate,
  12. unsigned long *parent_rate)
  13. {
  14. return divider_round_rate(&common->hw, rate, parent_rate,
  15. NULL, div->width, 0);
  16. }
  17. EXPORT_SYMBOL_GPL(sprd_div_helper_round_rate);
  18. static long sprd_div_round_rate(struct clk_hw *hw, unsigned long rate,
  19. unsigned long *parent_rate)
  20. {
  21. struct sprd_div *cd = hw_to_sprd_div(hw);
  22. return sprd_div_helper_round_rate(&cd->common, &cd->div,
  23. rate, parent_rate);
  24. }
  25. unsigned long sprd_div_helper_recalc_rate(struct sprd_clk_common *common,
  26. const struct sprd_div_internal *div,
  27. unsigned long parent_rate)
  28. {
  29. unsigned long val;
  30. unsigned int reg;
  31. regmap_read(common->regmap, common->reg, &reg);
  32. val = reg >> div->shift;
  33. val &= (1 << div->width) - 1;
  34. return divider_recalc_rate(&common->hw, parent_rate, val, NULL, 0,
  35. div->width);
  36. }
  37. EXPORT_SYMBOL_GPL(sprd_div_helper_recalc_rate);
  38. static unsigned long sprd_div_recalc_rate(struct clk_hw *hw,
  39. unsigned long parent_rate)
  40. {
  41. struct sprd_div *cd = hw_to_sprd_div(hw);
  42. return sprd_div_helper_recalc_rate(&cd->common, &cd->div, parent_rate);
  43. }
  44. int sprd_div_helper_set_rate(const struct sprd_clk_common *common,
  45. const struct sprd_div_internal *div,
  46. unsigned long rate,
  47. unsigned long parent_rate)
  48. {
  49. unsigned long val;
  50. unsigned int reg;
  51. val = divider_get_val(rate, parent_rate, NULL,
  52. div->width, 0);
  53. regmap_read(common->regmap, common->reg, &reg);
  54. reg &= ~GENMASK(div->width + div->shift - 1, div->shift);
  55. regmap_write(common->regmap, common->reg,
  56. reg | (val << div->shift));
  57. return 0;
  58. }
  59. EXPORT_SYMBOL_GPL(sprd_div_helper_set_rate);
  60. static int sprd_div_set_rate(struct clk_hw *hw, unsigned long rate,
  61. unsigned long parent_rate)
  62. {
  63. struct sprd_div *cd = hw_to_sprd_div(hw);
  64. return sprd_div_helper_set_rate(&cd->common, &cd->div,
  65. rate, parent_rate);
  66. }
  67. const struct clk_ops sprd_div_ops = {
  68. .recalc_rate = sprd_div_recalc_rate,
  69. .round_rate = sprd_div_round_rate,
  70. .set_rate = sprd_div_set_rate,
  71. };
  72. EXPORT_SYMBOL_GPL(sprd_div_ops);