• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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