Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
3 : : *
4 : : * This program is free software; you can redistribute it and/or modify
5 : : * it under the terms of the GNU General Public License version 2 as
6 : : * published by the Free Software Foundation.
7 : : *
8 : : * Standard functionality for the common clock API.
9 : : */
10 : : #include <linux/module.h>
11 : : #include <linux/clk-provider.h>
12 : : #include <linux/slab.h>
13 : : #include <linux/err.h>
14 : : #include <linux/of.h>
15 : :
16 : : /*
17 : : * DOC: basic fixed multiplier and divider clock that cannot gate
18 : : *
19 : : * Traits of this clock:
20 : : * prepare - clk_prepare only ensures that parents are prepared
21 : : * enable - clk_enable only ensures that parents are enabled
22 : : * rate - rate is fixed. clk->rate = parent->rate / div * mult
23 : : * parent - fixed parent. No clk_set_parent support
24 : : */
25 : :
26 : : #define to_clk_fixed_factor(_hw) container_of(_hw, struct clk_fixed_factor, hw)
27 : :
28 : 0 : static unsigned long clk_factor_recalc_rate(struct clk_hw *hw,
29 : : unsigned long parent_rate)
30 : : {
31 : : struct clk_fixed_factor *fix = to_clk_fixed_factor(hw);
32 : : unsigned long long int rate;
33 : :
34 : 0 : rate = (unsigned long long int)parent_rate * fix->mult;
35 [ # # ][ # # ]: 0 : do_div(rate, fix->div);
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
36 : 0 : return (unsigned long)rate;
37 : : }
38 : :
39 : 0 : static long clk_factor_round_rate(struct clk_hw *hw, unsigned long rate,
40 : : unsigned long *prate)
41 : : {
42 : : struct clk_fixed_factor *fix = to_clk_fixed_factor(hw);
43 : :
44 [ # # ]: 0 : if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
45 : : unsigned long best_parent;
46 : :
47 : 0 : best_parent = (rate / fix->mult) * fix->div;
48 : 0 : *prate = __clk_round_rate(__clk_get_parent(hw->clk),
49 : : best_parent);
50 : : }
51 : :
52 : 0 : return (*prate / fix->div) * fix->mult;
53 : : }
54 : :
55 : 0 : static int clk_factor_set_rate(struct clk_hw *hw, unsigned long rate,
56 : : unsigned long parent_rate)
57 : : {
58 : 0 : return 0;
59 : : }
60 : :
61 : : struct clk_ops clk_fixed_factor_ops = {
62 : : .round_rate = clk_factor_round_rate,
63 : : .set_rate = clk_factor_set_rate,
64 : : .recalc_rate = clk_factor_recalc_rate,
65 : : };
66 : : EXPORT_SYMBOL_GPL(clk_fixed_factor_ops);
67 : :
68 : 0 : struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
69 : : const char *parent_name, unsigned long flags,
70 : : unsigned int mult, unsigned int div)
71 : : {
72 : : struct clk_fixed_factor *fix;
73 : : struct clk_init_data init;
74 : : struct clk *clk;
75 : :
76 : : fix = kmalloc(sizeof(*fix), GFP_KERNEL);
77 [ # # ]: 0 : if (!fix) {
78 : 0 : pr_err("%s: could not allocate fixed factor clk\n", __func__);
79 : 0 : return ERR_PTR(-ENOMEM);
80 : : }
81 : :
82 : : /* struct clk_fixed_factor assignments */
83 : 0 : fix->mult = mult;
84 : 0 : fix->div = div;
85 : 0 : fix->hw.init = &init;
86 : :
87 : 0 : init.name = name;
88 : 0 : init.ops = &clk_fixed_factor_ops;
89 : 0 : init.flags = flags | CLK_IS_BASIC;
90 : 0 : init.parent_names = &parent_name;
91 : 0 : init.num_parents = 1;
92 : :
93 : 0 : clk = clk_register(dev, &fix->hw);
94 : :
95 [ # # ]: 0 : if (IS_ERR(clk))
96 : 0 : kfree(fix);
97 : :
98 : 0 : return clk;
99 : : }
100 : : EXPORT_SYMBOL_GPL(clk_register_fixed_factor);
101 : :
102 : : #ifdef CONFIG_OF
103 : : /**
104 : : * of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock
105 : : */
106 : 0 : void __init of_fixed_factor_clk_setup(struct device_node *node)
107 : : {
108 : : struct clk *clk;
109 : 0 : const char *clk_name = node->name;
110 : : const char *parent_name;
111 : : u32 div, mult;
112 : :
113 [ # # ]: 0 : if (of_property_read_u32(node, "clock-div", &div)) {
114 : 0 : pr_err("%s Fixed factor clock <%s> must have a clock-div property\n",
115 : : __func__, node->name);
116 : 0 : return;
117 : : }
118 : :
119 [ # # ]: 0 : if (of_property_read_u32(node, "clock-mult", &mult)) {
120 : 0 : pr_err("%s Fixed factor clock <%s> must have a clock-mult property\n",
121 : : __func__, node->name);
122 : 0 : return;
123 : : }
124 : :
125 : 0 : of_property_read_string(node, "clock-output-names", &clk_name);
126 : 0 : parent_name = of_clk_get_parent_name(node, 0);
127 : :
128 : 0 : clk = clk_register_fixed_factor(NULL, clk_name, parent_name, 0,
129 : : mult, div);
130 [ # # ]: 0 : if (!IS_ERR(clk))
131 : 0 : of_clk_add_provider(node, of_clk_src_simple_get, clk);
132 : : }
133 : : EXPORT_SYMBOL_GPL(of_fixed_factor_clk_setup);
134 : : CLK_OF_DECLARE(fixed_factor_clk, "fixed-factor-clock",
135 : : of_fixed_factor_clk_setup);
136 : : #endif
|