Merge tag 'vfio-v5.17-rc1' of git://github.com/awilliam/linux-vfio
[linux-2.6-microblaze.git] / drivers / clk / mediatek / clk-gate.c
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");