MT6737 Android N 平臺 Audio系統學習----ALSA Driver
1、ALSA簡述
ALSA是Advanced Linux Sound Architecture 的縮寫,目前已經成為了linux的主流音訊體系結構,在核心裝置驅動層,ALSA提供了alsa-driver,同時在應用層,ALSA為我們提供了alsa-lib,應用程式只要呼叫alsa-lib提供的API,即可以完成對底層音訊硬體的控制。
Kernel-3.10/sound/core該目錄包含了ALSA驅動的中間層,它是整個ALSA驅動的核心部分。
Kernel-3.10/sound/soc 針對system-on-chip體系的中間層程式碼 ,soc/codecs 針對soc體系的各種codec的程式碼,與平臺無關 。
音效卡的主要功能
三個主要功能:
(1)播放聲音(playback)
(2)錄音(capture)
(3)聲音控制(control)
執行adb shell ls -l /dev/snd,我們可以看到當前平臺註冊的音效卡驅動裝置。
主要分為以下幾類:
pcmC0D0p —— Playback
pcmC0D0c —— Capture
controlC0 —— Control,比如各種音訊控制元件開關、音量增益等
ASoC把音訊系統同樣分為3大部分:Machine,Platform和Codec。
Platform 一般是指某一個SoC平臺,比如MT6582, MT6595, MT6752等等,與音訊相關的通常包含該SoC中的Clock、AFE、I2S、DMA等等。
Codec 字面上的意思就是編解碼器,Codec裡面包含了I2S介面、DAC、ADC、Mixer、PA(功放),通常包含多種輸入(Mic、Line-in、I2S、PCM)和多個輸出(耳機、喇叭、聽筒,Line-out),Codec和Platform一樣,是可重用的部件。
Machine 繫結platform driver和codec driver 。
下面我們來對這三個模組進行分析。
2、Platform
從上圖可以看出ASOC中包含了多個platform,它們每種platform對應一個.c程式碼,下面針對這些platform進行分析。
2.1、錄音(capture)
kernel-3.18/sound/soc/mediatek/mt_soc_audio_v3/mt_soc_pcm_capture.c
snd_soc_register_platform() 該函式用於註冊一個snd_soc_platform,只有註冊以後,它才可以被Machine驅動使用。它的程式碼已經清晰地表達了它的實現過程:
為snd_soc_platform例項申請記憶體;
從platform_device中獲得它的名字,用於Machine驅動的匹配工作;
初始化snd_soc_platform的欄位;
把snd_soc_platform例項連線到全域性連結串列platform_list中;
呼叫snd_soc_instantiate_cards,觸發音效卡的machine、platform、codec、dai等的匹配工作;
由上圖可知capture被註冊到mtk_soc_platform結構體中,接下來分析mtk_afe_capture_ops
static struct snd_pcm_ops mtk_afe_capture_ops = {
.open = mtk_capture_pcm_open,
.close = mtk_capture_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = mtk_capture_pcm_hw_params,
.hw_free = mtk_capture_pcm_hw_free,
.prepare = mtk_capture_pcm_prepare,
.trigger = mtk_capture_pcm_trigger,
.pointer = mtk_capture_pcm_pointer,
.copy = mtk_capture_pcm_copy,
.silence = mtk_capture_pcm_silence,
.page = mtk_capture_pcm_page,
};
2.1.1、mtk_capture_pcm_open
static int mtk_capture_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
int ret = 0;
AudDrv_Clk_On();
AudDrv_ADC_Clk_On();//使能模擬時鐘
VUL_Control_context = Get_Mem_ControlT(Soc_Aud_Digital_Block_MEM_VUL);
/* can allocate sram_dbg */
AfeControlSramLock();
#ifndef CAPTURE_FORCE_USE_DRAM
if (GetSramState() == SRAM_STATE_FREE) {
pr_warn("mtk_capture_pcm_open use sram\n");
mtk_capture_hardware.buffer_bytes_max = GetCaptureSramSize();
SetSramState(SRAM_STATE_CAPTURE);
mCaptureUseSram = true;
} else {
pr_warn("mtk_capture_pcm_open use dram\n");
mtk_capture_hardware.buffer_bytes_max = UL1_MAX_BUFFER_SIZE;
mCaptureUseSram = false;
}
#else
pr_warn("mtk_capture_pcm_open use dram\n");
mtk_capture_hardware.buffer_bytes_max = UL1_MAX_BUFFER_SIZE;
#endif
AfeControlSramUnLock();
runtime->hw = mtk_capture_hardware;
memcpy((void *)(&(runtime->hw)), (void *)&mtk_capture_hardware , sizeof(struct snd_pcm_hardware));
ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_sample_rates);
ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0)
pr_warn("snd_pcm_hw_constraint_integer failed\n");
if (ret < 0) {
pr_err("mtk_capture_pcm_close\n");
mtk_capture_pcm_close(substream);
return ret;
}
if (mCaptureUseSram == false)
AudDrv_Emi_Clk_On();
pr_warn("mtk_capture_pcm_open return\n");
return 0;
}
2.1.2、mtk_capture_pcm_trigger
static int mtk_capture_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
pr_warn("mtk_capture_pcm_trigger cmd = %d\n", cmd);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
//喚醒
return mtk_capture_alsa_start(substream);
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
//睡眠
return mtk_capture_alsa_stop(substream);
}
return -EINVAL;
}
static int mtk_capture_alsa_start(struct snd_pcm_substream *substream)
{
pr_warn("mtk_capture_alsa_start\n");
SetMemifSubStream(Soc_Aud_Digital_Block_MEM_VUL, substream);
StartAudioCaptureHardware(substream);
#ifdef DENALI_FPGA_EARLYPORTING /* ccc early porting, copy from TurnOnDacPower() and ADC_LOOP_DAC_Func() */
/* Afe_Set_Reg(AFE_SGEN_CON0, 0x24862862, 0xffffffff); */
/* Ana_Set_Reg(PMIC_AFE_TOP_CON0, 0x0002, 0x0002); //UL from sinetable */
/* Ana_Set_Reg(PMIC_AFE_TOP_CON0, 0x0001, 0x0001); //DL from sinetable */
/* Ana_Set_Reg(AFE_SGEN_CFG0 , 0x0080 , 0xffff); */
/* Ana_Set_Reg(AFE_SGEN_CFG1 , 0x0101 , 0xffff); */
Ana_Get_Reg(AFE_AUDIO_TOP_CON0); /* power on clock */
Ana_Get_Reg(AFUNC_AUD_CON2);
Ana_Get_Reg(AFUNC_AUD_CON0); /* sdm audio fifo clock power on */
Ana_Get_Reg(AFUNC_AUD_CON2); /* sdm power on */
Ana_Get_Reg(AFUNC_AUD_CON2); /* sdm fifo enable */
Ana_Get_Reg(AFE_DL_SDM_CON1); /* set attenuation gain */
Ana_Get_Reg(AFE_UL_DL_CON0); /* [0] afe enable */
Ana_Get_Reg(AFE_PMIC_NEWIF_CFG0); /* 8k sample rate */
Ana_Get_Reg(AFE_DL_SRC2_CON0_H);/* 8k sample rate */
Ana_Get_Reg(AFE_DL_SRC2_CON0_L); /* turn off mute function and turn on dl */
Ana_Get_Reg(PMIC_AFE_TOP_CON0); /* set DL in normal path, not from sine gen table */
Ana_Get_Reg(AFE_SGEN_CFG0); /* set DL in normal path, not from sine gen table */
Ana_Get_Reg(AFE_SGEN_CFG1); /* set DL in normal path, not from sine gen table */
Ana_Get_Reg(TOP_CLKSQ); /* Enable CLKSQ 26MHz */
Ana_Get_Reg(TOP_CLKSQ_SET); /* Turn on 26MHz source clock */
Ana_Get_Reg(AFE_AUDIO_TOP_CON0); /* power on clock */
Ana_Get_Reg(FPGA_CFG1); /* must set in FPGA platform for PMIC digital loopback */
#endif
return 0;
}
2.1.3、snd_pcm_lib_ioctl
通用的PCM ioctl回撥函式
/**
* snd_pcm_lib_ioctl - a generic PCM ioctl callback
* @substream: the pcm substream instance
* @cmd: ioctl command
* @arg: ioctl argument
*
* Processes the generic ioctl commands for PCM.
* Can be passed as the ioctl callback for PCM ops.
*
* Return: Zero if successful, or a negative error code on failure.
*/
int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
unsigned int cmd, void *arg)
{
switch (cmd) {
case SNDRV_PCM_IOCTL1_INFO:
return 0;
case SNDRV_PCM_IOCTL1_RESET:
return snd_pcm_lib_ioctl_reset(substream, arg);
case SNDRV_PCM_IOCTL1_CHANNEL_INFO:
return snd_pcm_lib_ioctl_channel_info(substream, arg);
case SNDRV_PCM_IOCTL1_FIFO_SIZE:
return snd_pcm_lib_ioctl_fifo_size(substream, arg);
}
return -ENXIO;
}
2.2、FM
kernel-3.18/sound/soc/mediatek/mt_soc_audio_v3/mt_soc_pcm_fm_i2s.c
static struct snd_pcm_ops mtk_fm_i2s_ops = {
.open = mtk_pcm_fm_i2s_open,
.close = mtk_pcm_fm_i2s_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = mtk_pcm_fm_i2s_hw_params,
.hw_free = mtk_pcm_fm_i2s_hw_free,
.prepare = mtk_pcm_fm_i2s_prepare,
.trigger = mtk_pcm_fm_i2s_trigger,
.pointer = mtk_pcm_fm_i2s_pointer,
.copy = mtk_pcm_fm_i2s_copy,
.silence = mtk_pcm_fm_i2s_silence,
.page = mtk_fm_i2s_pcm_page,
};
接下來分析mtk_fm_i2s_ops
2.1、mtk_pcm_fm_i2s_open
static int mtk_pcm_fm_i2s_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
int ret = 0;
AudDrv_Clk_On();
AudDrv_I2S_Clk_On();//開啟I2S時鐘
/*
static struct snd_pcm_hardware mtk_fm_i2s_hardware = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_MMAP_VALID),
.formats = SND_SOC_STD_MT_FMTS,
.rates = SOC_HIGH_USE_RATE,
.rate_min = SOC_NORMAL_USE_RATE_MIN,
.rate_max = SOC_NORMAL_USE_RATE_MAX,
.channels_min = SOC_NORMAL_USE_CHANNELS_MIN,
.channels_max = SOC_NORMAL_USE_CHANNELS_MAX,
.buffer_bytes_max = FM_I2S_MAX_BUFFER_SIZE,
.period_bytes_max = FM_I2S_MAX_PERIOD_SIZE,
.periods_min = FM_I2S_MIN_PERIOD_SIZE,
.periods_max = FM_I2S_MAX_PERIOD_SIZE,
.fifo_size = 0,
};
#define SOC_HIGH_USE_RATE (SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000)
#define SOC_HIGH_USE_RATE_MIN 8000
#define SOC_HIGH_USE_RATE_MAX 192000
#define SOC_HIGH_USE_CHANNELS_MIN 1
#define SOC_HIGH_USE_CHANNELS_MAX 8
*/
/*pr_warn("mtk_pcm_fm_i2s_open\n");*/
runtime->hw = mtk_fm_i2s_hardware;
memcpy((void *)(&(runtime->hw)), (void *)&mtk_fm_i2s_hardware ,
sizeof(struct snd_pcm_hardware));
/*
static struct snd_pcm_hw_constraint_list fm_i2s_constraints_sample_rates = {
.count = ARRAY_SIZE(soc_fm_supported_sample_rates),
.list = soc_fm_supported_sample_rates,
.mask = 0,
};
const unsigned int soc_fm_supported_sample_rates[3] = {
32000, 44100, 48000
};
支援的取樣率
*/
ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&fm_i2s_constraints_sample_rates);
ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0)
pr_warn("snd_pcm_hw_constraint_integer failed\n");
if (ret < 0) {
pr_err("mtk_pcm_fm_i2s_close\n");
mtk_pcm_fm_i2s_close(substream);
return ret;
}
2.2、mtk_pcm_fm_i2s_prepare
static int mtk_pcm_fm_i2s_prepare(struct snd_pcm_substream *substream)
{
AudioDigtalI2S m2ndI2SInAttribute;
struct snd_pcm_runtime *runtime = substream->runtime;
pr_warn("%s rate = %d\n", __func__, runtime->rate);
if (mPrepareDone == false) {
/* mtk_wcn_cmb_stub_audio_ctrl((CMB_STUB_AIF_X)CMB_STUB_AIF_3);//temp mark for early porting */
/*
外掛smart pa,FM切到外放播放無聲
1.公版預設的行為,headset和speaker 都是走PMIC這邊輸出,也就是interconnection對應的O03,O04.
2.當外掛Smart PA後,Smart PA連線的I2S為I2S0,I2S3,output 的interconnection 為O00,O01;
3.FM 從headset 切換到speaker 後,headset走的還是PMIC(O03,O04),而speaker 走的是Smart PA,所以FM driver檔案裡面的interconnection 需要增加O00,O01的設定
4.如果還有其他應用場景,同樣會出現切換smart PA後,沒有聲音,請首先確認interconnection是否有正確的設定,具體的修改是根據應用場景走的是哪一隻driver 檔案,在對應的driver 檔案裡面prepare函式新增O00,O01的interconnection。
在mt_soc_pcm_dl1_i2s0Dl1.c的start函式中新增O00,O01的interconnection後,fm切換speaker可以使用了
我們公版預設的行為,,FM 從headset 切到speaker 後,把headset 關閉
只讓speaker 輸出,如果貴司想讓一起輸出,找到關閉headset地方開啟即可
*/
/* interconnection setting */
SetConnection(Soc_Aud_InterCon_Connection, Soc_Aud_InterConnectionInput_I00,
Soc_Aud_InterConnectionOutput_O13);
SetConnection(Soc_Aud_InterCon_Connection, Soc_Aud_InterConnectionInput_I01,
Soc_Aud_InterConnectionOutput_O14);
SetConnection(Soc_Aud_InterCon_Connection, Soc_Aud_InterConnectionInput_I10,
Soc_Aud_InterConnectionOutput_O03);
SetConnection(Soc_Aud_InterCon_Connection, Soc_Aud_InterConnectionInput_I11,
Soc_Aud_InterConnectionOutput_O04);
/* Set HW_GAIN */
SetHwDigitalGainMode(Soc_Aud_Hw_Digital_Gain_HW_DIGITAL_GAIN1, runtime->rate,
0x40);
SetHwDigitalGainEnable(Soc_Aud_Hw_Digital_Gain_HW_DIGITAL_GAIN1, true);
SetHwDigitalGain(mfm_i2s_Volume, Soc_Aud_Hw_Digital_Gain_HW_DIGITAL_GAIN1);
/* start I2S DAC out */
if (GetMemoryPathEnable(Soc_Aud_Digital_Block_I2S_OUT_DAC) == false) {
SetI2SDacOut(runtime->rate, false, Soc_Aud_I2S_WLEN_WLEN_16BITS);
SetMemoryPathEnable(Soc_Aud_Digital_Block_I2S_OUT_DAC, true);
SetI2SDacEnable(true);
} else
SetMemoryPathEnable(Soc_Aud_Digital_Block_I2S_OUT_DAC, true);
if (GetMemoryPathEnable(Soc_Aud_Digital_Block_I2S_IN_2) == false) {
/* set merge interface */
SetMemoryPathEnable(Soc_Aud_Digital_Block_I2S_IN_2, true);
/* Config 2nd I2S IN */
memset_io((void *)&m2ndI2SInAttribute, 0, sizeof(m2ndI2SInAttribute));
m2ndI2SInAttribute.mLR_SWAP = Soc_Aud_LR_SWAP_NO_SWAP;
m2ndI2SInAttribute.mI2S_IN_PAD_SEL = false; /* I2S_IN_FROM_CONNSYS */
m2ndI2SInAttribute.mI2S_SLAVE = Soc_Aud_I2S_SRC_SLAVE_MODE;
m2ndI2SInAttribute.mI2S_SAMPLERATE = 32000;
m2ndI2SInAttribute.mINV_LRCK = Soc_Aud_INV_LRCK_NO_INVERSE;
m2ndI2SInAttribute.mI2S_FMT = Soc_Aud_I2S_FORMAT_I2S;
m2ndI2SInAttribute.mI2S_WLEN = Soc_Aud_I2S_WLEN_WLEN_16BITS;
Set2ndI2SIn(&m2ndI2SInAttribute);
if (runtime->rate == 48000)
SetI2SASRCConfig(true, 48000); /* Covert from 32000 Hz to 48000 Hz */
else
SetI2SASRCConfig(true, 44100); /* Covert from 32000 Hz to 44100 Hz */
SetI2SASRCEnable(true);
Set2ndI2SInEnable(true);
} else
SetMemoryPathEnable(Soc_Aud_Digital_Block_I2S_IN_2, true);
EnableAfe(true);
if (GetMemoryPathEnable(Soc_Aud_Digital_Block_I2S_OUT_DAC) == true)
SetI2SADDAEnable(true);
mPrepareDone = true;
}
return 0;
}
2.3、mtk_pcm_fm_i2s_close
static int mtk_pcm_fm_i2s_close(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
pr_warn("%s rate = %d\n", __func__, runtime->rate);
/* mtk_wcn_cmb_stub_audio_ctrl((CMB_STUB_AIF_X)CMB_STUB_AIF_0);//temp mark for early porting */
SetMemoryPathEnable(Soc_Aud_Digital_Block_I2S_IN_2, false);
if (GetMemoryPathEnable(Soc_Aud_Digital_Block_I2S_IN_2) == false) {
SetI2SASRCEnable(false);
SetI2SASRCConfig(false, 0); /* Setting to bypass ASRC */
Set2ndI2SInEnable(false);
}
SetMemoryPathEnable(Soc_Aud_Digital_Block_I2S_OUT_DAC, false);
if (GetI2SDacEnable() == false) {
SetI2SADDAEnable(false);
SetI2SDacEnable(false);
}
/* interconnection setting */
SetConnection(Soc_Aud_InterCon_DisConnect, Soc_Aud_InterConnectionInput_I00,
Soc_Aud_InterConnectionOutput_O13);
SetConnection(Soc_Aud_InterCon_DisConnect, Soc_Aud_InterConnectionInput_I01,
Soc_Aud_InterConnectionOutput_O14);
SetConnection(Soc_Aud_InterCon_DisConnect, Soc_Aud_InterConnectionInput_I10,
Soc_Aud_InterConnectionOutput_O03);
SetConnection(Soc_Aud_InterCon_DisConnect, Soc_Aud_InterConnectionInput_I11,
Soc_Aud_InterConnectionOutput_O04);
EnableAfe(false);
AudDrv_I2S_Clk_Off();
AudDrv_Clk_Off();
mPrepareDone = false;
SetFMEnableFlag(false);
return 0;
}
2.3、mtk_pcm_fm_i2s_close
static int mtk_pcm_fm_i2s_close(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
pr_warn("%s rate = %d\n", __func__, runtime->rate);
/* mtk_wcn_cmb_stub_audio_ctrl((CMB_STUB_AIF_X)CMB_STUB_AIF_0);//temp mark for early porting */
SetMemoryPathEnable(Soc_Aud_Digital_Block_I2S_IN_2, false);
if (GetMemoryPathEnable(Soc_Aud_Digital_Block_I2S_IN_2) == false) {
SetI2SASRCEnable(false);
SetI2SASRCConfig(false, 0); /* Setting to bypass ASRC */
Set2ndI2SInEnable(false);
}
SetMemoryPathEnable(Soc_Aud_Digital_Block_I2S_OUT_DAC, false);
if (GetI2SDacEnable() == false) {
SetI2SADDAEnable(false);
SetI2SDacEnable(false);
}
/* interconnection setting */
SetConnection(Soc_Aud_InterCon_DisConnect, Soc_Aud_InterConnectionInput_I00,
Soc_Aud_InterConnectionOutput_O13);
SetConnection(Soc_Aud_InterCon_DisConnect, Soc_Aud_InterConnectionInput_I01,
Soc_Aud_InterConnectionOutput_O14);
SetConnection(Soc_Aud_InterCon_DisConnect, Soc_Aud_InterConnectionInput_I10,
Soc_Aud_InterConnectionOutput_O03);
SetConnection(Soc_Aud_InterCon_DisConnect, Soc_Aud_InterConnectionInput_I11,
Soc_Aud_InterConnectionOutput_O04);
EnableAfe(false);
AudDrv_I2S_Clk_Off();
AudDrv_Clk_Off();
mPrepareDone = false;
SetFMEnableFlag(false);
return 0;
}
Asoc 還有很多platform,和上面註冊方式都一致,只是在ops方面不同,在此就不一一分析了。
3、Platform Dai
kernel-3.18/sound/soc/mediatek/mt_soc_audio_v3/mt_soc_dai_stub.c
snd_soc_register_component(&pdev->dev, &mt_dai_component,
mtk_dai_stub_dai, ARRAY_SIZE(mtk_dai_stub_dai));
int snd_soc_register_component(struct device *dev,
const struct snd_soc_component_driver *cmpnt_drv,
struct snd_soc_dai_driver *dai_drv,
int num_dai)
{
...
cmpnt->ignore_pmdown_time = true;
cmpnt->registered_as_component = true;
ret = snd_soc_register_dais(cmpnt, dai_drv, num_dai, true);
...
snd_soc_component_add(cmpnt);
return 0;
}
static int snd_soc_register_dais(struct snd_soc_component *component,
struct snd_soc_dai_driver *dai_drv, size_t count,
bool legacy_dai_naming)
{
...
for (i = 0; i < count; i++) {
if (count == 1 && legacy_dai_naming) {
dai->name = fmt_single_name(dev, &dai->id);
} else {
dai->name = fmt_multiple_name(dev, &dai_drv[i]);
if (dai_drv[i].id)
dai->id = dai_drv[i].id;
else
dai->id = i;
}
}
dai->component = component;
dai->dev = dev;
dai->driver = &dai_drv[i]; //dai->driver = &dai_drv[i] = mtk_dai_stub_dai
list_add(&dai->list, &component->dai_list);//list_add(&cmpnt->list, &component_list)
}
...
return 0;
}
Platform Dai 通過snd_soc_register_component進行註冊,將陣列mtk_dai_stub_dai[]傳入,再通過snd_soc_register_dais將所有的PCM(platform)(如播放、錄音、通話等)迴圈加入dai list裡面。
下面看下mtk_dai_stub_dai陣列。
static struct snd_soc_dai_driver mtk_dai_stub_dai[] = {
{
.playback = {
.stream_name = MT_SOC_DL1_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 192000,
},
.name = MT_SOC_DL1DAI_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.capture = {
.stream_name = MT_SOC_UL1_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 192000,
},
.name = MT_SOC_UL1DAI_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.capture = {
.stream_name = MT_SOC_TDM_CAPTURE_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
.rate_max = 48000,
},
.name = MT_SOC_TDMRX_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.playback = {
.stream_name = MT_SOC_HDMI_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
.rate_max = 192000,
},
.capture = {
.stream_name = MT_SOC_HDMI_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
.rate_max = 192000,
},
.name = MT_SOC_HDMI_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.playback = {
.stream_name = MT_SOC_VOICE_MD1_BT_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 32000,
},
.name = MT_SOC_VOICE_MD1_BT_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.playback = {
.stream_name = MT_SOC_VOICE_MD2_BT_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 32000,
},
.name = MT_SOC_VOICE_MD2_BT_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.playback = {
.stream_name = MT_SOC_VOIP_BT_OUT_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 48000,
},
.name = MT_SOC_VOIP_CALL_BT_OUT_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.capture = {
.stream_name = MT_SOC_VOIP_BT_IN_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 48000,
},
.name = MT_SOC_VOIP_CALL_BT_IN_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.playback = {
.stream_name = MT_SOC_FM_I2S2_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000 ,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 48000,
},
.name = "FM_I2S2_OUT",
.ops = &mtk_dai_stub_ops,
},
{
.capture = {
.stream_name = MT_SOC_FM_I2S2_RECORD_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 48000,
},
.name = "FM_I2S2_IN",
.ops = &mtk_dai_stub_ops,
},
{
.playback = {
.stream_name = MT_SOC_VOICE_MD1_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SND_SOC_STD_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 32000,
},
.capture = {
.stream_name = MT_SOC_VOICE_MD1_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SND_SOC_STD_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 32000,
},
.name = MT_SOC_VOICE_MD1_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.playback = {
.stream_name = MT_SOC_VOICE_MD2_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SND_SOC_STD_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 32000,
},
.capture = {
.stream_name = MT_SOC_VOICE_MD2_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SND_SOC_STD_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 32000,
},
.name = MT_SOC_VOICE_MD2_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.playback = {
.stream_name = MT_SOC_ULDLLOOPBACK_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 48000,
},
.capture = {
.stream_name = MT_SOC_ULDLLOOPBACK_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 48000,
},
.name = MT_SOC_ULDLLOOPBACK_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.playback = {
.stream_name = MT_SOC_I2S0_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 192000,
},
.capture = {
.stream_name = MT_SOC_I2S0_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 192000,
},
.name = MT_SOC_I2S0_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.playback = {
.stream_name = MT_SOC_I2SDL1_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 192000,
},
.name = MT_SOC_I2S0DL1_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.capture = {
.stream_name = MT_SOC_DL1_AWB_RECORD_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 48000,
},
.name = MT_SOC_DL1AWB_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.playback = {
.stream_name = MT_SOC_MRGRX_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 48000,
},
.capture = {
.stream_name = MT_SOC_MRGRX_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 48000,
},
.name = MT_SOC_MRGRX_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.playback = {
.stream_name = MT_SOC_MRGRX_CAPTURE_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 48000,
},
.capture = {
.stream_name = MT_SOC_MRGRX_CAPTURE_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 48000,
},
.name = MT_SOC_MRGRXCAPTURE_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.playback = {
.stream_name = MT_SOC_FM_MRGTX_STREAM_NAME,
.rates = SNDRV_PCM_RATE_44100,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 44100,
.rate_max = 44100,
},
.name = MT_SOC_FM_MRGTX_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.capture = {
.stream_name = MT_SOC_UL1DATA2_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 48000,
},
.name = MT_SOC_UL2DAI_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.capture = {
.stream_name = MT_SOC_I2S0AWB_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 48000,
},
.name = MT_SOC_I2S0AWBDAI_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.capture = {
.stream_name = MT_SOC_MODADCI2S_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 48000,
},
.name = MT_SOC_MODADCI2SDAI_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.capture = {
.stream_name = MT_SOC_ADC2AWB_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 192000,
},
.name = MT_SOC_ADC2AWBDAI_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.capture = {
.stream_name = MT_SOC_IO2DAI_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 48000,
},
.name = MT_SOC_IO2DAIDAI_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.playback = {
.stream_name = MT_SOC_HP_IMPEDANCE_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
.rate_max = 48000,
},
.name = MT_SOC_HP_IMPEDANCE_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.playback = {
.stream_name = MT_SOC_FM_I2S_PLAYBACK_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 48000,
},
.capture = {
.stream_name = MT_SOC_FM_I2S_PLAYBACK_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 48000,
},
.name = MT_SOC_FM_I2S_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.playback = {
.stream_name = MT_SOC_FM_I2S_CAPTURE_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 48000,
},
.capture = {
.stream_name = MT_SOC_FM_I2S_CAPTURE_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 48000,
},
.name = MT_SOC_FM_I2S_CAPTURE_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.playback = {
.stream_name = MT_SOC_OFFLOAD_GDMA_STREAM_NAME,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SND_SOC_ADV_MT_FMTS,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 48000,
},
.compress_dai = 1,
.name = MT_SOC_OFFLOAD_GDMA_NAME,
.ops = &mtk_dai_stub_ops,
},
{
.playback = {