1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2019 DENX Software Engineering
4  * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
5  *
6  * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
7  */
8 
9 #define LOG_CATEGORY UCLASS_CLK
10 
11 #include <clk.h>
12 #include <clk-uclass.h>
13 #include <div64.h>
14 #include <log.h>
15 #include <malloc.h>
16 #include <dm/device.h>
17 #include <dm/devres.h>
18 #include <linux/clk-provider.h>
19 #include <linux/err.h>
20 
21 #include "clk.h"
22 
23 #define UBOOT_DM_CLK_IMX_FIXED_FACTOR "ccf_clk_fixed_factor"
24 
clk_factor_recalc_rate(struct clk * clk)25 static ulong clk_factor_recalc_rate(struct clk *clk)
26 {
27 	struct clk_fixed_factor *fix = to_clk_fixed_factor(clk);
28 	unsigned long parent_rate = clk_get_parent_rate(clk);
29 	unsigned long long int rate;
30 
31 	rate = (unsigned long long int)parent_rate * fix->mult;
32 	do_div(rate, fix->div);
33 	return (ulong)rate;
34 }
35 
36 const struct clk_ops ccf_clk_fixed_factor_ops = {
37 	.get_rate = clk_factor_recalc_rate,
38 };
39 
clk_hw_register_fixed_factor(struct udevice * dev,const char * name,const char * parent_name,unsigned long flags,unsigned int mult,unsigned int div)40 struct clk *clk_hw_register_fixed_factor(struct udevice *dev,
41 		const char *name, const char *parent_name, unsigned long flags,
42 		unsigned int mult, unsigned int div)
43 {
44 	struct clk_fixed_factor *fix;
45 	struct clk *clk;
46 	int ret;
47 
48 	fix = kzalloc(sizeof(*fix), GFP_KERNEL);
49 	if (!fix)
50 		return ERR_PTR(-ENOMEM);
51 
52 	/* struct clk_fixed_factor assignments */
53 	fix->mult = mult;
54 	fix->div = div;
55 	clk = &fix->clk;
56 	clk->flags = flags;
57 
58 	ret = clk_register(clk, UBOOT_DM_CLK_IMX_FIXED_FACTOR, name,
59 			   clk_resolve_parent_clk(dev, parent_name));
60 	if (ret) {
61 		kfree(fix);
62 		return ERR_PTR(ret);
63 	}
64 
65 	return clk;
66 }
67 
clk_register_fixed_factor(struct udevice * dev,const char * name,const char * parent_name,unsigned long flags,unsigned int mult,unsigned int div)68 struct clk *clk_register_fixed_factor(struct udevice *dev, const char *name,
69 		const char *parent_name, unsigned long flags,
70 		unsigned int mult, unsigned int div)
71 {
72 	struct clk *clk;
73 
74 	clk = clk_hw_register_fixed_factor(dev, name, parent_name, flags, mult,
75 					  div);
76 	if (IS_ERR(clk))
77 		return ERR_CAST(clk);
78 	return clk;
79 }
80 
81 U_BOOT_DRIVER(imx_clk_fixed_factor) = {
82 	.name	= UBOOT_DM_CLK_IMX_FIXED_FACTOR,
83 	.id	= UCLASS_CLK,
84 	.ops	= &ccf_clk_fixed_factor_ops,
85 	.flags = DM_FLAG_PRE_RELOC,
86 };
87