1# Pin 2 3## Overview 4 5### Function 6 7The pin module, also called pin controller, manages pin resources of the system on a chip (SoC) and implements the pin multiplexing function. 8 9### Basic Concepts 10 11Pin is a software concept designed to uniformly manage SoC pins, implement pin multiplexing, and set electrical features of pins. 12 13- SoC 14 15 An SoC is a chip that integrates microprocessors, analog IP cores, digital IP cores, and memory for specific purposes. 16 17- Pin multiplexing 18 19 When the number of pins of a chip cannot handle the increasing connection requests, you can set software registers to make the pins to work in different states. 20 21### Working Principles 22 23In the Hardware Driver Foundation (HDF), the pin module uses the unified service mode for API adaptation. In this mode, a device service is used as the pin 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 pin module is divided into the following layers: 28 29- Interface layer: provides APIs for obtaining a pin, setting or obtaining the pull type, pull strength, and function of a pin, and releasing a pin. 30- Core layer: provides APIs for matching pin resources, adding and removing a pin controller, and managing pins. The core layer interacts with the adaptation layer through hook functions. 31- Adaptation layer: instantiates the hook functions to implement specific features. 32 33**Figure 1** Unified service mode 34 35![](figures/unified-service-mode.png) 36 37### Constraints 38 39The pin module supports only the LiteOS-A kernel of the small system. 40 41## Development Guidelines 42 43### When to Use 44 45The pin module is used to manage pin resources. Before using the SoC with the HDF, you need to perform PIN driver adaptation. 46 47### Available APIs 48 49To enable the upper layer to successfully operate pins by calling the pin driver APIs, hook functions are defined in **//drivers/hdf_core/framework/support/platform/include/pin/pin_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. 50 51**PinCntlrMethod**: 52 53```c 54struct PinCntlrMethod { 55 int32_t (*SetPinPull)(struct PinCntlr *cntlr, uint32_t index, enum PinPullType pullType); 56 int32_t (*GetPinPull)(struct PinCntlr *cntlr, uint32_t index, enum PinPullType *pullType); 57 int32_t (*SetPinStrength)(struct PinCntlr *cntlr, uint32_t index, uint32_t strength); 58 int32_t (*GetPinStrength)(struct PinCntlr *cntlr, uint32_t index, uint32_t *strength); 59 int32_t (*SetPinFunc)(struct PinCntlr *cntlr, uint32_t index, const char *funcName); 60 int32_t (*GetPinFunc)(struct PinCntlr *cntlr, uint32_t index, const char **funcName); 61}; 62``` 63 64**Table 1** Hook functions in PinCntlrMethod 65 66| Function | Input Parameter | Output Parameter | Return Value| Description| 67| ------------ | ------------------------------------------- | ------ | ---- | ---- | 68| SetPinPull | **cntlr**: structure pointer to the pin controller at the core layer.<br>**index**: pin index, which is a uint32_t variable. <br>**pullType**: pull type of the pin.| -|HDF_STATUS|Sets the pull type of a pin.| 69| GetPinPull | **cntlr**: structure pointer to the pin controller at the core layer.<br>**index**: pin index, which is a uint32_t variable. | **pullType**: pointer to the pull type obtained.| HDF_STATUS| Obtains the pull type of a pin.| 70| SetPinStrength | **cntlr**: structure pointer to the pin controller at the core layer.<br>**index**: pin index, which is a uint32_t variable. <br>**strength**: pull type to set, which is a uint32_t variable.| -| HDF_STATUS| Sets the pull strength of a pin.| 71| GetPinStrength | **cntlr**: structure pointer to the pin controller at the core layer.<br>**index**: pin index, which is a uint32_t variable. | **strength**: pointer to the pull strength obtained.| HDF_STATUS| Obtains the pull strength of a pin.| 72| SetPinFunc | **cntlr**: structure pointer to the pin controller at the core layer.<br>**index**: pin index, which is a uint32_t variable. <br>**funcName**: pointer to the pin function to set. It is a character constant.| -| HDF_STATUS| Sets the pin function.| 73| GetPinFunc | **cntlr**: structure pointer to the pin controller at the core layer.<br>**index**: pin index, which is a uint32_t variable. | **funcName**: double pointer to the PIN function obtained. It is a character constant.| HDF_STATUS| Obtains the pin function.| 74 75### How to Develop 76 77The pin module adaptation procedure is as follows: 78 79- Instantiate the driver entry. 80- Configure attribute files. 81- Instantiate the pin controller object. 82- Debug the driver. 83 84### Example 85 86The following uses the **//device_soc_hisilicon/common/platform/pin/pin_hi35xx.c** driver of the Hi3516D V300 development board as an example to describe the pin driver adaptation. 87 881. Instantiate the driver entry. 89 90 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. 91 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. 92 93 PIN driver entry example: 94 95 ```c 96 static struct HdfDriverEntry g_hi35xxPinDriverEntry = { 97 .moduleVersion = 1, 98 .Bind = Hi35xxPinBind, 99 .Init = Hi35xxPinInit, 100 .Release = Hi35xxPinRelease, 101 .moduleName = "hi35xx_pin_driver", // (Mandatory) The value must be the same as that of moduleName in the .hcs file. 102 }; 103 HDF_INIT(g_hi35xxPinDriverEntry); // Call HDF_INIT to register the driver entry with the HDF. 104 ``` 105 1062. Configure attribute files. 107 108 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 pin controllers as an example. If there are more pin controllers, add the deviceNode information to the **device_info.hcs** file for each controller. The device attribute values configured in **pin_config.hcs** are closely related to the driver implementation and default values or value ranges of the **PinCntlr** members at the core layer. 109 110 - **device_info.hcs** example 111 112 Add the deviceNode information to the **//vendor/hisilicon/hispark_taurus/hdf_config/device_info/device_info.hcs** file. 113 114 ```c 115 root { 116 device_info { 117 platform :: host { 118 hostName = "platform_host"; 119 priority = 50; 120 device_pin :: device { 121 device0 :: deviceNode { // Used to manage pins and release services in a unified manner. 122 policy = 2; // The value 2 means to publish services for both kernel- and user-mode processes. 123 priority = 8; // Driver startup priority. 124 permission = 0644; // Permission for the device node created. 125 moduleName = "HDF_PLATFORM_PIN_MANAGER"; 126 serviceName = "HDF_PLATFORM_PIN_MANAGER"; 127 } 128 device1:: deviceNode { // Configure an HDF device node for each pin controller. 129 policy = 0; 130 priority = 10; // Driver startup priority. 131 permission = 0644; // Permission for the device node created. 132 moduleName = "hi35xx_pin_driver"; // (mandatory) Driver name, which must be the same as moduleName in the driver entry. 133 deviceMatchAttr = "hisilicon_hi35xx_pin_0"; // (Mandatory) Controller private data, which must be the same as that of the controller in pin_config.hcs. 134 } 135 device2 :: deviceNode { 136 policy = 0; 137 priority = 10; 138 permission = 0644; 139 moduleName = "hi35xx_pin_driver"; 140 deviceMatchAttr = "hisilicon_hi35xx_pin_1"; 141 } 142 ... 143 } 144 } 145 } 146 } 147 ``` 148 149 - **pin_config.hcs** example: 150 151 Configure the device attributes in the **//device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/pin/pin_config.hcs** file. The parameters are as follows: 152 153 ```c 154 root { 155 platform { 156 pin_config_hi35xx { 157 template pin_controller { // (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. 158 number = 0; // (Mandatory) PIN controller number. 159 regStartBasePhy = 0; // (Mandatory) Start address of the physical base address of the register. 160 regSize = 0; // (Mandatory) Register size. 161 pinCount = 0; // (Mandatory) Number of pins. 162 match_attr = ""; 163 template pin_desc { 164 pinName = ""; // (Mandatory) Pin name. 165 init = 0; // (Mandatory) Default value of the register. 166 F0 = ""; // (Mandatory) Function 0. 167 F1 = ""; // Function 1. 168 F2 = ""; // Function 2. 169 F3 = ""; // Function 3. 170 F4 = ""; // Function 4. 171 F5 = ""; // Function 5. 172 } 173 } 174 controller_0 :: pin_controller { 175 number = 0; 176 regStartBasePhy = 0x10FF0000; 177 regSize = 0x48; 178 pinCount = 18; 179 match_attr = "hisilicon_hi35xx_pin_0"; 180 T1 :: pin_desc { 181 pinName = "T1"; 182 init = 0x0600; 183 F0 = "EMMC_CLK"; 184 F1 = "SFC_CLK"; 185 F2 = "SFC_BOOT_MODE"; 186 } 187 ... // Add each pin under the pin controller. 188 } 189 ... // Each pin controller corresponds to a controller node. If there are multiple pin controllers, add the controller nodes one by one. 190 } 191 } 192 } 193 ``` 194 195 After the **pin_config.hcs** file is configured, include the file in the **hdf.hcs** file. Otherwise, the configuration file cannot take effect. 196 197 ```c 198 #include "../../../../device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/pin/pin_config.hcs" // Relative path of the file. 199 ``` 200 2013. Instantiate the pin controller object. 202 203 Initialize the **PinCntlr** 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 **PinCntlrMethod** in **PinCntlr** (so that the underlying driver functions can be called). 204 205 - Define a custom structure. 206 207 To the driver, the custom structure holds parameters and data. The **DeviceResourceIface** method provided by the HDF reads the values in the **pin_config.hcs** file to initialize the members in the custom structure and passes important parameters to the object at the core layer. 208 209 Initialize **PinCntlr** in **Hi35xxPinCntlrInit**. 210 211 ```c 212 // Custom pin description structure. 213 struct Hi35xxPinDesc { 214 const char *pinName; // Pin name. 215 uint32_t init; // Initial value. 216 uint32_t index; // Pin index. 217 int32_t pullType; // Pull type of the pin. 218 int32_t strength; // Pull strength of the pin. 219 const char *func[HI35XX_PIN_FUNC_MAX]; // Array of pin function names. 220 }; 221 222 /* Custom structure. 223 struct Hi35xxPinCntlr { 224 struct PinCntlr cntlr // Core layer control object. 225 struct Hi35xxPinDesc *desc; // Pointer to the pin description structure. 226 volatile unsigned char *regBase; // Register base address used for address mapping. 227 uint16_t number; // Pin controller number. 228 uint32_t regStartBasePhy; // Start address of the register physical base address. 229 uint32_t regSize; // Register size. 230 uint32_t pinCount; // Number of pins. 231 }; 232 233 // PinCntlr is the controller structure at the core layer. The Init function assigns values to the members of PinCntlr. 234 struct PinCntlr { 235 struct IDeviceIoService service; // Driver service. 236 struct HdfDeviceObject *device; // Driver device object. 237 struct PinCntlrMethod *method; // Hook functions. 238 struct DListHead node; // Linked list node. 239 OsalSpinlock spin; // Spinlock. 240 uint16_t number; // Pin controller number. 241 uint16_t pinCount; // Number of pins. 242 struct PinDesc *pins; // Pin resources. 243 void *priv; // Private data. 244 }; 245 246 // Initialize the pin controller. 247 static int32_t Hi35xxPinCntlrInit(struct HdfDeviceObject *device, struct Hi35xxPinCntlr *hi35xx) 248 { 249 struct DeviceResourceIface *drsOps = NULL; 250 int32_t ret; 251 // Read the pin controller attributes from the .hcs file. 252 drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); 253 if (drsOps == NULL || drsOps->GetUint32 == NULL || drsOps->GetUint16 == NULL) { 254 HDF_LOGE("%s: invalid drs ops fail!", __func__); 255 return HDF_FAILURE; 256 } 257 ret = drsOps->GetUint16(device->property, "number", &hi35xx->number, 0); 258 if (ret != HDF_SUCCESS) { 259 HDF_LOGE("%s: read number failed", __func__); 260 return ret; 261 } 262 263 if (hi35xx->number > HI35XX_PIN_MAX_NUMBER) { 264 HDF_LOGE("%s: invalid number:%u", __func__, hi35xx->number); 265 return HDF_ERR_INVALID_PARAM; 266 } 267 ret = drsOps->GetUint32(device->property, "regStartBasePhy", &hi35xx->regStartBasePhy, 0); 268 if (ret != HDF_SUCCESS) { 269 HDF_LOGE("%s: read regStartBasePhy failed", __func__); 270 return ret; 271 } 272 ret = drsOps->GetUint32(device->property, "regSize", &hi35xx->regSize, 0); 273 if (ret != HDF_SUCCESS) { 274 HDF_LOGE("%s: read regSize failed", __func__); 275 return ret; 276 } 277 ret = drsOps->GetUint32(device->property, "pinCount", &hi35xx->pinCount, 0); 278 if (ret != HDF_SUCCESS) { 279 HDF_LOGE("%s: read pinCount failed", __func__); 280 return ret; 281 } 282 if (hi35xx->pinCount > PIN_MAX_CNT_PER_CNTLR) { 283 HDF_LOGE("%s: invalid number:%u", __func__, hi35xx->number); 284 return HDF_ERR_INVALID_PARAM; 285 } 286 // Assign the values read to the members of the pin controller to initialize the pin controller. 287 hi35xx->cntlr.pinCount = hi35xx->pinCount; 288 hi35xx->cntlr.number = hi35xx->number; 289 hi35xx->regBase = OsalIoRemap(hi35xx->regStartBasePhy, hi35xx->regSize); // Pin controller mapping. 290 if (hi35xx->regBase == NULL) { 291 HDF_LOGE("%s: remap Pin base failed", __func__); 292 return HDF_ERR_IO; 293 } 294 hi35xx->desc = (struct Hi35xxPinDesc *)OsalMemCalloc(sizeof(struct Hi35xxPinDesc) * hi35xx->pinCount); 295 if (hi35xx->desc == NULL) { 296 HDF_LOGE("%s: memcalloc hi35xx desc failed", __func__); 297 return HDF_ERR_MALLOC_FAIL; 298 } 299 hi35xx->cntlr.pins = (struct PinDesc *)OsalMemCalloc(sizeof(struct PinDesc) * hi35xx->pinCount); 300 if (hi35xx->desc == NULL) { 301 HDF_LOGE("%s: memcalloc hi35xx cntlr pins failed", __func__); 302 return HDF_ERR_MALLOC_FAIL; 303 } 304 return HDF_SUCCESS; 305 } 306 ``` 307 308 - Instantiate the **PinCntlrMethod** structure in **PinCntlr**. 309 310 ```c 311 static struct PinCntlrMethod g_method = { 312 .SetPinPull = Hi35xxPinSetPull, // Set the pull type. 313 .GetPinPull = Hi35xxPinGetPull, // Obtain the pull type. 314 .SetPinStrength = Hi35xxPinSetStrength, // Set the pull strength. 315 .GetPinStrength = Hi35xxPinGetStrength, // Obtain the pull strength. 316 .SetPinFunc = Hi35xxPinSetFunc, // Set the pin functions. 317 .GetPinFunc = Hi35xxPinGetFunc, // Obtain the pin functions. 318 }; 319 ``` 320 321 - Implement the **Init** function. 322 323 Input Parameter 324 325 **HdfDeviceObject**, a device object created by the HDF for each driver, holds device-related private data and service APIs. 326 327 Return value: 328 329 **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. 330 331 | **State** | **Description** | 332 | ---------------------- | -------------- | 333 | HDF_ERR_INVALID_OBJECT | Invalid controller object.| 334 | HDF_ERR_MALLOC_FAIL | Failed to allocate memory. | 335 | HDF_ERR_INVALID_PARAM | Invalid parameter. | 336 | HDF_ERR_IO | I/O error. | 337 | HDF_SUCCESS | Initialization successful. | 338 | HDF_FAILURE | Initialization failed. | 339 340 Function description: 341 342 Initializes the custom structure object and **PinCntlr** members, and calls **PinCntlrAdd()** to add the pin controller to the core layer. 343 344 ```c 345 static int32_t Hi35xxPinReadFunc(struct Hi35xxPinDesc *desc, const struct DeviceResourceNode *node, struct DeviceResourceIface *drsOps) 346 { 347 int32_t ret; 348 uint32_t funcNum = 0; 349 // Read the pin function names of the pin controller child nodes from the .hcs file. 350 ret = drsOps->GetString(node, "F0", &desc->func[funcNum], "NULL"); 351 if (ret != HDF_SUCCESS) { 352 HDF_LOGE("%s: read F0 failed", __func__); 353 return ret; 354 } 355 356 funcNum++; 357 ret = drsOps->GetString(node, "F1", &desc->func[funcNum], "NULL"); 358 if (ret != HDF_SUCCESS) { 359 HDF_LOGE("%s: read F1 failed", __func__); 360 return ret; 361 } 362 363 funcNum++; 364 ... 365 return HDF_SUCCESS; 366 } 367 368 static int32_t Hi35xxPinParsePinNode(const struct DeviceResourceNode *node, struct Hi35xxPinCntlr *hi35xx, int32_t index) 369 { 370 int32_t ret; 371 struct DeviceResourceIface *drsOps = NULL; 372 // Read the pin attributes of the pin controller child nodes from the .hcs file. 373 drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); 374 if (drsOps == NULL || drsOps->GetUint32 == NULL || drsOps->GetString == NULL) { 375 HDF_LOGE("%s: invalid drs ops fail!", __func__); 376 return HDF_FAILURE; 377 } 378 ret = drsOps->GetString(node, "pinName", &hi35xx->desc[index].pinName, "NULL"); 379 if (ret != HDF_SUCCESS) { 380 HDF_LOGE("%s: read pinName failed", __func__); 381 return ret; 382 } 383 ... 384 ret = Hi35xxPinReadFunc(&hi35xx->desc[index], node, drsOps); 385 if (ret != HDF_SUCCESS) { 386 HDF_LOGE("%s:Pin read Func failed", __func__); 387 return ret; 388 } 389 hi35xx->cntlr.pins[index].pinName = hi35xx->desc[index].pinName; 390 hi35xx->cntlr.pins[index].priv = (void *)node; 391 ... 392 return HDF_SUCCESS; 393 } 394 395 static int32_t Hi35xxPinInit(struct HdfDeviceObject *device) 396 { 397 ... 398 struct Hi35xxPinCntlr *hi35xx = NULL; 399 ... 400 ret = Hi35xxPinCntlrInit(device, hi35xx); // Initialize the pin controller. 401 ... 402 DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) { // Traverse each child node of the pin controller. 403 ret = Hi35xxPinParsePinNode(childNode, hi35xx, index); // Parse child nodes. 404 ... 405 } 406 407 hi35xx->cntlr.method = &g_method; // Attach the PinCntlrMethod instance. 408 ret = PinCntlrAdd(&hi35xx->cntlr); // Add the controller. 409 if (ret != HDF_SUCCESS) { 410 HDF_LOGE("%s: add Pin cntlr: failed", __func__); 411 ret = HDF_FAILURE; 412 } 413 return HDF_SUCCESS; 414 } 415 ``` 416 417 - Implement the **Release** function. 418 419 Input parameters: 420 421 **HdfDeviceObject**, a device object created by the HDF for each driver, holds device-related private data and service APIs. 422 423 Return value: 424 425 No value is returned. 426 427 Function description: 428 429 Releases the memory and deletes the controller. This function needs to assign 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. 430 431 ```c 432 static void Hi35xxPinRelease(struct HdfDeviceObject *device) 433 { 434 int32_t ret; 435 uint16_t number; 436 struct PinCntlr *cntlr = NULL; 437 struct Hi35xxPinCntlr *hi35xx = NULL; 438 struct DeviceResourceIface *drsOps = NULL; 439 440 if (device == NULL || device->property == NULL) { 441 HDF_LOGE("%s: device or property is null", __func__); 442 return; 443 } 444 // Read the pin controller number from the .hcs file. 445 drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); 446 if (drsOps == NULL || drsOps->GetUint32 == NULL || drsOps->GetString == NULL) { 447 HDF_LOGE("%s: invalid drs ops", __func__); 448 return; 449 } 450 ret = drsOps->GetUint16(device->property, "number", &number, 0); 451 if (ret != HDF_SUCCESS) { 452 HDF_LOGE("%s: read cntlr number failed", __func__); 453 return; 454 } 455 456 cntlr = PinCntlrGetByNumber(number); // Obtain the pin controller based on the controller number. 457 PinCntlrRemove(cntlr); 458 hi35xx = (struct Hi35xxPinCntlr *)cntlr; 459 if (hi35xx != NULL) { 460 if (hi35xx->regBase != NULL) { 461 OsalIoUnmap((void *)hi35xx->regBase); 462 } 463 OsalMemFree(hi35xx); 464 } 465 } 466 ``` 467 4684. Debug the driver. 469 470 (Optional) Verify basic functionalities of new drivers. For example, verify the information returned when the driver is loaded and whether data is successfully transmitted. 471