1e41f4b71Sopenharmony_ci# PWM
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci## Overview
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ci### Function
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ciPulse Width Modulation (PWM) is a technology that performs digital coding on analog signal levels and converts them into pulses. It is widely used in fields, such as measurement, communication, and power control and conversion. The PWM module is used for controlling vibrators and adjusting backlight brightness in smart devices.
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ci### Basic Concepts
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ciA pulse (electrical pulse) is a burst of current or voltage, characterized by sudden change and discontinuity. There are many types of pulses. Common pulses include triangular, sharp, rectangular, square, trapezoidal, and zigzag pulses. Main pulse parameters include the repetition period **T** (**T** = 1/**F**, where **F** is the pulse repetition frequency), pulse amplitude **U**, rise time **ts** at the leading edge, fall time **t** at the trailing edge, and pulse width **tk**.
12e41f4b71Sopenharmony_ci
13e41f4b71Sopenharmony_ci### Working Principles
14e41f4b71Sopenharmony_ci
15e41f4b71Sopenharmony_ciIn the Hardware Driver Foundation (HDF), the PWM uses the independent service mode (see Figure 1) for API adaptation. In this mode, each device independently publishes a service to process external access requests. When receiving an access request, the HDF DeviceManager extracts parameters from the request to call the internal APIs of the target device. In the independent service mode, the HDF DeviceManager provides service management capabilities. However, you need to configure a node for each device, which increases memory usage.
16e41f4b71Sopenharmony_ci
17e41f4b71Sopenharmony_ciIn the independent service mode, the core layer does not publish a service for the upper layer. Therefore, a service must be published for each controller. To achieve this purpose:
18e41f4b71Sopenharmony_ci
19e41f4b71Sopenharmony_ci- You need to implement the **Bind()** function in **HdfDriverEntry** to bind services.
20e41f4b71Sopenharmony_ci- The **policy** field of **deviceNode** in the **device_info.hcs** file can be **1** or **2**, but not **0**.
21e41f4b71Sopenharmony_ci
22e41f4b71Sopenharmony_ciThe PWM module is divided into the following layers:
23e41f4b71Sopenharmony_ci
24e41f4b71Sopenharmony_ci- Interface layer: provides APIs for opening or closing a PWM device, setting the PWM period, signal ON-state time, PWM device polarity, or PWM device parameters, obtaining PWM device parameters, and enabling or disabling a PWM device
25e41f4b71Sopenharmony_ci- Core layer: provides the capabilities of adding or removing a PWM controller and managing PWM devices. The core layer interacts with the adaptation layer through hook functions.
26e41f4b71Sopenharmony_ci- Adaptation layer: instantiates the hook functions to implement specific features.
27e41f4b71Sopenharmony_ci
28e41f4b71Sopenharmony_ci**Figure 1** Independent service mode
29e41f4b71Sopenharmony_ci
30e41f4b71Sopenharmony_ci![image](figures/independent-service-mode.png "PWM independent service mode")
31e41f4b71Sopenharmony_ci
32e41f4b71Sopenharmony_ci## Development Guidelines
33e41f4b71Sopenharmony_ci
34e41f4b71Sopenharmony_ci### When to Use
35e41f4b71Sopenharmony_ci
36e41f4b71Sopenharmony_ciBefore using your PWM device with OpenHarmony, you need to perform PWM driver adaptation.
37e41f4b71Sopenharmony_ci
38e41f4b71Sopenharmony_ci### Available APIs
39e41f4b71Sopenharmony_ci
40e41f4b71Sopenharmony_ciTo enable the upper layer to successfully operate the PWM controller by calling the PWM APIs, hook functions are defined in **//drivers/hdf_core/framework/support/platform/include/pwm/pwm_core.h** for the core layer. You need to implement these hook functions at the adaptation layer and hook them to implement the interaction between the interface layer and the core layer.
41e41f4b71Sopenharmony_ci
42e41f4b71Sopenharmony_ci**PwmMethod**:
43e41f4b71Sopenharmony_ci
44e41f4b71Sopenharmony_ci```c
45e41f4b71Sopenharmony_cistruct PwmMethod {
46e41f4b71Sopenharmony_ci    int32_t (*setConfig)(struct PwmDev *pwm, struct PwmConfig *config);
47e41f4b71Sopenharmony_ci    int32_t (*open)(struct PwmDev *pwm);
48e41f4b71Sopenharmony_ci    int32_t (*close)(struct PwmDev *pwm);
49e41f4b71Sopenharmony_ci};
50e41f4b71Sopenharmony_ci```
51e41f4b71Sopenharmony_ci
52e41f4b71Sopenharmony_ci**Table 1** Hook functions in **PwmMethod**
53e41f4b71Sopenharmony_ci
54e41f4b71Sopenharmony_ci| Function| Input Parameter| Return Value| Description|
55e41f4b71Sopenharmony_ci| -------- | -------- | -------- | -------- |
56e41f4b71Sopenharmony_ci| setConfig | **pwm**: structure pointer to the PWM controller at the core layer.<br>**config**: structure pointer to the device attributes to set.| HDF_STATUS| Sets device attributes.|
57e41f4b71Sopenharmony_ci| open | **pwm**: structure pointer to the PWM controller at the core layer.| HDF_STATUS| Opens a PWM device.|
58e41f4b71Sopenharmony_ci| close | **pwm**: structure pointer to the PWM controller at the core layer.| HDF_STATUS| Closes a PWM device.|
59e41f4b71Sopenharmony_ci
60e41f4b71Sopenharmony_ci### How to Develop
61e41f4b71Sopenharmony_ci
62e41f4b71Sopenharmony_ciThe PWM module adaptation procedure is as follows:
63e41f4b71Sopenharmony_ci
64e41f4b71Sopenharmony_ci1. Instantiate the driver entry.
65e41f4b71Sopenharmony_ci2. Configure attribute files.
66e41f4b71Sopenharmony_ci3. Instantiate the PWM controller object.
67e41f4b71Sopenharmony_ci4. Debug the driver.
68e41f4b71Sopenharmony_ci
69e41f4b71Sopenharmony_ci### Example
70e41f4b71Sopenharmony_ci
71e41f4b71Sopenharmony_ciThe following uses the **//device_soc_hisilicon/common/platform/pwm/pwm_hi35xx.c** driver of the Hi3516D V300 development board as an example to describe the PWM driver adaptation.
72e41f4b71Sopenharmony_ci
73e41f4b71Sopenharmony_ci1. Instantiate the driver entry.
74e41f4b71Sopenharmony_ci
75e41f4b71Sopenharmony_ci   The driver entry must be a global variable of the **HdfDriverEntry** type (defined in **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.
76e41f4b71Sopenharmony_ci   Generally, the HDF calls **Bind()** and then **Init()** to load a driver. If **Init()** fails to be called, the HDF calls **Release()** to release driver resources and exit.
77e41f4b71Sopenharmony_ci
78e41f4b71Sopenharmony_ci   PWM driver entry example:
79e41f4b71Sopenharmony_ci
80e41f4b71Sopenharmony_ci   ```c
81e41f4b71Sopenharmony_ci   struct HdfDriverEntry g_hdfPwm = {
82e41f4b71Sopenharmony_ci       .moduleVersion = 1,
83e41f4b71Sopenharmony_ci       .moduleName = "HDF_PLATFORM_PWM",   // (Mandatory) The value must be the same as that of moduleName in the .hcs file.
84e41f4b71Sopenharmony_ci       .Bind = HdfPwmBind,                  // See the Bind function.
85e41f4b71Sopenharmony_ci       .Init = HdfPwmInit,                  // See the Init function.
86e41f4b71Sopenharmony_ci       .Release = HdfPwmRelease,            // See the Release function.
87e41f4b71Sopenharmony_ci   };
88e41f4b71Sopenharmony_ci   HDF_INIT(g_hdfPwm);                      // Call HDF_INIT to register the driver entry with the HDF.
89e41f4b71Sopenharmony_ci   ```
90e41f4b71Sopenharmony_ci
91e41f4b71Sopenharmony_ci2. Configure attribute files.
92e41f4b71Sopenharmony_ci
93e41f4b71Sopenharmony_ci   Add the deviceNode information to the **device_info.hcs** file. The deviceNode information is related to the driver entry registration. The following example uses two PWM controllers as an example. If there are more PWM controllers, add the deviceNode information to the **device_info.hcs** file for each controller. The device attribute values configured in **pwm_config.hcs** are closely related to default values or value ranges of the **PwmDev** members at the core layer.
94e41f4b71Sopenharmony_ci
95e41f4b71Sopenharmony_ci   - **device_info.hcs** example
96e41f4b71Sopenharmony_ci
97e41f4b71Sopenharmony_ci      Add the deviceNode information to the **//vendor/hisilicon/hispark_taurus/hdf_config/device_info/device_info.hcs** file.
98e41f4b71Sopenharmony_ci
99e41f4b71Sopenharmony_ci      ```c
100e41f4b71Sopenharmony_ci      root {
101e41f4b71Sopenharmony_ci          device_info { 
102e41f4b71Sopenharmony_ci              platform :: host {
103e41f4b71Sopenharmony_ci                  hostName = "platform_host";
104e41f4b71Sopenharmony_ci                  priority = 50;
105e41f4b71Sopenharmony_ci                  device_pwm ::device {                               // Configure an HDF device node for each PWM controller.
106e41f4b71Sopenharmony_ci                      device0 :: deviceNode {
107e41f4b71Sopenharmony_ci                          policy = 1;                                 // The value 1 means to publish services only to the kernel-mode processes.
108e41f4b71Sopenharmony_ci                          priority = 80;                              // Driver startup priority.
109e41f4b71Sopenharmony_ci                          permission = 0644;                          // Permission for the device node created.
110e41f4b71Sopenharmony_ci                          moduleName = "HDF_PLATFORM_PWM";            // (Mandatory) Driver name, which must be the same as moduleName in the driver entry.
111e41f4b71Sopenharmony_ci                          serviceName = "HDF_PLATFORM_PWM_0";         // (Mandatory) Unique name of the service published by the driver.
112e41f4b71Sopenharmony_ci                          deviceMatchAttr = "hisilicon_hi35xx_pwm_0"; // Controller private data, which must be the same as that of the controller in pwm_config.hcs.
113e41f4b71Sopenharmony_ci                      }
114e41f4b71Sopenharmony_ci                      device1 :: deviceNode {
115e41f4b71Sopenharmony_ci                          policy = 1;
116e41f4b71Sopenharmony_ci                          priority = 80;
117e41f4b71Sopenharmony_ci                          permission = 0644;
118e41f4b71Sopenharmony_ci                          moduleName = "HDF_PLATFORM_PWM";
119e41f4b71Sopenharmony_ci                          serviceName = "HDF_PLATFORM_PWM_1";
120e41f4b71Sopenharmony_ci                          deviceMatchAttr = "hisilicon_hi35xx_pwm_1";
121e41f4b71Sopenharmony_ci                      }
122e41f4b71Sopenharmony_ci                      ...
123e41f4b71Sopenharmony_ci                  }
124e41f4b71Sopenharmony_ci              }
125e41f4b71Sopenharmony_ci          }
126e41f4b71Sopenharmony_ci      }
127e41f4b71Sopenharmony_ci      ```
128e41f4b71Sopenharmony_ci
129e41f4b71Sopenharmony_ci   - **pwm_config.hcs** example
130e41f4b71Sopenharmony_ci
131e41f4b71Sopenharmony_ci      Configure the device attributes in the **//device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/pwm/pwm_config.hcs** file. The parameters are as follows:
132e41f4b71Sopenharmony_ci
133e41f4b71Sopenharmony_ci      ```c
134e41f4b71Sopenharmony_ci      root {
135e41f4b71Sopenharmony_ci          platform {
136e41f4b71Sopenharmony_ci              pwm_config {
137e41f4b71Sopenharmony_ci                  template pwm_device {                       // (Mandatory) Template configuration. If the template is used to configure device node information, the default values in the template will be used for the fields that are not declared for the node.
138e41f4b71Sopenharmony_ci                      serviceName = "";
139e41f4b71Sopenharmony_ci                      match_attr = "";
140e41f4b71Sopenharmony_ci                      num = 0;                                // (Mandatory) Device number.
141e41f4b71Sopenharmony_ci                      base = 0x12070000;                      // (Mandatory) Base address used for address mapping.
142e41f4b71Sopenharmony_ci                  }
143e41f4b71Sopenharmony_ci                  device_0x12070000 :: pwm_device {           // Add the HDF node and device node information for each device.
144e41f4b71Sopenharmony_ci                      match_attr = "hisilicon_hi35xx_pwm_0";  // (Mandatory) The value must be the same as that of deviceMatchAttr in device_info.hcs.
145e41f4b71Sopenharmony_ci                  }
146e41f4b71Sopenharmony_ci                  device_0x12070020 :: pwm_device {
147e41f4b71Sopenharmony_ci                      match_attr = "hisilicon_hi35xx_pwm_1";
148e41f4b71Sopenharmony_ci                      num = 1;
149e41f4b71Sopenharmony_ci                      base = 0x12070020;                      // (Mandatory) Base address used for address mapping.
150e41f4b71Sopenharmony_ci                  }
151e41f4b71Sopenharmony_ci              }
152e41f4b71Sopenharmony_ci          }
153e41f4b71Sopenharmony_ci      }
154e41f4b71Sopenharmony_ci      ```
155e41f4b71Sopenharmony_ci
156e41f4b71Sopenharmony_ci      After the **pwm_config.hcs** file is configured, include the file in the **hdf.hcs** file. Otherwise, the configuration file cannot take effect.
157e41f4b71Sopenharmony_ci
158e41f4b71Sopenharmony_ci      ```c
159e41f4b71Sopenharmony_ci      #include "../../../../device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/pwm/pwm_config.hcs" // Relative path of the file.
160e41f4b71Sopenharmony_ci      ```
161e41f4b71Sopenharmony_ci
162e41f4b71Sopenharmony_ci3. Instantiate the PWM controller object.
163e41f4b71Sopenharmony_ci
164e41f4b71Sopenharmony_ci   Initialize the **PwmDev** 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 **PwmMethod** in **PwmDev** (so that the underlying driver functions can be called).
165e41f4b71Sopenharmony_ci
166e41f4b71Sopenharmony_ci   - Define a custom structure.
167e41f4b71Sopenharmony_ci
168e41f4b71Sopenharmony_ci      To the driver, the custom structure holds parameters and data. The **DeviceResourceIface** method provided by the HDF reads the values in the **pwm_config.hcs** file to initialize the members in the custom structure and passes important parameters, such as the PWM device number, to the object at the core layer.
169e41f4b71Sopenharmony_ci
170e41f4b71Sopenharmony_ci      ```c
171e41f4b71Sopenharmony_ci      struct HiPwm {
172e41f4b71Sopenharmony_ci          struct PwmDev dev;                // (Mandatory) Control object at the core layer.
173e41f4b71Sopenharmony_ci          volatile unsigned char *base;     // (Mandatory) Register base address used for address mapping.
174e41f4b71Sopenharmony_ci          struct HiPwmRegs *reg;            // Device attribute structure, which can be customized.
175e41f4b71Sopenharmony_ci          bool supportPolarity;             // Whether polarity is supported.
176e41f4b71Sopenharmony_ci      };
177e41f4b71Sopenharmony_ci
178e41f4b71Sopenharmony_ci      struct PwmDev {                       // PwmDev is the core layer controller structure. The Bind function assigns values to the members of PwmDev.
179e41f4b71Sopenharmony_ci          struct IDeviceIoService service;  // Driver service.
180e41f4b71Sopenharmony_ci          struct HdfDeviceObject *device;   // Driver device object.
181e41f4b71Sopenharmony_ci          struct PwmConfig cfg;             // Device attribute structure. For details, see the following definition.
182e41f4b71Sopenharmony_ci          struct PwmMethod *method;         // Hook functions.
183e41f4b71Sopenharmony_ci          bool busy;                        // Whether the device is busy.
184e41f4b71Sopenharmony_ci          uint32_t num;                     // Device number.
185e41f4b71Sopenharmony_ci          OsalSpinlock lock;                // Spinlock.
186e41f4b71Sopenharmony_ci          void *priv;                       // Private data.
187e41f4b71Sopenharmony_ci      };
188e41f4b71Sopenharmony_ci
189e41f4b71Sopenharmony_ci      struct PwmConfig {                    // PWM device attributes.
190e41f4b71Sopenharmony_ci          uint32_t duty;                    // Time that a signal is in the ON state, in ns.
191e41f4b71Sopenharmony_ci          uint32_t period;                  // Time for a signal to complete an on-and-off cycle, in ns.
192e41f4b71Sopenharmony_ci          uint32_t number;                  // Number of square waves to generate.
193e41f4b71Sopenharmony_ci          uint8_t polarity;                 // Polarity
194e41f4b71Sopenharmony_ci                                            // ------------------- | --------------
195e41f4b71Sopenharmony_ci                                            // PWM_NORMAL_POLARITY | Normal polarity
196e41f4b71Sopenharmony_ci                                            // PWM_INVERTED_POLARITY | Inverted polarity
197e41f4b71Sopenharmony_ci                                            //
198e41f4b71Sopenharmony_ci          uint8_t status;                   // Running status.
199e41f4b71Sopenharmony_ci                                            // ------------------ | -----------------
200e41f4b71Sopenharmony_ci                                            // PWM_DISABLE_STATUS | Disabled
201e41f4b71Sopenharmony_ci                                            // PWM_ENABLE_STATUS  | Enabled
202e41f4b71Sopenharmony_ci      };
203e41f4b71Sopenharmony_ci      ```
204e41f4b71Sopenharmony_ci
205e41f4b71Sopenharmony_ci   - Instantiate the **PwmMethod** structure in **PwmDev**.
206e41f4b71Sopenharmony_ci
207e41f4b71Sopenharmony_ci      ```c
208e41f4b71Sopenharmony_ci      struct PwmMethod g_pwmOps = {         // Instantiate the hook functions in pwm_hi35xx.c.
209e41f4b71Sopenharmony_ci          .setConfig = HiPwmSetConfig,      // Set device attributes.
210e41f4b71Sopenharmony_ci      };
211e41f4b71Sopenharmony_ci      ```
212e41f4b71Sopenharmony_ci
213e41f4b71Sopenharmony_ci   - Implement the **Init** function.
214e41f4b71Sopenharmony_ci
215e41f4b71Sopenharmony_ci      **Input parameter**:
216e41f4b71Sopenharmony_ci
217e41f4b71Sopenharmony_ci      **HdfDeviceObject**, a device object created by the HDF for each driver, holds device-related private data and service APIs.
218e41f4b71Sopenharmony_ci
219e41f4b71Sopenharmony_ci      **Return value**:
220e41f4b71Sopenharmony_ci
221e41f4b71Sopenharmony_ci      **HDF_STATUS**<br/>The table below describes some status. For more information, see **HDF_STATUS** in the **//drivers/hdf_core/framework/include/utils/hdf_base.h** file.
222e41f4b71Sopenharmony_ci
223e41f4b71Sopenharmony_ci      | Status| Description|
224e41f4b71Sopenharmony_ci      | -------- | -------- |
225e41f4b71Sopenharmony_ci      | HDF_ERR_INVALID_OBJECT | Invalid controller object.|
226e41f4b71Sopenharmony_ci      | HDF_ERR_MALLOC_FAIL | Failed to allocate memory.|
227e41f4b71Sopenharmony_ci      | HDF_ERR_INVALID_PARAM | Invalid parameter.|
228e41f4b71Sopenharmony_ci      | HDF_ERR_IO | I/O error.|
229e41f4b71Sopenharmony_ci      | HDF_SUCCESS | Initialization successful.|
230e41f4b71Sopenharmony_ci      | HDF_FAILURE | Initialization failed.|
231e41f4b71Sopenharmony_ci
232e41f4b71Sopenharmony_ci      **Function description**:
233e41f4b71Sopenharmony_ci
234e41f4b71Sopenharmony_ci      Initializes the custom structure object and **PwmDev** members, and calls **PwmDeviceAdd()** to add the PWM controller to the core layer.
235e41f4b71Sopenharmony_ci
236e41f4b71Sopenharmony_ci      ```c
237e41f4b71Sopenharmony_ci      // In this example, Bind() is an empty function. You can add operations as required or implement related features in Init().
238e41f4b71Sopenharmony_ci      static int32_t HdfPwmBind(struct HdfDeviceObject *obj)
239e41f4b71Sopenharmony_ci      {
240e41f4b71Sopenharmony_ci          (void)obj;
241e41f4b71Sopenharmony_ci          return HDF_SUCCESS;
242e41f4b71Sopenharmony_ci      }
243e41f4b71Sopenharmony_ci
244e41f4b71Sopenharmony_ci      static int32_t HdfPwmInit(struct HdfDeviceObject *obj)
245e41f4b71Sopenharmony_ci      {
246e41f4b71Sopenharmony_ci          int ret;
247e41f4b71Sopenharmony_ci          struct HiPwm *hp = NULL;
248e41f4b71Sopenharmony_ci          ...
249e41f4b71Sopenharmony_ci          hp = (struct HiPwm *)OsalMemCalloc(sizeof(*hp));
250e41f4b71Sopenharmony_ci          ...
251e41f4b71Sopenharmony_ci          ret = HiPwmProbe(hp, obj);                                 // (Mandatory) The implementation is as follows.
252e41f4b71Sopenharmony_ci          ...
253e41f4b71Sopenharmony_ci          return ret;
254e41f4b71Sopenharmony_ci      }
255e41f4b71Sopenharmony_ci
256e41f4b71Sopenharmony_ci      static int32_t HiPwmProbe(struct HiPwm *hp, struct HdfDeviceObject *obj)
257e41f4b71Sopenharmony_ci      {
258e41f4b71Sopenharmony_ci          uint32_t tmp;
259e41f4b71Sopenharmony_ci          struct DeviceResourceIface *iface = NULL;
260e41f4b71Sopenharmony_ci      
261e41f4b71Sopenharmony_ci          iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); // Initialize the custom structure HiPwm.
262e41f4b71Sopenharmony_ci          ...
263e41f4b71Sopenharmony_ci          
264e41f4b71Sopenharmony_ci          hp->reg = (struct HiPwmRegs *)hp->base;                    // Initialize the custom structure HiPwm.
265e41f4b71Sopenharmony_ci          hp->supportPolarity = false;                               // Initialize the custom structure HiPwm.
266e41f4b71Sopenharmony_ci          hp->dev.method = &g_pwmOps;                                // Attach the PwmMethod instance.
267e41f4b71Sopenharmony_ci          hp->dev.cfg.duty = PWM_DEFAULT_DUTY_CYCLE;                 // Initialize PwmDev.
268e41f4b71Sopenharmony_ci          hp->dev.cfg.period = PWM_DEFAULT_PERIOD;                   // Initialize PwmDev.
269e41f4b71Sopenharmony_ci          hp->dev.cfg.polarity = PWM_DEFAULT_POLARITY;               // Initialize PwmDev.
270e41f4b71Sopenharmony_ci          hp->dev.cfg.status = PWM_DISABLE_STATUS;                   // Initialize PwmDev.
271e41f4b71Sopenharmony_ci          hp->dev.cfg.number = 0;                                    // Initialize PwmDev.
272e41f4b71Sopenharmony_ci          hp->dev.busy = false;                                      // Initialize PwmDev.
273e41f4b71Sopenharmony_ci          if (PwmDeviceAdd(obj, &(hp->dev)) ) != HDF_SUCCESS) {      // Call the core layer function to initialize devices and services.
274e41f4b71Sopenharmony_ci              OsalIoUnmap((void *)hp->base);
275e41f4b71Sopenharmony_ci              return HDF_FAILURE;
276e41f4b71Sopenharmony_ci          }
277e41f4b71Sopenharmony_ci          return HDF_SUCCESS;
278e41f4b71Sopenharmony_ci      }
279e41f4b71Sopenharmony_ci      ```
280e41f4b71Sopenharmony_ci
281e41f4b71Sopenharmony_ci   - Implement the **Release** function.
282e41f4b71Sopenharmony_ci
283e41f4b71Sopenharmony_ci      **Input parameter**:
284e41f4b71Sopenharmony_ci
285e41f4b71Sopenharmony_ci      **HdfDeviceObject**, a device object created by the HDF for each driver, holds device-related private data and service APIs.
286e41f4b71Sopenharmony_ci
287e41f4b71Sopenharmony_ci      **Return value**:
288e41f4b71Sopenharmony_ci
289e41f4b71Sopenharmony_ci      No value is returned.
290e41f4b71Sopenharmony_ci
291e41f4b71Sopenharmony_ci      **Function description**:
292e41f4b71Sopenharmony_ci
293e41f4b71Sopenharmony_ci      Releases the memory and deletes the controller. This function assigns values to **Release()** in the driver entry structure. If the HDF fails to call **Init()** to initialize the driver, **Release()** is called to release driver resources.
294e41f4b71Sopenharmony_ci
295e41f4b71Sopenharmony_ci      ```c
296e41f4b71Sopenharmony_ci      static void HdfPwmRelease(struct HdfDeviceObject *obj)
297e41f4b71Sopenharmony_ci      {
298e41f4b71Sopenharmony_ci          struct HiPwm *hp = NULL;
299e41f4b71Sopenharmony_ci          ...
300e41f4b71Sopenharmony_ci          hp = (struct HiPwm *)obj->service;        // A forced conversion from HdfDeviceObject to HiPwm is involved.
301e41f4b71Sopenharmony_ci          ...                                       
302e41f4b71Sopenharmony_ci          PwmDeviceRemove(obj, &(hp->dev));         // (Mandatory) Call the core layer functions to release PwmDev devices and services. A forced conversion from HiPwm to PwmDev is involved in the process.
303e41f4b71Sopenharmony_ci          HiPwmRemove(hp);                          // Release HiPwm.
304e41f4b71Sopenharmony_ci      }
305e41f4b71Sopenharmony_ci      ```
306e41f4b71Sopenharmony_ci
307e41f4b71Sopenharmony_ci4. Debug the driver.
308e41f4b71Sopenharmony_ci
309e41f4b71Sopenharmony_ci    (Optional) For new drivers, verify the basic functions, such as the PWM status control and response to interrupts.
310