• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# I2C<a name="EN-US_TOPIC_0000001153579420"></a>
2
3
4
5## Overview<a name="section2040078630114257"></a>
6
7The Inter-Integrated Circuit \(I2C\) bus is a simple and bidirectional two-wire synchronous serial bus developed by Philips. In the Hardware Driver Foundation (HDF) framework, 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 external access requests in a unified manner, which is reflected in the configuration file. The unified service mode applies to the scenario where there are many device objects of the same type, for example, when the I2C module has more than 10 controllers. If the independent service mode is used, more device nodes need to be configured and memory resources will be consumed by services.
8
9**Figure  1**  Unified service mode<a name="fig17640124912440"></a>
10![](figures/unified-service-mode.png "unified-service-mode-8")
11
12## Available APIs<a name="section752964871810"></a>
13
14I2cMethod and I2cLockMethod
15
16```
17struct I2cMethod {
18int32_t (*transfer)(struct I2cCntlr *cntlr, struct I2cMsg *msgs, int16_t count);
19};
20struct I2cLockMethod {// Lock mechanism operation structure
21     int32_t (*lock)(struct I2cCntlr *cntlr); // Add a lock.
22     void (*unlock)(struct I2cCntlr *cntlr);  // Release the lock.
23};
24```
25
26**Table  1**  Callbacks for the members in the I2cMethod structure
27
28<a name="table10549174014611"></a>
29<table><thead align="left"><tr id="row17550114013460"><th class="cellrowborder" valign="top" width="20%" id="mcps1.2.6.1.1"><p id="p155014403467"><a name="p155014403467"></a><a name="p155014403467"></a>Callback</p>
30</th>
31<th class="cellrowborder" valign="top" width="20%" id="mcps1.2.6.1.2"><p id="p165507404466"><a name="p165507404466"></a><a name="p165507404466"></a>Input Parameter</p>
32</th>
33<th class="cellrowborder" valign="top" width="20%" id="mcps1.2.6.1.3"><p id="p8550194015467"><a name="p8550194015467"></a><a name="p8550194015467"></a>Output Parameter</p>
34</th>
35<th class="cellrowborder" valign="top" width="20%" id="mcps1.2.6.1.4"><p id="p65501540184618"><a name="p65501540184618"></a><a name="p65501540184618"></a>Return Value</p>
36</th>
37<th class="cellrowborder" valign="top" width="20%" id="mcps1.2.6.1.5"><p id="p185501740194610"><a name="p185501740194610"></a><a name="p185501740194610"></a>Description</p>
38</th>
39</tr>
40</thead>
41<tbody><tr id="row75509402460"><td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.1 "><p id="p0550104084617"><a name="p0550104084617"></a><a name="p0550104084617"></a>transfer</p>
42</td>
43<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.2 "><p id="p9551164011468"><a name="p9551164011468"></a><a name="p9551164011468"></a><strong id="b1413775771219"><a name="b1413775771219"></a><a name="b1413775771219"></a>cntlr</strong>: structure pointer to the I2C controller at the core layer. <strong id="b13955019171313"><a name="b13955019171313"></a><a name="b13955019171313"></a>msgs</strong>: structure pointer to the user message. <strong id="b4678857181319"><a name="b4678857181319"></a><a name="b4678857181319"></a>count</strong>: number of messages, which is of the uint16_t type.</p>
44</td>
45<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.3 "><p id="p6551140124620"><a name="p6551140124620"></a><a name="p6551140124620"></a>–</p>
46</td>
47<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.4 "><p id="p555144084619"><a name="p555144084619"></a><a name="p555144084619"></a>HDF_STATUS</p>
48</td>
49<td class="cellrowborder" valign="top" width="20%" headers="mcps1.2.6.1.5 "><p id="p8551174044612"><a name="p8551174044612"></a><a name="p8551174044612"></a>Transfers user messages.</p>
50</td>
51</tr>
52</tbody>
53</table>
54
55## How to Develop<a name="section1085786591114257"></a>
56
57The I2C module adaptation involves the following steps:
58
591.  Instantiate the driver entry.
60    -   Instantiate the  **HdfDriverEntry**  structure.
61    -   Call  **HDF\_INIT**  to register the  **HdfDriverEntry**  instance with the HDF framework.
62
632.  Configure attribute files.
64    -   Add the  **deviceNode**  information to the  **device\_info.hcs**  file.
65    -   \(Optional\) Add the  **i2c\_config.hcs**  file.
66
673.  Instantiate the I2C controller object.
68    -   Initialize  **I2cCntlr**.
69    -   Instantiate  **I2cMethod**  and  **I2cLockMethod**  in  **I2cCntlr**.
70
71        >![](../public_sys-resources/icon-note.gif) **NOTE**
72
73        >For details, see [Available APIs](#available-apis).
74
75
764.  Debug the driver.
77    -   \(Optional\) For new drivers, verify basic functions, for example, verify the information returned after the connect operation and whether data is successfully transmitted.
78
79
80
81
82## Development Example<a name="section1773332551114257"></a>
83
84The following uses  **i2c\_hi35xx.c**  as an example to present the contents that need to be provided by the vendor to implement device functions.
85
861.  Instantiate the driver entry. 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 framework, 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.
87
88    Generally, HDF calls the  **Bind**  function and then the  **Init**  function to load a driver. If  **Init**  fails to be called, HDF calls  **Release**  to release driver resources and exit.
89
90    -   I2C driver entry reference
91
92        Many devices may be connected to the I2C module. Therefore, in the HDF framework, a manager object is created for the I2C, and a manager service is launched to handle external access requests in a unified manner. When a user wants to open a device, the user obtains the manager service first. Then, the manager service locates the target device based on the parameters specified by the user.
93
94        The driver of the I2C manager is implemented by the core layer. Vendors do not need to pay attention to the implementation of this part. However, when they implement the  **Init**  function, the  **I2cCntlrAdd**  function of the core layer must be called to implement the corresponding features.
95
96        ```
97        struct HdfDriverEntry g_i2cDriverEntry = {
98            .moduleVersion = 1,
99            .Init = Hi35xxI2cInit,
100            .Release = Hi35xxI2cRelease,
101            .moduleName = "hi35xx_i2c_driver",// (Mandatory) The value must be the same as that in the config.hcs file.
102        };
103        HDF_INIT(g_i2cDriverEntry);   // Call HDF_INIT to register the driver entry with the HDF framework.
104
105        // Driver entry of the i2c_core.c manager service at the core layer
106        struct HdfDriverEntry g_i2cManagerEntry = {
107            .moduleVersion = 1,
108            .Bind = I2cManagerBind,
109            .Init = I2cManagerInit,
110            .Release = I2cManagerRelease,
111         .moduleName = "HDF_PLATFORM_I2C_MANAGER",// This parameter corresponds to device0 in the device_info file.
112        };
113        HDF_INIT(g_i2cManagerEntry);
114        ```
115
1162.  Add the  **deviceNode**  information to the  **device\_info.hcs**  file and configure the device attributes in the  **i2c\_config.hcs**  file. The  **deviceNode**  information is related to registration of the driver entry. 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.
117
118    In the unified service mode, the first device node in the  **device\_info**  file must be the I2C manager.  [Table 2](#table96651915911)  lists settings of its parameters.
119
120    **Table  2**  Settings of the I2C manager
121
122    <a name="table96651915911"></a>
123    <table><thead align="left"><tr id="row96618194915"><th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.1"><p id="p1066119790"><a name="p1066119790"></a><a name="p1066119790"></a>Member</p>
124    </th>
125    <th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.2"><p id="p8674191494"><a name="p8674191494"></a><a name="p8674191494"></a>Value</p>
126    </th>
127    </tr>
128    </thead>
129    <tbody><tr id="row767111916914"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p46714196920"><a name="p46714196920"></a><a name="p46714196920"></a>moduleName</p>
130    </td>
131    <td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p36717191292"><a name="p36717191292"></a><a name="p36717191292"></a>It has a fixed value of <strong id="b1343012314357"><a name="b1343012314357"></a><a name="b1343012314357"></a>HDF_PLATFORM_I2C_MANAGER</strong>.</p>
132    </td>
133    </tr>
134    <tr id="row16671119392"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p11671019699"><a name="p11671019699"></a><a name="p11671019699"></a>serviceName</p>
135    </td>
136    <td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p86716195912"><a name="p86716195912"></a><a name="p86716195912"></a>It has a fixed value of <strong id="b107651238143515"><a name="b107651238143515"></a><a name="b107651238143515"></a>HDF_PLATFORM_I2C_MANAGER</strong>.</p>
137    </td>
138    </tr>
139    <tr id="row17673191911"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p5673191898"><a name="p5673191898"></a><a name="p5673191898"></a>policy</p>
140    </td>
141    <td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p18677191699"><a name="p18677191699"></a><a name="p18677191699"></a>The value can be <strong id="b13997735183718"><a name="b13997735183718"></a><a name="b13997735183718"></a>1</strong> or <strong id="b165591038103717"><a name="b165591038103717"></a><a name="b165591038103717"></a>2</strong>, depending on whether it is visible to the user mode.</p>
142    </td>
143    </tr>
144    <tr id="row8675191894"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p12677191913"><a name="p12677191913"></a><a name="p12677191913"></a>deviceMatchAttr</p>
145    </td>
146    <td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p1567171918915"><a name="p1567171918915"></a><a name="p1567171918915"></a>This parameter is not used.</p>
147    </td>
148    </tr>
149    </tbody>
150    </table>
151
152    Configure I2C controller information from the second node. This node specifies a type of I2C controllers rather than an I2C controller. The  **busID**  and  **reg\_pbase**  parameters distinguish controllers, which can be seen in the  **i2c\_config**  file.
153
154    -   **device\_info.hcs**  configuration reference
155
156        ```
157        root {
158        device_info {
159        match_attr = "hdf_manager";
160            device_i2c :: device {
161            device0 :: deviceNode {
162                policy = 2;
163                priority = 50;
164                permission = 0644;
165                moduleName = "HDF_PLATFORM_I2C_MANAGER";
166                serviceName = "HDF_PLATFORM_I2C_MANAGER";
167                deviceMatchAttr = "hdf_platform_i2c_manager";
168            }
169            device1 :: deviceNode {
170         policy = 0; // The value 0 indicates that no service needs to be published.
171                 priority = 55;                           // Driver startup priority
172                permission = 0644;                  // Permission for the driver to create a device node
173                moduleName = "hi35xx_i2c_driver";        // (Mandatory) Driver name, which must be the same as the moduleName in the driver entry.
174                serviceName = "HI35XX_I2C_DRIVER"; // (Mandatory) Unique name of the service published by the driver
175                deviceMatchAttr = "hisilicon_hi35xx_i2c";// (Mandatory) Used to configure the private data of the controller. The value must be the same as the controller in i2c_config.hcs.
176                } // The specific controller information is in i2c_config.hcs.
177            }
178            }
179        }
180        }
181        ```
182
183    -   **i2c\_config.hcs**  configuration reference
184
185        ```
186        root {
187        platform {
188            i2c_config {
189            match_attr = "hisilicon_hi35xx_i2c";// (Mandatory) The value must be the same as that of deviceMatchAttr in device_info.hcs.
190            template i2c_controller {           // Template configuration. In the template, you can configure the common parameters shared by service nodes.
191                  bus = 0;                          // (Mandatory) I2C ID
192                 reg_pbase = 0x120b0000;           // (Mandatory) Physical base address
193               reg_size = 0xd1;                  // (Mandatory) Register bit width
194                 irq = 0;                          // (Optional) Configured based on the vendor's requirements.
195                freq = 400000;                    // (Optional) Configured based on the vendor's requirements.
196                 clk = 50000000;                   // (Optional) Configured based on the vendor's requirements.
197            }
198            controller_0x120b0000 :: i2c_controller {
199                bus = 0;
200            }
201            controller_0x120b1000 :: i2c_controller {
202                bus = 1;
203                reg_pbase = 0x120b1000;
204            }
205            ...
206            }
207        }
208        }
209        ```
210
2113.  Initialize the  **I2cCntlr**  object at the core layer, including initializing the vendor custom structure \(transferring parameters and data\), instantiating  **I2cMethod**  \(used to call underlying functions of the driver\) in  **I2cCntlr**, and implementing the  **HdfDriverEntry**  member functions \(**Bind**,  **Init**, and  **Release**\).
212    -   Custom structure reference
213
214        To the driver, the custom structure carries parameters and data. The values in the  **i2c\_config.hcs**  file are read by HDF, and the structure members are initialized through  **DeviceResourceIface**. Some important values, such as the device number and bus number, are also passed to the  **I2cCntlr**  object at the core layer.
215
216        ```
217        // Vendor custom function structure
218        struct Hi35xxI2cCntlr {
219            struct I2cCntlr cntlr;            // (Mandatory) Control object of the core layer. For details, see the following description.
220            OsalSpinlock spin;                // (Mandatory) The vendor needs to implement lock and unlock for I2C operation functions based on this variable.
221            volatile unsigned char  *regBase; // (Mandatory) Base address of the register
222             uint16_t regSize; // (mandatory) Bit width of the register
223            int16_t bus;                      // (Mandatory) The value can be read from the i2c_config.hcs file.
224            uint32_t clk;                     // (Optional) Customized by the vendor.
225            uint32_t freq;                    // (Optional) Customized by the vendor.
226            uint32_t irq;                     // (Optional) Customized by the vendor.
227            uint32_t regBasePhy;              // (Mandatory) Physical base address of the register
228        };
229
230        // I2cCntlr is the controller structure at the core layer. Its members are assigned with values by using the Init function.
231        struct I2cCntlr {
232            struct OsalMutex lock;
233            void *owner;
234            int16_t busId;
235            void *priv;
236            const struct I2cMethod *ops;
237            const struct I2cLockMethod *lockOps;
238        };
239        ```
240
241    -   Instantiate the member callback function structure  **I2cMethod**  in  **I2cCntlr**  and the lock callback function structure  **I2cLockMethod**. Other members are initialized by using the  **Init**  function.
242
243        ```
244        // Example in i2c_hi35xx.c
245        static const struct I2cMethod g_method = {
246            .transfer = Hi35xxI2cTransfer,
247        };
248
249        static const struct I2cLockMethod g_lockOps = {
250            .lock = Hi35xxI2cLock, // Lock function
251            .unlock = Hi35xxI2cUnlock,// Unlock function
252        };
253        ```
254
255    -   Init function
256
257        Input parameters:
258
259        **HdfDeviceObject**, an interface parameter exposed by the driver, contains the .hcs configuration file information.
260
261        Return values:
262
263        HDF\_STATUS \(The following table lists some status. For details about other status, see  **HDF\_STATUS**  in the  **//drivers/framework/include/utils/hdf\_base.h**  file.\)
264
265        **Table  3**  Input parameters and return values of the Init function
266
267        <a name="table1743073181511"></a>
268        <table><thead align="left"><tr id="row443033171513"><th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.1"><p id="p34306341517"><a name="p34306341517"></a><a name="p34306341517"></a>Status (Value)</p>
269        </th>
270        <th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.2"><p id="p1243123101510"><a name="p1243123101510"></a><a name="p1243123101510"></a>Description</p>
271        </th>
272        </tr>
273        </thead>
274        <tbody><tr id="row5431638151"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p1043114319156"><a name="p1043114319156"></a><a name="p1043114319156"></a>HDF_ERR_INVALID_OBJECT</p>
275        </td>
276        <td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p343173101513"><a name="p343173101513"></a><a name="p343173101513"></a>Invalid controller object</p>
277        </td>
278        </tr>
279        <tr id="row1243143181516"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p1443118317154"><a name="p1443118317154"></a><a name="p1443118317154"></a>HDF_ERR_INVALID_PARAM</p>
280        </td>
281        <td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p343113341515"><a name="p343113341515"></a><a name="p343113341515"></a>Invalid parameter</p>
282        </td>
283        </tr>
284        <tr id="row1943115391516"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p1843143171511"><a name="p1843143171511"></a><a name="p1843143171511"></a>HDF_ERR_MALLOC_FAIL</p>
285        </td>
286        <td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p943114391515"><a name="p943114391515"></a><a name="p943114391515"></a>Failed to allocate memory</p>
287        </td>
288        </tr>
289        <tr id="row1443183101514"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p54311031157"><a name="p54311031157"></a><a name="p54311031157"></a>HDF_ERR_IO</p>
290        </td>
291        <td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p74315311158"><a name="p74315311158"></a><a name="p74315311158"></a>I/O error</p>
292        </td>
293        </tr>
294        <tr id="row3431437158"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p8432332158"><a name="p8432332158"></a><a name="p8432332158"></a>HDF_SUCCESS</p>
295        </td>
296        <td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p104329391519"><a name="p104329391519"></a><a name="p104329391519"></a>Transmission successful</p>
297        </td>
298        </tr>
299        <tr id="row34321136152"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p184325391517"><a name="p184325391517"></a><a name="p184325391517"></a>HDF_FAILURE</p>
300        </td>
301        <td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p1343220319154"><a name="p1343220319154"></a><a name="p1343220319154"></a>Transmission failed</p>
302        </td>
303        </tr>
304        </tbody>
305        </table>
306
307        Function description:
308
309        Initializes the custom structure object and  **I2cCntlr**, calls the  **I2cCntlrAdd**  function at the core layer, and connects to the VFS \(optional\).
310
311        ```
312        static int32_t Hi35xxI2cInit(struct HdfDeviceObject *device)
313        {
314            ...
315        // Traverse and parse all nodes in i2c_config.hcs and call Hi35xxI2cParseAndInit to initialize the devices separately.
316            DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
317                ret = Hi35xxI2cParseAndInit(device, childNode);// For details about the function definition, see the following description.
318            ...
319            }
320            ...
321        }
322
323        static int32_t Hi35xxI2cParseAndInit(struct HdfDeviceObject *device, const struct DeviceResourceNode *node)
324        {
325            struct Hi35xxI2cCntlr *hi35xx = NULL;
326            ...
327            hi35xx = (struct Hi35xxI2cCntlr *)OsalMemCalloc(sizeof(*hi35xx));   // Apply for memory.
328            ...
329        hi35xx->regBase = OsalIoRemap(hi35xx->regBasePhy, hi35xx->regSize); // Address mapping
330            ...
331            Hi35xxI2cCntlrInit(hi35xx);         // (Mandatory) Initialize the I2C device.
332
333           hi35xx->cntlr.priv = (void *)node;  // (Mandatory) Store device attributes.
334            hi35xx->cntlr.busId = hi35xx->bus; // (Mandatory) Initialize busId in I2cCntlr.
335         hi35xx->cntlr.ops = &g_method;      // (Mandatory) Connect to the I2cMethod instance.
336         hi35xx->cntlr.lockOps = &g_lockOps; // (Mandatory) Connect to the I2cLockMethod instance.
337            (void)OsalSpinInit(&hi35xx->spin); // (Mandatory) Initialize the lock.
338          ret = I2cCntlrAdd(&hi35xx->cntlr);  // (Mandatory) Call this function to set the structure of the core layer. The driver accesses the platform core layer only after a success signal is returned.
339            ...
340        #ifdef USER_VFS_SUPPORT
341            (void)I2cAddVfsById(hi35xx->cntlr.busId);// (Optional) Connect the driver to the user-level virtual file system supported.
342        #endif
343            return HDF_SUCCESS;
344         __ERR__:                       // If the operation fails, execute the initialization function reversely.
345            if (hi35xx != NULL) {
346                if (hi35xx->regBase != NULL) {
347                    OsalIoUnmap((void *)hi35xx->regBase);
348                    hi35xx->regBase = NULL;
349                }
350                OsalMemFree(hi35xx);
351                hi35xx = NULL;
352            }
353            return ret;
354        }
355        ```
356
357    -   Release function
358
359        Input parameters:
360
361        **HdfDeviceObject**, an interface parameter exposed by the driver, contains the .hcs configuration file information.
362
363        Return values:
364
365366
367        Function description:
368
369        Releases the memory and deletes the controller. This function assigns a value to the  **Release**  API in the driver entry structure. When the HDF framework fails to call the  **Init**  function to initialize the driver, the  **Release**  function can be called to release driver resources.
370
371        ```
372        static void Hi35xxI2cRelease(struct HdfDeviceObject *device)
373        {
374            ...
375            // Release each node separately, like Hi35xxI2cInit.
376            DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
377            Hi35xxI2cRemoveByNode(childNode);// The function definition is as follows:
378            }
379        }
380
381        static void Hi35xxI2cRemoveByNode(const struct DeviceResourceNode *node)
382        {
383            ...
384            // (Mandatory) Call the I2cCntlrGet function to obtain the I2cCntlr object based on busid of the device, and call the I2cCntlrRemove function to release the I2cCntlr object.
385            cntlr = I2cCntlrGet(bus);
386            if (cntlr != NULL && cntlr->priv == node) {
387                ...
388                I2cCntlrRemove(cntlr);
389                // (Mandatory) Remove the address mapping and release the lock and memory.
390                hi35xx = (struct Hi35xxI2cCntlr *)cntlr;
391                OsalIoUnmap((void *)hi35xx->regBase);
392                (void)OsalSpinDestroy(&hi35xx->spin);
393                OsalMemFree(hi35xx);
394            }
395            return;
396        }
397        ```
398
399
400
401