1 // SPDX-License-Identifier: GPL-2.0+
2 //
3 // OWL composite clock driver
4 //
5 // Copyright (c) 2014 Actions Semi Inc.
6 // Author: David Liu <liuwei@actions-semi.com>
7 //
8 // Copyright (c) 2018 Linaro Ltd.
9 // Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
10 
11 #include <linux/clk-provider.h>
12 #include <linux/regmap.h>
13 
14 #include "owl-composite.h"
15 
16 static u8 owl_comp_get_parent(struct clk_hw *hw)
17 {
18 	struct owl_composite *comp = hw_to_owl_comp(hw);
19 
20 	return owl_mux_helper_get_parent(&comp->common, &comp->mux_hw);
21 }
22 
23 static int owl_comp_set_parent(struct clk_hw *hw, u8 index)
24 {
25 	struct owl_composite *comp = hw_to_owl_comp(hw);
26 
27 	return owl_mux_helper_set_parent(&comp->common, &comp->mux_hw, index);
28 }
29 
30 static void owl_comp_disable(struct clk_hw *hw)
31 {
32 	struct owl_composite *comp = hw_to_owl_comp(hw);
33 	struct owl_clk_common *common = &comp->common;
34 
35 	owl_gate_set(common, &comp->gate_hw, false);
36 }
37 
38 static int owl_comp_enable(struct clk_hw *hw)
39 {
40 	struct owl_composite *comp = hw_to_owl_comp(hw);
41 	struct owl_clk_common *common = &comp->common;
42 
43 	owl_gate_set(common, &comp->gate_hw, true);
44 
45 	return 0;
46 }
47 
48 static int owl_comp_is_enabled(struct clk_hw *hw)
49 {
50 	struct owl_composite *comp = hw_to_owl_comp(hw);
51 	struct owl_clk_common *common = &comp->common;
52 
53 	return owl_gate_clk_is_enabled(common, &comp->gate_hw);
54 }
55 
56 static int owl_comp_div_determine_rate(struct clk_hw *hw,
57 				       struct clk_rate_request *req)
58 {
59 	struct owl_composite *comp = hw_to_owl_comp(hw);
60 	long rate;
61 
62 	rate = owl_divider_helper_round_rate(&comp->common, &comp->rate.div_hw,
63 					     req->rate, &req->best_parent_rate);
64 	if (rate < 0)
65 		return rate;
66 
67 	req->rate = rate;
68 	return 0;
69 }
70 
71 static unsigned long owl_comp_div_recalc_rate(struct clk_hw *hw,
72 					  unsigned long parent_rate)
73 {
74 	struct owl_composite *comp = hw_to_owl_comp(hw);
75 
76 	return owl_divider_helper_recalc_rate(&comp->common, &comp->rate.div_hw,
77 					parent_rate);
78 }
79 
80 static int owl_comp_div_set_rate(struct clk_hw *hw, unsigned long rate,
81 				unsigned long parent_rate)
82 {
83 	struct owl_composite *comp = hw_to_owl_comp(hw);
84 
85 	return owl_divider_helper_set_rate(&comp->common, &comp->rate.div_hw,
86 					rate, parent_rate);
87 }
88 
89 static int owl_comp_fact_determine_rate(struct clk_hw *hw,
90 					struct clk_rate_request *req)
91 {
92 	struct owl_composite *comp = hw_to_owl_comp(hw);
93 	long rate;
94 
95 	rate = owl_factor_helper_round_rate(&comp->common,
96 					    &comp->rate.factor_hw,
97 					    req->rate, &req->best_parent_rate);
98 	if (rate < 0)
99 		return rate;
100 
101 	req->rate = rate;
102 	return 0;
103 }
104 
105 static unsigned long owl_comp_fact_recalc_rate(struct clk_hw *hw,
106 			unsigned long parent_rate)
107 {
108 	struct owl_composite *comp = hw_to_owl_comp(hw);
109 
110 	return owl_factor_helper_recalc_rate(&comp->common,
111 					&comp->rate.factor_hw,
112 					parent_rate);
113 }
114 
115 static int owl_comp_fact_set_rate(struct clk_hw *hw, unsigned long rate,
116 			unsigned long parent_rate)
117 {
118 	struct owl_composite *comp = hw_to_owl_comp(hw);
119 
120 	return owl_factor_helper_set_rate(&comp->common,
121 					&comp->rate.factor_hw,
122 					rate, parent_rate);
123 }
124 
125 static long owl_comp_fix_fact_round_rate(struct clk_hw *hw, unsigned long rate,
126 			unsigned long *parent_rate)
127 {
128 	struct owl_composite *comp = hw_to_owl_comp(hw);
129 	struct clk_fixed_factor *fix_fact_hw = &comp->rate.fix_fact_hw;
130 
131 	return comp->fix_fact_ops->round_rate(&fix_fact_hw->hw, rate, parent_rate);
132 }
133 
134 static unsigned long owl_comp_fix_fact_recalc_rate(struct clk_hw *hw,
135 			unsigned long parent_rate)
136 {
137 	struct owl_composite *comp = hw_to_owl_comp(hw);
138 	struct clk_fixed_factor *fix_fact_hw = &comp->rate.fix_fact_hw;
139 
140 	return comp->fix_fact_ops->recalc_rate(&fix_fact_hw->hw, parent_rate);
141 
142 }
143 
144 static int owl_comp_fix_fact_set_rate(struct clk_hw *hw, unsigned long rate,
145 			unsigned long parent_rate)
146 {
147 	/*
148 	 * We must report success but we can do so unconditionally because
149 	 * owl_comp_fix_fact_round_rate returns values that ensure this call is
150 	 * a nop.
151 	 */
152 
153 	return 0;
154 }
155 
156 const struct clk_ops owl_comp_div_ops = {
157 	/* mux_ops */
158 	.get_parent	= owl_comp_get_parent,
159 	.set_parent	= owl_comp_set_parent,
160 
161 	/* gate_ops */
162 	.disable	= owl_comp_disable,
163 	.enable		= owl_comp_enable,
164 	.is_enabled	= owl_comp_is_enabled,
165 
166 	/* div_ops */
167 	.determine_rate	= owl_comp_div_determine_rate,
168 	.recalc_rate	= owl_comp_div_recalc_rate,
169 	.set_rate	= owl_comp_div_set_rate,
170 };
171 
172 
173 const struct clk_ops owl_comp_fact_ops = {
174 	/* mux_ops */
175 	.get_parent	= owl_comp_get_parent,
176 	.set_parent	= owl_comp_set_parent,
177 
178 	/* gate_ops */
179 	.disable	= owl_comp_disable,
180 	.enable		= owl_comp_enable,
181 	.is_enabled	= owl_comp_is_enabled,
182 
183 	/* fact_ops */
184 	.determine_rate	= owl_comp_fact_determine_rate,
185 	.recalc_rate	= owl_comp_fact_recalc_rate,
186 	.set_rate	= owl_comp_fact_set_rate,
187 };
188 
189 const struct clk_ops owl_comp_fix_fact_ops = {
190 	/* gate_ops */
191 	.disable	= owl_comp_disable,
192 	.enable		= owl_comp_enable,
193 	.is_enabled	= owl_comp_is_enabled,
194 
195 	/* fix_fact_ops */
196 	.round_rate	= owl_comp_fix_fact_round_rate,
197 	.recalc_rate	= owl_comp_fix_fact_recalc_rate,
198 	.set_rate	= owl_comp_fix_fact_set_rate,
199 };
200 
201 
202 const struct clk_ops owl_comp_pass_ops = {
203 	/* mux_ops */
204 	.determine_rate	= clk_hw_determine_rate_no_reparent,
205 	.get_parent	= owl_comp_get_parent,
206 	.set_parent	= owl_comp_set_parent,
207 
208 	/* gate_ops */
209 	.disable	= owl_comp_disable,
210 	.enable		= owl_comp_enable,
211 	.is_enabled	= owl_comp_is_enabled,
212 };
213