1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
4  */
5 #include "ccu.h"
6 
7 /*
8  * DOC: basic fixed multiplier and divider clock that cannot gate
9  *
10  * Traits of this clock:
11  * prepare - clk_prepare only ensures that parents are prepared
12  * enable - clk_enable only ensures that parents are enabled
13  * rate - rate is fixed.  clk->rate = parent->rate / div * mult
14  * parent - fixed parent.  No clk_set_parent support
15  */
16 
clk_factor_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)17 static unsigned long clk_factor_recalc_rate(struct clk_hw *hw,
18         unsigned long parent_rate)
19 {
20     struct clk_fixed_factor *fix = to_clk_fixed_factor(hw);
21     unsigned long long int rate;
22 
23     rate = (unsigned long long int)parent_rate * fix->mult;
24     rate /= fix->div;
25     return (unsigned long)rate;
26 }
27 
clk_factor_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * prate)28 static long clk_factor_round_rate(struct clk_hw *hw, unsigned long rate,
29                                   unsigned long *prate)
30 {
31     struct clk_fixed_factor *fix = to_clk_fixed_factor(hw);
32 
33     if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)
34     {
35         unsigned long best_parent;
36 
37         best_parent = (rate / fix->mult) * fix->div;
38         *prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
39     }
40 
41     return (*prate / fix->div) * fix->mult;
42 }
43 
clk_factor_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)44 static int clk_factor_set_rate(struct clk_hw *hw, unsigned long rate,
45                                unsigned long parent_rate)
46 {
47     struct clk_fixed_factor *fix = to_clk_fixed_factor(hw);
48      /*
49      * We must report success but we can do so unconditionally because
50      * clk_factor_round_rate returns values that ensure this call is a
51      * nop.
52      */
53     if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)
54     {
55         unsigned long p_rate;
56 
57         p_rate = (rate / fix->mult) * fix->div;
58     return clk_hw_set_rate(clk_hw_get_parent(hw), p_rate);
59 
60     }
61 
62     return 0;
63 }
64 
65 const struct clk_ops clk_fixed_factor_ops =
66 {
67     .round_rate = clk_factor_round_rate,
68     .set_rate = clk_factor_set_rate,
69     .recalc_rate = clk_factor_recalc_rate,
70 };
71