ccu_frac.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (C) 2016 Maxime Ripard
  4. * Maxime Ripard <[email protected]>
  5. */
  6. #include <linux/clk-provider.h>
  7. #include <linux/io.h>
  8. #include <linux/spinlock.h>
  9. #include "ccu_frac.h"
  10. bool ccu_frac_helper_is_enabled(struct ccu_common *common,
  11. struct ccu_frac_internal *cf)
  12. {
  13. if (!(common->features & CCU_FEATURE_FRACTIONAL))
  14. return false;
  15. return !(readl(common->base + common->reg) & cf->enable);
  16. }
  17. EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_is_enabled, SUNXI_CCU);
  18. void ccu_frac_helper_enable(struct ccu_common *common,
  19. struct ccu_frac_internal *cf)
  20. {
  21. unsigned long flags;
  22. u32 reg;
  23. if (!(common->features & CCU_FEATURE_FRACTIONAL))
  24. return;
  25. spin_lock_irqsave(common->lock, flags);
  26. reg = readl(common->base + common->reg);
  27. writel(reg & ~cf->enable, common->base + common->reg);
  28. spin_unlock_irqrestore(common->lock, flags);
  29. }
  30. EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_enable, SUNXI_CCU);
  31. void ccu_frac_helper_disable(struct ccu_common *common,
  32. struct ccu_frac_internal *cf)
  33. {
  34. unsigned long flags;
  35. u32 reg;
  36. if (!(common->features & CCU_FEATURE_FRACTIONAL))
  37. return;
  38. spin_lock_irqsave(common->lock, flags);
  39. reg = readl(common->base + common->reg);
  40. writel(reg | cf->enable, common->base + common->reg);
  41. spin_unlock_irqrestore(common->lock, flags);
  42. }
  43. EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_disable, SUNXI_CCU);
  44. bool ccu_frac_helper_has_rate(struct ccu_common *common,
  45. struct ccu_frac_internal *cf,
  46. unsigned long rate)
  47. {
  48. if (!(common->features & CCU_FEATURE_FRACTIONAL))
  49. return false;
  50. return (cf->rates[0] == rate) || (cf->rates[1] == rate);
  51. }
  52. EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_has_rate, SUNXI_CCU);
  53. unsigned long ccu_frac_helper_read_rate(struct ccu_common *common,
  54. struct ccu_frac_internal *cf)
  55. {
  56. u32 reg;
  57. pr_debug("%s: Read fractional\n", clk_hw_get_name(&common->hw));
  58. if (!(common->features & CCU_FEATURE_FRACTIONAL))
  59. return 0;
  60. pr_debug("%s: clock is fractional (rates %lu and %lu)\n",
  61. clk_hw_get_name(&common->hw), cf->rates[0], cf->rates[1]);
  62. reg = readl(common->base + common->reg);
  63. pr_debug("%s: clock reg is 0x%x (select is 0x%x)\n",
  64. clk_hw_get_name(&common->hw), reg, cf->select);
  65. return (reg & cf->select) ? cf->rates[1] : cf->rates[0];
  66. }
  67. EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_read_rate, SUNXI_CCU);
  68. int ccu_frac_helper_set_rate(struct ccu_common *common,
  69. struct ccu_frac_internal *cf,
  70. unsigned long rate, u32 lock)
  71. {
  72. unsigned long flags;
  73. u32 reg, sel;
  74. if (!(common->features & CCU_FEATURE_FRACTIONAL))
  75. return -EINVAL;
  76. if (cf->rates[0] == rate)
  77. sel = 0;
  78. else if (cf->rates[1] == rate)
  79. sel = cf->select;
  80. else
  81. return -EINVAL;
  82. spin_lock_irqsave(common->lock, flags);
  83. reg = readl(common->base + common->reg);
  84. reg &= ~cf->select;
  85. writel(reg | sel, common->base + common->reg);
  86. spin_unlock_irqrestore(common->lock, flags);
  87. ccu_helper_wait_for_lock(common, lock);
  88. return 0;
  89. }
  90. EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_set_rate, SUNXI_CCU);