1 /*
2  * Copyright 2021-2022 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #ifndef _SRTM_PDM_SDMA_ADAPTER_H_
9 #define _SRTM_PDM_SDMA_ADAPTER_H_
10 
11 #include "srtm_audio_service.h"
12 #include "fsl_pdm_sdma.h"
13 
14 /*!
15  * @addtogroup srtm_service
16  * @{
17  */
18 
19 /*******************************************************************************
20  * Definitions
21  ******************************************************************************/
22 #ifndef SRTM_PDM_SDMA_ADAPTER_USE_HWVAD
23 #define SRTM_PDM_SDMA_ADAPTER_USE_HWVAD (1U)
24 #endif
25 #ifndef SRTM_PDM_SDMA_ADAPTER_USE_EXTRA_BUFFER
26 #define SRTM_PDM_SDMA_ADAPTER_USE_EXTRA_BUFFER (1U)
27 #endif
28 
29 /* Compile option to force usage of local and extra buffers.
30  * Help saving code space by removing code needed when one of
31  * these buffers is not used.
32  * Will generate errors if application does not configure them.
33  */
34 #ifndef SRTM_PDM_SDMA_ADAPTER_FORCE_LOCAL_AND_EXTRA_BUFFERS
35 #define SRTM_PDM_SDMA_ADAPTER_FORCE_LOCAL_AND_EXTRA_BUFFERS 0
36 #endif
37 
38 #define SRTM_PDM_SDMA_MAX_LOCAL_PERIOD_ALIGNMENT (4U)
39 
40 /*! @brief Extra device intitialize function for PDM SDMA adapter. */
41 typedef void (*pdm_dev_init)(bool enable);
42 /*! @brief Extra device configuration function based on format and sample rate, return PMD clock source in HZ. */
43 typedef uint32_t (*pdm_dev_conf)(srtm_audio_format_type_t format, uint32_t srate);
44 
45 /*! @brief Misc configuration structure. */
46 typedef struct _pdm_misc_set
47 {
48     pdm_dev_init audioDevInit; /*!< Audio device init function. */
49     pdm_dev_conf audioDevConf; /*!< config audio device based on format and sample rate, return source clock in HZ */
50 } pdm_misc_set_t;
51 
52 /*! @brief PDM SDMA configuration.  */
53 typedef struct _srtm_pdm_sdma_config
54 {
55     pdm_config_t config;                /*!< PDM user configuration. */
56     pdm_channel_config_t channelConfig; /*!< PDM channel configurations. */
57     uint32_t pdmSrcClk;                 /*!< PDM source clock in Hz. */
58     uint32_t dmaChannel;                /*!< DMA channel. */
59     uint8_t channelPriority;            /*!< The priority of DMA channel. */
60     bool stopOnSuspend;                 /*!< Stop capture when received suspend command. */
61     uint32_t eventSource;               /*!< DMA request source. */
62 
63     sdma_context_data_t rxContext;
64     pdm_misc_set_t extendConfig;
65 } srtm_pdm_sdma_config_t;
66 
67 /*! @brief PDM SDMA local buffer.  */
68 typedef struct _srtm_pdm_sdma_local_buf
69 {
70     uint8_t *buf;              /*!< Pointer of the buffer */
71     uint32_t bufSize;          /*!< bytes of the whole local buffer */
72     uint32_t periods;          /*!< periods in local buffer */
73     uint32_t samplesPerPeriod; /*!< number of samples per period (ignored if set to 0 - otherwise "periods" field is
74 re-computed based on the value and bufSize) */
75     uint32_t threshold; /*!< Threshold period number: under which will trigger copy from local buffer to extra buffer if
76                            extra buffer is used. Otherwise the local buffer is overwritten.*/
77 } srtm_pdm_sdma_local_buf_t;
78 
79 #if SRTM_PDM_SDMA_ADAPTER_USE_EXTRA_BUFFER
80 /*! @brief PDM SDMA extra buffer. When the local buffer is full, the data can be copied to extra buffer.  */
81 typedef struct _srtm_pdm_sdma_ext_buf
82 {
83     uint8_t *buf;     /*!< Pointer of the buffer */
84     uint32_t bufSize; /*!< bytes of the whole extra buffer */
85     uint32_t periods; /*!< periods in the buffer, it will be recalculated by the driver using given bufSize and local
86                          buffer configuration. */
87     uint32_t bufWriteDmaChannel; /*!< The extra buffer write DMA channel. */
88     uint32_t bufReadDmaChannel;  /*!< The extra buffer read DMA channel. */
89     uint8_t channelPriority;     /*!< The priority of DMA channel. */
90 } srtm_pdm_sdma_ext_buf_t;
91 #endif
92 
93 #if SRTM_PDM_SDMA_ADAPTER_USE_HWVAD
94 typedef enum _srtm_pdm_hwvad_mode
95 {
96     kSRTM_PDM_Hwvad_Disabled          = 0U,
97     kSRTM_PDM_Hwvad_EnergyBasedMode   = 1U,
98     kSRTM_PDM_Hwvad_EnvelopeBasedMode = 2U,
99 } srtm_pdm_hwvad_mode_t;
100 
101 typedef struct _srtm_pdm_hwvad_config
102 {
103     srtm_pdm_hwvad_mode_t mode;
104     pdm_hwvad_config_t hwvadConfig;
105     pdm_hwvad_noise_filter_t noiseFilterConfig;
106     pdm_hwvad_zero_cross_detector_t zcdConfig;
107     uint32_t signalGain;
108 } srtm_pdm_hwvad_config_t;
109 
110 /*! @brief HWVAD callback function pointer. The callback is called when voice activity is detected by HWVAD.
111  */
112 typedef void (*srtm_pdm_sdma_hwvad_callback_t)(srtm_sai_adapter_t adapter, void *params);
113 #endif /* SRTM_PDM_SDMA_ADAPTER_USE_HWVAD */
114 
115 /*! @brief The callback function pointer.  Voice data can be passed to application via callback when the host side is
116  * suspend. The callback is also a notification to the application for the host side resumes from suspend when the data
117  * and bytes are 0(NULL). */
118 typedef void (*srtm_pdm_sdma_data_callback_t)(srtm_sai_adapter_t adapter, void *data, uint32_t bytes, void *params);
119 
120 /*******************************************************************************
121  * API
122  ******************************************************************************/
123 #ifdef __cplusplus
124 extern "C" {
125 #endif
126 
127 /*!
128  * @brief Create PDM SDMA adapter.
129  *
130  * @param pdm PDM base address.
131  * @param dma DMA base address.
132  * @param rxConfig PDM Rx channel configuration.
133  * @return SRTM PDM SDMA adapter on success or NULL on failure.
134  */
135 srtm_sai_adapter_t SRTM_PdmSdmaAdapter_Create(PDM_Type *pdm, SDMAARM_Type *dma, srtm_pdm_sdma_config_t *rxConfig);
136 
137 /*!
138  * @brief Destroy PDM SDMA adapter.
139  *
140  * @param adapter PDM SDMA adapter to destroy.
141  */
142 void SRTM_PdmSdmaAdapter_Destroy(srtm_sai_adapter_t adapter);
143 
144 /*!
145  * @brief Get the audio service status.
146  * @param adapter PDM SDMA adapter.
147  * @param pRxState status pointer.
148  */
149 void SRTM_PdmSdmaAdapter_GetAudioServiceState(srtm_sai_adapter_t adapter, srtm_audio_state_t *pRxState);
150 
151 /*!
152  * @brief Set local buffer to use in DMA transfer. If local buffer is set, the audio data will be captured
153  * and transfered to local buffer, then copied to share buffer. Otherwise the data will be
154  * transfered from PDM interface to shared buffer directly.
155  * NOTE: it must be called before service start.
156  *
157  * @param adapter PDM SDMA adapter to set.
158  * @param localBuf Local buffer information to be set to the adapter RX path.
159  */
160 void SRTM_PdmSdmaAdapter_SetRxLocalBuf(srtm_sai_adapter_t adapter, srtm_pdm_sdma_local_buf_t *localBuf);
161 
162 #if SRTM_PDM_SDMA_ADAPTER_USE_EXTRA_BUFFER
163 /*!
164  * @brief Set extra buffer to be used when local buffer is full. The extra buffer could be in external memory.
165  * If extra buffer is set, once the local buffer is full it will not be overwritten, instead the audio data in the local
166  * buffer will be copied to the extra buffer, then copied to the shared buffer.
167  * NOTE: It used only if local buffer is set by SRTM_PdmSdmaAdapter_SetRxLocalBuf and it must be called before service
168  * start.
169  *
170  * @param adapter PDM SDMA adapter to set.
171  * @param extBuf extra buffer information to be set to the adapter RX path.
172  */
173 void SRTM_PdmSdmaAdapter_SetRxExtBuf(srtm_sai_adapter_t adapter, srtm_pdm_sdma_ext_buf_t *extBuf);
174 #endif /* SRTM_PDM_SDMA_ADAPTER_USE_EXTRA_BUFFER */
175 
176 /*!
177  * @brief When the host driver suspends, voice data can be passed to application via callback.
178  *        When the host driver is waking up, the notfication is sent via callback.
179  *        The callback is called in SRTM dispatcher task context and should not cost much time.
180  *
181  * @param adapter PDM SDMA adapter instance.
182  * @param cb Callback function pointer.
183  * @param param Callback function argument to be passed back to applicaiton.
184  */
185 void SRTM_PdmSdmaAdapter_SetDataHandlerOnHostSuspend(srtm_sai_adapter_t adapter,
186                                                      srtm_pdm_sdma_data_callback_t cb,
187                                                      void *param);
188 
189 /*!
190  * @brief When key word detected, voice data will be sent to host again.
191  *
192  * @param adapter PDM SDMA adapter instance.
193  */
194 void SRTM_PdmSdmaAdapter_ResumeHost(srtm_sai_adapter_t adapter);
195 
196 /*!
197  * @brief get audio format currently configured on an adapter.
198  *
199  * @return audio format setting
200  */
201 srtm_audio_format_type_t SRTM_PdmSdmaAdapter_GetDataFormat(srtm_sai_adapter_t adapter);
202 
203 #if SRTM_PDM_SDMA_ADAPTER_USE_HWVAD
204 
205 /* clang-format off */
206 /*!
207  * @brief Setup HWVAD. This function is used to configure the HWVAD function of PDM module, the API should be called
208  * before the start of PDM capture. Once successfully configured and HWVAD mode is not kSRTM_PDM_Hwvad_Disabled mode,
209  * the HWVAD will be enabled when the PDM capture starts. SRTM_PdmSdmaAdapter_EnableHwvad can be used to disable or
210  * re-enable the HWVAD function during capture.
211  * Sample configurations for EnvelopeBasedMode,
212  * code
213  * static srtm_pdm_hwvad_config_t pdm_hwvad_config = {
214  *     .mode = kSRTM_PDM_Hwvad_EnvelopeBasedMode,
215  *     .hwvadConfig.channel = 0U,
216  *     .hwvadConfig.initializeTime = 10U,
217  *     .hwvadConfig.cicOverSampleRate = 0U,
218  *     .hwvadConfig.inputGain = 0U,
219  *     .hwvadConfig.frameTime = 10U,
220  *     .hwvadConfig.cutOffFreq        = kPDM_HwvadHpfBypassed,
221  *     .hwvadConfig.enableFrameEnergy = false,
222  *     .hwvadConfig.enablePreFilter   = true,
223  *     .noiseFilterConfig.enableAutoNoiseFilter = false,
224  *     .noiseFilterConfig.enableNoiseMin        = true,
225  *     .noiseFilterConfig.enableNoiseDecimation = true,
226  *     .noiseFilterConfig.noiseFilterAdjustment = 0U,
227  *     .noiseFilterConfig.noiseGain             = 7U,
228  *     .noiseFilterConfig.enableNoiseDetectOR   = true,
229  *     .signalGain = 0U,
230  *  };
231  * code
232  * @param adapter PDM SDMA adapter instance.
233  * @param hwvadConfig The HWVAD configuration structure.
234  * @param cb The callback function pointer.
235  * @param param Callback function argument to be passed back to applicaiton.
236  * @return Configured the HWVAD successfully or with failure.
237  */
238 /* clang-format on */
239 srtm_status_t SRTM_PdmSdmaAdapter_ConfigHwvad(srtm_sai_adapter_t adapter,
240                                               const srtm_pdm_hwvad_config_t *hwvadConfig,
241                                               srtm_pdm_sdma_hwvad_callback_t cb,
242                                               void *param);
243 
244 /*!
245  * @brief Enable/Disable the HWVAD, this API is used to enable/disable the HWVAD during PDM capture.
246  *
247  * @param adapter PDM SDMA adapter instance.
248  * @param enable Enable or disable the HWVAD.
249  */
250 void SRTM_PdmSdmaAdapter_EnableHwvad(srtm_sai_adapter_t adapter, bool enable);
251 #endif /* SRTM_PDM_SDMA_ADAPTER_USE_HWVAD */
252 /*******************************************************************************
253  * Definitions from other files
254  ******************************************************************************/
255 
256 #ifdef __cplusplus
257 }
258 #endif
259 
260 /*! @} */
261 
262 #endif /* __SRTM_SAI_SDMA_ADAPTER_H__ */
263