1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
5 #include <linux/module.h>
6 #include <linux/clk-provider.h>
7 #include <linux/slab.h>
10 #include <linux/platform_device.h>
13 * DOC: basic fixed multiplier and divider clock that cannot gate
15 * Traits of this clock:
16 * prepare - clk_prepare only ensures that parents are prepared
17 * enable - clk_enable only ensures that parents are enabled
18 * rate - rate is fixed. clk->rate = parent->rate / div * mult
19 * parent - fixed parent. No clk_set_parent support
22 static unsigned long clk_factor_recalc_rate(struct clk_hw
*hw
,
23 unsigned long parent_rate
)
25 struct clk_fixed_factor
*fix
= to_clk_fixed_factor(hw
);
26 unsigned long long int rate
;
28 rate
= (unsigned long long int)parent_rate
* fix
->mult
;
29 do_div(rate
, fix
->div
);
30 return (unsigned long)rate
;
33 static long clk_factor_round_rate(struct clk_hw
*hw
, unsigned long rate
,
36 struct clk_fixed_factor
*fix
= to_clk_fixed_factor(hw
);
38 if (clk_hw_get_flags(hw
) & CLK_SET_RATE_PARENT
) {
39 unsigned long best_parent
;
41 best_parent
= (rate
/ fix
->mult
) * fix
->div
;
42 *prate
= clk_hw_round_rate(clk_hw_get_parent(hw
), best_parent
);
45 return (*prate
/ fix
->div
) * fix
->mult
;
48 static int clk_factor_set_rate(struct clk_hw
*hw
, unsigned long rate
,
49 unsigned long parent_rate
)
52 * We must report success but we can do so unconditionally because
53 * clk_factor_round_rate returns values that ensure this call is a
60 const struct clk_ops clk_fixed_factor_ops
= {
61 .round_rate
= clk_factor_round_rate
,
62 .set_rate
= clk_factor_set_rate
,
63 .recalc_rate
= clk_factor_recalc_rate
,
65 EXPORT_SYMBOL_GPL(clk_fixed_factor_ops
);
67 static struct clk_hw
*
68 __clk_hw_register_fixed_factor(struct device
*dev
, struct device_node
*np
,
69 const char *name
, const char *parent_name
, int index
,
70 unsigned long flags
, unsigned int mult
, unsigned int div
)
72 struct clk_fixed_factor
*fix
;
73 struct clk_init_data init
= { };
74 struct clk_parent_data pdata
= { .index
= index
};
78 fix
= kmalloc(sizeof(*fix
), GFP_KERNEL
);
80 return ERR_PTR(-ENOMEM
);
82 /* struct clk_fixed_factor assignments */
88 init
.ops
= &clk_fixed_factor_ops
;
91 init
.parent_names
= &parent_name
;
93 init
.parent_data
= &pdata
;
98 ret
= clk_hw_register(dev
, hw
);
100 ret
= of_clk_hw_register(np
, hw
);
109 struct clk_hw
*clk_hw_register_fixed_factor(struct device
*dev
,
110 const char *name
, const char *parent_name
, unsigned long flags
,
111 unsigned int mult
, unsigned int div
)
113 return __clk_hw_register_fixed_factor(dev
, NULL
, name
, parent_name
, -1,
116 EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor
);
118 struct clk
*clk_register_fixed_factor(struct device
*dev
, const char *name
,
119 const char *parent_name
, unsigned long flags
,
120 unsigned int mult
, unsigned int div
)
124 hw
= clk_hw_register_fixed_factor(dev
, name
, parent_name
, flags
, mult
,
130 EXPORT_SYMBOL_GPL(clk_register_fixed_factor
);
132 void clk_unregister_fixed_factor(struct clk
*clk
)
136 hw
= __clk_get_hw(clk
);
141 kfree(to_clk_fixed_factor(hw
));
143 EXPORT_SYMBOL_GPL(clk_unregister_fixed_factor
);
145 void clk_hw_unregister_fixed_factor(struct clk_hw
*hw
)
147 struct clk_fixed_factor
*fix
;
149 fix
= to_clk_fixed_factor(hw
);
151 clk_hw_unregister(hw
);
154 EXPORT_SYMBOL_GPL(clk_hw_unregister_fixed_factor
);
157 static const struct of_device_id set_rate_parent_matches
[] = {
158 { .compatible
= "allwinner,sun4i-a10-pll3-2x-clk" },
162 static struct clk_hw
*_of_fixed_factor_clk_setup(struct device_node
*node
)
165 const char *clk_name
= node
->name
;
166 unsigned long flags
= 0;
170 if (of_property_read_u32(node
, "clock-div", &div
)) {
171 pr_err("%s Fixed factor clock <%pOFn> must have a clock-div property\n",
173 return ERR_PTR(-EIO
);
176 if (of_property_read_u32(node
, "clock-mult", &mult
)) {
177 pr_err("%s Fixed factor clock <%pOFn> must have a clock-mult property\n",
179 return ERR_PTR(-EIO
);
182 of_property_read_string(node
, "clock-output-names", &clk_name
);
184 if (of_match_node(set_rate_parent_matches
, node
))
185 flags
|= CLK_SET_RATE_PARENT
;
187 hw
= __clk_hw_register_fixed_factor(NULL
, node
, clk_name
, NULL
, 0,
191 * Clear OF_POPULATED flag so that clock registration can be
192 * attempted again from probe function.
194 of_node_clear_flag(node
, OF_POPULATED
);
198 ret
= of_clk_add_hw_provider(node
, of_clk_hw_simple_get
, hw
);
200 clk_hw_unregister_fixed_factor(hw
);
208 * of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock
209 * @node: device node for the clock
211 void __init
of_fixed_factor_clk_setup(struct device_node
*node
)
213 _of_fixed_factor_clk_setup(node
);
215 CLK_OF_DECLARE(fixed_factor_clk
, "fixed-factor-clock",
216 of_fixed_factor_clk_setup
);
218 static int of_fixed_factor_clk_remove(struct platform_device
*pdev
)
220 struct clk_hw
*clk
= platform_get_drvdata(pdev
);
222 of_clk_del_provider(pdev
->dev
.of_node
);
223 clk_hw_unregister_fixed_factor(clk
);
228 static int of_fixed_factor_clk_probe(struct platform_device
*pdev
)
233 * This function is not executed when of_fixed_factor_clk_setup
236 clk
= _of_fixed_factor_clk_setup(pdev
->dev
.of_node
);
240 platform_set_drvdata(pdev
, clk
);
245 static const struct of_device_id of_fixed_factor_clk_ids
[] = {
246 { .compatible
= "fixed-factor-clock" },
249 MODULE_DEVICE_TABLE(of
, of_fixed_factor_clk_ids
);
251 static struct platform_driver of_fixed_factor_clk_driver
= {
253 .name
= "of_fixed_factor_clk",
254 .of_match_table
= of_fixed_factor_clk_ids
,
256 .probe
= of_fixed_factor_clk_probe
,
257 .remove
= of_fixed_factor_clk_remove
,
259 builtin_platform_driver(of_fixed_factor_clk_driver
);