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  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 >  **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 >  **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