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