]>
Commit | Line | Data |
---|---|---|
f26c8a8e SG |
1 | /* |
2 | * Copyright (C) 2015 Google, Inc | |
3 | * Written by Simon Glass <sjg@chromium.org> | |
135aa950 | 4 | * Copyright (c) 2016, NVIDIA CORPORATION. |
f26c8a8e SG |
5 | * |
6 | * SPDX-License-Identifier: GPL-2.0+ | |
7 | */ | |
8 | ||
9 | #include <common.h> | |
10 | #include <clk.h> | |
135aa950 | 11 | #include <clk-uclass.h> |
f26c8a8e | 12 | #include <dm.h> |
7423daa6 | 13 | #include <dt-structs.h> |
f26c8a8e | 14 | #include <errno.h> |
f26c8a8e | 15 | |
e70cc438 SG |
16 | DECLARE_GLOBAL_DATA_PTR; |
17 | ||
135aa950 | 18 | static inline struct clk_ops *clk_dev_ops(struct udevice *dev) |
f26c8a8e | 19 | { |
135aa950 | 20 | return (struct clk_ops *)dev->driver->ops; |
f26c8a8e SG |
21 | } |
22 | ||
135aa950 SW |
23 | #if CONFIG_IS_ENABLED(OF_CONTROL) |
24 | #ifdef CONFIG_SPL_BUILD | |
7423daa6 SG |
25 | # if CONFIG_IS_ENABLED(OF_PLATDATA) |
26 | int clk_get_by_index_platdata(struct udevice *dev, int index, | |
27 | struct phandle_2_cell *cells, struct clk *clk) | |
28 | { | |
29 | int ret; | |
30 | ||
31 | if (index != 0) | |
32 | return -ENOSYS; | |
33 | ret = uclass_get_device(UCLASS_CLK, 0, &clk->dev); | |
34 | if (ret) | |
35 | return ret; | |
36 | clk->id = cells[0].id; | |
37 | ||
38 | return 0; | |
39 | } | |
40 | # else | |
135aa950 | 41 | int clk_get_by_index(struct udevice *dev, int index, struct clk *clk) |
f26c8a8e | 42 | { |
135aa950 SW |
43 | int ret; |
44 | u32 cell[2]; | |
f26c8a8e | 45 | |
135aa950 | 46 | if (index != 0) |
f26c8a8e | 47 | return -ENOSYS; |
135aa950 SW |
48 | assert(clk); |
49 | ret = uclass_get_device(UCLASS_CLK, 0, &clk->dev); | |
50 | if (ret) | |
51 | return ret; | |
52 | ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "clocks", | |
53 | cell, 2); | |
54 | if (ret) | |
55 | return ret; | |
56 | clk->id = cell[1]; | |
57 | return 0; | |
f26c8a8e | 58 | } |
7423daa6 | 59 | # endif /* OF_PLATDATA */ |
f26c8a8e | 60 | |
135aa950 | 61 | int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk) |
f0e07516 | 62 | { |
135aa950 | 63 | return -ENOSYS; |
f0e07516 | 64 | } |
135aa950 SW |
65 | #else |
66 | static int clk_of_xlate_default(struct clk *clk, | |
67 | struct fdtdec_phandle_args *args) | |
f26c8a8e | 68 | { |
135aa950 | 69 | debug("%s(clk=%p)\n", __func__, clk); |
f26c8a8e | 70 | |
135aa950 SW |
71 | if (args->args_count > 1) { |
72 | debug("Invaild args_count: %d\n", args->args_count); | |
73 | return -EINVAL; | |
74 | } | |
f26c8a8e | 75 | |
135aa950 SW |
76 | if (args->args_count) |
77 | clk->id = args->args[0]; | |
78 | else | |
79 | clk->id = 0; | |
f26c8a8e | 80 | |
135aa950 | 81 | return 0; |
f26c8a8e SG |
82 | } |
83 | ||
135aa950 | 84 | int clk_get_by_index(struct udevice *dev, int index, struct clk *clk) |
e70cc438 | 85 | { |
e70cc438 | 86 | int ret; |
a4b10c08 | 87 | struct fdtdec_phandle_args args; |
135aa950 SW |
88 | struct udevice *dev_clk; |
89 | struct clk_ops *ops; | |
90 | ||
91 | debug("%s(dev=%p, index=%d, clk=%p)\n", __func__, dev, index, clk); | |
e70cc438 | 92 | |
135aa950 | 93 | assert(clk); |
e70cc438 SG |
94 | ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset, |
95 | "clocks", "#clock-cells", 0, index, | |
96 | &args); | |
97 | if (ret) { | |
98 | debug("%s: fdtdec_parse_phandle_with_args failed: err=%d\n", | |
99 | __func__, ret); | |
100 | return ret; | |
101 | } | |
102 | ||
135aa950 | 103 | ret = uclass_get_device_by_of_offset(UCLASS_CLK, args.node, &dev_clk); |
e70cc438 SG |
104 | if (ret) { |
105 | debug("%s: uclass_get_device_by_of_offset failed: err=%d\n", | |
106 | __func__, ret); | |
107 | return ret; | |
108 | } | |
135aa950 SW |
109 | ops = clk_dev_ops(dev_clk); |
110 | ||
111 | if (ops->of_xlate) | |
112 | ret = ops->of_xlate(clk, &args); | |
113 | else | |
114 | ret = clk_of_xlate_default(clk, &args); | |
115 | if (ret) { | |
116 | debug("of_xlate() failed: %d\n", ret); | |
117 | return ret; | |
118 | } | |
119 | ||
120 | return clk_request(dev_clk, clk); | |
121 | } | |
122 | ||
123 | int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk) | |
124 | { | |
125 | int index; | |
126 | ||
127 | debug("%s(dev=%p, name=%s, clk=%p)\n", __func__, dev, name, clk); | |
128 | ||
129 | index = fdt_find_string(gd->fdt_blob, dev->of_offset, "clock-names", | |
130 | name); | |
131 | if (index < 0) { | |
132 | debug("fdt_find_string() failed: %d\n", index); | |
133 | return index; | |
134 | } | |
135 | ||
136 | return clk_get_by_index(dev, index, clk); | |
e70cc438 | 137 | } |
7423daa6 SG |
138 | #endif /* CONFIG_SPL_BUILD */ |
139 | #endif /* OF_CONTROL */ | |
135aa950 SW |
140 | |
141 | int clk_request(struct udevice *dev, struct clk *clk) | |
142 | { | |
143 | struct clk_ops *ops = clk_dev_ops(dev); | |
144 | ||
145 | debug("%s(dev=%p, clk=%p)\n", __func__, dev, clk); | |
146 | ||
147 | clk->dev = dev; | |
148 | ||
149 | if (!ops->request) | |
150 | return 0; | |
151 | ||
152 | return ops->request(clk); | |
153 | } | |
154 | ||
155 | int clk_free(struct clk *clk) | |
156 | { | |
157 | struct clk_ops *ops = clk_dev_ops(clk->dev); | |
158 | ||
159 | debug("%s(clk=%p)\n", __func__, clk); | |
160 | ||
161 | if (!ops->free) | |
162 | return 0; | |
163 | ||
164 | return ops->free(clk); | |
165 | } | |
166 | ||
167 | ulong clk_get_rate(struct clk *clk) | |
168 | { | |
169 | struct clk_ops *ops = clk_dev_ops(clk->dev); | |
170 | ||
171 | debug("%s(clk=%p)\n", __func__, clk); | |
172 | ||
173 | if (!ops->get_rate) | |
174 | return -ENOSYS; | |
175 | ||
176 | return ops->get_rate(clk); | |
177 | } | |
178 | ||
179 | ulong clk_set_rate(struct clk *clk, ulong rate) | |
180 | { | |
181 | struct clk_ops *ops = clk_dev_ops(clk->dev); | |
182 | ||
183 | debug("%s(clk=%p, rate=%lu)\n", __func__, clk, rate); | |
184 | ||
185 | if (!ops->set_rate) | |
186 | return -ENOSYS; | |
187 | ||
188 | return ops->set_rate(clk, rate); | |
189 | } | |
190 | ||
191 | int clk_enable(struct clk *clk) | |
192 | { | |
193 | struct clk_ops *ops = clk_dev_ops(clk->dev); | |
194 | ||
195 | debug("%s(clk=%p)\n", __func__, clk); | |
196 | ||
197 | if (!ops->enable) | |
198 | return -ENOSYS; | |
199 | ||
200 | return ops->enable(clk); | |
201 | } | |
202 | ||
203 | int clk_disable(struct clk *clk) | |
204 | { | |
205 | struct clk_ops *ops = clk_dev_ops(clk->dev); | |
206 | ||
207 | debug("%s(clk=%p)\n", __func__, clk); | |
208 | ||
209 | if (!ops->disable) | |
210 | return -ENOSYS; | |
211 | ||
212 | return ops->disable(clk); | |
213 | } | |
e70cc438 | 214 | |
f26c8a8e SG |
215 | UCLASS_DRIVER(clk) = { |
216 | .id = UCLASS_CLK, | |
217 | .name = "clk", | |
218 | }; |