From 829c17a722611c39cda6926f0fac46fa586c70ef Mon Sep 17 00:00:00 2001 From: tienphitran Date: Mon, 17 Jun 2019 17:04:02 +0700 Subject: [PATCH 2/6] ADSP: add ADSP sound driver source Signed-off-by: tienphitran diff --git a/include/adsp_drv/xf-adsp-drv-ext.h b/include/adsp_drv/xf-adsp-drv-ext.h new file mode 100644 index 0000000..6c3dbc0 --- /dev/null +++ b/include/adsp_drv/xf-adsp-drv-ext.h @@ -0,0 +1,58 @@ +/***************************************************************************** + * \file xf-adsp-driver-ext.h + * \brief Header file for ADSP driver extension part + * \addtogroup ADSP Driver + ****************************************************************************** + * \date Oct. 21, 2017 + * \author Renesas Electronics Corporation + ****************************************************************************** + * \par Copyright + * + * Copyright(c) 2016 Renesas Electoronics Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#ifndef __XF_ADSP_DRV_EXT_H +#define __XF_ADSP_DRV_EXT_H + +/*********************************************************** + * Extension client APIs + * ********************************************************/ + +struct xf_adsp_base_cmd { + /* register new client for ADSP base control */ + int (*client_register)(void **private_data); + /* unregister client */ + int (*client_unregister)(void *private_data); + /* get data from proxy */ + int (*recv)(void *private_data, void *buf); + /* send data to proxy */ + int (*send)(void *private_data, void *buf); + /* wait the valid message in the response queue */ + int (*poll)(void *private_data, int *condition); +}; + +/* create ADSP base control data */ +int xf_adsp_base_create(struct xf_adsp_base_cmd *cmd); + +/* destroy ADSP base control data */ +int xf_adsp_base_destroy(void); + +#endif diff --git a/sound/soc/adsp/Kconfig b/sound/soc/adsp/Kconfig new file mode 100644 index 0000000..605261f --- /dev/null +++ b/sound/soc/adsp/Kconfig @@ -0,0 +1,14 @@ +## SoC for ADSP driver configuration +menu "ASoC ADSP driver" + +config SND_SOC_ADSP + tristate "SoC Audio for R-Car ADSP" + select SND_SIMPLE_CARD + select SND_SIMPLE_SCU_CARD + select SND_AUDIO_GRAPH_CARD + select SND_AUDIO_GRAPH_SCU_CARD + default y + help + This option enables ALSA ADSP sound supports ADSP module + +endmenu diff --git a/sound/soc/adsp/Makefile b/sound/soc/adsp/Makefile new file mode 100644 index 0000000..8277fdb --- /dev/null +++ b/sound/soc/adsp/Makefile @@ -0,0 +1,3 @@ +## Makefile for SoC ADSP driver +snd-soc-adsp-objs := xf-adsp-alsa.o xf-adsp-base.o +obj-$(CONFIG_SND_SOC_ADSP) += snd-soc-adsp.o diff --git a/sound/soc/adsp/xf-adsp-alsa.c b/sound/soc/adsp/xf-adsp-alsa.c new file mode 100644 index 0000000..493ff84 --- /dev/null +++ b/sound/soc/adsp/xf-adsp-alsa.c @@ -0,0 +1,3939 @@ +/** *************************************************************************** + * \file xf-adsp-alsa.c + * \brief Source file for ADSP ALSA Driver + * \addtogroup ADSP Driver + ****************************************************************************** + * \date Oct. 21, 2017 + * \author Renesas Electronics Corporation + ****************************************************************************** + * \par Copyright + * + * Copyright(c) 2016 Renesas Electoronics Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xf-adsp-base.h" + +/* Name of Volume control for playback */ +#define PLAYBACK_VOLUME_CTR_NAME "PlaybackVolume" + +/* Name of Volume control for capture */ +#define CAPTURE_VOLUME_CTR_NAME "CaptureVolume" + +/* Name of Sample Rate control for playback */ +#define PLAYBACK_OUT_RATE_CTR_NAME "PlaybackOutRate" + +/* Name of Output Channel control for playback */ +#define PLAYBACK_OUT_CHANNEL_CTR_NAME "PlaybackOutChannel" + +/* Name of Sample Rate control for capture */ +#define CAPTURE_IN_RATE_CTR_NAME "CaptureInRate" + +/* Name of Equalizer parameters control for playback */ +#define PLAYBACK_EQZ_CTR_NAME "PlaybackEQZControl" + +/* Name of Equalizer parameters control for capture */ +#define CAPTURE_EQZ_CTR_NAME "CaptureEQZControl" + +/* Name of Equalizer Switch control for playback */ +#define PLAYBACK_EQZ_SWITCH_CTR_NAME "PlaybackEQZSwitch" + +/* Name of Equalizer Switch control for capture */ +#define CAPTURE_EQZ_SWITCH_CTR_NAME "CaptureEQZSwitch" + +/* Name of Volume control for TDM playback */ +#define TDM_PLAYBACK_VOLUME_CTR_NAME "TDMPlaybackVolume" + +/* Name of Volume control for TDM capture */ +#define TDM_CAPTURE_VOLUME_CTR_NAME "TDMCaptureVolume" + +/* Name of Sample Rate control for TDM playback */ +#define TDM_PLAYBACK_OUT_RATE_CTR_NAME "TDMPlaybackOutRate" + +/* Name of Sample Rate control for TDM capture */ +#define TDM_CAPTURE_IN_RATE_CTR_NAME "TDMCaptureInRate" + +/* Prefix of Playback control name */ +#define PREFIX_OF_PLAYBACK_CTR_NAME PLAYBACK_VOLUME_CTR_NAME[0] + +/* Prefix of Capture control name */ +#define PREFIX_OF_CAPTURE_CTR_NAME CAPTURE_VOLUME_CTR_NAME[0] + +/* Prefix of TDM control name */ +#define PREFIX_OF_TDM_CTR_NAME TDM_PLAYBACK_VOLUME_CTR_NAME[0] + +/* Prefix of TDM playback */ +#define TDM_PLAYBACK TDM_PLAYBACK_VOLUME_CTR_NAME[3] + +/* Prefix of TDM record */ +#define TDM_CAPTURE TDM_CAPTURE_VOLUME_CTR_NAME[3] + +/* Number of control for playback & capture */ +#define RDR_CONTROL_NUM (9) + +/* Number of controls for TDM */ +#define TDM_CONTROL_NUM (4) + +/* Indicate playback stream */ +#define DIRECT_PLAYBACK (0) + +/* Indicate capture stream */ +#define DIRECT_CAPTURE (1) + +/* Indicate stream number */ +#define DIRECT_NUM (2) + +/* Supported frame size for playback/record function in driver */ +#define FRAME_SIZE (1024) + +/* Supported frame size for TDM playback/record function in driver */ +#define TDM_FRAME_SIZE (1024) + +/* Supported sample rate in driver */ +#define SND_ADSP_SAMPLE_RATES (SNDRV_PCM_RATE_32000 | \ + SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000) + +/* Supported PCM width in driver */ +#define SND_ADSP_PCM_WIDTHS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +/* Macro to control DAI index */ +/* DAI 0 index for playback/record functions of stereo/mono formats */ +#define RDR_DAI_IDX0 (0) + +/* DAI 1 index for playback/record functions of stereo/mono formats */ +#define RDR_DAI_IDX1 (1) + +/* DAI 2 index for playback/record functions of stereo/mono formats */ +#define RDR_DAI_IDX2 (2) + +/* DAI 3 index for playback/record functions of stereo/mono formats */ +#define RDR_DAI_IDX3 (3) + +/* DAI 4 index for playback/record functions of TDM formats */ +#define TDM_DAI_IDX (4) + +/* Maximum number of DAI supported by driver */ +#define MAX_DAI_IDX (5) + +/* Renderer/Capture software information */ +/* Minimum channel number supported */ +#define MIN_CHANNEL (1) + +/* Maximum channel number supported */ +#define MAX_CHANNEL (2) + +/* Minimum buffer size in byte */ +#define MIN_BUF_SIZE (FRAME_SIZE * MIN_CHANNEL * 2) + +/* Maximum buffer size in byte */ +#define MAX_BUF_SIZE (FRAME_SIZE * MAX_CHANNEL * 4) + +/* Minimum numbers of period in the buffer */ +#define MIN_PERIOD (1) + +/* Maximum numbers of period in the buffer */ +#define MAX_PERIOD (4) + +/* Maximun numbers of bytes in ALSA buffer */ +#define MAX_BUFFER_BYTES (MAX_PERIOD * MAX_BUF_SIZE) + +/* TDM software information */ +/*< Minimum channel number supported in TDM plugin */ +#define TDM_MIN_CHANNEL (6) + +/* Maximum channel number supported in TDM plugin */ +#define TDM_MAX_CHANNEL (8) + +/* Minimum buffer size in byte for TDM format */ +#define TDM_MIN_BUF_SIZE (TDM_FRAME_SIZE * TDM_MIN_CHANNEL * 2) + +/* Maximum buffer size in byte for TDM format */ +#define TDM_MAX_BUF_SIZE (TDM_FRAME_SIZE * TDM_MAX_CHANNEL * 4) + +/* Minimum numbers of period in the buffer for TDM format */ +#define TDM_MIN_PERIOD (1) + +/* Maximum numbers of period in the buffer for TDM format */ +#define TDM_MAX_PERIOD (4) + +/* Maximum numbers of bytes in ALSA buffer for TDM format */ +#define TDM_MAX_BUFFER_BYTES (TDM_MAX_PERIOD * TDM_MAX_BUF_SIZE) + +/* Volume scale used when user set */ +#define VOLUME_SCALE (100) + +/* Maximum element in Equalizer parameter control */ +#define MAX_EQZ_PARAM_NUMBER (55) + +/* Equalizer control is disabled */ +#define EQZ_OFF (0) + +/* Equalizer control is enabled */ +#define EQZ_ON (1) + +/* Component status */ +/* Handle state is NULL */ +#define XF_HANDLE_NULL (0) + +/* Handle state is CREATED after creating handle successfully */ +#define XF_HANDLE_CREATED BIT(0) + +/* Handle state is READY after finishing handle init */ +#define XF_HANDLE_READY BIT(1) + +/* channels */ +/* Mono stream */ +#define MONAURAL (1) + +/* Stereo stream */ +#define STEREO (2) + +/* define number of bytes in a sample of 24 bits format types */ +/* store 24 bits data in 4 bytes LE */ +#define FMTBIT_S24_LE_BYTES_PER_SAMPLE (4) + +/* store 24 bits data in 3 bytes LE */ +#define FMTBIT_S24_3LE_BYTES_PER_SAMPLE (3) + +/* helper macro to get bytes per sample number */ +#define BYTES_PER_SAMPLE(fmt) (FMTBIT_##fmt##_BYTES_PER_SAMPLE) + +/* check component is created */ +#define COMPONENT_IS_CREATED(n) (((n & XF_HANDLE_CREATED) != 0) ? TRUE : FALSE) + +/* check component is ready */ +#define COMPONENT_IS_READY(n) (((n & XF_HANDLE_READY) != 0) ? TRUE : FALSE) + +/* indicator of stream order */ +#define MIX_UNUSED (0) +#define FIRST_RUN (2) +#define SECOND_RUN (1) + +/* check MIX usage */ +#define MIX_ENABLED(mix_ctl) ((mix_ctl == SECOND_RUN) ? TRUE : FALSE) + +/******************************************************************* + * base structures for ADSP ALSA driver + * ****************************************************************/ + +/** \struct snd_adsp_control + * \brief Structure stores parameters from user + */ +struct snd_adsp_control { + /* Volume rate for playback/record */ + int vol_rate[DIRECT_NUM][MAX_DAI_IDX - 1]; + + /* Volume rate for TDM playback/TDM record */ + int tdm_vol_rate[DIRECT_NUM]; + + /* Out sample rate with Renderer, in sample rate with Capture */ + int sample_rate[DIRECT_NUM][MAX_DAI_IDX - 1]; + + /* Out sample rate for TDM Renderer, in sample rate for TDM Capture */ + int tdm_sample_rate[DIRECT_NUM]; + + /* Output channel of playback */ + int rdr_out_ch[MAX_DAI_IDX - 1]; + + /* Equalizer parameters */ + struct xf_adsp_equalizer_params eqz_params[DIRECT_NUM][MAX_DAI_IDX - 1]; + + /* Equalizer switch */ + int eqz_switch[DIRECT_NUM][MAX_DAI_IDX - 1]; + + /* Indicator of MIX usage */ + int mix_usage; +}; + +/** \struct snd_adsp_base_info + * \brief Structure stores some base information of a stream + */ +struct snd_adsp_base_info { + /* high resolution timer data */ + struct hrtimer hrtimer; + + /* kernel time value in nanosecond */ + ktime_t ktime; + + /* save interrupt state before getting lock */ + unsigned long flag; + + /* high resolution timer state */ + int hrt_state; + + /* target handle id of ALSA driver */ + int handle_id; + + /* data buffer */ + char *buffer[XF_BUF_POOL_SIZE]; + + /* size of each allocated data buffer */ + int buf_bytes; + + /* data index of buffer */ + int buf_idx; + + /* queue index of buffer */ + int buf_queue; + + /* HW index in bytes */ + int hw_idx; + + /* number of bytes in a period */ + int period_bytes; + + /* substream runtime object */ + struct snd_pcm_substream *substream; + + /* indirect PCM data transfer */ + struct snd_pcm_indirect pcm_indirect; + + /* spinlock data */ + spinlock_t lock; + + /* runtime error indicator */ + int runtime_err; +}; + +/** \struct snd_adsp_playback + * \brief Structure stores data for playback function + */ +struct snd_adsp_playback { + /* base information of stream */ + struct snd_adsp_base_info base; + + /* Renderer component data */ + struct xf_adsp_renderer *renderer; + + /* Equalizer component data */ + struct xf_adsp_equalizer *equalizer; + + /* Renderer component state */ + int rdr_state; + + /* Equalizer component state */ + int eqz_state; +}; + +/** \struct snd_adsp_record + * \brief Structure stores data for record function + */ +struct snd_adsp_record { + /* base information of stream */ + struct snd_adsp_base_info base; + + /* Capture component data */ + struct xf_adsp_capture *capture; + + /* Equalizer component data */ + struct xf_adsp_equalizer *equalizer; + + /* Capture component state */ + int cap_state; + + /* Equalizer component state */ + int eqz_state; +}; + +/** \struct snd_adsp_tdm_playback + * \brief Structure stores data for TDM playback function + */ +struct snd_adsp_tdm_playback { + /* base information of stream */ + struct snd_adsp_base_info base; + + /* TDM Renderer component data */ + struct xf_adsp_tdm_renderer *tdm_renderer; + + /* TDM Renderer component state */ + int state; +}; + +/** \struct snd_adsp_tdm_record + * \brief Structure stores data for TDM record function + */ +struct snd_adsp_tdm_record { + /* base information of stream */ + struct snd_adsp_base_info base; + + /* TDM Capture component data */ + struct xf_adsp_tdm_capture *tdm_capture; + + /* TDM Capture component state */ + int state; +}; + +/** \struct snd_adsp_card + * \brief Structure stores data for ALSA sound card + */ +struct snd_adsp_card { + /* playback data */ + struct snd_adsp_playback *playback[MAX_DAI_IDX - 1]; + + /* record data */ + struct snd_adsp_record *record[MAX_DAI_IDX - 1]; + + /* TDM playback data */ + struct snd_adsp_tdm_playback *tdm_playback; + + /* TDM record data */ + struct snd_adsp_tdm_record *tdm_record; + + /* Structure contains params information for control */ + struct snd_adsp_control ctr_if; +}; + +/** HW configuration of ALSA ADSP card for Renderer/Capture */ +static struct snd_pcm_hardware snd_pcm_adsp_hw = { + .info = (SNDRV_PCM_INFO_INTERLEAVED /* PRQA S 1053 14 */ + | SNDRV_PCM_INFO_RESUME + | SNDRV_PCM_INFO_BLOCK_TRANSFER + | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), + .formats = SND_ADSP_PCM_WIDTHS, + .rates = SND_ADSP_SAMPLE_RATES, + .rate_min = 32000, + .rate_max = 48000, + .channels_min = MIN_CHANNEL, + .channels_max = MAX_CHANNEL, + + /* maximum buffer size in bytes */ + .buffer_bytes_max = MAX_BUFFER_BYTES, + + /* minimum size of the periods (frame) in bytes */ + .period_bytes_min = MIN_BUF_SIZE, + + /* maximum size of the periods (frame) in bytes */ + .period_bytes_max = MAX_BUF_SIZE, + + /* minimum periods (frames) in a buffer */ + .periods_min = MIN_PERIOD, + + /* maximum periods (frames) in a buffer */ + .periods_max = MAX_PERIOD, +}; + +/* HW configuration of ALSA ADSP card for TDM */ +static struct snd_pcm_hardware snd_pcm_adsp_tdm_hw = { + .info = (SNDRV_PCM_INFO_INTERLEAVED /* PRQA S 1053 14 */ + | SNDRV_PCM_INFO_RESUME + | SNDRV_PCM_INFO_BLOCK_TRANSFER + | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), + .formats = SND_ADSP_PCM_WIDTHS, + .rates = SND_ADSP_SAMPLE_RATES, + .rate_min = 32000, + .rate_max = 48000, + .channels_min = TDM_MIN_CHANNEL, + .channels_max = TDM_MAX_CHANNEL, + + /* maximum buffer size in bytes */ + .buffer_bytes_max = TDM_MAX_BUFFER_BYTES, + + /* minimum size of the periods (frame) in bytes */ + .period_bytes_min = TDM_MIN_BUF_SIZE, + + /* maximum size of the periods (frame) in bytes */ + .period_bytes_max = TDM_MAX_BUF_SIZE, + + /* minimum periods (frames) in a buffer */ + .periods_min = TDM_MIN_PERIOD, + + /* maximum periods (frames) in a buffer */ + .periods_max = TDM_MAX_PERIOD, +}; + +/******************************************************************* + * function declaration + * ****************************************************************/ + +static int +snd_adsp_rdr_empty_buf_done(void *data, int opcode, int length, char *buffer); +static int +snd_adsp_rdr_fill_buf_done(void *data, int opcode, int length, char *buffer); +static int +snd_adsp_cap_empty_buf_done(void *data, int opcode, int length, char *buffer); +static int +snd_adsp_cap_fill_buf_done(void *data, int opcode, int length, char *buffer); +static int +snd_adsp_get_dai_id_from_substream(struct snd_pcm_substream *substream); +static void * +snd_adsp_get_drvdata_from_substream(struct snd_pcm_substream *substream); +static struct snd_adsp_base_info * +snd_adsp_get_base_from_substream(struct snd_pcm_substream *substream); +static struct snd_adsp_base_info * +snd_adsp_get_base_from_hrt(struct hrtimer *hrt); +static enum hrtimer_restart snd_adsp_hrtimer_func(struct hrtimer *hrt); +static int snd_adsp_playback_init(struct snd_adsp_playback **data, + int eqz_flag, + struct snd_pcm_substream *substream); +static int snd_adsp_record_init(struct snd_adsp_record **data, + int eqz_flag, + struct snd_pcm_substream *substream); +static int snd_adsp_playback_prepare(struct snd_adsp_playback *playback, + struct snd_pcm_substream *substream); +static int snd_adsp_record_prepare(struct snd_adsp_record *record, + struct snd_pcm_substream *substream); +static int snd_adsp_playback_deinit(struct snd_adsp_playback *playback); +static int snd_adsp_record_deinit(struct snd_adsp_record *record); +static int snd_adsp_tdm_playback_init(struct snd_adsp_tdm_playback **data, + struct snd_pcm_substream *substream); +static int snd_adsp_tdm_record_init(struct snd_adsp_tdm_record **data, + struct snd_pcm_substream *substream); +static int +snd_adsp_tdm_playback_prepare(struct snd_adsp_tdm_playback *tdm_playback, + struct snd_pcm_substream *substream); +static int snd_adsp_tdm_record_prepare(struct snd_adsp_tdm_record *tdm_record, + struct snd_pcm_substream *substream); +static int +snd_adsp_tdm_playback_deinit(struct snd_adsp_tdm_playback *tdm_playback); +static int snd_adsp_tdm_record_deinit(struct snd_adsp_tdm_record *tdm_record); +static int snd_adsp_pcm_open(struct snd_pcm_substream *substream); +static int snd_adsp_pcm_close(struct snd_pcm_substream *substream); +static int snd_adsp_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params); +static int snd_adsp_pcm_hw_free(struct snd_pcm_substream *substream); +static int snd_adsp_pcm_prepare(struct snd_pcm_substream *substream); +static int snd_adsp_pcm_trigger(struct snd_pcm_substream *substream, int idx); +static snd_pcm_uframes_t +snd_adsp_pcm_pointer(struct snd_pcm_substream *substream); +static int snd_adsp_pcm_ack(struct snd_pcm_substream *substream); +static void snd_adsp_pcm_transfer(struct snd_pcm_substream *substream, + struct snd_pcm_indirect *rec, size_t bytes); +static int snd_adsp_control_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +static int snd_adsp_control_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int snd_adsp_control_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int snd_adsp_control_eqz_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int snd_adsp_control_eqz_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +static int snd_adsp_control_eqz_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int +snd_adsp_control_eqz_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int +snd_adsp_control_eqz_switch_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +static int +snd_adsp_control_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int +snd_adsp_control_sample_rate_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +static int +snd_adsp_control_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int +snd_adsp_control_eqz_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static void snd_adsp_get_eqz_params_from_control( + struct xf_adsp_equalizer_params *eqz_params, + struct xf_adsp_equalizer_params *eqz_ctr_params, + bool flag); +static int snd_adsp_pcm_new(struct snd_soc_pcm_runtime *runtime); +static int snd_adsp_probe(struct platform_device *pdev); +static int snd_adsp_remove(struct platform_device *pdev); + +/******************************************************************* + * callback function of ADSP control interface + * ****************************************************************/ +/** ************************************************************************** + * \brief event handler callback to notify error from ADSP + * + * \param[in] data Pointer to ADSP ALSA sound card + * \retval 0 Success + *****************************************************************************/ +static int snd_adsp_event_handler(void *data) +{ + struct snd_adsp_base_info *base = (struct snd_adsp_base_info *)data; + + if (base) + base->runtime_err = TRUE; + + return 0; +} + +/** ************************************************************************** + * \brief empty buf done callback for playback/TDM playback functions + * + * \param[in] data Pointer to ADSP ALSA sound card + * \param[in] opcode Opcode of message + * \param[in] length Length of data buffer + * \param[in] buffer Pointer to data buffer + * \retval 0 Success + *****************************************************************************/ +static int +snd_adsp_rdr_empty_buf_done(void *data, int opcode, int length, char *buffer) +{ + struct snd_adsp_base_info *base = (struct snd_adsp_base_info *)data; + + if (base) { + spin_lock_irqsave(&base->lock, base->flag); + + base->buf_queue++; + base->hw_idx += length; /* increase the DMA buffer index */ + + spin_unlock_irqrestore(&base->lock, base->flag); + } + + return 0; +} + +/** ************************************************************************** + * \brief fill buf done callback for playback/TDM playback functions + * + * \param[in] data Pointer to ADSP ALSA sound card + * \param[in] opcode Opcode of message + * \param[in] length Length of data buffer + * \param[in] buffer Pointer to data buffer + * \retval 0 Success + *****************************************************************************/ +static int +snd_adsp_rdr_fill_buf_done(void *data, int opcode, int length, char *buffer) +{ + return 0; +} + +/** ************************************************************************** + * \brief empty buf done callback for record/TDM record functions + * + * \param[in] data Pointer to ADSP ALSA sound card + * \param[in] opcode Opcode of message + * \param[in] length Length of data buffer + * \param[in] buffer Pointer to data buffer + * \retval 0 Success + *****************************************************************************/ +static int +snd_adsp_cap_empty_buf_done(void *data, int opcode, int length, char *buffer) +{ + return 0; +} + +/** ************************************************************************** + * \brief fill buf done callback for record/TDM record functions + * + * \param[in] data Pointer to ADSP ALSA sound card + * \param[in] opcode Opcode of message + * \param[in] length Length of data buffer + * \param[in] buffer Pointer to data buffer + * \retval 0 Success + *****************************************************************************/ +static int +snd_adsp_cap_fill_buf_done(void *data, int opcode, int length, char *buffer) +{ + struct snd_adsp_base_info *base = (struct snd_adsp_base_info *)data; + + if (base) { + spin_lock_irqsave(&base->lock, base->flag); + + base->buf_queue++; + base->hw_idx += length; /* increase the DMA buffer index */ + + spin_unlock_irqrestore(&base->lock, base->flag); + } + + return 0; +} + +/** callback functions for playback/TDM playback */ +static struct xf_callback_func rdr_callbacks = /* PRQA S 3218 */ +{ + .empty_buf_done = &snd_adsp_rdr_empty_buf_done, /* PRQA S 1053 2 */ + .fill_buf_done = &snd_adsp_rdr_fill_buf_done, + .event_handler = &snd_adsp_event_handler +}; + +/** callback functions for record/TDM record */ +static struct xf_callback_func cap_callbacks = /* PRQA S 3218 */ +{ + .empty_buf_done = &snd_adsp_cap_empty_buf_done, /* PRQA S 1053 2 */ + .fill_buf_done = &snd_adsp_cap_fill_buf_done, + .event_handler = &snd_adsp_event_handler +}; + +/******************************************************************* + * helper functions to get some internal data + * ****************************************************************/ + +/** ************************************************************************** + * \brief Get current index of CPU DAI from runtime data of substream + * + * \param[in] substream Pointer to PCM stream data + * \retval id Index of current CPU DAI + *****************************************************************************/ +static int +snd_adsp_get_dai_id_from_substream(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd; + + rtd = (struct snd_soc_pcm_runtime *)substream->private_data; + return rtd->cpu_dai->id; +} + +/** ************************************************************************** + * \brief Get ADSP ALSA driver's data from runtime data of substream + * + * \param[in] substream Pointer to PCM stream data + * \retval pointer Pointer to driver's data + *****************************************************************************/ +static void * +snd_adsp_get_drvdata_from_substream(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd; + + rtd = (struct snd_soc_pcm_runtime *)substream->private_data; + return snd_soc_dai_get_drvdata(rtd->cpu_dai); +} + +/** ************************************************************************** + * \brief Get base's data of playback/record from runtime data of substream + * + * \param[in] substream Pointer to PCM stream data + * \retval pointer Pointer to playback/record's base data + *****************************************************************************/ +static struct snd_adsp_base_info * +snd_adsp_get_base_from_substream(struct snd_pcm_substream *substream) +{ + struct snd_adsp_card *adsp_card; + struct snd_adsp_base_info *base; + int dai_idx; + + adsp_card = snd_adsp_get_drvdata_from_substream(substream); + + /* get DAI index of substream */ + dai_idx = snd_adsp_get_dai_id_from_substream(substream); + + /* get base data of the substream */ + if (dai_idx == RDR_DAI_IDX0 || dai_idx == RDR_DAI_IDX1 || + dai_idx == RDR_DAI_IDX2 || dai_idx == RDR_DAI_IDX3) { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + base = !adsp_card->playback[dai_idx] ? + NULL : &adsp_card->playback[dai_idx]->base; + } else { + base = !adsp_card->record[dai_idx] ? + NULL : &adsp_card->record[dai_idx]->base; + } + } else { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + base = !adsp_card->tdm_playback ? + NULL : &adsp_card->tdm_playback->base; + } else { + base = !adsp_card->tdm_record ? + NULL : &adsp_card->tdm_record->base; + } + } + + return base; +} + +/** *************************************************************************** + * \brief Get playback/record/TDM playback/TDM record's base data + * from hr timer data + * + * \param[in] hrt Pointer to hr timer data + * \retval pointer Pointer to playback/record's base data + *****************************************************************************/ +static struct snd_adsp_base_info * +snd_adsp_get_base_from_hrt(struct hrtimer *hrt) +{ + return (struct snd_adsp_base_info *)hrt; +} + +/***************************************************************************** + * hrtimer interrupt function + * ***************************************************************************/ + +/** ************************************************************************** + * \brief Interrupt function of high resolution timer + * + * \param[in] hrt Pointer to hr timer data + * \retval HRTIMER_RESTART Restart the timer after expire time + *****************************************************************************/ +static enum hrtimer_restart snd_adsp_hrtimer_func(struct hrtimer *hrt) +{ + struct snd_adsp_base_info *base = snd_adsp_get_base_from_hrt(hrt); + + spin_lock_irqsave(&base->lock, base->flag); + if (base->hw_idx != 0) { + spin_unlock_irqrestore(&base->lock, base->flag); + /* update PCM status for the next period */ + snd_pcm_period_elapsed(base->substream); + } else { + spin_unlock_irqrestore(&base->lock, base->flag); + } + + hrtimer_forward_now(hrt, base->ktime); + + return HRTIMER_RESTART; +} + +/***************************************************************************** + * internal functions to manage playback and record functions + * ***************************************************************************/ + +/** ************************************************************************** + * \brief Initialize playback data + * + * \param[out] playback_data Pointer to store playback data + * \param[in] eqz_flag Flag to indicate equalizer usage + * \param[in] substream Pointer to substream data + * \retval EINVAL Failed to initialize playback data + * \retval 0 Success + *****************************************************************************/ +static int snd_adsp_playback_init(struct snd_adsp_playback **playback_data, + int eqz_flag, + struct snd_pcm_substream *substream) +{ + struct snd_adsp_playback *playback; + + /* allocate memory for playback data */ + playback = kmalloc(sizeof(*playback), GFP_KERNEL); + if (!playback) + return -EINVAL; + + /* init params */ + memset(playback, 0, sizeof(struct snd_adsp_playback)); + + /* save the playback data */ + *playback_data = playback; + + /* set handle state as NULL state */ + playback->rdr_state = XF_HANDLE_NULL; + playback->eqz_state = XF_HANDLE_NULL; + playback->base.hrt_state = XF_HANDLE_NULL; + + /* register renderer component */ + if (xf_adsp_renderer_create(&playback->renderer, + &rdr_callbacks, + (void *)&playback->base) < 0) + return -EINVAL; + + /* mark renderer component created */ + playback->rdr_state = XF_HANDLE_CREATED; + + /* set target handle ID as renderer ID */ + playback->base.handle_id = playback->renderer->handle_id; + + if (eqz_flag == EQZ_ON) { + /* create equalizer component when equalizer is used */ + if (xf_adsp_equalizer_create(&playback->equalizer, + &rdr_callbacks, + (void *)&playback->base) < 0) + return -EINVAL; + + /* mark equalizer component created */ + playback->eqz_state = XF_HANDLE_CREATED; + + /* set target handle ID as equalizer ID */ + playback->base.handle_id = playback->equalizer->handle_id; + } + + /* init lock */ + spin_lock_init(&playback->base.lock); + + /* save the substream data */ + playback->base.substream = substream; + + /* init high resolution timer for updating hw status */ + hrtimer_init(&playback->base.hrtimer, + CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + + /* PRQA S 0563 1 */ + playback->base.hrtimer.function = &snd_adsp_hrtimer_func; + playback->base.hrt_state = XF_HANDLE_CREATED; + + /* success */ + return 0; +} + +/** ************************************************************************** + * \brief Initialize record data + * + * \param[out] record_data Pointer to store record data + * \param[in] eqz_flag Flag to indicate equalizer usage + * \param[in] substream Pointer to substream data + * \retval -EINVAL Failed to initialize record data + * \retval 0 Success + *****************************************************************************/ +static int snd_adsp_record_init(struct snd_adsp_record **record_data, + int eqz_flag, + struct snd_pcm_substream *substream) +{ + struct snd_adsp_record *record; + + /* allocate memory for record data */ + record = kmalloc(sizeof(*record), GFP_KERNEL); + if (!record) + return -EINVAL; + + /* init params */ + memset(record, 0, sizeof(struct snd_adsp_record)); + + /* save the record data */ + *record_data = record; + + /* set handle state as NULL state */ + record->cap_state = XF_HANDLE_NULL; + record->eqz_state = XF_HANDLE_NULL; + record->base.hrt_state = XF_HANDLE_NULL; + + /* register capture component */ + if (xf_adsp_capture_create(&record->capture, + &cap_callbacks, + (void *)&record->base) < 0) + return -EINVAL; + + /* mark capture component created */ + record->cap_state = XF_HANDLE_CREATED; + + /* set target handle ID as capture ID */ + record->base.handle_id = record->capture->handle_id; + + /* create equalizer component in case of it being used */ + if (eqz_flag == EQZ_ON) { + if (xf_adsp_equalizer_create(&record->equalizer, + &cap_callbacks, + (void *)&record->base) < 0) + return -EINVAL; + + /* mark equalizer component created */ + record->eqz_state = XF_HANDLE_CREATED; + + /* set target handle ID as equalizer ID */ + record->base.handle_id = record->equalizer->handle_id; + } + + /* init lock */ + spin_lock_init(&record->base.lock); + + /* save the substream data */ + record->base.substream = substream; + + /* init high resolution timer for updating hw status */ + hrtimer_init(&record->base.hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + + /* PRQA S 0563 1 */ + record->base.hrtimer.function = &snd_adsp_hrtimer_func; + record->base.hrt_state = XF_HANDLE_CREATED; + + /* success */ + return 0; +} + +/** ************************************************************************** + * \brief Prepare playback function + * + * \param[out] playback Pointer to playback data + * \param[in] substream Pointer to substream data + * \retval -EINVAL Failed to prepare playback function + * \retval 0 Success + *****************************************************************************/ +static int snd_adsp_playback_prepare(struct snd_adsp_playback *playback, + struct snd_pcm_substream *substream) +{ + struct snd_adsp_card *adsp_card; + int dai_idx, pcm_width, ch, fs, frame_size, vol_rate, hw_buffer_size; + int out_rate; + struct snd_adsp_control *ctr_if; + struct snd_pcm_runtime *runtime; + struct xf_adsp_renderer *renderer; + struct xf_adsp_equalizer *equalizer; + struct snd_adsp_base_info *base; + int i; + + adsp_card = snd_adsp_get_drvdata_from_substream(substream); + dai_idx = snd_adsp_get_dai_id_from_substream(substream); + ctr_if = &adsp_card->ctr_if; + runtime = substream->runtime; + renderer = playback->renderer; + equalizer = playback->equalizer; + base = &playback->base; + + /* runtime parameter */ + fs = runtime->rate; + ch = runtime->channels; + pcm_width = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? 16 : 24; + frame_size = runtime->period_size; + vol_rate = ctr_if->vol_rate[DIRECT_PLAYBACK][dai_idx]; + out_rate = ctr_if->sample_rate[DIRECT_PLAYBACK][dai_idx]; + hw_buffer_size = snd_pcm_lib_buffer_bytes(substream); + + /* get number of bytes in a period */ + base->period_bytes = snd_pcm_lib_period_bytes(substream); + + if (pcm_width == 16) + base->buf_bytes = base->period_bytes; + else + base->buf_bytes = (base->period_bytes * + BYTES_PER_SAMPLE(S24_3LE)) / BYTES_PER_SAMPLE(S24_LE); + + /* pcm indirect configuration */ + base->pcm_indirect.hw_buffer_size = hw_buffer_size; + base->pcm_indirect.sw_buffer_size = base->pcm_indirect.hw_buffer_size; + + /* it should equal to a period size in bytes */ + base->pcm_indirect.hw_queue_size = base->period_bytes; + + /* set parameters when Renderer is not ready */ + if (COMPONENT_IS_READY(playback->rdr_state) == FALSE) { + struct xf_adsp_renderer_params *params = &renderer->params; + + /* apply renderer parameters */ + params->in_rate = fs; + params->channel = ch; + params->pcm_width = pcm_width; + params->frame_size = frame_size; + + if (ctr_if->mix_usage == SECOND_RUN) + params->mix_ctrl = ctr_if->mix_usage; + else + params->mix_ctrl = MIX_UNUSED; + + /* set flow as ADSP->PDMA0->SRC0->PDMA1->SSI0 */ + params->dev1 = SRC0; + params->dev2 = SSI00; + params->dma1 = PDMA_CH00; + params->dma2 = PDMA_CH01; + + /* when MIX is enabled, change to DMAC transfer type to save */ + /* hw FIFO */ + if (MIX_ENABLED(params->mix_ctrl) == TRUE) + params->dma1 = ADMAC_CH01; + + /* set volume rate if it is set by user or default value */ + /* is 100% */ + if (vol_rate >= 0) + params->vol_rate = vol_rate; + else + params->vol_rate = (1 << 20); + + /* set output channel if it is set by user */ + if (ctr_if->rdr_out_ch[dai_idx] >= MONAURAL) + params->out_channel = ctr_if->rdr_out_ch[dai_idx]; + else + params->out_channel = params->channel; + + /* set sample rate output if it is set by user */ + if (out_rate >= 0) + params->out_rate = out_rate; + + /* set parameters to ADSP Renderer plugin */ + if (xf_adsp_renderer_set_params(renderer) != 0) + return -EINVAL; + + /* allocate buffer pool to prepare the execution */ + renderer->buf_pool = xf_adsp_allocate_mem_pool( + XF_BUF_POOL_SIZE, base->buf_bytes); + + if (IS_ERR(renderer->buf_pool)) /* PRQA S 306*/ + return -EINVAL; + + for (i = 0; i < XF_BUF_POOL_SIZE; i++) { + base->buffer[i] = xf_adsp_get_data_from_pool( + renderer->buf_pool, i); + + base->buf_queue++; + memset(base->buffer[i], 0, base->buf_bytes); + } + + /* mark Renderer ready */ + playback->rdr_state |= XF_HANDLE_READY; + + /* set parameters for Equalizer if it is used */ + if (COMPONENT_IS_CREATED(playback->eqz_state) == TRUE) { + /* apply Equalizer parameter setting */ + equalizer->params.channel = ch; + equalizer->params.pcm_width = pcm_width; + equalizer->params.rate = fs; + + /* get equalizer parameters from control interface */ + /* data */ + snd_adsp_get_eqz_params_from_control( + &equalizer->params, + &ctr_if->eqz_params[DIRECT_PLAYBACK][dai_idx], + true); + + /* set parameters to Equalizer plugin */ + if (xf_adsp_equalizer_set_params(equalizer) != 0) + return -EINVAL; + + /* route Equalizer to Renderer */ + if (xf_adsp_route(equalizer->handle_id, + renderer->handle_id, + XF_BUF_POOL_SIZE, + base->buf_bytes) != 0) + return -EINVAL; + + /* mark Equalizer ready */ + playback->eqz_state |= XF_HANDLE_READY; + + /* prepare data before start PCM */ + /* PRQA S 2462 1 */ /* PRQA S 2463 1 */ + for (i = 0; i < XF_BUF_POOL_SIZE; i++) { + /* send buffer to plugin to kick */ + /* init-processing */ + if (xf_adsp_empty_this_buffer( + base->handle_id, + base->buffer[i], + base->buf_bytes) != 0) + return -EINVAL; + + spin_lock_irqsave(&base->lock, base->flag); + base->buf_queue--; + spin_unlock_irqrestore(&base->lock, base->flag); + } + } else { + /* send zero buffer to plugin to kick */ + /* init-processing */ + if (xf_adsp_empty_this_buffer(base->handle_id, + base->buffer[0], + base->buf_bytes) != 0) + return -EINVAL; + + spin_lock_irqsave(&base->lock, base->flag); + base->buf_queue--; + spin_unlock_irqrestore(&base->lock, base->flag); + } + + /* wait until all the buffer have been consummed */ + while (base->buf_queue != XF_BUF_POOL_SIZE) { + schedule_timeout_interruptible(2); + if (signal_pending(current)) + break; + + /* check the error from initialization */ + if (base->runtime_err) + return -EINVAL; + } + + /* reset HW index */ + base->hw_idx = 0; + } + + /* success */ + return 0; +} + +/** ************************************************************************** + * \brief Prepare record function + * + * \param[out] record Pointer to record data + * \param[in] substream Pointer to substream data + * \retval -EINVAL Failed to prepare record function + * \retval 0 Success + *****************************************************************************/ +static int snd_adsp_record_prepare(struct snd_adsp_record *record, + struct snd_pcm_substream *substream) +{ + struct snd_adsp_card *adsp_card; + int dai_idx, pcm_width, ch, fs, frame_size, vol_rate, in_rate; + int hw_buffer_size, hw_queue_size; + struct snd_adsp_control *ctr_if; + struct snd_pcm_runtime *runtime; + struct xf_adsp_capture *capture; + struct xf_adsp_equalizer *equalizer; + struct snd_adsp_base_info *base; + int i; + + adsp_card = snd_adsp_get_drvdata_from_substream(substream); + dai_idx = snd_adsp_get_dai_id_from_substream(substream); + ctr_if = &adsp_card->ctr_if; + runtime = substream->runtime; + capture = record->capture; + equalizer = record->equalizer; + base = &record->base; + + /* runtime parameter */ + fs = runtime->rate; + ch = runtime->channels; + pcm_width = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? 16 : 24; + frame_size = runtime->period_size; + vol_rate = ctr_if->vol_rate[DIRECT_CAPTURE][dai_idx]; + in_rate = ctr_if->sample_rate[DIRECT_CAPTURE][dai_idx]; + hw_buffer_size = snd_pcm_lib_buffer_bytes(substream); + + /* total size of allocated buffers */ + hw_queue_size = base->period_bytes * XF_BUF_POOL_SIZE; + + /* get number of bytes in a period */ + base->period_bytes = snd_pcm_lib_period_bytes(substream); + + if (pcm_width == 16) + base->buf_bytes = base->period_bytes; + else + base->buf_bytes = ((base->period_bytes * + BYTES_PER_SAMPLE(S24_3LE)) / BYTES_PER_SAMPLE(S24_LE)); + + /* pcm indirect configuration */ + base->pcm_indirect.hw_buffer_size = hw_buffer_size; + base->pcm_indirect.sw_buffer_size = base->pcm_indirect.hw_buffer_size; + base->pcm_indirect.hw_queue_size = hw_queue_size; + + /* prepare parameters to set to Capture plugin when it is not yet */ + /* ready */ + if (COMPONENT_IS_READY(record->cap_state) == FALSE) { + struct xf_adsp_capture_params *params = &capture->params; + + /* apply capture parameters */ + params->out_rate = fs; + params->channel = ch; + params->pcm_width = pcm_width; + params->frame_size = frame_size; + + params->dev1 = SRC0; + params->dev2 = SSI10; + params->dma1 = PDMA_CH00; + params->dma2 = PDMA_CH01; + + /* set volume rate if it is set by user or default volume as */ + /* 100% */ + if (vol_rate >= 0) + params->vol_rate = vol_rate; + else + params->vol_rate = (1 << 20); + + /* set sample rate input if it is set by user */ + if (in_rate >= 0) + params->in_rate = in_rate; + + /* allocate buffer pool to prepare the execution */ + capture->buf_pool = xf_adsp_allocate_mem_pool( + XF_BUF_POOL_SIZE, base->buf_bytes); + + if (IS_ERR(capture->buf_pool)) /* PRQA S 306 */ + return -EINVAL; + + for (i = 0; i < XF_BUF_POOL_SIZE; i++) { + base->buffer[i] = xf_adsp_get_data_from_pool( + capture->buf_pool, i); + + base->buf_queue++; + } + + /* set parameters to ADSP Capture plugin */ + if (xf_adsp_capture_set_params(capture) != 0) + return -EINVAL; + + /* mark Capture ready */ + record->cap_state |= XF_HANDLE_READY; + + /* set parameters for Equalizer if it's used */ + if (COMPONENT_IS_CREATED(record->eqz_state) == TRUE) { + /* apply Equalizer parameter setting */ + equalizer->params.channel = ch; + equalizer->params.pcm_width = pcm_width; + equalizer->params.rate = fs; + + /* get equalizer parameter from control interface */ + /* data */ + snd_adsp_get_eqz_params_from_control( + &equalizer->params, + &ctr_if->eqz_params[DIRECT_CAPTURE][dai_idx], + true); + + /* set parameters to Equalizer plugin */ + if (xf_adsp_equalizer_set_params(equalizer) != 0) + return -EINVAL; + + /* route Capture to Equalizer */ + if (xf_adsp_route(capture->handle_id, + equalizer->handle_id, + XF_BUF_POOL_SIZE, + base->buf_bytes) != 0) + return -EINVAL; + + /* mark Equalizer ready */ + record->eqz_state |= XF_HANDLE_READY; + } + + /* kick init process by sending a zero buffer length */ + xf_adsp_fill_this_buffer(base->handle_id, base->buffer[0], 0); + + spin_lock_irqsave(&base->lock, base->flag); + base->buf_queue--; + spin_unlock_irqrestore(&base->lock, base->flag); + + /* wait until finishing initialization */ + while (base->buf_queue != XF_BUF_POOL_SIZE) { + schedule_timeout_interruptible(2); + if (signal_pending(current)) + break; + + /* check the error from initialization */ + if (base->runtime_err) + return -EINVAL; + } + + if (COMPONENT_IS_CREATED(record->eqz_state) == TRUE) { + /* PRQA S 2462 1 */ /* PRQA S 2463 1 */ + for (i = 0; i < XF_BUF_POOL_SIZE; i++) { + /* send buffer to plugin */ + if (xf_adsp_fill_this_buffer( + base->handle_id, + base->buffer[i], + base->buf_bytes) != 0) + return -EINVAL; + + spin_lock_irqsave(&base->lock, base->flag); + base->buf_queue--; + spin_unlock_irqrestore(&base->lock, base->flag); + } + + /* wait until all the buffer have been responsed */ + while (base->buf_queue != XF_BUF_POOL_SIZE) { + schedule_timeout_interruptible(2); + if (signal_pending(current)) + break; + + /* check the error from initialization */ + if (base->runtime_err) + return -EINVAL; + } + } + + /* reset hw data position */ + base->hw_idx = 0; + } + + /* success */ + return 0; +} + +/** ************************************************************************** + * \brief Deinitialize playback function + * + * \param[out] playback Pointer to playback data + * \retval -EINVAL Failed to deinitialize playback function + * \retval 0 Success + *****************************************************************************/ +static int snd_adsp_playback_deinit(struct snd_adsp_playback *playback) +{ + int ret = 0; + + /* perform de-initialization if playback has been created already */ + if (playback) { + /* perform completion process */ + if (COMPONENT_IS_CREATED(playback->rdr_state) == TRUE) { + /* send buffer with zero length to plugin for */ + /* completion process *//* PRQA S 3200 2 */ + xf_adsp_empty_this_buffer(playback->base.handle_id, + NULL, 0); + + /* free buffer pool */ /* PRQA S 3200 1 */ + xf_adsp_free_mem_pool(playback->renderer->buf_pool); + + /* destroy Renderer */ + if (xf_adsp_renderer_destroy(playback->renderer) != 0) + ret = -EINVAL; + + playback->renderer = NULL; + } + + /* destroy Equalizer if it is used */ + if (COMPONENT_IS_CREATED(playback->eqz_state) == TRUE) { + if (xf_adsp_equalizer_destroy(playback->equalizer)) + ret = -EINVAL; + + playback->equalizer = NULL; + } + + /* canncel timer interrupt */ + if (COMPONENT_IS_CREATED(playback->base.hrt_state) == TRUE) + hrtimer_cancel(&playback->base.hrtimer); + + /* free playback data */ + kfree(playback); + } + + return ret; +} + +/** ************************************************************************** + * \brief Deinitialize record function + * + * \param[out] record Pointer to record data + * \retval -EINVAL Failed to deinitialize record function + * \retval 0 Success + *****************************************************************************/ +static int snd_adsp_record_deinit(struct snd_adsp_record *record) +{ + int ret = 0; + + /* perform de-initialization if record has been created already */ + if (!record) + return ret; + + /* perform completion process */ + if (COMPONENT_IS_CREATED(record->cap_state) == TRUE) { + /* send buffer with zero length to plugin for */ + /* completion process *//* PRQA S 3200 2 */ + xf_adsp_empty_this_buffer(record->base.handle_id, NULL, 0); + + /* free buffer pool */ /* PRQA S 3200 1 */ + xf_adsp_free_mem_pool(record->capture->buf_pool); + + if (xf_adsp_capture_destroy(record->capture)) + ret = -EINVAL; + + record->capture = NULL; + } + + /* destroy Equalizer if it is used */ + if (COMPONENT_IS_CREATED(record->eqz_state) == TRUE) { + if (xf_adsp_equalizer_destroy(record->equalizer) != 0) + ret = -EINVAL; + + record->equalizer = NULL; + } + + /* canncel timer interrupt */ + if (COMPONENT_IS_CREATED(record->base.hrt_state) == TRUE) + hrtimer_cancel(&record->base.hrtimer); + + /* free record data */ + kfree(record); + + return ret; +} + +/***************************************************************************** + * internal functions to manage TDM playback and TDM record functions + * ***************************************************************************/ + +/** ************************************************************************** + * \brief Initialize TDM playback data + * + * \param[out] tdm_playback_data Pointer to store TDM playback data + * \param[in] substream Pointer to substream data + * \retval -EINVAL Failed to initialize TDM playback data + * \retval 0 Success + *****************************************************************************/ +static int +snd_adsp_tdm_playback_init(struct snd_adsp_tdm_playback **tdm_playback_data, + struct snd_pcm_substream *substream) +{ + struct snd_adsp_tdm_playback *tdm_playback; + + /* allocate memory for TDM playback data */ + tdm_playback = kmalloc(sizeof(*tdm_playback), GFP_KERNEL); + + if (!tdm_playback) + return -EINVAL; + + /* init params */ + memset(tdm_playback, 0, sizeof(struct snd_adsp_tdm_playback)); + + /* save the TDM playback data */ + *tdm_playback_data = tdm_playback; + + /* set handle state as NULL state */ + tdm_playback->state = XF_HANDLE_NULL; + tdm_playback->base.hrt_state = XF_HANDLE_NULL; + + /* register TDM renderer component */ + if (xf_adsp_tdm_renderer_create(&tdm_playback->tdm_renderer, + &rdr_callbacks, + (void *)&tdm_playback->base) < 0) + return -EINVAL; + + /* mark TDM renderer component created */ + tdm_playback->state = XF_HANDLE_CREATED; + + /* set target handle ID as TDM renderer ID */ + tdm_playback->base.handle_id = tdm_playback->tdm_renderer->handle_id; + + /* init lock */ + spin_lock_init(&tdm_playback->base.lock); + + /* save the substream data */ + tdm_playback->base.substream = substream; + + /* init high resolution timer for updating hw status */ + hrtimer_init(&tdm_playback->base.hrtimer, + CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + + /* PRQA S 0563 1 */ + tdm_playback->base.hrtimer.function = &snd_adsp_hrtimer_func; + tdm_playback->base.hrt_state = XF_HANDLE_CREATED; + + return 0; +} + +/** ************************************************************************** + * \brief Initialize TDM record data + * + * \param[out] tdm_record_data Pointer to store TDM record data + * \param[in] substream Pointer to substream data + * \retval -EINVAL Failed to initialize TDM record data + * \retval 0 Success + *****************************************************************************/ +static int +snd_adsp_tdm_record_init(struct snd_adsp_tdm_record **tdm_record_data, + struct snd_pcm_substream *substream) +{ + struct snd_adsp_tdm_record *tdm_record; + + /* allocate memory for TDM record data */ + tdm_record = kmalloc(sizeof(*tdm_record), GFP_KERNEL); + if (!tdm_record) + return -EINVAL; + + /* init params */ + memset(tdm_record, 0, sizeof(struct snd_adsp_tdm_record)); + + /* save the TDM record data */ + *tdm_record_data = tdm_record; + + /* set handle state as NULL state */ + tdm_record->state = XF_HANDLE_NULL; + tdm_record->base.hrt_state = XF_HANDLE_NULL; + + /* register TDM Capture component */ + if (xf_adsp_tdm_capture_create(&tdm_record->tdm_capture, + &cap_callbacks, + (void *)&tdm_record->base) != 0) + return -EINVAL; + + /* mark TDM capture component created */ + tdm_record->state = XF_HANDLE_CREATED; + + /* set target handle ID as TDM capture ID */ + tdm_record->base.handle_id = tdm_record->tdm_capture->handle_id; + + /* init lock */ + spin_lock_init(&tdm_record->base.lock); + + /* save the substream data */ + tdm_record->base.substream = substream; + + /* init high resolution timer for updating hw status */ + hrtimer_init(&tdm_record->base.hrtimer, + CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + + /* PRQA S 0563 1 */ + tdm_record->base.hrtimer.function = &snd_adsp_hrtimer_func; + tdm_record->base.hrt_state = XF_HANDLE_CREATED; + + /* success */ + return 0; +} + +/** ************************************************************************** + * \brief Prepare TDM playback function + * + * \param[out] tdm_playback Pointer to TDM playback data + * \param[in] substream Pointer to substream data + * \retval -EINVAL Failed to prepare TDM playback function + * \retval 0 Success + *****************************************************************************/ +static int +snd_adsp_tdm_playback_prepare(struct snd_adsp_tdm_playback *tdm_playback, + struct snd_pcm_substream *substream) +{ + struct snd_adsp_card *adsp_card; + struct snd_adsp_control *ctr_if; + struct snd_pcm_runtime *runtime; + struct xf_adsp_tdm_renderer *tdm_renderer; + struct snd_adsp_base_info *base; + int i; + int pcm_width, ch_mode, fs, frame_size, hw_buffer_size; + + adsp_card = snd_adsp_get_drvdata_from_substream(substream); + ctr_if = &adsp_card->ctr_if; + runtime = substream->runtime; + tdm_renderer = tdm_playback->tdm_renderer; + base = &tdm_playback->base; + + /* runtime parameter */ + fs = runtime->rate; + pcm_width = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? 16 : 24; + frame_size = runtime->period_size; + + ch_mode = (runtime->channels == 8) ? + XA_TDM_RDR_CHANNEL_MODE_1X8 : XA_TDM_RDR_CHANNEL_MODE_1X6; + + hw_buffer_size = snd_pcm_lib_buffer_bytes(substream); + + /* get number of bytes in a period */ + base->period_bytes = snd_pcm_lib_period_bytes(substream); + + if (pcm_width == 16) + base->buf_bytes = base->period_bytes; + else + base->buf_bytes = ((base->period_bytes * + BYTES_PER_SAMPLE(S24_3LE)) / BYTES_PER_SAMPLE(S24_LE)); + + /* pcm indirect configuration */ + base->pcm_indirect.hw_buffer_size = hw_buffer_size; + base->pcm_indirect.sw_buffer_size = base->pcm_indirect.hw_buffer_size; + + /* it should equal to a period size in bytes */ + base->pcm_indirect.hw_queue_size = base->period_bytes; + + /* prepare parameters to set to TDM playback as it is not ready */ + if (COMPONENT_IS_READY(tdm_playback->state) == FALSE) { + struct xf_adsp_tdm_renderer_params *params; + + params = &tdm_renderer->params; + + /* apply renderer parameters */ + params->in_rate = fs; + params->ch_mode = ch_mode; + params->pcm_width = pcm_width; + params->frame_size = frame_size; + + /* setting Audio device indexes */ + params->dma1 = ADMAC_CH00; /* use DMAC for transfer data */ + params->dma2 = PDMA_CH03; + params->dev1 = SRC1; + params->dev2 = SSI30; /* set SSI index to SSI30 */ + + /* set volume rate if it is set by user or default value as */ + /* 100% */ + params->vol_rate = (ctr_if->tdm_vol_rate[DIRECT_PLAYBACK] >= 0) + ? ctr_if->tdm_vol_rate[DIRECT_PLAYBACK] : (1 << 20); + + /* set output sampling rate if it is set by user */ + if (ctr_if->tdm_sample_rate[DIRECT_PLAYBACK] >= 0) + params->out_rate = + ctr_if->tdm_sample_rate[DIRECT_PLAYBACK]; + + /* set parameters to ADSP TDM Renderer plugin */ + if (xf_adsp_tdm_renderer_set_params(tdm_renderer) != 0) + return -EINVAL; + + /* allocate buffer pool to prepare the execution */ + tdm_renderer->buf_pool = xf_adsp_allocate_mem_pool( + XF_BUF_POOL_SIZE, base->buf_bytes); + + if (IS_ERR(tdm_renderer->buf_pool)) /* PRQA S 306*/ + return -EINVAL; + + for (i = 0; i < XF_BUF_POOL_SIZE; i++) { + base->buffer[i] = xf_adsp_get_data_from_pool( + tdm_renderer->buf_pool, i); + + base->buf_queue++; + } + + /* mark TDM Renderer created */ + tdm_playback->state |= XF_HANDLE_READY; + + /* send zero buffer to plugin to kick init-processing */ + memset(base->buffer[0], 0, base->buf_bytes); + + if (xf_adsp_empty_this_buffer(base->handle_id, base->buffer[0], + base->buf_bytes) != 0) + return -EINVAL; + + spin_lock_irqsave(&base->lock, base->flag); + base->buf_queue--; + spin_unlock_irqrestore(&base->lock, base->flag); + + /* wait until all the buffer have been consummed */ + while (base->buf_queue != XF_BUF_POOL_SIZE) { + schedule_timeout_interruptible(2); + if (signal_pending(current)) + break; + + /* check the error from initialization */ + if (base->runtime_err) + return -EINVAL; + } + + /* reset HW index */ + base->hw_idx = 0; + } + + /* success */ + return 0; +} + +/** ************************************************************************** + * \brief Prepare TDM record function + * + * \param[out] tdm_record Pointer to TDM record data + * \param[in] substream Pointer to substream data + * \retval -EINVAL Failed to prepare TDM record function + * \retval 0 Success + *****************************************************************************/ +static int snd_adsp_tdm_record_prepare(struct snd_adsp_tdm_record *tdm_record, + struct snd_pcm_substream *substream) +{ + struct snd_adsp_card *adsp_card = + snd_adsp_get_drvdata_from_substream(substream); + struct snd_adsp_control *ctr_if = &adsp_card->ctr_if; + struct snd_pcm_runtime *runtime = substream->runtime; + struct xf_adsp_tdm_capture *tdm_capture = tdm_record->tdm_capture; + struct snd_adsp_base_info *base = &tdm_record->base; + int i; + int pcm_width, ch_mode, fs, frame_size; + + /* runtime parameter */ + fs = runtime->rate; + + ch_mode = (runtime->channels == 8) ? + XA_TDM_RDR_CHANNEL_MODE_1X8 : XA_TDM_RDR_CHANNEL_MODE_1X6; + + pcm_width = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? 16 : 24; + frame_size = runtime->period_size; + + /* get number of bytes in a period */ + base->period_bytes = snd_pcm_lib_period_bytes(substream); + base->buf_bytes = (pcm_width == 16) ? + base->period_bytes : ((base->period_bytes * + BYTES_PER_SAMPLE(S24_3LE)) / + BYTES_PER_SAMPLE(S24_LE)); + + /* pcm indirect configuration */ + base->pcm_indirect.hw_buffer_size = snd_pcm_lib_buffer_bytes(substream); + base->pcm_indirect.sw_buffer_size = base->pcm_indirect.hw_buffer_size; + + /* total size of allocated buffers */ + base->pcm_indirect.hw_queue_size = base->period_bytes * + XF_BUF_POOL_SIZE; + + /* prepare parameters to set to TDM Capture as it is not yet ready */ + if (COMPONENT_IS_READY(tdm_record->state) == FALSE) { + struct xf_adsp_tdm_capture_params *params; + + params = &tdm_capture->params; + + /* apply capture parameters */ + params->out_rate = fs; + params->ch_mode = ch_mode; + params->pcm_width = pcm_width; + params->frame_size = frame_size; + + /* setting Audio device indexes */ + params->dma1 = PDMA_CH00; + params->dma2 = PDMA_CH01; + params->dev1 = SRC0; + params->dev2 = SSI40; /* set input device is SSI40 */ + + /* set volume rate if it is set by user or default value as */ + /* 100% */ + params->vol_rate = (ctr_if->tdm_vol_rate[DIRECT_CAPTURE] >= 0) + ? ctr_if->tdm_vol_rate[DIRECT_CAPTURE] : (1 << 20); + + /* set input rate if it is set by user */ + if (ctr_if->tdm_sample_rate[DIRECT_CAPTURE] >= 0) { + params->in_rate = + ctr_if->tdm_sample_rate[DIRECT_CAPTURE]; + } + + /* allocate buffer pool to prepare the execution */ + tdm_capture->buf_pool = xf_adsp_allocate_mem_pool( + XF_BUF_POOL_SIZE, base->buf_bytes); + + if (IS_ERR(tdm_capture->buf_pool)) /* PRQA S 306 */ + return -EINVAL; + + for (i = 0; i < XF_BUF_POOL_SIZE; i++) { + base->buffer[i] = xf_adsp_get_data_from_pool( + tdm_capture->buf_pool, i); + + base->buf_queue++; + } + + /* set parameters to ADSP TDM Capture plugin */ + if (xf_adsp_tdm_capture_set_params(tdm_capture) != 0) + return -EINVAL; + + /* mark TDM Capture ready */ + tdm_record->state |= XF_HANDLE_READY; + + /* kick init process by sending a zero buffer length */ + xf_adsp_fill_this_buffer(base->handle_id, base->buffer[0], 0); + + spin_lock_irqsave(&base->lock, base->flag); + base->buf_queue--; + spin_unlock_irqrestore(&base->lock, base->flag); + + /* wait until finishing initialization */ + while (base->buf_queue != XF_BUF_POOL_SIZE) { + schedule_timeout_interruptible(2); + if (signal_pending(current)) + break; + + /* check the error from initialization */ + if (base->runtime_err) + return -EINVAL; + } + + /* reset hw data position */ + base->hw_idx = 0; + } + + /* success */ + return 0; +} + +/** ************************************************************************** + * \brief Deinitialize TDM playback function + * + * \param[out] tdm_playback Pointer to TDM playback data + * \retval -EINVAL Failed to deinitialize TDM playback function + * \retval 0 Success + *****************************************************************************/ +static int +snd_adsp_tdm_playback_deinit(struct snd_adsp_tdm_playback *tdm_playback) +{ + int ret = 0; + + /* perform de-initialization if TDM playback has been created */ + if (!tdm_playback) + return ret; + + /* perform completion process */ + if (COMPONENT_IS_CREATED(tdm_playback->state) == TRUE) { + /* send buffer with zero length to plugin for */ + /* completion process */ + /* PRQA S 3200 2 */ + xf_adsp_empty_this_buffer(tdm_playback->base.handle_id, + NULL, 0); + + /* free buffer pool *//* PRQA S 3200 2 */ + xf_adsp_free_mem_pool(tdm_playback->tdm_renderer->buf_pool); + + /* destroy TDM Renderer component */ + if (xf_adsp_tdm_renderer_destroy( + tdm_playback->tdm_renderer) != 0) + ret = -EINVAL; + + tdm_playback->tdm_renderer = NULL; + } + + /* canncel timer interrupt */ + if (COMPONENT_IS_CREATED(tdm_playback->base.hrt_state) == TRUE) + hrtimer_cancel(&tdm_playback->base.hrtimer); + + /* free playback data */ + kfree(tdm_playback); + + return ret; +} + +/** ************************************************************************** + * \brief Deinitialize TDM record function + * + * \param[out] tdm_record Pointer to TDM record data + * \retval -EINVAL Failed to deinitialize TDM record function + * \retval 0 Success + *****************************************************************************/ +static int snd_adsp_tdm_record_deinit(struct snd_adsp_tdm_record *tdm_record) +{ + int ret = 0; + + /* perform de-initialization if TDM record has been created already */ + if (!tdm_record) + return ret; + + /* perform completion process */ + if (COMPONENT_IS_CREATED(tdm_record->state) == TRUE) { + /* send buffer with zero length to plugin for */ + /* completion process */ + /* PRQA S 3200 2 */ + xf_adsp_empty_this_buffer(tdm_record->base.handle_id, NULL, 0); + + /* free buffer pool *//* PRQA S 3200 2 */ + xf_adsp_free_mem_pool(tdm_record->tdm_capture->buf_pool); + + /* destroy TDM Capture component */ + if (xf_adsp_tdm_capture_destroy(tdm_record->tdm_capture) != 0) + ret = -EINVAL; + + tdm_record->tdm_capture = NULL; + } + + /* canncel timer interrupt */ + if (COMPONENT_IS_CREATED(tdm_record->base.hrt_state) == TRUE) + hrtimer_cancel(&tdm_record->base.hrtimer); + + /* free record data */ + kfree(tdm_record); + + return ret; +} + +/***************************************************************************** + * callback functions of ADSP ALSA driver + * ***************************************************************************/ + +/** ************************************************************************** + * \brief Open a playback/TDM playback or record/TDM record stream + * + * \param[in] substream Pointer to substream object + * \retval 0 Success + * \retval -EINVAL Error + *****************************************************************************/ +static int snd_adsp_pcm_open(struct snd_pcm_substream *substream) +{ + /* get ADSP soundcard and CPU DAI index */ + struct snd_adsp_card *adsp_card; + int dai_idx = snd_adsp_get_dai_id_from_substream(substream); + struct snd_adsp_control *ctr_if; + + adsp_card = snd_adsp_get_drvdata_from_substream(substream); + ctr_if = &adsp_card->ctr_if; + + if (dai_idx == RDR_DAI_IDX0 || dai_idx == RDR_DAI_IDX1 || + dai_idx == RDR_DAI_IDX2 || dai_idx == RDR_DAI_IDX3) { + /* register data for playback/record functions */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* perform playback initialization */ + if (snd_adsp_playback_init( + &adsp_card->playback[dai_idx], + ctr_if->eqz_switch[DIRECT_PLAYBACK][dai_idx], + substream) < 0) { + /* perform playback de-initialization when */ + /* the initialization fails */ + snd_adsp_playback_deinit( + adsp_card->playback[dai_idx]); + + adsp_card->playback[dai_idx] = NULL; + return -EINVAL; + } + } else { + /* perform record initialization */ + if (snd_adsp_record_init( + &adsp_card->record[dai_idx], + ctr_if->eqz_switch[DIRECT_CAPTURE][dai_idx], + substream) < 0) { + /* perform record de-initialization when the */ + /* initialization fails */ + snd_adsp_record_deinit( + adsp_card->record[dai_idx]); + + adsp_card->record[dai_idx] = NULL; + return -EINVAL; + } + } + + /* save the hardware parameters */ + snd_soc_set_runtime_hwparams(substream, &snd_pcm_adsp_hw); + + /* each period has a frame size */ + snd_pcm_hw_constraint_single(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + FRAME_SIZE); + } else { + /* register data for TDM playback/record functions */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* perform TDM playback initialization */ + if (snd_adsp_tdm_playback_init( + &adsp_card->tdm_playback, + substream) < 0) { + /* perform TDM playback de-initialization */ + /* when the initialization fails */ + snd_adsp_tdm_playback_deinit( + adsp_card->tdm_playback); + + adsp_card->tdm_playback = NULL; + return -EINVAL; + } + } else { + /* perform TDM record initialization */ + if (snd_adsp_tdm_record_init(&adsp_card->tdm_record, + substream) < 0) { + /* perform TDM record de-initialization */ + /* when the initialization fails */ + snd_adsp_tdm_record_deinit( + adsp_card->tdm_record); + + adsp_card->tdm_record = NULL; + return -EINVAL; + } + } + + /* save the hardware parameters */ + snd_soc_set_runtime_hwparams(substream, &snd_pcm_adsp_tdm_hw); + + /* each period has a frame size */ + snd_pcm_hw_constraint_single(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + TDM_FRAME_SIZE); + } + + snd_pcm_hw_constraint_integer(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + + return 0; +} + +/** ************************************************************************** + * \brief Close a playback/TDM playback or record/TDM record stream + * + * \param[in] substream Pointer to substream object + * \retval 0 Success + * \retval -EINVAL Error + *****************************************************************************/ +static int snd_adsp_pcm_close(struct snd_pcm_substream *substream) +{ + /* get ADSP soundcard and CPU DAI index */ + struct snd_adsp_card *adsp_card = + snd_adsp_get_drvdata_from_substream(substream); + int dai_idx = snd_adsp_get_dai_id_from_substream(substream); + int err = 0; + + if (dai_idx == RDR_DAI_IDX0 || dai_idx == RDR_DAI_IDX1 || + dai_idx == RDR_DAI_IDX2 || dai_idx == RDR_DAI_IDX3) { + /* destroy Renderer/Capture or Equalizer (if used) */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (snd_adsp_playback_deinit( + adsp_card->playback[dai_idx]) < 0) + err = -EINVAL; + + adsp_card->playback[dai_idx] = NULL; + } else { + if (snd_adsp_record_deinit( + adsp_card->record[dai_idx]) < 0) + err = -EINVAL; + + adsp_card->record[dai_idx] = NULL; + } + } else { + /* destroy TDM Renderer/TDM Capture */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (snd_adsp_tdm_playback_deinit( + adsp_card->tdm_playback) < 0) + err = -EINVAL; + + adsp_card->tdm_playback = NULL; + } else { + if (snd_adsp_tdm_record_deinit( + adsp_card->tdm_record) < 0) + err = -EINVAL; + + adsp_card->tdm_record = NULL; + } + } + + return err; +} + +/** ************************************************************************** + * \brief Allocate ALSA buffer and calculate expire time of hr timer + * + * \param[in] substream Pointer to substream object + * \retval 0 Success + * \retval -ENOMEM Cannot allocate ALSA buffer + *****************************************************************************/ +static int snd_adsp_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct snd_adsp_base_info *base; + int err = 0; + + base = snd_adsp_get_base_from_substream(substream); + + /* set expire time of hrtimer, this value should be time for */ + /* transfer a frame */ + base->ktime = ns_to_ktime((1000000000 / params_rate(hw_params)) * + params_period_size(hw_params)); + + err = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); + + /* reset DMA buffer area */ + memset(substream->runtime->dma_area, 0, substream->runtime->dma_bytes); + + return err; +} + +/** ************************************************************************** + * \brief Free the allocated ALSA buffer + * + * \param[in] substream Pointer to substream object + * \retval 0 Success + * \retval -EINVAL Cannot deallocate buffer + *****************************************************************************/ +static int snd_adsp_pcm_hw_free(struct snd_pcm_substream *substream) +{ + return snd_pcm_lib_free_pages(substream); +} + +/** ************************************************************************** + * \brief Prepare playback/TDM playback or record/TDM record function + * before transferring data + * + * \param[in] substream Pointer to substream object + * \retval 0 Success + * \retval -EINVAL Error + *****************************************************************************/ +static int snd_adsp_pcm_prepare(struct snd_pcm_substream *substream) +{ + /* get ADSP soundcard and CPU DAI index */ + struct snd_adsp_card * + adsp_card = snd_adsp_get_drvdata_from_substream(substream); + int dai_idx = snd_adsp_get_dai_id_from_substream(substream); + int err = 0; + + if (dai_idx == RDR_DAI_IDX0 || dai_idx == RDR_DAI_IDX1 || + dai_idx == RDR_DAI_IDX2 || dai_idx == RDR_DAI_IDX3) { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + /* get playback prepared to execute */ + err = snd_adsp_playback_prepare( + adsp_card->playback[dai_idx], substream); + else + /* get record prepared to execute */ + err = snd_adsp_record_prepare( + adsp_card->record[dai_idx], substream); + } else { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + /* get TDM playback prepared to execute */ + err = snd_adsp_tdm_playback_prepare( + adsp_card->tdm_playback, substream); + else + /* get TDM record prepared to execute */ + err = snd_adsp_tdm_record_prepare( + adsp_card->tdm_record, substream); + } + + return err; +} + +/** ************************************************************************** + * \brief Trigger playback/TDM playback or record/TDM record stream + * to go to next phase + * + * \param[in] substream Pointer to substream object + * \retval 0 Success + * \retval -EINVAL Error + *****************************************************************************/ +static int snd_adsp_pcm_trigger(struct snd_pcm_substream *substream, int idx) +{ + struct snd_adsp_base_info * + base = snd_adsp_get_base_from_substream(substream); + + switch (idx) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + /* start high-resolution timer */ + hrtimer_start(&base->hrtimer, base->ktime, HRTIMER_MODE_REL); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + int buf_queue = 0; + + /* get current available buffer */ + spin_lock_irqsave(&base->lock, base->flag); + buf_queue = base->buf_queue; + spin_unlock_irqrestore(&base->lock, base->flag); + + /* send all available buffer to plugin to */ + /* get data */ + for (; buf_queue > 0; buf_queue--) { + if (xf_adsp_fill_this_buffer( + base->handle_id, + base->buffer[base->buf_idx], + base->buf_bytes) != 0) + return -EINVAL; + + spin_lock_irqsave(&base->lock, base->flag); + base->buf_queue--; + spin_unlock_irqrestore(&base->lock, base->flag); + + base->buf_idx++; + + if (base->buf_idx >= XF_BUF_POOL_SIZE) + base->buf_idx = 0; + } + } + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + break; + default: + return -EINVAL; + } + return 0; +} + +/** ************************************************************************** + * \brief Return HW data position + * + * \param[in] substream Pointer to substream object + * \retval position HW data position + *****************************************************************************/ +static snd_pcm_uframes_t +snd_adsp_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_adsp_base_info * + base = snd_adsp_get_base_from_substream(substream); + unsigned int hw_idx, hw_buffer_size; + snd_pcm_uframes_t pointer; + + /* convert hw index to correct as submitted bytes */ + spin_lock_irqsave(&base->lock, base->flag); + hw_idx = (base->hw_idx / base->buf_bytes) * base->period_bytes; + spin_unlock_irqrestore(&base->lock, base->flag); + + hw_buffer_size = base->pcm_indirect.hw_buffer_size; + + if (hw_idx >= hw_buffer_size) { + spin_lock_irqsave(&base->lock, base->flag); + + base->hw_idx -= (hw_buffer_size / base->period_bytes) * + base->buf_bytes; + + spin_unlock_irqrestore(&base->lock, base->flag); + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + pointer = snd_pcm_indirect_playback_pointer(substream, + &base->pcm_indirect, + hw_idx); + else + pointer = snd_pcm_indirect_capture_pointer(substream, + &base->pcm_indirect, + hw_idx); + + return pointer; +} + +/** ************************************************************************** + * \brief Call read/write process to transfer data + * + * \param[in] substream Pointer to substream object + * \retval 0 Success + * \retval -EINVAL Error + *****************************************************************************/ +static int snd_adsp_pcm_ack(struct snd_pcm_substream *substream) +{ + struct snd_adsp_base_info * + base = snd_adsp_get_base_from_substream(substream); + + if (base->runtime_err) + return -EINVAL; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_pcm_indirect_playback_transfer(substream, + &base->pcm_indirect, + snd_adsp_pcm_transfer); + else + snd_pcm_indirect_capture_transfer(substream, + &base->pcm_indirect, + snd_adsp_pcm_transfer); + + return 0; +} + +/** *************************************************************************** + * \brief Copy data from source buffer to destination buffer + * + * \params[in] dst Destination buffer pointer + * \params[out] src Source buffer pointer + * \params[in] dst_size Destination buffer size in byte + * \params[in] src_size Source buffer size in byte + * \retval None + *****************************************************************************/ +static inline void +snd_adsp_copy_data(void *dst, void *src, int dst_size, int src_size) +{ + unsigned char *data_dst = dst; + unsigned char *data_src = src; + int i; + + if (dst_size == src_size) { + /* src and dst bufs are same size, does not need to convert */ + memcpy(data_dst, data_src, dst_size); + + } else if (dst_size < src_size) { + for (i = 0; i < (dst_size - BYTES_PER_SAMPLE(S24_3LE)); + i += BYTES_PER_SAMPLE(S24_3LE)) { + *(u32 *)data_dst = *(u32 *)data_src; + + data_dst += BYTES_PER_SAMPLE(S24_3LE); + data_src += BYTES_PER_SAMPLE(S24_LE); + } + + /* copy a S24_3LE sample from S24_LE sample */ + data_dst[0] = data_src[0]; + data_dst[1] = data_src[1]; + data_dst[2] = data_src[2]; + + } else { + unsigned int tmp; + + for (i = 0; i < (dst_size - BYTES_PER_SAMPLE(S24_LE)); + i += BYTES_PER_SAMPLE(S24_LE)) { + tmp = *(u32 *)data_src; + *(u32 *)data_dst = tmp & 0x0FFFFFF; + + data_dst += BYTES_PER_SAMPLE(S24_LE); + data_src += BYTES_PER_SAMPLE(S24_3LE); + } + + /* copy a S24_LE sample from S24_3LE sample */ + data_dst[0] = data_src[0]; + data_dst[1] = data_src[1]; + data_dst[2] = data_src[2]; + data_dst[3] = 0; + } +} + +/** ************************************************************************** + * \brief Transfer data process between ALSA buffer and ADSP buffer + * + * \param[in] substream Pointer to substream object + * \param[in] rec Pointer to indirect PCM data + * \param[in] bytes Number of byte need to be transferred + * \retval None + *****************************************************************************/ +static void snd_adsp_pcm_transfer(struct snd_pcm_substream *substream, + struct snd_pcm_indirect *rec, + size_t bytes) +{ + struct snd_adsp_base_info * + base = snd_adsp_get_base_from_substream(substream); + int direct = substream->stream; + int trans_bytes = bytes; + int buf_bytes, period_bytes; + void *dma_buf, *data_buff; + + /* get the DMA buffer pointer */ + dma_buf = (void *)(substream->runtime->dma_area + rec->sw_data); + + /* get information from base */ + buf_bytes = base->buf_bytes; + period_bytes = base->period_bytes; + + /* make sure the available buffer and transfer size - TBD */ + while (trans_bytes > 0) { + spin_lock_irqsave(&base->lock, base->flag); + if (base->buf_queue > 0 && trans_bytes >= period_bytes) { + base->buf_queue--; + spin_unlock_irqrestore(&base->lock, base->flag); + + /* get the buffer pointer from stream */ + data_buff = base->buffer[base->buf_idx]; + + if (direct == SNDRV_PCM_STREAM_PLAYBACK) { + /* copy data from user *//* PRQA S 3200 2 */ + snd_adsp_copy_data(data_buff, dma_buf, + buf_bytes, period_bytes); + + /* send buffer to plugin */ + if (xf_adsp_empty_this_buffer(base->handle_id, + data_buff, + buf_bytes) < 0) + base->runtime_err = TRUE; + } else { + /* copy data to user *//* PRQA S 3200 2 */ + snd_adsp_copy_data(dma_buf, data_buff, + period_bytes, buf_bytes); + + /* send buffer to plugin */ + if (xf_adsp_fill_this_buffer(base->handle_id, + data_buff, + buf_bytes) < 0) + base->runtime_err = TRUE; + } + + base->buf_idx++; + if (base->buf_idx >= XF_BUF_POOL_SIZE) + base->buf_idx = 0; + } else { + spin_unlock_irqrestore(&base->lock, base->flag); + break; + } + + trans_bytes -= period_bytes; + } +} + +/** ************************************************************************** + * \brief Get info of Volume control + * + * \param[in] kcontrol Pointer to control instance + * \param[in] uinfo Pointer to info structure of volume control + * \retval 0 Success + *****************************************************************************/ +static int snd_adsp_control_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = -1; + uinfo->value.integer.max = 799; + return 0; +} + +/** ************************************************************************** + * \brief Get volume value + * + * \param[in] kcontrol Pointer to control instance + * \param[in] ucontrol Pointer to volume value + * \retval 0 Success + * \retval -EINVAL Error + *****************************************************************************/ +static int snd_adsp_control_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); + struct snd_adsp_control *ctr_if = &adsp_card->ctr_if; + int handle_state, handle_id; + int volume, cmd_idx, direction; + unsigned int index; + + /* get the index */ + index = kcontrol->id.index; + + /* set handle state as NULL state */ + handle_state = XF_HANDLE_NULL; + handle_id = -1; + + /* determine command index, direction, handle state, handle ID */ + if (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) { + cmd_idx = XA_RDR_CONFIG_PARAM_VOLUME_RATE; + direction = DIRECT_PLAYBACK; + + if (adsp_card->playback[index]) { + handle_state = adsp_card->playback[index]->rdr_state; + + handle_id = + adsp_card->playback[index]->renderer->handle_id; + } + } else if (kcontrol->id.name[0] == PREFIX_OF_CAPTURE_CTR_NAME) { + cmd_idx = XA_CAP_CONFIG_PARAM_VOLUME_RATE; + direction = DIRECT_CAPTURE; + + if (adsp_card->record[index]) { + handle_state = adsp_card->record[index]->cap_state; + + handle_id = + adsp_card->record[index]->capture->handle_id; + } + } else { + if (kcontrol->id.name[3] == TDM_PLAYBACK) { + cmd_idx = XA_TDM_RDR_CONFIG_PARAM_VOLUME_RATE; + direction = DIRECT_PLAYBACK; + + if (adsp_card->tdm_playback) { + handle_state = adsp_card->tdm_playback->state; + + handle_id = + adsp_card->tdm_playback->tdm_renderer->handle_id; + } + } else { + cmd_idx = XA_TDM_CAP_CONFIG_PARAM_VOLUME_RATE; + direction = DIRECT_CAPTURE; + + if (adsp_card->tdm_record) { + handle_state = adsp_card->tdm_record->state; + + handle_id = + adsp_card->tdm_record->tdm_capture->handle_id; + } + } + } + + /* get the volume's value */ + if (COMPONENT_IS_READY(handle_state) == TRUE) { + /* get the volume's value from the plugin */ + if (xf_adsp_get_param(handle_id, cmd_idx, &volume) != 0) + return -EINVAL; + + /* check the value after getting it and adjust it */ + ucontrol->value.integer.value[0] = (volume == 0xFFFFFFFF) ? + (-1) : (volume * VOLUME_SCALE) >> 20; + } else { + if (kcontrol->id.name[0] != PREFIX_OF_TDM_CTR_NAME) + ucontrol->value.integer.value[0] = + (ctr_if->vol_rate[direction][index] * + VOLUME_SCALE) >> 20; + else + ucontrol->value.integer.value[0] = + (ctr_if->tdm_vol_rate[direction] * + VOLUME_SCALE) >> 20; + } + + return 0; +} + +/** ************************************************************************** + * \brief Set volume value + * + * \param[in] kcontrol Pointer to control instance + * \param[in] ucontrol Pointer to volume value + * \retval 1 Volume change + * \retval 0 Volume does not change + * \retval -EINVAL Error + *****************************************************************************/ +/* PRQA S 3673 1*/ +static int +snd_adsp_control_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); + struct snd_adsp_control *ctr_if = &adsp_card->ctr_if; + int volume; + int ret; + int handle_state, handle_id, cmd_idx, volume_get; + int direction; + unsigned int index; + + /* get the index */ + index = kcontrol->id.index; + + /* set handle state as NULL state and handle ID */ + handle_state = XF_HANDLE_NULL; + handle_id = -1; + + /* get the value to set */ + if (ucontrol->value.integer.value[0] == -1) { + volume = 0xFFFFFFFF; + } else { + /* round up the value if needed */ + volume = (ucontrol->value.integer.value[0] * (1 << 20)) / + VOLUME_SCALE; + + if ((ucontrol->value.integer.value[0] * (1 << 20)) > + (VOLUME_SCALE * volume)) + volume += 1; + } + + /* determine command index, direction, handle state, handle ID */ + if (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) { + cmd_idx = XA_RDR_CONFIG_PARAM_VOLUME_RATE; + direction = DIRECT_PLAYBACK; + + if (adsp_card->playback[index]) { + handle_state = adsp_card->playback[index]->rdr_state; + + handle_id = + adsp_card->playback[index]->renderer->handle_id; + } + } else if (kcontrol->id.name[0] == PREFIX_OF_CAPTURE_CTR_NAME) { + cmd_idx = XA_CAP_CONFIG_PARAM_VOLUME_RATE; + direction = DIRECT_CAPTURE; + + if (adsp_card->record[index]) { + handle_state = adsp_card->record[index]->cap_state; + + handle_id = + adsp_card->record[index]->capture->handle_id; + } + } else { + if (kcontrol->id.name[3] == TDM_PLAYBACK) { + cmd_idx = XA_TDM_RDR_CONFIG_PARAM_VOLUME_RATE; + direction = DIRECT_PLAYBACK; + + if (adsp_card->tdm_playback) { + handle_state = adsp_card->tdm_playback->state; + + handle_id = + adsp_card->tdm_playback->tdm_renderer->handle_id; + } + } else { + cmd_idx = XA_TDM_CAP_CONFIG_PARAM_VOLUME_RATE; + direction = DIRECT_CAPTURE; + + if (adsp_card->tdm_record) { + handle_state = adsp_card->tdm_record->state; + + handle_id = + adsp_card->tdm_record->tdm_capture->handle_id; + } + } + } + + /* set volume to plugin */ + if (COMPONENT_IS_READY(handle_state) == TRUE) { + /* TDM does not support set volume in runtime state */ + if (kcontrol->id.name[0] == PREFIX_OF_TDM_CTR_NAME) + return -EINVAL; + + /* apply set volume value to ADSP from user setting */ + if (xf_adsp_set_param(handle_id, cmd_idx, volume) != 0) + return -EINVAL; + + /* get volume from ADSP after setting to confirm */ + if (xf_adsp_get_param(handle_id, cmd_idx, &volume_get) != 0) + return -EINVAL; + + /* check if the value has changed */ + ret = (volume_get == volume) ? 1 : 0; + } else { + if (kcontrol->id.name[0] != PREFIX_OF_TDM_CTR_NAME) + ctr_if->vol_rate[direction][index] = volume; + else + ctr_if->tdm_vol_rate[direction] = volume; + + ret = 1; + } + + return ret; +} + +/** ************************************************************************** + * \brief Get info of Sample Rate Converter control + * + * \param[in] kcontrol Pointer to control instance + * \param[in] uinfo Pointer to info structure of sample rate + * converter control + * \retval 0 Success + *****************************************************************************/ +static int snd_adsp_control_sample_rate_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = -1; + uinfo->value.integer.max = 48000; + return 0; +} + +/** ************************************************************************** + * \brief Get sample rate value + * + * \param[in] kcontrol Pointer to control instance + * \param[in] ucontrol Pointer to sample rate value + * \retval 0 Success + * \retval -EINVAL Error + *****************************************************************************/ +static int snd_adsp_control_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); + int *rate; + int handle_id, handle_state, cmd_idx, direction; + unsigned int index; + + rate = (int *)&ucontrol->value.integer.value[0]; /* PRQA S 310 */ + + /* get the index */ + index = kcontrol->id.index; + + /* set handle state as NULL state and handle ID */ + handle_state = XF_HANDLE_NULL; + handle_id = -1; + + /* determine command, direction, handle state, handle ID */ + if (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) { + cmd_idx = XA_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; + direction = DIRECT_PLAYBACK; + + if (adsp_card->playback[index]) { + handle_state = adsp_card->playback[index]->rdr_state; + + handle_id = + adsp_card->playback[index]->renderer->handle_id; + } + } else if (kcontrol->id.name[0] == PREFIX_OF_CAPTURE_CTR_NAME) { + cmd_idx = XA_CAP_CONFIG_PARAM_SAMPLE_RATE; + direction = DIRECT_CAPTURE; + + if (adsp_card->record[index]) { + handle_state = adsp_card->record[index]->cap_state; + + handle_id = + adsp_card->record[index]->capture->handle_id; + } + } else { + if (kcontrol->id.name[3] == TDM_PLAYBACK) { + cmd_idx = XA_TDM_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; + direction = DIRECT_PLAYBACK; + + if (adsp_card->tdm_playback) { + handle_state = adsp_card->tdm_playback->state; + + handle_id = + adsp_card->tdm_playback->tdm_renderer->handle_id; + } + } else { + cmd_idx = XA_TDM_CAP_CONFIG_PARAM_IN_SAMPLE_RATE; + direction = DIRECT_CAPTURE; + + if (adsp_card->tdm_record) { + handle_state = adsp_card->tdm_record->state; + + handle_id = + adsp_card->tdm_record->tdm_capture->handle_id; + } + } + } + + /* get parameter from plugin */ + if (COMPONENT_IS_READY(handle_state) == TRUE) { + if (xf_adsp_get_param(handle_id, cmd_idx, rate) != 0) + return -EINVAL; + } else { + if (kcontrol->id.name[0] != PREFIX_OF_TDM_CTR_NAME) + *rate = adsp_card->ctr_if.sample_rate[direction][index]; + else + *rate = adsp_card->ctr_if.tdm_sample_rate[direction]; + } + + /* success */ + return 0; +} + +/** ************************************************************************** + * \brief Set sample rate value + * + * \param[in] kcontrol Pointer to control instance + * \param[in] ucontrol Pointer to sample rate value + * \retval 1 Sample rate change + * \retval 0 Sample rate does not change + * \retval -EINVAL Error + *****************************************************************************/ +/* PRQA S 3673 1 */ +static int +snd_adsp_control_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); + unsigned int index; + int rate; + int handle_state, cmd_idx, direction; + int ret = 1; + + rate = (int)ucontrol->value.integer.value[0]; + + /* get the index */ + index = kcontrol->id.index; + + /* set handle state as NULL state */ + handle_state = XF_HANDLE_NULL; + + /* determine command, direction and handle state */ + if (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) { + cmd_idx = XA_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; + direction = DIRECT_PLAYBACK; + + if (adsp_card->playback[index]) + handle_state = adsp_card->playback[index]->rdr_state; + + } else if (kcontrol->id.name[0] == PREFIX_OF_CAPTURE_CTR_NAME) { + cmd_idx = XA_CAP_CONFIG_PARAM_SAMPLE_RATE; + direction = DIRECT_CAPTURE; + + if (adsp_card->record[index]) + handle_state = adsp_card->record[index]->cap_state; + + } else { + if (kcontrol->id.name[3] == TDM_PLAYBACK) { + cmd_idx = XA_TDM_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; + direction = DIRECT_PLAYBACK; + + if (adsp_card->tdm_playback) + handle_state = adsp_card->tdm_playback->state; + + } else { + cmd_idx = XA_TDM_CAP_CONFIG_PARAM_IN_SAMPLE_RATE; + direction = DIRECT_CAPTURE; + + if (adsp_card->tdm_record) + handle_state = adsp_card->tdm_record->state; + } + } + + /* get the value to set */ + if (COMPONENT_IS_READY(handle_state) == TRUE) + return -EINVAL; + + if (kcontrol->id.name[0] != PREFIX_OF_TDM_CTR_NAME) + adsp_card->ctr_if.sample_rate[direction][index] = rate; + else + adsp_card->ctr_if.tdm_sample_rate[direction] = rate; + + ret = 1; + + return ret; +} + +/** ************************************************************************** + * \brief Get info of Equalizer control + * + * \param[in] kcontrol Pointer to control instance + * \param[in] uinfo Pointer to info structure of Equalizer control + * \retval 0 Success + *****************************************************************************/ +static int snd_adsp_control_eqz_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = MAX_EQZ_PARAM_NUMBER; + uinfo->value.integer.min = -1; + uinfo->value.integer.max = 0x7fffffff; + return 0; +} + +/** ************************************************************************** + * \brief Get equalizer parameters value + * + * \param[in] kcontrol Pointer to control instance + * \param[in] ucontrol Pointer to equalizer parameters value + * \retval 0 Success + * \retval -EINVAL Error + *****************************************************************************/ +static int snd_adsp_control_eqz_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); + int handle_state, direction; + int i, j, filter_index; + unsigned int index; + struct xf_adsp_equalizer *equalizer; + struct xf_adsp_equalizer_params *eqz_params; + + /* get the index */ + index = kcontrol->id.index; + + /* determin direction of stream */ + direction = (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) ? + DIRECT_PLAYBACK : DIRECT_CAPTURE; + + /* set handle state as NULL state, handle ID, equalizer pointer */ + handle_state = XF_HANDLE_NULL; + equalizer = NULL; + + /* get component's state */ + if (direction == DIRECT_PLAYBACK) { + if (adsp_card->playback[index]) { + handle_state = adsp_card->playback[index]->eqz_state; + equalizer = adsp_card->playback[index]->equalizer; + } + } else { + if (adsp_card->record[index]) { + handle_state = adsp_card->record[index]->eqz_state; + equalizer = adsp_card->record[index]->equalizer; + } + } + + /* perform parameters' values getting */ + if (COMPONENT_IS_READY(handle_state) == TRUE) { + /* get equalizer's parameters */ + if (xf_adsp_equalizer_get_params(equalizer) != 0) + return -EINVAL; + + eqz_params = &equalizer->params; + } else { + eqz_params = &adsp_card->ctr_if.eqz_params[direction][index]; + } + + /* get equalizer type: PARAMETRIC or GRAPHIC */ + ucontrol->value.integer.value[0] = eqz_params->eqz_type; + + /* get parameters' value from Equalizer plugin */ + if (eqz_params->eqz_type == XA_REL_EQZ_TYPE_PARAMETRIC) { + for (i = 0, filter_index = 1; + filter_index <= XA_REL_EQZ_FILTER_NUM; + i++, filter_index++) { + /* get filter index */ + ucontrol->value.integer.value[(i * 6) + 1] = + filter_index; + + /* get frequency centre */ + ucontrol->value.integer.value[(i * 6) + 2] = + eqz_params->p_coef.fc[i]; + + /* get bandwidth */ + ucontrol->value.integer.value[(i * 6) + 3] = + eqz_params->p_coef.band_width[i]; + + /* get filter type */ + ucontrol->value.integer.value[(i * 6) + 4] = + eqz_params->p_coef.type[i]; + + /* get gain base */ + ucontrol->value.integer.value[(i * 6) + 5] = + eqz_params->p_coef.gain_base[i]; + + /* get gain */ + ucontrol->value.integer.value[(i * 6) + 6] = + eqz_params->p_coef.gain[i]; + } + } else { + for (i = 0, filter_index = 1; + filter_index <= XA_REL_EQZ_GRAPHIC_BAND_NUM; + i++, filter_index++) { + /* get band index */ + ucontrol->value.integer.value[(i * 2) + 1] = + filter_index; + + /* get graphic gain */ + ucontrol->value.integer.value[(i * 2) + 2] = + eqz_params->g_coef.gain_g[i]; + } + + j = (i * 2) + 1; + + /* make the rest of values silent */ + while (j < MAX_EQZ_PARAM_NUMBER) { + ucontrol->value.integer.value[j] = -1; + j++; + } + } + + return 0; +} + +/** ************************************************************************** + * \brief Set equalizer parameters value + * + * \param[in] kcontrol Pointer to control instance + * \param[in] ucontrol Pointer to equalizer parameters value + * \retval 1 Equalizer parameters change + * \retval 0 Equalizer parameters does not change + * \retval -EINVAL Error + *****************************************************************************/ +/* PRQA S 3673 1*/ +static int snd_adsp_control_eqz_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); + int handle_state, direction, filter_idx; + int i; + int index; + struct xf_adsp_equalizer_params *eqz_params = NULL; + + /* get the index */ + index = kcontrol->id.index; + + /* determine the direction */ + direction = (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) ? + DIRECT_PLAYBACK : DIRECT_CAPTURE; + + /* set handle state as NULL state */ + handle_state = XF_HANDLE_NULL; + + /* get the handle state */ + if (direction == DIRECT_PLAYBACK) { + if (adsp_card->playback[index]) + handle_state = adsp_card->playback[index]->eqz_state; + } else { + if (adsp_card->record[index]) + handle_state = adsp_card->record[index]->eqz_state; + } + + /* perform equalizer's parameters setting */ + if (COMPONENT_IS_READY(handle_state) == TRUE) + return -EINVAL; + + /* PRQA S 310 1*/ + eqz_params = &adsp_card->ctr_if.eqz_params[direction][index]; + + i = 0; + /* PRQA S 3440 1*/ + eqz_params->eqz_type = ucontrol->value.integer.value[i]; + i++; + filter_idx = 0; + + if (eqz_params->eqz_type == XA_REL_EQZ_TYPE_PARAMETRIC) { + while (i < MAX_EQZ_PARAM_NUMBER) { + /* get index filter */ + /* PRQA S 3440*/ + filter_idx = ucontrol->value.integer.value[i]; + i++; + + /* valid index filter is range */ + /* (1 to XA_REL_EQZ_FILTER_NUM) */ + if (filter_idx >= 1 && + filter_idx <= XA_REL_EQZ_FILTER_NUM) { + /* PRQA S 3440 5*/ + eqz_params->p_coef.fc[filter_idx - 1] = + ucontrol->value.integer.value[i]; + + i++; + eqz_params->p_coef.band_width[filter_idx - 1] = + ucontrol->value.integer.value[i]; + + i++; + eqz_params->p_coef.type[filter_idx - 1] = + ucontrol->value.integer.value[i]; + + i++; + eqz_params->p_coef.gain_base[filter_idx - 1] = + ucontrol->value.integer.value[i]; + + i++; + eqz_params->p_coef.gain[filter_idx - 1] = + ucontrol->value.integer.value[i]; + + i++; + } + /* index filter = -1 means that user */ + /* does not set this filter */ + else if (filter_idx == -1 || filter_idx == 0) { + i += 5; + } else { + return -EINVAL; + } + } + } else if (eqz_params->eqz_type == XA_REL_EQZ_TYPE_GRAPHIC) { + while (i < ((XA_REL_EQZ_GRAPHIC_BAND_NUM * 2) + 1)) { + /*get index filter */ + /* PRQA S 3440 */ + filter_idx = ucontrol->value.integer.value[i++]; + + if (filter_idx >= 1 && + filter_idx <= XA_REL_EQZ_GRAPHIC_BAND_NUM) { + eqz_params->g_coef.gain_g[filter_idx - 1] = + ucontrol->value.integer.value[i]; + i++; + + } else if (filter_idx == -1 || filter_idx == 0) { + i += 1; + } else { + return -EINVAL; + } + } + } else { + return -EINVAL; + } + + return 1; +} + +/** ************************************************************************** + * \brief Get info of Equalizer Switch control + * + * \param[in] kcontrol Pointer to control instance + * \param[in] uinfo Pointer to info structure of Equalizer + * Switch control + * \retval 0 Success + *****************************************************************************/ +static int snd_adsp_control_eqz_switch_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +/** ************************************************************************** + * \brief Get equalizer switch value + * + * \param[in] kcontrol Pointer to control instance + * \param[in] ucontrol Pointer to equalizer switch value + * \retval 0 Success + * \retval -EINVAL Error + *****************************************************************************/ +static int +snd_adsp_control_eqz_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); + int direction; + unsigned int index; + + /* get the index */ + index = kcontrol->id.index; + + /* determine the direction */ + direction = (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) ? + DIRECT_PLAYBACK : DIRECT_CAPTURE; + + /* get the Equalizer switch status */ + ucontrol->value.integer.value[0] = + adsp_card->ctr_if.eqz_switch[direction][index]; + + return 0; +} + +/** ************************************************************************** + * \brief Set equalizer switch value + * + * \param[in] kcontrol Pointer to control instance + * \param[in] ucontrol Pointer to equalizer switch value + * \retval 1 Equalizer switch change + * \retval 0 Equalizer switch does not change + * \retval -EINVAL Error + *****************************************************************************/ +/* PRQA S 3673 1 */ +static int +snd_adsp_control_eqz_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); + int eqz_switch; + int handle_state, direction; + unsigned int index; + int ret = 0; + + eqz_switch = ucontrol->value.integer.value[0]; + + /* get the index */ + index = kcontrol->id.index; + + /* determine the direction */ + direction = (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) ? + DIRECT_PLAYBACK : DIRECT_CAPTURE; + + /* set handle state as NULL state */ + handle_state = XF_HANDLE_NULL; + + /* determine handle state */ + if (direction == DIRECT_PLAYBACK) { + if (adsp_card->playback[index]) + handle_state = adsp_card->playback[index]->rdr_state; + } else { + if (adsp_card->record[index]) + handle_state = adsp_card->record[index]->cap_state; + } + + /* set the status of Equalizer */ + if (COMPONENT_IS_READY(handle_state) == TRUE) { + /* runtime setting is not supported */ + ret = -EINVAL; + } else { + adsp_card->ctr_if.eqz_switch[direction][index] = eqz_switch; + ret = 1; + } + + return ret; +} + +/** ************************************************************************** + * \brief Get info of Renderer output channel + * + * \param[in] kcontrol Pointer to control instance + * \param[in] uinfo Pointer to info structure of Renderer output channel + * \retval 0 Success + *****************************************************************************/ +static int +snd_adsp_control_rdr_out_channel_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = MONAURAL; + uinfo->value.integer.max = STEREO; + return 0; +} + +/** ************************************************************************** + * \brief Get Renderer output channel's value + * + * \param[in] kcontrol Pointer to control instance + * \param[in] ucontrol Pointer to Renderer output channel value + * \retval 0 Success + * \retval -EINVAL Error + *****************************************************************************/ +static int +snd_adsp_control_rdr_out_channel_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); + int rdr_out_ch; + unsigned int index; + int handle_state, handle_id; + + /* get the index */ + index = kcontrol->id.index; + + handle_state = XF_HANDLE_NULL; + handle_id = -1; + + /* determine handle state and handle ID */ + if (adsp_card->playback[index]) { + handle_state = adsp_card->playback[index]->rdr_state; + handle_id = adsp_card->playback[index]->renderer->handle_id; + } + + /* get Renderer output channel's value */ + if (COMPONENT_IS_READY(handle_state) == TRUE) { + /* get Renderer output channel's value from Renderer plugin */ + if (xf_adsp_get_param(handle_id, + XA_RDR_CONFIG_PARAM_OUT_CHANNELS, + &rdr_out_ch) != 0) { + return -EINVAL; + } + + ucontrol->value.integer.value[0] = rdr_out_ch; + } else { + ucontrol->value.integer.value[0] = + adsp_card->ctr_if.rdr_out_ch[index]; + } + + return 0; +} + +/** ************************************************************************** + * \brief Set Renderer output channel's value + * + * \param[in] kcontrol Pointer to control instance + * \param[in] ucontrol Pointer to Renderer output channel value + * \retval 1 Success + * \retval -EINVAL Error + *****************************************************************************/ +static int +snd_adsp_control_rdr_out_channel_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); + unsigned int index; + int handle_state; + int ret = 1; + + /* get the index */ + index = kcontrol->id.index; + + handle_state = XF_HANDLE_NULL; + + /* determine handle state and handle ID */ + if (adsp_card->playback[index]) + handle_state = adsp_card->playback[index]->rdr_state; + + /* get Renderer output channel's value */ + if (COMPONENT_IS_READY(handle_state) == TRUE) + /* not support runtime setting */ + ret = -EINVAL; + else + adsp_card->ctr_if.rdr_out_ch[index] = + ucontrol->value.integer.value[0]; + + return ret; +} + +/** control interface for playback's volume rate */ +/* PRQA S 3218 */ +static struct snd_kcontrol_new +snd_adsp_playback_volume_control[MAX_DAI_IDX - 1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX0, + .name = PLAYBACK_VOLUME_CTR_NAME, + .info = &snd_adsp_control_volume_info, + .get = &snd_adsp_control_volume_get, + .put = &snd_adsp_control_volume_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX1, + .name = PLAYBACK_VOLUME_CTR_NAME, + .info = &snd_adsp_control_volume_info, + .get = &snd_adsp_control_volume_get, + .put = &snd_adsp_control_volume_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX2, + .name = PLAYBACK_VOLUME_CTR_NAME, + .info = &snd_adsp_control_volume_info, + .get = &snd_adsp_control_volume_get, + .put = &snd_adsp_control_volume_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX3, + .name = PLAYBACK_VOLUME_CTR_NAME, + .info = &snd_adsp_control_volume_info, + .get = &snd_adsp_control_volume_get, + .put = &snd_adsp_control_volume_put + } +}; + +/** control interface for Capture's volume rate */ +/* PRQA S 3218 1*/ +static struct snd_kcontrol_new +snd_adsp_capture_volume_control[MAX_DAI_IDX - 1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX0, + .name = CAPTURE_VOLUME_CTR_NAME, + .info = &snd_adsp_control_volume_info, + .get = &snd_adsp_control_volume_get, + .put = &snd_adsp_control_volume_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX1, + .name = CAPTURE_VOLUME_CTR_NAME, + .info = &snd_adsp_control_volume_info, + .get = &snd_adsp_control_volume_get, + .put = &snd_adsp_control_volume_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX2, + .name = CAPTURE_VOLUME_CTR_NAME, + .info = &snd_adsp_control_volume_info, + .get = &snd_adsp_control_volume_get, + .put = &snd_adsp_control_volume_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX3, + .name = CAPTURE_VOLUME_CTR_NAME, + .info = &snd_adsp_control_volume_info, + .get = &snd_adsp_control_volume_get, + .put = &snd_adsp_control_volume_put + } +}; + +/** control interface for playback's output sample rate */ +/* PRQA S 3218 1*/ +static struct snd_kcontrol_new +snd_adsp_playback_sample_rate_out_control[MAX_DAI_IDX - 1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX0, + .name = PLAYBACK_OUT_RATE_CTR_NAME, + .info = &snd_adsp_control_sample_rate_info, + .get = &snd_adsp_control_sample_rate_get, + .put = &snd_adsp_control_sample_rate_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX1, + .name = PLAYBACK_OUT_RATE_CTR_NAME, + .info = &snd_adsp_control_sample_rate_info, + .get = &snd_adsp_control_sample_rate_get, + .put = &snd_adsp_control_sample_rate_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX2, + .name = PLAYBACK_OUT_RATE_CTR_NAME, + .info = &snd_adsp_control_sample_rate_info, + .get = &snd_adsp_control_sample_rate_get, + .put = &snd_adsp_control_sample_rate_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX3, + .name = PLAYBACK_OUT_RATE_CTR_NAME, + .info = &snd_adsp_control_sample_rate_info, + .get = &snd_adsp_control_sample_rate_get, + .put = &snd_adsp_control_sample_rate_put + } +}; + +/** control interface for Capture's input sample rate */ +/* PRQA S 3218 */ +static struct snd_kcontrol_new +snd_adsp_capture_sample_rate_in_control[MAX_DAI_IDX - 1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX0, + .name = CAPTURE_IN_RATE_CTR_NAME, + .info = &snd_adsp_control_sample_rate_info, + .get = &snd_adsp_control_sample_rate_get, + .put = &snd_adsp_control_sample_rate_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX1, + .name = CAPTURE_IN_RATE_CTR_NAME, + .info = &snd_adsp_control_sample_rate_info, + .get = &snd_adsp_control_sample_rate_get, + .put = &snd_adsp_control_sample_rate_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX2, + .name = CAPTURE_IN_RATE_CTR_NAME, + .info = &snd_adsp_control_sample_rate_info, + .get = &snd_adsp_control_sample_rate_get, + .put = &snd_adsp_control_sample_rate_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX3, + .name = CAPTURE_IN_RATE_CTR_NAME, + .info = &snd_adsp_control_sample_rate_info, + .get = &snd_adsp_control_sample_rate_get, + .put = &snd_adsp_control_sample_rate_put + } +}; + +/** control interface for Equalizer parameters in playback */ +/* PRQA S 3218 1*/ +static struct snd_kcontrol_new +snd_adsp_playback_equalizer_control[MAX_DAI_IDX - 1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX0, + .name = PLAYBACK_EQZ_CTR_NAME, + .info = &snd_adsp_control_eqz_info, + .get = &snd_adsp_control_eqz_get, + .put = &snd_adsp_control_eqz_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX1, + .name = PLAYBACK_EQZ_CTR_NAME, + .info = &snd_adsp_control_eqz_info, + .get = &snd_adsp_control_eqz_get, + .put = &snd_adsp_control_eqz_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX2, + .name = PLAYBACK_EQZ_CTR_NAME, + .info = &snd_adsp_control_eqz_info, + .get = &snd_adsp_control_eqz_get, + .put = &snd_adsp_control_eqz_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX3, + .name = PLAYBACK_EQZ_CTR_NAME, + .info = &snd_adsp_control_eqz_info, + .get = &snd_adsp_control_eqz_get, + .put = &snd_adsp_control_eqz_put + } +}; + +/** control interface for Equalizer parameters in record */ +/* PRQA S 3218 */ +static struct snd_kcontrol_new +snd_adsp_capture_equalizer_control[MAX_DAI_IDX - 1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX0, + .name = CAPTURE_EQZ_CTR_NAME, + .info = &snd_adsp_control_eqz_info, + .get = &snd_adsp_control_eqz_get, + .put = &snd_adsp_control_eqz_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX1, + .name = CAPTURE_EQZ_CTR_NAME, + .info = &snd_adsp_control_eqz_info, + .get = &snd_adsp_control_eqz_get, + .put = &snd_adsp_control_eqz_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX2, + .name = CAPTURE_EQZ_CTR_NAME, + .info = &snd_adsp_control_eqz_info, + .get = &snd_adsp_control_eqz_get, + .put = &snd_adsp_control_eqz_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX3, + .name = CAPTURE_EQZ_CTR_NAME, + .info = &snd_adsp_control_eqz_info, + .get = &snd_adsp_control_eqz_get, + .put = &snd_adsp_control_eqz_put + } +}; + +/** control interface for Equalizer usage in playback */ +/* PRQA S 3218 */ +static struct snd_kcontrol_new +snd_adsp_playback_equalizer_switch_control[MAX_DAI_IDX - 1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX0, + .name = PLAYBACK_EQZ_SWITCH_CTR_NAME, + .info = &snd_adsp_control_eqz_switch_info, + .get = &snd_adsp_control_eqz_switch_get, + .put = &snd_adsp_control_eqz_switch_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX1, + .name = PLAYBACK_EQZ_SWITCH_CTR_NAME, + .info = &snd_adsp_control_eqz_switch_info, + .get = &snd_adsp_control_eqz_switch_get, + .put = &snd_adsp_control_eqz_switch_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX2, + .name = PLAYBACK_EQZ_SWITCH_CTR_NAME, + .info = &snd_adsp_control_eqz_switch_info, + .get = &snd_adsp_control_eqz_switch_get, + .put = &snd_adsp_control_eqz_switch_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX3, + .name = PLAYBACK_EQZ_SWITCH_CTR_NAME, + .info = &snd_adsp_control_eqz_switch_info, + .get = &snd_adsp_control_eqz_switch_get, + .put = &snd_adsp_control_eqz_switch_put + } +}; + +/** control interface for Equalizer usage in record */ +/* PRQA S 3218 1*/ +static struct snd_kcontrol_new +snd_adsp_capture_equalizer_switch_control[MAX_DAI_IDX - 1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX0, + .name = CAPTURE_EQZ_SWITCH_CTR_NAME, + .info = &snd_adsp_control_eqz_switch_info, + .get = &snd_adsp_control_eqz_switch_get, + .put = &snd_adsp_control_eqz_switch_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX1, + .name = CAPTURE_EQZ_SWITCH_CTR_NAME, + .info = &snd_adsp_control_eqz_switch_info, + .get = &snd_adsp_control_eqz_switch_get, + .put = &snd_adsp_control_eqz_switch_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX2, + .name = CAPTURE_EQZ_SWITCH_CTR_NAME, + .info = &snd_adsp_control_eqz_switch_info, + .get = &snd_adsp_control_eqz_switch_get, + .put = &snd_adsp_control_eqz_switch_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX3, + .name = CAPTURE_EQZ_SWITCH_CTR_NAME, + .info = &snd_adsp_control_eqz_switch_info, + .get = &snd_adsp_control_eqz_switch_get, + .put = &snd_adsp_control_eqz_switch_put + } +}; + +/** control interface for playback's output channel */ +static struct snd_kcontrol_new +snd_adsp_playback_out_channel_control[MAX_DAI_IDX - 1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .index = RDR_DAI_IDX0, + .name = PLAYBACK_OUT_CHANNEL_CTR_NAME, + .info = &snd_adsp_control_rdr_out_channel_info, + .get = &snd_adsp_control_rdr_out_channel_get, + .put = &snd_adsp_control_rdr_out_channel_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .index = RDR_DAI_IDX1, + .name = PLAYBACK_OUT_CHANNEL_CTR_NAME, + .info = &snd_adsp_control_rdr_out_channel_info, + .get = &snd_adsp_control_rdr_out_channel_get, + .put = &snd_adsp_control_rdr_out_channel_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .index = RDR_DAI_IDX2, + .name = PLAYBACK_OUT_CHANNEL_CTR_NAME, + .info = &snd_adsp_control_rdr_out_channel_info, + .get = &snd_adsp_control_rdr_out_channel_get, + .put = &snd_adsp_control_rdr_out_channel_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .index = RDR_DAI_IDX3, + .name = PLAYBACK_OUT_CHANNEL_CTR_NAME, + .info = &snd_adsp_control_rdr_out_channel_info, + .get = &snd_adsp_control_rdr_out_channel_get, + .put = &snd_adsp_control_rdr_out_channel_put + } +}; + +/** control interface for TDM playback's volume rate */ +static struct snd_kcontrol_new snd_adsp_tdm_playback_volume_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .name = TDM_PLAYBACK_VOLUME_CTR_NAME, + .info = &snd_adsp_control_volume_info, + .get = &snd_adsp_control_volume_get, + .put = &snd_adsp_control_volume_put +}; + +/** control interface for TDM capture's volume rate */ +static struct snd_kcontrol_new snd_adsp_tdm_capture_volume_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .name = TDM_CAPTURE_VOLUME_CTR_NAME, + .info = &snd_adsp_control_volume_info, + .get = &snd_adsp_control_volume_get, + .put = &snd_adsp_control_volume_put +}; + +/** control interface for TDM playback's output sample rate */ +static struct snd_kcontrol_new snd_adsp_tdm_playback_sample_rate_out_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .name = TDM_PLAYBACK_OUT_RATE_CTR_NAME, + .info = &snd_adsp_control_sample_rate_info, + .get = &snd_adsp_control_sample_rate_get, + .put = &snd_adsp_control_sample_rate_put +}; + +/** control interface for TDM capture's input sample rate */ +static struct snd_kcontrol_new snd_adsp_tdm_capture_sample_rate_in_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ + .name = TDM_CAPTURE_IN_RATE_CTR_NAME, + .info = &snd_adsp_control_sample_rate_info, + .get = &snd_adsp_control_sample_rate_get, + .put = &snd_adsp_control_sample_rate_put +}; + +/** PCM callback function of the sound card */ +static struct snd_pcm_ops snd_adsp_pcm_ops = { + .open = &snd_adsp_pcm_open, /* PRQA S 1053 10 */ + .close = &snd_adsp_pcm_close, + .ioctl = &snd_pcm_lib_ioctl, + .hw_params = &snd_adsp_pcm_hw_params, + .hw_free = &snd_adsp_pcm_hw_free, + .prepare = &snd_adsp_pcm_prepare, + .trigger = &snd_adsp_pcm_trigger, + .pointer = &snd_adsp_pcm_pointer, + .ack = &snd_adsp_pcm_ack +}; + +/******************************************************************* + * Internal functions + * ****************************************************************/ + +/** ************************************************************************** + * \brief Process information get from control structure + * + * \param[in] eqz_params Equalizer parameters object + * \param[in] eqz_ctr_params Equalizer parameters stored in control object + * \param[in] flag Indicate playback or capture stream + *****************************************************************************/ +static void snd_adsp_get_eqz_params_from_control( + struct xf_adsp_equalizer_params *eqz_params, + struct xf_adsp_equalizer_params *eqz_ctr_params, bool flag) +{ + int filter_idx; + + if (flag) { + if (eqz_ctr_params->eqz_type >= 0) + eqz_params->eqz_type = eqz_ctr_params->eqz_type; + + for (filter_idx = 0; filter_idx < XA_REL_EQZ_FILTER_NUM; + filter_idx++) { + if (eqz_ctr_params->p_coef.fc[filter_idx] >= 0) + eqz_params->p_coef.fc[filter_idx] = + eqz_ctr_params->p_coef.fc[filter_idx]; + + if (eqz_ctr_params->p_coef.band_width[filter_idx] >= 0) + eqz_params->p_coef.band_width[filter_idx] = + eqz_ctr_params->p_coef.band_width[filter_idx]; + + if (eqz_ctr_params->p_coef.type[filter_idx] >= 0) + eqz_params->p_coef.type[filter_idx] = + eqz_ctr_params->p_coef.type[filter_idx]; + + if (eqz_ctr_params->p_coef.gain_base[filter_idx] >= 0) + eqz_params->p_coef.gain_base[filter_idx] = + eqz_ctr_params->p_coef.gain_base[filter_idx]; + + if (eqz_ctr_params->p_coef.gain[filter_idx] >= 0) + eqz_params->p_coef.gain[filter_idx] = + eqz_ctr_params->p_coef.gain[filter_idx]; + } + for (filter_idx = 0; filter_idx < XA_REL_EQZ_GRAPHIC_BAND_NUM; + filter_idx++) { + if (eqz_ctr_params->g_coef.gain_g[filter_idx] >= 0) + eqz_params->g_coef.gain_g[filter_idx] = + eqz_ctr_params->g_coef.gain_g[filter_idx]; + } + } else { + memcpy(eqz_ctr_params, eqz_params, sizeof(*eqz_params)); + } +} + +/******************************************************************* + * ALSA ADSP Platform driver interface + * ****************************************************************/ + +/** **************************************************************************** + * \brief Register control interface and preallocate ALSA buffer + * + * \param[in] runtime Pointer to runtime PCM data + * \retval 0 Success + * \retval -EINVAL Cannot register control interface + ******************************************************************************/ +static int snd_adsp_pcm_new(struct snd_soc_pcm_runtime *runtime) +{ + int i = 0, err = 0; + int id; + struct snd_card *card; + struct snd_adsp_card *adsp_card; + int alsa_buf_sz = 0; + + /* get sound card data */ + card = runtime->card->snd_card; + + /* get driver data */ + adsp_card = snd_soc_dai_get_drvdata(runtime->cpu_dai); + + /* get the ID of CPU DAI */ + id = runtime->cpu_dai->id; + + /* register control interfaces */ + if (id == RDR_DAI_IDX0 || id == RDR_DAI_IDX1 || + id == RDR_DAI_IDX2 || id == RDR_DAI_IDX3) { + struct snd_kcontrol *kctl[RDR_CONTROL_NUM]; + void *rdr_ctr[RDR_CONTROL_NUM] = { + &snd_adsp_playback_volume_control[id], /* PRQA S 1031 */ + &snd_adsp_capture_volume_control[id], + &snd_adsp_playback_sample_rate_out_control[id], + &snd_adsp_capture_sample_rate_in_control[id], + &snd_adsp_playback_equalizer_control[id], + &snd_adsp_capture_equalizer_control[id], + &snd_adsp_playback_equalizer_switch_control[id], + &snd_adsp_capture_equalizer_switch_control[id], + &snd_adsp_playback_out_channel_control[id] + }; + + /* add basic control instance */ + for (i = 0; i < RDR_CONTROL_NUM; i++) { + kctl[i] = snd_ctl_new1(rdr_ctr[i], adsp_card); + err = snd_ctl_add(card, kctl[i]); + if (err < 0) + return -EINVAL; + } + + /* assign ALSA buffer size */ + alsa_buf_sz = MAX_BUFFER_BYTES; + + /* enable MIX feature from the 2nd playback/record stream */ + if (adsp_card->ctr_if.mix_usage == MIX_UNUSED) + adsp_card->ctr_if.mix_usage = FIRST_RUN; + else if (adsp_card->ctr_if.mix_usage == FIRST_RUN) + adsp_card->ctr_if.mix_usage = SECOND_RUN; + + } else { + struct snd_kcontrol *kctl[TDM_CONTROL_NUM]; + void *tdm_ctr[TDM_CONTROL_NUM] = { + &snd_adsp_tdm_playback_volume_control, + &snd_adsp_tdm_playback_sample_rate_out_control, + &snd_adsp_tdm_capture_volume_control, + &snd_adsp_tdm_capture_sample_rate_in_control + }; + + /* add basic control instances */ + for (i = 0; i < TDM_CONTROL_NUM; i++) { + kctl[i] = snd_ctl_new1(tdm_ctr[i], adsp_card); + err = snd_ctl_add(card, kctl[i]); + if (err < 0) + return -EINVAL; + } + + /* assign ALSA buffer size */ + alsa_buf_sz = TDM_MAX_BUFFER_BYTES; + } + + return snd_pcm_lib_preallocate_pages_for_all(runtime->pcm, + SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), + alsa_buf_sz, alsa_buf_sz); +} + +/* **************************************************************************** + * ALSA ADSP DAI register + * ***************************************************************************/ + +/** callback function of platform driver */ +static struct snd_soc_platform_driver snd_adsp_platform = { + .pcm_new = &snd_adsp_pcm_new, /* PRQA S 1053 *//* PRQA S 0674 */ + .ops = &snd_adsp_pcm_ops, +}; + +/** component information of driver */ +static const struct snd_soc_component_driver snd_adsp_component = { + .name = "snd_adsp", /* PRQA S 1053 */ +}; + +/** DAI information of ADSP ALSA driver */ +static struct snd_soc_dai_driver snd_adsp_dai[MAX_DAI_IDX] = { + { + /* PRQA S 1053 */ + .id = RDR_DAI_IDX0, + .name = "adsp-dai.0", + .playback.stream_name = "Playback0", + .capture.stream_name = "Capture0", + }, + { + .id = RDR_DAI_IDX1, + .name = "adsp-dai.1", + .playback.stream_name = "Playback1", + .capture.stream_name = "Capture1", + }, + { + .id = RDR_DAI_IDX2, + .name = "adsp-dai.2", + .playback.stream_name = "Playback2", + .capture.stream_name = "Capture2", + }, + { + .id = RDR_DAI_IDX3, + .name = "adsp-dai.3", + .playback.stream_name = "Playback3", + .capture.stream_name = "Capture3", + }, + { + .id = TDM_DAI_IDX, + .name = "adsp-tdm-dai", + .playback.stream_name = "TDM Playback", + .capture.stream_name = "TDM Capture", + } +}; + +/** *************************************************************************** + * \brief Register platform driver and ADSP ALSA sound card + * + * \param[in] pdev Pointer to platform driver data + * \retval 0 Success + * \retval -ENOMEM Cannot allocate driver's data + * \retval -EINVAL Cannot register platform driver or sound card + ****************************************************************************/ +static int snd_adsp_probe(struct platform_device *pdev) +{ + struct snd_adsp_card *adsp_card; + int i; + + /* allocate a card data structure */ + adsp_card = kmalloc(sizeof(*adsp_card), GFP_KERNEL); + if (!adsp_card) + return -ENOMEM; + + /* init parameters */ + memset(adsp_card, 0, sizeof(*adsp_card)); /* PRQA S 3200 */ + + /* PRQA S 3200 1*/ + memset(&adsp_card->ctr_if, -1, sizeof(struct snd_adsp_control)); + + /* disable Equalizer for all streams */ + for (i = 0; i < (MAX_DAI_IDX - 1); i++) { + adsp_card->ctr_if.eqz_switch[DIRECT_CAPTURE][i] = 0; + adsp_card->ctr_if.eqz_switch[DIRECT_PLAYBACK][i] = 0; + } + + /* disable MIX function for all */ + adsp_card->ctr_if.mix_usage = MIX_UNUSED; + + /* save driver data */ + dev_set_drvdata(&pdev->dev, adsp_card); + + /* register platform device */ + if (snd_soc_register_platform(&pdev->dev, &snd_adsp_platform) < 0) { + snd_soc_unregister_platform(&pdev->dev); + return -EINVAL; + } + + /* fill format information of sound DAI driver for Rdr/Cap function */ + for (i = 0; i < (MAX_DAI_IDX - 1); i++) { + snd_adsp_dai[i].playback.rates = SND_ADSP_SAMPLE_RATES; + snd_adsp_dai[i].playback.formats = SND_ADSP_PCM_WIDTHS; + snd_adsp_dai[i].playback.channels_min = MIN_CHANNEL; + snd_adsp_dai[i].playback.channels_max = MAX_CHANNEL; + + snd_adsp_dai[i].capture.rates = SND_ADSP_SAMPLE_RATES; + snd_adsp_dai[i].capture.formats = SND_ADSP_PCM_WIDTHS; + snd_adsp_dai[i].capture.channels_min = MIN_CHANNEL; + snd_adsp_dai[i].capture.channels_max = MAX_CHANNEL; + } + + /* fill format information of sound DAI driver for TDM function */ + snd_adsp_dai[i].playback.rates = SND_ADSP_SAMPLE_RATES; + snd_adsp_dai[i].playback.formats = SND_ADSP_PCM_WIDTHS; + snd_adsp_dai[i].playback.channels_min = TDM_MIN_CHANNEL; + snd_adsp_dai[i].playback.channels_max = TDM_MAX_CHANNEL; + + snd_adsp_dai[i].capture.rates = SND_ADSP_SAMPLE_RATES; + snd_adsp_dai[i].capture.formats = SND_ADSP_PCM_WIDTHS; + snd_adsp_dai[i].capture.channels_min = TDM_MIN_CHANNEL; + snd_adsp_dai[i].capture.channels_max = TDM_MAX_CHANNEL; + + /* register CPU dai */ + if (snd_soc_register_component(&pdev->dev, &snd_adsp_component, + snd_adsp_dai, + ARRAY_SIZE(snd_adsp_dai)) < 0) { + snd_soc_unregister_platform(&pdev->dev); + return -EINVAL; + } + + dev_info(&pdev->dev, "probed\n"); + + /* success */ + return 0; +} + +/** ************************************************************************** + * \brief Unregister platform driver and ADSP ALSA sound card + * + * \param[in] pdev Pointer platform driver data + * \retval 0 Success + * \retval -EINVAL Invalid driver's data + *****************************************************************************/ +static int snd_adsp_remove(struct platform_device *pdev) +{ + /* get ADSP sound card data */ + struct snd_adsp_card *adsp_card = dev_get_drvdata(&pdev->dev); + + if (!adsp_card) + return -ENODEV; + + /* release the ADSP sound card */ + kfree(adsp_card); + + /* unregister platform driver */ + snd_soc_unregister_component(&pdev->dev); + snd_soc_unregister_platform(&pdev->dev); + + /* success */ + return 0; +} + +/** ADSP ALSA driver information */ +static const struct of_device_id snd_adsp_id[] = { + { .compatible = "renesas,rcar_adsp_sound_gen3", }, /* PRQA S 1053 */ +}; +MODULE_DEVICE_TABLE(of, snd_adsp_id); + +/** platform driver of ADSP ALSA sound card */ +static struct platform_driver snd_adsp_driver = { + .driver = { /* PRQA S 1053 */ + .name = "rcar_adsp_sound", + .of_match_table = snd_adsp_id, + }, + .probe = snd_adsp_probe, + .remove = snd_adsp_remove, +}; +module_platform_driver(snd_adsp_driver); /* PRQA S 0651 */ + +MODULE_AUTHOR("Renesas AudioDSP"); +MODULE_DESCRIPTION("Platform driver for ADSP"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:ADSP-PCM-AUDIO"); diff --git a/sound/soc/adsp/xf-adsp-base.c b/sound/soc/adsp/xf-adsp-base.c new file mode 100644 index 0000000..3ad9445 --- /dev/null +++ b/sound/soc/adsp/xf-adsp-base.c @@ -0,0 +1,2259 @@ +/** *************************************************************************** + *\file xf-adsp-base.c + *\brief Source file for ADSP Base Control layer + *\addtogroup ADSP Driver + ****************************************************************************** + *\date Oct. 21, 2017 + *\author Renesas Electronics Corporation + ****************************************************************************** + *\par Copyright + * + * Copyright(c) 2016 Renesas Electoronics Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include +#include +#include + +#include "xf-adsp-base.h" + +#define XF_AUX_POOL_SIZE (16) /**< size of auxiliary pool*/ +#define XF_AUX_POOL_MSG_LENGTH (256) /**< size of auxiliary buffer */ + +#define XF_PROXY_ALIGN (64) /**< proxy alignment */ + +/** \def XF_ALIGNED(size) + * Get properly aligned buffer length + */ +#define XF_ALIGNED(size)\ +((((size) + XF_PROXY_ALIGN) - 1) & ~(XF_PROXY_ALIGN - 1)) /* PRQA S 3453 */ + +#ifndef offset_of +/** \def offset_of(type, member) + * Return the offset of member in type structuer in byte + */ +#define offset_of(type, member) \ + ((int)(long int)&(((const type *)(0))->member)) /* PRQA S 3453 */ +#endif + +/************************************************* + * Variable and and function declaration + * **********************************************/ + +/** ADSP base control data */ +static struct xf_adsp_base *base; + +/* function declaration */ +static int xf_adsp_base_register_handle(void *private_data, + struct xf_callback_func *cb, + int comp_id); +static inline struct xf_handle *xf_adsp_base_get_handle(int handle_id); +static int xf_adsp_base_free_handle(int handle_id); +static void xf_adsp_base_init_handle(void); +static int xf_adsp_base_get_valid_handle(void); +static int xf_send_and_receive(struct xf_message *msg); +static int xf_response_thread(void *data); +static void xf_buffer_put(struct xf_buffer *buffer); +static u32 xf_buffer_length(struct xf_buffer *b); +static struct xf_buffer *xf_buffer_get(struct xf_pool *pool); +static void *xf_buffer_data(struct xf_buffer *b); +static int xf_adsp_unregister(int comp_id); +static int xf_adsp_register(char *name, int *comp_id); + +/************************************************* + * Helper function to process pool data + * **********************************************/ + +/** *********************************************************** + * \brief get buffer from given pool + * + * \param[in] pool Data pool address + * \retval b Pointer to buffer address in pool + **************************************************************/ +static struct xf_buffer *xf_buffer_get(struct xf_pool *pool) +{ + struct xf_buffer *b; + + b = pool->free; + if (b) { + pool->free = b->link.next; + b->link.pool = pool; + } + return b; +} + +/*********************************************************** + *\brief return buffer back to pool + * + *\param[in] buffer Pointer to the buffer data + ************************************************************/ +static void xf_buffer_put(struct xf_buffer *buffer) +{ + struct xf_pool *pool = buffer->link.pool; + + buffer->link.next = pool->free; + pool->free = buffer; +} + +/*********************************************************** + *\brief get the address of the given buffer data + * + *\param[in] b Pointer to the buffer data + *\retval address Address of buffer data + ************************************************************/ +static void *xf_buffer_data(struct xf_buffer *b) +{ + return b->address; +} + +/************************************************************ + *\brief get the length of the given buffer data + * + *\param[in] b Pointer to the buffer data + *\retval length Size of buffer data + ************************************************************/ +static u32 xf_buffer_length(struct xf_buffer *b) /* PRQA S 3673 */ +{ + return b->link.pool->length; +} + +/************************************************************ + *\brief set data to the given command message + * + *\param[out] m Pointer to the command message + *\param[in] id Message ID + *\param[in] opcode Message opcode + *\param[in] length Message length + *\param[in] buf Pointer to the buffer data + *\param[in] next Pointer to the next message + *\retval m Pointer to the command message + ************************************************************/ +static inline struct xf_message * +xf_create_msg(struct xf_message *m, u32 id, u32 opcode, u32 length, void *buf, + struct xf_message *next) +{ + if (m) { + m->id = id; + m->opcode = opcode; + m->length = length; + m->buffer = buf; + m->next = next; + } + + return m; +} + +/***************************************************************** + *\brief synchronous send and wait for response message from proxy + * + *\param[in] msg Pointer to the command message + *\retval 0 Success + *\retval -EINVAL Failed + ****************************************************************/ +static int xf_send_and_receive(struct xf_message *msg) +{ + int err; + int opcode = msg->opcode; + + /* reset the base flag */ + spin_lock(&base->lock); + base->base_flag = FALSE; + spin_unlock(&base->lock); + + err = base->cmd.send(base->client, (void *)msg); + if (err != 0) + return err; + + /* sleep and wait for the response wake up event */ + if (wait_event_interruptible(base->base_wait, + base->base_flag || base->err_flag)) { + return -EINVAL; + } + + if (base->err_flag != 0) { + spin_lock(&base->lock); + base->err_flag = FALSE; + spin_unlock(&base->lock); + return -EINVAL; + } + + /* save the response message */ + /* PRQA S 3200 */ + memcpy(msg, &base->base_msg, sizeof(struct xf_message)); + + /* check if the reponsed message is right */ + if (msg->opcode != opcode) + return -EINVAL; + + return 0; +} + +/************************************************************* + *\brief send a message to proxy + * + *\param[in] msg Pointer to the command message + *\retval 0 Success + *\retval -EINVAL Failed + **************************************************************/ +static inline int xf_send(struct xf_message *msg) +{ + return base->cmd.send(base->client, (void *)msg); +} + +/** *********************************************************** + *\brief receive message from proxy + * + *\param[in] msg Pointer to store the response message + *\retval 0 Success + *\retval -EINVAL Failed + **************************************************************/ +static inline int xf_receive(struct xf_message *msg) +{ + /* do not wait here */ + return base->cmd.recv(base->client, (void *)msg); +} + +/** *********************************************************** + *\brief thread for receive response data + **************************************************************/ +static int xf_response_thread(void *data) +{ + struct xf_message msg; + struct xf_handle *handle; + int id; + + /* set polling to wait the response message */ + spin_lock(&base->lock); + base->wait_flag = FALSE; + spin_unlock(&base->lock); + + while (!kthread_should_stop()) { + if (base->cmd.poll(base->client, &base->wait_flag) != 0) + continue; + + if (xf_receive(&msg) != 0) + continue; + + /* get the handle id */ + id = XF_AP_CLIENT(msg.id); + + /* check the destination of the response message */ + if (id == 0) { + /* message is from base control */ + /* PRQA S 3200 1*/ + memcpy(&base->base_msg, &msg, + sizeof(struct xf_message)); + + spin_lock(&base->lock); + base->base_flag = TRUE; + spin_unlock(&base->lock); + + wake_up(&base->base_wait); + continue; + } + + /* get handle data */ + handle = xf_adsp_base_get_handle(id); + + if (handle == 0) + continue; + + switch (msg.opcode) { + case XF_EMPTY_THIS_BUFFER: /* PRQA S 0594 */ + handle->cb->empty_buf_done(handle->private_data, + msg.opcode, + msg.length, + msg.buffer); + break; + case XF_FILL_THIS_BUFFER: /* PRQA S 0594 */ + handle->cb->fill_buf_done(handle->private_data, + msg.opcode, + msg.length, + msg.buffer); + break; + case XF_SET_PARAM: /* PRQA S 0594 4 */ + case XF_GET_PARAM: + case XF_ROUTE: + case XF_UNROUTE: + /* message is from base control */ + memcpy(&base->base_msg, &msg, + sizeof(struct xf_message)); /* PRQA S 3200 */ + + spin_lock(&base->lock); + base->base_flag = TRUE; + spin_unlock(&base->lock); + + wake_up(&base->base_wait); + break; + default: + /* error has occurred */ + handle->cb->event_handler(handle->private_data); + + xf_adsp_base_free_handle(id); /* PRQA S 3200 */ + + spin_lock(&base->lock); + base->err_flag = TRUE; + spin_unlock(&base->lock); + + wake_up(&base->base_wait); + break; + } + } + + pr_info("ADSP base thread was exited\n"); + + do_exit(0); + return 0; +} + +/************************************************************* + * \brief register component to ADSP + * + * \param[in] name Name string of component + * \param[out] comp_id Store the registered component ID + * \retval 0 Success + * \retval -EINVAL Failed + **************************************************************/ +static int xf_adsp_register(char *name, int *comp_id) /* PRQA S 3673 */ +{ + struct xf_message msg; + struct xf_buffer *b = xf_buffer_get(base->aux_pool); + int err = 0; + + msg.id = __XF_MSG_ID(__XF_AP_PROXY(0), __XF_DSP_PROXY(0)); + msg.opcode = XF_REGISTER; + msg.length = strlen(name) + 1; + msg.buffer = xf_buffer_data(b); + + /* copy identify name of ADSP component */ + if (msg.length <= xf_buffer_length(b)) + strncpy(msg.buffer, name, msg.length); /* PRQA S 3200 */ + else + strncpy(msg.buffer, name, xf_buffer_length(b));/* PRQA S 3200 */ + + err = xf_send_and_receive(&msg); + if (err != 0) + goto exit; /* PRQA S 2001 */ + + /* save the registered component ID */ + *comp_id = XF_MSG_SRC(msg.id); + +exit: + /* return msg to pool */ + xf_buffer_put(b); + + return err; +} + +/** *********************************************************** + * \brief unregister component from ADSP + * \param[in] comp_id Registered component ID + * \retval 0 Success + * \retval -EINVAL Failed + **************************************************************/ +static int xf_adsp_unregister(int comp_id) +{ + struct xf_message msg; + + xf_create_msg(&msg, __XF_MSG_ID(__XF_AP_PROXY(0), comp_id), + XF_UNREGISTER, 0, NULL, NULL); /* PRQA S 3200 */ + + return xf_send_and_receive(&msg); +} + +/*************************************************************** + * APIs for ADSP component helper + * ************************************************************/ +/** *********************************************************** + * \brief allocate memory pool from shared memory + * \param[in] pool_size Number of buffer need to allocate + * \param[in] buf_length Size of each buffer in bytes + * \retval pool Pointer to allocated pool + * \retval -EINVAL Invalid base data + * \retval -ENOMEM Out of memory resource + **************************************************************/ +struct xf_pool *xf_adsp_allocate_mem_pool(int pool_size, int buf_length) +{ + void *data; + u32 number; + struct xf_buffer *b; + struct xf_message msg; + struct xf_pool *pool; + int err = 0; + + /* check the sane ADSP base data */ + if (!base) + return ERR_PTR(-EINVAL); /* PRQA S 0306 */ + + xf_create_msg(&msg, __XF_MSG_ID(__XF_AP_PROXY(0), __XF_DSP_PROXY(0)), + XF_ALLOC, + buf_length * pool_size, NULL, NULL); /* PRQA S 3200 */ + + err = xf_send_and_receive(&msg); + if (err != 0) + return ERR_PTR(-ENOMEM); /* PRQA S 0306 */ + + /* PRQA S 0306 1 */ + pool = kmalloc(offset_of(struct xf_pool, buffer) + + (pool_size * sizeof(struct xf_buffer)), GFP_KERNEL); + + if (!pool) + return ERR_PTR(-ENOMEM); /* PRQA S 0306 */ + + pool->length = buf_length; + pool->number = pool_size; + pool->p = msg.buffer; + + number = pool_size; + for (pool->free = b = &pool->buffer[0], data = pool->p; + number > 0; number--, b++) { /* PRQA S 2462,3418,0489 */ + /* set address of the buffer */ + b->address = data; + + /* fill buffer into free list */ + if (number == 1) + b->link.next = NULL; + else + b->link.next = b + 1; /* PRQA S 0489 */ + + /* advance data pointer in contigous buffer */ + data += buf_length; /* PRQA S 0550 */ + } + + return pool; +} + +/** *********************************************************** + *\brief return memory to shared memory + *\param[in] pool Data pool address + *\retval 0 Success + *\retval -EINVAL Invalid base or pool data + **************************************************************/ +int xf_adsp_free_mem_pool(struct xf_pool *pool) +{ + struct xf_message msg; + + /* check the sane ADSP base pool data*/ + if (!base || !pool) + return -EINVAL; + + xf_create_msg(&msg, __XF_MSG_ID(__XF_AP_PROXY(0), __XF_DSP_PROXY(0)), + XF_FREE, pool->number * pool->length, + pool->p, NULL); /* PRQA S 3200 */ + + xf_send_and_receive(&msg); /* PRQA S 3200 */ + + kfree(pool); + + return 0; +} + +/** *********************************************************** + *\brief get buffer from given pool + * + *\param[in] pool Data pool address + *\param[in] index Buffer index + *\retval b Pointer to buffer address in pool + *\retval -EINVAL Invalid pool or index + **************************************************************/ +char *xf_adsp_get_data_from_pool(struct xf_pool *pool, int index) +{ + struct xf_buffer *buf[XF_BUF_POOL_SIZE] = {0}; + char *data; + int i; + + /* check the sane pool data*/ + if (!pool) + return ERR_PTR(-EINVAL); /* PRQA S 306 */ + + /* check the index is valid */ + if (index > (pool->number - 1)) + return ERR_PTR(-EINVAL); /* PRQA S 306 */ + + /* get buffer from pool */ + for (i = 0; i <= index; i++) + buf[i] = xf_buffer_get(pool); + + /* get data from buffer */ + data = xf_buffer_data(buf[index]); + + /* return buffer to pool */ + for (i = index; i >= 0; i--) + xf_buffer_put(buf[i]); + + return data; +} + +/** *********************************************************** + *\brief send empty this buffer command to ADSP framework + * + *\param[in] handle_id ID of the registered handle + *\param[in] buffer Pointer to data buffer + *\param[in] length Size of buffer in bytes + *\retval 0 Success + *\retval -EINVAL Failed + **************************************************************/ +int xf_adsp_empty_this_buffer(int handle_id, char *buffer, int length) +{ + struct xf_message msg; + struct xf_handle *handle; + + /* check the sane ADSP base data */ + if (!base) + return -EINVAL; + + handle = xf_adsp_base_get_handle(handle_id); + if (!handle) + return -EINVAL; + + /* submit message to port 0 of component */ + /* PRQA S 3200 2 */ + xf_create_msg(&msg, + __XF_MSG_ID(__XF_AP_CLIENT(0, handle_id), + __XF_PORT_SPEC2(handle->comp_id, 0)), + XF_EMPTY_THIS_BUFFER, length, buffer, NULL); + + xf_send(&msg); /* PRQA S 3200 */ + + return 0; +} + +/** *********************************************************** + *\brief send fill this buffer command to ADSP framework + * + *\param[in] handle_id ID of the registered handle + *\param[in] buffer Pointer to data buffer + *\param[in] length Size of buffer in bytes + *\retval 0 Success + *\retval -EINVAL Failed + **************************************************************/ +int xf_adsp_fill_this_buffer(int handle_id, char *buffer, int length) +{ + struct xf_message msg; + struct xf_handle *handle; + + /* check the sane ADSP base data */ + if (!base) + return -EINVAL; + + handle = xf_adsp_base_get_handle(handle_id); + if (!handle) + return -EINVAL; + + /* submit message to port 1 of component */ + /* PRQA S 3200 2 */ + xf_create_msg(&msg, + __XF_MSG_ID(__XF_AP_CLIENT(0, handle_id), + __XF_PORT_SPEC2(handle->comp_id, 1)), + XF_FILL_THIS_BUFFER, length, buffer, NULL); + + xf_send(&msg); /* PRQA S 3200 */ + + return 0; +} + +/** *********************************************************** + *\brief route data between two registered ADSP plugins + * + *\param[in] src_handle_id Handle ID of source plugin + *\param[in] dst_handle_id Handle ID of sink plugin + *\param[in] buf_cnt Number of buffer in tunnel + *\param[in] buf_size Size of each buffer in tunnel + *\retval 0 Success + *\retval -EINVAL Failed + **************************************************************/ +int +xf_adsp_route(int src_handle_id, int dst_handle_id, int buf_cnt, int buf_size) +{ + struct xf_route_port_msg *route_msg; + struct xf_message msg; + struct xf_buffer *b; + struct xf_handle *dst_handle, *src_handle; + int err = 0; + + /* check the sane ADSP base data */ + if (!base) + return -EINVAL; + + /* get handle data */ + dst_handle = xf_adsp_base_get_handle(dst_handle_id); + src_handle = xf_adsp_base_get_handle(src_handle_id); + + if (!dst_handle || !src_handle) + return -EINVAL; + + b = xf_buffer_get(base->aux_pool); + route_msg = xf_buffer_data(b); + + /* route information */ + route_msg->dst = __XF_PORT_SPEC2(dst_handle->comp_id, 0); + route_msg->alloc_align = 4; + route_msg->alloc_number = buf_cnt; + route_msg->alloc_size = buf_size; + + /* PRQA S 3200 2*/ + xf_create_msg(&msg, + __XF_MSG_ID(__XF_AP_CLIENT(0, src_handle_id), + __XF_PORT_SPEC2(src_handle->comp_id, 1)), + XF_ROUTE, sizeof(*route_msg), route_msg, NULL); + + err = xf_send_and_receive(&msg); + + xf_buffer_put(b); + + return err; +} + +/** *********************************************************** + *\brief set a single parameter + * + *\param[in] handle_id ID of registered handle + *\param[in] index Sub-command index of parameter + *\param[in] value the setting value + *\retval 0 Success + *\retval -EINVAL Failed + **************************************************************/ +int xf_adsp_set_param(int handle_id, int index, int value) +{ + struct xf_message msg; + struct xf_buffer *b; + struct xf_set_param_msg *msg_params; + struct xf_handle *handle; + int err = 0; + + /* check the sane ADSP base data */ + if (!base) + return -EINVAL; + + handle = xf_adsp_base_get_handle(handle_id); + if (!handle) + return -EINVAL; + + b = xf_buffer_get(base->aux_pool); + msg_params = xf_buffer_data(b); + + msg_params->item[0].id = index; + msg_params->item[0].value = value; + + /* PRQA S 3200 2 */ + xf_create_msg(&msg, + __XF_MSG_ID(__XF_AP_CLIENT(0, handle_id), + __XF_PORT_SPEC2(handle->comp_id, 0)), + XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(1), msg_params, NULL); + + err = xf_send_and_receive(&msg); + + /* return msg to pool */ + xf_buffer_put(b); + + return err; +} + +/** *********************************************************** + *\brief get a single parameter + * + *\param[in] handle_id ID of registered handle + *\param[in] index Sub-command index of parameter + *\param[out] value Store the getting value + *\retval 0 Success + *\retval -EINVAL Failed + **************************************************************/ +int xf_adsp_get_param(int handle_id, int index, int *value) +{ + struct xf_message msg; + struct xf_buffer *b; + union xf_get_param_msg *msg_params; + struct xf_handle *handle; + int err = 0; + + /* check the sane ADSP base and value data */ + if (!base || !value) + return -EINVAL; + + handle = xf_adsp_base_get_handle(handle_id); + if (!handle) + return -EINVAL; + + b = xf_buffer_get(base->aux_pool); + msg_params = xf_buffer_data(b); + + msg_params->c.id[0] = index; + + /* PRQA S 3200 2 */ + xf_create_msg(&msg, + __XF_MSG_ID(__XF_AP_CLIENT(0, handle_id), + __XF_PORT_SPEC2(handle->comp_id, 0)), + XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(1), msg_params, NULL); + + err = xf_send_and_receive(&msg); + if (err != 0) + goto exit; /* PRQA S 2001 */ + + /* save the received parameters */ + *value = msg_params->r.value[0]; + +exit: + /* return msg to pool */ + xf_buffer_put(b); + + return err; +} + +/*************************************************** + * APIs for ADSP base control + * ************************************************/ + +/** *********************************************************** + *\brief initialize ADSP base's instance + * + *\retval 0 Success + *\retval -EINVAL ADSP base's instance has been initialized + *\retval -ENOMEM Cannot allocate memory for ADSP base + *\retval -EBUSY Cannot register client to proxy + **************************************************************/ +int xf_adsp_base_create(struct xf_adsp_base_cmd *cmd) +{ + int err = 0; + + if (base != 0) + return -EINVAL; + + if (!cmd || !cmd->recv || !cmd->send || !cmd->poll || + !cmd->client_register || !cmd->client_unregister) + return -EINVAL; + + base = kmalloc(sizeof(*base), GFP_KERNEL); + if (!base) + return -ENOMEM; + + memset(base, 0, sizeof(struct xf_adsp_base)); /* PRQA S 3200 */ + + /* store the proxy command */ + memcpy(&base->cmd, cmd, sizeof(struct xf_adsp_base_cmd)); + + /* create client to connect from proxy driver */ + err = base->cmd.client_register(&base->client); + if (err != 0) + goto err3; /* PRQA S 2001 */ + + /* initialize waiting queue */ + init_waitqueue_head(&base->base_wait); + + /* initialize handle */ + xf_adsp_base_init_handle(); + + /* create thread to get the responsed message from proxy */ + base->rsp_thread = kthread_run(&xf_response_thread, + (void *)base, "adsp base"); + + if (base->rsp_thread != 0) { + pr_info("ADSP base thread has been started.\n"); + } else { + pr_info("Failed in create base thread\n"); + err = -ENOMEM; + goto err2; /* PRQA S 2001 */ + } + + /* allocate auxiliary pool for component usage */ + base->aux_pool = xf_adsp_allocate_mem_pool( + XF_AUX_POOL_SIZE, + XF_ALIGNED(XF_AUX_POOL_MSG_LENGTH)); + + if (IS_ERR(base->aux_pool)) { /* PRQA S 306 */ + err = -ENOMEM; + goto err1; /* PRQA S 2001 */ + } + + pr_info("ADSP base was created\n"); + return 0; + +err1: + /* cancel the waitting queue */ + spin_lock(&base->lock); + base->wait_flag = TRUE; + spin_unlock(&base->lock); + + /* stop thread inadvance */ + kthread_stop(base->rsp_thread); + +err2: + base->cmd.client_unregister(base->client); + +err3: + kfree(base); + base = NULL; + + return err; +} +EXPORT_SYMBOL(xf_adsp_base_create); /* PRQA S 0651 */ + +/** *********************************************************** + *\brief deinitialize ADSP base's instance + * + *\retval 0 Success + *\retval -EINVAL Invalid ADSP base's instance + **************************************************************/ +int xf_adsp_base_destroy(void) +{ + /* check the sane ADSP base data */ + if (!base) + return -EINVAL; + + /* free auxiliary pool to shared memory */ + xf_adsp_free_mem_pool(base->aux_pool); /* PRQA S 3200 */ + + /* cancel wait the response message, go to stop process */ + spin_lock(&base->lock); + base->wait_flag = TRUE; + spin_unlock(&base->lock); + + /* stop response thread */ + kthread_stop(base->rsp_thread); + + /* unregister client */ + base->cmd.client_unregister(base->client); + + kfree(base); + base = NULL; + + pr_info("ADSP base was destroyed\n"); + return 0; +} +EXPORT_SYMBOL(xf_adsp_base_destroy); /* PRQA S 0651 */ + +/** *********************************************************** + * \brief initialize handle instance + **************************************************************/ +static inline void xf_adsp_base_init_handle(void) +{ + int i; + + for (i = 0; i < MAX_HANDLE; i++) + base->handle[i] = NULL; +} + +/** *********************************************************** + *\brief get the next available handle ID for register + * + *\retval -1 Unavailable handle ID + *\retval 0 to 255 Available handle ID + **************************************************************/ +static inline int xf_adsp_base_get_valid_handle(void) +{ + int id = -1; + int i; + + for (i = 0; i < MAX_HANDLE; i++) { + /* get the id of the first available handler */ + if (!base->handle[i]) { + id = i; + break; + } + } + + return id; +} + +/** *********************************************************** + *\brief register a handle instance for component usage + * + *\param[in] private_data Private data of this component + *\param[in] cb Callback function + *\param[in] comp_id ID of register component + *\retval id ID of registered handle + *\retval -EINVAL Cannot get the handle instance + *\retval -ENOMEM Cannot allocate handle memory + **************************************************************/ +static int xf_adsp_base_register_handle(void *private_data, + struct xf_callback_func *cb, + int comp_id) +{ + struct xf_handle *handle; + int id; + + /* get the next handle id */ + id = xf_adsp_base_get_valid_handle(); + + /* check available handle in base */ + if (id < 0) + return -EINVAL; + + /* allocate handle data */ + handle = kmalloc(sizeof(*handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; + + /* save handle data */ + handle->private_data = private_data; + handle->cb = cb; + handle->comp_id = comp_id; + + /* save the hanle data */ + base->handle[id] = handle; + + /* return the id numbering in base handle */ + return (id + 1); +} + +/** *********************************************************** + *\brief get handle instance from handle ID + * + *\param[in] handle_id ID of registered handle + *\retval handle Pointer to handle instance + **************************************************************/ +static inline struct xf_handle *xf_adsp_base_get_handle(int handle_id) +{ + return base->handle[handle_id - 1]; +} + +/** *********************************************************** + *\brief free the registered handle instance + * + *\param[in] handle_id ID of registered handle + *\retval 0 Success + *\retval -EINVAL Invalid handle ID + **************************************************************/ +static int xf_adsp_base_free_handle(int handle_id) +{ + if (handle_id < 1 || handle_id > MAX_HANDLE) + return -EINVAL; + + kfree(base->handle[handle_id - 1]); + base->handle[handle_id - 1] = NULL; + + return 0; +} + +/*********************************************************************** + * APIs for Renderer component + * ********************************************************************/ + +/** *********************************************************** + *\brief set ADSP Renderer parameters + * + *\param[in] renderer Pointer to Renderer component + *\retval 0 Success + *\retval -EINVAL Failed + **************************************************************/ +int xf_adsp_renderer_set_params(struct xf_adsp_renderer *renderer) +{ + struct xf_message msg; + struct xf_set_param_msg *msg_params; + struct xf_adsp_renderer_params *params; + struct xf_buffer *b; + int i; + struct xf_handle *handle; + int err = 0; + + /* check the sane ADSP base data */ + if (!base || !renderer) + return -EINVAL; + + params = &renderer->params; + + /* get Renderer's handle data */ + handle = xf_adsp_base_get_handle(renderer->handle_id); + if (!handle) + return -EINVAL; + + b = xf_buffer_get(base->aux_pool); + + msg_params = xf_buffer_data(b); + + i = 0; + msg_params->item[i].id = XA_RDR_CONFIG_PARAM_SAMPLE_RATE; + msg_params->item[i++].value = params->in_rate; + + msg_params->item[i].id = XA_RDR_CONFIG_PARAM_CHANNELS; + msg_params->item[i++].value = params->channel; + + msg_params->item[i].id = XA_RDR_CONFIG_PARAM_PCM_WIDTH; + msg_params->item[i++].value = params->pcm_width; + + msg_params->item[i].id = XA_RDR_CONFIG_PARAM_FRAME_SIZE; + msg_params->item[i++].value = params->frame_size; + + msg_params->item[i].id = XA_RDR_CONFIG_PARAM_OUTPUT1; + msg_params->item[i++].value = params->dev1; + + msg_params->item[i].id = XA_RDR_CONFIG_PARAM_OUTPUT2; + msg_params->item[i++].value = params->dev2; + + msg_params->item[i].id = XA_RDR_CONFIG_PARAM_DMACHANNEL1; + msg_params->item[i++].value = params->dma1; + + msg_params->item[i].id = XA_RDR_CONFIG_PARAM_DMACHANNEL2; + msg_params->item[i++].value = params->dma2; + + msg_params->item[i].id = XA_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; + msg_params->item[i++].value = params->out_rate; + + msg_params->item[i].id = XA_RDR_CONFIG_PARAM_VOLUME_RATE; + msg_params->item[i++].value = params->vol_rate; + + msg_params->item[i].id = XA_RDR_CONFIG_PARAM_OUT_CHANNELS; + msg_params->item[i++].value = params->out_channel; + + msg_params->item[i].id = XA_RDR_CONFIG_PARAM_MIX_CONTROL; + msg_params->item[i++].value = params->mix_ctrl; + + msg_params->item[i].id = XA_RDR_CONFIG_PARAM_STATE; + msg_params->item[i++].value = params->state; + + /* PRQA S 3200 2*/ + xf_create_msg(&msg, + __XF_MSG_ID(__XF_AP_CLIENT(0, renderer->handle_id), + __XF_PORT_SPEC2(handle->comp_id, 0)), + XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(i), msg_params, NULL); + + err = xf_send_and_receive(&msg); + + /* return msg to pool */ + xf_buffer_put(b); + + return err; +} + +/** *********************************************************** + *\brief get ADSP Renderer parameters + * + *\param[in] renderer Pointer to Renderer component + *\retval 0 Success + *\retval -EINVAL Failed + **************************************************************/ +/* PRQA S 1505 */ +int xf_adsp_renderer_get_params(struct xf_adsp_renderer *renderer) +{ + struct xf_adsp_renderer_params *rdr_params; + struct xf_message msg; + struct xf_buffer *b; + union xf_get_param_msg *msg_params; + int i; + struct xf_handle *handle; + int err = 0; + + /* check the sane ADSP base data */ + if (!base || !renderer) + return -EINVAL; + + rdr_params = &renderer->params; + + /* get Renderer's handle data */ + handle = xf_adsp_base_get_handle(renderer->handle_id); + if (!handle) + return -EINVAL; + + b = xf_buffer_get(base->aux_pool); + msg_params = xf_buffer_data(b); + + i = 0; + /* PRQA S 3440 13 1*/ + msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_SAMPLE_RATE; + msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_CHANNELS; + msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_PCM_WIDTH; + msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_FRAME_SIZE; + msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_OUTPUT1; + msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_OUTPUT2; + msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_DMACHANNEL1; + msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_DMACHANNEL2; + msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; + msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_VOLUME_RATE; + msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_OUT_CHANNELS; + msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_MIX_CONTROL; + msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_STATE; + + /* PRQA S 3200 2*/ + xf_create_msg(&msg, + __XF_MSG_ID(__XF_AP_CLIENT(0, renderer->handle_id), + __XF_PORT_SPEC2(handle->comp_id, 0)), + XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(i), msg_params, NULL); + + err = xf_send_and_receive(&msg); + if (err != 0) + goto exit; /* PRQA S 2001 */ + + /* save the received parameters */ + i = 0; + rdr_params->in_rate = msg_params->r.value[i++]; /* PRQA S 3440 13 */ + rdr_params->channel = msg_params->r.value[i++]; + rdr_params->pcm_width = msg_params->r.value[i++]; + rdr_params->frame_size = msg_params->r.value[i++]; + rdr_params->dev1 = msg_params->r.value[i++]; + rdr_params->dev2 = msg_params->r.value[i++]; + rdr_params->dma1 = msg_params->r.value[i++]; + rdr_params->dma2 = msg_params->r.value[i++]; + rdr_params->out_rate = msg_params->r.value[i++]; + rdr_params->vol_rate = msg_params->r.value[i++]; + rdr_params->out_channel = msg_params->r.value[i++]; + rdr_params->mix_ctrl = msg_params->r.value[i++]; + rdr_params->state = msg_params->r.value[i++]; + +exit: + /* return msg to pool */ + xf_buffer_put(b); + + return err; +} + +/** ************************************************************************** + *\brief create Renderer component + * + *\param[in,out] renderer Pointer to the registered component + *\param[in] cb Callback function + *\param[in] private_data Private data + *\retval 0 Success + *\retval -EINVAL Invalid base instance or register fail + *\retval -ENOMEM Cannot allocate Renderer instance + *****************************************************************************/ +int xf_adsp_renderer_create(struct xf_adsp_renderer **renderer, + struct xf_callback_func *cb, void *private_data) +{ + struct xf_adsp_renderer *rdr; + int err; + int comp_id; + + /* check the sane ADSP base data */ + if (!base) + return -EINVAL; + + rdr = kmalloc(sizeof(*rdr), GFP_KERNEL); + if (!rdr) + return -ENOMEM; + + memset(rdr, 0, sizeof(struct xf_adsp_renderer)); /* PRQA S 3200 */ + + /* register renderer component */ + err = xf_adsp_register("renderer", &comp_id); + if (err != 0) + goto err2; /* PRQA S 2001 */ + + /* register Renderer to ADSP base control */ + rdr->handle_id = xf_adsp_base_register_handle(private_data, + cb, comp_id); + + if (rdr->handle_id <= 0) { + err = -EINVAL; + goto err1; /* PRQA S 2001 */ + } + + /* get the default parameter from Renderer plugin */ + err = xf_adsp_renderer_get_params(rdr); + if (err != 0) + goto err1; /* PRQA S 2001 */ + + /* save renderer compoent data */ + *renderer = rdr; + + return 0; + +err1: + xf_adsp_unregister(comp_id); /* PRQA S 3200 */ + +err2: + kfree(rdr); + + return err; +} + +/** *********************************************************** + *\brief deinitialize ADSP Renderer component + * + *\param[in] renderer Pointer to Renderer component + *\retval 0 Success + *\retval -EINVAL Invalid base or Renderer data + **************************************************************/ +/* PRQA S 3673 */ +int xf_adsp_renderer_destroy(struct xf_adsp_renderer *renderer) +{ + struct xf_handle *handle; + int handle_id; + + /* check the sane ADSP base data */ + if (!base || !renderer) + return -EINVAL; + + handle_id = renderer->handle_id; + + handle = xf_adsp_base_get_handle(handle_id); + if (!handle) + goto exit; /* PRQA S 2001 */ + + /* unregister component */ + xf_adsp_unregister(handle->comp_id); /* PRQA S 3200 */ + + /* free handle data from base control */ + xf_adsp_base_free_handle(handle_id); /* PRQA S 3200 */ + +exit: + kfree(renderer); + + return 0; +} + +/*********************************************************************** + * APIs for Capture component + * ********************************************************************/ + +/** *********************************************************** + *\brief set ADSP Capture parameters + * + *\param[in] capture Pointer to Capture component + *\retval 0 Success + *\retval -EINVAL Failed + **************************************************************/ +int xf_adsp_capture_set_params(struct xf_adsp_capture *capture) +{ + struct xf_message msg; + struct xf_set_param_msg *msg_params; + struct xf_adsp_capture_params *params; + struct xf_buffer *b; + int i; + struct xf_handle *handle; + int err = 0; + + /* check the sane ADSP base data */ + if (!base || !capture) + return -EINVAL; + + params = &capture->params; + + /* get Capture's handle data */ + handle = xf_adsp_base_get_handle(capture->handle_id); + if (!handle) + return -EINVAL; + + b = xf_buffer_get(base->aux_pool); + + msg_params = xf_buffer_data(b); + + i = 0; + msg_params->item[i].id = XA_CAP_CONFIG_PARAM_SAMPLE_RATE; + msg_params->item[i++].value = params->in_rate; + + msg_params->item[i].id = XA_CAP_CONFIG_PARAM_CHANNELS; + msg_params->item[i++].value = params->channel; + + msg_params->item[i].id = XA_CAP_CONFIG_PARAM_PCM_WIDTH; + msg_params->item[i++].value = params->pcm_width; + + msg_params->item[i].id = XA_CAP_CONFIG_PARAM_FRAME_SIZE; + msg_params->item[i++].value = params->frame_size; + + msg_params->item[i].id = XA_CAP_CONFIG_PARAM_INPUT1; + msg_params->item[i++].value = params->dev1; + + msg_params->item[i].id = XA_CAP_CONFIG_PARAM_INPUT2; + msg_params->item[i++].value = params->dev2; + + msg_params->item[i].id = XA_CAP_CONFIG_PARAM_DMACHANNEL1; + msg_params->item[i++].value = params->dma1; + + msg_params->item[i].id = XA_CAP_CONFIG_PARAM_DMACHANNEL2; + msg_params->item[i++].value = params->dma2; + + msg_params->item[i].id = XA_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE; + msg_params->item[i++].value = params->out_rate; + + msg_params->item[i].id = XA_CAP_CONFIG_PARAM_VOLUME_RATE; + msg_params->item[i++].value = params->vol_rate; + + msg_params->item[i].id = XA_CAP_CONFIG_PARAM_STATE; + msg_params->item[i++].value = params->state; + + /* PRQA S 3200 2 */ + xf_create_msg(&msg, + __XF_MSG_ID(__XF_AP_CLIENT(0, capture->handle_id), + __XF_PORT_SPEC2(handle->comp_id, 0)), + XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(i), msg_params, NULL); + + err = xf_send_and_receive(&msg); + + /* return msg to pool */ + xf_buffer_put(b); + + return err; +} + +/** *********************************************************** + *\brief get ADSP Capture parameters + * + *\param[in] capture Pointer to Capture component + *\retval 0 Success + *\retval -EINVAL Failed + **************************************************************/ +/* PRQA S 1505 */ +int xf_adsp_capture_get_params(struct xf_adsp_capture *capture) +{ + struct xf_adsp_capture_params *cap_params; + struct xf_message msg; + struct xf_buffer *b; + union xf_get_param_msg *msg_params; + int i; + struct xf_handle *handle; + int err = 0; + + /* check the sane ADSP base data */ + if (!base || !capture) + return -EINVAL; + + cap_params = &capture->params; + + /* get Capture's handle data */ + handle = xf_adsp_base_get_handle(capture->handle_id); + if (!handle) + return -EINVAL; + + b = xf_buffer_get(base->aux_pool); + msg_params = xf_buffer_data(b); + + i = 0; + /* PRQA S 3440 11 1*/ + msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_SAMPLE_RATE; + msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_CHANNELS; + msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_PCM_WIDTH; + msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_FRAME_SIZE; + msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_INPUT1; + msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_INPUT2; + msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_DMACHANNEL1; + msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_DMACHANNEL2; + msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE; + msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_VOLUME_RATE; + msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_STATE; + + /* PRQA S 3200 2 */ + xf_create_msg(&msg, + __XF_MSG_ID(__XF_AP_CLIENT(0, capture->handle_id), + __XF_PORT_SPEC2(handle->comp_id, 0)), + XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(i), msg_params, NULL); + + err = xf_send_and_receive(&msg); + if (err != 0) + goto exit; /* PRQA S 2001 */ + + /* save the received parameters */ + i = 0; + cap_params->in_rate = msg_params->r.value[i++]; /* PRQA S 3440 11 */ + cap_params->channel = msg_params->r.value[i++]; + cap_params->pcm_width = msg_params->r.value[i++]; + cap_params->frame_size = msg_params->r.value[i++]; + cap_params->dev1 = msg_params->r.value[i++]; + cap_params->dev2 = msg_params->r.value[i++]; + cap_params->dma1 = msg_params->r.value[i++]; + cap_params->dma2 = msg_params->r.value[i++]; + cap_params->out_rate = msg_params->r.value[i++]; + cap_params->vol_rate = msg_params->r.value[i++]; + cap_params->state = msg_params->r.value[i++]; + +exit: + /* return msg to pool */ + xf_buffer_put(b); + + return err; +} + +/** ************************************************************************** + *\brief create Capture component + * + *\param[in,out] capture Pointer to the registered component + *\param[in] cb Callback function + *\param[in] private_data Private data + *\retval 0 Success + *\retval -EINVAL Invalid base instance or register fail + *\retval -ENOMEM Cannot allocate Capture instance + *****************************************************************************/ +int xf_adsp_capture_create(struct xf_adsp_capture **capture, + struct xf_callback_func *cb, void *private_data) +{ + struct xf_adsp_capture *cap; + int err; + int comp_id; + + /* check the sane ADSP base data */ + if (!base) + return -EINVAL; + + cap = kmalloc(sizeof(*cap), GFP_KERNEL); + if (!cap) + return -ENOMEM; + + memset(cap, 0, sizeof(struct xf_adsp_capture)); /* PRQA S 3200 */ + + /* register capture component */ + err = xf_adsp_register("capture", &comp_id); + if (err != 0) + goto err2; /* PRQA S 2001 */ + + /* register capture to ADSP base control */ + cap->handle_id = xf_adsp_base_register_handle(private_data, + cb, comp_id); + + if (cap->handle_id <= 0) { + err = -EINVAL; + goto err1; /* PRQA S 2001 */ + } + + /* get the default parameter from capture plugin */ + err = xf_adsp_capture_get_params(cap); + if (err != 0) + goto err1; /* PRQA S 2001 */ + + /* save capture compoent data */ + *capture = cap; + + return 0; + +err1: + xf_adsp_unregister(comp_id); /* PRQA S 3200 */ + +err2: + kfree(cap); + + return err; +} + +/** *********************************************************** + *\brief deinitialize ADSP Capture component + * + *\param[in] capture Pointer to Capture component + *\retval 0 Success + *\retval -EINVAL Invalid base or Capture data + **************************************************************/ +int xf_adsp_capture_destroy(struct xf_adsp_capture *capture) /* PRQA S 3673 */ +{ + struct xf_handle *handle; + int handle_id; + + /* check the sane ADSP base data */ + if (!base || !capture) + return -EINVAL; + + handle_id = capture->handle_id; + + handle = xf_adsp_base_get_handle(handle_id); + if (!handle) + goto exit; /* PRQA S 2001 */ + + /* unregister component */ + xf_adsp_unregister(handle->comp_id); /* PRQA S 3200 */ + + /* free handle data from base control */ + xf_adsp_base_free_handle(handle_id); /* PRQA S 3200 */ + +exit: + kfree(capture); + + return 0; +} + +/*********************************************************************** + * APIs for Equalizer component + * ********************************************************************/ + +/** *********************************************************** + *\brief set ADSP Equalizer parameters + * + *\param[in] equalizer Pointer to Equalizer component + *\retval 0 Success + *\retval -EINVAL Failed + **************************************************************/ +int xf_adsp_equalizer_set_params(struct xf_adsp_equalizer *equalizer) +{ + struct xf_message msg; + struct xf_set_param_msg *msg_params; + struct xf_adsp_equalizer_params *params; + struct xf_buffer *b; + int i, n; + struct xf_handle *handle; + int err = 0; + + /* check the sane ADSP base data */ + if (!base || !equalizer) + return -EINVAL; + + params = &equalizer->params; + + /* get Equalizer's handle data */ + handle = xf_adsp_base_get_handle(equalizer->handle_id); + if (!handle) + return -EINVAL; + + b = xf_buffer_get(base->aux_pool); + + msg_params = xf_buffer_data(b); + + i = 0; + msg_params->item[i].id = XA_EQZ_CONFIG_PARAM_COEF_FS; + msg_params->item[i++].value = params->rate; + + msg_params->item[i].id = XA_EQZ_CONFIG_PARAM_CH; + msg_params->item[i++].value = params->channel; + + msg_params->item[i].id = XA_EQZ_CONFIG_PARAM_PCM_WIDTH; + msg_params->item[i++].value = params->pcm_width; + + msg_params->item[i].id = XA_EQZ_CONFIG_PARAM_EQZ_TYPE; + msg_params->item[i++].value = params->eqz_type; + + if (params->eqz_type == XA_REL_EQZ_TYPE_PARAMETRIC) { + struct xf_equalizer_parametric_coef *coef = ¶ms->p_coef; + + for (n = 0; n < XA_REL_EQZ_FILTER_NUM; n++) { + msg_params->item[i].id = + XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_TYPE + n; + msg_params->item[i++].value = coef->type[n]; + + msg_params->item[i].id = + XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_FC + n; + msg_params->item[i++].value = coef->fc[n]; + + msg_params->item[i].id = + XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BW + n; + msg_params->item[i++].value = coef->band_width[n]; + + msg_params->item[i].id = + XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_GA + n; + msg_params->item[i++].value = coef->gain[n]; + + msg_params->item[i].id = + XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BA + n; + msg_params->item[i++].value = coef->gain_base[n]; + } + } else { + struct xf_equalizer_graphic_coef *coef = ¶ms->g_coef; + + for (n = 0; n < XA_REL_EQZ_GRAPHIC_BAND_NUM; n++) { + msg_params->item[i].id = + XA_EQZ_CONFIG_PARAM_BAND_0_GCOEF_GA + n; + msg_params->item[i++].value = coef->gain_g[n]; + } + } + + /* PRQA S 3200 2 */ + xf_create_msg(&msg, + __XF_MSG_ID(__XF_AP_CLIENT(0, equalizer->handle_id), + __XF_PORT_SPEC2(handle->comp_id, 0)), + XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(i), msg_params, NULL); + + err = xf_send_and_receive(&msg); + + /* return msg to pool */ + xf_buffer_put(b); + + return err; +} + +/** *********************************************************** + *\brief get ADSP Equalizer parameters + * + *\param[in] equalizer Pointer to Equalizer component + *\retval 0 Success + *\retval -EINVAL Failed + **************************************************************/ +/* PRQA S 1505 1*/ +int xf_adsp_equalizer_get_params(struct xf_adsp_equalizer *equalizer) +{ + struct xf_adsp_equalizer_params *eqz_params; + struct xf_message msg; + struct xf_buffer *b; + union xf_get_param_msg *msg_params; + int i, n; + struct xf_handle *handle; + int err = 0; + + /* check the sane ADSP base data */ + if (!base || !equalizer) + return -EINVAL; + + eqz_params = &equalizer->params; + + /* get Equalizer's handle data */ + handle = xf_adsp_base_get_handle(equalizer->handle_id); + if (!handle) + return -EINVAL; + + b = xf_buffer_get(base->aux_pool); + msg_params = xf_buffer_data(b); + + i = 0; + msg_params->c.id[i++] = XA_EQZ_CONFIG_PARAM_COEF_FS; /* PRQA S 3440 4 */ + msg_params->c.id[i++] = XA_EQZ_CONFIG_PARAM_CH; + msg_params->c.id[i++] = XA_EQZ_CONFIG_PARAM_PCM_WIDTH; + msg_params->c.id[i++] = XA_EQZ_CONFIG_PARAM_EQZ_TYPE; + + for (n = 0; n < XA_REL_EQZ_FILTER_NUM; n++) { + /* PRQA S 3440 5 */ + msg_params->c.id[i++] = + XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_TYPE + n; + + msg_params->c.id[i++] = + XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_FC + n; + + msg_params->c.id[i++] = + XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BW + n; + + msg_params->c.id[i++] = + XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_GA + n; + + msg_params->c.id[i++] = + XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BA + n; + } + + for (n = 0; n < XA_REL_EQZ_GRAPHIC_BAND_NUM; n++) + /* PRQA S 3440 1 */ + msg_params->c.id[i++] = XA_EQZ_CONFIG_PARAM_BAND_0_GCOEF_GA + n; + + /* PRQA S 3200 2 */ + xf_create_msg(&msg, + __XF_MSG_ID(__XF_AP_CLIENT(0, equalizer->handle_id), + __XF_PORT_SPEC2(handle->comp_id, 0)), + XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(i), msg_params, NULL); + + err = xf_send_and_receive(&msg); + if (err != 0) + goto exit; /* PRQA S 2001 */ + + /* save the received parameters */ + i = 0; + eqz_params->rate = msg_params->r.value[i++]; /* PRQA S 3440 4 */ + eqz_params->channel = msg_params->r.value[i++]; + eqz_params->pcm_width = msg_params->r.value[i++]; + eqz_params->eqz_type = msg_params->r.value[i++]; + + for (n = 0; n < XA_REL_EQZ_FILTER_NUM; n++) { + /* PRQA S 3440 5 */ + eqz_params->p_coef.type[n] = msg_params->r.value[i++]; + eqz_params->p_coef.fc[n] = msg_params->r.value[i++]; + eqz_params->p_coef.band_width[n] = msg_params->r.value[i++]; + eqz_params->p_coef.gain[n] = msg_params->r.value[i++]; + eqz_params->p_coef.gain_base[n] = msg_params->r.value[i++]; + } + + for (n = 0; n < XA_REL_EQZ_GRAPHIC_BAND_NUM; n++) { + /* PRQA S 3440 1 */ + eqz_params->g_coef.gain_g[n] = msg_params->r.value[i++]; + } + +exit: + /* return msg to pool */ + xf_buffer_put(b); + + return err; +} + +/** ************************************************************************** + *\brief create Equalizer component + * + *\param[in,out] equalizer Pointer to the registered component + *\param[in] cb Callback function + *\param[in] private_data Private data + *\retval 0 Success + *\retval -EINVAL Invalid base instance or register fail + *\retval -ENOMEM Cannot allocate Equalier instance + *****************************************************************************/ +int xf_adsp_equalizer_create(struct xf_adsp_equalizer **equalizer, + struct xf_callback_func *cb, void *private_data) +{ + struct xf_adsp_equalizer *eqz; + int err; + int comp_id; + + /* check the sane ADSP base data */ + if (!base) + return -EINVAL; + + eqz = kmalloc(sizeof(*eqz), GFP_KERNEL); + if (!eqz) + return -ENOMEM; + + memset(eqz, 0, sizeof(struct xf_adsp_equalizer)); /* PRQA S 3200 */ + + /* register equalizer component */ + err = xf_adsp_register("equalizer", &comp_id); + if (err != 0) + goto err2; /* PRQA S 2001 */ + + /* register equalizer to ADSP base control */ + eqz->handle_id = xf_adsp_base_register_handle(private_data, + cb, comp_id); + + if (eqz->handle_id <= 0) { + err = -EINVAL; + goto err1; /* PRQA S 2001 */ + } + + /* get the default parameter from equalizer plugin */ + err = xf_adsp_equalizer_get_params(eqz); + if (err != 0) + goto err1; /* PRQA S 2001 */ + + /* save equalizer compoent data */ + *equalizer = eqz; + + return 0; + +err1: + xf_adsp_unregister(comp_id); /* PRQA S 3200 */ + +err2: + kfree(eqz); + + return err; +} + +/** *********************************************************** + *\brief deinitialize ADSP Equalizer component + * + *\param[in] equalizer Pointer to Equalizer component + *\retval 0 Success + *\retval -EINVAL Invalid base or Equalizer data + **************************************************************/ +/* PRQA S 3673 */ +int xf_adsp_equalizer_destroy(struct xf_adsp_equalizer *equalizer) +{ + struct xf_handle *handle; + int handle_id; + + /* check the sane ADSP base and Equalizer data */ + if (!base || !equalizer) + return -EINVAL; + + handle_id = equalizer->handle_id; + + handle = xf_adsp_base_get_handle(handle_id); + if (!handle) + goto exit; /* PRQA S 2001 */ + + /* unregister component */ + xf_adsp_unregister(handle->comp_id); /* PRQA S 3200 */ + + /* free handle data from base control */ + xf_adsp_base_free_handle(handle_id); /* PRQA S 3200 */ + +exit: + kfree(equalizer); + + return 0; +} + +/*********************************************************************** + * APIs for TDM Renderer component + * ********************************************************************/ + +/** *********************************************************** + *\brief set ADSP TDM Renderer parameters + * + *\param[in] tdm_renderer Pointer to TDM Renderer component + *\retval 0 Success + *\retval -EINVAL Failed + **************************************************************/ +int xf_adsp_tdm_renderer_set_params(struct xf_adsp_tdm_renderer *tdm_renderer) +{ + struct xf_message msg; + struct xf_set_param_msg *msg_params; + struct xf_adsp_tdm_renderer_params *params; + struct xf_buffer *b; + int i; + struct xf_handle *handle; + int err = 0; + + /* check the sane ADSP base data */ + if (!base || !tdm_renderer) + return -EINVAL; + + params = &tdm_renderer->params; + + /* get TDM Renderer's handle data */ + handle = xf_adsp_base_get_handle(tdm_renderer->handle_id); + if (!handle) + return -EINVAL; + + b = xf_buffer_get(base->aux_pool); + + msg_params = xf_buffer_data(b); + + i = 0; + msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_IN_SAMPLE_RATE; + msg_params->item[i++].value = params->in_rate; + + msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_CHANNEL_MODE; + msg_params->item[i++].value = params->ch_mode; + + msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_PCM_WIDTH; + msg_params->item[i++].value = params->pcm_width; + + msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_FRAME_SIZE; + msg_params->item[i++].value = params->frame_size; + + msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_OUTPUT1; + msg_params->item[i++].value = params->dev1; + + msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_OUTPUT2; + msg_params->item[i++].value = params->dev2; + + msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL1; + msg_params->item[i++].value = params->dma1; + + msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL2; + msg_params->item[i++].value = params->dma2; + + msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; + msg_params->item[i++].value = params->out_rate; + + msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_VOLUME_RATE; + msg_params->item[i++].value = params->vol_rate; + + /* PRQA S 3200 2*/ + xf_create_msg(&msg, + __XF_MSG_ID(__XF_AP_CLIENT(0, tdm_renderer->handle_id), + __XF_PORT_SPEC2(handle->comp_id, 0)), + XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(i), msg_params, NULL); + + err = xf_send_and_receive(&msg); + + /* return msg to pool */ + xf_buffer_put(b); + + return err; +} + +/** *********************************************************** + *\brief get ADSP TDM Renderer parameters + * + *\param[in] tdm_renderer Pointer to TDM Renderer component + *\retval 0 Success + *\retval -EINVAL Failed + **************************************************************/ +/* PRQA S 1505 1*/ +int xf_adsp_tdm_renderer_get_params(struct xf_adsp_tdm_renderer *tdm_renderer) +{ + struct xf_adsp_tdm_renderer_params *params; + struct xf_message msg; + struct xf_buffer *b; + union xf_get_param_msg *msg_params; + int i; + struct xf_handle *handle; + int err = 0; + + /* check the sane ADSP base data */ + if (!base || !tdm_renderer) + return -EINVAL; + + params = &tdm_renderer->params; + + /* get TDM Renderer's handle data */ + handle = xf_adsp_base_get_handle(tdm_renderer->handle_id); + if (!handle) + return -EINVAL; + + b = xf_buffer_get(base->aux_pool); + msg_params = xf_buffer_data(b); + + i = 0; + /* PRQA S 3440 13 1*/ + msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_IN_SAMPLE_RATE; + msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_CHANNEL_MODE; + msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_PCM_WIDTH; + msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_FRAME_SIZE; + msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_OUTPUT1; + msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_OUTPUT2; + msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL1; + msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL2; + msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; + msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_VOLUME_RATE; + + /* PRQA S 3200 2*/ + xf_create_msg(&msg, + __XF_MSG_ID(__XF_AP_CLIENT(0, tdm_renderer->handle_id), + __XF_PORT_SPEC2(handle->comp_id, 0)), + XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(i), msg_params, NULL); + + err = xf_send_and_receive(&msg); + if (err != 0) + goto exit; /* PRQA S 2001 */ + + /* save the received parameters */ + i = 0; + params->in_rate = msg_params->r.value[i++]; /* PRQA S 3440 13 */ + params->ch_mode = msg_params->r.value[i++]; + params->pcm_width = msg_params->r.value[i++]; + params->frame_size = msg_params->r.value[i++]; + params->dev1 = msg_params->r.value[i++]; + params->dev2 = msg_params->r.value[i++]; + params->dma1 = msg_params->r.value[i++]; + params->dma2 = msg_params->r.value[i++]; + params->out_rate = msg_params->r.value[i++]; + params->vol_rate = msg_params->r.value[i++]; + +exit: + /* return msg to pool */ + xf_buffer_put(b); + + return err; +} + +/** ************************************************************************** + *\brief create TDM Renderer component + * + *\param[in,out] tdm_renderer Pointer to the registered component + *\param[in] cb Callback function + *\param[in] private_data Private data + *\retval 0 Success + *\retval -EINVAL Invalid base instance or register fail + *\retval -ENOMEM Cannot allocate Renderer instance + *****************************************************************************/ +int xf_adsp_tdm_renderer_create(struct xf_adsp_tdm_renderer **tdm_renderer, + struct xf_callback_func *cb, + void *private_data) +{ + struct xf_adsp_tdm_renderer *tdm_rdr; + int err; + int comp_id; + + /* check the sane ADSP base data */ + if (!base) + return -EINVAL; + + tdm_rdr = kmalloc(sizeof(*tdm_rdr), GFP_KERNEL); + if (!tdm_rdr) + return -ENOMEM; + + /* PRQA S 3200 */ + memset(tdm_rdr, 0, sizeof(struct xf_adsp_tdm_renderer)); + + /* register TDM Renderer component */ + err = xf_adsp_register("tdm-renderer", &comp_id); + if (err != 0) + goto err2; /* PRQA S 2001 */ + + /* register TDM Renderer to ADSP base control */ + tdm_rdr->handle_id = xf_adsp_base_register_handle(private_data, + cb, comp_id); + + if (tdm_rdr->handle_id <= 0) { + err = -EINVAL; + goto err1; /* PRQA S 2001 */ + } + + /* get the default parameter from plugin */ + err = xf_adsp_tdm_renderer_get_params(tdm_rdr); + if (err != 0) + goto err1; /* PRQA S 2001 */ + + /* save compoent data */ + *tdm_renderer = tdm_rdr; + + return 0; + +err1: + xf_adsp_unregister(comp_id); /* PRQA S 3200 */ + +err2: + kfree(tdm_rdr); + + return err; +} + +/** *********************************************************** + *\brief deinitialize ADSP TDM Renderer component + * + *\param[in] tdm_renderer Pointer to TDM Renderer component + *\retval 0 Success + *\retval -EINVAL Invalid base or Renderer data + **************************************************************/ +/* PRQA S 3673 1*/ +int xf_adsp_tdm_renderer_destroy(struct xf_adsp_tdm_renderer *tdm_renderer) +{ + struct xf_handle *handle; + int handle_id; + + /* check the sane ADSP base data */ + if (!base || !tdm_renderer) + return -EINVAL; + + handle_id = tdm_renderer->handle_id; + + handle = xf_adsp_base_get_handle(handle_id); + if (!handle) + goto exit; /* PRQA S 2001 */ + + /* unregister component */ + xf_adsp_unregister(handle->comp_id); /* PRQA S 3200 */ + + /* free handle data from base control */ + xf_adsp_base_free_handle(handle_id); /* PRQA S 3200 */ + +exit: + kfree(tdm_renderer); + + return 0; +} + +/*********************************************************************** + * APIs for TDM Capture component + * ********************************************************************/ + +/** *********************************************************** + *\brief set ADSP TDM Capture parameters + * + *\param[in] tdm_capture Pointer to TDM Capture component + *\retval 0 Success + *\retval -EINVAL Failed + **************************************************************/ +int xf_adsp_tdm_capture_set_params(struct xf_adsp_tdm_capture *tdm_capture) +{ + struct xf_message msg; + struct xf_set_param_msg *msg_params; + struct xf_adsp_tdm_capture_params *params; + struct xf_buffer *b; + int i; + struct xf_handle *handle; + int err = 0; + + /* check the sane ADSP base data */ + if (!base || !tdm_capture) + return -EINVAL; + + params = &tdm_capture->params; + + /* get TDM Capture's handle data */ + handle = xf_adsp_base_get_handle(tdm_capture->handle_id); + if (!handle) + return -EINVAL; + + b = xf_buffer_get(base->aux_pool); + + msg_params = xf_buffer_data(b); + + i = 0; + msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_IN_SAMPLE_RATE; + msg_params->item[i++].value = params->in_rate; + + msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_CHANNEL_MODE; + msg_params->item[i++].value = params->ch_mode; + + msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_PCM_WIDTH; + msg_params->item[i++].value = params->pcm_width; + + msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_FRAME_SIZE; + msg_params->item[i++].value = params->frame_size; + + msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_INPUT1; + msg_params->item[i++].value = params->dev1; + + msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_INPUT2; + msg_params->item[i++].value = params->dev2; + + msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL1; + msg_params->item[i++].value = params->dma1; + + msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL2; + msg_params->item[i++].value = params->dma2; + + msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE; + msg_params->item[i++].value = params->out_rate; + + msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_VOLUME_RATE; + msg_params->item[i++].value = params->vol_rate; + + /* PRQA S 3200 2*/ + xf_create_msg(&msg, + __XF_MSG_ID(__XF_AP_CLIENT(0, tdm_capture->handle_id), + __XF_PORT_SPEC2(handle->comp_id, 0)), + XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(i), msg_params, NULL); + + err = xf_send_and_receive(&msg); + + /* return msg to pool */ + xf_buffer_put(b); + + return err; +} + +/** *********************************************************** + *\brief get ADSP TDM Capture parameters + * + *\param[in] tdm_capture Pointer to TDM Capture component + *\retval 0 Success + *\retval -EINVAL Failed + **************************************************************/ +/* PRQA S 1505 1*/ +int xf_adsp_tdm_capture_get_params(struct xf_adsp_tdm_capture *tdm_capture) +{ + struct xf_adsp_tdm_capture_params *params; + struct xf_message msg; + struct xf_buffer *b; + union xf_get_param_msg *msg_params; + int i; + struct xf_handle *handle; + int err = 0; + + /* check the sane ADSP base data */ + if (!base || !tdm_capture) + return -EINVAL; + + params = &tdm_capture->params; + + /* get TDM Capture's handle data */ + handle = xf_adsp_base_get_handle(tdm_capture->handle_id); + if (!handle) + return -EINVAL; + + b = xf_buffer_get(base->aux_pool); + msg_params = xf_buffer_data(b); + + i = 0; + /* PRQA S 3440 13 1*/ + msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_IN_SAMPLE_RATE; + msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_CHANNEL_MODE; + msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_PCM_WIDTH; + msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_FRAME_SIZE; + msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_INPUT1; + msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_INPUT2; + msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL1; + msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL2; + msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE; + msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_VOLUME_RATE; + + /* PRQA S 3200 2*/ + xf_create_msg(&msg, + __XF_MSG_ID(__XF_AP_CLIENT(0, tdm_capture->handle_id), + __XF_PORT_SPEC2(handle->comp_id, 0)), + XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(i), msg_params, NULL); + + err = xf_send_and_receive(&msg); + if (err != 0) + goto exit; /* PRQA S 2001 */ + + /* save the received parameters */ + i = 0; + params->in_rate = msg_params->r.value[i++]; /* PRQA S 3440 13 */ + params->ch_mode = msg_params->r.value[i++]; + params->pcm_width = msg_params->r.value[i++]; + params->frame_size = msg_params->r.value[i++]; + params->dev1 = msg_params->r.value[i++]; + params->dev2 = msg_params->r.value[i++]; + params->dma1 = msg_params->r.value[i++]; + params->dma2 = msg_params->r.value[i++]; + params->out_rate = msg_params->r.value[i++]; + params->vol_rate = msg_params->r.value[i++]; + +exit: + /* return msg to pool */ + xf_buffer_put(b); + + return err; +} + +/** ************************************************************************** + *\brief create TDM Capture component + * + *\param[in,out] tdm_capture Pointer to the registered component + *\param[in] cb Callback function + *\param[in] private_data Private data + *\retval 0 Success + *\retval -EINVAL Invalid base instance or register fail + *\retval -ENOMEM Cannot allocate Renderer instance + *****************************************************************************/ +int xf_adsp_tdm_capture_create(struct xf_adsp_tdm_capture **tdm_capture, + struct xf_callback_func *cb, void *private_data) +{ + struct xf_adsp_tdm_capture *tdm_cap; + int err; + int comp_id; + + /* check the sane ADSP base data */ + if (!base) + return -EINVAL; + + tdm_cap = kmalloc(sizeof(*tdm_cap), GFP_KERNEL); + if (!tdm_cap) + return -ENOMEM; + + /* PRQA S 3200 */ + memset(tdm_cap, 0, sizeof(struct xf_adsp_tdm_capture)); + + /* register TDM Capture component */ + err = xf_adsp_register("tdm-capture", &comp_id); + if (err != 0) + goto err2; /* PRQA S 2001 */ + + /* register TDM Capture to ADSP base control */ + tdm_cap->handle_id = xf_adsp_base_register_handle(private_data, + cb, comp_id); + + if (tdm_cap->handle_id <= 0) { + err = -EINVAL; + goto err1; /* PRQA S 2001 */ + } + + /* get the default parameter from plugin */ + err = xf_adsp_tdm_capture_get_params(tdm_cap); + if (err != 0) + goto err1; /* PRQA S 2001 */ + + /* save compoent data */ + *tdm_capture = tdm_cap; + + return 0; + +err1: + xf_adsp_unregister(comp_id); /* PRQA S 3200 */ + +err2: + kfree(tdm_cap); + + return err; +} + +/** *********************************************************** + *\brief deinitialize ADSP TDM Capture component + * + *\param[in] tdm_capture Pointer to TDM Capture component + *\retval 0 Success + *\retval -EINVAL Invalid base or Renderer data + **************************************************************/ +/* PRQA S 3673 */ +int xf_adsp_tdm_capture_destroy(struct xf_adsp_tdm_capture *tdm_capture) +{ + struct xf_handle *handle; + int handle_id; + + /* check the sane ADSP base data */ + if (!base || !tdm_capture) + return -EINVAL; + + handle_id = tdm_capture->handle_id; + + handle = xf_adsp_base_get_handle(handle_id); + if (!handle) + goto exit; /* PRQA S 2001 */ + + /* unregister component */ + xf_adsp_unregister(handle->comp_id); /* PRQA S 3200 */ + + /* free handle data from base control */ + xf_adsp_base_free_handle(handle_id); /* PRQA S 3200 */ + +exit: + kfree(tdm_capture); + + return 0; +} diff --git a/sound/soc/adsp/xf-adsp-base.h b/sound/soc/adsp/xf-adsp-base.h new file mode 100644 index 0000000..27eb084 --- /dev/null +++ b/sound/soc/adsp/xf-adsp-base.h @@ -0,0 +1,275 @@ +/** ************************************************************************* + *\file xf-adsp-base.h + *\brief Header file for ADSP Base Control layer + *\addtogroup ADSP Driver + **************************************************************************** + *\date Oct. 21, 2017 + *\author Renesas Electronics Corporation + **************************************************************************** + *\par Copyright + * + * Copyright(c) 2016 Renesas Electoronics Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#ifndef __XF_ADSP_BASE_H +#define __XF_ADSP_BASE_H + +#include "xf-adsp-config.h" +#include + +#define XF_BUF_POOL_SIZE (4) /**< number of buffer in a data pool */ + +/**< maximum number of DSP component can be registered */ +#define MAX_HANDLE (256) + +/* define boolean */ +#define TRUE (1) +#define FALSE (0) + +/** \struct xf_callback_func + * \brief callback function for ADSP's response message + */ +struct xf_callback_func { + /** callback for empty buffer done message */ + int (*empty_buf_done)(void *data, int opcode, int length, char *buffer); + + /** callback for fill buffer done message */ + int (*fill_buf_done)(void *data, int opcode, int length, char *buffer); + + /** callback for event handler */ + int (*event_handler)(void *data); +}; + +/** \struct xf_adsp_renderer_params + * \brief parameter structure for Renderer component + */ +struct xf_adsp_renderer_params { + int channel; /**< channel number */ + int pcm_width; /**< PCM width */ + int frame_size; /**< frame size */ + int in_rate; /**< input sampling rate */ + int out_rate; /**< output sampling rate */ + int vol_rate; /**< volume rate */ + int dev1; /**< 1st device index */ + int dev2; /**< 2nd device index */ + int dma1; /**< 1st DMA index */ + int dma2; /**< 2nd DMA index */ + int out_channel; /**< output channels */ + int mix_ctrl; /**< mix control flag */ + int state; /**< operation state */ +}; + +/** \struct xf_adsp_renderer + * \brief Renderer component structure + */ +struct xf_adsp_renderer { + struct xf_adsp_renderer_params params; /**< parameter structure*/ + struct xf_pool *buf_pool; /**< buffer pool for data transfer */ + int handle_id; /**< ID of registered handle*/ +}; + +/** \struct xf_adsp_capture_params + *\brief parameter structure of Capture component + */ +struct xf_adsp_capture_params { + int channel; /**< channel number */ + int pcm_width; /**< PCM width */ + int frame_size; /**< frame size */ + int in_rate; /**< input sampling rate */ + int out_rate; /**< output sampling rate */ + int vol_rate; /**< volume rate */ + int dev1; /**< 1st device index */ + int dev2; /**< 2nd device index */ + int dma1; /**< 1st DMA index */ + int dma2; /**< 2nd DMA index */ + int state; /**< operation state */ +}; + +/** \struct xf_adsp_capture + * \brief Capture component structure + */ +struct xf_adsp_capture { + struct xf_adsp_capture_params params; /**< parameter structuer*/ + struct xf_pool *buf_pool; /**< buffer pool for data transfer */ + int handle_id; /**< ID of registered handle*/ +}; + +/** \struct xf_equalizer_parametric_coef + *\brief Parametric Equalizer type's parameters + */ +struct xf_equalizer_parametric_coef { + int type[XA_REL_EQZ_FILTER_NUM]; /**< Filter type */ + int fc[XA_REL_EQZ_FILTER_NUM]; /**< Filter center frequency */ + int gain[XA_REL_EQZ_FILTER_NUM]; /**< Filter gain */ + int band_width[XA_REL_EQZ_FILTER_NUM]; /**< Filter band width */ + int gain_base[XA_REL_EQZ_FILTER_NUM]; /**< Filter base gain */ +}; + +/** \struct xf_equalizer_graphic_coef + * \brief Graphic Equalizer type's parameters + */ +struct xf_equalizer_graphic_coef { + int gain_g[XA_REL_EQZ_GRAPHIC_BAND_NUM];/**< Graphic equalizer gain */ +}; + +/** \struct xf_adsp_equalizer_params + *\brief Equalizer parameters + */ +struct xf_adsp_equalizer_params { + int channel; /**< channel number */ + int pcm_width; /**< PCM width */ + int rate; /**< sampling rate */ + int eqz_type; /**< Equalizer type */ + struct xf_equalizer_parametric_coef p_coef; /**< Parametric params */ + struct xf_equalizer_graphic_coef g_coef; /**< Graphic params */ +}; + +/** \struct xf_adsp_equalizer + * \brief Equalizer component's structure + */ +struct xf_adsp_equalizer { + struct xf_adsp_equalizer_params params;/**< Equalizer parameters */ + struct xf_pool *buf_pool; /**< buffer pool for transfer data */ + int handle_id; /**< ID of registered handle */ +}; + +/** \struct xf_adsp_tdm_renderer_params + * \brief parameter structure for TDM Renderer component + */ +struct xf_adsp_tdm_renderer_params { + int ch_mode; /**< channel mode */ + int pcm_width; /**< PCM width */ + int frame_size; /**< frame size */ + int in_rate; /**< input sampling rate */ + int out_rate; /**< output sampling rate */ + int vol_rate; /**< volume rate */ + int dev1; /**< 1st device index */ + int dev2; /**< 2nd device index */ + int dma1; /**< 1st DMA index */ + int dma2; /**< 2nd DMA index */ +}; + +/** \struct xf_adsp_tdm_renderer + * \brief TDM Renderer component structure + */ +struct xf_adsp_tdm_renderer { + struct xf_adsp_tdm_renderer_params params; /**< parameter structure*/ + struct xf_pool *buf_pool; /**< buffer pool for data transfer */ + int handle_id; /**< ID of registered handle */ +}; + +/** \struct xf_adsp_tdm_capture_params + * \brief parameter structure for TDM Capture component + */ +struct xf_adsp_tdm_capture_params { + int ch_mode; /**< channel mode */ + int pcm_width; /**< PCM width */ + int frame_size; /**< frame size */ + int in_rate; /**< input sampling rate */ + int out_rate; /**< output sampling rate */ + int vol_rate; /**< volume rate */ + int dev1; /**< 1st device index */ + int dev2; /**< 2nd device index */ + int dma1; /**< 1st DMA index */ + int dma2; /**< 2nd DMA index */ +}; + +/** \struct xf_adsp_tdm_capture + * \brief TDM Capture component structure + */ +struct xf_adsp_tdm_capture { + struct xf_adsp_tdm_capture_params params; /**< parameter structure*/ + struct xf_pool *buf_pool; /**< buffer pool for data transfer */ + int handle_id; /**< ID of registered handle*/ +}; + +/** \struct xf_handle + * \brief Handle struct for each ADSP component + */ +struct xf_handle { + int comp_id;/**< ADSP component ID */ + struct xf_callback_func *cb;/**< callback functions */ + void *private_data; /**< private data for callback functions*/ +}; + +/** \struct xf_adsp_base + * \brief Base component structure + */ +struct xf_adsp_base { + struct xf_adsp_base_cmd cmd; /**< proxy commands */ + void *client; /**< client data which registered to proxy */ + struct xf_pool *aux_pool; /**< auxiliary buffer pool data */ + struct xf_handle *handle[MAX_HANDLE]; /**< handler data */ + struct task_struct *rsp_thread;/**< thread for response message*/ + wait_queue_head_t base_wait; /**< ADSP base's waiting queue */ + struct xf_message base_msg; /**< ADSP base's response message */ + int base_flag; /**< flag to control its waiting queue */ + int err_flag; /**< flag to indicate a error from plugins */ + int wait_flag; /**< flag to control the polling waiting*/ + spinlock_t lock; /**< spinlock data */ +}; + +struct xf_pool *xf_adsp_allocate_mem_pool(int pool_size, int buf_length); +int xf_adsp_free_mem_pool(struct xf_pool *pool); +char *xf_adsp_get_data_from_pool(struct xf_pool *pool, int index); + +int xf_adsp_empty_this_buffer(int handle_id, char *buffer, int length); +int xf_adsp_fill_this_buffer(int handle_id, char *buffer, int length); + +int xf_adsp_route(int src_handle_id, int dst_handle_id + , int buf_cnt, int buf_size); + +int xf_adsp_set_param(int handle_id, int index, int value); +int xf_adsp_get_param(int handle_id, int index, int *value); + +int xf_adsp_renderer_create(struct xf_adsp_renderer **renderer, + struct xf_callback_func *cb, void *private_data); +int xf_adsp_renderer_destroy(struct xf_adsp_renderer *renderer); +int xf_adsp_renderer_set_params(struct xf_adsp_renderer *renderer); +int xf_adsp_renderer_get_params(struct xf_adsp_renderer *renderer); + +int xf_adsp_capture_create(struct xf_adsp_capture **capture, + struct xf_callback_func *cb, void *private_data); +int xf_adsp_capture_destroy(struct xf_adsp_capture *capture); +int xf_adsp_capture_set_params(struct xf_adsp_capture *capture); +int xf_adsp_capture_get_params(struct xf_adsp_capture *capture); + +int xf_adsp_equalizer_create(struct xf_adsp_equalizer **equalizer, + struct xf_callback_func *cb, void *private_data); +int xf_adsp_equalizer_destroy(struct xf_adsp_equalizer *equalizer); +int xf_adsp_equalizer_set_params(struct xf_adsp_equalizer *equalizer); +int xf_adsp_equalizer_get_params(struct xf_adsp_equalizer *equalizer); + +int xf_adsp_tdm_renderer_create(struct xf_adsp_tdm_renderer **tdm_renderer, + struct xf_callback_func *cb, + void *private_data); +int xf_adsp_tdm_renderer_destroy(struct xf_adsp_tdm_renderer *tdm_renderer); +int xf_adsp_tdm_renderer_set_params(struct xf_adsp_tdm_renderer *tdm_renderer); +int xf_adsp_tdm_renderer_get_params(struct xf_adsp_tdm_renderer *tdm_renderer); + +int xf_adsp_tdm_capture_create(struct xf_adsp_tdm_capture **tdm_capture, + struct xf_callback_func *cb, + void *private_data); +int xf_adsp_tdm_capture_destroy(struct xf_adsp_tdm_capture *tdm_capture); +int xf_adsp_tdm_capture_set_params(struct xf_adsp_tdm_capture *tdm_capture); +int xf_adsp_tdm_capture_get_params(struct xf_adsp_tdm_capture *tdm_capture); + +#endif diff --git a/sound/soc/adsp/xf-adsp-config.h b/sound/soc/adsp/xf-adsp-config.h new file mode 100644 index 0000000..818a46a --- /dev/null +++ b/sound/soc/adsp/xf-adsp-config.h @@ -0,0 +1,604 @@ +/** **************************************************************************** + *\file xf-adsp-config.h + *\brief Header file for ADSP configuration + *\addtogroup ADSP Driver + ******************************************************************************* + *\date Oct. 21, 2017 + *\author Renesas Electronics Corporation + ******************************************************************************* + *\par Copyright + * + * Copyright(c) 2016 Renesas Electoronics Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#ifndef __XF_ADSP_CONFIG_H +#define __XF_ADSP_CONFIG_H + +/* Equalizer definition */ +#define XA_REL_EQZ_FILTER_NUM (9) /**< number of filter */ +#define XA_REL_EQZ_GRAPHIC_BAND_NUM (5) /**< number of graphic band */ + +struct xf_buffer { + void *address; + union { /* PRQA S 750 3 */ + struct xf_buffer *next; + struct xf_pool *pool; + } link; +}; + +struct xf_pool { + /* length of individual buffer in a pool */ + u32 length; + + /* number of buffer in a pool */ + u32 number; + + /* pointer to pool memory */ + void *p; + + /* pointer to first free buffer in a pool */ + struct xf_buffer *free; + + /* individual buffer */ + struct xf_buffer buffer[0]; /* PRQA S 1037 */ +}; + +struct xf_message { + /* pointer to the next item in the list */ + struct xf_message *next; + + /* shmem session_id */ + u32 id; + + /* operation code */ + u32 opcode; + + /* length of attached message buffer */ + u32 length; + + /* message buffer */ + void *buffer; +}; + +/******************************************************************************* + * XF_GET_PARAM message + ******************************************************************************/ + +/* ...message body (command/response) */ +union xf_get_param_msg { /* PRQA S 750 18 */ + /* ...command structure */ + struct { + /* ...array of parameters requested */ + u32 id[0]; /* PRQA S 1037 */ + + } __attribute__((__packed__)) c; + + /* ...response structure */ + struct { + /* ...array of parameters values */ + u32 value[0];/* PRQA S 1037 */ + + } __attribute__((__packed__)) r; + +}; + +/* ...length of the XF_GET_PARAM command/response */ +/* PRQA S 3453 2 */ +#define XF_GET_PARAM_CMD_LEN(params) (sizeof(u32) * (params)) +#define XF_GET_PARAM_RSP_LEN(params) (sizeof(u32) * (params)) + +/******************************************************************************* + * XF_SET_PARAM message + ******************************************************************************/ + +/* ...component initialization parameter */ +struct xf_set_param_item { + /* ...index of parameter passed to SET_CONFIG_PARAM call */ + u32 id; + + /* ...value of parameter */ + u32 value; + +} __attribute__ ((__packed__)); + +/* ...message body (no response message? - tbd) */ +struct xf_set_param_msg { + /* ...command message */ + struct xf_set_param_item item[0]; /* PRQA S 1037 */ + +} __attribute__ ((__packed__)); + +/* ...length of the command message */ +/* PRQA S 3453 */ +#define XF_SET_PARAM_CMD_LEN(params) \ + (sizeof(struct xf_set_param_item) * (params)) + +/******************************************************************************* + * XF_ROUTE definition + ******************************************************************************/ + +/* ...port routing command */ +struct xf_route_port_msg { + /* ...source port specification */ + u32 src; + + /* ...destination port specification */ + u32 dst; + + /* ...number of buffers to allocate */ + u32 alloc_number; + + /* ...length of buffer to allocate */ + u32 alloc_size; + + /* ...alignment restriction for a buffer */ + u32 alloc_align; + +} __attribute__((__packed__)); + +/******************************************************************************* + * XF_UNROUTE definition + ******************************************************************************/ + +/* ...port unrouting command */ +struct xf_unroute_port_msg { + /* ...source port specification */ + u32 src; + + /* ...destination port specification */ + u32 dst; + +} __attribute__((__packed__)); + +/* ...Capture states */ +enum xa_capture_state { + XA_CAP_STATE_RUN = 0, + XA_CAP_STATE_IDLE = 1, + XA_CAP_STATE_PAUSE = 2 +}; + +/* ...Renderer states */ +enum xa_renderer_state { + XA_RDR_STATE_RUN = 0, + XA_RDR_STATE_IDLE = 1, + XA_RDR_STATE_PAUSE = 2 +}; + +/******************************************************************************* + * Message routing composition - move somewhere else - tbd + ******************************************************************************/ + +/* ...adjust IPC client of message going from user-space */ +#define XF_MSG_AP_FROM_USER(id, client) \ + (((id) & ~(0xF << 2)) | ((client) << 2)) + +/* ...wipe out IPC client from message going to user-space */ +#define XF_MSG_AP_TO_USER(id) \ + ((id) & ~(0xF << 18)) + +/* ...port specification (12 bits) */ +#define __XF_PORT_SPEC(core, id, port) ((core) | ((id) << 2) | ((port) << 8)) +#define __XF_PORT_SPEC2(id, port) ((id) | ((port) << 8)) +#define XF_PORT_CORE(spec) ((spec) & 0x3) +#define XF_PORT_CLIENT(spec) (((spec) >> 2) & 0x3F) +#define XF_PORT_ID(spec) (((spec) >> 8) & 0xF) + +/* ...message id contains source and destination ports specification */ +#define __XF_MSG_ID(src, dst) (((src) & 0xFFFF) | (((dst) & 0xFFFF) << 16)) +#define XF_MSG_SRC(id) (((id) >> 0) & 0xFFFF) +#define XF_MSG_SRC_CORE(id) (((id) >> 0) & 0x3) +#define XF_MSG_SRC_CLIENT(id) (((id) >> 2) & 0x3F) +#define XF_MSG_SRC_PORT(id) (((id) >> 8) & 0xF) +#define XF_MSG_SRC_PROXY(id) (((id) >> 15) & 0x1) +#define XF_MSG_DST(id) (((id) >> 16) & 0xFFFF) +#define XF_MSG_DST_CORE(id) (((id) >> 16) & 0x3) +#define XF_MSG_DST_CLIENT(id) (((id) >> 18) & 0x3F) +#define XF_MSG_DST_PORT(id) (((id) >> 24) & 0xF) +#define XF_MSG_DST_PROXY(id) (((id) >> 31) & 0x1) + +/* ...special treatment of AP-proxy destination field */ +#define XF_AP_IPC_CLIENT(id) (((id) >> 18) & 0xF) +#define XF_AP_CLIENT(id) (((id) >> 22) & 0x1FF) +#define __XF_AP_PROXY(core) ((core) | 0x8000) +#define __XF_DSP_PROXY(core) ((core) | 0x8000) +#define __XF_AP_CLIENT(core, client) ((core) | ((client) << 6) | 0x8000) + +/******************************************************************************* + * Opcode composition + ******************************************************************************/ + +/* ...opcode composition with command/response data tags */ +#define __XF_OPCODE(c, r, op) (((c) << 31) | ((r) << 30) | ((op) & 0x3F)) + +/* ...accessors */ +#define XF_OPCODE_CDATA(opcode) ((opcode) & (1 << 31)) +#define XF_OPCODE_RDATA(opcode) ((opcode) & (1 << 30)) +#define XF_OPCODE_TYPE(opcode) ((opcode) & (0x3F)) + +/******************************************************************************* + * Opcode types + ******************************************************************************/ + +/* ...unregister client */ +#define XF_UNREGISTER __XF_OPCODE(0, 0, 0) + +/* ...register client at proxy */ +#define XF_REGISTER __XF_OPCODE(1, 0, 1) + +/* ...port routing command */ +#define XF_ROUTE __XF_OPCODE(1, 0, 2) + +/* ...port unrouting command */ +#define XF_UNROUTE __XF_OPCODE(1, 0, 3) + +/* ...shared buffer allocation */ +#define XF_ALLOC __XF_OPCODE(0, 0, 4) + +/* ...shared buffer freeing */ +#define XF_FREE __XF_OPCODE(0, 0, 5) + +/* ...set component parameters */ +#define XF_SET_PARAM __XF_OPCODE(1, 0, 6) + +/* ...get component parameters */ +#define XF_GET_PARAM __XF_OPCODE(1, 1, 7) + +/* ...input buffer reception */ +#define XF_EMPTY_THIS_BUFFER __XF_OPCODE(1, 0, 8) + +/* ...output buffer reception */ +#define XF_FILL_THIS_BUFFER __XF_OPCODE(0, 1, 9) + +/* ...flush specific port */ +#define XF_FLUSH __XF_OPCODE(0, 0, 10) + +/* ...start component operation */ +#define XF_START __XF_OPCODE(0, 0, 11) + +/* ...stop component operation */ +#define XF_STOP __XF_OPCODE(0, 0, 12) + +/* ...pause component operation */ +#define XF_PAUSE __XF_OPCODE(0, 0, 13) + +/* ...resume component operation */ +#define XF_RESUME __XF_OPCODE(0, 0, 14) + +/* ...total amount of supported decoder commands */ +#define __XF_OP_NUM (15) + +/************************************************* + * Renderer - specific configuration parameters + * **********************************************/ + +enum xa_config_param_renderer { + XA_RDR_CONFIG_PARAM_STATE = 0, + XA_RDR_CONFIG_PARAM_PCM_WIDTH = 1, + XA_RDR_CONFIG_PARAM_CHANNELS = 2, + XA_RDR_CONFIG_PARAM_SAMPLE_RATE = 3, + XA_RDR_CONFIG_PARAM_FRAME_SIZE = 4, + XA_RDR_CONFIG_PARAM_OUTPUT1 = 5, + XA_RDR_CONFIG_PARAM_DMACHANNEL1 = 6, + XA_RDR_CONFIG_PARAM_OUTPUT2 = 7, + XA_RDR_CONFIG_PARAM_DMACHANNEL2 = 8, + XA_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE = 9, + XA_RDR_CONFIG_PARAM_VOLUME_RATE = 10, + XA_RDR_CONFIG_PARAM_OUT_CHANNELS = 11, + XA_RDR_CONFIG_PARAM_MIX_CONTROL = 12, + XA_RDR_CONFIG_PARAM_NUM = 13 +}; + +/************************************************* + * Capture - specific configuration parameters + * **********************************************/ + +enum xa_config_param_capture { + XA_CAP_CONFIG_PARAM_CB = 0, + XA_CAP_CONFIG_PARAM_STATE = 1, + XA_CAP_CONFIG_PARAM_PCM_WIDTH = 2, + XA_CAP_CONFIG_PARAM_CHANNELS = 3, + XA_CAP_CONFIG_PARAM_SAMPLE_RATE = 4, + XA_CAP_CONFIG_PARAM_FRAME_SIZE = 5, + XA_CAP_CONFIG_PARAM_INPUT1 = 6, + XA_CAP_CONFIG_PARAM_DMACHANNEL1 = 7, + XA_CAP_CONFIG_PARAM_INPUT2 = 8, + XA_CAP_CONFIG_PARAM_DMACHANNEL2 = 9, + XA_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE = 10, + XA_CAP_CONFIG_PARAM_VOLUME_RATE = 11, + XA_CAP_CONFIG_PARAM_NUM = 12 +}; + +/************************************************* + * Equalizer - specific configuration parameters + * **********************************************/ + +enum xa_rel_eqz_filter_type { + XA_REL_EQZ_TYPE_THROUGH = 0, + XA_REL_EQZ_TYPE_PEAK = 1, + XA_REL_EQZ_TYPE_BASS = 2, + XA_REL_EQZ_TYPE_TREBLE = 3 +}; + +enum xa_rel_eqz_type { + XA_REL_EQZ_TYPE_PARAMETRIC = 0, + XA_REL_EQZ_TYPE_GRAPHIC = 1 +}; + +/*****************************************************************************/ +/* Additional subcommand indices */ +/*****************************************************************************/ + +enum xa_add_cmd_type_generic { + /* XA_API_CMD_SET_CONFIG_PARAM indices */ + XA_EQZ_CONFIG_PARAM_COEF_FS = 0x0000, + XA_EQZ_CONFIG_PARAM_PCM_WIDTH = 0x0001, + XA_EQZ_CONFIG_PARAM_CH = 0x0002, + XA_EQZ_CONFIG_PARAM_EQZ_TYPE = 0x0003, + + XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_FC = 0x0010, + XA_EQZ_CONFIG_PARAM_FILTER_1_COEF_FC = 0x0011, + XA_EQZ_CONFIG_PARAM_FILTER_2_COEF_FC = 0x0012, + XA_EQZ_CONFIG_PARAM_FILTER_3_COEF_FC = 0x0013, + XA_EQZ_CONFIG_PARAM_FILTER_4_COEF_FC = 0x0014, + XA_EQZ_CONFIG_PARAM_FILTER_5_COEF_FC = 0x0015, + XA_EQZ_CONFIG_PARAM_FILTER_6_COEF_FC = 0x0016, + XA_EQZ_CONFIG_PARAM_FILTER_7_COEF_FC = 0x0017, + XA_EQZ_CONFIG_PARAM_FILTER_8_COEF_FC = 0x0018, + + XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_TYPE = 0x0020, + XA_EQZ_CONFIG_PARAM_FILTER_1_COEF_TYPE = 0x0021, + XA_EQZ_CONFIG_PARAM_FILTER_2_COEF_TYPE = 0x0022, + XA_EQZ_CONFIG_PARAM_FILTER_3_COEF_TYPE = 0x0023, + XA_EQZ_CONFIG_PARAM_FILTER_4_COEF_TYPE = 0x0024, + XA_EQZ_CONFIG_PARAM_FILTER_5_COEF_TYPE = 0x0025, + XA_EQZ_CONFIG_PARAM_FILTER_6_COEF_TYPE = 0x0026, + XA_EQZ_CONFIG_PARAM_FILTER_7_COEF_TYPE = 0x0027, + XA_EQZ_CONFIG_PARAM_FILTER_8_COEF_TYPE = 0x0028, + + XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BW = 0x0030, + XA_EQZ_CONFIG_PARAM_FILTER_1_COEF_BW = 0x0031, + XA_EQZ_CONFIG_PARAM_FILTER_2_COEF_BW = 0x0032, + XA_EQZ_CONFIG_PARAM_FILTER_3_COEF_BW = 0x0033, + XA_EQZ_CONFIG_PARAM_FILTER_4_COEF_BW = 0x0034, + XA_EQZ_CONFIG_PARAM_FILTER_5_COEF_BW = 0x0035, + XA_EQZ_CONFIG_PARAM_FILTER_6_COEF_BW = 0x0036, + XA_EQZ_CONFIG_PARAM_FILTER_7_COEF_BW = 0x0037, + XA_EQZ_CONFIG_PARAM_FILTER_8_COEF_BW = 0x0038, + + XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_GA = 0x0040, + XA_EQZ_CONFIG_PARAM_FILTER_1_COEF_GA = 0x0041, + XA_EQZ_CONFIG_PARAM_FILTER_2_COEF_GA = 0x0042, + XA_EQZ_CONFIG_PARAM_FILTER_3_COEF_GA = 0x0043, + XA_EQZ_CONFIG_PARAM_FILTER_4_COEF_GA = 0x0044, + XA_EQZ_CONFIG_PARAM_FILTER_5_COEF_GA = 0x0045, + XA_EQZ_CONFIG_PARAM_FILTER_6_COEF_GA = 0x0046, + XA_EQZ_CONFIG_PARAM_FILTER_7_COEF_GA = 0x0047, + XA_EQZ_CONFIG_PARAM_FILTER_8_COEF_GA = 0x0048, + + XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BA = 0x0050, + XA_EQZ_CONFIG_PARAM_FILTER_1_COEF_BA = 0x0051, + XA_EQZ_CONFIG_PARAM_FILTER_2_COEF_BA = 0x0052, + XA_EQZ_CONFIG_PARAM_FILTER_3_COEF_BA = 0x0053, + XA_EQZ_CONFIG_PARAM_FILTER_4_COEF_BA = 0x0054, + XA_EQZ_CONFIG_PARAM_FILTER_5_COEF_BA = 0x0055, + XA_EQZ_CONFIG_PARAM_FILTER_6_COEF_BA = 0x0056, + XA_EQZ_CONFIG_PARAM_FILTER_7_COEF_BA = 0x0057, + XA_EQZ_CONFIG_PARAM_FILTER_8_COEF_BA = 0x0058, + + XA_EQZ_CONFIG_PARAM_BAND_0_GCOEF_GA = 0x0060, + XA_EQZ_CONFIG_PARAM_BAND_1_GCOEF_GA = 0x0061, + XA_EQZ_CONFIG_PARAM_BAND_2_GCOEF_GA = 0x0062, + XA_EQZ_CONFIG_PARAM_BAND_3_GCOEF_GA = 0x0063, + XA_EQZ_CONFIG_PARAM_BAND_4_GCOEF_GA = 0x0064 +}; + +/* ...tdm-renderer-specific configuration parameters */ +enum xa_config_param_tdm_renderer { + XA_TDM_RDR_CONFIG_PARAM_PCM_WIDTH = 0, + XA_TDM_RDR_CONFIG_PARAM_CHANNEL_MODE = 1, + XA_TDM_RDR_CONFIG_PARAM_IN_SAMPLE_RATE = 2, + XA_TDM_RDR_CONFIG_PARAM_FRAME_SIZE = 3, + XA_TDM_RDR_CONFIG_PARAM_OUTPUT1 = 4, + XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL1 = 5, + XA_TDM_RDR_CONFIG_PARAM_OUTPUT2 = 6, + XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL2 = 7, + XA_TDM_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE = 8, + XA_TDM_RDR_CONFIG_PARAM_VOLUME_RATE = 9 +}; + +enum xa_rel_tdm_renderer_channel_mode { + XA_TDM_RDR_CHANNEL_MODE_2X4 = 0, /**< 4 stereo TDM data */ + XA_TDM_RDR_CHANNEL_MODE_1X8 = 1, /**< 1 eight-channel TDM data*/ + /**< 1 six-channels plus 1 two-channels TDM data */ + XA_TDM_RDR_CHANNEL_MODE_6_2 = 2, + XA_TDM_RDR_CHANNEL_MODE_2X3 = 3, /**< 3 stereo TDM data */ + XA_TDM_RDR_CHANNEL_MODE_1X6 = 4 /**< 1 six-channel TDM data */ +}; + +/* ...TDM Capture-specific configuration parameters */ +enum xa_config_param_tdm_capture { + XA_TDM_CAP_CONFIG_PARAM_PCM_WIDTH = 0, + XA_TDM_CAP_CONFIG_PARAM_CHANNEL_MODE = 1, + XA_TDM_CAP_CONFIG_PARAM_IN_SAMPLE_RATE = 2, + XA_TDM_CAP_CONFIG_PARAM_FRAME_SIZE = 3, + XA_TDM_CAP_CONFIG_PARAM_INPUT1 = 4, + XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL1 = 5, + XA_TDM_CAP_CONFIG_PARAM_INPUT2 = 6, + XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL2 = 7, + XA_TDM_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE = 8, + XA_TDM_CAP_CONFIG_PARAM_VOLUME_RATE = 9 +}; + +enum xa_rel_tdm_capture_channel_mode { + XA_TDM_CAP_CHANNEL_MODE_2X4 = 0, /**< 4 stereo TDM data */ + XA_TDM_CAP_CHANNEL_MODE_1X8 = 1, /**< 1 eight-channel TDM data*/ + /**< 1 six-channels plus 1 two-channels TDM data */ + XA_TDM_CAP_CHANNEL_MODE_6_2 = 2, + XA_TDM_CAP_CHANNEL_MODE_2X3 = 3, /**< 3 stereo TDM data */ + XA_TDM_CAP_CHANNEL_MODE_1X6 = 4 /**< 1 six-channel TDM data */ +}; + +/*****************************************************************************/ +/* HW supported */ +/*****************************************************************************/ +/* ...SSI modules supported by HW */ +enum ssi_module { + SSI00 = 0, + SSI01 = 1, + SSI02 = 2, + SSI03 = 3, + SSI04 = 4, + SSI05 = 5, + SSI06 = 6, + SSI07 = 7, + SSI10 = 10, + SSI11 = 11, + SSI12 = 12, + SSI13 = 13, + SSI14 = 14, + SSI15 = 15, + SSI16 = 16, + SSI17 = 17, + SSI20 = 20, + SSI21 = 21, + SSI22 = 22, + SSI23 = 23, + SSI24 = 24, + SSI25 = 25, + SSI26 = 26, + SSI27 = 27, + SSI30 = 30, + SSI31 = 31, + SSI32 = 32, + SSI33 = 33, + SSI34 = 34, + SSI35 = 35, + SSI36 = 36, + SSI37 = 37, + SSI40 = 40, + SSI41 = 41, + SSI42 = 42, + SSI43 = 43, + SSI44 = 44, + SSI45 = 45, + SSI46 = 46, + SSI47 = 47, + SSI5 = 50, + SSI6 = 60, + SSI7 = 70, + SSI8 = 80, + SSI90 = 90, + SSI91 = 91, + SSI92 = 92, + SSI93 = 93, + SSI94 = 94, + SSI95 = 95, + SSI96 = 96, + SSI97 = 97 +}; + +/* ...SRC modules supported by HW */ +enum src_module { + SRC0 = 110, /* SRC0 */ + SRC1 = 111, /* SRC1 */ + SRC2 = 112, /* SRC2 */ + SRC3 = 113, /* SRC3 */ + SRC4 = 114, /* SRC4 */ + SRC5 = 115, /* SRC5 */ + SRC6 = 116, /* SRC6 */ + SRC7 = 117, /* SRC7 */ + SRC8 = 118, /* SRC8 */ + SRC9 = 119, /* SRC9 */ + SRCMAX = 120 /* Maximum number of SRC modules */ +}; + +/* ...PDMA supported by HW */ +enum { + PDMA_CH00 = 0, + PDMA_CH01 = 1, + PDMA_CH02 = 2, + PDMA_CH03 = 3, + PDMA_CH04 = 4, + PDMA_CH05 = 5, + PDMA_CH06 = 6, + PDMA_CH07 = 7, + PDMA_CH08 = 8, + PDMA_CH09 = 9, + PDMA_CH10 = 10, + PDMA_CH11 = 11, + PDMA_CH12 = 12, + PDMA_CH13 = 13, + PDMA_CH14 = 14, + PDMA_CH15 = 15, + PDMA_CH16 = 16, + PDMA_CH17 = 17, + PDMA_CH18 = 18, + PDMA_CH19 = 19, + PDMA_CH20 = 20, + PDMA_CH21 = 21, + PDMA_CH22 = 22, + PDMA_CH23 = 23, + PDMA_CH24 = 24, + PDMA_CH25 = 25, + PDMA_CH26 = 26, + PDMA_CH27 = 27, + PDMA_CH28 = 28, + PDMA_CHMAX = 29 +}; + +/* ...DMAC supported by HW */ +enum { + ADMAC_CH00 = PDMA_CHMAX + 0, + ADMAC_CH01 = PDMA_CHMAX + 1, + ADMAC_CH02 = PDMA_CHMAX + 2, + ADMAC_CH03 = PDMA_CHMAX + 3, + ADMAC_CH04 = PDMA_CHMAX + 4, + ADMAC_CH05 = PDMA_CHMAX + 5, + ADMAC_CH06 = PDMA_CHMAX + 6, + ADMAC_CH07 = PDMA_CHMAX + 7, + ADMAC_CH08 = PDMA_CHMAX + 8, + ADMAC_CH09 = PDMA_CHMAX + 9, + ADMAC_CH10 = PDMA_CHMAX + 10, + ADMAC_CH11 = PDMA_CHMAX + 11, + ADMAC_CH12 = PDMA_CHMAX + 12, + ADMAC_CH13 = PDMA_CHMAX + 13, + ADMAC_CH14 = PDMA_CHMAX + 14, + ADMAC_CH15 = PDMA_CHMAX + 15, + ADMAC_CH16 = PDMA_CHMAX + 16, + ADMAC_CH17 = PDMA_CHMAX + 17, + ADMAC_CH18 = PDMA_CHMAX + 18, + ADMAC_CH19 = PDMA_CHMAX + 19, + ADMAC_CH20 = PDMA_CHMAX + 20, + ADMAC_CH21 = PDMA_CHMAX + 21, + ADMAC_CH22 = PDMA_CHMAX + 22, + ADMAC_CH23 = PDMA_CHMAX + 23, + ADMAC_CH24 = PDMA_CHMAX + 24, + ADMAC_CH25 = PDMA_CHMAX + 25, + ADMAC_CH26 = PDMA_CHMAX + 26, + ADMAC_CH27 = PDMA_CHMAX + 27, + ADMAC_CH28 = PDMA_CHMAX + 28, + ADMAC_CH29 = PDMA_CHMAX + 29, + ADMAC_CH30 = PDMA_CHMAX + 30, + ADMAC_CH31 = PDMA_CHMAX + 31, + ADMAC_CHMAX = PDMA_CHMAX + 32 +}; + +#endif -- 2.7.4