/* * Copyright (c) 2021 Actions Semiconductor Co., Ltd * * SPDX-License-Identifier: Apache-2.0 */ /** * @file audio_in.h * @brief Audio input channels common interface. * * Audio input channels are used to record a uncompressed PCM data * through analog(e.g line-in) or digital physical interface(e.g. SPDIF). * * This public audio input interface aims to define a unified structures and functions * for vary audio input channels. */ #ifndef __AUDIO_IN_H__ #define __AUDIO_IN_H__ #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** * @defgroup audio_in_apis Audio In Device APIs * @ingroup driver_apis * @{ */ /** * @brief The Audio input channels contains the following channels. * - ADC (analog convert to digital) * - I2SRX * - SPDIFRX * * All audio input channels follow the same interfaces to record a PCM stream. * The different operations between the input channels are the parameter * structures that used to open or control an dedicated audio input channel. * For example open an ADC channel need to inplement the structure #adc_setting_t, * whileas the structure to open an I2SRX channel is #i2srx_setting_t. * Moreover, Some special control commands are dedicated for some input channel, * such as #AIN_CMD_SPDIF_IS_PCM_STREAM only work for SPDIFRX channel. * * Example: * * @code * * #include * * // Note that all audio input channels only support DMA reload mode. * * #define SHELL_AUDIO_BUFFER_SIZE (1024) * static uint8_t audio_pcm_buffer[SHELL_AUDIO_BUFFER_SIZE]; * * // Audio input DMA callback function. * static int audio_rec_read_data_cb(void *callback_data, uint32_t reason) { * uint32_t len = sizeof(audio_pcm_buffer) / 2; * uint8_t *buf = NULL; * * if (AIN_DMA_IRQ_HF == reason) { * buf = audio_pcm_buffer; * } else { * buf = audio_pcm_buffer + len; * } * * // The recorded data is in the memory of buf, and its length is len. * } * * //1. Get a audio input device. * struct device *ain_dev = device_get_binding(CONFIG_AUDIO_IN_ACTS_DEV_NAME); * if (!ain_dev) { * printk("failed to get audio input device\n"); * return -ENODEV; * } * * // 2. Open a ADC channel * ain_param_t ain_param = {0}; * adc_setting_t adc_setting = {0}; * void *ain_handle; * * ain_param.sample_rate = SAMPLE_RATE_16KHZ; * ain_param.callback = audio_rec_read_data_cb; * ain_param.cb_data = NULL; * ain_param.reload_setting.reload_addr = audio_pcm_buffer; * ain_param.reload_setting.reload_len = sizeof(audio_pcm_buffer); * ain_param.channel_type = AUDIO_CHANNEL_ADC; * ain_param.channel_width = CHANNEL_WIDTH_16BITS; * * adc_setting.device = AUDIO_ANALOG_MIC0; * uint8_t i; * for (i = 0; i < ADC_CH_NUM_MAX; i++) { * adc_setting.gain.ch_gain[i] = 365; * } * ain_param.adc_setting = &adc_setting; * * ain_handle = audio_in_open(ain_dev, &ain_param); * if (!ain_handle) { * printk("failed to open the audio in channel"); * return -EIO; * } * * // 3. Use audio_out_control to send extra comands to the opened ADC channel if needed. * * // 4. Start to play the ADC channel * ret = audio_record_start(ain_dev, ain_handle); * * @endcode * * @note For more detailed audio input channel example, please make a reference to the file:audio_driver_shell.c. * */ /** * @name Definition for the audio in control commands * @{ */ #define AIN_CMD_SET_ADC_GAIN (1) /*!< Set the ADC left channel gain value which in dB format. * int audio_in_control(dev, handle, #AIN_CMD_SET_ADC_GAIN, adc_gain *gain) * Returns 0 if successful and negative errno code if error. * * @note You can get the dB range from #AIN_CMD_GET_ADC_LEFT_GAIN_RANGE and AIN_CMD_GET_ADC_RIGHT_GAIN_RANGE. */ #define AIN_CMD_GET_ADC_LEFT_GAIN_RANGE (2) /*!< Get the ADC left channel gain range in dB format. * int audio_in_control(dev, handle, #AIN_CMD_GET_ADC_LEFT_GAIN_RANGE, adc_gain_range *range) * Returns 0 if successful and negative errno code if error. */ #define AIN_CMD_GET_ADC_RIGHT_GAIN_RANGE (3) /*!< Get the ADC right channel gain range in dB format. * int audio_in_control(dev, handle, #AIN_CMD_GET_ADC_RIGHT_GAIN_RANGE, adc_gain_range *range) * Returns 0 if successful and negative errno code if error. */ #define AIN_CMD_SPDIF_GET_CHANNEL_STATUS (4) /* Get the SPDIFRX channel status. * int audio_in_control(dev, handle, #AIN_CMD_SPDIF_GET_CHANNEL_STATUS, audio_spdif_ch_status_t *sts) * Returns 0 if successful and negative errno code if error. */ #define AIN_CMD_SPDIF_IS_PCM_STREAM (5) /* Check if the stream that received from spdifrx is the pcm format * int audio_in_control(dev, handle, #AIN_CMD_SPDIF_IS_PCM_STREAM, bool *is_pcm) * Returns 0 if successful and negative errno code if error. */ #define AIN_CMD_SPDIF_CHECK_DECODE_ERR (6) /* Check if there is spdif decode error happened * int audio_in_control(dev, handle, #AIN_CMD_SPDIF_CHECK_DECODE_ERR, bool *is_err) * Returns 0 if successful and negative errno code if error. */ #define AIN_CMD_I2SRX_QUERY_SAMPLE_RATE (7) /* Query the i2c master device sample rate and i2srx works in slave mode. * int audio_in_control(dev, handle, #AIN_CMD_I2SRX_QUERY_SAMPLE_RATE, audio_sr_sel_e *is_err) * Returns 0 if successful and negative errno code if error. */ #define AIN_CMD_GET_SAMPLERATE (8) /*!< Get the channel audio sample rate by specified the audio channel handler. * int audio_in_control(dev, handle, #AIN_CMD_GET_SAMPLERATE, audio_sr_sel_e *sr) * Returns 0 if successful and negative errno code if error. */ #define AIN_CMD_SET_SAMPLERATE (9) /*!< Set the channel audio sample rate by the giving audio channel handler. * int audio_in_control(dev, handle, #AIN_CMD_SET_SAMPLERATE, audio_sr_sel_e *sr) * Returns 0 if successful and negative errno code if error. */ #define AIN_CMD_GET_APS (10) /*!< Get the AUDIO_PLL APS * int audio_in_control(dev, handle, #AIN_CMD_GET_APS, audio_aps_level_e *aps) * Returns 0 if successful and negative errno code if error. */ #define AIN_CMD_SET_APS (11) /*!< Set the AUDIO_PLL APS for the sample rate tuning * int audio_in_control(dev, handle, #AIN_CMD_SET_APS, audio_aps_level_e *aps) * Returns 0 if successful and negative errno code if error. */ #define AIN_CMD_BIND_CHANNEL (12) /*!< Bind the different audio in channels that can start simutaneously. * int audio_in_control(dev, handle, #AIN_CMD_BIND_CHANNEL, void *hdl) * Returns 0 if successful and negative errno code if error. */ #define AIN_CMD_GET_ADC_FIFO_DRQ_LEVEL (13) /*!< Get the ADC FIFO DRQ level. * int audio_in_control(dev, NULL, #AIN_CMD_GET_ADC_FIFO_DRQ_LEVEL, uint8_t *level) * Returns 0 if successful and negative errno code if error. */ #define AIN_CMD_SET_ADC_FIFO_DRQ_LEVEL (14) /*!< Set the ADC FIFO DRQ level. * int audio_in_control(dev, NULL, #AIN_CMD_SET_ADC_FIFO_DRQ_LEVEL, uint8_t *level) * Returns 0 if successful and negative errno code if error. * * @note The parameter level is range from 0 to 15; */ #define AIN_CMD_DEBUG_PERFORMANCE_CTL (15) /*!< Control to enable or disable to dump the perfornamce infomation for debug. * int audio_in_control(dev, NULL, #AOUT_CMD_DEBUG_PERFORMANCE_CTL, uint8_t *en) * Returns 0 if successful and negative errno code if error. * * @note en: 0 to disable; 1 to enable */ #define AIN_CMD_DEBUG_PERFORMANCE_CTL_ALL (16) /*!< Control all sessions to enable or disable to dump the perfornamce infomation for debug. * int audio_in_control(dev, NULL, #AIN_CMD_DEBUG_PERFORMANCE_CTL_ALL, uint8_t *en) * Returns 0 if successful and negative errno code if error. * * @note en: 0 to disable; 1 to enable */ #define AIN_CMD_DEBUG_DUMP_LENGTH (17) /*!< Set the length of play buffer to print out per-second. * int audio_in_control(dev, NULL, #AIN_CMD_DEBUG_DUMP_LENGTH, uint8_t *len) * Returns 0 if successful and negative errno code if error. */ #define AIN_CMD_DEBUG_DUMP_LENGTH_ALL (18) /*!< Set the length of all sessions play buffer to print out per-second. * int audio_in_control(dev, NULL, #AIN_CMD_DEBUG_DUMP_LENGTH_ALL, uint8_t *len) * Returns 0 if successful and negative errno code if error. */ #define AIN_CMD_SET_ADC_TRIGGER_SRC (19) /*!< Set the source of trigger ADC to start by external IRQ signal. * int audio_in_control(dev, handle, #AIN_CMD_SET_ADC_TRIGGER_SRC, uint8_t *trigger_src) * The parameter trigger_src can refer to #audio_trigger_src. * Returns 0 if successful and negative errno code if error. * * @note The parameter trigger_src can refer to #audio_trigger_src. */ #define AIN_CMD_ANC_CONTROL (20) /*!< Control to enable or disable ANC function. * int audio_in_control(dev, NULL, #AIN_CMD_ANC_CONTROL, adc_anc_ctl_t *anc_ctl) * Returns 0 if successful and negative errno code if error. */ #define AIN_CMD_SET_SEPARATED_MODE (21) /*!< Set DMA as separated mode for mute left/right channel individually or store the PCM data by separated format. * int audio_in_control(dev, handle, #AIN_CMD_SET_SEPARATED_MODE, audio_interleave_mode_e *p_mode) * Returns 0 if successful and negative errno code if error. */ #define AIN_CMD_AEC_CONTROL (22) /*!< Control to enable or disable AEC function that send DAC data to ADC. * int audio_in_control(dev, handle, #AIN_CMD_AEC_CONTROL, uint8_t *en) * Returns 0 if successful and negative errno code if error. */ /** @} */ /*! * enum audio_interleave_mode_e * @brief Audio DMA interleave mode setting */ typedef enum { LEFT_MONO_RIGHT_MUTE_MODE = 0, LEFT_MUTE_RIGHT_MONO_MODE, LEFT_RIGHT_SEPERATE } audio_interleave_mode_e; /*! * struct adc_gain_range * @brief The ADC min and max gain range */ typedef struct { int16_t min; /*!< min gain */ int16_t max; /*!< max gain */ } adc_gain_range; /*! * struct adc_gain * @brief The ADC gain setting */ typedef struct { #define ADC_GAIN_INVALID (0xFFFF) int16_t ch_gain[ADC_CH_NUM_MAX]; /*!< The gain value shall be set by 10 multiple of actual value e.g. ch_gain[0]=100 means channel 0 gain is 10 db; * If gain value equal to #ADC_GAIN_INVALID that the setting will be ignored. */ } adc_gain; /*! * struct adc_setting_t * @brief The ADC setting parameters */ typedef struct { uint16_t device; /*!< ADC input device chooses */ adc_gain gain; /*!< ADC gain setting */ } adc_setting_t; /*! * struct i2srx_setting_t * @brief The I2SRX setting parameters */ typedef struct { #define I2SRX_SRD_FS_CHANGE (1 << 0) /*!< I2SRX SRD(sample rate detect) captures the event that the sample rate has changed * int callback(cb_data, #I2STX_SRD_FS_CHANGE, audio_sr_sel_e *sr) */ #define I2SRX_SRD_WL_CHANGE (1 << 1) /*!< I2SRX SRD(sample rate detect) captures the event that the effective width length has changed * int callback(cb_data, #I2STX_SRD_WL_CHANGE, audio_i2s_srd_wl_e *wl) */ #define I2SRX_SRD_TIMEOUT (1 << 2) /*!< I2SRX SRD(sample rate detect) captures the timeout (disconnection) event * int callback(cb_data, #I2STX_SRD_TIMEOUT, NULL) */ int (*srd_callback)(void *cb_data, uint32_t cmd, void *param); /*!< The callback function from I2SRX SRD module which worked in the slave mode */ void *cb_data; /*!< Callback user data */ audio_i2s_mode_e mode; } i2srx_setting_t; /*! * struct spdifrx_setting_t * @brief The SPDIFRX setting parameters */ typedef struct { #define SPDIFRX_SRD_FS_CHANGE (1 << 0) /*!< SPDIFRX SRD(sample rate detect) captures the event that the sample rate has changed. * int callback(cb_data, #SPDIFRX_SRD_FS_CHANGE, audio_sr_sel_e *sr) */ #define SPDIFRX_SRD_TIMEOUT (1 << 1) /*!< SPDIFRX SRD(sample rate detect) timeout (disconnect) event. * int callback(cb_data, #SPDIFRX_SRD_TIMEOUT, NULL) */ int (*srd_callback)(void *cb_data, uint32_t cmd, void *param); /*!< sample rate detect callback */ void *cb_data; /*!< callback user data */ } spdifrx_setting_t; /*! * struct ain_param_t * @brief The audio in configuration parameters */ typedef struct { #define AIN_DMA_IRQ_HF (1 << 0) /*!< DMA irq half full flag */ #define AIN_DMA_IRQ_TC (1 << 1) /*!< DMA irq transfer completly flag */ uint8_t sample_rate; /*!< The sample rate setting refer to enum audio_sr_sel_e */ uint16_t channel_type; /*!< Indicates the channel type selection and can refer to #AUDIO_CHANNEL_ADC, #AUDIO_CHANNEL_I2SRX, #AUDIO_CHANNEL_SPDIFRX*/ audio_ch_width_e channel_width; /*!< The channel effective data width */ adc_setting_t *adc_setting; /*!< The ADC function setting if has */ i2srx_setting_t *i2srx_setting; /*!< The I2SRX function setting if has */ spdifrx_setting_t *spdifrx_setting; /*!< The SPDIFRX function setting if has */ int (*callback)(void *cb_data, uint32_t reason); /*!< The callback function which called when #AIN_DMA_IRQ_HF or #AIN_DMA_IRQ_TC events happened */ void *cb_data; /*!< callback user data */ audio_reload_t reload_setting; /*!< The reload mode setting which is mandatory*/ } ain_param_t; /*! * struct ain_driver_api * @brief Public API for audio in driver */ struct ain_driver_api { void* (*ain_open)(struct device *dev, ain_param_t *param); int (*ain_close)(struct device *dev, void *handle); int (*ain_start)(struct device *dev, void *handle); int (*ain_stop)(struct device *dev, void *handle); int (*ain_control)(struct device *dev, void *handle, int cmd, void *param); }; /*! * @brief Open the audio input channel by specified parameters * * @param dev Pointer to the device structure for the audio input channel instance. * * @param setting Pointer to the audio input channel parameter. * * @return The audio input channel instance handle. */ static inline void* audio_in_open(struct device *dev, ain_param_t *setting) { const struct ain_driver_api *api = dev->api; return api->ain_open(dev, setting); } /*! * @brief Close the audio input channel by the specified handle. * * @param dev Pointer to the device structure for the audio input channel instance. * * @param handle The audio input channel instance handle. * * @return 0 on success, negative errno code on fail. * * @note the handle shall be the same as the retval of #audio_in_open. */ static inline int audio_in_close(struct device *dev, void *handle) { const struct ain_driver_api *api = dev->api; return api->ain_close(dev, handle); } /*! * @brief Control the audio input channel by the specified handle. * * @param dev Pointer to the device structure for the audio input channel instance. * * @param handle The audio input channel instance handle. * * @param cmd The control command that sent to the audio input channel. * * @param param The audio out in/out parameters which corresponding with the commands * * @return 0 on success, negative errno code on fail. * * @note the handle shall be the same as the retval of #audio_in_open. */ static inline int audio_in_control(struct device *dev, void *handle, int cmd, void *param) { const struct ain_driver_api *api = dev->api; return api->ain_control(dev, handle, cmd, param); } /*! * @brief Start the audio input channel by the specified handle. * * @param dev Pointer to the device structure for the audio input channel instance. * * @param handle The audio input channel instance handle. * * @return 0 on success, negative errno code on fail. * * @note the handle shall be the same as the retval of #audio_in_open. */ static inline int audio_in_start(struct device *dev, void *handle) { const struct ain_driver_api *api = dev->api; return api->ain_start(dev, handle); } /*! * @brief Stop the audio input channel by the specified handle. * * @param dev Pointer to the device structure for the audio input channel instance. * * @param handle The audio input channel instance handle. * * @return 0 on success, negative errno code on fail. * * @note the handle shall be the same as the retval of #audio_in_open. */ static inline int audio_in_stop(struct device *dev, void *handle) { const struct ain_driver_api *api = dev->api; return api->ain_stop(dev, handle); } #ifdef __cplusplus } #endif /** * @} end defgroup audio_in_apis */ #endif /* __AUDIO_IN_H__ */