1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2016 Maxime Ripard
4 * Maxime Ripard <maxime.ripard@free-electrons.com>
5 */
6 #include "ccu.h"
7 #include "ccu_gate.h"
8
ccu_gate_helper_disable(struct ccu_common * common,u32 gate)9 void ccu_gate_helper_disable(struct ccu_common *common, u32 gate)
10 {
11 u32 reg;
12 u32 __cspr;
13
14 if (!gate)
15 {
16 return;
17 }
18
19 __cspr = hal_spin_lock_irqsave(&common->lock);
20
21 reg = readl(common->base + common->reg);
22 writel(reg & ~gate, common->base + common->reg);
23
24 hal_spin_unlock_irqrestore(&common->lock, __cspr);
25 }
26
ccu_gate_disable(struct clk_hw * hw)27 static void ccu_gate_disable(struct clk_hw *hw)
28 {
29 struct ccu_gate *cg = hw_to_ccu_gate(hw);
30
31 return ccu_gate_helper_disable(&cg->common, cg->enable);
32 }
33
ccu_gate_helper_enable(struct ccu_common * common,u32 gate)34 int ccu_gate_helper_enable(struct ccu_common *common, u32 gate)
35 {
36 u32 reg;
37 u32 __cspr;
38
39 if (!gate)
40 {
41 return 0;
42 }
43
44 __cspr = hal_spin_lock_irqsave(&common->lock);
45
46 reg = readl(common->base + common->reg);
47 writel(reg | gate, common->base + common->reg);
48
49 hal_spin_unlock_irqrestore(&common->lock, __cspr);
50
51 return 0;
52 }
53
ccu_gate_enable(struct clk_hw * hw)54 static int ccu_gate_enable(struct clk_hw *hw)
55 {
56 struct ccu_gate *cg = hw_to_ccu_gate(hw);
57
58 return ccu_gate_helper_enable(&cg->common, cg->enable);
59 }
60
ccu_gate_helper_is_enabled(struct ccu_common * common,u32 gate)61 int ccu_gate_helper_is_enabled(struct ccu_common *common, u32 gate)
62 {
63 u32 value;
64
65 if (!gate)
66 {
67 return 1;
68 }
69
70 value = readl(common->base + common->reg);
71 return !!(value & gate);
72 }
73
ccu_gate_is_enabled(struct clk_hw * hw)74 static int ccu_gate_is_enabled(struct clk_hw *hw)
75 {
76 struct ccu_gate *cg = hw_to_ccu_gate(hw);
77
78 return ccu_gate_helper_is_enabled(&cg->common, cg->enable);
79 }
80
ccu_gate_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)81 static unsigned long ccu_gate_recalc_rate(struct clk_hw *hw,
82 unsigned long parent_rate)
83 {
84 struct ccu_gate *cg = hw_to_ccu_gate(hw);
85 unsigned long rate = parent_rate;
86
87 if (cg->common.features & CCU_FEATURE_ALL_PREDIV)
88 {
89 rate /= cg->common.prediv;
90 }
91
92 return rate;
93 }
94
ccu_gate_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * prate)95 static long ccu_gate_round_rate(struct clk_hw *hw, unsigned long rate,
96 unsigned long *prate)
97 {
98 struct ccu_gate *cg = hw_to_ccu_gate(hw);
99 int div = 1;
100
101 if (cg->common.features & CCU_FEATURE_ALL_PREDIV)
102 {
103 div = cg->common.prediv;
104 }
105
106 if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)
107 {
108 unsigned long best_parent = rate;
109
110 if (cg->common.features & CCU_FEATURE_ALL_PREDIV)
111 {
112 best_parent *= div;
113 }
114 *prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
115 }
116
117 return *prate / div;
118 }
119
ccu_gate_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)120 static int ccu_gate_set_rate(struct clk_hw *hw, unsigned long rate,
121 unsigned long parent_rate)
122 {
123 /*
124 * We must report success but we can do so unconditionally because
125 * clk_factor_round_rate returns values that ensure this call is a
126 * nop.
127 */
128
129 return 0;
130 }
131
132 const struct clk_ops ccu_gate_ops =
133 {
134 .disable = ccu_gate_disable,
135 .enable = ccu_gate_enable,
136 .is_enabled = ccu_gate_is_enabled,
137 .round_rate = ccu_gate_round_rate,
138 .set_rate = ccu_gate_set_rate,
139 .recalc_rate = ccu_gate_recalc_rate,
140 };
141