1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * (C) Copyright 2015 Google, Inc
4  */
5 
6 #include <common.h>
7 #include <clk-uclass.h>
8 #include <dm.h>
9 #include <errno.h>
10 #include <malloc.h>
11 #include <asm/clk.h>
12 #include <linux/clk-provider.h>
13 
sandbox_clk_get_rate(struct clk * clk)14 static ulong sandbox_clk_get_rate(struct clk *clk)
15 {
16 	struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
17 
18 	if (!priv->probed)
19 		return -ENODEV;
20 
21 	if (clk->id >= SANDBOX_CLK_ID_COUNT)
22 		return -EINVAL;
23 
24 	return priv->rate[clk->id];
25 }
26 
sandbox_clk_round_rate(struct clk * clk,ulong rate)27 static ulong sandbox_clk_round_rate(struct clk *clk, ulong rate)
28 {
29 	struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
30 
31 	if (!priv->probed)
32 		return -ENODEV;
33 
34 	if (clk->id >= SANDBOX_CLK_ID_COUNT)
35 		return -EINVAL;
36 
37 	if (!rate)
38 		return -EINVAL;
39 
40 	return rate;
41 }
42 
sandbox_clk_set_rate(struct clk * clk,ulong rate)43 static ulong sandbox_clk_set_rate(struct clk *clk, ulong rate)
44 {
45 	struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
46 	ulong old_rate;
47 
48 	if (!priv->probed)
49 		return -ENODEV;
50 
51 	if (clk->id >= SANDBOX_CLK_ID_COUNT)
52 		return -EINVAL;
53 
54 	if (!rate)
55 		return -EINVAL;
56 
57 	old_rate = priv->rate[clk->id];
58 	priv->rate[clk->id] = rate;
59 
60 	return old_rate;
61 }
62 
sandbox_clk_enable(struct clk * clk)63 static int sandbox_clk_enable(struct clk *clk)
64 {
65 	struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
66 
67 	if (!priv->probed)
68 		return -ENODEV;
69 
70 	if (clk->id >= SANDBOX_CLK_ID_COUNT)
71 		return -EINVAL;
72 
73 	priv->enabled[clk->id] = true;
74 
75 	return 0;
76 }
77 
sandbox_clk_disable(struct clk * clk)78 static int sandbox_clk_disable(struct clk *clk)
79 {
80 	struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
81 
82 	if (!priv->probed)
83 		return -ENODEV;
84 
85 	if (clk->id >= SANDBOX_CLK_ID_COUNT)
86 		return -EINVAL;
87 
88 	priv->enabled[clk->id] = false;
89 
90 	return 0;
91 }
92 
sandbox_clk_request(struct clk * clk)93 static int sandbox_clk_request(struct clk *clk)
94 {
95 	struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
96 
97 	if (clk->id >= SANDBOX_CLK_ID_COUNT)
98 		return -EINVAL;
99 
100 	priv->requested[clk->id] = true;
101 	return 0;
102 }
103 
sandbox_clk_free(struct clk * clk)104 static int sandbox_clk_free(struct clk *clk)
105 {
106 	struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
107 
108 	if (clk->id >= SANDBOX_CLK_ID_COUNT)
109 		return -EINVAL;
110 
111 	priv->requested[clk->id] = false;
112 	return 0;
113 }
114 
115 static struct clk_ops sandbox_clk_ops = {
116 	.round_rate	= sandbox_clk_round_rate,
117 	.get_rate	= sandbox_clk_get_rate,
118 	.set_rate	= sandbox_clk_set_rate,
119 	.enable		= sandbox_clk_enable,
120 	.disable	= sandbox_clk_disable,
121 	.request	= sandbox_clk_request,
122 	.rfree		= sandbox_clk_free,
123 };
124 
sandbox_clk_probe(struct udevice * dev)125 static int sandbox_clk_probe(struct udevice *dev)
126 {
127 	struct sandbox_clk_priv *priv = dev_get_priv(dev);
128 
129 	priv->probed = true;
130 	return 0;
131 }
132 
133 static const struct udevice_id sandbox_clk_ids[] = {
134 	{ .compatible = "sandbox,clk" },
135 	{ }
136 };
137 
138 U_BOOT_DRIVER(sandbox_clk) = {
139 	.name		= "sandbox_clk",
140 	.id		= UCLASS_CLK,
141 	.of_match	= sandbox_clk_ids,
142 	.ops		= &sandbox_clk_ops,
143 	.probe		= sandbox_clk_probe,
144 	.priv_auto	= sizeof(struct sandbox_clk_priv),
145 };
146 
sandbox_clk_query_rate(struct udevice * dev,int id)147 ulong sandbox_clk_query_rate(struct udevice *dev, int id)
148 {
149 	struct sandbox_clk_priv *priv = dev_get_priv(dev);
150 
151 	if (id < 0 || id >= SANDBOX_CLK_ID_COUNT)
152 		return -EINVAL;
153 
154 	return priv->rate[id];
155 }
156 
sandbox_clk_query_enable(struct udevice * dev,int id)157 int sandbox_clk_query_enable(struct udevice *dev, int id)
158 {
159 	struct sandbox_clk_priv *priv = dev_get_priv(dev);
160 
161 	if (id < 0 || id >= SANDBOX_CLK_ID_COUNT)
162 		return -EINVAL;
163 
164 	return priv->enabled[id];
165 }
166 
sandbox_clk_query_requested(struct udevice * dev,int id)167 int sandbox_clk_query_requested(struct udevice *dev, int id)
168 {
169 	struct sandbox_clk_priv *priv = dev_get_priv(dev);
170 
171 	if (id < 0 || id >= SANDBOX_CLK_ID_COUNT)
172 		return -EINVAL;
173 	return priv->requested[id];
174 }
175 
clk_fixed_rate_of_to_plat(struct udevice * dev)176 int clk_fixed_rate_of_to_plat(struct udevice *dev)
177 {
178 	struct clk_fixed_rate *cplat;
179 
180 #if CONFIG_IS_ENABLED(OF_PLATDATA)
181 	struct sandbox_clk_fixed_rate_plat *plat = dev_get_plat(dev);
182 
183 	cplat = &plat->fixed;
184 	cplat->fixed_rate = plat->dtplat.clock_frequency;
185 #else
186 	cplat = to_clk_fixed_rate(dev);
187 #endif
188 	clk_fixed_rate_ofdata_to_plat_(dev, cplat);
189 
190 	return 0;
191 }
192 
193 static const struct udevice_id sandbox_clk_fixed_rate_match[] = {
194 	{ .compatible = "sandbox,fixed-clock" },
195 	{ /* sentinel */ }
196 };
197 
198 U_BOOT_DRIVER(sandbox_fixed_clock) = {
199 	.name = "sandbox_fixed_clock",
200 	.id = UCLASS_CLK,
201 	.of_match = sandbox_clk_fixed_rate_match,
202 	.of_to_plat = clk_fixed_rate_of_to_plat,
203 	.plat_auto = sizeof(struct sandbox_clk_fixed_rate_plat),
204 	.ops = &clk_fixed_rate_ops,
205 	.flags = DM_FLAG_PRE_RELOC,
206 };
207