Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux
[sfrench/cifs-2.6.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
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 }