xref: /OK3568_Linux_fs/kernel/drivers/clk/mediatek/clk-mux.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 2018 MediaTek Inc.
4*4882a593Smuzhiyun  * Author: Owen Chen <owen.chen@mediatek.com>
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <linux/of.h>
8*4882a593Smuzhiyun #include <linux/of_address.h>
9*4882a593Smuzhiyun #include <linux/slab.h>
10*4882a593Smuzhiyun #include <linux/mfd/syscon.h>
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include "clk-mtk.h"
13*4882a593Smuzhiyun #include "clk-mux.h"
14*4882a593Smuzhiyun 
to_mtk_clk_mux(struct clk_hw * hw)15*4882a593Smuzhiyun static inline struct mtk_clk_mux *to_mtk_clk_mux(struct clk_hw *hw)
16*4882a593Smuzhiyun {
17*4882a593Smuzhiyun 	return container_of(hw, struct mtk_clk_mux, hw);
18*4882a593Smuzhiyun }
19*4882a593Smuzhiyun 
mtk_clk_mux_enable(struct clk_hw * hw)20*4882a593Smuzhiyun static int mtk_clk_mux_enable(struct clk_hw *hw)
21*4882a593Smuzhiyun {
22*4882a593Smuzhiyun 	struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
23*4882a593Smuzhiyun 	u32 mask = BIT(mux->data->gate_shift);
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun 	return regmap_update_bits(mux->regmap, mux->data->mux_ofs,
26*4882a593Smuzhiyun 			mask, ~mask);
27*4882a593Smuzhiyun }
28*4882a593Smuzhiyun 
mtk_clk_mux_disable(struct clk_hw * hw)29*4882a593Smuzhiyun static void mtk_clk_mux_disable(struct clk_hw *hw)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun 	struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
32*4882a593Smuzhiyun 	u32 mask = BIT(mux->data->gate_shift);
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 	regmap_update_bits(mux->regmap, mux->data->mux_ofs, mask, mask);
35*4882a593Smuzhiyun }
36*4882a593Smuzhiyun 
mtk_clk_mux_enable_setclr(struct clk_hw * hw)37*4882a593Smuzhiyun static int mtk_clk_mux_enable_setclr(struct clk_hw *hw)
38*4882a593Smuzhiyun {
39*4882a593Smuzhiyun 	struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 	return regmap_write(mux->regmap, mux->data->clr_ofs,
42*4882a593Smuzhiyun 			BIT(mux->data->gate_shift));
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun 
mtk_clk_mux_disable_setclr(struct clk_hw * hw)45*4882a593Smuzhiyun static void mtk_clk_mux_disable_setclr(struct clk_hw *hw)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	regmap_write(mux->regmap, mux->data->set_ofs,
50*4882a593Smuzhiyun 			BIT(mux->data->gate_shift));
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun 
mtk_clk_mux_is_enabled(struct clk_hw * hw)53*4882a593Smuzhiyun static int mtk_clk_mux_is_enabled(struct clk_hw *hw)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun 	struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
56*4882a593Smuzhiyun 	u32 val;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	regmap_read(mux->regmap, mux->data->mux_ofs, &val);
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	return (val & BIT(mux->data->gate_shift)) == 0;
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun 
mtk_clk_mux_get_parent(struct clk_hw * hw)63*4882a593Smuzhiyun static u8 mtk_clk_mux_get_parent(struct clk_hw *hw)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun 	struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
66*4882a593Smuzhiyun 	u32 mask = GENMASK(mux->data->mux_width - 1, 0);
67*4882a593Smuzhiyun 	u32 val;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	regmap_read(mux->regmap, mux->data->mux_ofs, &val);
70*4882a593Smuzhiyun 	val = (val >> mux->data->mux_shift) & mask;
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	return val;
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun 
mtk_clk_mux_set_parent_lock(struct clk_hw * hw,u8 index)75*4882a593Smuzhiyun static int mtk_clk_mux_set_parent_lock(struct clk_hw *hw, u8 index)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun 	struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
78*4882a593Smuzhiyun 	u32 mask = GENMASK(mux->data->mux_width - 1, 0);
79*4882a593Smuzhiyun 	unsigned long flags = 0;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	if (mux->lock)
82*4882a593Smuzhiyun 		spin_lock_irqsave(mux->lock, flags);
83*4882a593Smuzhiyun 	else
84*4882a593Smuzhiyun 		__acquire(mux->lock);
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	regmap_update_bits(mux->regmap, mux->data->mux_ofs, mask,
87*4882a593Smuzhiyun 		index << mux->data->mux_shift);
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	if (mux->lock)
90*4882a593Smuzhiyun 		spin_unlock_irqrestore(mux->lock, flags);
91*4882a593Smuzhiyun 	else
92*4882a593Smuzhiyun 		__release(mux->lock);
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	return 0;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun 
mtk_clk_mux_set_parent_setclr_lock(struct clk_hw * hw,u8 index)97*4882a593Smuzhiyun static int mtk_clk_mux_set_parent_setclr_lock(struct clk_hw *hw, u8 index)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun 	struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
100*4882a593Smuzhiyun 	u32 mask = GENMASK(mux->data->mux_width - 1, 0);
101*4882a593Smuzhiyun 	u32 val, orig;
102*4882a593Smuzhiyun 	unsigned long flags = 0;
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	if (mux->lock)
105*4882a593Smuzhiyun 		spin_lock_irqsave(mux->lock, flags);
106*4882a593Smuzhiyun 	else
107*4882a593Smuzhiyun 		__acquire(mux->lock);
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	regmap_read(mux->regmap, mux->data->mux_ofs, &orig);
110*4882a593Smuzhiyun 	val = (orig & ~(mask << mux->data->mux_shift))
111*4882a593Smuzhiyun 			| (index << mux->data->mux_shift);
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	if (val != orig) {
114*4882a593Smuzhiyun 		regmap_write(mux->regmap, mux->data->clr_ofs,
115*4882a593Smuzhiyun 				mask << mux->data->mux_shift);
116*4882a593Smuzhiyun 		regmap_write(mux->regmap, mux->data->set_ofs,
117*4882a593Smuzhiyun 				index << mux->data->mux_shift);
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 		if (mux->data->upd_shift >= 0)
120*4882a593Smuzhiyun 			regmap_write(mux->regmap, mux->data->upd_ofs,
121*4882a593Smuzhiyun 					BIT(mux->data->upd_shift));
122*4882a593Smuzhiyun 	}
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	if (mux->lock)
125*4882a593Smuzhiyun 		spin_unlock_irqrestore(mux->lock, flags);
126*4882a593Smuzhiyun 	else
127*4882a593Smuzhiyun 		__release(mux->lock);
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	return 0;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun const struct clk_ops mtk_mux_ops = {
133*4882a593Smuzhiyun 	.get_parent = mtk_clk_mux_get_parent,
134*4882a593Smuzhiyun 	.set_parent = mtk_clk_mux_set_parent_lock,
135*4882a593Smuzhiyun };
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun const struct clk_ops mtk_mux_clr_set_upd_ops = {
138*4882a593Smuzhiyun 	.get_parent = mtk_clk_mux_get_parent,
139*4882a593Smuzhiyun 	.set_parent = mtk_clk_mux_set_parent_setclr_lock,
140*4882a593Smuzhiyun };
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun const struct clk_ops mtk_mux_gate_ops = {
143*4882a593Smuzhiyun 	.enable = mtk_clk_mux_enable,
144*4882a593Smuzhiyun 	.disable = mtk_clk_mux_disable,
145*4882a593Smuzhiyun 	.is_enabled = mtk_clk_mux_is_enabled,
146*4882a593Smuzhiyun 	.get_parent = mtk_clk_mux_get_parent,
147*4882a593Smuzhiyun 	.set_parent = mtk_clk_mux_set_parent_lock,
148*4882a593Smuzhiyun };
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun const struct clk_ops mtk_mux_gate_clr_set_upd_ops = {
151*4882a593Smuzhiyun 	.enable = mtk_clk_mux_enable_setclr,
152*4882a593Smuzhiyun 	.disable = mtk_clk_mux_disable_setclr,
153*4882a593Smuzhiyun 	.is_enabled = mtk_clk_mux_is_enabled,
154*4882a593Smuzhiyun 	.get_parent = mtk_clk_mux_get_parent,
155*4882a593Smuzhiyun 	.set_parent = mtk_clk_mux_set_parent_setclr_lock,
156*4882a593Smuzhiyun };
157*4882a593Smuzhiyun 
mtk_clk_register_mux(const struct mtk_mux * mux,struct regmap * regmap,spinlock_t * lock)158*4882a593Smuzhiyun struct clk *mtk_clk_register_mux(const struct mtk_mux *mux,
159*4882a593Smuzhiyun 				 struct regmap *regmap,
160*4882a593Smuzhiyun 				 spinlock_t *lock)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun 	struct mtk_clk_mux *clk_mux;
163*4882a593Smuzhiyun 	struct clk_init_data init = {};
164*4882a593Smuzhiyun 	struct clk *clk;
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	clk_mux = kzalloc(sizeof(*clk_mux), GFP_KERNEL);
167*4882a593Smuzhiyun 	if (!clk_mux)
168*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	init.name = mux->name;
171*4882a593Smuzhiyun 	init.flags = mux->flags | CLK_SET_RATE_PARENT;
172*4882a593Smuzhiyun 	init.parent_names = mux->parent_names;
173*4882a593Smuzhiyun 	init.num_parents = mux->num_parents;
174*4882a593Smuzhiyun 	init.ops = mux->ops;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	clk_mux->regmap = regmap;
177*4882a593Smuzhiyun 	clk_mux->data = mux;
178*4882a593Smuzhiyun 	clk_mux->lock = lock;
179*4882a593Smuzhiyun 	clk_mux->hw.init = &init;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	clk = clk_register(NULL, &clk_mux->hw);
182*4882a593Smuzhiyun 	if (IS_ERR(clk)) {
183*4882a593Smuzhiyun 		kfree(clk_mux);
184*4882a593Smuzhiyun 		return clk;
185*4882a593Smuzhiyun 	}
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	return clk;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun 
mtk_clk_register_muxes(const struct mtk_mux * muxes,int num,struct device_node * node,spinlock_t * lock,struct clk_onecell_data * clk_data)190*4882a593Smuzhiyun int mtk_clk_register_muxes(const struct mtk_mux *muxes,
191*4882a593Smuzhiyun 			   int num, struct device_node *node,
192*4882a593Smuzhiyun 			   spinlock_t *lock,
193*4882a593Smuzhiyun 			   struct clk_onecell_data *clk_data)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun 	struct regmap *regmap;
196*4882a593Smuzhiyun 	struct clk *clk;
197*4882a593Smuzhiyun 	int i;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	regmap = syscon_node_to_regmap(node);
200*4882a593Smuzhiyun 	if (IS_ERR(regmap)) {
201*4882a593Smuzhiyun 		pr_err("Cannot find regmap for %pOF: %ld\n", node,
202*4882a593Smuzhiyun 		       PTR_ERR(regmap));
203*4882a593Smuzhiyun 		return PTR_ERR(regmap);
204*4882a593Smuzhiyun 	}
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	for (i = 0; i < num; i++) {
207*4882a593Smuzhiyun 		const struct mtk_mux *mux = &muxes[i];
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 		if (IS_ERR_OR_NULL(clk_data->clks[mux->id])) {
210*4882a593Smuzhiyun 			clk = mtk_clk_register_mux(mux, regmap, lock);
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 			if (IS_ERR(clk)) {
213*4882a593Smuzhiyun 				pr_err("Failed to register clk %s: %ld\n",
214*4882a593Smuzhiyun 				       mux->name, PTR_ERR(clk));
215*4882a593Smuzhiyun 				continue;
216*4882a593Smuzhiyun 			}
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 			clk_data->clks[mux->id] = clk;
219*4882a593Smuzhiyun 		}
220*4882a593Smuzhiyun 	}
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	return 0;
223*4882a593Smuzhiyun }
224