clk: mediatek: add support to configure clock driver parent
[platform/kernel/u-boot.git] / drivers / clk / clk_sandbox.c
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
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
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
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
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
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
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
104 static void 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;
110
111         priv->requested[clk->id] = false;
112         return;
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
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
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
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
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
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 };