xref: /openbmc/linux/drivers/clk/clk-composite.c (revision b34e08d5)
1 /*
2  * Copyright (c) 2013 NVIDIA CORPORATION.  All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms and conditions of the GNU General Public License,
6  * version 2, as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11  * more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 #include <linux/clk.h>
18 #include <linux/clk-provider.h>
19 #include <linux/err.h>
20 #include <linux/slab.h>
21 
22 #define to_clk_composite(_hw) container_of(_hw, struct clk_composite, hw)
23 
24 static u8 clk_composite_get_parent(struct clk_hw *hw)
25 {
26 	struct clk_composite *composite = to_clk_composite(hw);
27 	const struct clk_ops *mux_ops = composite->mux_ops;
28 	struct clk_hw *mux_hw = composite->mux_hw;
29 
30 	mux_hw->clk = hw->clk;
31 
32 	return mux_ops->get_parent(mux_hw);
33 }
34 
35 static int clk_composite_set_parent(struct clk_hw *hw, u8 index)
36 {
37 	struct clk_composite *composite = to_clk_composite(hw);
38 	const struct clk_ops *mux_ops = composite->mux_ops;
39 	struct clk_hw *mux_hw = composite->mux_hw;
40 
41 	mux_hw->clk = hw->clk;
42 
43 	return mux_ops->set_parent(mux_hw, index);
44 }
45 
46 static unsigned long clk_composite_recalc_rate(struct clk_hw *hw,
47 					    unsigned long parent_rate)
48 {
49 	struct clk_composite *composite = to_clk_composite(hw);
50 	const struct clk_ops *rate_ops = composite->rate_ops;
51 	struct clk_hw *rate_hw = composite->rate_hw;
52 
53 	rate_hw->clk = hw->clk;
54 
55 	return rate_ops->recalc_rate(rate_hw, parent_rate);
56 }
57 
58 static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
59 					unsigned long *best_parent_rate,
60 					struct clk **best_parent_p)
61 {
62 	struct clk_composite *composite = to_clk_composite(hw);
63 	const struct clk_ops *rate_ops = composite->rate_ops;
64 	const struct clk_ops *mux_ops = composite->mux_ops;
65 	struct clk_hw *rate_hw = composite->rate_hw;
66 	struct clk_hw *mux_hw = composite->mux_hw;
67 
68 	if (rate_hw && rate_ops && rate_ops->determine_rate) {
69 		rate_hw->clk = hw->clk;
70 		return rate_ops->determine_rate(rate_hw, rate, best_parent_rate,
71 						best_parent_p);
72 	} else if (mux_hw && mux_ops && mux_ops->determine_rate) {
73 		mux_hw->clk = hw->clk;
74 		return mux_ops->determine_rate(mux_hw, rate, best_parent_rate,
75 					       best_parent_p);
76 	} else {
77 		pr_err("clk: clk_composite_determine_rate function called, but no mux or rate callback set!\n");
78 		return 0;
79 	}
80 }
81 
82 static long clk_composite_round_rate(struct clk_hw *hw, unsigned long rate,
83 				  unsigned long *prate)
84 {
85 	struct clk_composite *composite = to_clk_composite(hw);
86 	const struct clk_ops *rate_ops = composite->rate_ops;
87 	struct clk_hw *rate_hw = composite->rate_hw;
88 
89 	rate_hw->clk = hw->clk;
90 
91 	return rate_ops->round_rate(rate_hw, rate, prate);
92 }
93 
94 static int clk_composite_set_rate(struct clk_hw *hw, unsigned long rate,
95 			       unsigned long parent_rate)
96 {
97 	struct clk_composite *composite = to_clk_composite(hw);
98 	const struct clk_ops *rate_ops = composite->rate_ops;
99 	struct clk_hw *rate_hw = composite->rate_hw;
100 
101 	rate_hw->clk = hw->clk;
102 
103 	return rate_ops->set_rate(rate_hw, rate, parent_rate);
104 }
105 
106 static int clk_composite_is_enabled(struct clk_hw *hw)
107 {
108 	struct clk_composite *composite = to_clk_composite(hw);
109 	const struct clk_ops *gate_ops = composite->gate_ops;
110 	struct clk_hw *gate_hw = composite->gate_hw;
111 
112 	gate_hw->clk = hw->clk;
113 
114 	return gate_ops->is_enabled(gate_hw);
115 }
116 
117 static int clk_composite_enable(struct clk_hw *hw)
118 {
119 	struct clk_composite *composite = to_clk_composite(hw);
120 	const struct clk_ops *gate_ops = composite->gate_ops;
121 	struct clk_hw *gate_hw = composite->gate_hw;
122 
123 	gate_hw->clk = hw->clk;
124 
125 	return gate_ops->enable(gate_hw);
126 }
127 
128 static void clk_composite_disable(struct clk_hw *hw)
129 {
130 	struct clk_composite *composite = to_clk_composite(hw);
131 	const struct clk_ops *gate_ops = composite->gate_ops;
132 	struct clk_hw *gate_hw = composite->gate_hw;
133 
134 	gate_hw->clk = hw->clk;
135 
136 	gate_ops->disable(gate_hw);
137 }
138 
139 struct clk *clk_register_composite(struct device *dev, const char *name,
140 			const char **parent_names, int num_parents,
141 			struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
142 			struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
143 			struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
144 			unsigned long flags)
145 {
146 	struct clk *clk;
147 	struct clk_init_data init;
148 	struct clk_composite *composite;
149 	struct clk_ops *clk_composite_ops;
150 
151 	composite = kzalloc(sizeof(*composite), GFP_KERNEL);
152 	if (!composite) {
153 		pr_err("%s: could not allocate composite clk\n", __func__);
154 		return ERR_PTR(-ENOMEM);
155 	}
156 
157 	init.name = name;
158 	init.flags = flags | CLK_IS_BASIC;
159 	init.parent_names = parent_names;
160 	init.num_parents = num_parents;
161 
162 	clk_composite_ops = &composite->ops;
163 
164 	if (mux_hw && mux_ops) {
165 		if (!mux_ops->get_parent || !mux_ops->set_parent) {
166 			clk = ERR_PTR(-EINVAL);
167 			goto err;
168 		}
169 
170 		composite->mux_hw = mux_hw;
171 		composite->mux_ops = mux_ops;
172 		clk_composite_ops->get_parent = clk_composite_get_parent;
173 		clk_composite_ops->set_parent = clk_composite_set_parent;
174 		if (mux_ops->determine_rate)
175 			clk_composite_ops->determine_rate = clk_composite_determine_rate;
176 	}
177 
178 	if (rate_hw && rate_ops) {
179 		if (!rate_ops->recalc_rate) {
180 			clk = ERR_PTR(-EINVAL);
181 			goto err;
182 		}
183 
184 		/* .round_rate is a prerequisite for .set_rate */
185 		if (rate_ops->round_rate) {
186 			clk_composite_ops->round_rate = clk_composite_round_rate;
187 			if (rate_ops->set_rate) {
188 				clk_composite_ops->set_rate = clk_composite_set_rate;
189 			}
190 		} else {
191 			WARN(rate_ops->set_rate,
192 				"%s: missing round_rate op is required\n",
193 				__func__);
194 		}
195 
196 		composite->rate_hw = rate_hw;
197 		composite->rate_ops = rate_ops;
198 		clk_composite_ops->recalc_rate = clk_composite_recalc_rate;
199 		if (rate_ops->determine_rate)
200 			clk_composite_ops->determine_rate = clk_composite_determine_rate;
201 	}
202 
203 	if (gate_hw && gate_ops) {
204 		if (!gate_ops->is_enabled || !gate_ops->enable ||
205 		    !gate_ops->disable) {
206 			clk = ERR_PTR(-EINVAL);
207 			goto err;
208 		}
209 
210 		composite->gate_hw = gate_hw;
211 		composite->gate_ops = gate_ops;
212 		clk_composite_ops->is_enabled = clk_composite_is_enabled;
213 		clk_composite_ops->enable = clk_composite_enable;
214 		clk_composite_ops->disable = clk_composite_disable;
215 	}
216 
217 	init.ops = clk_composite_ops;
218 	composite->hw.init = &init;
219 
220 	clk = clk_register(dev, &composite->hw);
221 	if (IS_ERR(clk))
222 		goto err;
223 
224 	if (composite->mux_hw)
225 		composite->mux_hw->clk = clk;
226 
227 	if (composite->rate_hw)
228 		composite->rate_hw->clk = clk;
229 
230 	if (composite->gate_hw)
231 		composite->gate_hw->clk = clk;
232 
233 	return clk;
234 
235 err:
236 	kfree(composite);
237 	return clk;
238 }
239