1e41f4b71Sopenharmony_ci# GPIO
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci## Overview
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ci### Function
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ciA general-purpose input/output (GPIO) controller manages all GPIO pins by group. Each group of GPIO pins is associated with one or more registers. The GPIO controller manages the pins by reading data from and writing data to the registers.
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ci### Basic Concepts
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ciA GPIO can be used as an input, an output, or both, and is controllable by software.
12e41f4b71Sopenharmony_ci
13e41f4b71Sopenharmony_ci- GPIO input
14e41f4b71Sopenharmony_ci
15e41f4b71Sopenharmony_ci  When a GPIO is used as an input, it reads the level state (high or low) of each pin. Common input modes include analog input, floating input, pull-up input, and pull-down input.
16e41f4b71Sopenharmony_ci
17e41f4b71Sopenharmony_ci- GPIO output
18e41f4b71Sopenharmony_ci
19e41f4b71Sopenharmony_ci  When a GPIO is used as an output, it sets the pin level. Common output modes include open-drain output, push-pull output, multiplexed open-drain output, and multiplexed push-pull output.
20e41f4b71Sopenharmony_ci
21e41f4b71Sopenharmony_ci### Working Principles
22e41f4b71Sopenharmony_ci
23e41f4b71Sopenharmony_ciIn the Hardware Driver Foundation (HDF), the GPIO module uses the unified service mode for API adaptation. In this mode, a device service is used as the GPIO manager to handle access requests from the devices of the same type in a unified manner. The unified service mode applies to the scenario where there are many 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 following figure shows the unified service mode.
24e41f4b71Sopenharmony_ci
25e41f4b71Sopenharmony_ciIn 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.
26e41f4b71Sopenharmony_ci
27e41f4b71Sopenharmony_ciThe GPIO module is divided into the following layers:
28e41f4b71Sopenharmony_ci
29e41f4b71Sopenharmony_ci- Interface layer: provides APIs for operating GPIO pins.
30e41f4b71Sopenharmony_ci- Core layer: provides the capabilities of adding and removing a GPIO controller and managing GPIO pins. This layer interacts with the adaptation layer through hook functions to allow the GPIO chip drivers of different vendors to quickly access the HDF.
31e41f4b71Sopenharmony_ci- Adaptation layer: instantiates hook functions to implement specific features.
32e41f4b71Sopenharmony_ci
33e41f4b71Sopenharmony_ci**Figure 1** Unified service mode
34e41f4b71Sopenharmony_ci
35e41f4b71Sopenharmony_ci![](figures/unified-service-mode.png)
36e41f4b71Sopenharmony_ci
37e41f4b71Sopenharmony_ci## Development Guidelines
38e41f4b71Sopenharmony_ci
39e41f4b71Sopenharmony_ci### When to Use
40e41f4b71Sopenharmony_ci
41e41f4b71Sopenharmony_ciAs a concept at the software layer, GPIO is used to manage GPIO pin resources. You can use the APIs provided by the GPIO module to control pins. Before using your GPIO driver with OpenHarmony, you need to perform GPIO driver adaptation. The following sections describe how to adapt the GPIO driver.
42e41f4b71Sopenharmony_ci
43e41f4b71Sopenharmony_ci### Available APIs
44e41f4b71Sopenharmony_ci
45e41f4b71Sopenharmony_ciTo enable the upper layer to successfully operate GPIO pins by calling the GPIO APIs, hook functions are defined in **//drivers/hdf_core/framework/support/platform/include/gpio/gpio_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.
46e41f4b71Sopenharmony_ci
47e41f4b71Sopenharmony_ci**GpioMethod**:
48e41f4b71Sopenharmony_ci
49e41f4b71Sopenharmony_ci```c
50e41f4b71Sopenharmony_cistruct GpioMethod {
51e41f4b71Sopenharmony_ci    int32_t (*request)(struct GpioCntlr *cntlr, uint16_t local);                // Reserved.
52e41f4b71Sopenharmony_ci    int32_t (*release)(struct GpioCntlr *cntlr, uint16_t local);                // Reserved.
53e41f4b71Sopenharmony_ci    int32_t (*write)(struct GpioCntlr *cntlr, uint16_t local, uint16_t val);
54e41f4b71Sopenharmony_ci    int32_t (*read)(struct GpioCntlr *cntlr, uint16_t local, uint16_t *val);
55e41f4b71Sopenharmony_ci    int32_t (*setDir)(struct GpioCntlr *cntlr, uint16_t local, uint16_t dir);
56e41f4b71Sopenharmony_ci    int32_t (*getDir)(struct GpioCntlr *cntlr, uint16_t local, uint16_t *dir);
57e41f4b71Sopenharmony_ci    int32_t (*toIrq)(struct GpioCntlr *cntlr, uint16_t local, uint16_t *irq);   // Reserved.
58e41f4b71Sopenharmony_ci    int32_t (*setIrq)(struct GpioCntlr *cntlr, uint16_t local, uint16_t mode, GpioIrqFunc func, void *arg);
59e41f4b71Sopenharmony_ci    int32_t (*unsetIrq)(struct GpioCntlr *cntlr, uint16_t local);
60e41f4b71Sopenharmony_ci    int32_t (*enableIrq)(struct GpioCntlr *cntlr, uint16_t local);
61e41f4b71Sopenharmony_ci    int32_t (*disableIrq)(struct GpioCntlr *cntlr, uint16_t local);
62e41f4b71Sopenharmony_ci}
63e41f4b71Sopenharmony_ci```
64e41f4b71Sopenharmony_ci
65e41f4b71Sopenharmony_ci**Table 1** Hook functions in **GpioMethod**
66e41f4b71Sopenharmony_ci
67e41f4b71Sopenharmony_ci| Function| Input Parameter| Output Parameter| Return Value| Description|
68e41f4b71Sopenharmony_ci| -------- | -------- | -------- | -------- | -------- |
69e41f4b71Sopenharmony_ci| write | **cntlr**: structure pointer to the GPIO controller at the core layer.<br>**local**: GPIO port number, which is of the uint16_t type.<br>**val**: level value to write, which is of the uint16_t type.| –| HDF_STATUS| Writes the level for a GPIO pin.|
70e41f4b71Sopenharmony_ci| read | **cntlr**: structure pointer to the GPIO controller at the core layer.<br>**local**: GPIO port number, which is of the uint16_t type.| **val**: level value read, which is of the uint16_t type.| HDF_STATUS| Reads the level of a GPIO pin.|
71e41f4b71Sopenharmony_ci| setDir | **cntlr**: structure pointer to the GPIO controller at the core layer.<br>**local**: GPIO port number, which is of the uint16_t type.<br>**dir**: pin direction to set, which is of the uint16_t type.| –| HDF_STATUS| Sets the direction (input or output) for a GPIO pin.|
72e41f4b71Sopenharmony_ci| getDir | **cntlr**: structure pointer to the GPIO controller at the core layer.<br>**local**: GPIO port number, which is of the uint16_t type.| **dir**: pin direction read, which is of the uint16_t type.| HDF_STATUS| Obtains the input or output direction of a GPIO pin.|
73e41f4b71Sopenharmony_ci| setIrq | **cntlr**: structure pointer to the GPIO controller at the core layer.<br>**local**: GPIO port number, which is of the uint16_t type.<br>**mode**: interrupt trigger mode, which can be edge or level. The value is of the uint16_t type.<br>**func**: pointer to the interrupt request (IRQ) handler.<br>**arg**: void pointer to the input parameters of the IRQ handler.| –| HDF_STATUS| Sets an IRQ function for a GPIO pin.|
74e41f4b71Sopenharmony_ci| unsetIrq | **cntlr**: structure pointer to the GPIO controller at the core layer.<br>**local**: GPIO port number, which is of the uint16_t type.| –| HDF_STATUS| Cancels the IRQ function for a GPIO pin.|
75e41f4b71Sopenharmony_ci| enableIrq | **cntlr**: structure pointer to the GPIO controller at the core layer.<br>**local**: GPIO port number, which is of the uint16_t type.| –| HDF_STATUS| Enables interrupts for a GPIO pin.|
76e41f4b71Sopenharmony_ci| disableIrq | **cntlr**: structure pointer to the GPIO controller at the core layer.<br>**local**: GPIO port number, which is of the uint16_t type.| –| HDF_STATUS| Disables interrupts for a GPIO pin.|
77e41f4b71Sopenharmony_ci
78e41f4b71Sopenharmony_ci### How to Develop
79e41f4b71Sopenharmony_ci
80e41f4b71Sopenharmony_ciThe GPIO module adaptation procedure is as follows:
81e41f4b71Sopenharmony_ci
82e41f4b71Sopenharmony_ci1. Instantiate the driver entry.
83e41f4b71Sopenharmony_ci2. Configure attribute files.
84e41f4b71Sopenharmony_ci3. Instantiate the GPIO controller object.
85e41f4b71Sopenharmony_ci4. Debug the driver.
86e41f4b71Sopenharmony_ci
87e41f4b71Sopenharmony_ci### Example
88e41f4b71Sopenharmony_ci
89e41f4b71Sopenharmony_ciThe following uses the **//device_soc_hisilicon/common/platform/gpio/gpio_hi35xx.c** driver of the Hi3516D V300 development board as an example to describe the driver adaptation.
90e41f4b71Sopenharmony_ci
91e41f4b71Sopenharmony_ci1. Instantiate the driver entry.
92e41f4b71Sopenharmony_ci
93e41f4b71Sopenharmony_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 are collected to form a segment address space similar to an array for the upper layer to invoke.
94e41f4b71Sopenharmony_ci   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.
95e41f4b71Sopenharmony_ci
96e41f4b71Sopenharmony_ci   GPIO driver entry example:
97e41f4b71Sopenharmony_ci
98e41f4b71Sopenharmony_ci   ```c
99e41f4b71Sopenharmony_ci   struct HdfDriverEntry g_gpioDriverEntry = {
100e41f4b71Sopenharmony_ci       .moduleVersion = 1,
101e41f4b71Sopenharmony_ci       .Bind = Pl061GpioBind,                // GPIO does not use the Bind function, which is an empty implementation in this example. You can add related operations as required.
102e41f4b71Sopenharmony_ci       ..Init = Pl061GpioInit,               // See the Init function.
103e41f4b71Sopenharmony_ci       .Release = Pl061GpioRelease,          // See the Release function.
104e41f4b71Sopenharmony_ci       .moduleName = "hisi_pl061_driver",    // (Mandatory) The value must be the same as that of moduleName in the .hcs file.
105e41f4b71Sopenharmony_ci   };
106e41f4b71Sopenharmony_ci   HDF_INIT(g_gpioDriverEntry);              // Call HDF_INIT to register the driver entry with the HDF.
107e41f4b71Sopenharmony_ci   ```
108e41f4b71Sopenharmony_ci
109e41f4b71Sopenharmony_ci2. Configure attribute files.
110e41f4b71Sopenharmony_ci
111e41f4b71Sopenharmony_ci   Add the deviceNode information to the **device_info.hcs** file. The deviceNode information is closely related to driver entry registration. In this example, there is only one GPIO controller. If there are multiple GPIO controllers, add the deviceNode information to the **device_info.hcs** file for each controller. The device attribute values are closely related to the default values or value ranges of the **GpioCntlr** members at the core layer, and are configured in **gpio_config.hcs**.
112e41f4b71Sopenharmony_ci
113e41f4b71Sopenharmony_ci   - **device_info.hcs** example
114e41f4b71Sopenharmony_ci
115e41f4b71Sopenharmony_ci      Add the deviceNode information to the **//vendor/hisilicon/hispark_taurus/hdf_config/device_info/device_info.hcs** file.
116e41f4b71Sopenharmony_ci
117e41f4b71Sopenharmony_ci      ```c
118e41f4b71Sopenharmony_ci      root {
119e41f4b71Sopenharmony_ci          device_info {
120e41f4b71Sopenharmony_ci              platform :: host {
121e41f4b71Sopenharmony_ci                  hostName = "platform_host";
122e41f4b71Sopenharmony_ci                  priority = 50;
123e41f4b71Sopenharmony_ci                  device_gpio :: device {
124e41f4b71Sopenharmony_ci                      device0 :: deviceNode {
125e41f4b71Sopenharmony_ci                       policy = 0;                                 // The value 0 indicates that no service needs to be published.
126e41f4b71Sopenharmony_ci                      priority = 10;                               // Driver startup priority.
127e41f4b71Sopenharmony_ci                      permission = 0644;                           // Permission for the device node created.
128e41f4b71Sopenharmony_ci                      oduleName = "hisi_pl061_driver";             // (Mandatory) Driver name, which must be the same as moduleName in the driver entry.
129e41f4b71Sopenharmony_ci                      deviceMatchAttr = "hisilicon_hi35xx_pl061";  // (Mandatory) Private data of the controller. The value must be the same as the controller information in gpio_config.hcs.
130e41f4b71Sopenharmony_ci                                                                   // The private information about all controllers is in the gpio_config.hcs file.
131e41f4b71Sopenharmony_ci                      }
132e41f4b71Sopenharmony_ci                  }
133e41f4b71Sopenharmony_ci              }
134e41f4b71Sopenharmony_ci          }
135e41f4b71Sopenharmony_ci      }
136e41f4b71Sopenharmony_ci      ```
137e41f4b71Sopenharmony_ci
138e41f4b71Sopenharmony_ci   - **gpio_config.hcs** example
139e41f4b71Sopenharmony_ci
140e41f4b71Sopenharmony_ci      Configure the device attributes in the **//device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/gpio/gpio_config.hcs** file. The parameters are as follows:
141e41f4b71Sopenharmony_ci
142e41f4b71Sopenharmony_ci      ```c
143e41f4b71Sopenharmony_ci      root {
144e41f4b71Sopenharmony_ci          platform {
145e41f4b71Sopenharmony_ci              gpio_config {
146e41f4b71Sopenharmony_ci                  controller_0x120d0000 {
147e41f4b71Sopenharmony_ci                      match_attr = "hisilicon_hi35xx_pl061";   // (Mandatory) The value must be the same as that of deviceMatchAttr in device_info.hcs.
148e41f4b71Sopenharmony_ci                      groupNum = 12;                           // (Mandatory) GPIO group number.
149e41f4b71Sopenharmony_ci                      bitNum = 8;                              // (Mandatory) Number of GPIO pins in each group.
150e41f4b71Sopenharmony_ci                      regBase = 0x120d0000;                    // (Mandatory) Physical base address.
151e41f4b71Sopenharmony_ci                      regStep = 0x1000;                        // (Mandatory) Register offset step.
152e41f4b71Sopenharmony_ci                      irqStart = 48;                           // (Mandatory) Enable interrupts.
153e41f4b71Sopenharmony_ci                      irqShare = 0;                            // (Mandatory) Whether to share interrupt. The value 1 means to share interrupt; the value 0 means the opposite.
154e41f4b71Sopenharmony_ci                  }
155e41f4b71Sopenharmony_ci                  ... 
156e41f4b71Sopenharmony_ci              }
157e41f4b71Sopenharmony_ci          }
158e41f4b71Sopenharmony_ci      }
159e41f4b71Sopenharmony_ci      ```
160e41f4b71Sopenharmony_ci
161e41f4b71Sopenharmony_ci      After the **gpio_config.hcs** file is configured, include the file in the **hdf.hcs** file. Otherwise, the configuration file cannot take effect.
162e41f4b71Sopenharmony_ci
163e41f4b71Sopenharmony_ci      ```c
164e41f4b71Sopenharmony_ci      #include "../../../../device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/gpio/gpio_config.hcs" // Relative path of the gpio_config.hcs file.
165e41f4b71Sopenharmony_ci      ```
166e41f4b71Sopenharmony_ci
167e41f4b71Sopenharmony_ci3. Instantiate the GPIO controller object.
168e41f4b71Sopenharmony_ci
169e41f4b71Sopenharmony_ci   Initialize the **GpioCntlr** 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 **GpioMethod** in **GpioCntlr** (so that the underlying driver functions can be called).
170e41f4b71Sopenharmony_ci
171e41f4b71Sopenharmony_ci   - Define a custom structure.
172e41f4b71Sopenharmony_ci
173e41f4b71Sopenharmony_ci      To the driver, the custom structure holds parameters and data. The **DeviceResourceIface** method provided by the HDF reads the values in the **gpio_config.hcs** file to initialize the members in the custom structure and passes important parameters, such as the GPIO group number and the number of pins, to the **GpioCntlr** object at the core layer.
174e41f4b71Sopenharmony_ci
175e41f4b71Sopenharmony_ci      ```c
176e41f4b71Sopenharmony_ci      // Define the GPIO group information.
177e41f4b71Sopenharmony_ci      struct Pl061GpioGroup {
178e41f4b71Sopenharmony_ci          struct GpioCntlr cntlr             // (Mandatory) Control object of the core layer.
179e41f4b71Sopenharmony_ci          volatile unsigned char *regBase;   // (Mandatory) Register base address.
180e41f4b71Sopenharmony_ci          unsigned int index;
181e41f4b71Sopenharmony_ci          unsigned int irq;
182e41f4b71Sopenharmony_ci          OsalIRQHandle irqFunc;
183e41f4b71Sopenharmony_ci          OsalSpinlock lock;
184e41f4b71Sopenharmony_ci          uint32_t irqSave;
185e41f4b71Sopenharmony_ci          bool irqShare;
186e41f4b71Sopenharmony_ci          struct PlatformDumper *dumper;
187e41f4b71Sopenharmony_ci          char *dumperName;
188e41f4b71Sopenharmony_ci      };
189e41f4b71Sopenharmony_ci      
190e41f4b71Sopenharmony_ci      struct Pl061GpioData {
191e41f4b71Sopenharmony_ci          volatile unsigned char *regBase;   // (Mandatory) Register base address.
192e41f4b71Sopenharmony_ci          uint32_t phyBase;                  // (Mandatory) Physical base address.
193e41f4b71Sopenharmony_ci          uint32_t regStep;;                 // (Mandatory) Register offset step.
194e41f4b71Sopenharmony_ci          uint32_t irqStart;                 // (Mandatory) Enable interrupts.
195e41f4b71Sopenharmony_ci          uint16_t groupNum;                 // (Mandatory) Parameter of the GPIO port number.
196e41f4b71Sopenharmony_ci          uint16_t bitNum;                   // (Mandatory) Parameter of the GPIO port number.
197e41f4b71Sopenharmony_ci          uint8_t irqShare;                  // (Mandatory) Whether to share interrupt.
198e41f4b71Sopenharmony_ci          struct Pl061GpioGroup *groups;     // (Optional) Set as required.
199e41f4b71Sopenharmony_ci          struct GpioInfo *gpioInfo;
200e41f4b71Sopenharmony_ci          void *priv;
201e41f4b71Sopenharmony_ci      };
202e41f4b71Sopenharmony_ci      
203e41f4b71Sopenharmony_ci      struct GpioInfo {
204e41f4b71Sopenharmony_ci          struct GpioCntlr *cntlr;
205e41f4b71Sopenharmony_ci          char name[GPIO_NAME_LEN];
206e41f4b71Sopenharmony_ci          OsalSpinlock spin;
207e41f4b71Sopenharmony_ci          uint32_t irqSave;
208e41f4b71Sopenharmony_ci          struct GpioIrqRecord *irqRecord;
209e41f4b71Sopenharmony_ci      };
210e41f4b71Sopenharmony_ci      // GpioCntlr is the controller structure at the core layer. The Init function assigns values to the members of GpioCntlr.
211e41f4b71Sopenharmony_ci      struct GpioCntlr {
212e41f4b71Sopenharmony_ci          struct PlatformDevice device;
213e41f4b71Sopenharmony_ci          struct GpioMethod *ops;
214e41f4b71Sopenharmony_ci          uint16_t start;
215e41f4b71Sopenharmony_ci          uint16_t count;
216e41f4b71Sopenharmony_ci          struct GpioInfo *ginfos;
217e41f4b71Sopenharmony_ci          bool isAutoAlloced;
218e41f4b71Sopenharmony_ci          void *priv;
219e41f4b71Sopenharmony_ci      };
220e41f4b71Sopenharmony_ci      ```
221e41f4b71Sopenharmony_ci
222e41f4b71Sopenharmony_ci   - Instantiate the **GpioMethod** structure in **GpioCntlr**.
223e41f4b71Sopenharmony_ci
224e41f4b71Sopenharmony_ci      ```c
225e41f4b71Sopenharmony_ci      // The members of the GpioMethod structure are hook functions. You need to implement them by referring to Table 1.
226e41f4b71Sopenharmony_ci      static struct GpioMethod g_method = {
227e41f4b71Sopenharmony_ci          .request = NULL,
228e41f4b71Sopenharmony_ci          .release = NULL,
229e41f4b71Sopenharmony_ci          .write = Pl061GpioWrite,              // Write the pin level.
230e41f4b71Sopenharmony_ci          .read = Pl061GpioRead,                // Read the pin level.
231e41f4b71Sopenharmony_ci          .setDir = Pl061GpioSetDir,            // Set the pin direction.
232e41f4b71Sopenharmony_ci          .getDir = Pl061GpioGetDir,            // Obtain the pin direction.
233e41f4b71Sopenharmony_ci          .toIrq = NULL,                        
234e41f4b71Sopenharmony_ci          .setIrq = Pl061GpioSetIrq,            // Set an IRQ function for a pin. Skip it if this capability is not available.
235e41f4b71Sopenharmony_ci          .unsetIrq = Pl061GpioUnsetIrq,        // Cancel the IRQ function for a pin. Skip it if this capability is not available.
236e41f4b71Sopenharmony_ci          .enableIrq = Pl061GpioEnableIrq,      // Enable interrupts for a pin. Skip it if this capability is not available.
237e41f4b71Sopenharmony_ci          .disableIrq = Pl061GpioDisableIrq,    // Disable interrupts for a pin. Skip it if this capability is not available.
238e41f4b71Sopenharmony_ci      };
239e41f4b71Sopenharmony_ci      ```
240e41f4b71Sopenharmony_ci
241e41f4b71Sopenharmony_ci   - Implement the **Init** function.
242e41f4b71Sopenharmony_ci
243e41f4b71Sopenharmony_ci      Input parameters:
244e41f4b71Sopenharmony_ci
245e41f4b71Sopenharmony_ci      **HdfDeviceObject**, a device object created by the HDF for each driver, holds device-related private data and service APIs.
246e41f4b71Sopenharmony_ci
247e41f4b71Sopenharmony_ci      Return value:
248e41f4b71Sopenharmony_ci
249e41f4b71Sopenharmony_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.
250e41f4b71Sopenharmony_ci
251e41f4b71Sopenharmony_ci      **Table 2** HDF_STATUS
252e41f4b71Sopenharmony_ci
253e41f4b71Sopenharmony_ci      | Status| Description|
254e41f4b71Sopenharmony_ci      | -------- | -------- |
255e41f4b71Sopenharmony_ci      | HDF_ERR_INVALID_OBJECT | Invalid controller object.|
256e41f4b71Sopenharmony_ci      | HDF_ERR_MALLOC_FAIL | Failed to allocate memory.|
257e41f4b71Sopenharmony_ci      | HDF_ERR_INVALID_PARAM | Invalid parameter.|
258e41f4b71Sopenharmony_ci      | HDF_ERR_IO | I/O error.|
259e41f4b71Sopenharmony_ci      | HDF_SUCCESS | Initialization successful.|
260e41f4b71Sopenharmony_ci      | HDF_FAILURE | Initialization failed.|
261e41f4b71Sopenharmony_ci
262e41f4b71Sopenharmony_ci      Function description:
263e41f4b71Sopenharmony_ci
264e41f4b71Sopenharmony_ci      Initializes the custom structure object and **GpioCntlr**, calls **GpioCntlrAdd()** at the core layer, and (optional) accesses the virtual file system (VFS).
265e41f4b71Sopenharmony_ci
266e41f4b71Sopenharmony_ci      ```c
267e41f4b71Sopenharmony_ci      static struct Pl061GpioData g_pl061 = {
268e41f4b71Sopenharmony_ci          .groups = NULL,
269e41f4b71Sopenharmony_ci          .groupNum = PL061_GROUP_MAX,
270e41f4b71Sopenharmony_ci          .bitNum = PL061_BIT_MAX,
271e41f4b71Sopenharmony_ci      };
272e41f4b71Sopenharmony_ci      
273e41f4b71Sopenharmony_ci      static int32_t Pl061GpioInitGroups(struct Pl061GpioData *pl061)
274e41f4b71Sopenharmony_ci      {
275e41f4b71Sopenharmony_ci          int32_t ret;
276e41f4b71Sopenharmony_ci          uint16_t i;
277e41f4b71Sopenharmony_ci          struct Pl061GpioGroup *groups = NULL;
278e41f4b71Sopenharmony_ci      
279e41f4b71Sopenharmony_ci          if (pl061 == NULL) {
280e41f4b71Sopenharmony_ci              return HDF_ERR_INVALID_PARAM;
281e41f4b71Sopenharmony_ci          }
282e41f4b71Sopenharmony_ci      
283e41f4b71Sopenharmony_ci          groups = (struct Pl061GpioGroup *)OsalMemCalloc(sizeof(*groups) * pl061->groupNum);
284e41f4b71Sopenharmony_ci          if (groups == NULL) {
285e41f4b71Sopenharmony_ci              return HDF_ERR_MALLOC_FAIL;
286e41f4b71Sopenharmony_ci          }
287e41f4b71Sopenharmony_ci          pl061->groups = groups;
288e41f4b71Sopenharmony_ci      
289e41f4b71Sopenharmony_ci          for (i = 0; i < pl061->groupNum; i++) {
290e41f4b71Sopenharmony_ci              // Initialize related information.
291e41f4b71Sopenharmony_ci              groups[i].index = i;
292e41f4b71Sopenharmony_ci              groups[i].regBase = pl061->regBase + i * pl061->regStep;
293e41f4b71Sopenharmony_ci              groups[i].irq = pl061->irqStart + i;
294e41f4b71Sopenharmony_ci              groups[i].irqShare = pl061->irqShare;
295e41f4b71Sopenharmony_ci              groups[i].cntlr.start = i * pl061->bitNum;
296e41f4b71Sopenharmony_ci              groups[i].cntlr.count = pl061->bitNum;
297e41f4b71Sopenharmony_ci              groups[i].cntlr.ops = &g_method;
298e41f4b71Sopenharmony_ci              groups[i].cntlr.ginfos = &pl061->gpioInfo[i * pl061->bitNum];
299e41f4b71Sopenharmony_ci      
300e41f4b71Sopenharmony_ci              if ((ret = OsalSpinInit(&groups[i].lock)) != HDF_SUCCESS) {
301e41f4b71Sopenharmony_ci                  goto ERR_EXIT;
302e41f4b71Sopenharmony_ci              }
303e41f4b71Sopenharmony_ci      
304e41f4b71Sopenharmony_ci              ret = GpioCntlrAdd(&groups[i].cntlr); // Add related information to the HDF core.
305e41f4b71Sopenharmony_ci              if (ret != HDF_SUCCESS) {
306e41f4b71Sopenharmony_ci                  HDF_LOGE("%s: err add controller(%hu:%hu):%d", __func__,
307e41f4b71Sopenharmony_ci                      groups[i].cntlr.start, groups[i].cntlr.count, ret);
308e41f4b71Sopenharmony_ci                  (void)OsalSpinDestroy(&groups[i].lock);
309e41f4b71Sopenharmony_ci                  goto ERR_EXIT;
310e41f4b71Sopenharmony_ci              }
311e41f4b71Sopenharmony_ci          }
312e41f4b71Sopenharmony_ci          return HDF_SUCCESS;
313e41f4b71Sopenharmony_ci      
314e41f4b71Sopenharmony_ci      ERR_EXIT:
315e41f4b71Sopenharmony_ci          while (i-- > 0) {
316e41f4b71Sopenharmony_ci              GpioCntlrRemove(&groups[i].cntlr);
317e41f4b71Sopenharmony_ci              (void)OsalSpinDestroy(&groups[i].lock);
318e41f4b71Sopenharmony_ci          }
319e41f4b71Sopenharmony_ci          pl061->groups = NULL;
320e41f4b71Sopenharmony_ci          OsalMemFree(groups);
321e41f4b71Sopenharmony_ci          return ret;
322e41f4b71Sopenharmony_ci      }
323e41f4b71Sopenharmony_ci      
324e41f4b71Sopenharmony_ci      static int32_t Pl061GpioInit(struct HdfDeviceObject *device)
325e41f4b71Sopenharmony_ci      {
326e41f4b71Sopenharmony_ci          int32_t ret;
327e41f4b71Sopenharmony_ci          struct Pl061GpioData *pl061 = &g_pl061;
328e41f4b71Sopenharmony_ci      
329e41f4b71Sopenharmony_ci          if (device == NULL || device->property == NULL) {
330e41f4b71Sopenharmony_ci              HDF_LOGE("%s: device or property null!", __func__);
331e41f4b71Sopenharmony_ci              return HDF_ERR_INVALID_OBJECT;
332e41f4b71Sopenharmony_ci          }
333e41f4b71Sopenharmony_ci      
334e41f4b71Sopenharmony_ci          pl061->gpioInfo = OsalMemCalloc(sizeof(struct GpioInfo) * GPIO_MAX_INFO_NUM);
335e41f4b71Sopenharmony_ci          if (pl061->gpioInfo == NULL) {
336e41f4b71Sopenharmony_ci              HDF_LOGE("%s: failed to calloc gpioInfo!", __func__);
337e41f4b71Sopenharmony_ci              return HDF_ERR_MALLOC_FAIL;
338e41f4b71Sopenharmony_ci          }
339e41f4b71Sopenharmony_ci      
340e41f4b71Sopenharmony_ci          ret = Pl061GpioReadDrs(pl061, device->property);// Use the attribute values read from the gpio_config.hcs file to initialize the members of the custom structure object.
341e41f4b71Sopenharmony_ci          if (ret != HDF_SUCCESS) {
342e41f4b71Sopenharmony_ci              HDF_LOGE("%s: failed to read drs:%d", __func__, ret);
343e41f4b71Sopenharmony_ci              return ret;
344e41f4b71Sopenharmony_ci          }
345e41f4b71Sopenharmony_ci      
346e41f4b71Sopenharmony_ci          if (pl061->groupNum > PL061_GROUP_MAX || pl061->groupNum <= 0 ||
347e41f4b71Sopenharmony_ci              pl061->bitNum > PL061_BIT_MAX || pl061->bitNum <= 0) {
348e41f4b71Sopenharmony_ci              HDF_LOGE("%s: err groupNum:%hu, bitNum:%hu", __func__, pl061->groupNum, pl061->bitNum);
349e41f4b71Sopenharmony_ci              return HDF_ERR_INVALID_PARAM;
350e41f4b71Sopenharmony_ci          }
351e41f4b71Sopenharmony_ci      
352e41f4b71Sopenharmony_ci          pl061->regBase = OsalIoRemap(pl061->phyBase, pl061->groupNum * pl061->regStep);// Create address mapping.
353e41f4b71Sopenharmony_ci          if (pl061->regBase == NULL) {
354e41f4b71Sopenharmony_ci              HDF_LOGE("%s: err remap phy:0x%x", __func__, pl061->phyBase);
355e41f4b71Sopenharmony_ci              return HDF_ERR_IO;
356e41f4b71Sopenharmony_ci          }
357e41f4b71Sopenharmony_ci      
358e41f4b71Sopenharmony_ci          ret = Pl061GpioInitGroups(pl061); // Initialize the group information and add it to the HDF core layer.
359e41f4b71Sopenharmony_ci          if (ret != HDF_SUCCESS) {
360e41f4b71Sopenharmony_ci              HDF_LOGE("%s: err init groups:%d", __func__, ret);
361e41f4b71Sopenharmony_ci              OsalIoUnmap((void *)pl061->regBase);
362e41f4b71Sopenharmony_ci              pl061->regBase = NULL;
363e41f4b71Sopenharmony_ci              return ret;
364e41f4b71Sopenharmony_ci          }
365e41f4b71Sopenharmony_ci          pl061->priv = (void *)device->property;
366e41f4b71Sopenharmony_ci          device->priv = (void *)pl061;
367e41f4b71Sopenharmony_ci          Pl061GpioDebug(pl061);
368e41f4b71Sopenharmony_ci      
369e41f4b71Sopenharmony_ci      #ifdef PL061_GPIO_USER_SUPPORT
370e41f4b71Sopenharmony_ci          if (GpioAddVfs(pl061->bitNum) != HDF_SUCCESS) {
371e41f4b71Sopenharmony_ci              HDF_LOGE("%s: add vfs fail!", __func__);
372e41f4b71Sopenharmony_ci          }
373e41f4b71Sopenharmony_ci      #endif
374e41f4b71Sopenharmony_ci          HDF_LOGI("%s: dev service:%s init success!", __func__, HdfDeviceGetServiceName(device));
375e41f4b71Sopenharmony_ci          return HDF_SUCCESS;
376e41f4b71Sopenharmony_ci      }
377e41f4b71Sopenharmony_ci      ```
378e41f4b71Sopenharmony_ci
379e41f4b71Sopenharmony_ci   - Implement the **Release** function.
380e41f4b71Sopenharmony_ci
381e41f4b71Sopenharmony_ci      Input parameters:
382e41f4b71Sopenharmony_ci
383e41f4b71Sopenharmony_ci      **HdfDeviceObject**, a device object created by the HDF for each driver, holds device-related private data and service APIs.
384e41f4b71Sopenharmony_ci
385e41f4b71Sopenharmony_ci      Return value:
386e41f4b71Sopenharmony_ci
387e41f4b71Sopenharmony_ci      No value is returned.
388e41f4b71Sopenharmony_ci
389e41f4b71Sopenharmony_ci      Function description:
390e41f4b71Sopenharmony_ci
391e41f4b71Sopenharmony_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.
392e41f4b71Sopenharmony_ci
393e41f4b71Sopenharmony_ci      > ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
394e41f4b71Sopenharmony_ci      >
395e41f4b71Sopenharmony_ci      > All forced conversion operations for obtaining the corresponding object can be successful only when the **Init** function has the value assignment operations.
396e41f4b71Sopenharmony_ci
397e41f4b71Sopenharmony_ci      ```c
398e41f4b71Sopenharmony_ci      static void Pl061GpioUninitGroups(struct Pl061GpioData *pl061)
399e41f4b71Sopenharmony_ci      {
400e41f4b71Sopenharmony_ci          uint16_t i;
401e41f4b71Sopenharmony_ci          struct Pl061GpioGroup *group = NULL;
402e41f4b71Sopenharmony_ci      
403e41f4b71Sopenharmony_ci          for (i = 0; i < pl061->groupNum; i++) {
404e41f4b71Sopenharmony_ci              group = &pl061->groups[i];
405e41f4b71Sopenharmony_ci              GpioDumperDestroy(&pl061->groups[i]);
406e41f4b71Sopenharmony_ci              GpioCntlrRemove(&group->cntlr); // Remove from the HDF core layer.
407e41f4b71Sopenharmony_ci          }
408e41f4b71Sopenharmony_ci      
409e41f4b71Sopenharmony_ci          OsalMemFree(pl061->groups);
410e41f4b71Sopenharmony_ci          pl061->groups = NULL;
411e41f4b71Sopenharmony_ci      }
412e41f4b71Sopenharmony_ci      
413e41f4b71Sopenharmony_ci      static void Pl061GpioRelease(struct HdfDeviceObject *device)
414e41f4b71Sopenharmony_ci      {
415e41f4b71Sopenharmony_ci          struct Pl061GpioData *pl061 = NULL;
416e41f4b71Sopenharmony_ci      
417e41f4b71Sopenharmony_ci          HDF_LOGI("%s: enter", __func__);
418e41f4b71Sopenharmony_ci          if (device == NULL) {
419e41f4b71Sopenharmony_ci              HDF_LOGE("%s: device is null!", __func__);
420e41f4b71Sopenharmony_ci              return;
421e41f4b71Sopenharmony_ci          }
422e41f4b71Sopenharmony_ci      
423e41f4b71Sopenharmony_ci      #ifdef PL061_GPIO_USER_SUPPORT
424e41f4b71Sopenharmony_ci          GpioRemoveVfs();
425e41f4b71Sopenharmony_ci      #endif
426e41f4b71Sopenharmony_ci      
427e41f4b71Sopenharmony_ci          pl061 = (struct Pl061GpioData *)device->priv;
428e41f4b71Sopenharmony_ci          if (pl061 == NULL) {
429e41f4b71Sopenharmony_ci              HDF_LOGE("%s: device priv is null", __func__);
430e41f4b71Sopenharmony_ci              return;
431e41f4b71Sopenharmony_ci          }
432e41f4b71Sopenharmony_ci      
433e41f4b71Sopenharmony_ci          Pl061GpioUninitGroups(pl061);
434e41f4b71Sopenharmony_ci          OsalMemFree(pl061->gpioInfo);
435e41f4b71Sopenharmony_ci          pl061->gpioInfo = NULL;
436e41f4b71Sopenharmony_ci          OsalIoUnmap((void *)pl061->regBase);
437e41f4b71Sopenharmony_ci          pl061->regBase = NULL;
438e41f4b71Sopenharmony_ci      }
439e41f4b71Sopenharmony_ci      ```
440e41f4b71Sopenharmony_ci
441e41f4b71Sopenharmony_ci4. Debug the driver.
442e41f4b71Sopenharmony_ci
443e41f4b71Sopenharmony_ci   (Optional) For new drivers, verify the basic functions, such as the GPIO status control and response to interrupts.
444