1 // SPDX-License-Identifier: GPL-2.0-only
3 * mmp APB clock operation source file
5 * Copyright (C) 2012 Marvell
6 * Chao Xie <xiechao.mail@gmail.com>
9 #include <linux/kernel.h>
11 #include <linux/err.h>
12 #include <linux/delay.h>
13 #include <linux/slab.h>
17 /* Common APB clock register bit definitions */
18 #define APBC_APBCLK (1 << 0) /* APB Bus Clock Enable */
19 #define APBC_FNCLK (1 << 1) /* Functional Clock Enable */
20 #define APBC_RST (1 << 2) /* Reset Generation */
21 #define APBC_POWER (1 << 7) /* Reset Generation */
23 #define to_clk_apbc(hw) container_of(hw, struct clk_apbc, hw)
32 static int clk_apbc_prepare(struct clk_hw *hw)
34 struct clk_apbc *apbc = to_clk_apbc(hw);
36 unsigned long flags = 0;
39 * It may share same register as MUX clock,
40 * and it will impact FNCLK enable. Spinlock is needed
43 spin_lock_irqsave(apbc->lock, flags);
45 data = readl_relaxed(apbc->base);
46 if (apbc->flags & APBC_POWER_CTRL)
49 writel_relaxed(data, apbc->base);
52 spin_unlock_irqrestore(apbc->lock, flags);
57 spin_lock_irqsave(apbc->lock, flags);
59 data = readl_relaxed(apbc->base);
61 writel_relaxed(data, apbc->base);
64 spin_unlock_irqrestore(apbc->lock, flags);
68 if (!(apbc->flags & APBC_NO_BUS_CTRL)) {
70 spin_lock_irqsave(apbc->lock, flags);
72 data = readl_relaxed(apbc->base);
74 writel_relaxed(data, apbc->base);
77 spin_unlock_irqrestore(apbc->lock, flags);
83 static void clk_apbc_unprepare(struct clk_hw *hw)
85 struct clk_apbc *apbc = to_clk_apbc(hw);
87 unsigned long flags = 0;
90 spin_lock_irqsave(apbc->lock, flags);
92 data = readl_relaxed(apbc->base);
93 if (apbc->flags & APBC_POWER_CTRL)
96 writel_relaxed(data, apbc->base);
99 spin_unlock_irqrestore(apbc->lock, flags);
104 spin_lock_irqsave(apbc->lock, flags);
106 data = readl_relaxed(apbc->base);
107 data &= ~APBC_APBCLK;
108 writel_relaxed(data, apbc->base);
111 spin_unlock_irqrestore(apbc->lock, flags);
114 static const struct clk_ops clk_apbc_ops = {
115 .prepare = clk_apbc_prepare,
116 .unprepare = clk_apbc_unprepare,
119 struct clk *mmp_clk_register_apbc(const char *name, const char *parent_name,
120 void __iomem *base, unsigned int delay,
121 unsigned int apbc_flags, spinlock_t *lock)
123 struct clk_apbc *apbc;
125 struct clk_init_data init;
127 apbc = kzalloc(sizeof(*apbc), GFP_KERNEL);
132 init.ops = &clk_apbc_ops;
133 init.flags = CLK_SET_RATE_PARENT;
134 init.parent_names = (parent_name ? &parent_name : NULL);
135 init.num_parents = (parent_name ? 1 : 0);
139 apbc->flags = apbc_flags;
141 apbc->hw.init = &init;
143 clk = clk_register(NULL, &apbc->hw);