clk-periph-fixed.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /*
  2. * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved.
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms and conditions of the GNU General Public License,
  6. * version 2, as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope it will be useful, but WITHOUT
  9. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  11. * more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include <linux/clk-provider.h>
  17. #include "clk.h"
  18. static inline struct tegra_clk_periph_fixed *
  19. to_tegra_clk_periph_fixed(struct clk_hw *hw)
  20. {
  21. return container_of(hw, struct tegra_clk_periph_fixed, hw);
  22. }
  23. static int tegra_clk_periph_fixed_is_enabled(struct clk_hw *hw)
  24. {
  25. struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw);
  26. u32 mask = 1 << (fixed->num % 32), value;
  27. value = readl(fixed->base + fixed->regs->enb_reg);
  28. if (value & mask) {
  29. value = readl(fixed->base + fixed->regs->rst_reg);
  30. if ((value & mask) == 0)
  31. return 1;
  32. }
  33. return 0;
  34. }
  35. static int tegra_clk_periph_fixed_enable(struct clk_hw *hw)
  36. {
  37. struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw);
  38. u32 mask = 1 << (fixed->num % 32);
  39. writel(mask, fixed->base + fixed->regs->enb_set_reg);
  40. return 0;
  41. }
  42. static void tegra_clk_periph_fixed_disable(struct clk_hw *hw)
  43. {
  44. struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw);
  45. u32 mask = 1 << (fixed->num % 32);
  46. writel(mask, fixed->base + fixed->regs->enb_clr_reg);
  47. }
  48. static unsigned long
  49. tegra_clk_periph_fixed_recalc_rate(struct clk_hw *hw,
  50. unsigned long parent_rate)
  51. {
  52. struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw);
  53. unsigned long long rate;
  54. rate = (unsigned long long)parent_rate * fixed->mul;
  55. do_div(rate, fixed->div);
  56. return (unsigned long)rate;
  57. }
  58. static const struct clk_ops tegra_clk_periph_fixed_ops = {
  59. .is_enabled = tegra_clk_periph_fixed_is_enabled,
  60. .enable = tegra_clk_periph_fixed_enable,
  61. .disable = tegra_clk_periph_fixed_disable,
  62. .recalc_rate = tegra_clk_periph_fixed_recalc_rate,
  63. };
  64. struct clk *tegra_clk_register_periph_fixed(const char *name,
  65. const char *parent,
  66. unsigned long flags,
  67. void __iomem *base,
  68. unsigned int mul,
  69. unsigned int div,
  70. unsigned int num)
  71. {
  72. const struct tegra_clk_periph_regs *regs;
  73. struct tegra_clk_periph_fixed *fixed;
  74. struct clk_init_data init;
  75. struct clk *clk;
  76. regs = get_reg_bank(num);
  77. if (!regs)
  78. return ERR_PTR(-EINVAL);
  79. fixed = kzalloc(sizeof(*fixed), GFP_KERNEL);
  80. if (!fixed)
  81. return ERR_PTR(-ENOMEM);
  82. init.name = name;
  83. init.flags = flags;
  84. init.parent_names = parent ? &parent : NULL;
  85. init.num_parents = parent ? 1 : 0;
  86. init.ops = &tegra_clk_periph_fixed_ops;
  87. fixed->base = base;
  88. fixed->regs = regs;
  89. fixed->mul = mul;
  90. fixed->div = div;
  91. fixed->num = num;
  92. fixed->hw.init = &init;
  93. clk = clk_register(NULL, &fixed->hw);
  94. if (IS_ERR(clk))
  95. kfree(fixed);
  96. return clk;
  97. }