1e41f4b71Sopenharmony_ci# SPI
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci
4e41f4b71Sopenharmony_ci## Overview
5e41f4b71Sopenharmony_ci
6e41f4b71Sopenharmony_ciSerial Peripheral Interface (SPI) is a serial bus specification used for high-speed, full-duplex, and synchronous communication. In the Hardware Driver Foundation (HDF), the SPI module uses the independent service mode for API adaptation. In this mode, each device independently publishes a service to process external access requests. When receiving an access request, the HDF DeviceManager extracts parameters from the request to call the internal APIs of the target device. In the independent service mode, the HDF DeviceManager provides service management capabilities. However, you need to configure a node for each device, which increases memory usage.
7e41f4b71Sopenharmony_ci
8e41f4b71Sopenharmony_ci  **Figure 1** Independent service mode
9e41f4b71Sopenharmony_ci
10e41f4b71Sopenharmony_ci  ![image](figures/independent-service-mode.png)
11e41f4b71Sopenharmony_ci
12e41f4b71Sopenharmony_ci## Available APIs
13e41f4b71Sopenharmony_ci
14e41f4b71Sopenharmony_ci**SpiCntlrMethod**:
15e41f4b71Sopenharmony_ci
16e41f4b71Sopenharmony_ci
17e41f4b71Sopenharmony_ci```
18e41f4b71Sopenharmony_cistruct SpiCntlrMethod {
19e41f4b71Sopenharmony_ci  int32_t (*GetCfg)(struct SpiCntlr *cntlr, struct SpiCfg *cfg);
20e41f4b71Sopenharmony_ci  int32_t (*SetCfg)(struct SpiCntlr *cntlr, struct SpiCfg *cfg);
21e41f4b71Sopenharmony_ci  int32_t (*Transfer)(struct SpiCntlr *cntlr, struct SpiMsg *msg, uint32_t count);
22e41f4b71Sopenharmony_ci  int32_t (*Open)(struct SpiCntlr *cntlr);
23e41f4b71Sopenharmony_ci  int32_t (*Close)(struct SpiCntlr *cntlr);
24e41f4b71Sopenharmony_ci};
25e41f4b71Sopenharmony_ci```
26e41f4b71Sopenharmony_ci
27e41f4b71Sopenharmony_ci  **Table 1** Description of the callback functions in SpiCntlrMethod
28e41f4b71Sopenharmony_ci
29e41f4b71Sopenharmony_ci| Function| Input Parameter| Return Value| Description|
30e41f4b71Sopenharmony_ci| -------- | -------- | -------- | -------- |
31e41f4b71Sopenharmony_ci| Transfer | **cntlr**: structure pointer to the SPI controller at the core layer.<br>**msg**: structure pointer to the SPI message.<br>**count**: number of messages. The value is of the uint32_t type.| HDF_STATUS| Transfers messages.|
32e41f4b71Sopenharmony_ci| SetCfg | **cntlr**: structure pointer to the SPI controller at the core layer.<br>**cfg**: structure pointer to the SPI attributes.| HDF_STATUS| Sets SPI controller attributes.|
33e41f4b71Sopenharmony_ci| GetCfg | **cntlr**: structure pointer to the SPI controller at the core layer.<br>**cfg**: structure pointer to the SPI attributes.| HDF_STATUS| Obtains SPI controller attributes.|
34e41f4b71Sopenharmony_ci| Open | **cntlr**: structure pointer to the SPI controller at the core layer.| HDF_STATUS| Opens an SPI device.|
35e41f4b71Sopenharmony_ci| Close | **cntlr**: structure pointer to the SPI controller at the core layer.| HDF_STATUS| Closes an SPI device.|
36e41f4b71Sopenharmony_ci
37e41f4b71Sopenharmony_ci
38e41f4b71Sopenharmony_ci## How to Develop
39e41f4b71Sopenharmony_ci
40e41f4b71Sopenharmony_ciThe SPI module adaptation involves the following steps:
41e41f4b71Sopenharmony_ci
42e41f4b71Sopenharmony_ci1. Instantiate the driver entry.
43e41f4b71Sopenharmony_ci   - Instantiate the **HdfDriverEntry** structure.
44e41f4b71Sopenharmony_ci   - Call **HDF_INIT** to register the **HdfDriverEntry** instance with the HDF.
45e41f4b71Sopenharmony_ci
46e41f4b71Sopenharmony_ci2. Configure attribute files.
47e41f4b71Sopenharmony_ci   - Add the **deviceNode** information to the **device_info.hcs** file.
48e41f4b71Sopenharmony_ci   - (Optional) Add the **spi_config.hcs** file.
49e41f4b71Sopenharmony_ci
50e41f4b71Sopenharmony_ci3. Instantiate the SPI controller object.
51e41f4b71Sopenharmony_ci   - Initialize **SpiCntlr**.
52e41f4b71Sopenharmony_ci   - Instantiate **SpiCntlrMethod** in the **SpiCntlr** object.
53e41f4b71Sopenharmony_ci      > ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br>
54e41f4b71Sopenharmony_ci      > For details about the functions in **SpiCntlrMethod**, see [Available APIs](#available-apis).
55e41f4b71Sopenharmony_ci
56e41f4b71Sopenharmony_ci4. Debug the driver.
57e41f4b71Sopenharmony_ci
58e41f4b71Sopenharmony_ci   (Optional) For new drivers, verify the basic functions, such as the SPI status control and response to interrupts.
59e41f4b71Sopenharmony_ci
60e41f4b71Sopenharmony_ci
61e41f4b71Sopenharmony_ci## Development Example
62e41f4b71Sopenharmony_ci
63e41f4b71Sopenharmony_ciThe following uses **spi_hi35xx.c** as an example to present the information required for implementing device functions.
64e41f4b71Sopenharmony_ci
65e41f4b71Sopenharmony_ci1. Instantiate the driver entry.
66e41f4b71Sopenharmony_ci
67e41f4b71Sopenharmony_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**.
68e41f4b71Sopenharmony_ci
69e41f4b71Sopenharmony_ci   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.
70e41f4b71Sopenharmony_ci
71e41f4b71Sopenharmony_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.
72e41f4b71Sopenharmony_ci
73e41f4b71Sopenharmony_ci   SPI driver entry example:
74e41f4b71Sopenharmony_ci   
75e41f4b71Sopenharmony_ci   ```
76e41f4b71Sopenharmony_ci   struct HdfDriverEntry g_hdfSpiDevice = {
77e41f4b71Sopenharmony_ci       .moduleVersion = 1,
78e41f4b71Sopenharmony_ci       .moduleName = "HDF_PLATFORM_SPI",// (Mandatory) The value must be the same as that of moduleName in the .hcs file.
79e41f4b71Sopenharmony_ci       .Bind = HdfSpiDeviceBind,        // See the Bind function.
80e41f4b71Sopenharmony_ci       .Init = HdfSpiDeviceInit,        // See the Init function.
81e41f4b71Sopenharmony_ci       .Release = HdfSpiDeviceRelease,  //See the Release function.
82e41f4b71Sopenharmony_ci   };
83e41f4b71Sopenharmony_ci   // Call HDF_INIT to register the driver entry with the HDF.
84e41f4b71Sopenharmony_ci   HDF_INIT(g_hdfSpiDevice);
85e41f4b71Sopenharmony_ci   ```
86e41f4b71Sopenharmony_ci
87e41f4b71Sopenharmony_ci2. Add the **deviceNode** information to the **device_info.hcs** file and configure the device attributes in the **spi_config.hcs** file.
88e41f4b71Sopenharmony_ci
89e41f4b71Sopenharmony_ci   The **deviceNode** information is related to registration of the driver entry. The device attribute values are closely related to the default values or value ranges of the **SpiCntlr** members at the core layer.
90e41f4b71Sopenharmony_ci
91e41f4b71Sopenharmony_ci   In this example, there is only one SPI controller. If there are multiple SPI controllers, you need to add the **deviceNode** information to the **device_info** file and add the corresponding device attributes to the **spi_config** file for each controller.
92e41f4b71Sopenharmony_ci
93e41f4b71Sopenharmony_ci   - **device_info.hcs** configuration example
94e41f4b71Sopenharmony_ci   
95e41f4b71Sopenharmony_ci     
96e41f4b71Sopenharmony_ci     ```
97e41f4b71Sopenharmony_ci     root {
98e41f4b71Sopenharmony_ci       device_info {
99e41f4b71Sopenharmony_ci         match_attr = "hdf_manager";
100e41f4b71Sopenharmony_ci         platform :: host {
101e41f4b71Sopenharmony_ci           hostName = "platform_host";
102e41f4b71Sopenharmony_ci           priority = 50;
103e41f4b71Sopenharmony_ci           device_spi :: device {                            // Configure an HDF device node for each SPI controller.
104e41f4b71Sopenharmony_ci             device0 :: deviceNode {
105e41f4b71Sopenharmony_ci               policy = 1;
106e41f4b71Sopenharmony_ci               priority = 60;
107e41f4b71Sopenharmony_ci               permission = 0644;
108e41f4b71Sopenharmony_ci               moduleName = "HDF_PLATFORM_SPI";
109e41f4b71Sopenharmony_ci               serviceName = "HDF_PLATFORM_SPI_0";
110e41f4b71Sopenharmony_ci               deviceMatchAttr = "hisilicon_hi35xx_spi_0";
111e41f4b71Sopenharmony_ci             }
112e41f4b71Sopenharmony_ci             device1 :: deviceNode {
113e41f4b71Sopenharmony_ci               policy = 1;
114e41f4b71Sopenharmony_ci               priority = 60;
115e41f4b71Sopenharmony_ci               permission = 0644;
116e41f4b71Sopenharmony_ci               moduleName = "HDF_PLATFORM_SPI";             // (Mandatory) Driver name, which must be the same as that of moduleName in the driver entry structure.
117e41f4b71Sopenharmony_ci               serviceName = "HDF_PLATFORM_SPI_1";           // (Mandatory) Unique name of the service published by the driver.
118e41f4b71Sopenharmony_ci               deviceMatchAttr = "hisilicon_hi35xx_spi_1";       // The value must be the same as that of match_attr in the .hcs file.
119e41f4b71Sopenharmony_ci             }
120e41f4b71Sopenharmony_ci             ...
121e41f4b71Sopenharmony_ci           }
122e41f4b71Sopenharmony_ci         }
123e41f4b71Sopenharmony_ci       }
124e41f4b71Sopenharmony_ci     }
125e41f4b71Sopenharmony_ci     ```
126e41f4b71Sopenharmony_ci   
127e41f4b71Sopenharmony_ci   - **spi_config.hcs** configuration example
128e41f4b71Sopenharmony_ci   
129e41f4b71Sopenharmony_ci     
130e41f4b71Sopenharmony_ci     ```
131e41f4b71Sopenharmony_ci     root {
132e41f4b71Sopenharmony_ci       platform {
133e41f4b71Sopenharmony_ci         spi_config {                        // Configure private data for each SPI controller.
134e41f4b71Sopenharmony_ci           template spi_controller {           // Template configuration. In the template, you can configure the common parameters shared by device nodes.
135e41f4b71Sopenharmony_ci             serviceName = "";
136e41f4b71Sopenharmony_ci             match_attr = "";
137e41f4b71Sopenharmony_ci             transferMode = 0; // Data transfer mode. The value **0** indicates interrupt transfer, **1** indicates flow control transfer, and **2** indicates DMA transfer.
138e41f4b71Sopenharmony_ci             busNum = 0;           // Bus number.
139e41f4b71Sopenharmony_ci             clkRate = 100000000;
140e41f4b71Sopenharmony_ci             bitsPerWord = 8;                // Number of bits per word.
141e41f4b71Sopenharmony_ci             mode = 19;                      // SPI data input/output mode.
142e41f4b71Sopenharmony_ci             maxSpeedHz = 0;                 // Maximum clock frequency.
143e41f4b71Sopenharmony_ci             minSpeedHz = 0;                 // Minimum clock frequency.
144e41f4b71Sopenharmony_ci             speed = 2000000;                // Current message transfer speed.
145e41f4b71Sopenharmony_ci             fifoSize = 256;                 // FIFO size.
146e41f4b71Sopenharmony_ci             numCs = 1;                      // Chip select (CS) number.
147e41f4b71Sopenharmony_ci             regBase = 0x120c0000;           // Used for address mapping.
148e41f4b71Sopenharmony_ci             irqNum = 100;                   // Interrupt request (IRQ) number.
149e41f4b71Sopenharmony_ci             REG_CRG_SPI = 0x120100e4;       // CRG_REG_BASE(0x12010000) + 0x0e4
150e41f4b71Sopenharmony_ci             CRG_SPI_CKEN = 0;
151e41f4b71Sopenharmony_ci             CRG_SPI_RST = 0;
152e41f4b71Sopenharmony_ci             REG_MISC_CTRL_SPI = 0x12030024; // MISC_REG_BASE(0x12030000) + 0x24
153e41f4b71Sopenharmony_ci             MISC_CTRL_SPI_CS = 0;
154e41f4b71Sopenharmony_ci             MISC_CTRL_SPI_CS_SHIFT = 0;
155e41f4b71Sopenharmony_ci           }      
156e41f4b71Sopenharmony_ci           controller_0x120c0000 :: spi_controller {
157e41f4b71Sopenharmony_ci             busNum = 0;                           // (Mandatory) Bus number.
158e41f4b71Sopenharmony_ci             CRG_SPI_CKEN = 0x10000;               // (0x1 << 16) 0:close clk, 1:open clk 
159e41f4b71Sopenharmony_ci             CRG_SPI_RST = 0x1;                    // (0x1 << 0) 0:cancel reset, 1:reset 
160e41f4b71Sopenharmony_ci             match_attr = "hisilicon_hi35xx_spi_0";// (Mandatory) The value must be the same as that of deviceMatchAttr in device_info.hcs.
161e41f4b71Sopenharmony_ci           }      
162e41f4b71Sopenharmony_ci           controller_0x120c1000 :: spi_controller {
163e41f4b71Sopenharmony_ci             busNum = 1;
164e41f4b71Sopenharmony_ci             CRG_SPI_CKEN = 0x20000;    // (0x1 << 17) 0:close clk, 1:open clk
165e41f4b71Sopenharmony_ci             CRG_SPI_RST = 0x2;         // (0x1 << 1) 0:cancel reset, 1:reset 
166e41f4b71Sopenharmony_ci             match_attr = "hisilicon_hi35xx_spi_1"; 
167e41f4b71Sopenharmony_ci             regBase = 0x120c1000;      // (Mandatory) Used for address mapping.
168e41f4b71Sopenharmony_ci             irqNum = 101;              // (Mandatory) IRQ number.
169e41f4b71Sopenharmony_ci           }
170e41f4b71Sopenharmony_ci         ...
171e41f4b71Sopenharmony_ci         //(Optional) Add nodes to the device_info.hcs file as required.
172e41f4b71Sopenharmony_ci         }
173e41f4b71Sopenharmony_ci       }
174e41f4b71Sopenharmony_ci     }
175e41f4b71Sopenharmony_ci     ```
176e41f4b71Sopenharmony_ci
177e41f4b71Sopenharmony_ci3. Initialize the **SpiCntlr** 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 **SpiCntlrMethod** in **SpiCntlr** (so that the underlying driver functions can be called).
178e41f4b71Sopenharmony_ci
179e41f4b71Sopenharmony_ci   - Defining a custom structure
180e41f4b71Sopenharmony_ci
181e41f4b71Sopenharmony_ci     To the driver, the custom structure holds parameters and data. The **DeviceResourceIface** method provided by the HDF reads the values in the **spi_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 **SpiCntlr** object at the core layer.
182e41f4b71Sopenharmony_ci
183e41f4b71Sopenharmony_ci     
184e41f4b71Sopenharmony_ci      ```
185e41f4b71Sopenharmony_ci      struct Pl022 {// Corresponds to parameters in .hcs.
186e41f4b71Sopenharmony_ci          struct SpiCntlr *cntlr;
187e41f4b71Sopenharmony_ci          struct DListHead deviceList;
188e41f4b71Sopenharmony_ci          struct OsalSem sem;
189e41f4b71Sopenharmony_ci          volatile unsigned char *phyBase;
190e41f4b71Sopenharmony_ci          volatile unsigned char *regBase;
191e41f4b71Sopenharmony_ci          uint32_t irqNum;
192e41f4b71Sopenharmony_ci          uint32_t busNum;
193e41f4b71Sopenharmony_ci          uint32_t numCs;
194e41f4b71Sopenharmony_ci          uint32_t curCs;
195e41f4b71Sopenharmony_ci          uint32_t speed;
196e41f4b71Sopenharmony_ci          uint32_t fifoSize;
197e41f4b71Sopenharmony_ci          uint32_t clkRate;
198e41f4b71Sopenharmony_ci          uint32_t maxSpeedHz;
199e41f4b71Sopenharmony_ci          uint32_t minSpeedHz;
200e41f4b71Sopenharmony_ci          uint32_t regCrg;
201e41f4b71Sopenharmony_ci          uint32_t clkEnBit;
202e41f4b71Sopenharmony_ci          uint32_t clkRstBit;
203e41f4b71Sopenharmony_ci          uint32_t regMiscCtrl;
204e41f4b71Sopenharmony_ci          uint32_t miscCtrlCsShift;
205e41f4b71Sopenharmony_ci          uint32_t miscCtrlCs;
206e41f4b71Sopenharmony_ci          uint16_t mode;
207e41f4b71Sopenharmony_ci          uint8_t bitsPerWord;
208e41f4b71Sopenharmony_ci          uint8_t transferMode;
209e41f4b71Sopenharmony_ci      };
210e41f4b71Sopenharmony_ci      
211e41f4b71Sopenharmony_ci      // SpiCntlr is the core layer controller structure. The Init function assigns values to the members of SpiCntlr.
212e41f4b71Sopenharmony_ci      struct SpiCntlr {
213e41f4b71Sopenharmony_ci          struct IDeviceIoService service;
214e41f4b71Sopenharmony_ci          struct HdfDeviceObject *device;
215e41f4b71Sopenharmony_ci          uint32_t busNum;
216e41f4b71Sopenharmony_ci          uint32_t numCs;
217e41f4b71Sopenharmony_ci          uint32_t curCs;
218e41f4b71Sopenharmony_ci          struct OsalMutex lock;
219e41f4b71Sopenharmony_ci          struct SpiCntlrMethod *method;
220e41f4b71Sopenharmony_ci          struct DListHead list;
221e41f4b71Sopenharmony_ci          void *priv;
222e41f4b71Sopenharmony_ci      };
223e41f4b71Sopenharmony_ci      ```
224e41f4b71Sopenharmony_ci
225e41f4b71Sopenharmony_ci   - Instantiating **SpiCntlrMethod** in **SpiCntlr** (other members are initialized by **Init**)
226e41f4b71Sopenharmony_ci
227e41f4b71Sopenharmony_ci     
228e41f4b71Sopenharmony_ci      ```
229e41f4b71Sopenharmony_ci      // Example in spi_hi35xx.c: instantiate the hooks.
230e41f4b71Sopenharmony_ci      struct SpiCntlrMethod g_method = {
231e41f4b71Sopenharmony_ci          .Transfer = Pl022Transfer,
232e41f4b71Sopenharmony_ci          .SetCfg = Pl022SetCfg,
233e41f4b71Sopenharmony_ci          .GetCfg = Pl022GetCfg,
234e41f4b71Sopenharmony_ci          .Open = Pl022Open,
235e41f4b71Sopenharmony_ci          .Close = Pl022Close,
236e41f4b71Sopenharmony_ci      };
237e41f4b71Sopenharmony_ci      ```
238e41f4b71Sopenharmony_ci
239e41f4b71Sopenharmony_ci   - **Bind** function
240e41f4b71Sopenharmony_ci
241e41f4b71Sopenharmony_ci      **Input parameter**:
242e41f4b71Sopenharmony_ci
243e41f4b71Sopenharmony_ci      **HdfDeviceObject**, an interface parameter exposed by the driver, contains the .hcs information.
244e41f4b71Sopenharmony_ci
245e41f4b71Sopenharmony_ci      **Return value**:
246e41f4b71Sopenharmony_ci
247e41f4b71Sopenharmony_ci      **HDF_STATUS**
248e41f4b71Sopenharmony_ci
249e41f4b71Sopenharmony_ci      **Function description**:
250e41f4b71Sopenharmony_ci
251e41f4b71Sopenharmony_ci      Associates the **SpiCntlr** object with **HdfDeviceObject**.
252e41f4b71Sopenharmony_ci
253e41f4b71Sopenharmony_ci      
254e41f4b71Sopenharmony_ci      ```
255e41f4b71Sopenharmony_ci      static int32_t HdfSpiDeviceBind(struct HdfDeviceObject *device)
256e41f4b71Sopenharmony_ci      {
257e41f4b71Sopenharmony_ci          ...
258e41f4b71Sopenharmony_ci          return (SpiCntlrCreate(device) == NULL) ? HDF_FAILURE : HDF_SUCCESS;
259e41f4b71Sopenharmony_ci      }
260e41f4b71Sopenharmony_ci      
261e41f4b71Sopenharmony_ci      struct SpiCntlr *SpiCntlrCreate(struct HdfDeviceObject *device)
262e41f4b71Sopenharmony_ci      {
263e41f4b71Sopenharmony_ci          struct SpiCntlr *cntlr = NULL;                           // Create an SpiCntlr object.
264e41f4b71Sopenharmony_ci          ...
265e41f4b71Sopenharmony_ci          cntlr = (struct SpiCntlr *)OsalMemCalloc(sizeof(*cntlr));// Allocate memory.
266e41f4b71Sopenharmony_ci          ...
267e41f4b71Sopenharmony_ci          cntlr->device = device;                                  // Prerequisites for conversion between HdfDeviceObject and SpiCntlr.
268e41f4b71Sopenharmony_ci          device->service = &(cntlr->service);                     // Prerequisites for conversion between HdfDeviceObject and SpiCntlr.
269e41f4b71Sopenharmony_ci          (void)OsalMutexInit(&cntlr->lock);                       // Initialize the lock.
270e41f4b71Sopenharmony_ci          DListHeadInit(&cntlr->list);                             // Add nodes.
271e41f4b71Sopenharmony_ci          cntlr->priv = NULL;
272e41f4b71Sopenharmony_ci          return cntlr;
273e41f4b71Sopenharmony_ci      }
274e41f4b71Sopenharmony_ci      ```
275e41f4b71Sopenharmony_ci
276e41f4b71Sopenharmony_ci   - **Init** function
277e41f4b71Sopenharmony_ci
278e41f4b71Sopenharmony_ci      **Input parameter**:
279e41f4b71Sopenharmony_ci
280e41f4b71Sopenharmony_ci      **HdfDeviceObject**, an interface parameter exposed 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/framework/include/utils/hdf_base.h** file.
285e41f4b71Sopenharmony_ci
286e41f4b71Sopenharmony_ci        **Table 2** Description of HDF_STATUS
287e41f4b71Sopenharmony_ci      
288e41f4b71Sopenharmony_ci      | Status| Description|
289e41f4b71Sopenharmony_ci      | -------- | -------- |
290e41f4b71Sopenharmony_ci      | HDF_ERR_INVALID_OBJECT | Invalid controller object.|
291e41f4b71Sopenharmony_ci      | HDF_ERR_MALLOC_FAIL | Failed to allocate memory.|
292e41f4b71Sopenharmony_ci      | HDF_ERR_INVALID_PARAM | Invalid parameter.|
293e41f4b71Sopenharmony_ci      | HDF_ERR_IO | I/O error.|
294e41f4b71Sopenharmony_ci      | HDF_SUCCESS | Initialization successful.|
295e41f4b71Sopenharmony_ci      | HDF_FAILURE | Initialization failed.|
296e41f4b71Sopenharmony_ci
297e41f4b71Sopenharmony_ci      **Function description**:
298e41f4b71Sopenharmony_ci
299e41f4b71Sopenharmony_ci      Initializes the custom structure object and **SpiCntlr**.
300e41f4b71Sopenharmony_ci
301e41f4b71Sopenharmony_ci      
302e41f4b71Sopenharmony_ci      ```
303e41f4b71Sopenharmony_ci      static int32_t HdfSpiDeviceInit(struct HdfDeviceObject *device)
304e41f4b71Sopenharmony_ci      {
305e41f4b71Sopenharmony_ci      int32_t ret;
306e41f4b71Sopenharmony_ci      struct SpiCntlr *cntlr = NULL;
307e41f4b71Sopenharmony_ci      ...
308e41f4b71Sopenharmony_ci      cntlr = SpiCntlrFromDevice(device); // Forcibly convert HdfDeviceObject to SpiCntlr using service. For details about the value assignment, see the Bind function.
309e41f4b71Sopenharmony_ci                                          // return (device == NULL) ? NULL : (struct SpiCntlr *)device->service;
310e41f4b71Sopenharmony_ci      ...
311e41f4b71Sopenharmony_ci      ret = Pl022Init(cntlr, device);     // (Mandatory) Instantiate the custom operation object. The following is an example:
312e41f4b71Sopenharmony_ci      ...
313e41f4b71Sopenharmony_ci      ret = Pl022Probe(cntlr->priv);
314e41f4b71Sopenharmony_ci      ...
315e41f4b71Sopenharmony_ci      return ret;
316e41f4b71Sopenharmony_ci      }
317e41f4b71Sopenharmony_ci      
318e41f4b71Sopenharmony_ci      static int32_t Pl022Init(struct SpiCntlr *cntlr, const struct HdfDeviceObject *device)
319e41f4b71Sopenharmony_ci      {
320e41f4b71Sopenharmony_ci      int32_t ret;
321e41f4b71Sopenharmony_ci      struct Pl022 *pl022 = NULL;
322e41f4b71Sopenharmony_ci      ...
323e41f4b71Sopenharmony_ci      pl022 = (struct Pl022 *)OsalMemCalloc(sizeof(*pl022));// Request memory.
324e41f4b71Sopenharmony_ci      ...
325e41f4b71Sopenharmony_ci      ret = SpiGetBaseCfgFromHcs(pl022, device->property);  // Initialize busNum, numCs, speed, fifoSize, clkRate, mode, bitsPerWord, and transferMode.
326e41f4b71Sopenharmony_ci      ...
327e41f4b71Sopenharmony_ci      ret = SpiGetRegCfgFromHcs(pl022, device->property);   // Initialize regBase, phyBase, irqNum, regCrg, clkEnBit, clkRstBit, regMiscCtrl, regMiscCtrl, miscCtrlCs, and miscCtrlCsShift.
328e41f4b71Sopenharmony_ci      ...
329e41f4b71Sopenharmony_ci      // Calculate the frequencies corresponding to the maximum and minimum speeds.
330e41f4b71Sopenharmony_ci      pl022->maxSpeedHz = (pl022->clkRate) / ((SCR_MIN + 1) * CPSDVSR_MIN);
331e41f4b71Sopenharmony_ci      pl022->minSpeedHz = (pl022->clkRate) / ((SCR_MAX + 1) * CPSDVSR_MAX);
332e41f4b71Sopenharmony_ci      DListHeadInit(&pl022->deviceList);// Initialize the DList linked list.
333e41f4b71Sopenharmony_ci      pl022->cntlr = cntlr;              // Prerequisite for conversion between Pl022 and SpiCntlr.
334e41f4b71Sopenharmony_ci      cntlr->priv = pl022;               // Prerequisite for conversion between Pl022 and SpiCntlr.
335e41f4b71Sopenharmony_ci      cntlr->busNum = pl022->busNum;     // Assign a value to busNum in SpiCntlr.
336e41f4b71Sopenharmony_ci      cntlr->method = &g_method;         // Attach the SpiCntlrMethod instance.
337e41f4b71Sopenharmony_ci      ...
338e41f4b71Sopenharmony_ci      ret = Pl022CreatAndInitDevice(pl022);
339e41f4b71Sopenharmony_ci      if (ret != 0) {
340e41f4b71Sopenharmony_ci          Pl022Release(pl022);           // Release the Pl022 object if the initialization fails.
341e41f4b71Sopenharmony_ci          return ret;
342e41f4b71Sopenharmony_ci      }
343e41f4b71Sopenharmony_ci      return 0;
344e41f4b71Sopenharmony_ci      }
345e41f4b71Sopenharmony_ci      ```
346e41f4b71Sopenharmony_ci   - **Release** function
347e41f4b71Sopenharmony_ci
348e41f4b71Sopenharmony_ci      **Input parameter**:
349e41f4b71Sopenharmony_ci
350e41f4b71Sopenharmony_ci      **HdfDeviceObject**, an interface parameter exposed by the driver, contains the .hcs information.
351e41f4b71Sopenharmony_ci
352e41f4b71Sopenharmony_ci      **Return value**:
353e41f4b71Sopenharmony_ci
354e41f4b71Sopenharmony_ci      No value is returned.
355e41f4b71Sopenharmony_ci
356e41f4b71Sopenharmony_ci      **Function description**:
357e41f4b71Sopenharmony_ci
358e41f4b71Sopenharmony_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.
359e41f4b71Sopenharmony_ci
360e41f4b71Sopenharmony_ci      > ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br>
361e41f4b71Sopenharmony_ci      > All forced conversion operations for obtaining the corresponding object can be successful only when **Init()** has the corresponding value assignment operations.
362e41f4b71Sopenharmony_ci
363e41f4b71Sopenharmony_ci      
364e41f4b71Sopenharmony_ci      ```
365e41f4b71Sopenharmony_ci      static void HdfSpiDeviceRelease(struct HdfDeviceObject *device)
366e41f4b71Sopenharmony_ci      {
367e41f4b71Sopenharmony_ci          struct SpiCntlr *cntlr = NULL;
368e41f4b71Sopenharmony_ci          ...
369e41f4b71Sopenharmony_ci          cntlr = SpiCntlrFromDevice(device);             // Forced conversion from HdfDeviceObject to SpiCntlr is involved. For details about the value assignment, see the Bind function.
370e41f4b71Sopenharmony_ci                                                          // return (device==NULL) ?NULL:(struct SpiCntlr *)device->service;
371e41f4b71Sopenharmony_ci          ...
372e41f4b71Sopenharmony_ci          if (cntlr->priv != NULL) {
373e41f4b71Sopenharmony_ci              Pl022Remove((struct Pl022 *)cntlr->priv);// A forced conversion from SpiCntlr to Pl022 is involved.
374e41f4b71Sopenharmony_ci          }
375e41f4b71Sopenharmony_ci          SpiCntlrDestroy(cntlr);                         // Release the Pl022 object.
376e41f4b71Sopenharmony_ci      }
377e41f4b71Sopenharmony_ci      ```
378