ccu_frac.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. /*
  2. * Copyright (C) 2016 Maxime Ripard
  3. * Maxime Ripard <maxime.ripard@free-electrons.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or (at your option) any later version.
  9. */
  10. #include <linux/clk-provider.h>
  11. #include <linux/spinlock.h>
  12. #include "ccu_frac.h"
  13. bool ccu_frac_helper_is_enabled(struct ccu_common *common,
  14. struct _ccu_frac *cf)
  15. {
  16. if (!(common->features & CCU_FEATURE_FRACTIONAL))
  17. return false;
  18. return !(readl(common->base + common->reg) & cf->enable);
  19. }
  20. void ccu_frac_helper_enable(struct ccu_common *common,
  21. struct _ccu_frac *cf)
  22. {
  23. unsigned long flags;
  24. u32 reg;
  25. if (!(common->features & CCU_FEATURE_FRACTIONAL))
  26. return;
  27. spin_lock_irqsave(common->lock, flags);
  28. reg = readl(common->base + common->reg);
  29. writel(reg & ~cf->enable, common->base + common->reg);
  30. spin_unlock_irqrestore(common->lock, flags);
  31. }
  32. void ccu_frac_helper_disable(struct ccu_common *common,
  33. struct _ccu_frac *cf)
  34. {
  35. unsigned long flags;
  36. u32 reg;
  37. if (!(common->features & CCU_FEATURE_FRACTIONAL))
  38. return;
  39. spin_lock_irqsave(common->lock, flags);
  40. reg = readl(common->base + common->reg);
  41. writel(reg | cf->enable, common->base + common->reg);
  42. spin_unlock_irqrestore(common->lock, flags);
  43. }
  44. bool ccu_frac_helper_has_rate(struct ccu_common *common,
  45. struct _ccu_frac *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. unsigned long ccu_frac_helper_read_rate(struct ccu_common *common,
  53. struct _ccu_frac *cf)
  54. {
  55. u32 reg;
  56. printk("%s: Read fractional\n", clk_hw_get_name(&common->hw));
  57. if (!(common->features & CCU_FEATURE_FRACTIONAL))
  58. return 0;
  59. printk("%s: clock is fractional (rates %lu and %lu)\n",
  60. clk_hw_get_name(&common->hw), cf->rates[0], cf->rates[1]);
  61. reg = readl(common->base + common->reg);
  62. printk("%s: clock reg is 0x%x (select is 0x%x)\n",
  63. clk_hw_get_name(&common->hw), reg, cf->select);
  64. return (reg & cf->select) ? cf->rates[1] : cf->rates[0];
  65. }
  66. int ccu_frac_helper_set_rate(struct ccu_common *common,
  67. struct _ccu_frac *cf,
  68. unsigned long rate)
  69. {
  70. unsigned long flags;
  71. u32 reg, sel;
  72. if (!(common->features & CCU_FEATURE_FRACTIONAL))
  73. return -EINVAL;
  74. if (cf->rates[0] == rate)
  75. sel = 0;
  76. else if (cf->rates[1] == rate)
  77. sel = cf->select;
  78. else
  79. return -EINVAL;
  80. spin_lock_irqsave(common->lock, flags);
  81. reg = readl(common->base + common->reg);
  82. reg &= ~cf->select;
  83. writel(reg | sel, common->base + common->reg);
  84. spin_unlock_irqrestore(common->lock, flags);
  85. return 0;
  86. }