xref: /openbmc/linux/drivers/clk/mediatek/clk-gate.c (revision 7f6964c5)
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 
15 #include "clk-mtk.h"
16 #include "clk-gate.h"
17 
18 static 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 
30 static 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 
42 static 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 
49 static 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 
56 static 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 
64 static 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 
72 static int mtk_cg_enable(struct clk_hw *hw)
73 {
74 	mtk_cg_clr_bit(hw);
75 
76 	return 0;
77 }
78 
79 static void mtk_cg_disable(struct clk_hw *hw)
80 {
81 	mtk_cg_set_bit(hw);
82 }
83 
84 static int mtk_cg_enable_inv(struct clk_hw *hw)
85 {
86 	mtk_cg_set_bit(hw);
87 
88 	return 0;
89 }
90 
91 static void mtk_cg_disable_inv(struct clk_hw *hw)
92 {
93 	mtk_cg_clr_bit(hw);
94 }
95 
96 static 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 
103 static void mtk_cg_disable_no_setclr(struct clk_hw *hw)
104 {
105 	mtk_cg_set_bit_no_setclr(hw);
106 }
107 
108 static 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 
115 static void mtk_cg_disable_inv_no_setclr(struct clk_hw *hw)
116 {
117 	mtk_cg_clr_bit_no_setclr(hw);
118 }
119 
120 const 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 
126 const 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 
132 const 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 
138 const 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 
144 struct 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 {
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(NULL, &cg->hw);
178 	if (IS_ERR(clk))
179 		kfree(cg);
180 
181 	return clk;
182 }
183