gate.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. // SPDX-License-Identifier: GPL-2.0
  2. //
  3. // Spreadtrum gate clock driver
  4. //
  5. // Copyright (C) 2017 Spreadtrum, Inc.
  6. // Author: Chunyan Zhang <[email protected]>
  7. #include <linux/clk-provider.h>
  8. #include <linux/regmap.h>
  9. #include "gate.h"
  10. static void clk_gate_toggle(const struct sprd_gate *sg, bool en)
  11. {
  12. const struct sprd_clk_common *common = &sg->common;
  13. unsigned int reg;
  14. bool set = sg->flags & CLK_GATE_SET_TO_DISABLE ? true : false;
  15. set ^= en;
  16. regmap_read(common->regmap, common->reg, &reg);
  17. if (set)
  18. reg |= sg->enable_mask;
  19. else
  20. reg &= ~sg->enable_mask;
  21. regmap_write(common->regmap, common->reg, reg);
  22. }
  23. static void clk_sc_gate_toggle(const struct sprd_gate *sg, bool en)
  24. {
  25. const struct sprd_clk_common *common = &sg->common;
  26. bool set = sg->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
  27. unsigned int offset;
  28. set ^= en;
  29. /*
  30. * Each set/clear gate clock has three registers:
  31. * common->reg - base register
  32. * common->reg + offset - set register
  33. * common->reg + 2 * offset - clear register
  34. */
  35. offset = set ? sg->sc_offset : sg->sc_offset * 2;
  36. regmap_write(common->regmap, common->reg + offset,
  37. sg->enable_mask);
  38. }
  39. static void sprd_gate_disable(struct clk_hw *hw)
  40. {
  41. struct sprd_gate *sg = hw_to_sprd_gate(hw);
  42. clk_gate_toggle(sg, false);
  43. }
  44. static int sprd_gate_enable(struct clk_hw *hw)
  45. {
  46. struct sprd_gate *sg = hw_to_sprd_gate(hw);
  47. clk_gate_toggle(sg, true);
  48. return 0;
  49. }
  50. static void sprd_sc_gate_disable(struct clk_hw *hw)
  51. {
  52. struct sprd_gate *sg = hw_to_sprd_gate(hw);
  53. clk_sc_gate_toggle(sg, false);
  54. }
  55. static int sprd_sc_gate_enable(struct clk_hw *hw)
  56. {
  57. struct sprd_gate *sg = hw_to_sprd_gate(hw);
  58. clk_sc_gate_toggle(sg, true);
  59. return 0;
  60. }
  61. static int sprd_pll_sc_gate_prepare(struct clk_hw *hw)
  62. {
  63. struct sprd_gate *sg = hw_to_sprd_gate(hw);
  64. clk_sc_gate_toggle(sg, true);
  65. udelay(sg->udelay);
  66. return 0;
  67. }
  68. static int sprd_gate_is_enabled(struct clk_hw *hw)
  69. {
  70. struct sprd_gate *sg = hw_to_sprd_gate(hw);
  71. struct sprd_clk_common *common = &sg->common;
  72. struct clk_hw *parent;
  73. unsigned int reg;
  74. if (sg->flags & SPRD_GATE_NON_AON) {
  75. parent = clk_hw_get_parent(hw);
  76. if (!parent || !clk_hw_is_enabled(parent))
  77. return 0;
  78. }
  79. regmap_read(common->regmap, common->reg, &reg);
  80. if (sg->flags & CLK_GATE_SET_TO_DISABLE)
  81. reg ^= sg->enable_mask;
  82. reg &= sg->enable_mask;
  83. return reg ? 1 : 0;
  84. }
  85. const struct clk_ops sprd_gate_ops = {
  86. .disable = sprd_gate_disable,
  87. .enable = sprd_gate_enable,
  88. .is_enabled = sprd_gate_is_enabled,
  89. };
  90. EXPORT_SYMBOL_GPL(sprd_gate_ops);
  91. const struct clk_ops sprd_sc_gate_ops = {
  92. .disable = sprd_sc_gate_disable,
  93. .enable = sprd_sc_gate_enable,
  94. .is_enabled = sprd_gate_is_enabled,
  95. };
  96. EXPORT_SYMBOL_GPL(sprd_sc_gate_ops);
  97. const struct clk_ops sprd_pll_sc_gate_ops = {
  98. .unprepare = sprd_sc_gate_disable,
  99. .prepare = sprd_pll_sc_gate_prepare,
  100. .is_enabled = sprd_gate_is_enabled,
  101. };
  102. EXPORT_SYMBOL_GPL(sprd_pll_sc_gate_ops);