1e41f4b71Sopenharmony_ci# I3C 
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci## Introduction
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ci### Function
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ciImproved Inter-Integrated Circuit (I3C) is a simple and cost-efficient two-wire bidirectional synchronous serial bus protocol developed by the Mobile Industry Processor Interface (MIPI) Alliance.
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ciI3C is a two-wire bidirectional serial bus, optimized for multiple sensor target devices and controlled by only one I3C controller at a time.  It is backward compatible with Inter-Integrated circuit (I2C) target devices, but features higher speed and lower power consumption and supports in-band interrupts (IBIs), hot-joins of target devices, and controller switchover. 
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ciThe IBIs over the serial bus eliminates the need for an extra interrupt line to complete interrupts in I2C. I2C devices, I3C target devices, and the I3C secondary controller can co-exist on the same I3C bus.
12e41f4b71Sopenharmony_ci
13e41f4b71Sopenharmony_ci### Basic Concepts
14e41f4b71Sopenharmony_ci
15e41f4b71Sopenharmony_ci- IBI
16e41f4b71Sopenharmony_ci
17e41f4b71Sopenharmony_ci  When there is no start signal on the serial clock (SCL) line, the I3C target device can pull down the serial data (SDA) line to make the controller send an SCL start signal, which initiates an IBI request. If multiple target devices send interrupt requests at the same time, the I3C controller arbitrates the requests based on the target device addresses. The request with a lower address is responded first.
18e41f4b71Sopenharmony_ci
19e41f4b71Sopenharmony_ci- Dynamic Address Assignment (DAA)
20e41f4b71Sopenharmony_ci
21e41f4b71Sopenharmony_ci  The I3C controller can dynamically allocate addresses to target devices to avoid address conflicts. Before addresses are allocated, each I3C device connected to an I3C bus must be uniquely identified in either of the following ways:
22e41f4b71Sopenharmony_ci
23e41f4b71Sopenharmony_ci  - The device has an I2C compliant static address that can be used by the host.
24e41f4b71Sopenharmony_ci  - The device has a 48-bit temporary ID. 
25e41f4b71Sopenharmony_ci
26e41f4b71Sopenharmony_ci  The host must use a 48-bit temporary ID unless the device has a static IP address. 
27e41f4b71Sopenharmony_ci
28e41f4b71Sopenharmony_ci- Common Command Code (CCC)
29e41f4b71Sopenharmony_ci
30e41f4b71Sopenharmony_ci  All I3C devices support CCC. The CCC can be sent to an I3C target device or all I3C target devices.
31e41f4b71Sopenharmony_ci
32e41f4b71Sopenharmony_ci- Bus Characteristic Register (BCR)
33e41f4b71Sopenharmony_ci
34e41f4b71Sopenharmony_ci  Each I3C device connected to an I3C bus has a read-only BCR, which describes the I3C compliant device's role and capabilities for use in DAA and CCC.
35e41f4b71Sopenharmony_ci
36e41f4b71Sopenharmony_ci- Device Characteristic Register (DCR)
37e41f4b71Sopenharmony_ci
38e41f4b71Sopenharmony_ci  Each I3C device connected to an I3C bus has a read-only DCR, which describes the I3C compliant device type (such as accelerometers, gyroscope, and others) for use in DAA and DCC.
39e41f4b71Sopenharmony_ci
40e41f4b71Sopenharmony_ci
41e41f4b71Sopenharmony_ci### Working Principles
42e41f4b71Sopenharmony_ci
43e41f4b71Sopenharmony_ciIn the Hardware Driver Foundation (HDF), the I3C module uses the unified service mode for API adaptation. In this mode, a service is used as the I3C manager to handle external access requests in a unified manner. The unified service mode applies when the system has multiple device objects of the same type, for example, when there are more than 10 I3C controllers. 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 illustrtes the unified service mode.
44e41f4b71Sopenharmony_ci
45e41f4b71Sopenharmony_ciThe I3C module is divided into the following layers:
46e41f4b71Sopenharmony_ci
47e41f4b71Sopenharmony_ci- Interface layer: provides the capabilities of opening a device, writing data, and closing a device.
48e41f4b71Sopenharmony_ci- Core layer: binds services, initializes and releases the PlatformManager, and provides the capabilities of adding, deleting, and obtaining controllers. The core layer also provides capabilities of adding, deleting, and obtaining the devices connected to the I3C bus and interrupt callbacks.
49e41f4b71Sopenharmony_ci- Adaptation layer: implements hardware-related functions, such as controller initialization.
50e41f4b71Sopenharmony_ci
51e41f4b71Sopenharmony_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.
52e41f4b71Sopenharmony_ci
53e41f4b71Sopenharmony_ci **Figure 1** Unified service mode 
54e41f4b71Sopenharmony_ci
55e41f4b71Sopenharmony_ci![image1](figures/unified-service-mode.png)
56e41f4b71Sopenharmony_ci
57e41f4b71Sopenharmony_ci### Constraints
58e41f4b71Sopenharmony_ci
59e41f4b71Sopenharmony_ciThe I3C module supports only the kernel (LiteOS-A) for mini and small systems.
60e41f4b71Sopenharmony_ci
61e41f4b71Sopenharmony_ci## Development Guidelines
62e41f4b71Sopenharmony_ci
63e41f4b71Sopenharmony_ci### When to Use
64e41f4b71Sopenharmony_ci
65e41f4b71Sopenharmony_ciI3C can connect to one or more I3C or I2C target devices. It is used to:
66e41f4b71Sopenharmony_ci
67e41f4b71Sopenharmony_ci- Communicate with sensors, such as gyroscopes, barometers, and image sensors that support the I3C protocol.
68e41f4b71Sopenharmony_ci- Communicate with devices with other ports (such as UART serial ports) through software or hardware protocols.
69e41f4b71Sopenharmony_ci
70e41f4b71Sopenharmony_ciBefore using I3C devices with OpenHarmony, you need to adapt the I3C driver to OpenHarmony. The following describes how to do it.
71e41f4b71Sopenharmony_ci
72e41f4b71Sopenharmony_ci### Available APIs
73e41f4b71Sopenharmony_ci
74e41f4b71Sopenharmony_ciTo enable the upper layer to successfully operate the hardware by calling the I3C APIs, hook functions are defined in **//drivers/hdf_core/framework/support/platform/include/i3c/i3c_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.
75e41f4b71Sopenharmony_ci
76e41f4b71Sopenharmony_ci**I3cMethod**:
77e41f4b71Sopenharmony_ci```c
78e41f4b71Sopenharmony_cistruct I3cMethod {
79e41f4b71Sopenharmony_ci    int32_t (*sendCccCmd)(struct I3cCntlr *cntlr, struct I3cCccCmd *ccc);
80e41f4b71Sopenharmony_ci    int32_t (*transfer)(struct I3cCntlr *cntlr, struct I3cMsg *msgs, int16_t count);
81e41f4b71Sopenharmony_ci    int32_t (*i2cTransfer)(struct I3cCntlr *cntlr, struct I3cMsg *msgs, int16_t count);
82e41f4b71Sopenharmony_ci    int32_t (*setConfig)(struct I3cCntlr *cntlr, struct I3cConfig *config);
83e41f4b71Sopenharmony_ci    int32_t (*getConfig)(struct I3cCntlr *cntlr, struct I3cConfig *config);
84e41f4b71Sopenharmony_ci    int32_t (*requestIbi)(struct I3cDevice *dev);
85e41f4b71Sopenharmony_ci    void (*freeIbi)(struct I3cDevice *dev);
86e41f4b71Sopenharmony_ci};
87e41f4b71Sopenharmony_ci```
88e41f4b71Sopenharmony_ci
89e41f4b71Sopenharmony_ci**Table 1** Hook functions in **I3cMethod**
90e41f4b71Sopenharmony_ci|Function|Input Parameter|Output Parameter|Return Value|Description|
91e41f4b71Sopenharmony_ci|-|-|-|-|-|
92e41f4b71Sopenharmony_ci|sendCccCmd| **cntlr**: structure pointer to an I3C controller at the core layer.<br>**ccc**: pointer to the CCC to send.| **ccc**: pointer to the CCC sent.| HDF_STATUS|Sends a CCC.|
93e41f4b71Sopenharmony_ci|Transfer  | **cntlr**: structure pointer to an I3C controller at the core layer.<br>**msgs**: structure pointer to the messages to transfer.<br>**count**: number of messages to transfer, which is of the int16_t type.| **msgs**: structure pointer to the messages transferred.| HDF_STATUS| Transfers user messages in I3C mode.|
94e41f4b71Sopenharmony_ci|i2cTransfer | **cntlr**: structure pointer to an I3C controller at the core layer.<br>**msgs**: structure pointer to the messages to transfer.<br>**count**: number of messages to transfer, which is of the int16_t type.| **msgs**: structure pointer to the messages transferred.| HDF_STATUS| Transfers user messages in I2C mode.|
95e41f4b71Sopenharmony_ci|setConfig| **cntlr**: structure pointer to an I3C controller at the core layer.<br>**config**: pointer to the controller configuration.| –| HDF_STATUS| Sets an I3C controller.|
96e41f4b71Sopenharmony_ci|getConfig| **cntlr**: structure pointer to an I3C controller at the core layer.| **config**: pointer to the controller configuration.| HDF_STATUS| Obtains the I3C controller configuration.|
97e41f4b71Sopenharmony_ci|requestIbi| **device**: structure pointer to an I3C device at the core layer.| –| HDF_STATUS| Requests an IBI for an I3C device.|
98e41f4b71Sopenharmony_ci|freeIbi| **device**: structure pointer to an I3C device at the core layer.| –| HDF_STATUS| Releases the IBI for an I3C device.|
99e41f4b71Sopenharmony_ci
100e41f4b71Sopenharmony_ci### How to Develop
101e41f4b71Sopenharmony_ci
102e41f4b71Sopenharmony_ciThe I3C module adaptation involves the following steps:
103e41f4b71Sopenharmony_ci
104e41f4b71Sopenharmony_ci1. Instantiate the driver entry.
105e41f4b71Sopenharmony_ci
106e41f4b71Sopenharmony_ci   - Instantiate the **HdfDriverEntry** structure.
107e41f4b71Sopenharmony_ci   - Call **HDF_INIT** to register the **HdfDriverEntry** instance with the HDF.
108e41f4b71Sopenharmony_ci
109e41f4b71Sopenharmony_ci2. Configure attribute files.
110e41f4b71Sopenharmony_ci
111e41f4b71Sopenharmony_ci   - Add the **deviceNode** information to the **device_info.hcs** file.
112e41f4b71Sopenharmony_ci   - (Optional) Add the **i3c_config.hcs** file.
113e41f4b71Sopenharmony_ci
114e41f4b71Sopenharmony_ci3. Instantiate the I3C controller object.
115e41f4b71Sopenharmony_ci
116e41f4b71Sopenharmony_ci   - Initialize **I3cCntlr**.
117e41f4b71Sopenharmony_ci   - Instantiate **I3cMethod** in **I3cCntlr**. For details, see the description of **I3cMethod** below.
118e41f4b71Sopenharmony_ci
119e41f4b71Sopenharmony_ci4. Register an interrupt handler.
120e41f4b71Sopenharmony_ci
121e41f4b71Sopenharmony_ci   Registers an interrupt handler for the controller to implement the device hot-join and IBI features.
122e41f4b71Sopenharmony_ci
123e41f4b71Sopenharmony_ci### Example
124e41f4b71Sopenharmony_ci
125e41f4b71Sopenharmony_ci1. Instantiate the driver entry.
126e41f4b71Sopenharmony_ci
127e41f4b71Sopenharmony_ci    The driver entry must be a global variable of the **HdfDriverEntry** type (defined in **//drivers/hdf_core/framework/include/core/hdf_device_desc.h**), and the module name 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.
128e41f4b71Sopenharmony_ci
129e41f4b71Sopenharmony_ci    Generally, the HDF calls the **Bind** function and then the **Init** function to load a driver. If **Init** fails to be called, the HDF calls **Release** to release driver resources and exit.
130e41f4b71Sopenharmony_ci
131e41f4b71Sopenharmony_ci    I3C driver entry example:
132e41f4b71Sopenharmony_ci
133e41f4b71Sopenharmony_ci    > ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
134e41f4b71Sopenharmony_ci    >
135e41f4b71Sopenharmony_ci    > Multiple devices may connect to the I3C 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.
136e41f4b71Sopenharmony_ci    >
137e41f4b71Sopenharmony_ci    > You do not need to implement the driver of the I3C manager, which is implemented by the core layer. However, the **I3cCntlrAdd** function of the core layer must be invoked in the **Init** function to implement the related features.
138e41f4b71Sopenharmony_ci
139e41f4b71Sopenharmony_ci    ```c
140e41f4b71Sopenharmony_ci    static struct HdfDriverEntry g_virtualI3cDriverEntry = {
141e41f4b71Sopenharmony_ci        .moduleVersion = 1,
142e41f4b71Sopenharmony_ci        .Init = VirtualI3cInit,
143e41f4b71Sopenharmony_ci        .Release = VirtualI3cRelease,
144e41f4b71Sopenharmony_ci        .moduleName = "virtual_i3c_driver",      // (Mandatory) The value must be the same as that in the .hcs file.
145e41f4b71Sopenharmony_ci    };
146e41f4b71Sopenharmony_ci    HDF_INIT(g_virtualI3cDriverEntry);           // Call HDF_INIT to register the driver entry with the HDF.
147e41f4b71Sopenharmony_ci    
148e41f4b71Sopenharmony_ci    /* Driver entry of the i3c_core.c manager service at the core layer. */
149e41f4b71Sopenharmony_ci    struct HdfDriverEntry g_i3cManagerEntry = {
150e41f4b71Sopenharmony_ci        .moduleVersion = 1,
151e41f4b71Sopenharmony_ci        .Init     = I3cManagerInit,
152e41f4b71Sopenharmony_ci        .Release  = I3cManagerRelease,
153e41f4b71Sopenharmony_ci        .moduleName = "HDF_PLATFORM_I3C_MANAGER", // The value must be the same as that of device0 in the device_info.hcs file.
154e41f4b71Sopenharmony_ci    };
155e41f4b71Sopenharmony_ci    HDF_INIT(g_i3cManagerEntry);
156e41f4b71Sopenharmony_ci    ```
157e41f4b71Sopenharmony_ci
158e41f4b71Sopenharmony_ci2. Configure attribute files.
159e41f4b71Sopenharmony_ci
160e41f4b71Sopenharmony_ci    Add the **deviceNode** information to the **//vendor/hisilicon/hispark_taurus/hdf_config/device_info/device_info.hcs** file and configure the device attributes in **i3c_config.hcs**.
161e41f4b71Sopenharmony_ci
162e41f4b71Sopenharmony_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 **I3cCntlr** members at the core layer.
163e41f4b71Sopenharmony_ci
164e41f4b71Sopenharmony_ci    In the unified service mode, the first device node in the **device_info.hcs** file must be the I3C manager. The I3C manager parameters must be set as follows:
165e41f4b71Sopenharmony_ci
166e41f4b71Sopenharmony_ci    |Parameter|Value|
167e41f4b71Sopenharmony_ci    |-|-|
168e41f4b71Sopenharmony_ci    |moduleName |HDF_PLATFORM_I3C_MANAGER|
169e41f4b71Sopenharmony_ci    |serviceName|Reserved.|
170e41f4b71Sopenharmony_ci    |policy|0|
171e41f4b71Sopenharmony_ci    |cntlrMatchAttr| Reserved.|
172e41f4b71Sopenharmony_ci
173e41f4b71Sopenharmony_ci    Configure I3C controller information from the second node. This node specifies a type of I3C controllers rather than a specific I3C controller. In this example, there is only one I3C controller. If there are multiple I3C controllers, add the **deviceNode** information to the **device_info.hcs** file and add the corresponding device attributes to the **i3c_config** file for each controller.
174e41f4b71Sopenharmony_ci
175e41f4b71Sopenharmony_ci    - **device_info.hcs** example
176e41f4b71Sopenharmony_ci
177e41f4b71Sopenharmony_ci        ```c
178e41f4b71Sopenharmony_ci        root {
179e41f4b71Sopenharmony_ci            device_i3c :: device {
180e41f4b71Sopenharmony_ci                device0 :: deviceNode {
181e41f4b71Sopenharmony_ci                    policy = 0;
182e41f4b71Sopenharmony_ci                    priority = 52;
183e41f4b71Sopenharmony_ci                    permission = 0644;
184e41f4b71Sopenharmony_ci                    serviceName = "HDF_PLATFORM_I3C_MANAGER";
185e41f4b71Sopenharmony_ci                    moduleName = "HDF_PLATFORM_I3C_MANAGER";
186e41f4b71Sopenharmony_ci                }
187e41f4b71Sopenharmony_ci            }
188e41f4b71Sopenharmony_ci            i3c_virtual :: deviceNode {
189e41f4b71Sopenharmony_ci                policy = 0;                               // The value 0 indicates that no service is published.
190e41f4b71Sopenharmony_ci                priority = 56;                            // Driver startup priority.
191e41f4b71Sopenharmony_ci                permission = 0644;                        // Permission for the device node created.
192e41f4b71Sopenharmony_ci                moduleName = "virtual_i3c_driver";        // (Mandatory) Driver name, which must be the same as moduleName in the driver entry.
193e41f4b71Sopenharmony_ci                serviceName = "VIRTUAL_I3C_DRIVER";       // (Mandatory) Unique name of the service published by the driver.
194e41f4b71Sopenharmony_ci                deviceMatchAttr = "virtual_i3c"; // (Mandatory) Controller private data, which must be same as that of the controller in i3c_config.hcs.
195e41f4b71Sopenharmony_ci            }                                             // The specific controller information is in i3c_config.hcs.
196e41f4b71Sopenharmony_ci        }
197e41f4b71Sopenharmony_ci        ```
198e41f4b71Sopenharmony_ci
199e41f4b71Sopenharmony_ci    - i3c_config.hcs example
200e41f4b71Sopenharmony_ci
201e41f4b71Sopenharmony_ci        ```c
202e41f4b71Sopenharmony_ci        root {
203e41f4b71Sopenharmony_ci            platform {
204e41f4b71Sopenharmony_ci                i3c_config {
205e41f4b71Sopenharmony_ci                    match_attr = "virtual_i3c";  // (Mandatory) The value must be the same as that of deviceMatchAttr in device_info.hcs.
206e41f4b71Sopenharmony_ci                    template i3c_controller {    // Template configuration. In the template, you can configure the common parameters shared by device nodes.
207e41f4b71Sopenharmony_ci                        busId = 0;               // (Mandatory) I3C bus number.
208e41f4b71Sopenharmony_ci                        busMode = 0x0;           // Bus mode, which can be 0x0 (pure), 0x1 (mixed-fast), 0x2 (mixed-limited), or 0x3 (mixed-slow).
209e41f4b71Sopenharmony_ci                        regBasePhy = 0x120b0000; // (Mandatory) Physical base address.
210e41f4b71Sopenharmony_ci                        regSize = 0xd1;          // (Mandatory) Register bit width.
211e41f4b71Sopenharmony_ci                        IrqNum = 20;             // (Mandatory) Interrupt request (IRQ) number.
212e41f4b71Sopenharmony_ci                        i3cMaxRate = 12900000;   // (Optional) Maximum clock rate in I3C mode.
213e41f4b71Sopenharmony_ci                        i3cRate = 12500000;      // (Optional) Clock rate in I3C mode.
214e41f4b71Sopenharmony_ci                        i2cFmRate = 1000000;     // (Optional) Clock rate in I2C FM mode.
215e41f4b71Sopenharmony_ci                        i2cFmPlusRate = 400000;  // (Optional) Clock rate in I2C FM+ mode.
216e41f4b71Sopenharmony_ci                    }
217e41f4b71Sopenharmony_ci                    controller_0 :: i3c_controller {
218e41f4b71Sopenharmony_ci                        busId = 18;
219e41f4b71Sopenharmony_ci                        IrqNum = 20;
220e41f4b71Sopenharmony_ci                    }
221e41f4b71Sopenharmony_ci                }
222e41f4b71Sopenharmony_ci            }
223e41f4b71Sopenharmony_ci        }
224e41f4b71Sopenharmony_ci        ```
225e41f4b71Sopenharmony_ci        After the **i3c_config.hcs** file is configured, include the file in the **hdf.hcs** file. Otherwise, the configuration file cannot take effect.
226e41f4b71Sopenharmony_ci
227e41f4b71Sopenharmony_ci         For example, if the path of **i3c_config.hcs** is **device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/i3c/i3c_config.hcs**, add the following statement to **hdf.hcs** of the product:
228e41f4b71Sopenharmony_ci
229e41f4b71Sopenharmony_ci        ```c
230e41f4b71Sopenharmony_ci         #include "../../../../device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/i3c/i3c_config.hcs" // Relative path of the file.
231e41f4b71Sopenharmony_ci        ```
232e41f4b71Sopenharmony_ci
233e41f4b71Sopenharmony_ci           
234e41f4b71Sopenharmony_ci
235e41f4b71Sopenharmony_ci3. Instantiate the I3C controller object.
236e41f4b71Sopenharmony_ci
237e41f4b71Sopenharmony_ci    Initialize the **I3cCntlr** 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 I3cMethod in I3cCntlr (so that the underlying driver functions can be called).
238e41f4b71Sopenharmony_ci
239e41f4b71Sopenharmony_ci    Instantiate **I3cMethod** in **I3cCntlr**.<br>The **I3cLockMethod** hook function structure is not implemented in this example. To instantiate the structure, refer to the I2C driver development. Other members are initialized in **Init()**.
240e41f4b71Sopenharmony_ci
241e41f4b71Sopenharmony_ci    - Define a custom structure.
242e41f4b71Sopenharmony_ci
243e41f4b71Sopenharmony_ci      > ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
244e41f4b71Sopenharmony_ci      >
245e41f4b71Sopenharmony_ci      > To the driver, the custom structure holds parameters and data. The **DeviceResourceIface** method provided by the HDF reads the values in the **i3c_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 **I3cCntlr** object at the core layer.
246e41f4b71Sopenharmony_ci
247e41f4b71Sopenharmony_ci        ```c
248e41f4b71Sopenharmony_ci        struct VirtualI3cCntlr {
249e41f4b71Sopenharmony_ci            struct I3cCntlr cntlr;           // (Mandatory) Control object at the core layer. For details, see the following description.
250e41f4b71Sopenharmony_ci            volatile unsigned char *regBase; // (Mandatory) Register base address.
251e41f4b71Sopenharmony_ci            uint32_t regBasePhy              // (Mandatory) Physical base address of the register.
252e41f4b71Sopenharmony_ci            uint32_t regSize;                // (Mandatory) Register bit width.
253e41f4b71Sopenharmony_ci            uint16_t busId;                  // (Mandatory) Bus number.
254e41f4b71Sopenharmony_ci            uint16_t busMode;
255e41f4b71Sopenharmony_ci            uint16_t IrqNum;
256e41f4b71Sopenharmony_ci            uint32_t i3cMaxRate;
257e41f4b71Sopenharmony_ci            uint32_t i3cRate;
258e41f4b71Sopenharmony_ci            uint32_t i2cFmRate;
259e41f4b71Sopenharmony_ci            uint32_t i2cFmPlusRate;
260e41f4b71Sopenharmony_ci        };
261e41f4b71Sopenharmony_ci        
262e41f4b71Sopenharmony_ci        /* I3cCntlr is the controller structure at the core layer. The Init function assigns values to the members of I3cCntlr. */
263e41f4b71Sopenharmony_ci        struct I3cCntlr {
264e41f4b71Sopenharmony_ci            OsalSpinlock lock;
265e41f4b71Sopenharmony_ci            void *owner;
266e41f4b71Sopenharmony_ci            int16_t busId;
267e41f4b71Sopenharmony_ci            struct I3cConfig config;
268e41f4b71Sopenharmony_ci            uint16_t addrSlot[(I3C_ADDR_MAX + 1) / ADDRS_PER_UINT16];
269e41f4b71Sopenharmony_ci            struct I3cIbiInfo *ibiSlot[I3C_IBI_MAX];
270e41f4b71Sopenharmony_ci            const struct I3cMethod *ops;
271e41f4b71Sopenharmony_ci            const struct I3cLockMethod *lockOps;
272e41f4b71Sopenharmony_ci            void *priv;
273e41f4b71Sopenharmony_ci        };
274e41f4b71Sopenharmony_ci        ```
275e41f4b71Sopenharmony_ci
276e41f4b71Sopenharmony_ci    - Implement the **Init** function.
277e41f4b71Sopenharmony_ci
278e41f4b71Sopenharmony_ci        **Input parameter**:
279e41f4b71Sopenharmony_ci
280e41f4b71Sopenharmony_ci        **HdfDeviceObject**, an interface parameter provided by the driver, contains the .hcs information.
281e41f4b71Sopenharmony_ci
282e41f4b71Sopenharmony_ci        **Return value**:
283e41f4b71Sopenharmony_ci
284e41f4b71Sopenharmony_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.
285e41f4b71Sopenharmony_ci             
286e41f4b71Sopenharmony_ci
287e41f4b71Sopenharmony_ci        |Status|Description|
288e41f4b71Sopenharmony_ci        |:-|:-:|
289e41f4b71Sopenharmony_ci        |HDF_ERR_INVALID_OBJECT|Invalid controller object.|
290e41f4b71Sopenharmony_ci        |HDF_ERR_INVALID_PARAM |Invalid parameter.|
291e41f4b71Sopenharmony_ci        |HDF_ERR_MALLOC_FAIL   |Failed to allocate the memory.|
292e41f4b71Sopenharmony_ci        |HDF_ERR_IO            |I/O error.|
293e41f4b71Sopenharmony_ci        |HDF_SUCCESS           |Transmission successful.|
294e41f4b71Sopenharmony_ci        |HDF_FAILURE           |Transmission failed.|
295e41f4b71Sopenharmony_ci
296e41f4b71Sopenharmony_ci        **Function description**:
297e41f4b71Sopenharmony_ci
298e41f4b71Sopenharmony_ci        Initializes the custom structure object and **I3cCntlr**, and calls the **I3cCntlrAdd** function to add the I3C controller to the core layer.
299e41f4b71Sopenharmony_ci
300e41f4b71Sopenharmony_ci         ```c
301e41f4b71Sopenharmony_ci         static int32_t VirtualI3cParseAndInit(struct HdfDeviceObject *device, const struct DeviceResourceNode *node)
302e41f4b71Sopenharmony_ci         {
303e41f4b71Sopenharmony_ci             int32_t ret;
304e41f4b71Sopenharmony_ci             struct VirtualI3cCntlr *virtual = NULL;                               // (Mandatory) Custom structure object.
305e41f4b71Sopenharmony_ci             (void)device;
306e41f4b71Sopenharmony_ci         
307e41f4b71Sopenharmony_ci             virtual = (struct VirtualI3cCntlr *)OsalMemCalloc(sizeof(*virtual)); // (Mandatory) Allocate memory.
308e41f4b71Sopenharmony_ci             if (virtual == NULL) {
309e41f4b71Sopenharmony_ci                 HDF_LOGE("%s: Malloc virtual fail!", __func__);
310e41f4b71Sopenharmony_ci                 return HDF_ERR_MALLOC_FAIL;
311e41f4b71Sopenharmony_ci             }
312e41f4b71Sopenharmony_ci         
313e41f4b71Sopenharmony_ci             ret = VirtualI3cReadDrs(virtual, node);     // (Mandatory) Use the default values in the i3c_config file to fill in the structure. For details about the function definition, see the following.
314e41f4b71Sopenharmony_ci             if (ret != HDF_SUCCESS) {
315e41f4b71Sopenharmony_ci                 HDF_LOGE("%s: Read drs fail! ret:%d", __func__, ret);
316e41f4b71Sopenharmony_ci                 goto __ERR__;
317e41f4b71Sopenharmony_ci             }
318e41f4b71Sopenharmony_ci             ...
319e41f4b71Sopenharmony_ci             virtual->regBase = OsalIoRemap(virtual->regBasePhy, virtual->regSize);// (Mandatory) Address mapping.
320e41f4b71Sopenharmony_ci             ret = OsalRegisterIrq(hi35xx->softIrqNum, OSAL_IRQF_TRIGGER_NONE, I3cIbiHandle, "I3C", virtual); // (Mandatory) Register an interrupt handler.
321e41f4b71Sopenharmony_ci             if (ret != HDF_SUCCESS) {
322e41f4b71Sopenharmony_ci                 HDF_LOGE("%s: register irq failed!", __func__);
323e41f4b71Sopenharmony_ci                 return ret;
324e41f4b71Sopenharmony_ci             }
325e41f4b71Sopenharmony_ci             ...
326e41f4b71Sopenharmony_ci             VirtualI3cCntlrInit(virtual);              // (Mandatory) Initialize the I3C device.
327e41f4b71Sopenharmony_ci             virtual->cntlr.priv = (void *)node;        // (Mandatory) Set the storage device attributes.
328e41f4b71Sopenharmony_ci             virtual->cntlr.busId = virtual->busId;     // (Mandatory) Initialize I3cCntlr.
329e41f4b71Sopenharmony_ci             virtual->cntlr.ops = &g_method;            // (Mandatory) Attach the I3cMethod instance. 
330e41f4b71Sopenharmony_ci             (void)OsalSpinInit(&virtual->spin);
331e41f4b71Sopenharmony_ci             ret = I3cCntlrAdd(&virtual->cntlr);        // (Mandatory) Call this function to add the controller to the core layer. The driver can access the platform core layer only when a success signal is returned.
332e41f4b71Sopenharmony_ci             if (ret != HDF_SUCCESS) {
333e41f4b71Sopenharmony_ci                 HDF_LOGE("%s: add i3c controller failed! ret = %d", __func__, ret);
334e41f4b71Sopenharmony_ci                 (void)OsalSpinDestroy(&virtual->spin);
335e41f4b71Sopenharmony_ci                 goto __ERR__;
336e41f4b71Sopenharmony_ci             }
337e41f4b71Sopenharmony_ci         
338e41f4b71Sopenharmony_ci             return HDF_SUCCESS;
339e41f4b71Sopenharmony_ci         __ERR__:                                       // If the controller fails to be added, deinitialize related functions.
340e41f4b71Sopenharmony_ci             if (virtual != NULL) {
341e41f4b71Sopenharmony_ci                 OsalMemFree(virtual);
342e41f4b71Sopenharmony_ci                 virtual = NULL;
343e41f4b71Sopenharmony_ci             }
344e41f4b71Sopenharmony_ci         
345e41f4b71Sopenharmony_ci             return ret;
346e41f4b71Sopenharmony_ci         }
347e41f4b71Sopenharmony_ci         
348e41f4b71Sopenharmony_ci         static int32_t VirtualI3cInit(struct HdfDeviceObject *device)
349e41f4b71Sopenharmony_ci         {
350e41f4b71Sopenharmony_ci             int32_t ret;
351e41f4b71Sopenharmony_ci             const struct DeviceResourceNode *childNode = NULL;
352e41f4b71Sopenharmony_ci         
353e41f4b71Sopenharmony_ci             if (device == NULL || device->property == NULL) {
354e41f4b71Sopenharmony_ci                 HDF_LOGE("%s: device or property is NULL", __func__);
355e41f4b71Sopenharmony_ci                 return HDF_ERR_INVALID_OBJECT;
356e41f4b71Sopenharmony_ci             }
357e41f4b71Sopenharmony_ci         
358e41f4b71Sopenharmony_ci             DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
359e41f4b71Sopenharmony_ci                 ret = VirtualI3cParseAndInit(device, childNode);
360e41f4b71Sopenharmony_ci                 if (ret != HDF_SUCCESS) {
361e41f4b71Sopenharmony_ci                     break;
362e41f4b71Sopenharmony_ci                 }
363e41f4b71Sopenharmony_ci             }
364e41f4b71Sopenharmony_ci         
365e41f4b71Sopenharmony_ci             return ret;
366e41f4b71Sopenharmony_ci         }
367e41f4b71Sopenharmony_ci         
368e41f4b71Sopenharmony_ci         static int32_t VirtualI3cReadDrs(struct VirtualI3cCntlr *virtual, const struct DeviceResourceNode *node)
369e41f4b71Sopenharmony_ci         {
370e41f4b71Sopenharmony_ci             struct DeviceResourceIface *drsOps = NULL;
371e41f4b71Sopenharmony_ci         
372e41f4b71Sopenharmony_ci             /* Obtain the drsOps method. */
373e41f4b71Sopenharmony_ci             drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
374e41f4b71Sopenharmony_ci             if (drsOps == NULL || drsOps->GetUint32 == NULL || drsOps->GetUint16 == NULL) {
375e41f4b71Sopenharmony_ci                 HDF_LOGE("%s: Invalid drs ops fail!", __func__);
376e41f4b71Sopenharmony_ci                 return HDF_FAILURE;
377e41f4b71Sopenharmony_ci             }
378e41f4b71Sopenharmony_ci             /* Read the configuration parameters in sequence and fill them in the structure. */
379e41f4b71Sopenharmony_ci             if (drsOps->GetUint16(node, "busId", &virtual->busId, 0) != HDF_SUCCESS) {
380e41f4b71Sopenharmony_ci                 HDF_LOGE("%s: Read busId fail!", __func__);
381e41f4b71Sopenharmony_ci                 return HDF_ERR_IO;
382e41f4b71Sopenharmony_ci             }
383e41f4b71Sopenharmony_ci             if (drsOps->GetUint16(node, "busMode", &virtual->busMode, 0) != HDF_SUCCESS) {
384e41f4b71Sopenharmony_ci                 HDF_LOGE("%s: Read busMode fail!", __func__);
385e41f4b71Sopenharmony_ci                 return HDF_ERR_IO;
386e41f4b71Sopenharmony_ci             }
387e41f4b71Sopenharmony_ci             if (drsOps->GetUint16(node, "IrqNum", &virtual->IrqNum, 0) != HDF_SUCCESS) {
388e41f4b71Sopenharmony_ci                 HDF_LOGE("%s: Read IrqNum fail!", __func__);
389e41f4b71Sopenharmony_ci                 return HDF_ERR_IO;
390e41f4b71Sopenharmony_ci             }
391e41f4b71Sopenharmony_ci             ···
392e41f4b71Sopenharmony_ci             return HDF_SUCCESS;
393e41f4b71Sopenharmony_ci         }
394e41f4b71Sopenharmony_ci         ```
395e41f4b71Sopenharmony_ci
396e41f4b71Sopenharmony_ci    - Implement the **Release** function.
397e41f4b71Sopenharmony_ci
398e41f4b71Sopenharmony_ci        **Input parameter**:
399e41f4b71Sopenharmony_ci
400e41f4b71Sopenharmony_ci        **HdfDeviceObject**, an interface parameter provided by the driver, contains the .hcs information.
401e41f4b71Sopenharmony_ci
402e41f4b71Sopenharmony_ci        **Return value**:
403e41f4b71Sopenharmony_ci
404e41f4b71Sopenharmony_ci        No value is returned.
405e41f4b71Sopenharmony_ci
406e41f4b71Sopenharmony_ci        **Function description**:
407e41f4b71Sopenharmony_ci
408e41f4b71Sopenharmony_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.
409e41f4b71Sopenharmony_ci
410e41f4b71Sopenharmony_ci        > ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE** 
411e41f4b71Sopenharmony_ci        >
412e41f4b71Sopenharmony_ci        > All forced conversion operations for obtaining the corresponding object can be successful only when the **Init** function has the value assignment operations.
413e41f4b71Sopenharmony_ci
414e41f4b71Sopenharmony_ci        ```c
415e41f4b71Sopenharmony_ci        static void VirtualI3cRemoveByNode(const struct DeviceResourceNode *node)
416e41f4b71Sopenharmony_ci        {
417e41f4b71Sopenharmony_ci            int32_t ret;
418e41f4b71Sopenharmony_ci            int16_t busId;
419e41f4b71Sopenharmony_ci            struct I3cCntlr *cntlr = NULL;
420e41f4b71Sopenharmony_ci            struct VirtualI3cCntlr *virtual = NULL;
421e41f4b71Sopenharmony_ci            struct DeviceResourceIface *drsOps = NULL;
422e41f4b71Sopenharmony_ci        
423e41f4b71Sopenharmony_ci            drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
424e41f4b71Sopenharmony_ci            if (drsOps == NULL || drsOps->GetUint32 == NULL) {
425e41f4b71Sopenharmony_ci                HDF_LOGE("%s: invalid drs ops fail!", __func__);
426e41f4b71Sopenharmony_ci                return;
427e41f4b71Sopenharmony_ci            }
428e41f4b71Sopenharmony_ci        
429e41f4b71Sopenharmony_ci            ret = drsOps->GetUint16(node, "busId", (uint16_t *)&busId, 0);
430e41f4b71Sopenharmony_ci            if (ret != HDF_SUCCESS) {
431e41f4b71Sopenharmony_ci                HDF_LOGE("%s: read busId fail!", __func__);
432e41f4b71Sopenharmony_ci                return;
433e41f4b71Sopenharmony_ci            }
434e41f4b71Sopenharmony_ci        ...
435e41f4b71Sopenharmony_ci        /* Call I3cCntlrGet() to obtain the I3cCntlr object based on the cntlrNum of the device, and then call I3cCntlrRemove() to release the I3cCntlr object. */
436e41f4b71Sopenharmony_ci            cntlr = I3cCntlrGet(busId);
437e41f4b71Sopenharmony_ci            if (cntlr != NULL && cntlr->priv == node) {
438e41f4b71Sopenharmony_ci                I3cCntlrPut(cntlr);
439e41f4b71Sopenharmony_ci                I3cCntlrRemove(cntlr);                    // (Mandatory) Remove the I3cCntlr object from the manager driver.
440e41f4b71Sopenharmony_ci                virtual = (struct VirtualI3cCntlr *)cntlr; // (Mandatory) Obtain the custom object through a forced conversion and perform the release operation.
441e41f4b71Sopenharmony_ci                (void)OsalSpinDestroy(&virtual->spin);
442e41f4b71Sopenharmony_ci                OsalMemFree(virtual);
443e41f4b71Sopenharmony_ci            }
444e41f4b71Sopenharmony_ci            return;
445e41f4b71Sopenharmony_ci        }
446e41f4b71Sopenharmony_ci        
447e41f4b71Sopenharmony_ci        static void VirtualI3cRelease(struct HdfDeviceObject *device)
448e41f4b71Sopenharmony_ci        {
449e41f4b71Sopenharmony_ci            const struct DeviceResourceNode *childNode = NULL;
450e41f4b71Sopenharmony_ci        
451e41f4b71Sopenharmony_ci            HDF_LOGI("%s: enter", __func__);
452e41f4b71Sopenharmony_ci        
453e41f4b71Sopenharmony_ci            if (device == NULL || device->property == NULL) {
454e41f4b71Sopenharmony_ci                HDF_LOGE("%s: device or property is NULL", __func__);
455e41f4b71Sopenharmony_ci                return;
456e41f4b71Sopenharmony_ci            }
457e41f4b71Sopenharmony_ci        ...
458e41f4b71Sopenharmony_ci        /* Traverse and parse all nodes in i3c_config.hcs and perform the release operation on each node. */
459e41f4b71Sopenharmony_ci            DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
460e41f4b71Sopenharmony_ci                VirtualI3cRemoveByNode(childNode);  // See the description of VirtualI3cRemoveByNode for more details.
461e41f4b71Sopenharmony_ci            }
462e41f4b71Sopenharmony_ci        }
463e41f4b71Sopenharmony_ci        ```
464e41f4b71Sopenharmony_ci
465e41f4b71Sopenharmony_ci4. Register an interrupt handler.
466e41f4b71Sopenharmony_ci
467e41f4b71Sopenharmony_ci    The interrupt handler performs an IBI or hot-join based on the address where the interrupt is generated.
468e41f4b71Sopenharmony_ci
469e41f4b71Sopenharmony_ci    ```c
470e41f4b71Sopenharmony_ci    static int32_t VirtualI3cReservedAddrWorker(struct VirtualI3cCntlr *virtual, uint16_t addr)
471e41f4b71Sopenharmony_ci    {
472e41f4b71Sopenharmony_ci        (void)virtual;
473e41f4b71Sopenharmony_ci        switch (addr) {
474e41f4b71Sopenharmony_ci            case I3C_HOT_JOIN_ADDR:
475e41f4b71Sopenharmony_ci                 VirtualI3cHotJoin(virtual);
476e41f4b71Sopenharmony_ci                break;
477e41f4b71Sopenharmony_ci            case I3C_RESERVED_ADDR_7H3E:
478e41f4b71Sopenharmony_ci            case I3C_RESERVED_ADDR_7H5E:
479e41f4b71Sopenharmony_ci            case I3C_RESERVED_ADDR_7H6E:
480e41f4b71Sopenharmony_ci            case I3C_RESERVED_ADDR_7H76:
481e41f4b71Sopenharmony_ci            case I3C_RESERVED_ADDR_7H7A:
482e41f4b71Sopenharmony_ci            case I3C_RESERVED_ADDR_7H7C:
483e41f4b71Sopenharmony_ci            case I3C_RESERVED_ADDR_7H7F:
484e41f4b71Sopenharmony_ci            /* All single-bit errors in the broadcast address */
485e41f4b71Sopenharmony_ci            HDF_LOGW("%s: broadcast Address single bit error!", __func__);
486e41f4b71Sopenharmony_ci                break;
487e41f4b71Sopenharmony_ci            default:
488e41f4b71Sopenharmony_ci                HDF_LOGD("%s: Reserved address which is not supported!", __func__);
489e41f4b71Sopenharmony_ci                break;
490e41f4b71Sopenharmony_ci        }
491e41f4b71Sopenharmony_ci    
492e41f4b71Sopenharmony_ci        return HDF_SUCCESS;
493e41f4b71Sopenharmony_ci    }
494e41f4b71Sopenharmony_ci    
495e41f4b71Sopenharmony_ci    static int32_t I3cIbiHandle(uint32_t irq, void *data)
496e41f4b71Sopenharmony_ci    {
497e41f4b71Sopenharmony_ci        struct VirtualI3cCntlr *virtual = NULL;
498e41f4b71Sopenharmony_ci        struct I3cDevice *device = NULL;
499e41f4b71Sopenharmony_ci        uint16_t ibiAddr;
500e41f4b71Sopenharmony_ci        char *testStr = "Hello I3C!";
501e41f4b71Sopenharmony_ci    
502e41f4b71Sopenharmony_ci        (void)irq;
503e41f4b71Sopenharmony_ci        if (data == NULL) {
504e41f4b71Sopenharmony_ci            HDF_LOGW("%s: data is NULL!", __func__);
505e41f4b71Sopenharmony_ci            return HDF_ERR_INVALID_PARAM;
506e41f4b71Sopenharmony_ci        }
507e41f4b71Sopenharmony_ci        virtual = (struct VirtualI3cCntlr *)data;
508e41f4b71Sopenharmony_ci        /* (Mandatory) Obtain the address where the interrupt is generated. Use the CHECK_RESERVED_ADDR macro to determine whether the address is an I3C address. */
509e41f4b71Sopenharmony_ci        ibiAddr = VirtualI3cGetIbiAddr();
510e41f4b71Sopenharmony_ci        if (CHECK_RESERVED_ADDR(ibiAddr) == I3C_ADDR_RESERVED) {
511e41f4b71Sopenharmony_ci            HDF_LOGD("%s: Calling VirtualI3cResAddrWorker...", __func__);
512e41f4b71Sopenharmony_ci            return VirtualI3cReservedAddrWorker(virtual, ibiAddr);
513e41f4b71Sopenharmony_ci        } else {
514e41f4b71Sopenharmony_ci            HDF_LOGD("%s: Calling I3cCntlrIbiCallback...", __func__);
515e41f4b71Sopenharmony_ci            device = GetDeviceByAddr(&virtual->cntlr, ibiAddr);
516e41f4b71Sopenharmony_ci            if (device == NULL) {
517e41f4b71Sopenharmony_ci                HDF_LOGE("func:%s device is NULL!",__func__);
518e41f4b71Sopenharmony_ci                return HDF_ERR_MALLOC_FAIL;
519e41f4b71Sopenharmony_ci            }
520e41f4b71Sopenharmony_ci            if (device->ibi->payload > VIRTUAL_I3C_TEST_STR_LEN) {
521e41f4b71Sopenharmony_ci                /* Place the string "Hello I3C!" into the IBI buffer. */
522e41f4b71Sopenharmony_ci                *device->ibi->data = *testStr;
523e41f4b71Sopenharmony_ci            }
524e41f4b71Sopenharmony_ci            /* Invoke the IBI callback based on the I3C device that generates the IBI. */
525e41f4b71Sopenharmony_ci            return I3cCntlrIbiCallback(device);
526e41f4b71Sopenharmony_ci        }
527e41f4b71Sopenharmony_ci    
528e41f4b71Sopenharmony_ci        return HDF_SUCCESS;
529e41f4b71Sopenharmony_ci    }
530e41f4b71Sopenharmony_ci    ```
531