• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# SPI<a name="EN-US_TOPIC_0000001199690327"></a>
2
3
4## Overview<a name="section84922229152909"></a>
5
6In the Hardware Driver Foundation \(HDF\), the Serial Peripheral Interface \(SPI\) uses the independent service mode for API adaptation. In this mode, each device independently publishes a device service to handle external access requests. After receiving an access request from an API, the device manager extracts the parameters in the request to call the internal method of the target device. In the independent service mode, the service management capabilities of the HDFDeviceManager can be directly used. However, you need to configure a device node for each device, which increases the memory usage.
7
8**Figure  1**  Independent service mode<a name="fig666465313303"></a>
9![](figures/independent-service-mode.png "SPI-independent-service-mode")
10
11## Available APIs<a name="section752964871810"></a>
12
13SpiCntlrMethod:
14
15```
16struct SpiCntlrMethod {
17  int32_t (*GetCfg)(struct SpiCntlr *cntlr, struct SpiCfg *cfg);
18  int32_t (*SetCfg)(struct SpiCntlr *cntlr, struct SpiCfg *cfg);
19  int32_t (*Transfer)(struct SpiCntlr *cntlr, struct SpiMsg *msg, uint32_t count);
20  int32_t (*Open)(struct SpiCntlr *cntlr);
21  int32_t (*Close)(struct SpiCntlr *cntlr);
22};
23```
24**Table  1**  Callbacks for the members in the SpiCntlrMethod structure
25
26<a name="table7167123615321"></a>
27<table><thead align="left"><tr id="row816783615326"><th class="cellrowborder" valign="top" width="25%" id="mcps1.2.5.1.1"><p id="p8167193643218"><a name="p8167193643218"></a><a name="p8167193643218"></a>Callback</p>
28</th>
29<th class="cellrowborder" valign="top" width="25%" id="mcps1.2.5.1.2"><p id="p31672362325"><a name="p31672362325"></a><a name="p31672362325"></a>Input Parameter</p>
30</th>
31<th class="cellrowborder" valign="top" width="24.98%" id="mcps1.2.5.1.3"><p id="p51673367328"><a name="p51673367328"></a><a name="p51673367328"></a>Return Value</p>
32</th>
33<th class="cellrowborder" valign="top" width="25.019999999999996%" id="mcps1.2.5.1.4"><p id="p1116883619322"><a name="p1116883619322"></a><a name="p1116883619322"></a>Description</p>
34</th>
35</tr>
36</thead>
37<tbody><tr id="row816883693214"><td class="cellrowborder" valign="top" width="25%" headers="mcps1.2.5.1.1 "><p id="p11683369329"><a name="p11683369329"></a><a name="p11683369329"></a>Transfer</p>
38</td>
39<td class="cellrowborder" valign="top" width="25%" headers="mcps1.2.5.1.2 "><p id="p0671913132514"><a name="p0671913132514"></a><a name="p0671913132514"></a><strong id="b19675134258"><a name="b19675134258"></a><a name="b19675134258"></a>cntlr</strong>: structure pointer to the SPI controller at the core layer.</p>
40<p id="p192109186258"><a name="p192109186258"></a><a name="p192109186258"></a><strong id="b1921051810258"><a name="b1921051810258"></a><a name="b1921051810258"></a>msg</strong>: structure pointer to the SPI message.</p>
41<p id="p6168736173213"><a name="p6168736173213"></a><a name="p6168736173213"></a><strong id="b92627310191"><a name="b92627310191"></a><a name="b92627310191"></a>count</strong>: number of messages. The value is of the uint32_t type.</p>
42</td>
43<td class="cellrowborder" valign="top" width="24.98%" headers="mcps1.2.5.1.3 "><p id="p19168736113216"><a name="p19168736113216"></a><a name="p19168736113216"></a>HDF_STATUS</p>
44</td>
45<td class="cellrowborder" valign="top" width="25.019999999999996%" headers="mcps1.2.5.1.4 "><p id="p18168236143218"><a name="p18168236143218"></a><a name="p18168236143218"></a>Transfers messages.</p>
46</td>
47</tr>
48<tr id="row3168113633211"><td class="cellrowborder" valign="top" width="25%" headers="mcps1.2.5.1.1 "><p id="p4168636193212"><a name="p4168636193212"></a><a name="p4168636193212"></a>SetCfg</p>
49</td>
50<td class="cellrowborder" valign="top" width="25%" headers="mcps1.2.5.1.2 "><p id="p242632402513"><a name="p242632402513"></a><a name="p242632402513"></a><strong id="b742642452513"><a name="b742642452513"></a><a name="b742642452513"></a>cntlr</strong>: structure pointer to the SPI controller at the core layer.</p>
51<p id="p11168163643217"><a name="p11168163643217"></a><a name="p11168163643217"></a><strong id="b1283910558207"><a name="b1283910558207"></a><a name="b1283910558207"></a>cfg</strong>: structure pointer to the SPI attributes.</p>
52</td>
53<td class="cellrowborder" valign="top" width="24.98%" headers="mcps1.2.5.1.3 "><p id="p101683367325"><a name="p101683367325"></a><a name="p101683367325"></a>HDF_STATUS</p>
54</td>
55<td class="cellrowborder" valign="top" width="25.019999999999996%" headers="mcps1.2.5.1.4 "><p id="p1216815368329"><a name="p1216815368329"></a><a name="p1216815368329"></a>Sets SPI controller attributes.</p>
56</td>
57</tr>
58<tr id="row13168183683215"><td class="cellrowborder" valign="top" width="25%" headers="mcps1.2.5.1.1 "><p id="p11168436123220"><a name="p11168436123220"></a><a name="p11168436123220"></a>GetCfg</p>
59</td>
60<td class="cellrowborder" valign="top" width="25%" headers="mcps1.2.5.1.2 "><p id="p9698153182520"><a name="p9698153182520"></a><a name="p9698153182520"></a><strong id="b19698131162510"><a name="b19698131162510"></a><a name="b19698131162510"></a>cntlr</strong>: structure pointer to the SPI controller at the core layer.</p>
61<p id="p3168936133218"><a name="p3168936133218"></a><a name="p3168936133218"></a><strong id="b11555148182113"><a name="b11555148182113"></a><a name="b11555148182113"></a>cfg</strong>: structure pointer to the SPI attributes.</p>
62</td>
63<td class="cellrowborder" valign="top" width="24.98%" headers="mcps1.2.5.1.3 "><p id="p18169036193219"><a name="p18169036193219"></a><a name="p18169036193219"></a>HDF_STATUS</p>
64</td>
65<td class="cellrowborder" valign="top" width="25.019999999999996%" headers="mcps1.2.5.1.4 "><p id="p3169136173219"><a name="p3169136173219"></a><a name="p3169136173219"></a>Obtains SPI controller attributes.</p>
66</td>
67</tr>
68<tr id="row9169133643218"><td class="cellrowborder" valign="top" width="25%" headers="mcps1.2.5.1.1 "><p id="p13169163615320"><a name="p13169163615320"></a><a name="p13169163615320"></a>Open</p>
69</td>
70<td class="cellrowborder" valign="top" width="25%" headers="mcps1.2.5.1.2 "><p id="p181697365327"><a name="p181697365327"></a><a name="p181697365327"></a><strong id="b1876822162218"><a name="b1876822162218"></a><a name="b1876822162218"></a>cntlr</strong>: structure pointer to the SPI controller at the core layer. </p>
71</td>
72<td class="cellrowborder" valign="top" width="24.98%" headers="mcps1.2.5.1.3 "><p id="p1169163693216"><a name="p1169163693216"></a><a name="p1169163693216"></a>HDF_STATUS</p>
73</td>
74<td class="cellrowborder" valign="top" width="25.019999999999996%" headers="mcps1.2.5.1.4 "><p id="p1116963693218"><a name="p1116963693218"></a><a name="p1116963693218"></a>Enables the SPI.</p>
75</td>
76</tr>
77<tr id="row11169436153214"><td class="cellrowborder" valign="top" width="25%" headers="mcps1.2.5.1.1 "><p id="p0169736153219"><a name="p0169736153219"></a><a name="p0169736153219"></a>Close</p>
78</td>
79<td class="cellrowborder" valign="top" width="25%" headers="mcps1.2.5.1.2 "><p id="p31691936193210"><a name="p31691936193210"></a><a name="p31691936193210"></a><strong id="b16798152112239"><a name="b16798152112239"></a><a name="b16798152112239"></a>cntlr</strong>: structure pointer to the SPI controller at the core layer. </p>
80</td>
81<td class="cellrowborder" valign="top" width="24.98%" headers="mcps1.2.5.1.3 "><p id="p2169123617322"><a name="p2169123617322"></a><a name="p2169123617322"></a>HDF_STATUS</p>
82</td>
83<td class="cellrowborder" valign="top" width="25.019999999999996%" headers="mcps1.2.5.1.4 "><p id="p1169636103220"><a name="p1169636103220"></a><a name="p1169636103220"></a>Disables the SPI.</p>
84</td>
85</tr>
86</tbody>
87</table>
88
89## How to Develop<a name="section799667984152909"></a>
90
91The SPI module adaptation involves the following steps:
92
931.  Instantiate the driver entry.
94    -   Instantiate the  **HdfDriverEntry**  structure.
95    -   Call  **HDF\_INIT**  to register the  **HdfDriverEntry**  instance with the HDF.
96
972.  Configure attribute files.
98    -   Add the  **deviceNode**  information to the  **device\_info.hcs**  file.
99    -   \(Optional\) Add the  **spi\_config.hcs**  file.
100
1013.  Instantiate the SPI controller object.
102    -   Initialize  **SpiCntlr**.
103    -   Instantiate  **SpiCntlrMethod**  in the  **SpiCntlr**  object.
104
105        >![](../public_sys-resources/icon-note.gif) **NOTE**
106
107        >For details, see [Available APIs](#section752964871810).
108
1094.  Debug the driver.
110    -   \(Optional\) For new drivers, verify the basic functions, such as the SPI control status and response to interrupts.
111
112
113## Development Example<a name="section956157227152909"></a>
114
115The following uses  **spi\_hi35xx.c**  as an example to present the contents that need to be provided by the vendor to implement device functions.
116
1171.  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, 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.
118
119    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.
120
121    -   SPI driver entry reference
122
123        ```
124        struct HdfDriverEntry g_hdfSpiDevice = {
125            .moduleVersion = 1,
126            .moduleName = "HDF_PLATFORM_SPI",// (Mandatory) The value must be the same as that of moduleName in the .hcs file.
127                .Bind = HdfSpiDeviceBind,   // See the Bind function.
128         .Init = HdfSpiDeviceInit, // See the Init function.
129             .Release = HdfSpiDeviceRelease,  //See the Release function.
130        };
131        // Call HDF_INIT to register the driver entry with the HDF.
132        HDF_INIT(g_hdfSpiDevice);
133        ```
134
1352.  Add the  **deviceNode**  information to the  **device\_info.hcs**  file and configure the device attributes in the  **spi\_config.hcs**  file. 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.
136
137    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.
138
139    -   **device\_info.hcs**  configuration reference
140
141        ```
142        root {
143        device_info {
144            match_attr = "hdf_manager";
145            platform :: host {
146            hostName = "platform_host";
147            priority = 50;
148            device_spi :: device {// Configure an HDF device node for each SPI controller.
149                device0 :: deviceNode {
150                policy = 1;
151                priority = 60;
152                permission = 0644;
153                moduleName = "HDF_PLATFORM_SPI";
154                serviceName = "HDF_PLATFORM_SPI_0";
155                deviceMatchAttr = "hisilicon_hi35xx_spi_0";
156                }
157                device1 :: deviceNode {
158                policy = 1;
159                priority = 60;
160                permission = 0644;
161                moduleName = "HDF_PLATFORM_SPI"; // (Mandatory) Driver name, which must be the same as that of moduleName in the driver entry structure.
162                   serviceName = "HDF_PLATFORM_SPI_1"; // (Mandatory) Unique name of the service published by the driver
163                deviceMatchAttr = "hisilicon_hi35xx_spi_1";// The value must be the same as that of match_attr in the .hcs file.
164                }
165                ...
166            }
167            }
168        }
169        }
170        ```
171
172    -   **spi\_config.hcs**  configuration reference
173
174        ```
175        root {
176        platform {
177            spi_config {// Configure private data for each SPI controller.
178              template spi_controller {// Template configuration. In the template, you can configure the common parameters shared by service nodes.
179                serviceName = "";
180                match_attr = "";
181                transferMode = 0; // Data transfer mode, which can be interrupt transfer (0), flow control transfer (1), or DMA transfer (2).
182                busNum = 0; // Bus number
183                clkRate = 100000000;
184                bitsPerWord = 8; // Bit width of the data transferred
185                mode = 19; // SPI data input/output mode
186                maxSpeedHz = 0; // Maximum clock frequency
187                minSpeedHz = 0;  // Minimum clock frequency
188                speed = 2000000; // Current message transfer speed
189                fifoSize = 256; // FIFO size
190                numCs = 1; // Chip select (CS) number
191                regBase = 0x120c0000; // Used for address mapping.
192                irqNum = 100; // Interruption number
193                REG_CRG_SPI = 0x120100e4;       // CRG_REG_BASE(0x12010000) + 0x0e4
194                CRG_SPI_CKEN = 0;
195                CRG_SPI_RST = 0;
196                REG_MISC_CTRL_SPI = 0x12030024; // MISC_REG_BASE(0x12030000) + 0x24
197                MISC_CTRL_SPI_CS = 0;
198                MISC_CTRL_SPI_CS_SHIFT = 0;
199            }
200            controller_0x120c0000 :: spi_controller {
201                busNum = 0; // (Mandatory) Bus number
202                CRG_SPI_CKEN = 0x10000;    // (0x1 << 16) 0:close clk, 1:open clk
203                CRG_SPI_RST = 0x1;         // (0x1 << 0) 0:cancel reset, 1:reset
204                  match_attr = "hisilicon_hi35xx_spi_0";// (Mandatory) The value must be the same as that of deviceMatchAttr in device_info.hcs.
205            }
206            controller_0x120c1000 :: spi_controller {
207                busNum = 1;
208                CRG_SPI_CKEN = 0x20000;    // (0x1 << 17) 0:close clk, 1:open clk
209                CRG_SPI_RST = 0x2;         // (0x1 << 1) 0:cancel reset, 1:reset
210                match_attr = "hisilicon_hi35xx_spi_1";
211                regBase = 0x120c1000; // (Mandatory) Used for address mapping.
212                   irqNum = 101; // (Mandatory) Interrupt number
213            }
214            ...
215            //(Optional) Add nodes to the device_info.hcs file as required.
216            }
217        }
218        }
219        ```
220
2213.  Initialize the  **SpiCntlr**  object at the core layer, including initializing the vendor custom structure \(transferring parameters and data\), instantiating  **SpiCntlrMethod** \(used to call underlying functions of the driver\) in  **SpiCntlr**, and implementing the  **HdfDriverEntry**  member functions \(**Bind**,  **Init**, and  **Release**\).
222    -   Custom structure reference
223
224        To the driver, the custom structure carries parameters and data. The values in the  **spi\_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 object at the core layer.
225
226        ```
227        struct Pl022 {// Corresponds to parameters in .hcs.
228            struct SpiCntlr *cntlr;
229            struct DListHead deviceList;
230            struct OsalSem sem;
231            volatile unsigned char *phyBase;
232            volatile unsigned char *regBase;
233            uint32_t irqNum;
234            uint32_t busNum;
235            uint32_t numCs;
236            uint32_t curCs;
237            uint32_t speed;
238            uint32_t fifoSize;
239            uint32_t clkRate;
240            uint32_t maxSpeedHz;
241            uint32_t minSpeedHz;
242            uint32_t regCrg;
243            uint32_t clkEnBit;
244            uint32_t clkRstBit;
245            uint32_t regMiscCtrl;
246            uint32_t miscCtrlCsShift;
247            uint32_t miscCtrlCs;
248            uint16_t mode;
249            uint8_t bitsPerWord;
250            uint8_t transferMode;
251        };
252
253        // SpiCntlr is the core layer controller structure. Its members are assigned with values by using the Init function.
254        struct SpiCntlr {
255            struct IDeviceIoService service;
256            struct HdfDeviceObject *device;
257            uint32_t busNum;
258            uint32_t numCs;
259            uint32_t curCs;
260            struct OsalMutex lock;
261            struct SpiCntlrMethod *method;
262            struct DListHead list;
263            void *priv;
264        };
265        ```
266
267    -   Instantiate the callback function structure  **SpiCntlrMethod**  in  **SpiCntlr**. Other members are initialized by using the  **Init**  function.
268
269        ```
270        // Example in spi_hi35xx.c: instantiate the hook.
271        struct SpiCntlrMethod g_method = {
272            .Transfer = Pl022Transfer,
273            .SetCfg = Pl022SetCfg,
274            .GetCfg = Pl022GetCfg,
275            .Open = Pl022Open,
276            .Close = Pl022Close,
277        };
278        ```
279
280    -   Bind function
281
282        Input parameters:
283
284        **HdfDeviceObject**, an interface parameter exposed by the driver, contains the .hcs configuration file information.
285
286        Return values:
287
288        HDF\_STATUS
289
290        Function description:
291
292        Associates the  **SpiCntlr**  object with  **HdfDeviceObject**.
293
294        ```
295        static int32_t HdfSpiDeviceBind(struct HdfDeviceObject *device)
296        {
297            ...
298            return (SpiCntlrCreate(device) == NULL) ? HDF_FAILURE : HDF_SUCCESS;
299        }
300
301        struct SpiCntlr *SpiCntlrCreate(struct HdfDeviceObject *device)
302        {
303            struct SpiCntlr *cntlr = NULL; // Create the SpiCntlr object of the core layer.
304            ...
305             cntlr = (struct SpiCntlr *)OsalMemCalloc(sizeof(*cntlr));// Allocate memory.
306            ...
307            cntlr->device = device; // Enable conversion between HdfDeviceObject and SpiCntlr.
308             device->service = &(cntlr->service); // Enable conversion between HdfDeviceObject and SpiCntlr.
309            (void)OsalMutexInit(&cntlr->lock); // Initialize the lock.
310            DListHeadInit(&cntlr->list); // Add the corresponding node.
311            cntlr->priv = NULL;
312            return cntlr;
313        }
314        ```
315
316    -   Init function
317
318        Input parameters:
319
320        **HdfDeviceObject**, an interface parameter exposed by the driver, contains the .hcs configuration file information.
321
322        Return values:
323
324        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.\)
325
326        **Table  2**  Input parameters and return values of the init function
327
328        <a name="table4311552173914"></a>
329        <table><thead align="left"><tr id="row8314152103916"><th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.1"><p id="p331413523392"><a name="p331413523392"></a><a name="p331413523392"></a>Status (Value)</p>
330        </th>
331        <th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.2"><p id="p7314145220390"><a name="p7314145220390"></a><a name="p7314145220390"></a>Description</p>
332        </th>
333        </tr>
334        </thead>
335        <tbody><tr id="row93142052183918"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p93141252123914"><a name="p93141252123914"></a><a name="p93141252123914"></a>HDF_ERR_INVALID_OBJECT</p>
336        </td>
337        <td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p331485215390"><a name="p331485215390"></a><a name="p331485215390"></a>Invalid controller object</p>
338        </td>
339        </tr>
340        <tr id="row331445211399"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p83141352183917"><a name="p83141352183917"></a><a name="p83141352183917"></a>HDF_ERR_MALLOC_FAIL</p>
341        </td>
342        <td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p15314175220397"><a name="p15314175220397"></a><a name="p15314175220397"></a>Failed to allocate memory</p>
343        </td>
344        </tr>
345        <tr id="row20314175213918"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p9314352113917"><a name="p9314352113917"></a><a name="p9314352113917"></a>HDF_ERR_INVALID_PARAM</p>
346        </td>
347        <td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p131535273910"><a name="p131535273910"></a><a name="p131535273910"></a>Invalid parameter</p>
348        </td>
349        </tr>
350        <tr id="row1431565233911"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p0315052103915"><a name="p0315052103915"></a><a name="p0315052103915"></a>HDF_ERR_IO</p>
351        </td>
352        <td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p1831585215398"><a name="p1831585215398"></a><a name="p1831585215398"></a>I/O error</p>
353        </td>
354        </tr>
355        <tr id="row2315152193914"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p7315185263919"><a name="p7315185263919"></a><a name="p7315185263919"></a>HDF_SUCCESS</p>
356        </td>
357        <td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p1731585213910"><a name="p1731585213910"></a><a name="p1731585213910"></a>Initialization successful</p>
358        </td>
359        </tr>
360        <tr id="row5315752163916"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p6315105211392"><a name="p6315105211392"></a><a name="p6315105211392"></a>HDF_FAILURE</p>
361        </td>
362        <td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p83157528399"><a name="p83157528399"></a><a name="p83157528399"></a>Initialization failed</p>
363        </td>
364        </tr>
365        </tbody>
366        </table>
367
368        Function description:
369
370        Initializes the custom structure object and  **SpiCntlr**.
371
372        ```
373        static int32_t HdfSpiDeviceInit(struct HdfDeviceObject *device)
374        {
375        int32_t ret;
376        struct SpiCntlr *cntlr = NULL;
377        ...
378            cntlr = SpiCntlrFromDevice(device);// Forcibly convert HdfDeviceObject to SpiCntlr by using service. For details about the value assignment, see the Bind function.
379                                            //return (device == NULL) ? NULL : (struct SpiCntlr *)device->service;
380        ...
381        ret = Pl022Init(cntlr, device);// (Mandatory) Instantiate the operation object customized by the vendor. The following is an example:
382        ...
383        ret = Pl022Probe(cntlr->priv);
384        ...
385        return ret;
386        }
387
388        static int32_t Pl022Init(struct SpiCntlr *cntlr, const struct HdfDeviceObject *device)
389        {
390        int32_t ret;
391        struct Pl022 *pl022 = NULL;
392        ...
393        pl022 = (struct Pl022 *)OsalMemCalloc(sizeof(*pl022));// Apply for memory.
394        ...
395        ret = SpiGetBaseCfgFromHcs(pl022, device->property); // Initialize busNum, numCs, speed, fifoSize, clkRate, mode, bitsPerWord, and transferMode.
396        ...
397        ret = SpiGetRegCfgFromHcs(pl022, device->property); // Initialize regBase, phyBase, irqNum, regCrg, clkEnBit ,clkRstBit, regMiscCtrl, miscCtrlCs, and miscCtrlCsShift.
398        ...
399        // Calculate the frequencies corresponding to the maximum and minimum speeds.
400        pl022->maxSpeedHz = (pl022->clkRate) / ((SCR_MIN + 1) * CPSDVSR_MIN);
401        pl022->minSpeedHz = (pl022->clkRate) / ((SCR_MAX + 1) * CPSDVSR_MAX);
402        DListHeadInit(&pl022->deviceList);// Initialize the DList linked list.
403        pl022->cntlr = cntlr;                // Enable conversion between Pl022 and SpiCntlr.
404        cntlr->priv = pl022;              // Enable conversion between Pl022 and SpiCntlr.
405        cntlr->busNum = pl022->busNum;    // Assign a value to busNum in SpiCntlr.
406        cntlr->method = &g_method;        // Connect to the SpiCntlrMethod instance.
407        ...
408        ret = Pl022CreatAndInitDevice(pl022);
409        if (ret != 0) {
410            Pl022Release(pl022);             // Release the Pl022 object if the initialization fails.
411            return ret;
412        }
413        return 0;
414        }
415        ```
416
417    -   Release function
418
419        Input parameters:
420
421        **HdfDeviceObject**, an interface parameter exposed by the driver, contains the .hcs configuration file information.
422
423        Return values:
424
425426
427        Function description:
428
429        Releases the memory and deletes the controller. This function assigns a value to the  **Release**  API in the driver entry structure. When the HDF fails to call the  **Init**  function to initialize the driver, the  **Release**  function can be called to release driver resources. All forced conversion operations for obtaining the corresponding object can be successful only when the  **Init**  function has the corresponding value assignment operations.
430
431        ```
432        static void HdfSpiDeviceRelease(struct HdfDeviceObject *device)
433        {
434            struct SpiCntlr *cntlr = NULL;
435            ...
436            cntlr = SpiCntlrFromDevice(device);// Forcibly convert HdfDeviceObject to SpiCntlr by using service. For details about the value assignment, see the Bind function.
437                                            // return (device==NULL) ?NULL:(struct SpiCntlr *)device->service;
438            ...
439            if (cntlr->priv != NULL) {
440                Pl022Remove((struct Pl022 *)cntlr->priv);// A forced conversion from SpiCntlr to Pl022 is involved.
441            }
442            SpiCntlrDestroy(cntlr);                         // Release the Pl022 object.
443        }
444        ```
445
446
447
448
449