blob: 219181bb2c9dd0b3a7535ac0e456d45b2e5e5bd5 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2018 MediaTek Inc.
4 * Author: Owen Chen <owen.chen@mediatek.com>
5 */
6
7#include <linux/of.h>
8#include <linux/of_address.h>
9#include <linux/slab.h>
10
11#include "clk-mtk.h"
12#include "clk-mux.h"
13
14static inline struct mtk_clk_mux
15 *to_mtk_clk_mux(struct clk_hw *hw)
16{
17 return container_of(hw, struct mtk_clk_mux, hw);
18}
19
20static int mtk_mux_enable(struct clk_hw *hw)
21{
22 struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
23 u32 mask = BIT(mux->gate_shift);
24 unsigned long flags = 0;
25
26 if (mux->lock)
27 spin_lock_irqsave(mux->lock, flags);
28
29 regmap_update_bits(mux->regmap, mux->mux_ofs, mask, 0);
30
31 if (mux->lock)
32 spin_unlock_irqrestore(mux->lock, flags);
33 return 0;
34}
35
36static void mtk_mux_disable(struct clk_hw *hw)
37{
38 struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
39 u32 mask = BIT(mux->gate_shift);
40 unsigned long flags = 0;
41
42 if (mux->lock)
43 spin_lock_irqsave(mux->lock, flags);
44
45 regmap_update_bits(mux->regmap, mux->mux_ofs, mask, mask);
46
47 if (mux->lock)
48 spin_unlock_irqrestore(mux->lock, flags);
49}
50
51static int mtk_mux_enable_setclr(struct clk_hw *hw)
52{
53 struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
54 u32 val;
55 unsigned long flags = 0;
56
57 if (mux->lock)
58 spin_lock_irqsave(mux->lock, flags);
59
60 val = BIT(mux->gate_shift);
61 regmap_write(mux->regmap, mux->mux_clr_ofs, val);
62
63 if (mux->lock)
64 spin_unlock_irqrestore(mux->lock, flags);
65 return 0;
66}
67
68static void mtk_mux_disable_setclr(struct clk_hw *hw)
69{
70 struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
71 u32 val;
72 unsigned long flags = 0;
73
74 if (mux->lock)
75 spin_lock_irqsave(mux->lock, flags);
76
77 val = BIT(mux->gate_shift);
78 regmap_write(mux->regmap, mux->mux_set_ofs, val);
79
80 if (mux->lock)
81 spin_unlock_irqrestore(mux->lock, flags);
82}
83
84static int mtk_mux_is_enabled(struct clk_hw *hw)
85{
86 struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
87 u32 val = 0;
88
89 if (mux->gate_shift < 0)
90 return true;
91
92 regmap_read(mux->regmap, mux->mux_ofs, &val);
93
94 return (val & BIT(mux->gate_shift)) == 0;
95}
96
97static u8 mtk_mux_get_parent(struct clk_hw *hw)
98{
99 struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
100 int num_parents = clk_hw_get_num_parents(hw);
101 u32 mask = GENMASK(mux->mux_width - 1, 0);
102 u32 val;
103
104 regmap_read(mux->regmap, mux->mux_ofs, &val);
105 val = (val >> mux->mux_shift) & mask;
106
107 if (val >= num_parents)
108 return -EINVAL;
109
110 return val;
111}
112
113static int mtk_mux_set_parent(struct clk_hw *hw, u8 index)
114{
115 struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
116 u32 mask = GENMASK(mux->mux_width - 1, 0);
117 u32 val, orig;
118 unsigned long flags = 0;
119
120 if (mux->lock)
121 spin_lock_irqsave(mux->lock, flags);
122
123 regmap_read(mux->regmap, mux->mux_ofs, &val);
124 orig = val;
125 val &= ~(mask << mux->mux_shift);
126 val |= index << mux->mux_shift;
127
128 if (val != orig) {
129 regmap_write(mux->regmap, mux->mux_ofs, val);
130
131 if (mux->upd_shift >= 0)
132 regmap_write(mux->regmap, mux->upd_ofs,
133 BIT(mux->upd_shift));
134 }
135
136 if (mux->lock)
137 spin_unlock_irqrestore(mux->lock, flags);
138
139 return 0;
140}
141
142static int mtk_mux_set_parent_setclr(struct clk_hw *hw, u8 index)
143{
144 struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
145 u32 mask = GENMASK(mux->mux_width - 1, 0);
146 u32 val, orig;
147 unsigned long flags = 0;
148
149 if (mux->lock)
150 spin_lock_irqsave(mux->lock, flags);
151
152 regmap_read(mux->regmap, mux->mux_ofs, &val);
153 orig = val;
154 val &= ~(mask << mux->mux_shift);
155 val |= index << mux->mux_shift;
156
157 if (val != orig) {
158 val = (mask << mux->mux_shift);
159 regmap_write(mux->regmap, mux->mux_clr_ofs, val);
160 val = (index << mux->mux_shift);
161 regmap_write(mux->regmap, mux->mux_set_ofs, val);
162
163 if (mux->upd_shift >= 0)
164 regmap_write(mux->regmap, mux->upd_ofs,
165 BIT(mux->upd_shift));
166 }
167
168 if (mux->lock)
169 spin_unlock_irqrestore(mux->lock, flags);
170
171 return 0;
172}
173
174const struct clk_ops mtk_mux_upd_ops = {
175 .enable = mtk_mux_enable,
176 .disable = mtk_mux_disable,
177 .is_enabled = mtk_mux_is_enabled,
178 .get_parent = mtk_mux_get_parent,
179 .set_parent = mtk_mux_set_parent,
180 .determine_rate = NULL,
181};
182
183const struct clk_ops mtk_mux_clr_set_upd_ops = {
184 .enable = mtk_mux_enable_setclr,
185 .disable = mtk_mux_disable_setclr,
186 .is_enabled = mtk_mux_is_enabled,
187 .get_parent = mtk_mux_get_parent,
188 .set_parent = mtk_mux_set_parent_setclr,
189 .determine_rate = NULL,
190};
191
192struct clk *mtk_clk_register_mux(const struct mtk_mux *mux,
193 struct regmap *regmap,
194 spinlock_t *lock)
195{
196 struct clk *clk;
197 struct clk_init_data init;
198 struct mtk_clk_mux *mtk_mux = NULL;
199 int ret;
200
201 mtk_mux = kzalloc(sizeof(*mtk_mux), GFP_KERNEL);
202 if (!mtk_mux)
203 return ERR_PTR(-ENOMEM);
204
205 init.name = mux->name;
206 init.flags = (mux->flags) | CLK_SET_RATE_PARENT;
207 init.parent_names = mux->parent_names;
208 init.num_parents = mux->num_parents;
209 init.ops = mux->ops;
210
211 mtk_mux->regmap = regmap;
212 mtk_mux->name = mux->name;
213 mtk_mux->mux_ofs = mux->mux_ofs;
214 mtk_mux->mux_set_ofs = mux->set_ofs;
215 mtk_mux->mux_clr_ofs = mux->clr_ofs;
216 mtk_mux->upd_ofs = mux->upd_ofs;
217 mtk_mux->mux_shift = mux->mux_shift;
218 mtk_mux->mux_width = mux->mux_width;
219 mtk_mux->gate_shift = mux->gate_shift;
220 mtk_mux->upd_shift = mux->upd_shift;
221
222 mtk_mux->lock = lock;
223 mtk_mux->hw.init = &init;
224
225 clk = clk_register(NULL, &mtk_mux->hw);
226 if (IS_ERR(clk)) {
227 ret = PTR_ERR(clk);
228 goto err_out;
229 }
230
231 return clk;
232err_out:
233 kfree(mtk_mux);
234
235 return ERR_PTR(ret);
236}