1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2013 NVIDIA CORPORATION.  All rights reserved.
4  * Copyright 2019 NXP
5  */
6 
7 #include <common.h>
8 #include <asm/io.h>
9 #include <malloc.h>
10 #include <clk-uclass.h>
11 #include <dm/device.h>
12 #include <dm/devres.h>
13 #include <linux/clk-provider.h>
14 #include <clk.h>
15 #include <linux/err.h>
16 
17 #include "clk.h"
18 
19 #define UBOOT_DM_CLK_COMPOSITE "clk_composite"
20 
clk_composite_get_parent(struct clk * clk)21 static u8 clk_composite_get_parent(struct clk *clk)
22 {
23 	struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
24 		(struct clk *)dev_get_clk_ptr(clk->dev) : clk);
25 	struct clk *mux = composite->mux;
26 
27 	if (mux)
28 		return clk_mux_get_parent(mux);
29 	else
30 		return 0;
31 }
32 
clk_composite_set_parent(struct clk * clk,struct clk * parent)33 static int clk_composite_set_parent(struct clk *clk, struct clk *parent)
34 {
35 	struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
36 		(struct clk *)dev_get_clk_ptr(clk->dev) : clk);
37 	const struct clk_ops *mux_ops = composite->mux_ops;
38 	struct clk *mux = composite->mux;
39 
40 	if (mux && mux_ops)
41 		return mux_ops->set_parent(mux, parent);
42 	else
43 		return -ENOTSUPP;
44 }
45 
clk_composite_recalc_rate(struct clk * clk)46 static unsigned long clk_composite_recalc_rate(struct clk *clk)
47 {
48 	struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
49 		(struct clk *)dev_get_clk_ptr(clk->dev) : clk);
50 	const struct clk_ops *rate_ops = composite->rate_ops;
51 	struct clk *rate = composite->rate;
52 
53 	if (rate && rate_ops)
54 		return rate_ops->get_rate(rate);
55 	else
56 		return clk_get_parent_rate(clk);
57 }
58 
clk_composite_set_rate(struct clk * clk,unsigned long rate)59 static ulong clk_composite_set_rate(struct clk *clk, unsigned long rate)
60 {
61 	struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
62 		(struct clk *)dev_get_clk_ptr(clk->dev) : clk);
63 	const struct clk_ops *rate_ops = composite->rate_ops;
64 	struct clk *clk_rate = composite->rate;
65 
66 	if (rate && rate_ops)
67 		return rate_ops->set_rate(clk_rate, rate);
68 	else
69 		return clk_get_rate(clk);
70 }
71 
clk_composite_enable(struct clk * clk)72 static int clk_composite_enable(struct clk *clk)
73 {
74 	struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
75 		(struct clk *)dev_get_clk_ptr(clk->dev) : clk);
76 	const struct clk_ops *gate_ops = composite->gate_ops;
77 	struct clk *gate = composite->gate;
78 
79 	if (gate && gate_ops)
80 		return gate_ops->enable(gate);
81 	else
82 		return 0;
83 }
84 
clk_composite_disable(struct clk * clk)85 static int clk_composite_disable(struct clk *clk)
86 {
87 	struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
88 		(struct clk *)dev_get_clk_ptr(clk->dev) : clk);
89 	const struct clk_ops *gate_ops = composite->gate_ops;
90 	struct clk *gate = composite->gate;
91 
92 	if (gate && gate_ops)
93 		return gate_ops->disable(gate);
94 	else
95 		return 0;
96 }
97 
clk_register_composite(struct device * dev,const char * name,const char * const * parent_names,int num_parents,struct clk * mux,const struct clk_ops * mux_ops,struct clk * rate,const struct clk_ops * rate_ops,struct clk * gate,const struct clk_ops * gate_ops,unsigned long flags)98 struct clk *clk_register_composite(struct device *dev, const char *name,
99 				   const char * const *parent_names,
100 				   int num_parents, struct clk *mux,
101 				   const struct clk_ops *mux_ops,
102 				   struct clk *rate,
103 				   const struct clk_ops *rate_ops,
104 				   struct clk *gate,
105 				   const struct clk_ops *gate_ops,
106 				   unsigned long flags)
107 {
108 	struct clk *clk;
109 	struct clk_composite *composite;
110 	int ret;
111 
112 	if (!num_parents || (num_parents != 1 && !mux))
113 		return ERR_PTR(-EINVAL);
114 
115 	composite = kzalloc(sizeof(*composite), GFP_KERNEL);
116 	if (!composite)
117 		return ERR_PTR(-ENOMEM);
118 
119 	if (mux && mux_ops) {
120 		composite->mux = mux;
121 		composite->mux_ops = mux_ops;
122 		mux->data = (ulong)composite;
123 	}
124 
125 	if (rate && rate_ops) {
126 		if (!rate_ops->get_rate) {
127 			clk = ERR_PTR(-EINVAL);
128 			goto err;
129 		}
130 
131 		composite->rate = rate;
132 		composite->rate_ops = rate_ops;
133 		rate->data = (ulong)composite;
134 	}
135 
136 	if (gate && gate_ops) {
137 		if (!gate_ops->enable || !gate_ops->disable) {
138 			clk = ERR_PTR(-EINVAL);
139 			goto err;
140 		}
141 
142 		composite->gate = gate;
143 		composite->gate_ops = gate_ops;
144 		gate->data = (ulong)composite;
145 	}
146 
147 	clk = &composite->clk;
148 	clk->flags = flags;
149 	ret = clk_register(clk, UBOOT_DM_CLK_COMPOSITE, name,
150 			   parent_names[clk_composite_get_parent(clk)]);
151 	if (ret) {
152 		clk = ERR_PTR(ret);
153 		goto err;
154 	}
155 
156 	if (composite->mux)
157 		composite->mux->dev = clk->dev;
158 	if (composite->rate)
159 		composite->rate->dev = clk->dev;
160 	if (composite->gate)
161 		composite->gate->dev = clk->dev;
162 
163 	return clk;
164 
165 err:
166 	kfree(composite);
167 	return clk;
168 }
169 
170 static const struct clk_ops clk_composite_ops = {
171 	.set_parent = clk_composite_set_parent,
172 	.get_rate = clk_composite_recalc_rate,
173 	.set_rate = clk_composite_set_rate,
174 	.enable = clk_composite_enable,
175 	.disable = clk_composite_disable,
176 };
177 
178 U_BOOT_DRIVER(clk_composite) = {
179 	.name	= UBOOT_DM_CLK_COMPOSITE,
180 	.id	= UCLASS_CLK,
181 	.ops	= &clk_composite_ops,
182 	.flags = DM_FLAG_PRE_RELOC,
183 };
184