1
2
3
4
5
6
7#include <linux/of.h>
8#include <linux/of_address.h>
9
10#include <linux/io.h>
11#include <linux/slab.h>
12#include <linux/delay.h>
13#include <linux/clkdev.h>
14
15#include "clk-mtk.h"
16#include "clk-gate.h"
17
18static int mtk_cg_bit_is_cleared(struct clk_hw *hw)
19{
20 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
21 u32 val;
22
23 regmap_read(cg->regmap, cg->sta_ofs, &val);
24
25 val &= BIT(cg->bit);
26
27 return val == 0;
28}
29
30static int mtk_cg_bit_is_set(struct clk_hw *hw)
31{
32 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
33 u32 val;
34
35 regmap_read(cg->regmap, cg->sta_ofs, &val);
36
37 val &= BIT(cg->bit);
38
39 return val != 0;
40}
41
42static void mtk_cg_set_bit(struct clk_hw *hw)
43{
44 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
45
46 regmap_write(cg->regmap, cg->set_ofs, BIT(cg->bit));
47}
48
49static void mtk_cg_clr_bit(struct clk_hw *hw)
50{
51 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
52
53 regmap_write(cg->regmap, cg->clr_ofs, BIT(cg->bit));
54}
55
56static void mtk_cg_set_bit_no_setclr(struct clk_hw *hw)
57{
58 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
59 u32 cgbit = BIT(cg->bit);
60
61 regmap_update_bits(cg->regmap, cg->sta_ofs, cgbit, cgbit);
62}
63
64static void mtk_cg_clr_bit_no_setclr(struct clk_hw *hw)
65{
66 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
67 u32 cgbit = BIT(cg->bit);
68
69 regmap_update_bits(cg->regmap, cg->sta_ofs, cgbit, 0);
70}
71
72static int mtk_cg_enable(struct clk_hw *hw)
73{
74 mtk_cg_clr_bit(hw);
75
76 return 0;
77}
78
79static void mtk_cg_disable(struct clk_hw *hw)
80{
81 mtk_cg_set_bit(hw);
82}
83
84static int mtk_cg_enable_inv(struct clk_hw *hw)
85{
86 mtk_cg_set_bit(hw);
87
88 return 0;
89}
90
91static void mtk_cg_disable_inv(struct clk_hw *hw)
92{
93 mtk_cg_clr_bit(hw);
94}
95
96static int mtk_cg_enable_no_setclr(struct clk_hw *hw)
97{
98 mtk_cg_clr_bit_no_setclr(hw);
99
100 return 0;
101}
102
103static void mtk_cg_disable_no_setclr(struct clk_hw *hw)
104{
105 mtk_cg_set_bit_no_setclr(hw);
106}
107
108static int mtk_cg_enable_inv_no_setclr(struct clk_hw *hw)
109{
110 mtk_cg_set_bit_no_setclr(hw);
111
112 return 0;
113}
114
115static void mtk_cg_disable_inv_no_setclr(struct clk_hw *hw)
116{
117 mtk_cg_clr_bit_no_setclr(hw);
118}
119
120const struct clk_ops mtk_clk_gate_ops_setclr = {
121 .is_enabled = mtk_cg_bit_is_cleared,
122 .enable = mtk_cg_enable,
123 .disable = mtk_cg_disable,
124};
125
126const struct clk_ops mtk_clk_gate_ops_setclr_inv = {
127 .is_enabled = mtk_cg_bit_is_set,
128 .enable = mtk_cg_enable_inv,
129 .disable = mtk_cg_disable_inv,
130};
131
132const struct clk_ops mtk_clk_gate_ops_no_setclr = {
133 .is_enabled = mtk_cg_bit_is_cleared,
134 .enable = mtk_cg_enable_no_setclr,
135 .disable = mtk_cg_disable_no_setclr,
136};
137
138const struct clk_ops mtk_clk_gate_ops_no_setclr_inv = {
139 .is_enabled = mtk_cg_bit_is_set,
140 .enable = mtk_cg_enable_inv_no_setclr,
141 .disable = mtk_cg_disable_inv_no_setclr,
142};
143
144struct clk *mtk_clk_register_gate(
145 const char *name,
146 const char *parent_name,
147 struct regmap *regmap,
148 int set_ofs,
149 int clr_ofs,
150 int sta_ofs,
151 u8 bit,
152 const struct clk_ops *ops,
153 unsigned long flags,
154 struct device *dev)
155{
156 struct mtk_clk_gate *cg;
157 struct clk *clk;
158 struct clk_init_data init = {};
159
160 cg = kzalloc(sizeof(*cg), GFP_KERNEL);
161 if (!cg)
162 return ERR_PTR(-ENOMEM);
163
164 init.name = name;
165 init.flags = flags | CLK_SET_RATE_PARENT;
166 init.parent_names = parent_name ? &parent_name : NULL;
167 init.num_parents = parent_name ? 1 : 0;
168 init.ops = ops;
169
170 cg->regmap = regmap;
171 cg->set_ofs = set_ofs;
172 cg->clr_ofs = clr_ofs;
173 cg->sta_ofs = sta_ofs;
174 cg->bit = bit;
175
176 cg->hw.init = &init;
177
178 clk = clk_register(dev, &cg->hw);
179 if (IS_ERR(clk))
180 kfree(cg);
181
182 return clk;
183}
184