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