1e41f4b71Sopenharmony_ci# I2C
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci## Overview
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ci### Function
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ciThe Inter-Integrated Circuit (I2C) is a simple, bidirectional, and synchronous serial bus that uses merely two wires. It is widely used in short-distance communication due to simple connection and low cost.
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ci### Working Principles
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ciIn the Hardware Driver Foundation (HDF), the I2C module uses the unified service mode for API adaptation. In this mode, a device service is used as the I2C 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 illustrates the unified service mode.
12e41f4b71Sopenharmony_ci
13e41f4b71Sopenharmony_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.
14e41f4b71Sopenharmony_ci
15e41f4b71Sopenharmony_ciThe I2C module is divided into the following layers:
16e41f4b71Sopenharmony_ci
17e41f4b71Sopenharmony_ci- Interface layer: provides the capabilities of opening and closing a device and transferring data.
18e41f4b71Sopenharmony_ci- Core layer: binds services, initializes and releases the PlatformManager, and provides the capabilities of adding, deleting, and obtaining controllers.
19e41f4b71Sopenharmony_ci- Adaptation layer: implements hardware-related functions, such as controller initialization.
20e41f4b71Sopenharmony_ci
21e41f4b71Sopenharmony_ci**Figure 1** Unified service mode
22e41f4b71Sopenharmony_ci
23e41f4b71Sopenharmony_ci
24e41f4b71Sopenharmony_ci![image](figures/unified-service-mode.png "I2C Unified Service Mode")
25e41f4b71Sopenharmony_ci
26e41f4b71Sopenharmony_ci## Usage Guidelines
27e41f4b71Sopenharmony_ci
28e41f4b71Sopenharmony_ci### When to Use
29e41f4b71Sopenharmony_ci
30e41f4b71Sopenharmony_ciThe I2C is used in communication with the sensors, executors, and input/output devices that support the I2C protocol. Before using I2C devices with OpenHarmony, you need to adapt the I2C driver to OpenHarmony. The following describes how to do it.
31e41f4b71Sopenharmony_ci
32e41f4b71Sopenharmony_ci### Available APIs
33e41f4b71Sopenharmony_ci
34e41f4b71Sopenharmony_ciTo enable the upper layer to successfully operate the hardware by calling the I2C APIs, hook functions are defined in **//drivers/hdf_core/framework/support/platform/include/i2c/i2c_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.
35e41f4b71Sopenharmony_ci
36e41f4b71Sopenharmony_ci**I2cMethod** and **I2cLockMethod**:
37e41f4b71Sopenharmony_ci
38e41f4b71Sopenharmony_ci```c
39e41f4b71Sopenharmony_cistruct I2cMethod {
40e41f4b71Sopenharmony_ci    int32_t (*transfer)(struct I2cCntlr *cntlr, struct I2cMsg *msgs, int16_t count);
41e41f4b71Sopenharmony_ci};
42e41f4b71Sopenharmony_ci
43e41f4b71Sopenharmony_cistruct I2cLockMethod {// Structure for the lock operation.
44e41f4b71Sopenharmony_ci    int32_t (*lock)(struct I2cCntlr *cntlr);
45e41f4b71Sopenharmony_ci    void (*unlock)(struct I2cCntlr *cntlr);
46e41f4b71Sopenharmony_ci};
47e41f4b71Sopenharmony_ci```
48e41f4b71Sopenharmony_ci
49e41f4b71Sopenharmony_ciAt the adaptation layer, **I2cMethod** must be implemented, and **I2cLockMethod** can be implemented based on service requirements. The core layer provides the default **I2cLockMethod**, in which a mutex is used to protect the critical section.
50e41f4b71Sopenharmony_ci
51e41f4b71Sopenharmony_ci```c
52e41f4b71Sopenharmony_cistatic int32_t I2cCntlrLockDefault(struct I2cCntlr *cntlr)
53e41f4b71Sopenharmony_ci{
54e41f4b71Sopenharmony_ci    if (cntlr == NULL) {
55e41f4b71Sopenharmony_ci        return HDF_ERR_INVALID_OBJECT;
56e41f4b71Sopenharmony_ci    }
57e41f4b71Sopenharmony_ci    return OsalMutexLock(&cntlr->lock);
58e41f4b71Sopenharmony_ci}
59e41f4b71Sopenharmony_ci
60e41f4b71Sopenharmony_cistatic void I2cCntlrUnlockDefault(struct I2cCntlr *cntlr)
61e41f4b71Sopenharmony_ci{
62e41f4b71Sopenharmony_ci    if (cntlr == NULL) {
63e41f4b71Sopenharmony_ci        return;
64e41f4b71Sopenharmony_ci    }
65e41f4b71Sopenharmony_ci    (void)OsalMutexUnlock(&cntlr->lock);
66e41f4b71Sopenharmony_ci}
67e41f4b71Sopenharmony_ci
68e41f4b71Sopenharmony_cistatic const struct I2cLockMethod g_i2cLockOpsDefault = {
69e41f4b71Sopenharmony_ci    .lock = I2cCntlrLockDefault,
70e41f4b71Sopenharmony_ci    .unlock = I2cCntlrUnlockDefault,
71e41f4b71Sopenharmony_ci};
72e41f4b71Sopenharmony_ci```
73e41f4b71Sopenharmony_ci
74e41f4b71Sopenharmony_ciIf a mutex cannot be used (for example, an I2C API is called in the interrupt context, which does not allow sleep, but a mutex may cause sleep), you can use another type of lock to implement **I2cLockMethod**. The implemented **I2cLockMethod** will replace the default **I2cLockMethod**.
75e41f4b71Sopenharmony_ci
76e41f4b71Sopenharmony_ci  **Table 2** Function in **I2cMethod**
77e41f4b71Sopenharmony_ci
78e41f4b71Sopenharmony_ci| Function| Input Parameter| Output Parameter| Return Value| Description|
79e41f4b71Sopenharmony_ci| -------- | -------- | -------- | -------- | -------- |
80e41f4b71Sopenharmony_ci| transfer | **cntlr**: structure pointer to the I2C controller at the core layer.<br>**msgs**: structure pointer to the messages to transfer.<br>**count**: number of messages. The value is of the uint16_t type.| –| HDF_STATUS| Transfers user messages.|
81e41f4b71Sopenharmony_ci
82e41f4b71Sopenharmony_ci  **Table 2** Functions in **I2cLockMethod**
83e41f4b71Sopenharmony_ci
84e41f4b71Sopenharmony_ci| Function| Input Parameter| Output Parameter| Return Value| Description|
85e41f4b71Sopenharmony_ci| -------- | -------- | -------- | -------- | -------- |
86e41f4b71Sopenharmony_ci| lock | **cntlr**: structure pointer to the I2C controller at the core layer.| –| HDF_STATUS| Acquires the critical section lock.|
87e41f4b71Sopenharmony_ci| unlock | **cntlr**: structure pointer to the I2C controller at the core layer.| –| HDF_STATUS| Releases the critical section lock.|
88e41f4b71Sopenharmony_ci
89e41f4b71Sopenharmony_ci### How to Develop
90e41f4b71Sopenharmony_ci
91e41f4b71Sopenharmony_ciThe I2C module adaptation involves the following steps:
92e41f4b71Sopenharmony_ci
93e41f4b71Sopenharmony_ci1. Instantiate the driver entry.
94e41f4b71Sopenharmony_ci
95e41f4b71Sopenharmony_ci   - Instantiate the **HdfDriverEntry** structure.
96e41f4b71Sopenharmony_ci   - Call **HDF_INIT** to register the **HdfDriverEntry** instance with the HDF.
97e41f4b71Sopenharmony_ci
98e41f4b71Sopenharmony_ci2. Configure attribute files.
99e41f4b71Sopenharmony_ci
100e41f4b71Sopenharmony_ci   - Add the **deviceNode** information to the **device_info.hcs** file.
101e41f4b71Sopenharmony_ci   - (Optional) Add the **i2c_config.hcs** file.
102e41f4b71Sopenharmony_ci
103e41f4b71Sopenharmony_ci3. Instantiate the I2C controller object.
104e41f4b71Sopenharmony_ci
105e41f4b71Sopenharmony_ci   - Initialize **I2cCntlr**.
106e41f4b71Sopenharmony_ci   - Instantiate **I2cMethod** and **I2cLockMethod** in **I2cCntlr**.
107e41f4b71Sopenharmony_ci      > ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br>
108e41f4b71Sopenharmony_ci      > For details, see [Available APIs](#available-apis).
109e41f4b71Sopenharmony_ci
110e41f4b71Sopenharmony_ci4. Debug the driver.
111e41f4b71Sopenharmony_ci
112e41f4b71Sopenharmony_ci   (Optional) For new drivers, verify basic functions, for example, check whether data is successfully transferred and the information returned after the virtual file system (VFS) is mounted.
113e41f4b71Sopenharmony_ci
114e41f4b71Sopenharmony_ci### Example
115e41f4b71Sopenharmony_ci
116e41f4b71Sopenharmony_ciThe following uses the Hi3516D V300 driver **//device/soc/hisilicon/common/platform/i2c/i2c_hi35xx.c** as an example to describe how to perform the I2C driver adaptation.
117e41f4b71Sopenharmony_ci
118e41f4b71Sopenharmony_ci1. Instantiate the driver entry.
119e41f4b71Sopenharmony_ci
120e41f4b71Sopenharmony_ci   The driver entry must be a global variable of the **HdfDriverEntry** type (defined in **hdf_device_desc.h**), and the value of **moduleName** must be the same as that in **device_info.hcs**. In the HDF, the start address of each **HdfDriverEntry** object of all loaded drivers is collected to form a segment address space similar to an array for the upper layer to invoke.
121e41f4b71Sopenharmony_ci
122e41f4b71Sopenharmony_ci   Generally, the HDF calls **Bind()** and then **Init()** to load a driver. If **Init()** fails to be called, the HDF calls **Release()** to release driver resources and exit.
123e41f4b71Sopenharmony_ci
124e41f4b71Sopenharmony_ci   I2C driver entry example:
125e41f4b71Sopenharmony_ci
126e41f4b71Sopenharmony_ci   Multiple devices may connect to the I2C controller. In the HDF, a manager object needs to be created for this type of devices, and a manager service is published to handle external access requests uniformly. When a device needs to be started, the manager service locates the target device based on the specified parameters.
127e41f4b71Sopenharmony_ci
128e41f4b71Sopenharmony_ci   You do not need to implement the driver of the I2C manager, which is implemented by the core layer. However, the **I2cCntlrAdd** function of the core layer must be invoked in the **Init** function to implement the related features.
129e41f4b71Sopenharmony_ci
130e41f4b71Sopenharmony_ci    ```c
131e41f4b71Sopenharmony_ci    struct HdfDriverEntry g_i2cDriverEntry = {
132e41f4b71Sopenharmony_ci       .moduleVersion = 1,
133e41f4b71Sopenharmony_ci       .Init = Hi35xxI2cInit,
134e41f4b71Sopenharmony_ci       .Release = Hi35xxI2cRelease,
135e41f4b71Sopenharmony_ci       .moduleName = "hi35xx_i2c_driver",        // (Mandatory) The value must be the same as that in the config.hcs file.
136e41f4b71Sopenharmony_ci    };
137e41f4b71Sopenharmony_ci    HDF_INIT(g_i2cDriverEntry);                  // Call HDF_INIT to register the driver entry with the HDF.
138e41f4b71Sopenharmony_ci    
139e41f4b71Sopenharmony_ci    /* Driver entry of the manager service i2c_core.c at the core layer. */
140e41f4b71Sopenharmony_ci    struct HdfDriverEntry g_i2cManagerEntry = {
141e41f4b71Sopenharmony_ci       .moduleVersion = 1,
142e41f4b71Sopenharmony_ci       .Bind = I2cManagerBind,
143e41f4b71Sopenharmony_ci       .Init = I2cManagerInit,
144e41f4b71Sopenharmony_ci       .Release = I2cManagerRelease,
145e41f4b71Sopenharmony_ci       .moduleName = "HDF_PLATFORM_I2C_MANAGER", // The value must be the same as that of device0 in the device_info.hcs file.
146e41f4b71Sopenharmony_ci    };
147e41f4b71Sopenharmony_ci    HDF_INIT(g_i2cManagerEntry);
148e41f4b71Sopenharmony_ci    ```
149e41f4b71Sopenharmony_ci
150e41f4b71Sopenharmony_ci2. Add the **deviceNode** information to the **//vendor/hisilicon/hispark_taurus/hdf_config/device_info/device_info.hcs** file and configure the device attributes in **i2c_config.hcs**.
151e41f4b71Sopenharmony_ci
152e41f4b71Sopenharmony_ci   The **deviceNode** information is related to the driver entry registration. The device attribute values are closely related to the driver implementation and the default values or value ranges of the **I2cCntlr** members at the core layer.
153e41f4b71Sopenharmony_ci
154e41f4b71Sopenharmony_ci   In the unified service mode, the first device node in the **device_info.hcs** file must be the I2C manager. The table below lists the settings of its parameters.
155e41f4b71Sopenharmony_ci
156e41f4b71Sopenharmony_ci   **Table 3** Settings of the I2C manager
157e41f4b71Sopenharmony_ci   
158e41f4b71Sopenharmony_ci   | Parameter| Value|
159e41f4b71Sopenharmony_ci   | -------- | -------- |
160e41f4b71Sopenharmony_ci   | moduleName | **HDF_PLATFORM_I2C_MANAGER**|
161e41f4b71Sopenharmony_ci   | serviceName | **HDF_PLATFORM_I2C_MANAGER**|
162e41f4b71Sopenharmony_ci   | policy | **1** or **2**, depending on whether the service is published to the user mode.|
163e41f4b71Sopenharmony_ci   | deviceMatchAttr | This parameter is reserved.|
164e41f4b71Sopenharmony_ci
165e41f4b71Sopenharmony_ci    Configure I2C controller information from the second node. This node specifies a type of I2C controllers rather than a specific I2C controller. The controllers are distinguished by **busID** and **reg_pbase**, which can be seen in the **i2c_config.hcs** file.
166e41f4b71Sopenharmony_ci
167e41f4b71Sopenharmony_ci   - **device_info.hcs** example
168e41f4b71Sopenharmony_ci
169e41f4b71Sopenharmony_ci      ```c
170e41f4b71Sopenharmony_ci      root {
171e41f4b71Sopenharmony_ci          device_info {
172e41f4b71Sopenharmony_ci              match_attr = "hdf_manager";
173e41f4b71Sopenharmony_ci              device_i2c :: device {
174e41f4b71Sopenharmony_ci                  device0 :: deviceNode {
175e41f4b71Sopenharmony_ci                      policy = 2;
176e41f4b71Sopenharmony_ci                      priority = 50;
177e41f4b71Sopenharmony_ci                      permission = 0644;
178e41f4b71Sopenharmony_ci                      moduleName = "HDF_PLATFORM_I2C_MANAGER";
179e41f4b71Sopenharmony_ci                      serviceName = "HDF_PLATFORM_I2C_MANAGER";
180e41f4b71Sopenharmony_ci                      deviceMatchAttr = "hdf_platform_i2c_manager";
181e41f4b71Sopenharmony_ci                  }
182e41f4b71Sopenharmony_ci                  device1 :: deviceNode {
183e41f4b71Sopenharmony_ci                      policy = 0;                                // The value 0 indicates that no service is published.
184e41f4b71Sopenharmony_ci                      priority = 55;                             // Driver startup priority.
185e41f4b71Sopenharmony_ci                      permission = 0644;                         // Permission for the device node created.
186e41f4b71Sopenharmony_ci                      moduleName = "hi35xx_i2c_driver";          // (Mandatory) Driver name, which must be the same as moduleName in the driver entry.
187e41f4b71Sopenharmony_ci                      serviceName = "HI35XX_I2C_DRIVER";         // (Mandatory) Unique name of the service published by the driver.
188e41f4b71Sopenharmony_ci                       deviceMatchAttr = "hisilicon_hi35xx_i2c"; // (Mandatory) Private data of the controller. The value must be the same as the controller information in i2c_config.hcs.
189e41f4b71Sopenharmony_ci                                                                 //The specific controller information is in i2c_config.hcs.
190e41f4b71Sopenharmony_ci                  }
191e41f4b71Sopenharmony_ci              }
192e41f4b71Sopenharmony_ci          }
193e41f4b71Sopenharmony_ci      }
194e41f4b71Sopenharmony_ci      ```
195e41f4b71Sopenharmony_ci
196e41f4b71Sopenharmony_ci   - **i2c_config.hcs** example
197e41f4b71Sopenharmony_ci
198e41f4b71Sopenharmony_ci      ```c
199e41f4b71Sopenharmony_ci      root {
200e41f4b71Sopenharmony_ci          platform {
201e41f4b71Sopenharmony_ci              i2c_config {
202e41f4b71Sopenharmony_ci                  match_attr = "hisilicon_hi35xx_i2c";  // (Mandatory) The value must be the same as that of deviceMatchAttr in device_info.hcs.
203e41f4b71Sopenharmony_ci                  template i2c_controller {             // Template configuration. In the template, you can configure the common parameters shared by service nodes.
204e41f4b71Sopenharmony_ci                      bus = 0;                          // (Mandatory) I2C identifier.
205e41f4b71Sopenharmony_ci                      reg_pbase = 0x120b0000;           // (Mandatory) Physical base address.
206e41f4b71Sopenharmony_ci                      reg_size = 0xd1;                  // (Mandatory) Register bit width.
207e41f4b71Sopenharmony_ci                      irq = 0;                          // (Optional) Interrupt request (IRQ) number. The interrupt feature of the controller determines whether an IRQ number is required.
208e41f4b71Sopenharmony_ci                      freq = 400000;                    // (Optional) Frequency used in hardware controller initialization.
209e41f4b71Sopenharmony_ci                      clk = 50000000;                   // (Optional) Controller clock. The controller clock initialization process determines whether a controller clock is required.
210e41f4b71Sopenharmony_ci                  }
211e41f4b71Sopenharmony_ci                  controller_0x120b0000 :: i2c_controller {
212e41f4b71Sopenharmony_ci                      bus = 0;
213e41f4b71Sopenharmony_ci                  }
214e41f4b71Sopenharmony_ci                  controller_0x120b1000 :: i2c_controller {
215e41f4b71Sopenharmony_ci                      bus = 1;
216e41f4b71Sopenharmony_ci                      reg_pbase = 0x120b1000;
217e41f4b71Sopenharmony_ci                  }
218e41f4b71Sopenharmony_ci                  ...
219e41f4b71Sopenharmony_ci              }
220e41f4b71Sopenharmony_ci          }
221e41f4b71Sopenharmony_ci      }
222e41f4b71Sopenharmony_ci      ```
223e41f4b71Sopenharmony_ci
224e41f4b71Sopenharmony_ci      After the **i2c_config.hcs** file is configured, include the file in the **hdf.hcs** file. Otherwise, the configuration file cannot take effect.
225e41f4b71Sopenharmony_ci
226e41f4b71Sopenharmony_ci      For example, if the path of **i2c_config.hcs** is **device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/i2c/i2c_config.hcs**, add the following statement to **hdf.hcs** of the product:
227e41f4b71Sopenharmony_ci
228e41f4b71Sopenharmony_ci      ```c
229e41f4b71Sopenharmony_ci      #include "../../../../device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/i2c/i2c_config.hcs" // Relative path of the file.
230e41f4b71Sopenharmony_ci      ```
231e41f4b71Sopenharmony_ci
232e41f4b71Sopenharmony_ci3. Initialize the **I2cCntlr** 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 **I2cMethod** in **I2cCntlr** (so that the underlying driver functions can be called).
233e41f4b71Sopenharmony_ci
234e41f4b71Sopenharmony_ci   - Define a custom structure.
235e41f4b71Sopenharmony_ci
236e41f4b71Sopenharmony_ci      To the driver, the custom structure holds parameters and data. The **DeviceResourceIface** method provided by the HDF reads the values in the **i2c_config.hcs** file to initialize the members in the custom structure and passes important parameters, such as the device number and bus number, to the **I2cCntlr** object at the core layer.
237e41f4b71Sopenharmony_ci
238e41f4b71Sopenharmony_ci      ```c
239e41f4b71Sopenharmony_ci      /* Custom structure. */
240e41f4b71Sopenharmony_ci      struct Hi35xxI2cCntlr {
241e41f4b71Sopenharmony_ci          struct I2cCntlr cntlr;            // (Mandatory) Control object at the core layer. For details, see the following description.
242e41f4b71Sopenharmony_ci          OsalSpinlock spin;                // (Mandatory) Lock or unlock an I2C operation function.
243e41f4b71Sopenharmony_ci          volatile unsigned char *regBase;// (Mandatory) Register base address.
244e41f4b71Sopenharmony_ci          uint16_t regSize;                 // (Mandatory) Register bit width.
245e41f4b71Sopenharmony_ci          int16_t bus;                      // (Mandatory) The value can be read from the i2c_config.hcs file.
246e41f4b71Sopenharmony_ci          uint32_t clk;                     // (Optional) Set it as required.
247e41f4b71Sopenharmony_ci          uint32_t freq;                    // (Optional) Set it as required.
248e41f4b71Sopenharmony_ci          uint32_t irq;                     // (Optional) Set it as required.
249e41f4b71Sopenharmony_ci          uint32_t regBasePhy            // (Mandatory) Physical base address of the register.
250e41f4b71Sopenharmony_ci      };
251e41f4b71Sopenharmony_ci      
252e41f4b71Sopenharmony_ci      /* I2cCntlr is the core layer controller structure. The **Init()** function assigns values to the members of I2cCntlr. */
253e41f4b71Sopenharmony_ci      struct I2cCntlr {
254e41f4b71Sopenharmony_ci          struct OsalMutex lock;
255e41f4b71Sopenharmony_ci          void *owner;
256e41f4b71Sopenharmony_ci          int16_t busId;
257e41f4b71Sopenharmony_ci          void *priv;
258e41f4b71Sopenharmony_ci          const struct I2cMethod *ops;
259e41f4b71Sopenharmony_ci          const struct I2cLockMethod *lockOps;
260e41f4b71Sopenharmony_ci      };
261e41f4b71Sopenharmony_ci      ```
262e41f4b71Sopenharmony_ci
263e41f4b71Sopenharmony_ci   - Instantiate **I2cMethod** and **I2cLockMethod**. Other members are initialized by **Init**.
264e41f4b71Sopenharmony_ci
265e41f4b71Sopenharmony_ci      ```c
266e41f4b71Sopenharmony_ci      /* Example in i2c_hi35xx.c */
267e41f4b71Sopenharmony_ci      static const struct I2cMethod g_method = {
268e41f4b71Sopenharmony_ci          .transfer = Hi35xxI2cTransfer,
269e41f4b71Sopenharmony_ci      };
270e41f4b71Sopenharmony_ci      
271e41f4b71Sopenharmony_ci      static const struct I2cLockMethod g_lockOps = {
272e41f4b71Sopenharmony_ci          .lock = Hi35xxI2cLock,     // Acquires the lock.
273e41f4b71Sopenharmony_ci          .unlock = Hi35xxI2cUnlock, // Release the lock.
274e41f4b71Sopenharmony_ci      };
275e41f4b71Sopenharmony_ci      ```
276e41f4b71Sopenharmony_ci
277e41f4b71Sopenharmony_ci   - Implement the **Init** function.
278e41f4b71Sopenharmony_ci
279e41f4b71Sopenharmony_ci      Input parameter:
280e41f4b71Sopenharmony_ci
281e41f4b71Sopenharmony_ci      **HdfDeviceObject**, an interface parameter provided by the driver, contains the .hcs information.
282e41f4b71Sopenharmony_ci
283e41f4b71Sopenharmony_ci      Return value:
284e41f4b71Sopenharmony_ci
285e41f4b71Sopenharmony_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.
286e41f4b71Sopenharmony_ci
287e41f4b71Sopenharmony_ci      **Table 4** HDF_STATUS
288e41f4b71Sopenharmony_ci      
289e41f4b71Sopenharmony_ci      | Status| Description|
290e41f4b71Sopenharmony_ci      | -------- | -------- |
291e41f4b71Sopenharmony_ci      | HDF_ERR_INVALID_OBJECT | Invalid controller object.|
292e41f4b71Sopenharmony_ci      | HDF_ERR_INVALID_PARAM | Invalid parameter.|
293e41f4b71Sopenharmony_ci      | HDF_ERR_MALLOC_FAIL | Failed to allocate memory.|
294e41f4b71Sopenharmony_ci      | HDF_ERR_IO | I/O error.|
295e41f4b71Sopenharmony_ci      | HDF_SUCCESS | Transmission successful.|
296e41f4b71Sopenharmony_ci      | HDF_FAILURE | Transmission failed.|
297e41f4b71Sopenharmony_ci
298e41f4b71Sopenharmony_ci      Function description:
299e41f4b71Sopenharmony_ci
300e41f4b71Sopenharmony_ci      Initialize the custom structure object and **I2cCntlr**, call **I2cCntlrAdd()** at the core layer, and connect to the VFS (optional).
301e41f4b71Sopenharmony_ci
302e41f4b71Sopenharmony_ci      ```c
303e41f4b71Sopenharmony_ci      static int32_t Hi35xxI2cInit(struct HdfDeviceObject *device)
304e41f4b71Sopenharmony_ci      {
305e41f4b71Sopenharmony_ci          ...
306e41f4b71Sopenharmony_ci          /* Traverse and parse all nodes in i2c_config.hcs and call Hi35xxI2cParseAndInit to initialize the devices separately. */
307e41f4b71Sopenharmony_ci          DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
308e41f4b71Sopenharmony_ci              ret = Hi35xxI2cParseAndInit(device, childNode);// The function is defined as follows.
309e41f4b71Sopenharmony_ci          ...
310e41f4b71Sopenharmony_ci          }
311e41f4b71Sopenharmony_ci          ...
312e41f4b71Sopenharmony_ci      }
313e41f4b71Sopenharmony_ci      
314e41f4b71Sopenharmony_ci      static int32_t Hi35xxI2cParseAndInit(struct HdfDeviceObject *device, const struct DeviceResourceNode *node)
315e41f4b71Sopenharmony_ci      {
316e41f4b71Sopenharmony_ci          struct Hi35xxI2cCntlr *hi35xx = NULL;
317e41f4b71Sopenharmony_ci          ... // Check whether the input parameter is null.
318e41f4b71Sopenharmony_ci          hi35xx = (struct Hi35xxI2cCntlr *)OsalMemCalloc(sizeof(*hi35xx));   // Allocate memory.
319e41f4b71Sopenharmony_ci          ... // Verify the return value.
320e41f4b71Sopenharmony_ci          hi35xx->regBase = OsalIoRemap(hi35xx->regBasePhy, hi35xx->regSize); // Address mapping.
321e41f4b71Sopenharmony_ci          ... // Verify the return value.
322e41f4b71Sopenharmony_ci          Hi35xxI2cCntlrInit(hi35xx);         // (Mandatory) Initialize the I2C device.
323e41f4b71Sopenharmony_ci          
324e41f4b71Sopenharmony_ci          hi35xx->cntlr.priv = (void *)node;  // (Mandatory) Device attributes.
325e41f4b71Sopenharmony_ci          hi35xx->cntlr.busId = hi35xx->bus; // (Mandatory) Initialize busId in I2cCntlr.
326e41f4b71Sopenharmony_ci           hi35xx->cntlr.ops = &g_method;      // (Mandatory) Hook the I2cMethod instance.
327e41f4b71Sopenharmony_ci           hi35xx->cntlr.lockOps = &g_lockOps; // (Mandatory) Hook the I2cLockMethod instance.
328e41f4b71Sopenharmony_ci          (void)OsalSpinInit(&hi35xx->spin); // (Mandatory) Initialize the lock.
329e41f4b71Sopenharmony_ci          ret = I2cCntlrAdd(&hi35xx->cntlr); // (Mandatory) Call this function to add the controller object to the core layer of the platform. The driver can access the core layer of the platform only after a success signal is returned.
330e41f4b71Sopenharmony_ci          ...
331e41f4b71Sopenharmony_ci      #ifdef USER_VFS_SUPPORT
332e41f4b71Sopenharmony_ci          (void)I2cAddVfsById(hi35xx->cntlr.busId);// (Optional) Mount the user-level VFS if required.
333e41f4b71Sopenharmony_ci      #endif
334e41f4b71Sopenharmony_ci          return HDF_SUCCESS;
335e41f4b71Sopenharmony_ci      __ERR__:                                      // If the operation fails, roll back the operations that have been performed in the function (such as unmapping I/O and releasing memory) and return an error code.
336e41f4b71Sopenharmony_ci          if (hi35xx != NULL) {
337e41f4b71Sopenharmony_ci              if (hi35xx->regBase != NULL) {
338e41f4b71Sopenharmony_ci                  OsalIoUnmap((void *)hi35xx->regBase);
339e41f4b71Sopenharmony_ci                  hi35xx->regBase = NULL;
340e41f4b71Sopenharmony_ci              }
341e41f4b71Sopenharmony_ci              OsalMemFree(hi35xx);
342e41f4b71Sopenharmony_ci              hi35xx = NULL;
343e41f4b71Sopenharmony_ci          }
344e41f4b71Sopenharmony_ci          return ret;
345e41f4b71Sopenharmony_ci      }
346e41f4b71Sopenharmony_ci      ```
347e41f4b71Sopenharmony_ci
348e41f4b71Sopenharmony_ci   - Implement the **Release** function.
349e41f4b71Sopenharmony_ci
350e41f4b71Sopenharmony_ci      Input parameter:
351e41f4b71Sopenharmony_ci
352e41f4b71Sopenharmony_ci      **HdfDeviceObject**, an interface parameter provided by the driver, contains the .hcs information.
353e41f4b71Sopenharmony_ci
354e41f4b71Sopenharmony_ci      Return value:
355e41f4b71Sopenharmony_ci
356e41f4b71Sopenharmony_ci      No value is returned.
357e41f4b71Sopenharmony_ci
358e41f4b71Sopenharmony_ci      Function description:
359e41f4b71Sopenharmony_ci
360e41f4b71Sopenharmony_ci      Releases the memory and deletes the controller. This function assigns values to the **Release** function in the driver entry structure. If the HDF fails to call the **Init** function to initialize the driver, the **Release** function can be called to release driver resources.
361e41f4b71Sopenharmony_ci
362e41f4b71Sopenharmony_ci      ```c
363e41f4b71Sopenharmony_ci      static void Hi35xxI2cRelease(struct HdfDeviceObject *device)
364e41f4b71Sopenharmony_ci      {
365e41f4b71Sopenharmony_ci          ...
366e41f4b71Sopenharmony_ci          /* Release each node separately, like Hi35xxI2cInit. */
367e41f4b71Sopenharmony_ci          DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
368e41f4b71Sopenharmony_ci              Hi35xxI2cRemoveByNode(childNode);// The function is defined as follows:
369e41f4b71Sopenharmony_ci          }
370e41f4b71Sopenharmony_ci      }
371e41f4b71Sopenharmony_ci      
372e41f4b71Sopenharmony_ci      static void Hi35xxI2cRemoveByNode(const struct DeviceResourceNode *node)
373e41f4b71Sopenharmony_ci      {
374e41f4b71Sopenharmony_ci          ... 
375e41f4b71Sopenharmony_ci          /* (Mandatory) Call I2cCntlrGet() to obtain the pointer to the I2cCntlr object based on the bus number of the device, and call I2cCntlrRemove() to remove the I2cCntlr object from the core layer of the platform. */
376e41f4b71Sopenharmony_ci          cntlr = I2cCntlrGet(bus);
377e41f4b71Sopenharmony_ci          if (cntlr != NULL && cntlr->priv == node) {
378e41f4b71Sopenharmony_ci              ...
379e41f4b71Sopenharmony_ci              I2cCntlrRemove(cntlr); 
380e41f4b71Sopenharmony_ci              /* (Mandatory) Unmap the register address and release the lock and memory. */
381e41f4b71Sopenharmony_ci              hi35xx = (struct Hi35xxI2cCntlr *)cntlr; 
382e41f4b71Sopenharmony_ci              OsalIoUnmap((void *)hi35xx->regBase);
383e41f4b71Sopenharmony_ci              (void)OsalSpinDestroy(&hi35xx->spin);
384e41f4b71Sopenharmony_ci              OsalMemFree(hi35xx);
385e41f4b71Sopenharmony_ci          }
386e41f4b71Sopenharmony_ci          return;
387e41f4b71Sopenharmony_ci      }
388e41f4b71Sopenharmony_ci      ```
389