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