2 * Copyright (C) 2016 Maxime Ripard
3 * Maxime Ripard <maxime.ripard@free-electrons.com>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
11 #include <linux/clk-provider.h>
16 void ccu_mux_helper_adjust_parent_for_prediv(struct ccu_common
*common
,
17 struct ccu_mux_internal
*cm
,
19 unsigned long *parent_rate
)
24 if (!((common
->features
& CCU_FEATURE_FIXED_PREDIV
) ||
25 (common
->features
& CCU_FEATURE_VARIABLE_PREDIV
)))
28 reg
= readl(common
->base
+ common
->reg
);
29 if (parent_index
< 0) {
30 parent_index
= reg
>> cm
->shift
;
31 parent_index
&= (1 << cm
->width
) - 1;
34 if (common
->features
& CCU_FEATURE_FIXED_PREDIV
)
35 if (parent_index
== cm
->fixed_prediv
.index
)
36 prediv
= cm
->fixed_prediv
.div
;
38 if (common
->features
& CCU_FEATURE_VARIABLE_PREDIV
)
39 if (parent_index
== cm
->variable_prediv
.index
) {
42 div
= reg
>> cm
->variable_prediv
.shift
;
43 div
&= (1 << cm
->variable_prediv
.width
) - 1;
47 *parent_rate
= *parent_rate
/ prediv
;
50 int ccu_mux_helper_determine_rate(struct ccu_common
*common
,
51 struct ccu_mux_internal
*cm
,
52 struct clk_rate_request
*req
,
53 unsigned long (*round
)(struct ccu_mux_internal
*,
59 unsigned long best_parent_rate
= 0, best_rate
= 0;
60 struct clk_hw
*best_parent
, *hw
= &common
->hw
;
63 for (i
= 0; i
< clk_hw_get_num_parents(hw
); i
++) {
64 unsigned long tmp_rate
, parent_rate
;
65 struct clk_hw
*parent
;
67 parent
= clk_hw_get_parent_by_index(hw
, i
);
71 parent_rate
= clk_hw_get_rate(parent
);
72 ccu_mux_helper_adjust_parent_for_prediv(common
, cm
, i
,
75 tmp_rate
= round(cm
, clk_hw_get_rate(parent
), req
->rate
, data
);
76 if (tmp_rate
== req
->rate
) {
78 best_parent_rate
= parent_rate
;
83 if ((req
->rate
- tmp_rate
) < (req
->rate
- best_rate
)) {
85 best_parent_rate
= parent_rate
;
94 req
->best_parent_hw
= best_parent
;
95 req
->best_parent_rate
= best_parent_rate
;
96 req
->rate
= best_rate
;
100 u8
ccu_mux_helper_get_parent(struct ccu_common
*common
,
101 struct ccu_mux_internal
*cm
)
106 reg
= readl(common
->base
+ common
->reg
);
107 parent
= reg
>> cm
->shift
;
108 parent
&= (1 << cm
->width
) - 1;
113 int ccu_mux_helper_set_parent(struct ccu_common
*common
,
114 struct ccu_mux_internal
*cm
,
120 spin_lock_irqsave(common
->lock
, flags
);
122 reg
= readl(common
->base
+ common
->reg
);
123 reg
&= ~GENMASK(cm
->width
+ cm
->shift
- 1, cm
->shift
);
124 writel(reg
| (index
<< cm
->shift
), common
->base
+ common
->reg
);
126 spin_unlock_irqrestore(common
->lock
, flags
);
131 static void ccu_mux_disable(struct clk_hw
*hw
)
133 struct ccu_mux
*cm
= hw_to_ccu_mux(hw
);
135 return ccu_gate_helper_disable(&cm
->common
, cm
->enable
);
138 static int ccu_mux_enable(struct clk_hw
*hw
)
140 struct ccu_mux
*cm
= hw_to_ccu_mux(hw
);
142 return ccu_gate_helper_enable(&cm
->common
, cm
->enable
);
145 static int ccu_mux_is_enabled(struct clk_hw
*hw
)
147 struct ccu_mux
*cm
= hw_to_ccu_mux(hw
);
149 return ccu_gate_helper_is_enabled(&cm
->common
, cm
->enable
);
152 static u8
ccu_mux_get_parent(struct clk_hw
*hw
)
154 struct ccu_mux
*cm
= hw_to_ccu_mux(hw
);
156 return ccu_mux_helper_get_parent(&cm
->common
, &cm
->mux
);
159 static int ccu_mux_set_parent(struct clk_hw
*hw
, u8 index
)
161 struct ccu_mux
*cm
= hw_to_ccu_mux(hw
);
163 return ccu_mux_helper_set_parent(&cm
->common
, &cm
->mux
, index
);
166 static unsigned long ccu_mux_recalc_rate(struct clk_hw
*hw
,
167 unsigned long parent_rate
)
169 struct ccu_mux
*cm
= hw_to_ccu_mux(hw
);
171 ccu_mux_helper_adjust_parent_for_prediv(&cm
->common
, &cm
->mux
, -1,
177 const struct clk_ops ccu_mux_ops
= {
178 .disable
= ccu_mux_disable
,
179 .enable
= ccu_mux_enable
,
180 .is_enabled
= ccu_mux_is_enabled
,
182 .get_parent
= ccu_mux_get_parent
,
183 .set_parent
= ccu_mux_set_parent
,
185 .determine_rate
= __clk_mux_determine_rate
,
186 .recalc_rate
= ccu_mux_recalc_rate
,