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