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