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