clk-pll-out.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
  4. */
  5. #include <linux/kernel.h>
  6. #include <linux/io.h>
  7. #include <linux/err.h>
  8. #include <linux/delay.h>
  9. #include <linux/slab.h>
  10. #include <linux/clk-provider.h>
  11. #include "clk.h"
  12. #define pll_out_enb(p) (BIT(p->enb_bit_idx))
  13. #define pll_out_rst(p) (BIT(p->rst_bit_idx))
  14. static int clk_pll_out_is_enabled(struct clk_hw *hw)
  15. {
  16. struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw);
  17. u32 val = readl_relaxed(pll_out->reg);
  18. int state;
  19. state = (val & pll_out_enb(pll_out)) ? 1 : 0;
  20. if (!(val & (pll_out_rst(pll_out))))
  21. state = 0;
  22. return state;
  23. }
  24. static int clk_pll_out_enable(struct clk_hw *hw)
  25. {
  26. struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw);
  27. unsigned long flags = 0;
  28. u32 val;
  29. if (pll_out->lock)
  30. spin_lock_irqsave(pll_out->lock, flags);
  31. val = readl_relaxed(pll_out->reg);
  32. val |= (pll_out_enb(pll_out) | pll_out_rst(pll_out));
  33. writel_relaxed(val, pll_out->reg);
  34. udelay(2);
  35. if (pll_out->lock)
  36. spin_unlock_irqrestore(pll_out->lock, flags);
  37. return 0;
  38. }
  39. static void clk_pll_out_disable(struct clk_hw *hw)
  40. {
  41. struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw);
  42. unsigned long flags = 0;
  43. u32 val;
  44. if (pll_out->lock)
  45. spin_lock_irqsave(pll_out->lock, flags);
  46. val = readl_relaxed(pll_out->reg);
  47. val &= ~(pll_out_enb(pll_out) | pll_out_rst(pll_out));
  48. writel_relaxed(val, pll_out->reg);
  49. udelay(2);
  50. if (pll_out->lock)
  51. spin_unlock_irqrestore(pll_out->lock, flags);
  52. }
  53. static void tegra_clk_pll_out_restore_context(struct clk_hw *hw)
  54. {
  55. if (!__clk_get_enable_count(hw->clk))
  56. clk_pll_out_disable(hw);
  57. else
  58. clk_pll_out_enable(hw);
  59. }
  60. const struct clk_ops tegra_clk_pll_out_ops = {
  61. .is_enabled = clk_pll_out_is_enabled,
  62. .enable = clk_pll_out_enable,
  63. .disable = clk_pll_out_disable,
  64. .restore_context = tegra_clk_pll_out_restore_context,
  65. };
  66. struct clk *tegra_clk_register_pll_out(const char *name,
  67. const char *parent_name, void __iomem *reg, u8 enb_bit_idx,
  68. u8 rst_bit_idx, unsigned long flags, u8 pll_out_flags,
  69. spinlock_t *lock)
  70. {
  71. struct tegra_clk_pll_out *pll_out;
  72. struct clk *clk;
  73. struct clk_init_data init;
  74. pll_out = kzalloc(sizeof(*pll_out), GFP_KERNEL);
  75. if (!pll_out)
  76. return ERR_PTR(-ENOMEM);
  77. init.name = name;
  78. init.ops = &tegra_clk_pll_out_ops;
  79. init.parent_names = (parent_name ? &parent_name : NULL);
  80. init.num_parents = (parent_name ? 1 : 0);
  81. init.flags = flags;
  82. pll_out->reg = reg;
  83. pll_out->enb_bit_idx = enb_bit_idx;
  84. pll_out->rst_bit_idx = rst_bit_idx;
  85. pll_out->flags = pll_out_flags;
  86. pll_out->lock = lock;
  87. /* Data in .init is copied by clk_register(), so stack variable OK */
  88. pll_out->hw.init = &init;
  89. clk = clk_register(NULL, &pll_out->hw);
  90. if (IS_ERR(clk))
  91. kfree(pll_out);
  92. return clk;
  93. }