clk-apbc.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * mmp APB clock operation source file
  4. *
  5. * Copyright (C) 2012 Marvell
  6. * Chao Xie <[email protected]>
  7. */
  8. #include <linux/kernel.h>
  9. #include <linux/io.h>
  10. #include <linux/err.h>
  11. #include <linux/delay.h>
  12. #include <linux/slab.h>
  13. #include "clk.h"
  14. /* Common APB clock register bit definitions */
  15. #define APBC_APBCLK (1 << 0) /* APB Bus Clock Enable */
  16. #define APBC_FNCLK (1 << 1) /* Functional Clock Enable */
  17. #define APBC_RST (1 << 2) /* Reset Generation */
  18. #define APBC_POWER (1 << 7) /* Reset Generation */
  19. #define to_clk_apbc(hw) container_of(hw, struct clk_apbc, hw)
  20. struct clk_apbc {
  21. struct clk_hw hw;
  22. void __iomem *base;
  23. unsigned int delay;
  24. unsigned int flags;
  25. spinlock_t *lock;
  26. };
  27. static int clk_apbc_prepare(struct clk_hw *hw)
  28. {
  29. struct clk_apbc *apbc = to_clk_apbc(hw);
  30. unsigned int data;
  31. unsigned long flags = 0;
  32. /*
  33. * It may share same register as MUX clock,
  34. * and it will impact FNCLK enable. Spinlock is needed
  35. */
  36. if (apbc->lock)
  37. spin_lock_irqsave(apbc->lock, flags);
  38. data = readl_relaxed(apbc->base);
  39. if (apbc->flags & APBC_POWER_CTRL)
  40. data |= APBC_POWER;
  41. data |= APBC_FNCLK;
  42. writel_relaxed(data, apbc->base);
  43. if (apbc->lock)
  44. spin_unlock_irqrestore(apbc->lock, flags);
  45. udelay(apbc->delay);
  46. if (apbc->lock)
  47. spin_lock_irqsave(apbc->lock, flags);
  48. data = readl_relaxed(apbc->base);
  49. data |= APBC_APBCLK;
  50. writel_relaxed(data, apbc->base);
  51. if (apbc->lock)
  52. spin_unlock_irqrestore(apbc->lock, flags);
  53. udelay(apbc->delay);
  54. if (!(apbc->flags & APBC_NO_BUS_CTRL)) {
  55. if (apbc->lock)
  56. spin_lock_irqsave(apbc->lock, flags);
  57. data = readl_relaxed(apbc->base);
  58. data &= ~APBC_RST;
  59. writel_relaxed(data, apbc->base);
  60. if (apbc->lock)
  61. spin_unlock_irqrestore(apbc->lock, flags);
  62. }
  63. return 0;
  64. }
  65. static void clk_apbc_unprepare(struct clk_hw *hw)
  66. {
  67. struct clk_apbc *apbc = to_clk_apbc(hw);
  68. unsigned long data;
  69. unsigned long flags = 0;
  70. if (apbc->lock)
  71. spin_lock_irqsave(apbc->lock, flags);
  72. data = readl_relaxed(apbc->base);
  73. if (apbc->flags & APBC_POWER_CTRL)
  74. data &= ~APBC_POWER;
  75. data &= ~APBC_FNCLK;
  76. writel_relaxed(data, apbc->base);
  77. if (apbc->lock)
  78. spin_unlock_irqrestore(apbc->lock, flags);
  79. udelay(10);
  80. if (apbc->lock)
  81. spin_lock_irqsave(apbc->lock, flags);
  82. data = readl_relaxed(apbc->base);
  83. data &= ~APBC_APBCLK;
  84. writel_relaxed(data, apbc->base);
  85. if (apbc->lock)
  86. spin_unlock_irqrestore(apbc->lock, flags);
  87. }
  88. static const struct clk_ops clk_apbc_ops = {
  89. .prepare = clk_apbc_prepare,
  90. .unprepare = clk_apbc_unprepare,
  91. };
  92. struct clk *mmp_clk_register_apbc(const char *name, const char *parent_name,
  93. void __iomem *base, unsigned int delay,
  94. unsigned int apbc_flags, spinlock_t *lock)
  95. {
  96. struct clk_apbc *apbc;
  97. struct clk *clk;
  98. struct clk_init_data init;
  99. apbc = kzalloc(sizeof(*apbc), GFP_KERNEL);
  100. if (!apbc)
  101. return NULL;
  102. init.name = name;
  103. init.ops = &clk_apbc_ops;
  104. init.flags = CLK_SET_RATE_PARENT;
  105. init.parent_names = (parent_name ? &parent_name : NULL);
  106. init.num_parents = (parent_name ? 1 : 0);
  107. apbc->base = base;
  108. apbc->delay = delay;
  109. apbc->flags = apbc_flags;
  110. apbc->lock = lock;
  111. apbc->hw.init = &init;
  112. clk = clk_register(NULL, &apbc->hw);
  113. if (IS_ERR(clk))
  114. kfree(apbc);
  115. return clk;
  116. }