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