1# Clock
2
3## Overview
4
5### Function
6
7The clock regulates the timing and speed of all functions in a device. For example, the CPU clock is an internal time generator of the CPU. It operates in frequency and used to synchronize and control the operations within the CPU.
8
9### Basic Concepts
10
11The clock signal is used to synchronize and control the operations of the modules or components of an electronic device. It serves as a fundamental signal reference source to ensure proper functioning and accurate data transmission.
12
13### Working Principles
14
15In the Hardware Driver Foundation (HDF), the **Clock** module uses the unified service mode for API adaptation. In this mode, a service is used as the clock manager to handle external access requests in a unified manner. The unified service mode applies when the system has multiple device objects of the same type. If the independent service mode is used in this case, more device nodes need to be configured and more memory resources will be consumed. The **Clock** module uses the unified service mode (see **Figure 1**).
16
17The **Clock** module is divided into the following layers:
18- Interface layer: provides the APIs for opening a device, writing data, and closing a device.
19- Core layer: binds services, initializes and releases the PlatformManager, and provides the capabilities of adding, deleting, and obtaining controllers.
20- Adaptation layer: implements hardware-related functions, such as controller initialization.
21
22In the unified service mode, the core layer manages all controllers in a unified manner and publishes a service for the interface layer. That is, the driver does not need to publish a service for each controller.
23
24**Figure 1** Unified service mode
25
26![](figures/unified-service-mode.png "CLOCK Unified Service Mode")
27
28
29## Usage Guidelines
30
31### When to Use
32
33The **Clock** module provides chip-level clock management, including frequency division, frequency multiplication, clock source selection, and clock gating within the chip. Proper clock management can enhance chip efficiency while streamlining coordination and synergy among all functional components.
34
35### Available APIs
36
37To enable applications to successfully operate the hardware by calling the **Clock** APIs, the system provides the following hook APIs in **//drivers/hdf_core/framework/support/platform/include/clock/clock_core.h** for the core layer. You need to implement these hook APIs at the adaptation layer and hook them to implement the interaction between the interface layer and the core layer.
38
39Definitions of  **ClockMethod** and **ClockLockMethod**:
40
41```c
42struct ClockMethod {
43    int32_t (*start)(struct ClockDevice *device);
44    int32_t (*stop)(struct ClockDevice *device);
45    int32_t (*setRate)(struct ClockDevice *device, uint32_t rate);
46    int32_t (*getRate)(struct ClockDevice *device, uint32_t *rate);
47    int32_t (*disable)(struct ClockDevice *device);
48    int32_t (*enable)(struct ClockDevice *device);
49    struct ClockDevice *(*getParent)(struct ClockDevice *device);
50    int32_t (*setParent)(struct ClockDevice *device, struct ClockDevice *parent);
51};
52
53struct ClockLockMethod {
54    int32_t (*lock)(struct ClockDevice *device);
55    void (*unlock)(struct ClockDevice *device);
56};
57
58```
59
60The **ClockMethod** method must be implemented at the adaptation layer, and **ClockLockMethod** can be implemented based on service requirements. The core layer provides the default **ClockLockMethod** method, in which a spinlock is used to protect the critical section.
61
62```c
63static int32_t ClockDeviceLockDefault(struct ClockDevice *device)
64{
65    if (device == NULL) {
66        HDF_LOGE("ClockDeviceLockDefault: device is null!");
67        return HDF_ERR_INVALID_OBJECT;
68    }
69    return OsalSpinLock(&device->spin);
70}
71
72static void ClockDeviceUnlockDefault(struct ClockDevice *device)
73{
74    if (device == NULL) {
75        HDF_LOGE("ClockDeviceUnlockDefault: device is null!");
76        return;
77    }
78    (void)OsalSpinUnlock(&device->spin);
79}
80
81static const struct ClockLockMethod g_clockLockOpsDefault = {
82    .lock = ClockDeviceLockDefault,
83    .unlock = ClockDeviceUnlockDefault,
84};
85
86```
87
88If spinlock cannot be used, you can use another type of lock to implement **ClockLockMethod**. The customized **ClockLockMethod** method will replace the default **ClockLockMethod** method.
89
90  **Table 1** Hook APIs in **ClockMethod**
91
92| API | Input Parameter| Output Parameter| Return Value| Description|
93| -------- | -------- | -------- | -------- | -------- |
94| start | **device**: structure pointer to the clock controller at the core layer.| –| HDF_STATUS | Starts a clock device. |
95| stop | **device**: structure pointer to the clock controller at the core layer.| –| HDF_STATUS | Stops a clock device. |
96| setRate | **device**: structure pointer to the clock controller at the core layer.| –| HDF_STATUS | Sets the clock rate. |
97| getRate | **device**: structure pointer to the clock controller at the core layer.| Clock rate obtained. | HDF_STATUS | Obtains the clock rate. |
98| disable | **device**: structure pointer to the clock controller at the core layer.| –| HDF_STATUS | Enables clock. |
99| enable | **device**: structure pointer to the clock controller at the core layer.| –| HDF_STATUS | Disables clock. |
100| getParent | **device**: structure pointer to the clock controller at the core layer.| Structure pointer to the clock controller obtained. | HDF_STATUS | Obtains the parent clock. |
101| setParent | **device**: structure pointer to the clock controller at the core layer.| –| HDF_STATUS | Sets the parent clock. |
102
103**Table 2** APIs in **ClockLockMethod**
104
105| Function| Input Parameter| Output Parameter| Return Value| Description|
106| -------- | -------- | -------- | -------- | -------- |
107| lock | **device**: structure pointer to the clock device object at the core layer.| –| HDF_STATUS| Acquires the critical section lock. |
108| unlock | **device**: structure pointer to the clock device object at the core layer.| –| HDF_STATUS| Releases the critical section lock.|
109
110### How to Develop
111
112The **Clock** module adaptation involves the following steps:
113
1141. Instantiate the driver entry.
115   - Instantiate the **HdfDriverEntry** structure.
116   - Call **HDF_INIT** to register the **HdfDriverEntry** instance with the HDF.
117
1182. Configure attribute files.
119   - Add the **deviceNode** information to the **device_info.hcs** file.
120   - (Optional) Add the **clock_config.hcs** file.
121
1223. Instantiate the core layer APIs.
123   - Initialize **ClockDevice**.
124   - Instantiate **ClockMethod** in the **ClockDevice** object.
125      > **NOTE**
126      >
127      > For details about the functions in **ClockMethod**, see [Available APIs](#available-apis).
128
1294. (Optional) Debug the driver.
130
131   Verify the basic driver functionalities.
132
133
134### Example
135
136The following uses the RK3568 driver **//drivers/hdf_core/adapter/khdf/linux/platform/clock/clock_adapter.c** as an example to describe how to perform the clock driver adaptation.
137
1381. Instantiate the driver entry.
139
140   The driver entry must be a global variable of the **HdfDriverEntry** type (defined in **//drivers/hdf_core/interfaces/inner_api/host/shared/hdf_device_desc.h**), and the value of **moduleName** must be the same as that in **device_info.hcs**. In the HDF, the start address of each **HdfDriverEntry** object of all loaded drivers is collected to form a segment address space similar to an array for the upper layer to invoke.
141
142   Generally, the HDF calls the **Bind** function and then the **Init** function to load a driver. If **Init** fails to be called, the HDF calls **Release** to release driver resources and exit.
143
144   Clock driver entry example:
145
146   Multiple devices may connect to the clock controller. In the HDF, a manager object needs to be created for this type of devices. When a device needs to be started, the manager object locates the target device based on the specified parameters.
147
148   You do not need to implement the driver of the clock manager, which is implemented by the core layer. However, the **ClockDeviceAdd** method of the core layer must be invoked in the **Init** method to implement the related features.
149
150    ```c
151    struct HdfDriverEntry g_clockLinuxDriverEntry = {
152        .moduleVersion = 1,
153        .Bind = NULL,
154        .Init = LinuxClockInit,
155        .Release = LinuxClockRelease,
156        .moduleName = "linux_clock_adapter",      // (Mandatory) The value must be the same as the module name in the device_info.hcs file.
157    };
158    HDF_INIT(g_clockLinuxDriverEntry);            // Call HDF_INIT to register the driver entry with the HDF.
159
160    /* Driver entry of the clock_core.c manager service at the core layer */
161    struct HdfDriverEntry g_clockManagerEntry = {
162        .moduleVersion = 1,
163        .Bind = ClockManagerBind,
164        .Init = ClockManagerInit,
165        .Release = ClockManagerRelease,
166        .moduleName = "HDF_PLATFORM_CLOCK_MANAGER",   // The value must be that of device0 in the device_info.hcs file.
167    };
168    HDF_INIT(g_clockManagerEntry);
169    ```
170
1712. Add the **deviceNode** information to the **//vendor/hihope/rk3568/hdf_config/khdf/device_info/device_info.hcs** file and configure the device attributes in **clock_config.hcs**.
172
173   The **deviceNode** information is related to the driver entry registration. The device attribute values are closely related to the driver implementation and the default values or value ranges of the **ClockDevice** members at the core layer.
174
175   In the unified service mode, the first device node in the **device_info.hcs** file must be the clock manager. The parameters must be set as follows:
176
177   | Parameter| Value|
178   | -------- | -------- |
179   | policy | Service publishing policy. For the clock controller, it is **2**, which means to publish services for both kernel- and user-mode processes. |
180   | priority | Loading priority of the cloud driver. The value range is 0 to 200. A larger value indicates a lower priority.<br/>It is set to **59** for the clock controller. |
181   | permission | Permission for the device node created. It is **0664** for the clock controller. |
182   | moduleName | **HDF_PLATFORM_CLOCK_MANAGER**. |
183   | serviceName | **HDF_PLATFORM_CLOCK_MANAGER**. |
184   | deviceMatchAttr | Reserved.|
185
186   Configure clock controller information from the second node. This node specifies a type of clock controllers rather than a clock controller. In this example, there is only one clock device. If there are multiple clock devices, add the **deviceNode** information to the **device_info.hcs** file and add the corresponding device attributes to the **clock_config** file for each device.
187
188   - **device_info.hcs** example
189
190        ```
191        root {
192            device_info {
193                platform :: host {
194                    device_clock :: device {
195                        device0 :: deviceNode {
196                            policy = 2;
197                            priority = 59;
198                            permission = 0644;
199                            moduleName = "HDF_PLATFORM_CLOCK_MANAGER";
200                            serviceName = "HDF_PLATFORM_CLOCK_MANAGER";
201                        }
202                        device1 :: deviceNode {
203                            policy = 0;                                 // The value 0 indicates that no service is published.
204                            priority = 65;                              // Driver startup priority.
205                            permission = 0644;                          // Permission for the device node created.
206                            moduleName = "linux_clock_adapter";         // (Mandatory) Driver name, which must be the same as moduleName in the driver entry.
207                            deviceMatchAttr = "linux_clock_adapter_0";  // (Mandatory) Private data of the controller. The value must be the same as that of the controller
208                        }
209                    }
210                }
211            }
212        }
213        ```
214
215    - **clock_config.hcs** example
216
217      The following uses RK3568 as an example.
218
219        ```
220        root {
221            platform {
222                clock_config {
223                    match_attr = "linux_clock_adapter_0";
224                    template clock_device {
225                    }
226                    device_clock_0x0000 :: clock_device {
227                        deviceName = "/cpus/cpu@0";
228                        deviceIndex = 1;
229                    }
230                }
231            }
232        }
233        ```
234
235      After the **clock_config.hcs** file is configured, include the file in the **hdf.hcs** file. Otherwise, the configuration file cannot take effect.
236
237      For example, if the **clock_config.hcs** file is in **//vendor/hihope/rk3568/hdf_config/hdf_config/khdf/hdf.hcs**, add the following statement to **hdf.hcs** of the product:
238
239        ```
240        #include "platform/clock_config_linux.hcs" //  Relative path of the configuration file
241        ```
242
243      This example is based on RK3568 development board that runs the Standard system. The **hdf.hcs** file is in **//vendor/hihope/rk3568/hdf_config/ hdf_config/khdf/**. You can modify the file as required.
244
2453. Initialize the **ClockDevice** object at the core layer, including defining a custom structure (to pass parameters and data) and implementing the **HdfDriverEntry** member functions (**Bind**, **Init** and **Release**) to instantiate **ClocMethod** in **ClocDevice** (so that the underlying driver functions can be called).
246
247   - Define a custom structure.
248
249      To the driver, the custom structure holds parameters and data. The DeviceResourceIface() function provided by the HDF reads **clock_config.hcs** to initialize the custom structure and passes some important parameters, such as the device number and bus number, to the **ClockDevice** object at the core layer.
250        ```c
251      /* ClockDevice is the core layer controller structure. The **Init()** function assigns values to the members of ClockDevice. */
252        struct ClockDevice {
253            const struct ClockMethod *ops;
254            OsalSpinlock spin;
255            const char *deviceName;
256            const char *clockName;
257            uint32_t deviceIndex;
258            const struct ClockLockMethod *lockOps;
259            void *clk;
260            void *priv;
261            struct ClockDevice *parent;
262        };
263        ```
264
265- Instantiate the hook function structure **ClockMethod** of **ClockDevice**.
266
267   The **ClockLockMethod** is not implemented in this example. To instantiate the structure, refer to the I2C driver development. Other members are initialized in the **Init** function.
268
269        ```c
270        struct ClockMethod {
271            int32_t (*start)(struct ClockDevice *device);
272            int32_t (*stop)(struct ClockDevice *device);
273            int32_t (*setRate)(struct ClockDevice *device, uint32_t rate);
274            int32_t (*getRate)(struct ClockDevice *device, uint32_t *rate);
275            int32_t (*disable)(struct ClockDevice *device);
276            int32_t (*enable)(struct ClockDevice *device);
277            struct ClockDevice *(*getParent)(struct ClockDevice *device);
278            int32_t (*setParent)(struct ClockDevice *device, struct ClockDevice *parent);
279        };
280     ```
281
282   - Implement the **Init** function.
283
284      Input parameter:
285
286      **HdfDeviceObject**, an interface parameter provided by the driver, contains the .hcs information.
287
288      Return value:
289
290   **HDF_STATUS**<br/>The table below describes some status. For more information, see **HDF_STATUS** in the **//drivers/hdf_core/interfaces/inner_api/utils/hdf_base.h** file.
291
292        **Table 4** HDF_STATUS
293
294        | Value | Description |
295        | -------- | -------- |
296        | HDF_ERR_INVALID_OBJECT | Invalid controller object.|
297        | HDF_ERR_INVALID_PARAM | Invalid parameter.|
298        | HDF_ERR_MALLOC_FAIL | Failed to allocate memory.|
299        | HDF_ERR_IO | I/O error.|
300        | HDF_SUCCESS | Transmission successful.|
301        | HDF_FAILURE | Transmission failed.|
302
303   Function description:
304
305      Initializes the custom structure object and **ClockDevice**, and calls the **ClockDeviceAdd** function at the core layer.
306
307      ```c
308        static int32_t LinuxClockInit(struct HdfDeviceObject *device)
309          {
310              int32_t ret = HDF_SUCCESS;
311              struct DeviceResourceNode *childNode = NULL;
312
313              if (device == NULL || device->property == NULL) {
314                  HDF_LOGE("LinuxClockInit: device or property is null");
315                  return HDF_ERR_INVALID_OBJECT;
316              }
317
318              DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
319                  ret = ClockParseAndDeviceAdd(device, childNode);
320                  if (ret != HDF_SUCCESS) {
321                      HDF_LOGE("LinuxClockInit: clock init fail!");
322                      return ret;
323                  }
324              }
325              HDF_LOGE("LinuxClockInit: clock init success!");
326
327              return HDF_SUCCESS;
328          }
329
330          static int32_t ClockParseAndDeviceAdd(struct HdfDeviceObject *device, struct DeviceResourceNode *node)
331          {
332              int32_t ret;
333              struct ClockDevice *clockDevice = NULL;
334
335              (void)device;
336              clockDevice = (struct ClockDevice *)OsalMemCalloc(sizeof(*clockDevice));
337              if (clockDevice == NULL) {
338                  HDF_LOGE("ClockParseAndDeviceAdd: alloc clockDevice fail!");
339                  return HDF_ERR_MALLOC_FAIL;
340              }
341              ret = ClockReadDrs(clockDevice, node);
342              if (ret != HDF_SUCCESS) {
343                  HDF_LOGE("ClockParseAndDeviceAdd: read drs fail, ret: %d!", ret);
344                  OsalMemFree(clockDevice);
345                  return ret;
346              }
347
348              clockDevice->priv = (void *)node;
349              clockDevice->ops = &g_method;
350
351              ret = ClockDeviceAdd(clockDevice);
352              if (ret != HDF_SUCCESS) {
353                  HDF_LOGE("ClockParseAndDeviceAdd: add clock device:%u fail!", clockDevice->deviceIndex);
354                  OsalMemFree(clockDevice);
355                  return ret;
356              }
357
358              return HDF_SUCCESS;
359          }
360
361          static int32_t ClockReadDrs(struct ClockDevice *clockDevice, const struct DeviceResourceNode *node)
362          {
363              int32_t ret;
364              struct DeviceResourceIface *drsOps = NULL;
365
366              drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
367              if (drsOps == NULL || drsOps->GetUint32 == NULL || drsOps->GetString == NULL) {
368                  HDF_LOGE("ClockReadDrs: invalid drs ops!");
369                  return HDF_ERR_NOT_SUPPORT;
370              }
371              ret = drsOps->GetUint32(node, "deviceIndex", &clockDevice->deviceIndex, 0);
372              if (ret != HDF_SUCCESS) {
373                  HDF_LOGE("ClockReadDrs: read deviceIndex fail, ret: %d!", ret);
374                  return ret;
375              }
376
377              drsOps->GetString(node, "clockName", &clockDevice->clockName, 0);
378
379              ret = drsOps->GetString(node, "deviceName", &clockDevice->deviceName, 0);
380              if (ret != HDF_SUCCESS) {
381                  HDF_LOGE("ClockReadDrs: read deviceName fail, ret: %d!", ret);
382                  return ret;
383              }
384              return HDF_SUCCESS;
385          }
386      ```
387
388
389
390   - Implement the **Release** function.
391
392      Input parameter:
393
394      **HdfDeviceObject**, an interface parameter provided by the driver, contains the .hcs information.
395
396      Return value:
397
398      No value is returned.
399
400      Function description:
401
402
403      Releases the memory and deletes the controller. This function assigns values to the **Release** function in the driver entry structure. If the HDF fails to call the **Init** function to initialize the driver, the **Release** function can be called to release driver resources.
404
405        ```c
406        static void LinuxClockRelease(struct HdfDeviceObject *device)
407        {
408            const struct DeviceResourceNode *childNode = NULL;
409            if (device == NULL || device->property == NULL) {
410                HDF_LOGE("LinuxClockRelease: device or property is null!");
411                return;
412            }
413            DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
414                ClockRemoveByNode(childNode);
415            }
416        }
417
418        static void ClockRemoveByNode(const struct DeviceResourceNode *node)
419        {
420            int32_t ret;
421            int32_t deviceIndex;
422            struct ClockDevice *device = NULL;
423            struct DeviceResourceIface *drsOps = NULL;
424
425            drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
426            if (drsOps == NULL || drsOps->GetUint32 == NULL) {
427                HDF_LOGE("ClockRemoveByNode: invalid drs ops!");
428                return;
429            }
430
431            ret = drsOps->GetUint32(node, "deviceIndex", (uint32_t *)&deviceIndex, 0);
432            if (ret != HDF_SUCCESS) {
433                HDF_LOGE("ClockRemoveByNode: read deviceIndex fail, ret: %d!", ret);
434                return;
435            }
436
437            device = ClockDeviceGet(deviceIndex);
438            if (device != NULL && device->priv == node) {
439                ret = ClockStop(device);
440                if (ret != HDF_SUCCESS) {
441                    HDF_LOGE("ClockRemoveByNode: close fail, ret: %d!", ret);
442                }
443                if (device->parent  && device->parent->deviceName == NULL) {
444                    ClockDeviceRemove(device->parent);
445                    OsalMemFree(device->parent);
446                }
447                ClockDeviceRemove(device);
448                OsalMemFree(device);
449            }
450        }
451        ```
4524. (Optional) Debug the driver.
453    Verify the basic driver functionalities.
454