1# Audio
2
3
4## Audio Driver Overview
5
6A multimedia system is an indispensable part in Internet of Things (IoT) devices. Audio is an important module of the multimedia system, and building an audio driver model is particularly important in device development.
7
8This document describes the audio driver architecture and functional modules and how to develop audio drivers based on the Hardware Driver Foundation (HDF). You can develop your own drivers and call Hardware Abstraction Layer (HAL) APIs based on this driver architecture.
9
10
11
12## Audio Driver Architecture
13
14The audio driver framework is implemented based on the [HDF](driver-overview-foundation.md). The following figure illustrates the audio driver architecture.
15
16![](figures/Audio_architecture.png)
17
18The driver architecture consists of the following:
19- Hardware Device Interface (HDI) adapter: implements the audio HAL driver (for HDI adaptation) and provides hardware driver APIs for audio services (frameworks). The HDI adapter provides API objects such as **AudioManager**, **AudioAdapter**, **AudioControl**, **AudioCapture**, and **AudioRender**.
20- Audio Interface Lib: works with the Audio Driver Model (ADM) in the kernel to control audio hardware, read recording data, and write playback data. The **Stream_ctrl_common** in the Audio Interface Lib interacts with the Audio HDI Adapter layer.
21- ADM: helps system developers to develop scenario-specific applications for the multimedia audio subsystem. With the ADM, codec and DSP device vendors can adapt their driver code based on the APIs provided by the ADM and implement quick development and easy adaptation to the OpenHarmony system.
22- Audio Control Dispatch: dispatches the control instructions from the Audio Interface Lib to the driver layer.
23- Audio Stream Dispatch: dispatches the data from the Audio Interface Lib to the driver layer.
24
25- Card Manager: manages multiple audio adapters. Each audio adapter consists of the digital audio interface (DAI), platform, codec, DSP, and Smart Audio Power Manager (SAPM) modules.
26- Platform Drivers: driver adaptation layer.
27- SAPM: optimizes the power consumption policy of the ADM.
28
29## Audio Driver Development
30
31The following uses the Hi3516D V300 as an example to describe how to develop drivers based on the audio driver architecture.
32
33### Audio ADM Architecture
34
35The audio driver provides the **hdf_audio_render**, **hdf_audio_capture**, and **hdf_audio_control** services for the HDI layer. The driver service nodes in the **dev** directory of the development board are as follows:
36
37```shell
38# ls -l hdf_audio*
39crw-rw---- 1 system system 247,   6 1970-01-01 00:00 hdf_audio_capture             // Voice recording service.
40crw-rw---- 1 root   root   247,   4 1970-01-01 00:00 hdf_audio_codec_primary_dev0  // Audio adapter device 0.
41crw-rw---- 1 root   root   247,   4 1970-01-01 00:00 hdf_audio_codec_primary_dev11 // Audio adapter device 1.
42crw-rw---- 1 system system 247,   5 1970-01-01 00:00 hdf_audio_control             // Audio control service.
43crw-rw---- 1 system system 247,   7 1970-01-01 00:00 hdf_audio_render              // Audio playback service.
44```
45
46The audio adapters have the following driver services:
47
48hdf_audio_codec_primary_dev0
49
50- **dma_service_0**: DMA service
51- **dai_service**: CPU DAI service
52- **codec_service_0**: codec service (which can be smartPA)
53- **dsp_service_0**: DSP service (optional)
54
55hdf_audio_codec_primary_dev11
56
57- **dma_service_0**: DMA service
58- **dai_service**: CPU DAI service
59- **codec_service_1**: codec service (which can be smartPA)
60- **dsp_service_0**: DSP service (optional)
61
62#### Startup Process
63
64![](figures/ADM_startup_flowchart.png)
65
661. When the system starts, the platform, codec, DSP, and DAI drivers of the audio module are loaded first. Each driver obtains the configuration information from its configuration file and saves the obtained information to the data structs.
67
682. Each driver module calls the ADM registration interface to add itself to the linked list of the driver module.
69
703. The ADM obtains the hdf_audio_driver_0 and hdf_audio_driver_1 configuration and loads the devices of each module.
71
724. The ADM module initializes each module device by calling the initialization API of the respective module.
73
745. The initialized audio devices are added to the cardManager linked list.
75
76#### Playback Process
77
78![](figures/ADM_playback_flowchart.png)
79
801. The Audio Interface Lib sends the **Render Open** instruction to the Audio Stream Dispatch service. The Audio Stream Dispatch service calls the API of each module to deliver the instruction.
81
822. The Audio Interface Lib sends a path select instruction to the Control Dispatch service. The Control Dispatch service calls the DAI API to set the path.
83
843. The Audio Interface Lib sends hardware parameters to the Audio Stream Dispatch service. The Audio Stream Dispatch service calls the API of each module to set the hardware parameters.
85
864. The Audio Interface Lib sends the start playing instruction to the Audio Stream Dispatch service. The Audio Stream Dispatch service calls the API of each module to perform related settings for each module.
87
885. The Audio Interface Lib sends audio data to the Audio Stream Dispatch service. The Audio Stream Dispatch service calls the **Platform AudioPcmWrite** API to send the audio data to DMA.
89
906. The Audio Interface Lib sends the stop playing instruction to the Audio Stream Dispatch service. The Audio Stream Dispatch service calls the stop API of each module to perform related stop settings for each module.
91
927. The Audio Interface Lib sends the **Render Close** instruction to the Audio Stream Dispatch service. The Audio Stream Dispatch service calls the **Platform AudioRenderClose** API to release resources.
93
94#### Control Process
95
96![](figures/ADM_control_flowchart.png)
97
981. When the volume needs to be adjusted, the Audio Interface Lib sends an instruction for obtaining the volume range to the Control Dispatch service. The Control Dispatch service parses the instruction and calls **get()** of the codec module to obtain the volume range.
992. The Audio Interface Lib sends an instruction for setting the volume to the Control Dispatch service. The Control Dispatch service parses the instruction and calls **Set()** of the codec module to set the volume.
100
101### Common Audio Driver Functions
102
103| Function                        | Description                                       |
104| ------------------------------ | ------------------------------------------- |
105| CodecDeviceReadReg             | Reads data from a codec register.                          |
106| CodecDeviceWriteReg            | Writes data to a codec register.                          |
107| CodecDaiRegI2cRead             | Reads data from a codec register over an I2C interface to a codec DAI.           |
108| CodecDaiRegI2cWrite            | Writes data to a codec register over an I2C interface from a codec DAI.           |
109| CodecDeviceRegI2cRead          | Reads data from a codec register over an I2C interface to a codec device.               |
110| CodecDeviceRegI2cWrite         | Write data to a codec register over an I2C interface from a codec device.               |
111| CodecDeviceInitRegConfig       | Initializes codec.                            |
112| CodecDaiDeviceStartupRegConfig | Starts a codec device.                              |
113| CodecSetCtlFunc                | Sets the **set()** and **get()** functions.   |
114| CodecSetConfigInfoOfControls   | Sets the codec control function and register information.|
115| CodecGetConfigInfo             | Obtains the code HDF configuration source (HCS).                   |
116| CodecGetDaiName                | Obtains the DAI name in the HCS.                |
117| CodecGetServiceName            | Obtains the service name in the HCS.               |
118| DaiDeviceReadReg               | Reads data from a DAI register.                            |
119| DaiDeviceWriteReg              | Writes data to a DAI register.                            |
120| DaiSetConfigInfoOfControls     | Sets the DAI control function and register information.  |
121| DaiGetConfigInfo               | Obtains the DAI HCS.                     |
122
123
124
125### Audio Driver Development Procedure
126
127#### Development on an Adapted Platform
128
129The following figure shows the process for developing the codec or SmartPA driver on a chip platform (Hi3516D V300) to which the ADM has adapted.
130
131![](figures/audio_development_flowchart_1.png)
132
133- Add register information to the private HDF configuration source (HCS) of the codec or SmartPA based on the chip description.
134
135- If the workflow of the newly added codec or SmartPA is the same as that of the existing codec or SmartPA, you do not need to implement the operation function set or configure the compilation file for the newly added codec or SmartPA.
136
137- Perform build, debugging, and testing.
138
139#### Development on a New Platform
140
141The following figure shows the driver development process if the ADM has not adapted to the platform.
142
143![](figures/audio_development_flowchart_2.png)
144
145The codec (optional), DAI, DMA, DSP (optional), and SmartPA (optional) modules of the audio adapter need to be adapted to the new platform.
146
147- Add register information of each module driver to the private configuration file of the respective module according to the chip description.
148
149- Implement the operation function set of each module.
150
151- Modify the compilation file of the audio module.
152
153- Perform build, debugging, and testing.
154
155## Audio Driver Development Examples
156
157Code path: **device/board/hisilicon/hispark_taurus/audio_drivers**
158
159The following uses Hi3516D V300 as an example to describe how to develop the codec driver, DAI driver, and Platform driver.
160
161### Codec Driver Development Example
162
163Code path: **device/board/hisilicon/hispark_taurus/audio_drivers/codec/hi3516**
164
165The major steps for developing the codec driver are as follows:
166
1671. Define and fill in a codec instance.
1682. Implement callbacks for the codec instance.
1693. Register and bind the codec instance to the HDF.
1704. Configure the HCS and makefile.
171
172#### Filling in Codec Data Structs
173
174Fill in the following data structs for the codec module:
175
176- **g_codecData**: operation function set and private data set of the codec device.
177
178- **g_codecDaiDeviceOps**: codec DAI device operation function set, including APIs for starting transmission and setting parameters.
179
180- **g_codecDaiData**: operation function set and private data set of the digital audio interface of the codec.
181
182```c
183struct CodecData g_codecData = {
184  .Init = CodecDeviceInit,      // Initialize the codec device (need to be implemented for a new platform).
185  .Read = AudioDeviceReadReg,   // Read the register (available in the existing framework).
186  .Write = AudioDeviceWriteReg, // Write the register (available in the existing framework).
187};
188
189struct AudioDaiOps g_codecDaiDeviceOps = {
190  .Startup = CodecDaiStartup,   // Start transmission (need to be implemented for a new platform).
191  .HwParams = CodecDaiHwParams, // Set parameters (need to be implemented for a new platform).
192};
193
194struct DaiData g_codecDaiData = {
195  .DaiInit = CodecDaiDeviceInit,// Initialize the codec DAI device (need to be implemented for a new platform).
196  .ops = &g_codecDaiDeviceOps,  // Codec DAI device operation function set.
197};
198```
199
200#### Initializing codecDevice and codecDai
201
202**CODECDeviceInit** sets audio input/audio output (AIAO), initializes registers, inserts **g_audioControls** into the controller linked list, initializes the power management, and selects a path.
203
204```c
205int32_t CodecDeviceInit(struct AudioCard *audioCard, struct CodecDevice *codec)
206{
207    ...
208    /* Register set() and get() of the AIAO module on the Hi3516. */
209    CodecSetCtlFunc(codec->devData, AudioCodecAiaoGetCtrlOps, AudioCodecAiaoSetCtrlOps)
210    ...
211    /* Hi3516 codec register IoRemap. */
212    CodecHalSysInit();
213    ...
214    /* Initialize the codec registers of the Hi3516. */
215    CodecRegDefaultInit(codec->devData->regCfgGroup);
216    ...
217    /* Add g_audioControls of the Hi3516 to the controller linked list.*/
218    AudioAddControls(audioCard, codec->devData->controls, codec->devData->numControls);
219    ...
220    /* Load the codec of the Hi3516 to the SAPM. */
221    AudioSapmNewComponents(audioCard, codec->devData->sapmComponents, codec->devData->numSapmComponent);
222    ...
223    /* Add the codec of the Hi3516 to the audioRoutes linked list. */
224    AudioSapmAddRoutes(audioCard, g_audioRoutes, HDF_ARRAY_SIZE(g_audioRoutes);
225    ...
226    AudioSapmNewControls(audioCard);
227    ...
228    /* Hi3516 codec power management. */
229    AudioSapmSleep(audioCard);
230    ...
231    return HDF_SUCCESS;
232}
233```
234
235**CodecDaiDeviceInit** initializes the codec DAI device. This API is not used on the Hi3516 and is reserved.
236
237```c
238int32_t CodecDaiDeviceInit(struct AudioCard *card, const struct DaiDevice *device)
239
240{
241    ...
242    AUDIO_DRIVER_LOG_DEBUG("codec dai device name: %s\n", device->devDaiName);
243    (void)card;
244    return HDF_SUCCESS;
245}
246```
247
248#### Implementing the Codec Operation Function Set
249
250The codec module is encapsulated with the **read()** and **write()** functions of the read and write registers at the operating system abstraction layer (OSAL).
251
252If the new platform cannot use the OSAL **read()** and **write()** functions to operate registers, you should implement them.
253
254```c
255int32_t AudioDeviceReadReg(unsigned long virtualAddress, uint32_t reg, uint32_t *val)
256{
257  ...
258  *val = OSAL_READL((void *)((uintptr_t)(virtualAddress + reg)));
259  return HDF_SUCCESS;
260}
261
262int32_t AudioDeviceWriteReg(unsigned long virtualAddress, uint32_t reg, uint32_t value)
263{
264  OSAL_WRITEL(value, (void *)((uintptr_t)(virtualAddress + reg)));
265  return HDF_SUCCESS;
266}
267```
268
269**CodecDaiStartup** completes startup settings.
270
271```c
272int32_t CodecDaiStartup(const struct AudioCard *card, const struct DaiDevice *device)
273{
274  int32_t ret;
275  ...
276  (void)card;
277  ret = CodecSetAdcTuneEnable(device->devData->regCfgGroup);
278  ...
279  return HDF_SUCCESS;
280}
281```
282
283**CodecDaiHwParams** sets parameters, including the sampling rate and bit width.
284
285```c
286int32_t CodecDaiHwParams(const struct AudioCard *card, const struct AudioPcmHwParams *param)
287{
288  unsigned int bitWidth;
289  struct CodecDaiParamsVal codecDaiParamsVal;
290  ...
291  int ret = AudioFormatToBitWidth(param->format, &bitWidth);
292  ...
293  codecDaiParamsVal.frequencyVal = param->rate;
294  codecDaiParamsVal.formatVal = bitWidth;
295  ret = CodecDaiParamsUpdate(card->rtd->codecDai->devData->regCfgGroup, codecDaiParamsVal);
296  ...
297  return HDF_SUCCESS;
298}
299```
300
301#### Registering and Binding Codec to HDF
302
303The following implementation depends on the driver implementation mode of the HDF. For details, see [HDF](driver-overview-foundation.md).
304
305Fill in the **g_codecDriverEntry** struct. Ensure that the value of **moduleName** is the same as that in **device_info.hcs**. Implement the pointers to the **Bind**, **Init**, and **Release** functions.
306
307device/board/hisilicon/hispark_taurus/audio_drivers/codec/hi3516/src/hi3516_codec_adapter.c
308
309```c
310struct HdfDriverEntry g_codecDriverEntry = {
311   .moduleVersion = 1,
312   .moduleName = "CODEC_HI3516",
313   .Bind = CodecDriverBind,
314   .Init = CodecDriverInit,
315   .Release = CodecDriverRelease,
316};
317HDF_INIT(g_codecDriverEntry);
318```
319
320**CodecDriverBind** binds the device in the HDF to the codec and registers the codec service with the HDF.
321
322```c
323static int32_t CodecDriverBind(struct HdfDeviceObject *device)
324{
325  struct CodecHost *codecHost = (struct CodecHost *)OsalMemCalloc(sizeof(*codecHost));
326  ...
327  codecHost->device = device;
328  device->service = &codecHost->service;
329  return HDF_SUCCESS;
330}
331```
332
333**CodecDriverInit** obtains the **codecService** name and private register configuration, and inserts them into the linked list by using **AudioRegisterCodec**.
334
335```c
336static int32_t CodecDriverInit(struct HdfDeviceObject *device)
337{
338  ...
339  CodecGetConfigInfo(device, &g_codecData);
340  CodecSetConfigInfo(&g_codecData, &g_codecDaiData);
341  CodecGetServiceName(device, &g_codecData.drvCodecName);
342  CodecGetDaiName(device, &g_codecDaiData.drvDaiName);
343  AudioRegisterCodec(device, &g_codecData, &g_codecDaiData);
344  ...
345  return HDF_SUCCESS;
346}
347```
348
349**CodecDriverRelease** releases driver resources.
350
351```c
352static void CodecDriverRelease(struct HdfDeviceObject *device)
353{
354   codecHost = (struct CodecHost *)device->service;
355   OsalMemFree(codecHost);
356}
357```
358
359#### Configuring HCS
360
361Configure the driver node, loading sequence, and service name in the .hcs file. For details about the HCS syntax, see [Configuration Management](driver-hdf-manage.md) of the HDF.
362
363Path of the standard-system configuration file:
364
365**vendor/hisilicon/hispark_taurus_standard/hdf_config/khdf/**
366
367Path of the small-system configuration file:
368
369**vendor/hisilicon/hispark_taurus/hdf_config/**
370
371**Configuring Codec Device Information in device_info.hcs**
372
373Add codec node configuration. Modify **moduleName** in the configuration file. The value must be the same as **moduleName** in the **HdfDriverEntry** struct. Generally, the value should present the hardware platform. For example, moduleName = "CODEC_HI3516".
374
375The code snippet is as follows:
376
377```c
378     audio :: host {
379      device_codec :: device {
380         device0 :: deviceNode {
381           policy = 1;     // The codec module provides services only for the kernel.
382           priority = 50;  // The codec module must be loaded before the load of the HDF_AUDIO module.
383           preload = 0;
384           permission = 0666;
385           moduleName = "CODEC_HI3516";          // The value must be the same as moduleName in HdfDriverEntry.
386           serviceName = "codec_service_0";      // Name of the service provided externally.
387           deviceMatchAttr = "hdf_codec_driver"; // Name of the private attribute, which is used to match the corresponding private data (including the register configuration).
388         }
389       }
390```
391
392**Configuring Dependencies in audio_config.hcs**
393
394Configure the dependency between the codec, platform, DAI, and DSP on which the audio_card device depends.
395
396The code snippet is as follows:
397
398```c
399root {
400    platform {
401        ...
402        controller_0x120c1001 :: card_controller {
403            // Set the private data attribute name, which must be the same as the deviceMatchAttr in device_info.hcs.
404            match_attr = "hdf_audio_driver_1";
405            serviceName = "hdf_audio_codec_primary_dev11"; // Name of the service provided externally.
406            codecName = "codec_service_1";       // Codec service name.
407            platformName = "dma_service_0";      // DMA service.
408            cpuDaiName = "dai_service";          // CPU DAI service.
409            codecDaiName = "tfa9879_codec_dai";  // Codec DAI service.
410            dspName = "dsp_service_0";           // DSP service name.
411            dspDaiName = "dsp_dai";              // DSP DAI.
412        }
413    }
414}
415```
416
417**Configuring Private Registers in codec_config.hcs**
418
419The configuration matches **deviceMatchAttr** of the codec configured in **device_info.hcs**. It includes the register configuration.
420
421Binding the control functionality configuration is to configure the control functionalities and their register parameters in the .hcs file according to unified struct specifications. The configuration can be obtained and parsed, and added to the controller linked list.
422
423- **regConfig**: register and control functionality configuration.
424
425- **ctrlParamsSeqConfig**: register configuration for a function. The items in **ctrlParamsSeqConfig** must be in the same sequence as the items in **controlsConfig**.
426
427- **daiStartupSeqConfig**: DAI startup configuration.
428
429- **daiParamsSeqConfig**: playback parameter configuration.
430
431- **resetSeqConfig**: reset process register configuration.
432
433- **initSeqConfig**: initialization process register configuration.
434
435- **controlsConfig**: control function configuration. The **array index** (specific service scenario) and **iface** (same as that in the HAL) have fixed values.
436
437- **sapmConfig**: power management and control function configuration. The values of **array index** (specific service scenario) and **iface** (consistent with the HAL) have fixed values.
438
439- **ctrlSapmParamsSeqConfig**: register configuration of the power management and control function.
440
441- **sapmComponent**: power management component configuration.
442
443- **array index**:
444
445  The **array index** in **controlsConfig** is the element ID in the **g_audioCodecControlsList** array in the **audio_codec_base.c** file.
446
447  The **array index** in **sapmConfig** is the element ID in the **g_audioSapmCfgNameList** array in the **audio_codec_base.c** file.
448
449  The **compNameIndex** in **sapmComponent** is the element ID in the **g_audioSapmCompNameList** array in the **audio_codec_base.c** file.
450
451- **iface**: **2** for the virtual mixer device.
452
453```c
454 root {
455    platform {
456        template codec_controller {
457            match_attr = "";
458            serviceName = "";
459            codecDaiName = "";
460        }
461        controller_0x120c1030 :: codec_controller {
462            match_attr = "hdf_codec_driver";
463            serviceName = "codec_service_0";
464            codecDaiName = "codec_dai";
465
466            /* Base address of Hi3516 registers. */
467            idInfo {
468                chipName = "hi3516";          // Codec name.
469                chipIdRegister = 0x113c0000;  // Codec base address.
470                chipIdSize = 0x1000;          // Codec address offset.
471            }
472
473           /* Register configuration, including configuration of registers. */
474            regConfig {
475               /*   reg: register address
476                    rreg: register address
477                    shift: shift bits
478                    rshift: rshift bits
479                    min: min value
480                    max: max value
481                    mask: mask of value
482                    invert: enum InvertVal 0-uninvert 1-invert
483                    value: value
484                */
485
486                /* reg, value */
487                initSeqConfig = [
488                    0x14,    0x04000002,
489                    0x18,    0xFD200004,
490                    0x1C,    0x00180018,
491                    0x20,    0x83830028,
492                    0x24,    0x00005C5C,
493                    0x28,    0x00130000,
494                    0x30,    0xFF035A00,
495                    0x34,    0x08000001,
496                    0x38,    0x06062424,
497                    0x3C,    0x1E1EC001,
498                    0x14,    0x04000002
499                ];
500
501                /* Control functionality configuration.
502                    array index, iface, mixer/mux, enable, */
503                    0,  2,  0,  0,
504                    1,  2,  0,  1,
505                    2,  2,  0,  1,
506                    3,  2,  0,  1,
507                    4,  2,  0,  1,
508                    5,  2,  0,  1,
509                    8,  2,  0,  0,
510                    9,  2,  0,  0,
511                ];
512                /* Control functionality register configuration
513                   reg, rreg, shift, rshift, min, max, mask, invert, value */
514                ctrlParamsSeqConfig = [
515                    0x3c, 0x3c, 24, 24, 0x0, 0x57, 0x7F, 1, 0,   // "Main Capture Volume"
516                    0x38, 0x38, 31, 31, 0x0, 0x1, 0x1, 0, 0,     // "Playback Mute"
517                    0x3c, 0x3c, 31, 31, 0x0, 0x1, 0x1, 0, 0,     // "Capture Mute"
518                    0x20, 0x20, 16, 16, 0x0, 0xF, 0x1F, 0, 0,    // "Mic Left Gain"
519                    0x20, 0x20, 24, 24, 0x0, 0xF, 0x1F, 0, 0,    // "Mic Right Gain"
520                    0x2000, 0x2000, 16, 16, 0x0, 0x7, 0x7, 0, 0, // "Render Channel Mode"
521                    0x1000, 0x1000, 16, 16, 0x0, 0x7, 0x7, 0, 0  // "Capture Channel Mode"
522                ];
523
524                /* After the upper layer delivers parameters, write audio-related data to registers.
525                   reg, rreg, shift, rshift, min, max, mask, invert, value */
526                daiParamsSeqConfig = [
527                    0x30, 0x30, 13, 13, 0x0, 0x1F, 0x1F, 0, 0x0,   // i2s_frequency
528                    0x1C, 0x1C, 6, 6, 0x0, 0x3, 0x3, 0, 0x0,       // adc_mode_sel
529                    0x30, 0x30, 22, 22, 0x0, 0x3, 0x3, 0, 0x0,     // i2s_datawith
530                ];
531
532                /* Configuration of the power management function register.
533                   reg, rreg, shift, rshift, min, max, mask, invert, value */
534                ctrlSapmParamsSeqConfig = [
535                    0x20, 0x20, 23, 23, 0x0, 0x1, 0x1, 0, 0,  // LPGA MIC 0 -- connect MIC
536                    0x20, 0x20, 31, 31, 0x0, 0x1, 0x1, 0, 0,  // RPGA MIC 0 -- connect MIC
537                    0x30, 0x30, 27, 27, 0x0, 0x1, 0x1, 0, 0,  // dacl to dacr mixer
538                    0x30, 0x30, 26, 26, 0x0, 0x1, 0x1, 0, 0   // dacr to dacl mixer
539                ];
540
541                /*
542                 Power management component configuration.
543                 sapmType, compNameIndex, reg, mask, shift, invert, kcontrolNews, kcontrolsNum
544                 reg = 0xFFFF: component has no sapm register bit
545                */
546                sapmComponent = [
547                    10, 0,    0x20,    0x1, 15,  1, 0, 0, // ADCL
548                    10, 1,    0x20,    0x1, 14,  1, 0, 0, // ADCR
549                    11, 2,    0x14,    0x1, 11,  1, 0, 0, // DACL
550                    11, 3,    0x14,    0x1, 12,  1, 0, 0, // DACR
551                    17, 4,    0x20,    0x1, 13,  1, 1, 1, // LPGA
552                    17, 5,    0x20,    0x1, 12,  1, 2, 1, // RPGA
553                    15, 6,  0xFFFF, 0xFFFF,  0,  0, 0, 0, // SPKL
554                    15, 7,  0xFFFF, 0xFFFF,  0,  0, 0, 0, // SPKR
555                    17, 52, 0xFFFF, 0xFFFF,  0,  0, 3, 1, // SPKL PGA
556                    17, 53, 0xFFFF, 0xFFFF,  0,  0, 4, 1, // SPKR PGA
557                    13, 40, 0xFFFF, 0xFFFF,  0,  0, 0, 0, // MIC1
558                    13, 41, 0xFFFF, 0xFFFF,  0,  0, 0, 0  // MIC2
559                ];
560
561              /* Power management function configuration.
562                   array index, iface, mixer/mux, enable
563              */
564                sapmConfig = [
565                    0,    2,    0,    1,
566                    1,    2,    0,    1,
567                    2,    2,    0,    1,
568                    3,    2,    0,    1
569                ];
570            }
571        }
572    }
573}
574```
575
576Read the .hcs files in the C code to obtain register configuration.
577
578```c
579static int32_t CodecDriverInit(struct HdfDeviceObject *device)
580{
581  ...
582  CodecGetConfigInfo(device, &g_codecData) ;
583  CodecSetConfigInfo(&g_codecData, &g_codecDaiData);
584  ...
585  return HDF_SUCCESS;
586}
587```
588
589When the codec is registered, the input parameter **device** contains controller_0x120c1030 node information. You only need to parse the node to obtain the configuration information.
590
591```c
592int32_t CodecGetConfigInfo(const struct HdfDeviceObject *device, struct CodecData *codecData)
593{
594  codecData->regConfig = (struct AudioRegCfgData *)OsalMemCalloc(sizeof(*(codecData->regConfig)));
595  CodecGetRegConfig(device, codecData->regConfig);
596  return HDF_SUCCESS;
597}
598```
599
600Obtain the node configuration to configure the node.
601
602```c
603int32_t CodecGetRegConfig(const struct HdfDeviceObject *device, struct AudioRegCfgData *configData)
604{
605    ...
606    drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
607    ...
608    idNode = drsOps->GetChildNode(root, "idInfo");
609    ParseAudioAttr(drsOps, idNode, &configData->audioIdInfo);
610    regCfgNode = drsOps->GetChildNode(root, "regConfig");
611    ...
612    DEV_RES_NODE_FOR_EACH_ATTR(regCfgNode, regAttr) {
613    ...
614    return HDF_SUCCESS;
615}
616```
617
618Obtain and use the configuration of the **regConfig** node. After the configuration files are parsed, the register information in the code can be directly updated.
619
620```c
621int32_t CodecDeviceInit(struct AudioCard *audioCard, struct CodecDevice *codec)
622{
623...
624    if (CodecRegDefaultInit(codec->devData->regCfgGroup) != HDF_SUCCESS) {
625        AUDIO_DRIVER_LOG_ERR("CodecRegDefaultInit failed.");
626        return HDF_FAILURE;
627    }
628...
629    return HDF_SUCCESS;
630}
631```
632
633### SmartPA Driver Development Example
634
635Code path: **device/board/hisilicon/hispark_taurus/audio_drivers/codec/tfa9879**
636
637The SmartPA is a type of codec driver. The development process is as follows:
638
6391. Define and fill in a codec instance.
6402. Implement callbacks for the codec instance.
6413. Register and bind the codec instance to the HDF.
6424. Configure the HCS and makefile.
643
644#### Filling in the Codec Data Structs
645
646Fill in the following data structs for the codec module:
647
648- **g_tfa9879Data**: operation function set of the codec device. It contains the configuration in the .hcs file, and defines and maps the functions for initializing the codec device and reading and writing registers.
649
650- **g_tfa9879DaiDeviceOps**: DAI data set that defines and maps the operations of the codec device DAI.
651
652- **g_tfa9879DaiData**: DAI data set that defines and maps the driver name, initialization, and operations of the data access interfaces of the codec device.
653
654```c
655struct CodecData g_tfa9879Data = {
656    .Init = Tfa9879DeviceInit,
657    .Read = CodecDeviceRegI2cRead,
658    .Write = CodecDeviceRegI2cWrite,
659};
660
661struct AudioDaiOps g_tfa9879DaiDeviceOps = {
662    .Startup = Tfa9879DaiStartup,
663    .HwParams = Tfa9879DaiHwParams,
664};
665
666struct DaiData g_tfa9879DaiData = {
667    .drvDaiName = "tfa9879_codec_dai",
668    .DaiInit = Tfa9879DaiDeviceInit,
669    .ops = &g_tfa9879DaiDeviceOps,
670    .Read = CodecDaiRegI2cRead,
671    .Write = CodecDaiRegI2cWrite,
672};
673```
674
675#### Initializing codecDevice and codecDai
676
677As the entry function for device initialization, **Tfa9879DeviceInit** sets the address of the SmartPA I2C device, obtains configuration data, initializes (including resets) the device registers, and adds the control functionality to the controller linked list. The current demo also includes the initialization of the registers related to the Hi3516D V300 device, such as initialization of GPIO pins.
678
679```c
680int32_t Tfa9879DeviceInit(struct AudioCard *audioCard, const struct CodecDevice *device)
681{
682    int32_t ret;
683    ...
684    // Initialize GPIO pins.
685    ret = Hi35xxGpioPinInit();
686    ...
687    // Set I2C parameters.
688    g_transferParam.i2cBusNumber = TFA9879_I2C_BUS_NUMBER;
689    g_transferParam.i2cDevAddr = TFA9879_I2C_DEV_ADDR;
690    g_transferParam.i2cRegDataLen = TFA9879_I2C_REG_DATA_LEN;
691    device->devData->privateParam = &g_transferParam;
692    ...
693    // Initialize device registers.
694    ret = CodecDeviceInitRegConfig(device);
695    ...
696    // Bind the control functionality configuration.
697    if (AudioAddControls(audioCard, device->devData->controls, device->devData->numControls) !=
698        HDF_SUCCESS) {
699        AUDIO_DRIVER_LOG_ERR("add controls failed.");
700        return HDF_FAILURE;
701    }
702    ...
703}
704```
705
706Common functions of the I2C read/write registers:
707
708```c
709int32_t CodecDeviceRegI2cRead(const struct CodecDevice *codec, uint32_t reg, uint32_t *val)
710{
711    int32_t ret;
712    struct AudioAddrConfig regAttr;
713    struct I2cTransferParam *i2cTransferParam = NULL;
714    ...
715    i2cTransferParam = (struct I2cTransferParam *)codec->devData->privateParam;
716    ...
717    regAttr.addr = (uint8_t)reg;
718    regAttr.value = 0;
719    ret = CodecI2cTransfer(i2cTransferParam, &regAttr, I2C_FLAG_READ);
720    ...
721    *val = regAttr.value;
722    return HDF_SUCCESS;
723}
724
725int32_t CodecDeviceRegI2cWrite(const struct CodecDevice *codec, uint32_t reg, uint32_t value)
726{
727    int32_t ret;
728    struct AudioAddrConfig regAttr;
729    struct I2cTransferParam *i2cTransferParam = NULL;
730    ...
731    i2cTransferParam = (struct I2cTransferParam *)codec->devData->privateParam;
732    ...
733    regAttr.addr = (uint8_t)reg;
734    regAttr.value = (uint16_t)value;
735    ret = CodecI2cTransfer(i2cTransferParam, &regAttr, 0);
736    ...
737    return HDF_SUCCESS;
738}
739
740int32_t CodecDaiRegI2cRead(const struct DaiDevice *dai, uint32_t reg, uint32_t *value)
741{
742    ...
743    ret = CodecI2cTransfer(i2cTransferParam, &regAttr, I2C_FLAG_READ);
744    ...
745    return HDF_SUCCESS;
746}
747
748int32_t CodecDaiRegI2cWrite(const struct DaiDevice *dai, uint32_t reg, uint32_t value)
749{
750    ...
751    ret = CodecI2cTransfer(i2cTransferParam, &regAttr, 0);
752    ...
753    return HDF_SUCCESS;
754}
755```
756
757#### Implementing the Codec Operation Function Set
758
759**Tfa9879DaiStartup** performs startup settings. The code snippet is as follows:
760
761```c
762int32_t Tfa9879DaiStartup(const struct AudioCard *card, const struct DaiDevice *device)
763{
764    int ret;
765    (void)card;
766    (void)device;
767    // Set the register for starting the SmartPA.
768    ret = CodecDaiDeviceStartupRegConfig(device);
769    ...
770    return HDF_SUCCESS;
771}
772
773```
774
775**Tfa9879DaiHwParams** delivers playback parameters. The code snippet is as follows:
776
777```c
778int32_t Tfa9879DaiHwParams(const struct AudioCard *card, const struct AudioPcmHwParams *param)
779{
780    int32_t ret;
781    uint16_t frequency, bitWidth;
782    struct DaiParamsVal daiParamsVal;
783    (void)card;
784    ...
785    // Set the sampling rate.
786    ret = Tfa9879FrequencyParse(param->rate, &frequency);
787    ...
788    // Set the bit width.
789    ret = Tfa9879FormatParse(param->format, &bitWidth);
790    ...
791    daiParamsVal.frequencyVal = frequency;
792    daiParamsVal.formatVal = bitWidth;
793    daiParamsVal.channelVal = param->channels; // Set the audio channel.
794    ret = Tfa9879DaiParamsUpdate(card->rtd->codecDai, daiParamsVal);
795    ...
796    return HDF_SUCCESS;
797}
798```
799
800#### Registering and Binding Codec to HDF
801
802The following implementation depends on the driver implementation mode of the HDF. For details, see [HDF](driver-overview-foundation.md).
803
804Fill in the **g_tfa9879DriverEntry** struct. Ensure that the value of **moduleName** is the same as that in **device_info.hcs**. Implement the pointers to the **Bind**, **Init**, and **Release** functions.
805
806device/board/hisilicon/hispark_taurus/audio_drivers/codec/tfa9879/src/tfa9879_accessory_adapter.c
807
808```c
809static int32_t Tfa9879DriverBind(struct HdfDeviceObject *device)
810{
811    (void)device;
812    AUDIO_DRIVER_LOG_INFO("success!");
813    return HDF_SUCCESS;
814}
815
816static int32_t Tfa9879DriverInit(struct HdfDeviceObject *device)
817{
818    int32_t ret;
819    ...
820    // Obtain configuration data from .hcs files.
821    ret = CodecGetConfigInfo(device, &g_tfa9879Data);
822    ...
823    // Set the interface functions and register information related to codec control.
824    ret = CodecSetConfigInfoOfControls(&g_tfa9879Data, &g_tfa9879DaiData);
825    ...
826    ret = CodecGetServiceName(device, &g_tfa9879Data.drvCodecName);
827    ...
828    ret = CodecGetDaiName(device, &g_tfa9879DaiData.drvDaiName);
829    ...
830    // Register the codec with the audio adapter.
831    ret = AudioRegisterCodec(device, &g_tfa9879Data, &g_tfa9879DaiData);
832    ....
833    return HDF_SUCCESS;
834}
835
836/* HdfDriverEntry definitions */
837struct HdfDriverEntry g_tfa9879DriverEntry = {
838    .moduleVersion = 1,
839    .moduleName = "CODEC_TFA9879",
840    .Bind = Tfa9879DriverBind,
841    .Init = Tfa9879DriverInit,
842    .Release = NULL,
843};
844HDF_INIT(g_tfa9879DriverEntry);
845```
846
847#### Configuring HCS
848
849For details about the configuration process, see [Configuring HCS](#configuring-hcs) in **Codec Driver Development Example**.
850
851### Platform Driver Development Example
852
853Code path: **device/board/hisilicon/hispark_taurus/audio_drivers/soc**
854
855In audio driver development, the Platform module is configured to adapt to the DMA driver. The major steps for developing the platform driver are as follows:
856
8571. Define and fill in a platform instance.
8582. Implement callbacks for the platform instance.
8593. Register and bind the codec instance to the HDF.
8604. Configure the HCS and makefile.
861
862#### Filling in Platform Data Structures
863
864Fill in the following structs for the platform module:
865
866- **g_platformData**: private configuration of the platform device, including the initialization and operation functions of the platform device.
867
868- **g_dmaDeviceOps**: DMA device operation function set, including the encapsulation of some common DMA APIs.
869
870```c
871struct AudioDmaOps g_dmaDeviceOps = {
872    .DmaBufAlloc = Hi3516DmaBufAlloc,             // Apply for memory for the DMA device.
873    .DmaBufFree = Hi3516DmaBufFree,               // Release the memory of the DMA device.
874    .DmaRequestChannel = Hi3516DmaRequestChannel, // Request a DMA channel.
875    .DmaConfigChannel = Hi3516DmaConfigChannel,   // Configure the DMA channel.
876    .DmaPrep = Hi3516DmaPrep,                     // Prepare for DMA.
877    .DmaSubmit = Hi3516DmaSubmit,                 // Submit a DMA request.
878    .DmaPending = Hi3516DmaPending,               // Pend DMA.
879    .DmaPause = Hi3516DmaPause,                   // Pause or stop the DMA service.
880    .DmaResume = Hi3516DmaResume,                 // Resume the DMA service.
881    .DmaPointer = Hi3516DmaPointer,               // Obtain the current playing or recording position.
882};
883
884struct PlatformData g_platformData = {
885    .PlatformInit = AudioDmaDeviceInit, // Initialize the DMA device.
886    .ops = &g_dmaDeviceOps,
887};
888```
889
890#### Initializing dmaDevice
891
892**AudioDmaDeviceInit** initializes the DMA device, including setting the Hi3516 AIAO module.
893
894```c
895int32_t AudioDmaDeviceInit(const struct AudioCard *card, const struct PlatformDevice *platformDevice)
896{
897...
898    AiaoHalSysInit();
899    /* PIN MUX */
900    AiaoSysPinMux();
901    /* CLK reset */
902    AiaoClockReset();
903    /* AIAO initialization */
904    AiaoDeviceInit(chnId);
905...
906    return HDF_SUCCESS;
907}
908```
909
910#### Implementing the DMA Operation Function Set
911
912The DMA device operation function set includes the encapsulation of DMA common APIs. If the common APIs cannot meet development requirements, you can implement new DMA callbacks.
913
914```c
915int32_t AudioDmaDeviceInit(const struct AudioCard *card, const struct PlatformDevice *platform);
916int32_t Hi3516DmaBufAlloc(struct PlatformData *data, const enum AudioStreamType streamType);
917int32_t Hi3516DmaBufFree(struct PlatformData *data, const enum AudioStreamType streamType);
918int32_t Hi3516DmaRequestChannel(const struct PlatformData *data, const enum AudioStreamType streamType);
919int32_t Hi3516DmaConfigChannel(const struct PlatformData *data, const enum AudioStreamType streamType);
920int32_t Hi3516DmaPrep(const struct PlatformData *data, const enum AudioStreamType streamType);
921int32_t Hi3516DmaSubmit(const struct PlatformData *data, const enum AudioStreamType streamType);
922int32_t Hi3516DmaPending(struct PlatformData *data, const enum AudioStreamType streamType);
923int32_t Hi3516DmaPause(struct PlatformData *data, const enum AudioStreamType streamType);
924int32_t Hi3516DmaResume(const struct PlatformData *data, const enum AudioStreamType streamType);
925int32_t Hi3516DmaPointer(struct PlatformData *data, const enum AudioStreamType streamType, uint32_t *pointer);
926```
927
928#### Registering and Binding Platform to HDF
929
930The following implementation depends on the driver implementation mode of the HDF. For details, see [HDF](driver-overview-foundation.md).
931
932- Fill in the **g_platformDriverEntry** struct.
933- Ensure that the value of **moduleName** is the same as that in **device_info.hcs**.
934- Implement the pointers to the **Bind**, **Init**, and **Release** functions.
935
936**device/board/hisilicon/hispark_taurus/audio_drivers/soc/src/hi3516_dma_adapter.c**
937
938```c
939static int32_t Hi3516DmaDriverInit(struct HdfDeviceObject *device)
940{
941...
942    OsalMutexInit(&g_platformData.renderBufInfo.buffMutex);
943    OsalMutexInit(&g_platformData.captureBufInfo.buffMutex);
944    g_platformData.platformInitFlag = false;
945    ret = AudioSocRegisterPlatform(device, &g_platformData);
946...
947    return HDF_SUCCESS;
948}
949
950static void Hi3516DmaDriverRelease(struct HdfDeviceObject *device)
951{
952    struct PlatformHost *platformHost = NULL;
953...
954    platformHost = (struct PlatformHost *)device->service;
955...
956    OsalMutexDestroy(&g_platformData.renderBufInfo.buffMutex);
957    OsalMutexDestroy(&g_platformData.captureBufInfo.buffMutex);
958    OsalMemFree(platformHost);
959}
960
961/* HdfDriverEntry definitions */
962struct HdfDriverEntry g_platformDriverEntry = {
963    .moduleVersion = 1,
964    .moduleName = "DMA_HI3516",
965    .Bind = Hi3516DmaDriverBind,
966    .Init = Hi3516DmaDriverInit,
967    .Release = Hi3516DmaDriverRelease,
968};
969HDF_INIT(g_platformDriverEntry);
970```
971
972#### Configuring HCS
973
974For details about the configuration process, see [Configuring HCS](#configuring-hcs) in **Codec Driver Development Example**.
975
976### DAI Driver Development Example
977
978Code path: **device/board/hisilicon/hispark_taurus/audio_drivers/soc**
979
980The major steps for developing the DAI driver are as follows:
981
9821. Define and fill in a DAI instance.
9832. Implement callbacks for the DAI instance.
9843. Register and bind the codec instance to the HDF.
9854. Configure the HCS and makefile.
986
987#### Filling in DAI Data Structures
988
989Fill in the following structs for the DAI module:
990
991- **g_daiData**: private configuration of the DAI device, including the initialization of the DAI device, read/write of registers, and operation functions.
992
993- **g_daiDeviceOps**: DAI device operation function set, including setting DAI parameters and triggering and starting the DAI device.
994
995```c
996struct AudioDaiOps g_daiDeviceOps = {
997    .HwParams = DaiHwParams,
998    .Trigger = DaiTrigger,
999    .Startup = DaiStartup,
1000};
1001
1002struct DaiData g_daiData = {
1003    .DaiInit = DaiDeviceInit,
1004    .Read = AudioDeviceReadReg,
1005    .Write = AudioDeviceWriteReg,
1006    .ops = &g_daiDeviceOps,
1007};
1008```
1009
1010#### Initializing daiDevice
1011
1012**DaiDeviceInit** initializes DAI configuration and adds the information to the controller linked list.
1013
1014```c
1015int32_t DaiDeviceInit(struct AudioCard *audioCard, const struct DaiDevice *dai)
1016{
1017...
1018    struct DaiData *data = dai->devData;
1019    struct AudioRegCfgData *regConfig = dai->devData->regConfig;
1020...
1021    g_regCodecBase = OsalIoRemap(CODEC_REG_BASE, CODEC_MAX_REG_SIZE);
1022...
1023    data->regVirtualAddr = (uintptr_t)g_regCodecBase;
1024    DaiSetConfigInfo(data);
1025    AudioAddControls(audioCard, data->controls, data->numControls);
1026    I2c6PinInit();
1027...
1028    data->daiInitFlag = true;
1029    return HDF_SUCCESS;
1030}
1031```
1032
1033#### Implementing the DAI Operation Function Set
1034
1035**AudioDeviceReadReg** and **AudioDeviceWriteReg** are not used on the Hi3516 and are reserved.
1036
1037**DaiHwParams** sets PCM stream information.
1038
1039```c
1040int32_t DaiHwParams(const struct AudioCard *card, const struct AudioPcmHwParams *param)
1041{
1042    uint32_t bitWidth;
1043    struct DaiDevice *device = card->rtd->cpuDai;
1044...
1045    DaiCheckSampleRate(param->rate);
1046    struct DaiData *data = DaiDataFromCard(card);
1047    data->pcmInfo.channels = param->channels;
1048...
1049    AudioFormatToBitWidth(param->format, &bitWidth);
1050...
1051    data->pcmInfo.bitWidth = bitWidth;
1052    data->pcmInfo.rate = param->rate;
1053    data->pcmInfo.streamType = param->streamType;
1054    data->regVirtualAddr = (uintptr_t)g_regDaiBase;
1055...
1056    DaiParamsUpdate(device);
1057    data->regVirtualAddr = (uintptr_t)g_regCodecBase;
1058    return HDF_SUCCESS;
1059}
1060```
1061
1062**DaiTrigger** is not used on the Hi3516 and is reserved.
1063
1064**DaiStartup** updates the register configuration and configures the I2S.
1065
1066```c
1067int32_t DaiStartup(const struct AudioCard *card, const struct DaiDevice *device)
1068{
1069    struct AudioMixerControl *regCfgItem = NULL;
1070...
1071    regCfgItem = device->devData->regConfig->audioRegParams[AUDIO_DAI_STARTUP_PATAM_GROUP]->regCfgItem;
1072    itemNum = device->devData->regConfig->audioRegParams[AUDIO_DAI_STARTUP_PATAM_GROUP]->itemNum;
1073
1074    device->devData->regVirtualAddr = (uintptr_t)g_regDaiBase;
1075    for (int i = 0; i < itemNum; i++) {
1076        int ret = AudioUpdateDaiRegBits(device, &regCfgItem[i], regCfgItem[i].value);
1077        if (ret != HDF_SUCCESS) {
1078            AUDIO_DRIVER_LOG_ERR("set frequency fail.");
1079            return HDF_FAILURE;
1080        }
1081    }
1082    device->devData->regVirtualAddr = (uintptr_t)g_regCodecBase;
1083
1084    if (I2sPinInit() != HDF_SUCCESS) {
1085        AUDIO_DRIVER_LOG_ERR("I2sPinInit fail.");
1086    }
1087
1088    return HDF_SUCCESS;
1089}
1090```
1091
1092#### Registering and Binding DAI to HDF
1093
1094The following implementation depends on the driver implementation mode of the HDF. For details, see [HDF](driver-overview-foundation.md).
1095
1096- Fill in the **g_daiDriverEntry** struct.
1097- Ensure that the value of **moduleName** is the same as that in **device_info.hcs**.
1098- Implement the pointers to the **Bind**, **Init**, and **Release** functions.
1099
1100**device/board/hisilicon/hispark_taurus/audio_drivers/soc/src/hi3516_dai_adapter.c**
1101
1102```c
1103static int32_t DaiDriverBind(struct HdfDeviceObject *device)
1104{
1105...
1106    struct DaiHost *daiHost = (struct DaiHost *)OsalMemCalloc(sizeof(*daiHost));
1107...
1108    daiHost->device = device;
1109    device->service = &daiHost->service;
1110    g_daiData.daiInitFlag = false;
1111...
1112    return HDF_SUCCESS;
1113}
1114
1115static int32_t DaiDriverInit(struct HdfDeviceObject *device)
1116{
1117...
1118    DaiGetConfigInfo(device, &g_daiData);
1119    DaiGetServiceName(device);
1120...
1121    OsalMutexInit(&g_daiData.mutex);
1122    AudioSocRegisterDai(device, &g_daiData);
1123...
1124    return HDF_SUCCESS;
1125}
1126
1127static void DaiDriverRelease(struct HdfDeviceObject *device)
1128{
1129...
1130    OsalMutexDestroy(&g_daiData.mutex);
1131...
1132    struct DaiHost *daiHost = (struct DaiHost *)device->service;
1133...
1134    OsalMemFree(daiHost);
1135}
1136
1137/* HdfDriverEntry definitions */
1138struct HdfDriverEntry g_daiDriverEntry = {
1139    .moduleVersion = 1,
1140    .moduleName = "DAI_HI3516",
1141    .Bind = DaiDriverBind,
1142    .Init = DaiDriverInit,
1143    .Release = DaiDriverRelease,
1144};
1145HDF_INIT(g_daiDriverEntry);
1146```
1147
1148#### Configuring HCS
1149
1150For details about the configuration process, see [Configuring HCS](#configuring-hcs) in **Codec Driver Development Example**.
1151
1152### Adding Compilation Configuration to Makefile
1153
1154Add the newly added files to the **Makefile** file to link them to the kernel image.
1155
1156Standard system (Linux): **device/board/hisilicon/hispark_taurus/audio_drivers/Makefile**
1157
1158```makefile
1159obj-$(CONFIG_DRIVERS_HDF_AUDIO_HI3516CODEC) += \
1160        codec/tfa9879/src/tfa9879_codec_adapter.o \
1161        codec/tfa9879/src/tfa9879_codec_ops.o \
1162        codec/hi3516/src/hi3516_codec_adapter.o \
1163        codec/hi3516/src/hi3516_codec_impl.o \
1164        codec/hi3516/src/hi3516_codec_ops.o \
1165        dsp/src/dsp_adapter.o \
1166        dsp/src/dsp_ops.o \
1167        soc/src/hi3516_dai_adapter.o \
1168        soc/src/hi3516_dai_ops.o \
1169        soc/src/hi3516_aiao_impl.o \
1170        soc/src/hi3516_dma_ops.o \
1171        soc/src/hi3516_dma_adapter.o
1172```
1173
1174Small system (LiteOS): **drivers/adapter/khdf/liteos/model/audio/Makefile**
1175
1176```makefile
1177LOCAL_SRCS += \
1178    $(KHDF_AUDIO_HI3516DV300_DIR)/codec/tfa9879/src/tfa9879_codec_adapter.c \
1179    $(KHDF_AUDIO_HI3516DV300_DIR)/codec/tfa9879/src/tfa9879_codec_ops.c \
1180    $(KHDF_AUDIO_HI3516DV300_DIR)/codec/hi3516/src/hi3516_codec_adapter.c \
1181    $(KHDF_AUDIO_HI3516DV300_DIR)/codec/hi3516/src/hi3516_codec_impl.c \
1182    $(KHDF_AUDIO_HI3516DV300_DIR)/codec/hi3516/src/hi3516_codec_ops.c \
1183    $(KHDF_AUDIO_HI3516DV300_DIR)/dsp/src/dsp_adapter.c \
1184    $(KHDF_AUDIO_HI3516DV300_DIR)/dsp/src/dsp_ops.c \
1185    $(KHDF_AUDIO_HI3516DV300_DIR)/soc/src/hi3516_dai_adapter.c \
1186    $(KHDF_AUDIO_HI3516DV300_DIR)/soc/src/hi3516_dai_ops.c \
1187    $(KHDF_AUDIO_HI3516DV300_DIR)/soc/src/hi3516_aiao_impl.c \
1188    $(KHDF_AUDIO_HI3516DV300_DIR)/soc/src/hi3516_dma_ops.c \
1189    $(KHDF_AUDIO_HI3516DV300_DIR)/soc/src/hi3516_dma_adapter.c
1190```
1191
1192### Source Code Structure and Directory
1193
1194The development example implements the functions in the header file of the driver interface. The following uses Hi3516 as an example to describe the directory struct.
1195
1196Path of the driver implementation sample code: **device/board/hisilicon/hispark_taurus/audio_drivers/**
1197
1198```shell
1199.
1200├── codec
1201│   ├── hi3516
1202│   │   ├── include
1203│   │   │   ├── hi3516_codec_impl.h
1204│   │   │   └── hi3516_codec_ops.h
1205│   │   └── src
1206│   │   │   ├── hi3516_codec_adapter.c  // Codec driver entry
1207│   │   │   ├── hi3516_codec_impl.c     // Implementation of codec hardware operations
1208│   │   │   └── hi3516_codec_ops.c      // Implementation of codec driver APIs
1209│   └── tfa9879
1210│       ├── include
1211│       │   └── tfa9879_codec_ops.h
1212│       └── src
1213│           ├── tfa9879_codec_adapter.c
1214│           └── tfa9879_codec_ops.c
1215├── dsp
1216│   ├── include
1217│   │   └── dsp_ops.h
1218│   └── src
1219│       ├── dsp_adapter.c                 // DSP driver entry
1220│       └── dsp_ops.c
1221├── LICENSE
1222├── Makefile
1223└── soc
1224    ├── include
1225    │   ├── hi3516_aiao_impl.h
1226    │   ├── hi3516_dai_ops.h
1227    │   └── hi3516_dma_ops.h
1228    └── src
1229        ├── hi3516_aiao_impl.c
1230        ├── hi3516_dai_adapter.c          // DAI driver entry
1231        ├── hi3516_dai_ops.c
1232        ├── hi3516_dma_adapter.c          // DMA driver entry
1233        └── hi3516_dma_ops.c
1234```
1235
1236HCS Files and Directory
1237
1238```shell
1239Standard system:
1240vendor/hisilicon/hispark_taurus_standard/
1241└── hdf_config
1242    └── khdf
1243        ├── audio
1244        │   ├── audio_config.hcs
1245        │   ├── codec_config.hcs
1246        │   ├── dai_config.hcs
1247        │   ├── dma_config.hcs
1248        │   └── dsp_config.hcs
1249        ├── device_info
1250        │   └── device_info.hcs
1251        └── hdf.hcs
1252
1253Small system:
1254vendor/hisilicon/hispark_taurus/
1255├── config.json
1256└── hdf_config
1257    ├── audio
1258    │   ├── audio_config.hcs
1259    │   ├── codec_config.hcs
1260    │   ├── dai_config.hcs
1261    │   ├── dma_config.hcs
1262    │   └── dsp_config.hcs
1263    ├── device_info
1264    │   └── device_info.hcs
1265    └── hdf.hcs
1266```
1267
1268## HAL-based Development Procedure and Example
1269
1270The Hardware Abstraction Layer (HAL) provides the following function:
1271
1272- Provides audio HDIs for audio services to implement basic audio features on applications.
1273- Provides standard interfaces for device developers to comply with the HDI adapter standards. This promises a healthy evolution of the ecosystem.
1274
1275Code path: **drivers_interface/audio/v1_0**
1276
1277### Development procedure
1278
1279![](figures/HAL_flowchart.png)
1280
12811. Call **GetAudioManagerFuncs()** to obtain methods.
1282
12832. Use **GetAllAdapters()** to obtain information about the supported audio adapter, and call **LoadAdapter()** to load the audio adapter.
1284
12853. Create a **Render** class by calling **CreateRender()** or create a recorder class and deliver audio attributes.
1286
12874. Call the methods hooked in the **Render** class created. For example, call **render->Start()** to start the playback, and call **render->RenderFrame()** to deliver audio data cyclically.
1288
12895. During the playback, call control commands to control the playback service, for example, call **render->SetVolume()** to adjust the volume, call **render->Pause()** to pause the playback, and call **render->Resume()** to resume the playback.
1290
12916. After the playback is complete, call **render->Stop()** to stop the playback, call **adapter->DestroyRender()** to destroy the playback instance, and call **audioManagerIns->UnloadAdapter()** to unload the audio adapter.
1292
1293### HAL Usage Example
1294
1295```c
1296#include <string.h>
1297#include <stdio.h>
1298#include <pthread.h>
1299#include "v1_0/audio_types.h"
1300#include "v1_0/iaudio_manager.h"
1301
1302struct IAudioRender *g_render = NULL;
1303struct IAudioAdapter *g_adapter = NULL;
1304struct AudioDeviceDescriptor g_devDesc;
1305struct AudioSampleAttributes g_attrs;
1306struct AudioHeadInfo g_wavHeadInfo;
1307bool g_isDirect = false;  //IPC Loading
1308uint32_t g_renderId = 0;
1309
1310static int32_t FrameStart(const struct StrPara *param)
1311{
1312...
1313    /* Initialize parameters. */
1314    char *frame = param->frame;
1315    int32_t bufferSize = param->bufferSize;
1316    size_t remainingDataSize = g_wavHeadInfo.riffSize;
1317
1318    /* Send audio data cyclically. */
1319    do {
1320        uint64_t replyBytes = 0;
1321        size_t readSize = (remainingDataSize > bufferSize) ? (size_t)bufferSize : remainingDataSize;
1322        numRead = fread(frame, 1, readSize, g_file);
1323        if (numRead > 0) {
1324            int32_t ret = render->RenderFrame(render, (int8_t *)frame, numRead, &replyBytes);
1325            if (ret == HDF_ERR_INVALID_OBJECT) {
1326                AUDIO_FUNC_LOGE("Render already stop!");
1327                break;
1328            }
1329            remainingDataSize -= numRead;
1330        }
1331        /* Pause the playback and wait. */
1332        while (g_waitSleep) {
1333            printf("music pause now.\n");
1334            pthread_cond_wait(&g_functionCond, &g_mutex);
1335            printf("music resume now.\n");
1336        }
1337    } while (!g_closeEnd && numRead > 0 && remainingDataSize > 0);
1338...
1339}
1340
1341static void *hal_main()
1342{
1343    int32_t adapterIndex = 0;
1344    struct AudioPort *renderPort;
1345
1346    /* Call IAudioManagerGet() to obtain the entry function. */
1347    struct IAudioManager *audioManagerIns = IAudioManagerGet(g_isDirect);
1348    if (audioManagerIns == NULL) {
1349        AUDIO_FUNC_LOGE("Get Audio Manager Fail");
1350        return HDF_FAILURE;
1351    }
1352
1353    /* Obtain the audio adapter list. */
1354    struct AudioAdapterDescriptor *descs = (struct AudioAdapterDescriptor *)OsalMemCalloc(
1355        sizeof(struct AudioAdapterDescriptor) * (MAX_AUDIO_ADAPTER_DESC));
1356    uint32_t adapterNum = MAX_AUDIO_ADAPTER_DESC;
1357
1358    int32_t ret = audioManagerIns->GetAllAdapters(audioManagerIns, descs, &adapterNum);
1359
1360    /* Locate the audio adapter and port based on the specified audio adapter name and port description. */
1361    SelectAudioCard(descs, adapterNum, &adapterIndex);
1362    strcpy_s(g_adapterName, PATH_LEN, descs[adapterIndex - 1].adapterName);
1363    SwitchAudioPort(&descs[adapterIndex - 1], PORT_OUT, renderPort);  // The port type is OUT, which means playback.
1364
1365    /* Load the audio adapter based on the matched audio adapter information. */
1366    audioManagerIns->LoadAdapter(audioManagerIns, &descs[adapterIndex - 1], &g_adapter);                                               // Load the audio adapter and obtain the related instances.
1367
1368    /* Create a Render class. */
1369    uint32_t portId = renderPort->portId;
1370    InitDevDesc(&g_devDesc, portId);                       // Initialize the parameters for setting the device.
1371    InitAttrs(&g_attrs);                                   // Initialize audio attribute parameters.
1372    CheckWavFileHeader(g_file, &g_wavHeadInfo, &g_attrs);  // Parse the audio file and set attributes.
1373    g_adapter->CreateRender(g_adapter, &g_devDesc, &g_attrs, &g_render, &g_renderId);
1374
1375    /* Deliver the number of the audio to be played. */
1376    g_render->Start((void *)g_render);                                  // Send the start command to start the playback.
1377    pthread_create(&g_tids, &tidsAttr, (void *)(&FrameStart), &g_str);  // Start the thread to play the music.
1378
1379    /* Send the control instructions. */
1380    g_render->Pause((void *)g_render);           // Pause the playback.
1381    g_render->Resume((void *)g_render);          // Resume the playback.
1382    g_render->SetVolume((void *)g_render, 0.5);  // Set the volume.
1383
1384     /* Stop playback and destroy the Render class. */
1385    g_render->Stop((void *)g_render);
1386    g_adapter->DestroyRender(g_adapter, g_renderId);
1387     /* Unload the audio adapter. */
1388    audioManagerIns->UnloadAdapter(audioManagerIns, g_adapterName);
1389}
1390```
1391
1392
1393
1394## Summary
1395
1396This document provides all the key adaptations involved in the audio driver development. It elaborates how to adapt the audio driver and use HDI APIs. You can conduct development based on the chip you use. After reading this document, you will be able to master the audio driver development based on the HDF.
1397