1 /*
2 * clock driver adapter of linux
3 *
4 * Copyright (c) 2023 Huawei Device Co., Ltd.
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY;without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17 #include <linux/clk.h>
18 #include <linux/of.h>
19 #include <linux/of_platform.h>
20
21 #include "device_resource_if.h"
22 #include "hdf_base.h"
23 #include "hdf_device_desc.h"
24 #include "hdf_log.h"
25 #include "osal_mem.h"
26 #include "securec.h"
27 #include "clock_core.h"
28
29 #define HDF_LOG_TAG clock_adapter_c
30
ClockStart(struct ClockDevice * device)31 static int32_t ClockStart(struct ClockDevice *device)
32 {
33 struct clk *clk = NULL;
34 struct device_node *node = NULL;
35
36 if (device->clk != NULL) {
37 HDF_LOGI("device->clk already start\n");
38 return HDF_SUCCESS;
39 }
40
41 if (IS_ERR_OR_NULL(device->deviceName)) {
42 HDF_LOGE("ClockStart: deviceName IS_ERR_OR_NULL\n");
43 return HDF_ERR_INVALID_PARAM;
44 }
45
46 node = of_find_node_by_path(device->deviceName);
47 if (IS_ERR_OR_NULL(node)) {
48 HDF_LOGE("ClockStart: can not get node \n");
49 return HDF_ERR_INVALID_PARAM;
50 }
51
52 clk = of_clk_get_by_name(node, device->clockName);
53 if (IS_ERR_OR_NULL(clk)) {
54 HDF_LOGE("ClockStart: can not get clk \n");
55 return HDF_ERR_INVALID_PARAM;
56 }
57
58 device->clk = clk;
59 return HDF_SUCCESS;
60 }
61
ClockLinuxSetRate(struct ClockDevice * device,uint32_t rate)62 static int32_t ClockLinuxSetRate(struct ClockDevice *device, uint32_t rate)
63 {
64 struct clk *clk = NULL;
65 int32_t ret;
66
67 clk = device->clk;
68 if (IS_ERR_OR_NULL(clk)) {
69 HDF_LOGE("ClockLinuxSetRate: clk IS_ERR_OR_NULL\n");
70 return HDF_FAILURE;
71 }
72 ret = clk_set_rate(clk, rate);
73 return ret;
74 }
75
ClockStop(struct ClockDevice * device)76 static int32_t ClockStop(struct ClockDevice *device)
77 {
78 struct clk *clk = NULL;
79
80 clk = device->clk;
81 if (IS_ERR_OR_NULL(clk)) {
82 HDF_LOGE("ClockStop: clk IS_ERR_OR_NULL\n");
83 return HDF_ERR_INVALID_PARAM;
84 }
85
86 if (device->deviceName) {
87 clk_put(clk);
88 }
89
90 device->clk = NULL;
91 return HDF_SUCCESS;
92 }
93
ClockLinuxGetRate(struct ClockDevice * device,uint32_t * rate)94 static int32_t ClockLinuxGetRate(struct ClockDevice *device, uint32_t *rate)
95 {
96 struct clk *clk = NULL;
97
98 clk = device->clk;
99 if (IS_ERR_OR_NULL(clk)) {
100 HDF_LOGE("ClockLinuxGetRate: clk IS_ERR_OR_NULL\n");
101 return HDF_ERR_INVALID_PARAM;
102 }
103
104 *rate = clk_get_rate(clk);
105 return HDF_SUCCESS;
106 }
107
ClockLinuxDisable(struct ClockDevice * device)108 static int32_t ClockLinuxDisable(struct ClockDevice *device)
109 {
110 struct clk *clk = NULL;
111
112 clk = device->clk;
113 if (IS_ERR_OR_NULL(clk)) {
114 HDF_LOGE("ClockLinuxDisable: clk IS_ERR_OR_NULL\n");
115 return HDF_ERR_INVALID_PARAM;
116 }
117 clk_disable_unprepare(clk);
118 return HDF_SUCCESS;
119 }
120
ClockLinuxEnable(struct ClockDevice * device)121 static int32_t ClockLinuxEnable(struct ClockDevice *device)
122 {
123 struct clk *clk = NULL;
124 int32_t ret;
125
126 clk = device->clk;
127 if (IS_ERR_OR_NULL(clk)) {
128 HDF_LOGE("ClockLinuxDisable: clk IS_ERR_OR_NULL\n");
129 return HDF_ERR_INVALID_PARAM;
130 }
131
132 ret = clk_prepare_enable(clk);
133 if (ret != HDF_SUCCESS) {
134 HDF_LOGE("ClockLinuxDisable ret = %d \n", ret);
135 }
136
137 return ret;
138 }
139 static struct ClockDevice *ClockLinuxGetParent(struct ClockDevice *device);
140
141
ClockLinuxSetParent(struct ClockDevice * device,struct ClockDevice * parent)142 static int32_t ClockLinuxSetParent(struct ClockDevice *device, struct ClockDevice *parent)
143 {
144 struct clk *clk = NULL;
145 struct clk *clkParent = NULL;
146 int32_t ret;
147 if (device->parent == parent) {
148 HDF_LOGI("ClockLinuxSetParent:device parent is not change \n");
149 return HDF_SUCCESS;
150 }
151
152 clk = device->clk;
153 if (IS_ERR_OR_NULL(clk)) {
154 HDF_LOGE("ClockLinuxSetParent: clk IS_ERR_OR_NULL\n");
155 return HDF_ERR_INVALID_PARAM;
156 }
157
158 clkParent = parent->clk;
159 if (IS_ERR_OR_NULL(clkParent)) {
160 HDF_LOGE("ClockLinuxSetParent: clkParent IS_ERR_OR_NULL\n");
161 return HDF_ERR_INVALID_PARAM;
162 }
163
164 ret = clk_set_parent(clk, clkParent);
165 if (ret != HDF_SUCCESS) {
166 HDF_LOGE("ClockLinuxSetParent: clk_set_parent fail ret = %d\n", ret);
167 return ret;
168 }
169
170 if (device->parent && device->parent->deviceName == NULL) {
171 ClockDeviceRemove(device->parent);
172 OsalMemFree(device->parent);
173 }
174 device->parent = parent;
175
176 return ret;
177 }
178
179 static const struct ClockMethod g_method = {
180 .start = ClockStart,
181 .stop = ClockStop,
182 .setRate = ClockLinuxSetRate,
183 .getRate = ClockLinuxGetRate,
184 .disable = ClockLinuxDisable,
185 .enable = ClockLinuxEnable,
186 .getParent = ClockLinuxGetParent,
187 .setParent = ClockLinuxSetParent,
188 };
189
ClockLinuxGetParent(struct ClockDevice * device)190 static struct ClockDevice *ClockLinuxGetParent(struct ClockDevice *device)
191 {
192 struct clk *clk = NULL;
193 struct clk *clkParent = NULL;
194 struct ClockDevice *clockDevice = NULL;
195 int32_t ret;
196
197 clk = device->clk;
198 if (IS_ERR_OR_NULL(clk)) {
199 HDF_LOGE("ClockLinuxGetParent: clk IS_ERR_OR_NULL\n");
200 return NULL;
201 }
202
203 clkParent = clk_get_parent(clk);
204 if (IS_ERR_OR_NULL(clkParent)) {
205 HDF_LOGE("ClockLinuxGetParent: can not get clkParent \n");
206 return NULL;
207 }
208
209 if (device->parent != NULL) {
210 device->parent->clk = clkParent;
211 return device->parent;
212 }
213
214 clockDevice = (struct ClockDevice *)OsalMemCalloc(sizeof(*clockDevice));
215 if (clockDevice == NULL) {
216 HDF_LOGE("ClockLinuxGetParent: can not OsalMemCalloc clockDevice \n");
217 return NULL;
218 }
219
220 clockDevice->ops = &g_method;
221 ret = ClockManagerGetAIdleDeviceId();
222 if (ret < 0) {
223 HDF_LOGE("ClockLinuxGetParent: add clock device:%d device if full fail!", ret);
224 OsalMemFree(clockDevice);
225 return NULL;
226 }
227
228 clockDevice->deviceIndex = ret;
229 clockDevice->clk = clkParent;
230
231 ret = ClockDeviceAdd(clockDevice);
232 if (ret != HDF_SUCCESS) {
233 HDF_LOGE("ClockLinuxGetParent: add clock device:%u fail!", clockDevice->deviceIndex);
234 OsalMemFree(clockDevice);
235 return NULL;
236 }
237 device->parent = clockDevice;
238
239 return clockDevice;
240 }
241
ClockReadDrs(struct ClockDevice * clockDevice,const struct DeviceResourceNode * node)242 static int32_t ClockReadDrs(struct ClockDevice *clockDevice, const struct DeviceResourceNode *node)
243 {
244 int32_t ret;
245 struct DeviceResourceIface *drsOps = NULL;
246
247 drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
248 if (drsOps == NULL || drsOps->GetUint32 == NULL || drsOps->GetString == NULL) {
249 HDF_LOGE("ClockReadDrs: invalid drs ops!");
250 return HDF_ERR_NOT_SUPPORT;
251 }
252 ret = drsOps->GetUint32(node, "deviceIndex", &clockDevice->deviceIndex, 0);
253 if (ret != HDF_SUCCESS) {
254 HDF_LOGE("ClockReadDrs: read deviceIndex fail, ret: %d!", ret);
255 return ret;
256 }
257
258 drsOps->GetString(node, "clockName", &clockDevice->clockName, 0);
259
260 ret = drsOps->GetString(node, "deviceName", &clockDevice->deviceName, 0);
261 if (ret != HDF_SUCCESS) {
262 HDF_LOGE("ClockReadDrs: read deviceName fail, ret: %d!", ret);
263 return ret;
264 }
265 return HDF_SUCCESS;
266 }
267
ClockParseAndDeviceAdd(struct HdfDeviceObject * device,struct DeviceResourceNode * node)268 static int32_t ClockParseAndDeviceAdd(struct HdfDeviceObject *device, struct DeviceResourceNode *node)
269 {
270 int32_t ret;
271 struct ClockDevice *clockDevice = NULL;
272
273 (void)device;
274 clockDevice = (struct ClockDevice *)OsalMemCalloc(sizeof(*clockDevice));
275 if (clockDevice == NULL) {
276 HDF_LOGE("ClockParseAndDeviceAdd: alloc clockDevice fail!");
277 return HDF_ERR_MALLOC_FAIL;
278 }
279 ret = ClockReadDrs(clockDevice, node);
280 if (ret != HDF_SUCCESS) {
281 HDF_LOGE("ClockParseAndDeviceAdd: read drs fail, ret: %d!", ret);
282 OsalMemFree(clockDevice);
283 return ret;
284 }
285
286 clockDevice->priv = (void *)node;
287 clockDevice->ops = &g_method;
288
289 ret = ClockDeviceAdd(clockDevice);
290 if (ret != HDF_SUCCESS) {
291 HDF_LOGE("ClockParseAndDeviceAdd: add clock device:%u fail!", clockDevice->deviceIndex);
292 OsalMemFree(clockDevice);
293 return ret;
294 }
295
296 return HDF_SUCCESS;
297 }
298
LinuxClockInit(struct HdfDeviceObject * device)299 static int32_t LinuxClockInit(struct HdfDeviceObject *device)
300 {
301 int32_t ret = HDF_SUCCESS;
302 struct DeviceResourceNode *childNode = NULL;
303
304 if (device == NULL || device->property == NULL) {
305 HDF_LOGE("LinuxClockInit: device or property is null");
306 return HDF_ERR_INVALID_OBJECT;
307 }
308
309 DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
310 ret = ClockParseAndDeviceAdd(device, childNode);
311 if (ret != HDF_SUCCESS) {
312 HDF_LOGE("LinuxClockInit: clock init fail!");
313 return ret;
314 }
315 }
316 HDF_LOGE("LinuxClockInit: clock init success!");
317
318 return HDF_SUCCESS;
319 }
320
ClockRemoveByNode(const struct DeviceResourceNode * node)321 static void ClockRemoveByNode(const struct DeviceResourceNode *node)
322 {
323 int32_t ret;
324 int32_t deviceIndex;
325 struct ClockDevice *device = NULL;
326 struct DeviceResourceIface *drsOps = NULL;
327
328 drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
329 if (drsOps == NULL || drsOps->GetUint32 == NULL) {
330 HDF_LOGE("ClockRemoveByNode: invalid drs ops!");
331 return;
332 }
333
334 ret = drsOps->GetUint32(node, "deviceIndex", (uint32_t *)&deviceIndex, 0);
335 if (ret != HDF_SUCCESS) {
336 HDF_LOGE("ClockRemoveByNode: read deviceIndex fail, ret: %d!", ret);
337 return;
338 }
339
340 device = ClockDeviceGet(deviceIndex);
341 if (device != NULL && device->priv == node) {
342 ret = ClockStop(device);
343 if (ret != HDF_SUCCESS) {
344 HDF_LOGE("ClockRemoveByNode: close fail, ret: %d!", ret);
345 }
346 if (device->parent && device->parent->deviceName == NULL) {
347 ClockDeviceRemove(device->parent);
348 OsalMemFree(device->parent);
349 }
350 ClockDeviceRemove(device);
351 OsalMemFree(device);
352 }
353 }
354
LinuxClockRelease(struct HdfDeviceObject * device)355 static void LinuxClockRelease(struct HdfDeviceObject *device)
356 {
357 const struct DeviceResourceNode *childNode = NULL;
358 if (device == NULL || device->property == NULL) {
359 HDF_LOGE("LinuxClockRelease: device or property is null!");
360 return;
361 }
362 DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
363 ClockRemoveByNode(childNode);
364 }
365 }
366
367 struct HdfDriverEntry g_clockLinuxDriverEntry = {
368 .moduleVersion = 1,
369 .Bind = NULL,
370 .Init = LinuxClockInit,
371 .Release = LinuxClockRelease,
372 .moduleName = "linux_clock_adapter",
373 };
374 HDF_INIT(g_clockLinuxDriverEntry);
375