// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2019 MediaTek Inc. * Author: Michael Hsiao */ /******************************************************************************* * * Filename: * --------- * mt_soc_machine.c * * Project: * -------- * Audio soc machine driver * * Description: * ------------ * Audio machine driver * * Author: * ------- * Chipeng Chang * *------------------------------------------------------------------------------ * ****************************************************************************** */ /***************************************************************************** * C O M P I L E R F L A G S *****************************************************************************/ /***************************************************************************** * E X T E R N A L R E F E R E N C E S *****************************************************************************/ #include "mtk-auddrv-afe.h" #include "mtk-auddrv-ana.h" #include "mtk-auddrv-clk.h" #include "mtk-auddrv-common.h" #include "mtk-auddrv-def.h" #include "mtk-auddrv-kernel.h" #include "mtk-soc-afe-control.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mtk-soc-codec-63xx.h" #include #include #include #include #include #include #include #include #include #include "mtk-soc-speaker-amp.h" #if defined(CONFIG_SND_SOC_CS43130) #include "mtk-cs43130-machine-ops.h" #endif #if defined(CONFIG_SND_SOC_CS35L35) #include "mtk-cs35l35-machine-ops.h" #endif #ifdef CONFIG_DEBUG_FS #include static struct dentry *mt_sco_audio_debugfs; #define DEBUG_FS_NAME "mtksocaudio" #define DEBUG_ANA_FS_NAME "mtksocanaaudio" static int mt_soc_ana_debug_open(struct inode *inode, struct file *file) { return 0; } static ssize_t mt_soc_ana_debug_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { const int size = 8192; /* char buffer[size]; */ char *buffer = NULL; /* for reduce kernel stack */ int n = 0; int ret = 0; buffer = kmalloc(size, GFP_KERNEL); if (!buffer) { kfree(buffer); return -ENOMEM; } AudDrv_Clk_On(); audckbufEnable(true); n = Ana_Debug_Read(buffer, size); audckbufEnable(false); AudDrv_Clk_Off(); ret = simple_read_from_buffer(buf, count, pos, buffer, n); kfree(buffer); return ret; } static int mt_soc_debug_open(struct inode *inode, struct file *file) { return 0; } static ssize_t mt_soc_debug_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { const int size = 12288; /* char buffer[size]; */ char *buffer = NULL; /* for reduce kernel stack */ int n = 0; int ret = 0; buffer = kmalloc(size, GFP_KERNEL); if (!buffer) { kfree(buffer); return -ENOMEM; } AudDrv_Clk_On(); n = AudDrv_Reg_Dump(buffer, size); AudDrv_Clk_Off(); ret = simple_read_from_buffer(buf, count, pos, buffer, n); kfree(buffer); return ret; } static char const ParSetkeyAfe[] = "Setafereg"; static char const ParSetkeyAna[] = "Setanareg"; static char const PareGetkeyAfe[] = "Getafereg"; static char const PareGetkeyAna[] = "Getanareg"; static ssize_t mt_soc_debug_write(struct file *f, const char __user *buf, size_t count, loff_t *offset) { #define MAX_DEBUG_WRITE_INPUT 256 int ret = 0; char InputBuf[MAX_DEBUG_WRITE_INPUT]; char *token1 = NULL; char *token2 = NULL; char *token3 = NULL; char *token4 = NULL; char *token5 = NULL; char *temp = NULL; char *str_begin = NULL; unsigned long regaddr = 0; unsigned long regvalue = 0; char delim[] = " ,"; if (!count) { pr_debug("%s(), count is 0, return directly\n", __func__); goto exit; } if (count > MAX_DEBUG_WRITE_INPUT) count = MAX_DEBUG_WRITE_INPUT; memset_io((void *)InputBuf, 0, MAX_DEBUG_WRITE_INPUT); if (copy_from_user((InputBuf), buf, count)) { pr_debug("%s(), copy_from_user fail, count = %zu\n", __func__, count); goto exit; } str_begin = kstrndup(InputBuf, MAX_DEBUG_WRITE_INPUT - 1, GFP_KERNEL); if (!str_begin) { pr_warn("%s(), kstrdup fail\n", __func__); goto exit; } temp = str_begin; pr_debug( "copy_from_user count = %zu, temp = %s, pointer = %p\n", count, str_begin, str_begin); token1 = strsep(&temp, delim); token2 = strsep(&temp, delim); token3 = strsep(&temp, delim); token4 = strsep(&temp, delim); token5 = strsep(&temp, delim); pr_debug("token1 = %s token2 = %s token3 = %s token4 = %s token5 = %s\n", token1, token2, token3, token4, token5); AudDrv_Clk_On(); if (strcmp(token1, ParSetkeyAfe) == 0) { if ((token3 != NULL) && (token5 != NULL)) { ret = kstrtoul(token3, 16, ®addr); ret = kstrtoul(token5, 16, ®value); pr_debug("%s, regaddr = 0x%x, regvalue = 0x%x\n", ParSetkeyAfe, (unsigned int)regaddr, (unsigned int)regvalue); Afe_Set_Reg(regaddr, regvalue, 0xffffffff); regvalue = Afe_Get_Reg(regaddr); pr_debug("%s, regaddr = 0x%x, regvalue = 0x%x\n", ParSetkeyAfe, (unsigned int)regaddr, (unsigned int)regvalue); } else { pr_debug("token3 or token5 is NULL!\n"); } } if (strcmp(token1, ParSetkeyAna) == 0) { if ((token3 != NULL) && (token5 != NULL)) { ret = kstrtoul(token3, 16, ®addr); ret = kstrtoul(token5, 16, ®value); pr_debug("%s, regaddr = 0x%x, regvalue = 0x%x\n", ParSetkeyAna, (unsigned int)regaddr, (unsigned int)regvalue); audckbufEnable(true); Ana_Set_Reg(regaddr, regvalue, 0xffffffff); regvalue = Ana_Get_Reg(regaddr); audckbufEnable(false); pr_debug("%s, regaddr = 0x%x, regvalue = 0x%x\n", ParSetkeyAna, (unsigned int)regaddr, (unsigned int)regvalue); } else { pr_debug("token3 or token5 is NULL!\n"); } } if (strcmp(token1, PareGetkeyAfe) == 0) { if (token3 != NULL) { ret = kstrtoul(token3, 16, ®addr); regvalue = Afe_Get_Reg(regaddr); pr_debug("%s, regaddr = 0x%x, regvalue = 0x%x\n", PareGetkeyAfe, (unsigned int)regaddr, (unsigned int)regvalue); } else { pr_debug("token3 is NULL!\n"); } } if (strcmp(token1, PareGetkeyAna) == 0) { if (token3 != NULL) { ret = kstrtoul(token3, 16, ®addr); regvalue = Ana_Get_Reg(regaddr); pr_debug("%s, regaddr = 0x%x, regvalue = 0x%x\n", PareGetkeyAna, (unsigned int)regaddr, (unsigned int)regvalue); } else { pr_debug("token3 is NULL!\n"); } } AudDrv_Clk_Off(); kfree(str_begin); exit: return count; } static const struct file_operations mtaudio_debug_ops = { .open = mt_soc_debug_open, .read = mt_soc_debug_read, .write = mt_soc_debug_write, }; static const struct file_operations mtaudio_ana_debug_ops = { .open = mt_soc_ana_debug_open, .read = mt_soc_ana_debug_read, }; #endif /* snd_soc_ops */ static int mt_machine_trigger(struct snd_pcm_substream *substream, int cmd) { switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: EnableAfe(true); return 0; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: EnableAfe(false); return 0; } return -EINVAL; } static struct snd_soc_ops mt_machine_audio_ops = { .trigger = mt_machine_trigger, }; /* Digital audio interface glue - connects codec <---> CPU */ static struct snd_soc_dai_link mt_soc_dai_common[] = { /* FrontEnd DAI Links */ { .name = "MultiMedia1", .stream_name = MT_SOC_DL1_STREAM_NAME, .cpu_dai_name = MT_SOC_DL1DAI_NAME, .platform_name = MT_SOC_DL1_PCM, .codec_dai_name = MT_SOC_CODEC_TXDAI_NAME, .codec_name = MT_SOC_CODEC_NAME, }, { .name = "MultiMedia2", .stream_name = MT_SOC_UL1_STREAM_NAME, .cpu_dai_name = MT_SOC_UL1DAI_NAME, .platform_name = MT_SOC_UL1_PCM, .codec_dai_name = MT_SOC_CODEC_RXDAI_NAME, .codec_name = MT_SOC_CODEC_NAME, }, { .name = "Voice_MD1", .stream_name = MT_SOC_VOICE_MD1_STREAM_NAME, .cpu_dai_name = MT_SOC_VOICE_MD1_NAME, .platform_name = MT_SOC_VOICE_MD1, .codec_dai_name = MT_SOC_CODEC_VOICE_MD1DAI_NAME, .codec_name = MT_SOC_CODEC_NAME, }, #ifdef CONFIG_MTK_HDMI_TDM { .name = "HDMI_OUT", .stream_name = MT_SOC_HDMI_STREAM_NAME, .cpu_dai_name = MT_SOC_HDMI_NAME, .platform_name = MT_SOC_HDMI_PCM, .codec_dai_name = MT_SOC_CODEC_HDMI_DUMMY_DAI_NAME, .codec_name = MT_SOC_CODEC_DUMMY_NAME, }, #endif { .name = "ULDLOOPBACK", .stream_name = MT_SOC_ULDLLOOPBACK_STREAM_NAME, .cpu_dai_name = MT_SOC_ULDLLOOPBACK_NAME, .platform_name = MT_SOC_ULDLLOOPBACK_PCM, .codec_dai_name = MT_SOC_CODEC_ULDLLOOPBACK_NAME, .codec_name = MT_SOC_CODEC_NAME, }, { .name = "I2S0OUTPUT", .stream_name = MT_SOC_I2S0_STREAM_NAME, .cpu_dai_name = MT_SOC_I2S0_NAME, .platform_name = MT_SOC_I2S0_PCM, .codec_dai_name = MT_SOC_CODEC_I2S0_DUMMY_DAI_NAME, .codec_name = MT_SOC_CODEC_DUMMY_NAME, }, { .name = "MRGRX", .stream_name = MT_SOC_MRGRX_STREAM_NAME, .cpu_dai_name = MT_SOC_MRGRX_NAME, .platform_name = MT_SOC_MRGRX_PCM, .codec_dai_name = MT_SOC_CODEC_MRGRX_DAI_NAME, .codec_name = MT_SOC_CODEC_NAME, }, { .name = "MRGRXCAPTURE", .stream_name = MT_SOC_MRGRX_CAPTURE_STREAM_NAME, .cpu_dai_name = MT_SOC_MRGRX_NAME, .platform_name = MT_SOC_MRGRX_AWB_PCM, .codec_dai_name = MT_SOC_CODEC_MRGRX_DUMMY_DAI_NAME, .codec_name = MT_SOC_CODEC_DUMMY_NAME, }, { .name = "I2S0DL1OUTPUT", .stream_name = MT_SOC_I2SDL1_STREAM_NAME, .cpu_dai_name = MT_SOC_I2S0DL1_NAME, .platform_name = MT_SOC_I2S0DL1_PCM, .codec_dai_name = MT_SOC_CODEC_I2S0TXDAI_NAME, .codec_name = MT_SOC_CODEC_NAME, }, { .name = "DEEP_BUFFER_DL_OUTPUT", .stream_name = MT_SOC_DEEP_BUFFER_DL_STREAM_NAME, .cpu_dai_name = "snd-soc-dummy-dai", .platform_name = MT_SOC_DEEP_BUFFER_DL_PCM, .codec_dai_name = MT_SOC_CODEC_DEEPBUFFER_TX_DAI_NAME, .codec_name = MT_SOC_CODEC_NAME, }, { .name = "DL1AWBCAPTURE", .stream_name = MT_SOC_DL1_AWB_RECORD_STREAM_NAME, .cpu_dai_name = MT_SOC_DL1AWB_NAME, .platform_name = MT_SOC_DL1_AWB_PCM, .codec_dai_name = MT_SOC_CODEC_DL1AWBDAI_NAME, .codec_name = MT_SOC_CODEC_DUMMY_NAME, }, { .name = "Voice_MD1_BT", .stream_name = MT_SOC_VOICE_MD1_BT_STREAM_NAME, .cpu_dai_name = MT_SOC_VOICE_MD1_BT_NAME, .platform_name = MT_SOC_VOICE_MD1_BT, .codec_dai_name = MT_SOC_CODEC_VOICE_MD1_BTDAI_NAME, .codec_name = MT_SOC_CODEC_DUMMY_NAME, }, { .name = "VOIP_CALL_BT_PLAYBACK", .stream_name = MT_SOC_VOIP_BT_OUT_STREAM_NAME, .cpu_dai_name = MT_SOC_VOIP_CALL_BT_OUT_NAME, .platform_name = MT_SOC_VOIP_BT_OUT, .codec_dai_name = MT_SOC_CODEC_VOIPCALLBTOUTDAI_NAME, .codec_name = MT_SOC_CODEC_DUMMY_NAME, }, { .name = "VOIP_CALL_BT_CAPTURE", .stream_name = MT_SOC_VOIP_BT_IN_STREAM_NAME, .cpu_dai_name = MT_SOC_VOIP_CALL_BT_IN_NAME, .platform_name = MT_SOC_VOIP_BT_IN, .codec_dai_name = MT_SOC_CODEC_VOIPCALLBTINDAI_NAME, .codec_name = MT_SOC_CODEC_DUMMY_NAME, }, { .name = "TDM_Debug_CAPTURE", .stream_name = MT_SOC_TDM_CAPTURE_STREAM_NAME, .cpu_dai_name = MT_SOC_TDMRX_NAME, .platform_name = MT_SOC_TDMRX_PCM, .codec_dai_name = MT_SOC_CODEC_TDMRX_DAI_NAME, .codec_name = MT_SOC_CODEC_DUMMY_NAME, }, { .name = "FM_MRG_TX", .stream_name = MT_SOC_FM_MRGTX_STREAM_NAME, .cpu_dai_name = MT_SOC_FM_MRGTX_NAME, .platform_name = MT_SOC_FM_MRGTX_PCM, .codec_dai_name = MT_SOC_CODEC_FMMRGTXDAI_DUMMY_DAI_NAME, .codec_name = MT_SOC_CODEC_DUMMY_NAME, }, { .name = "MultiMedia3", .stream_name = MT_SOC_UL1DATA2_STREAM_NAME, .cpu_dai_name = MT_SOC_UL2DAI_NAME, .platform_name = MT_SOC_UL2_PCM, .codec_dai_name = MT_SOC_CODEC_RXDAI2_NAME, .codec_name = MT_SOC_CODEC_NAME, }, { .name = "I2S0_AWB_CAPTURE", .stream_name = MT_SOC_I2S0AWB_STREAM_NAME, .cpu_dai_name = MT_SOC_I2S0AWBDAI_NAME, .platform_name = MT_SOC_I2S0_AWB_PCM, .codec_dai_name = MT_SOC_CODEC_I2S0AWB_NAME, .codec_name = MT_SOC_CODEC_DUMMY_NAME, }, { .name = "Voice_MD2", .stream_name = MT_SOC_VOICE_MD2_STREAM_NAME, .cpu_dai_name = MT_SOC_VOICE_MD2_NAME, .platform_name = MT_SOC_VOICE_MD2, .codec_dai_name = MT_SOC_CODEC_VOICE_MD2DAI_NAME, .codec_name = MT_SOC_CODEC_NAME, }, { .name = "PLATOFRM_CONTROL", .stream_name = MT_SOC_ROUTING_STREAM_NAME, .cpu_dai_name = "snd-soc-dummy-dai", .platform_name = MT_SOC_ROUTING_PCM, .codec_dai_name = MT_SOC_CODEC_DUMMY_DAI_NAME, .codec_name = MT_SOC_CODEC_DUMMY_NAME, }, { .name = "Voice_MD2_BT", .stream_name = MT_SOC_VOICE_MD2_BT_STREAM_NAME, .cpu_dai_name = MT_SOC_VOICE_MD2_BT_NAME, .platform_name = MT_SOC_VOICE_MD2_BT, .codec_dai_name = MT_SOC_CODEC_VOICE_MD2_BTDAI_NAME, .codec_name = MT_SOC_CODEC_DUMMY_NAME, }, { .name = "HP_IMPEDANCE", .stream_name = MT_SOC_HP_IMPEDANCE_STREAM_NAME, .cpu_dai_name = MT_SOC_HP_IMPEDANCE_NAME, .platform_name = MT_SOC_HP_IMPEDANCE_PCM, .codec_dai_name = MT_SOC_CODEC_HP_IMPEDANCE_NAME, .codec_name = MT_SOC_CODEC_NAME, }, { .name = "FM_I2S_RX_Playback", .stream_name = MT_SOC_FM_I2S_PLAYBACK_STREAM_NAME, .cpu_dai_name = MT_SOC_FM_I2S_NAME, .platform_name = MT_SOC_FM_I2S_PCM, .codec_dai_name = MT_SOC_CODEC_FM_I2S_DAI_NAME, .codec_name = MT_SOC_CODEC_NAME, }, { .name = "FM_I2S_RX_Capture", .stream_name = MT_SOC_FM_I2S_CAPTURE_STREAM_NAME, .cpu_dai_name = MT_SOC_FM_I2S_NAME, .platform_name = MT_SOC_FM_I2S_AWB_PCM, .codec_dai_name = MT_SOC_CODEC_FM_I2S_DUMMY_DAI_NAME, .codec_name = MT_SOC_CODEC_DUMMY_NAME, }, { .name = "MultiMedia_DL2", .stream_name = MT_SOC_DL2_STREAM_NAME, .cpu_dai_name = MT_SOC_DL2DAI_NAME, .platform_name = MT_SOC_DL2_PCM, .codec_dai_name = MT_SOC_CODEC_TXDAI2_NAME, .codec_name = MT_SOC_CODEC_NAME, }, { .name = "MultiMedia_DL3", .stream_name = MT_SOC_DL3_STREAM_NAME, .cpu_dai_name = "snd-soc-dummy-dai", .platform_name = "snd-soc-dummy", .codec_dai_name = MT_SOC_CODEC_OFFLOAD_NAME, .codec_name = MT_SOC_CODEC_NAME, }, #ifdef _NON_COMMON_FEATURE_READY { .name = "MOD_DAI_CAPTURE", .stream_name = MT_SOC_MODDAI_STREAM_NAME, .cpu_dai_name = MT_SOC_MOD_DAI_NAME, .platform_name = MT_SOC_MOD_DAI_PCM, .codec_dai_name = MT_SOC_CODEC_MOD_DAI_NAME, .codec_name = MT_SOC_CODEC_DUMMY_NAME, }, #endif #ifdef CONFIG_SND_SOC_MTK_AUDIO_DSP { .name = "OFFLOAD", .stream_name = MT_SOC_OFFLOAD_STREAM_NAME, .cpu_dai_name = MT_SOC_OFFLOAD_PLAYBACK_DAI_NAME, .platform_name = MT_SOC_PLAYBACK_OFFLOAD, .codec_dai_name = MT_SOC_CODEC_OFFLOAD_NAME, .codec_name = MT_SOC_CODEC_NAME, }, #endif #ifdef _NON_COMMON_FEATURE_READY { .name = "PCM_ANC", .stream_name = MT_SOC_ANC_STREAM_NAME, .cpu_dai_name = MT_SOC_ANC_NAME, .platform_name = MT_SOC_ANC_PCM, .codec_dai_name = MT_SOC_CODEC_ANC_NAME, .codec_name = MT_SOC_CODEC_NAME, }, #endif { .name = "ANC_RECORD", .stream_name = MT_SOC_ANC_RECORD_STREAM_NAME, .cpu_dai_name = MT_SOC_ANC_RECORD_DAI_NAME, .platform_name = MT_SOC_I2S2_ADC2_PCM, .codec_dai_name = MT_SOC_CODEC_DUMMY_DAI_NAME, .codec_name = MT_SOC_CODEC_DUMMY_NAME, .ops = &mt_machine_audio_ops, }, #ifdef _NON_COMMON_FEATURE_READY { .name = "Voice_Ultrasound", .stream_name = MT_SOC_VOICE_ULTRA_STREAM_NAME, .cpu_dai_name = "snd-soc-dummy-dai", .platform_name = MT_SOC_VOICE_ULTRA, .codec_dai_name = MT_SOC_CODEC_VOICE_ULTRADAI_NAME, .codec_name = MT_SOC_CODEC_NAME, }, #endif { .name = "Voice_USB", .stream_name = MT_SOC_VOICE_USB_STREAM_NAME, .cpu_dai_name = "snd-soc-dummy-dai", .platform_name = MT_SOC_VOICE_USB, .codec_dai_name = MT_SOC_CODEC_VOICE_USBDAI_NAME, .codec_name = MT_SOC_CODEC_NAME, }, { .name = "Voice_USB_ECHOREF", .stream_name = MT_SOC_VOICE_USB_ECHOREF_STREAM_NAME, .cpu_dai_name = "snd-soc-dummy-dai", .platform_name = MT_SOC_VOICE_USB_ECHOREF, .codec_dai_name = MT_SOC_CODEC_VOICE_USB_ECHOREF_DAI_NAME, .codec_name = MT_SOC_CODEC_NAME, .playback_only = true, }, #ifdef CONFIG_MTK_AUDIO_SCP_SPKPROTECT_SUPPORT { .name = "DL1SCPSPKOUTPUT", .stream_name = MT_SOC_DL1SCPSPK_STREAM_NAME, .cpu_dai_name = MT_SOC_DL1SCPSPK_NAME, .platform_name = MT_SOC_DL1SCPSPK_PCM, .codec_dai_name = MT_SOC_CODEC_SPKSCPTXDAI_NAME, .codec_name = MT_SOC_CODEC_NAME, }, { .name = "VOICE_SCP", .stream_name = MT_SOC_SCPVOICE_STREAM_NAME, .cpu_dai_name = MT_SOC_SCPVOICE_NAME, .platform_name = MT_SOC_SCP_VOICE_PCM, .codec_dai_name = "snd-soc-dummy-dai", .codec_name = "snd-soc-dummy", }, #endif }; #ifdef CONFIG_SND_SOC_MTK_BTCVSD static struct snd_soc_dai_link mt_soc_btcvsd_dai[] = { { .name = "BTCVSD", .stream_name = "BTCVSD", .cpu_dai_name = MT_SOC_BTCVSD_DAI_NAME, .codec_dai_name = MT_SOC_CODEC_BTCVSD_DAI_NAME, .codec_name = MT_SOC_CODEC_DUMMY_NAME, }, }; #endif static struct snd_soc_dai_link mt_soc_exthp_dai[] = { { .name = "ext_Headphone_Multimedia", .stream_name = MT_SOC_HEADPHONE_STREAM_NAME, .cpu_dai_name = "snd-soc-dummy-dai", .platform_name = "snd-soc-dummy", #ifdef CONFIG_SND_SOC_CS43130 .codec_dai_name = "cs43130-hifi", .codec_name = "cs43130.2-0030", .ignore_suspend = 1, .ignore_pmdown_time = true, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_NB_NF, .ops = &cs43130_ops, #else .codec_dai_name = "snd-soc-dummy-dai", .codec_name = "snd-soc-dummy", #endif }, }; static struct snd_soc_dai_link mt_soc_extspk_dai[] = { { .name = "ext_Speaker_Multimedia", .stream_name = MT_SOC_SPEAKER_STREAM_NAME, .cpu_dai_name = "snd-soc-dummy-dai", .platform_name = "snd-soc-dummy", #ifdef CONFIG_SND_SOC_MAX98926 .codec_dai_name = "max98926-aif1", .codec_name = "MAX98926_MT", #elif defined(CONFIG_SND_SOC_CS35L35) .codec_dai_name = "cs35l35-pcm", .codec_name = "cs35l35.2-0040", .ignore_suspend = 1, .ignore_pmdown_time = true, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_NB_NF, .ops = &cs35l35_ops, #else .codec_dai_name = "snd-soc-dummy-dai", .codec_name = "snd-soc-dummy", #endif }, { .name = "I2S1_AWB_CAPTURE", .stream_name = MT_SOC_I2S2ADC2_STREAM_NAME, .cpu_dai_name = MT_SOC_I2S2ADC2DAI_NAME, .platform_name = MT_SOC_I2S2_ADC2_PCM, .codec_dai_name = "snd-soc-dummy-dai", .codec_name = "snd-soc-dummy", .ops = &mt_machine_audio_ops, }, }; static struct snd_soc_dai_link mt_soc_dai_component[ARRAY_SIZE(mt_soc_dai_common) + #ifdef CONFIG_SND_SOC_MTK_BTCVSD ARRAY_SIZE(mt_soc_btcvsd_dai) + #endif ARRAY_SIZE(mt_soc_exthp_dai) + ARRAY_SIZE(mt_soc_extspk_dai)]; #ifdef CONFIG_SND_SOC_MT6357_ACCDET static struct snd_soc_aux_dev mtk_aux_devs = { .name = "mtk-headset", }; #endif static struct snd_soc_card mt_snd_soc_card_mt = { .name = "mt-snd-card", .dai_link = mt_soc_dai_common, .num_links = ARRAY_SIZE(mt_soc_dai_common), #ifdef CONFIG_SND_SOC_MT6357_ACCDET .aux_dev = &mtk_aux_devs, .num_aux_devs = 1, #endif }; static int mt_soc_snd_probe(struct platform_device *pdev) { struct snd_soc_card *card = &mt_snd_soc_card_mt; #ifdef CONFIG_SND_SOC_MTK_BTCVSD struct device_node *btcvsd_node; #endif int ret; int daiLinkNum = 0; ret = mtk_spk_update_dai_link(mt_soc_extspk_dai, pdev); if (ret) { dev_err(&pdev->dev, "%s(), mtk_spk_update_dai_link error\n", __func__); return -EINVAL; } /* get_ext_dai_codec_name(); */ pr_debug("%s(), dai_link = %p\n", __func__, mt_snd_soc_card_mt.dai_link); /* DEAL WITH DAI LINK */ memcpy(mt_soc_dai_component, mt_soc_dai_common, sizeof(mt_soc_dai_common)); daiLinkNum += ARRAY_SIZE(mt_soc_dai_common); #ifdef CONFIG_SND_SOC_MTK_BTCVSD /* assign btcvsd platform_node */ btcvsd_node = of_parse_phandle(pdev->dev.of_node, "mediatek,btcvsd_snd", 0); if (!btcvsd_node) { dev_err(&pdev->dev, "Property 'btcvsd_snd' missing or invalid\n"); return -EINVAL; } mt_soc_btcvsd_dai[0].platform_of_node = btcvsd_node; memcpy(mt_soc_dai_component + daiLinkNum, mt_soc_btcvsd_dai, sizeof(mt_soc_btcvsd_dai)); daiLinkNum += ARRAY_SIZE(mt_soc_btcvsd_dai); #endif memcpy(mt_soc_dai_component + daiLinkNum, mt_soc_exthp_dai, sizeof(mt_soc_exthp_dai)); daiLinkNum += ARRAY_SIZE(mt_soc_exthp_dai); memcpy(mt_soc_dai_component + daiLinkNum, mt_soc_extspk_dai, sizeof(mt_soc_extspk_dai)); daiLinkNum += ARRAY_SIZE(mt_soc_extspk_dai); mt_snd_soc_card_mt.dai_link = mt_soc_dai_component; mt_snd_soc_card_mt.num_links = daiLinkNum; card->dev = &pdev->dev; platform_set_drvdata(pdev, card); #ifdef CONFIG_SND_SOC_MT6357_ACCDET mtk_aux_devs.codec_of_node = of_parse_phandle(pdev->dev.of_node, "mediatek,headset-codec", 0); if (!mtk_aux_devs.codec_of_node) { dev_err(&pdev->dev, "Can't find controls for headset codec.\n"); return -EINVAL; }; mtk_accdet_set_drvdata(card); #endif ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", __func__, ret); #ifdef CONFIG_DEBUG_FS /* create debug file */ mt_sco_audio_debugfs = debugfs_create_file(DEBUG_FS_NAME, S_IFREG | 0444, NULL, (void *)DEBUG_FS_NAME, &mtaudio_debug_ops); /* create analog debug file */ mt_sco_audio_debugfs = debugfs_create_file( DEBUG_ANA_FS_NAME, S_IFREG | 0444, NULL, (void *)DEBUG_ANA_FS_NAME, &mtaudio_ana_debug_ops); #endif return ret; } static int mt_soc_snd_remove(struct platform_device *pdev) { pr_debug("%s\n", __func__); snd_soc_unregister_component(&pdev->dev); return 0; } #ifdef CONFIG_OF static const struct of_device_id mt_audio_driver_dt_match[] = { { .compatible = "mediatek,audio", }, {} }; #endif static struct platform_driver mt_audio_driver = { .driver = { .name = "mtk-audio", .owner = THIS_MODULE, #ifdef CONFIG_OF .of_match_table = mt_audio_driver_dt_match, #endif }, .probe = mt_soc_snd_probe, .remove = mt_soc_snd_remove, }; #ifndef CONFIG_OF static struct platform_device *mtk_soc_snd_dev; #endif static int __init mt_soc_snd_init(void) { int ret; pr_debug("%s\n", __func__); #ifndef CONFIG_OF mtk_soc_snd_dev = platform_device_alloc("mtk-audio", -1); if (!mtk_soc_snd_dev) return -ENOMEM; ret = platform_device_add(mtk_soc_snd_dev); if (ret != 0) { platform_device_put(mtk_soc_snd_dev); return ret; } #endif ret = platform_driver_register(&mt_audio_driver); pr_debug("-%s\n", __func__); return ret; } module_init(mt_soc_snd_init); static void __exit mt_soc_snd_exit(void) { platform_driver_unregister(&mt_audio_driver); } module_exit(mt_soc_snd_exit); /* Module information */ MODULE_AUTHOR("ChiPeng "); MODULE_DESCRIPTION("ALSA SoC driver "); MODULE_LICENSE("GPL");